mirror of
https://code.briarproject.org/briar/briar.git
synced 2026-02-13 03:09:04 +01:00
Compare commits
388 Commits
41-alias-f
...
contact-re
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3c290a320e | ||
|
|
421c9c44d6 | ||
|
|
29d3ee2439 | ||
|
|
06d4f85768 | ||
|
|
9685462242 | ||
|
|
84f2c29c76 | ||
|
|
9c8125d77a | ||
|
|
1a1a010ee7 | ||
|
|
56fb20f257 | ||
|
|
f82294527f | ||
|
|
456f25b701 | ||
|
|
0587fdc54c | ||
|
|
ece083026e | ||
|
|
0e5bb3e9de | ||
|
|
dcebd5a81c | ||
|
|
e9a3685bfd | ||
|
|
3aadcc17dd | ||
|
|
296ce080e2 | ||
|
|
724e6643bd | ||
|
|
fafd0c7ff9 | ||
|
|
e91a7c64d8 | ||
|
|
f08e3a58e6 | ||
|
|
94de1834b8 | ||
|
|
6b24eeb84c | ||
|
|
f72ff9f812 | ||
|
|
0f5f440f1c | ||
|
|
7acbe56197 | ||
|
|
fccf735a89 | ||
|
|
d5ac2c9ead | ||
|
|
d4b929fc6c | ||
|
|
b568405f59 | ||
|
|
ff2f710495 | ||
|
|
d00094edab | ||
|
|
9ca854473f | ||
|
|
8603fd3257 | ||
|
|
648fc6e65c | ||
|
|
0c65e97fcf | ||
|
|
16d2154c73 | ||
|
|
b8e390db21 | ||
|
|
b2702062bc | ||
|
|
f11b32f188 | ||
|
|
d603607a90 | ||
|
|
6c0dffff56 | ||
|
|
9f3394aa1d | ||
|
|
74710664e3 | ||
|
|
0d0197fd2d | ||
|
|
c3b5b04b71 | ||
|
|
8b3164e107 | ||
|
|
79ff5aa148 | ||
|
|
652ce4a53d | ||
|
|
df0d6594b6 | ||
|
|
f73ecc6066 | ||
|
|
0f614e8460 | ||
|
|
f4bdd201a3 | ||
|
|
5130c83556 | ||
|
|
423ecc003b | ||
|
|
419f37a4a9 | ||
|
|
3d94ffb714 | ||
|
|
d40cfd30a2 | ||
|
|
3b4a92f66c | ||
|
|
f9dfbe3fa5 | ||
|
|
bc8bb08853 | ||
|
|
cc67a8fcdd | ||
|
|
f8cf88e6cd | ||
|
|
bc58c47a22 | ||
|
|
aa6879c48e | ||
|
|
4d26628f2a | ||
|
|
abaa70da99 | ||
|
|
6435c3520c | ||
|
|
b5c4c7ae61 | ||
|
|
5d96da3547 | ||
|
|
ed842f781a | ||
|
|
5e30e5e1de | ||
|
|
ce52a36db1 | ||
|
|
f5ef87b34b | ||
|
|
4c6f68c255 | ||
|
|
ae09b4c607 | ||
|
|
880d77922e | ||
|
|
1c227e81e4 | ||
|
|
541acad29a | ||
|
|
60f71648f3 | ||
|
|
270b8af39f | ||
|
|
31d3324701 | ||
|
|
dbe46d60fd | ||
|
|
d10ab96955 | ||
|
|
b2841e245a | ||
|
|
68c40f0c46 | ||
|
|
9ccd8d1602 | ||
|
|
ac3942975e | ||
|
|
b6455d40a7 | ||
|
|
2815ad042d | ||
|
|
2055961534 | ||
|
|
741eae34e9 | ||
|
|
50bd4cce6b | ||
|
|
0a5a8310fc | ||
|
|
cc43d5982a | ||
|
|
50675473ce | ||
|
|
de852b2a9f | ||
|
|
b7c712116b | ||
|
|
7dd4897c8c | ||
|
|
7469c0f5e3 | ||
|
|
144ea0c2fc | ||
|
|
a917ebdc76 | ||
|
|
2a389c74dc | ||
|
|
ef16d096f1 | ||
|
|
679455888b | ||
|
|
d4372ddae7 | ||
|
|
c3ef990a94 | ||
|
|
8ae9b7f5a2 | ||
|
|
106d80ef76 | ||
|
|
9422ba2718 | ||
|
|
8343f5c2db | ||
|
|
371c7efb04 | ||
|
|
92d67645ab | ||
|
|
a20e868970 | ||
|
|
dd853f6718 | ||
|
|
16a8ad996a | ||
|
|
e27885f0c8 | ||
|
|
f6ef48bf90 | ||
|
|
e282ca763d | ||
|
|
71016382dc | ||
|
|
d004933fae | ||
|
|
37512c50d8 | ||
|
|
0b61a5d40a | ||
|
|
5dd320f282 | ||
|
|
2a21db5fb6 | ||
|
|
b023593a2c | ||
|
|
5ccf2cae1f | ||
|
|
c2cb89ab73 | ||
|
|
b342759e06 | ||
|
|
93d99b0111 | ||
|
|
61e8d576d2 | ||
|
|
75c37a258e | ||
|
|
e964dae64b | ||
|
|
986d884b40 | ||
|
|
9557afabc6 | ||
|
|
ebe6b0d4c0 | ||
|
|
6e83fb7aef | ||
|
|
7a5ec2af12 | ||
|
|
ce1fde496c | ||
|
|
4b62c51fbf | ||
|
|
226ed3dd73 | ||
|
|
ab07dfb32c | ||
|
|
20c51c1aa4 | ||
|
|
232c2129a7 | ||
|
|
3620edbfc9 | ||
|
|
ad71d69149 | ||
|
|
f73f8ca7e7 | ||
|
|
16c701a71a | ||
|
|
8183b7b26a | ||
|
|
bd48c97eab | ||
|
|
925dc29a1f | ||
|
|
91777fd942 | ||
|
|
fbce8f81c7 | ||
|
|
d7c72c4d68 | ||
|
|
4faf535801 | ||
|
|
526ef7c6d8 | ||
|
|
798dff1a03 | ||
|
|
a4336776c9 | ||
|
|
418451cbd9 | ||
|
|
045fcfc5fa | ||
|
|
ef998577db | ||
|
|
a53345a3c9 | ||
|
|
ed8c09282d | ||
|
|
42197b5b5c | ||
|
|
374fc7035b | ||
|
|
9b796c7cc3 | ||
|
|
532edff642 | ||
|
|
6857252471 | ||
|
|
c229e19452 | ||
|
|
42bca09d16 | ||
|
|
9eacbfa659 | ||
|
|
f14e546dc6 | ||
|
|
684c64a1d9 | ||
|
|
6fdab959b1 | ||
|
|
c8487483ff | ||
|
|
a159b23dc0 | ||
|
|
5070a27a83 | ||
|
|
9ce73a6840 | ||
|
|
6e9928f20f | ||
|
|
b31d61afc5 | ||
|
|
5a99cb93cc | ||
|
|
d0bbebd25e | ||
|
|
4307d26606 | ||
|
|
0089c1ac6d | ||
|
|
2a7aac4930 | ||
|
|
a37b6d81ed | ||
|
|
1d09a6708a | ||
|
|
d3b6f484c8 | ||
|
|
039c6edb66 | ||
|
|
8b9f89eab2 | ||
|
|
1e2c17b170 | ||
|
|
a994966095 | ||
|
|
2bea581654 | ||
|
|
87377666aa | ||
|
|
9d07b2e141 | ||
|
|
5c312b49e2 | ||
|
|
f56efe45cd | ||
|
|
2332a58681 | ||
|
|
8c6dfaa196 | ||
|
|
3cfb04b60d | ||
|
|
e85fbfb952 | ||
|
|
80ee35d926 | ||
|
|
4796902b9c | ||
|
|
149e67c0f7 | ||
|
|
1d5214117f | ||
|
|
b8f248ca9c | ||
|
|
dfb71a03a5 | ||
|
|
961fdc8e72 | ||
|
|
c3d44663cd | ||
|
|
0081472489 | ||
|
|
cdf4f3a24b | ||
|
|
fb1d8e860f | ||
|
|
a3c526ec9a | ||
|
|
dee488d06d | ||
|
|
b29c7d8022 | ||
|
|
0725d207ec | ||
|
|
5a7599a88d | ||
|
|
59cd98db81 | ||
|
|
768488eb04 | ||
|
|
a6b1ad48c3 | ||
|
|
77299a68ed | ||
|
|
5e5705c73b | ||
|
|
e6229a3a13 | ||
|
|
5fbacb4ee4 | ||
|
|
c7f4e976ed | ||
|
|
419f2d966a | ||
|
|
d6c18db9e9 | ||
|
|
8fe49d9961 | ||
|
|
f536cfdab8 | ||
|
|
4d594acad5 | ||
|
|
800dfed5c1 | ||
|
|
54b823e401 | ||
|
|
52ec56d690 | ||
|
|
d4f8abfac1 | ||
|
|
d07c144316 | ||
|
|
dcd5189910 | ||
|
|
7b3afcca99 | ||
|
|
a22d03d028 | ||
|
|
d857338ad0 | ||
|
|
a5c9e7c74d | ||
|
|
8a4a343147 | ||
|
|
dcd5e34c6b | ||
|
|
7b22d3b84d | ||
|
|
c8fa23273f | ||
|
|
fbe5df8938 | ||
|
|
008cf95741 | ||
|
|
3eb066a836 | ||
|
|
674b29af25 | ||
|
|
b8ca5ab557 | ||
|
|
6e17709f46 | ||
|
|
726d90145c | ||
|
|
165211eb9b | ||
|
|
868c61e5d6 | ||
|
|
798bb6d4f7 | ||
|
|
bc352a2dc6 | ||
|
|
ce7d6d3db5 | ||
|
|
61276c81d2 | ||
|
|
c09abdb088 | ||
|
|
45a11badd5 | ||
|
|
152ac3df43 | ||
|
|
dd5ad86db8 | ||
|
|
10e9fb308d | ||
|
|
de8e95692a | ||
|
|
d6b52cf4ec | ||
|
|
8a839fb5e4 | ||
|
|
fbf8642edb | ||
|
|
ade6a14342 | ||
|
|
d500ff81c3 | ||
|
|
3053e3cfa7 | ||
|
|
6964a67ca3 | ||
|
|
f4b06e1fb3 | ||
|
|
4db075d643 | ||
|
|
78a8ae6b8e | ||
|
|
7866037d02 | ||
|
|
35716051fb | ||
|
|
6cafea836f | ||
|
|
bd0fd229c6 | ||
|
|
ea05a5c703 | ||
|
|
4103eaf639 | ||
|
|
753a25bc2a | ||
|
|
8f4c3c4528 | ||
|
|
636a7dfe72 | ||
|
|
08e99edd42 | ||
|
|
e28bc475df | ||
|
|
88276a4d44 | ||
|
|
f9987c89df | ||
|
|
2c8cb8301f | ||
|
|
c00ee80f0f | ||
|
|
3bfedfdc3d | ||
|
|
ecb63d1acb | ||
|
|
b24914408d | ||
|
|
5ede63edd5 | ||
|
|
4e523c5fbc | ||
|
|
cf79ed5633 | ||
|
|
0a0a6a6369 | ||
|
|
4784980e7b | ||
|
|
3bfa5e2081 | ||
|
|
f2b09deac4 | ||
|
|
ad4729b2f9 | ||
|
|
50cc0a6815 | ||
|
|
32c8ac6576 | ||
|
|
c12422d949 | ||
|
|
3841713c18 | ||
|
|
79232eb558 | ||
|
|
d02b30e751 | ||
|
|
043662a092 | ||
|
|
efc85fb88f | ||
|
|
8b3983ef9e | ||
|
|
6766fb76b2 | ||
|
|
7f74bd1c38 | ||
|
|
951ee30b95 | ||
|
|
c386a0f5eb | ||
|
|
52c778dce3 | ||
|
|
e846a13f50 | ||
|
|
23e9b119d1 | ||
|
|
e6f380296f | ||
|
|
794fb9686b | ||
|
|
bb22b9db10 | ||
|
|
d4f015d054 | ||
|
|
41e5d8900c | ||
|
|
c3cb966009 | ||
|
|
f964d1ef07 | ||
|
|
cccaeeda6c | ||
|
|
483106e00c | ||
|
|
934f14ef31 | ||
|
|
e3abff5ad8 | ||
|
|
391732b239 | ||
|
|
4738bfdd85 | ||
|
|
be1ca89309 | ||
|
|
866be99179 | ||
|
|
48822e2133 | ||
|
|
6883c5caa9 | ||
|
|
8b709969ab | ||
|
|
fe94b65b3b | ||
|
|
f54df1d787 | ||
|
|
a7e826ccf5 | ||
|
|
845eb3262b | ||
|
|
0a46ad439f | ||
|
|
d14d93ea35 | ||
|
|
12a1cf8f8b | ||
|
|
fb2ab861db | ||
|
|
aa15b68d24 | ||
|
|
7059f376f1 | ||
|
|
9313c191c1 | ||
|
|
7746364ae9 | ||
|
|
7429857b28 | ||
|
|
4db64f51a8 | ||
|
|
78172038ef | ||
|
|
7d0c418877 | ||
|
|
5ae4f8f6cb | ||
|
|
45dd10db9d | ||
|
|
5cc8c268ca | ||
|
|
93a6bf2f52 | ||
|
|
852dd46a1b | ||
|
|
4a42e767d3 | ||
|
|
8547b4dc91 | ||
|
|
f6c8a8cec7 | ||
|
|
db8796049e | ||
|
|
e1f31ad381 | ||
|
|
3a15e47ddd | ||
|
|
cf616905d6 | ||
|
|
d3f774f339 | ||
|
|
6c7c488892 | ||
|
|
3fe7aae97e | ||
|
|
ecf417c93b | ||
|
|
c1785c5b13 | ||
|
|
fb2c321a3d | ||
|
|
6e3adc0874 | ||
|
|
cdbe2a00f5 | ||
|
|
a51dc7e0d5 | ||
|
|
0ee7465429 | ||
|
|
7c202189a2 | ||
|
|
da3b2c1591 | ||
|
|
6c5e8ce4cf | ||
|
|
ca700d8d23 | ||
|
|
db11dad61e | ||
|
|
69e7366226 | ||
|
|
90b7b4e67f | ||
|
|
d29812a42b | ||
|
|
6565172e10 | ||
|
|
7447468ce5 | ||
|
|
2db2a1a208 | ||
|
|
0d7e4feaf2 | ||
|
|
eb3983f6b2 | ||
|
|
e2ce49c30e | ||
|
|
adc6fb2fd5 | ||
|
|
ca6dc33cdd |
@@ -3,7 +3,7 @@
|
|||||||
<module name="briar-headless" />
|
<module name="briar-headless" />
|
||||||
<option name="ALTERNATIVE_JRE_PATH_ENABLED" value="false" />
|
<option name="ALTERNATIVE_JRE_PATH_ENABLED" value="false" />
|
||||||
<option name="ALTERNATIVE_JRE_PATH" />
|
<option name="ALTERNATIVE_JRE_PATH" />
|
||||||
<option name="PACKAGE_NAME" value="" />
|
<option name="PACKAGE_NAME" value="org.briarproject.briar.headless" />
|
||||||
<option name="MAIN_CLASS_NAME" value="" />
|
<option name="MAIN_CLASS_NAME" value="" />
|
||||||
<option name="METHOD_NAME" value="" />
|
<option name="METHOD_NAME" value="" />
|
||||||
<option name="TEST_OBJECT" value="package" />
|
<option name="TEST_OBJECT" value="package" />
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
import com.android.build.gradle.tasks.MergeResources
|
||||||
|
|
||||||
apply plugin: 'com.android.library'
|
apply plugin: 'com.android.library'
|
||||||
apply plugin: 'witness'
|
apply plugin: 'witness'
|
||||||
apply from: 'witness.gradle'
|
apply from: 'witness.gradle'
|
||||||
@@ -9,8 +11,8 @@ android {
|
|||||||
defaultConfig {
|
defaultConfig {
|
||||||
minSdkVersion 14
|
minSdkVersion 14
|
||||||
targetSdkVersion 26
|
targetSdkVersion 26
|
||||||
versionCode 10103
|
versionCode 10106
|
||||||
versionName "1.1.3"
|
versionName "1.1.6"
|
||||||
consumerProguardFiles 'proguard-rules.txt'
|
consumerProguardFiles 'proguard-rules.txt'
|
||||||
|
|
||||||
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
|
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
|
||||||
@@ -28,9 +30,10 @@ configurations {
|
|||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
implementation project(path: ':bramble-core', configuration: 'default')
|
implementation project(path: ':bramble-core', configuration: 'default')
|
||||||
tor 'org.briarproject:tor-android:0.3.4.8@zip'
|
tor 'org.briarproject:tor-android:0.3.5.8@zip'
|
||||||
|
tor 'org.briarproject:obfs4proxy-android:0.0.9@zip'
|
||||||
|
|
||||||
annotationProcessor 'com.google.dagger:dagger-compiler:2.0.2'
|
annotationProcessor 'com.google.dagger:dagger-compiler:2.19'
|
||||||
|
|
||||||
compileOnly 'javax.annotation:jsr250-api:1.0'
|
compileOnly 'javax.annotation:jsr250-api:1.0'
|
||||||
|
|
||||||
@@ -39,13 +42,29 @@ dependencies {
|
|||||||
testImplementation "org.jmock:jmock:2.8.2"
|
testImplementation "org.jmock:jmock:2.8.2"
|
||||||
testImplementation "org.jmock:jmock-junit4:2.8.2"
|
testImplementation "org.jmock:jmock-junit4:2.8.2"
|
||||||
testImplementation "org.jmock:jmock-legacy:2.8.2"
|
testImplementation "org.jmock:jmock-legacy:2.8.2"
|
||||||
testImplementation "org.hamcrest:hamcrest-library:1.3"
|
|
||||||
testImplementation "org.hamcrest:hamcrest-core:1.3"
|
|
||||||
}
|
}
|
||||||
|
|
||||||
project.afterEvaluate {
|
def torBinariesDir = 'src/main/res/raw'
|
||||||
copy {
|
|
||||||
from configurations.tor.collect { zipTree(it) }
|
task cleanTorBinaries {
|
||||||
into 'src/main/res/raw'
|
doLast {
|
||||||
|
delete fileTree(torBinariesDir) { include '*.zip' }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
clean.dependsOn cleanTorBinaries
|
||||||
|
|
||||||
|
task unpackTorBinaries {
|
||||||
|
doLast {
|
||||||
|
copy {
|
||||||
|
from configurations.tor.collect { zipTree(it) }
|
||||||
|
into torBinariesDir
|
||||||
|
}
|
||||||
|
}
|
||||||
|
dependsOn cleanTorBinaries
|
||||||
|
}
|
||||||
|
|
||||||
|
tasks.withType(MergeResources) {
|
||||||
|
inputs.dir torBinariesDir
|
||||||
|
dependsOn unpackTorBinaries
|
||||||
|
}
|
||||||
|
|||||||
@@ -0,0 +1,11 @@
|
|||||||
|
package org.briarproject.bramble;
|
||||||
|
|
||||||
|
import org.briarproject.bramble.battery.AndroidBatteryModule;
|
||||||
|
import org.briarproject.bramble.network.AndroidNetworkModule;
|
||||||
|
|
||||||
|
public interface BrambleAndroidEagerSingletons {
|
||||||
|
|
||||||
|
void inject(AndroidBatteryModule.EagerSingletons init);
|
||||||
|
|
||||||
|
void inject(AndroidNetworkModule.EagerSingletons init);
|
||||||
|
}
|
||||||
@@ -1,5 +1,6 @@
|
|||||||
package org.briarproject.bramble;
|
package org.briarproject.bramble;
|
||||||
|
|
||||||
|
import org.briarproject.bramble.battery.AndroidBatteryModule;
|
||||||
import org.briarproject.bramble.network.AndroidNetworkModule;
|
import org.briarproject.bramble.network.AndroidNetworkModule;
|
||||||
import org.briarproject.bramble.plugin.tor.CircumventionModule;
|
import org.briarproject.bramble.plugin.tor.CircumventionModule;
|
||||||
import org.briarproject.bramble.system.AndroidSystemModule;
|
import org.briarproject.bramble.system.AndroidSystemModule;
|
||||||
@@ -7,10 +8,15 @@ import org.briarproject.bramble.system.AndroidSystemModule;
|
|||||||
import dagger.Module;
|
import dagger.Module;
|
||||||
|
|
||||||
@Module(includes = {
|
@Module(includes = {
|
||||||
|
AndroidBatteryModule.class,
|
||||||
AndroidNetworkModule.class,
|
AndroidNetworkModule.class,
|
||||||
AndroidSystemModule.class,
|
AndroidSystemModule.class,
|
||||||
CircumventionModule.class
|
CircumventionModule.class
|
||||||
})
|
})
|
||||||
public class BrambleAndroidModule {
|
public class BrambleAndroidModule {
|
||||||
|
|
||||||
|
public static void initEagerSingletons(BrambleAndroidEagerSingletons c) {
|
||||||
|
c.inject(new AndroidBatteryModule.EagerSingletons());
|
||||||
|
c.inject(new AndroidNetworkModule.EagerSingletons());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,11 +12,15 @@ 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 {
|
||||||
|
|
||||||
@@ -89,20 +93,42 @@ 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);
|
||||||
File[] children = dataDir.listFiles();
|
@Nullable
|
||||||
if (children == null) {
|
File[] fileArray = dataDir.listFiles();
|
||||||
|
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 child : children) {
|
for (File file : fileArray) {
|
||||||
String name = child.getName();
|
String name = file.getName();
|
||||||
if (!name.equals("lib") && !name.equals("shared_prefs")) {
|
if (!name.equals("lib") && !name.equals("shared_prefs")) {
|
||||||
IoUtils.deleteFileOrDir(child);
|
files.add(file);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
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").mkdir())
|
if (!new File(dataDir, "cache").mkdirs())
|
||||||
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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,81 @@
|
|||||||
|
package org.briarproject.bramble.battery;
|
||||||
|
|
||||||
|
import android.app.Application;
|
||||||
|
import android.content.BroadcastReceiver;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.content.Intent;
|
||||||
|
import android.content.IntentFilter;
|
||||||
|
|
||||||
|
import org.briarproject.bramble.api.battery.BatteryManager;
|
||||||
|
import org.briarproject.bramble.api.battery.event.BatteryEvent;
|
||||||
|
import org.briarproject.bramble.api.event.EventBus;
|
||||||
|
import org.briarproject.bramble.api.lifecycle.Service;
|
||||||
|
|
||||||
|
import java.util.concurrent.atomic.AtomicBoolean;
|
||||||
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
|
import javax.inject.Inject;
|
||||||
|
|
||||||
|
import static android.content.Intent.ACTION_BATTERY_CHANGED;
|
||||||
|
import static android.content.Intent.ACTION_POWER_CONNECTED;
|
||||||
|
import static android.content.Intent.ACTION_POWER_DISCONNECTED;
|
||||||
|
import static android.os.BatteryManager.EXTRA_PLUGGED;
|
||||||
|
import static java.util.logging.Level.INFO;
|
||||||
|
import static java.util.logging.Logger.getLogger;
|
||||||
|
|
||||||
|
class AndroidBatteryManager implements BatteryManager, Service {
|
||||||
|
|
||||||
|
private static final Logger LOG =
|
||||||
|
getLogger(AndroidBatteryManager.class.getName());
|
||||||
|
|
||||||
|
private final Context appContext;
|
||||||
|
private final EventBus eventBus;
|
||||||
|
private final AtomicBoolean used = new AtomicBoolean(false);
|
||||||
|
|
||||||
|
private volatile BroadcastReceiver batteryReceiver = null;
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
AndroidBatteryManager(Application app, EventBus eventBus) {
|
||||||
|
this.appContext = app.getApplicationContext();
|
||||||
|
this.eventBus = eventBus;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isCharging() {
|
||||||
|
// Get the sticky intent for ACTION_BATTERY_CHANGED
|
||||||
|
IntentFilter filter = new IntentFilter(ACTION_BATTERY_CHANGED);
|
||||||
|
Intent i = appContext.registerReceiver(null, filter);
|
||||||
|
if (i == null) return false;
|
||||||
|
int status = i.getIntExtra(EXTRA_PLUGGED, 0);
|
||||||
|
return status != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void startService() {
|
||||||
|
if (used.getAndSet(true)) throw new IllegalStateException();
|
||||||
|
batteryReceiver = new BatteryReceiver();
|
||||||
|
IntentFilter filter = new IntentFilter();
|
||||||
|
filter.addAction(ACTION_POWER_CONNECTED);
|
||||||
|
filter.addAction(ACTION_POWER_DISCONNECTED);
|
||||||
|
appContext.registerReceiver(batteryReceiver, filter);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void stopService() {
|
||||||
|
if (batteryReceiver != null)
|
||||||
|
appContext.unregisterReceiver(batteryReceiver);
|
||||||
|
}
|
||||||
|
|
||||||
|
private class BatteryReceiver extends BroadcastReceiver {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onReceive(Context ctx, Intent i) {
|
||||||
|
String action = i.getAction();
|
||||||
|
if (LOG.isLoggable(INFO)) LOG.info("Received broadcast " + action);
|
||||||
|
if (ACTION_POWER_CONNECTED.equals(action))
|
||||||
|
eventBus.broadcast(new BatteryEvent(true));
|
||||||
|
else if (ACTION_POWER_DISCONNECTED.equals(action))
|
||||||
|
eventBus.broadcast(new BatteryEvent(false));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
package org.briarproject.bramble.battery;
|
||||||
|
|
||||||
|
import org.briarproject.bramble.api.battery.BatteryManager;
|
||||||
|
import org.briarproject.bramble.api.lifecycle.LifecycleManager;
|
||||||
|
|
||||||
|
import javax.inject.Inject;
|
||||||
|
import javax.inject.Singleton;
|
||||||
|
|
||||||
|
import dagger.Module;
|
||||||
|
import dagger.Provides;
|
||||||
|
|
||||||
|
@Module
|
||||||
|
public class AndroidBatteryModule {
|
||||||
|
|
||||||
|
public static class EagerSingletons {
|
||||||
|
@Inject
|
||||||
|
BatteryManager batteryManager;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Provides
|
||||||
|
@Singleton
|
||||||
|
BatteryManager provideBatteryManager(LifecycleManager lifecycleManager,
|
||||||
|
AndroidBatteryManager batteryManager) {
|
||||||
|
lifecycleManager.registerService(batteryManager);
|
||||||
|
return batteryManager;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -3,6 +3,7 @@ package org.briarproject.bramble.network;
|
|||||||
import org.briarproject.bramble.api.lifecycle.LifecycleManager;
|
import org.briarproject.bramble.api.lifecycle.LifecycleManager;
|
||||||
import org.briarproject.bramble.api.network.NetworkManager;
|
import org.briarproject.bramble.api.network.NetworkManager;
|
||||||
|
|
||||||
|
import javax.inject.Inject;
|
||||||
import javax.inject.Singleton;
|
import javax.inject.Singleton;
|
||||||
|
|
||||||
import dagger.Module;
|
import dagger.Module;
|
||||||
@@ -11,6 +12,11 @@ import dagger.Provides;
|
|||||||
@Module
|
@Module
|
||||||
public class AndroidNetworkModule {
|
public class AndroidNetworkModule {
|
||||||
|
|
||||||
|
public static class EagerSingletons {
|
||||||
|
@Inject
|
||||||
|
NetworkManager networkManager;
|
||||||
|
}
|
||||||
|
|
||||||
@Provides
|
@Provides
|
||||||
@Singleton
|
@Singleton
|
||||||
NetworkManager provideNetworkManager(LifecycleManager lifecycleManager,
|
NetworkManager provideNetworkManager(LifecycleManager lifecycleManager,
|
||||||
|
|||||||
@@ -18,8 +18,8 @@ import org.briarproject.bramble.api.plugin.duplex.DuplexTransportConnection;
|
|||||||
import org.briarproject.bramble.api.system.AndroidExecutor;
|
import org.briarproject.bramble.api.system.AndroidExecutor;
|
||||||
import org.briarproject.bramble.api.system.Clock;
|
import org.briarproject.bramble.api.system.Clock;
|
||||||
import org.briarproject.bramble.util.AndroidUtils;
|
import org.briarproject.bramble.util.AndroidUtils;
|
||||||
|
import org.briarproject.bramble.util.IoUtils;
|
||||||
|
|
||||||
import java.io.Closeable;
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.security.SecureRandom;
|
import java.security.SecureRandom;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
@@ -51,7 +51,6 @@ import static android.bluetooth.BluetoothDevice.EXTRA_DEVICE;
|
|||||||
import static java.util.concurrent.TimeUnit.MILLISECONDS;
|
import static java.util.concurrent.TimeUnit.MILLISECONDS;
|
||||||
import static java.util.logging.Level.INFO;
|
import static java.util.logging.Level.INFO;
|
||||||
import static java.util.logging.Level.WARNING;
|
import static java.util.logging.Level.WARNING;
|
||||||
import static org.briarproject.bramble.util.LogUtils.logException;
|
|
||||||
import static org.briarproject.bramble.util.PrivacyUtils.scrubMacAddress;
|
import static org.briarproject.bramble.util.PrivacyUtils.scrubMacAddress;
|
||||||
|
|
||||||
@MethodsNotNullByDefault
|
@MethodsNotNullByDefault
|
||||||
@@ -161,11 +160,7 @@ class AndroidBluetoothPlugin extends BluetoothPlugin<BluetoothServerSocket> {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
void tryToClose(@Nullable BluetoothServerSocket ss) {
|
void tryToClose(@Nullable BluetoothServerSocket ss) {
|
||||||
try {
|
IoUtils.tryToClose(ss, LOG, WARNING);
|
||||||
if (ss != null) ss.close();
|
|
||||||
} catch (IOException e) {
|
|
||||||
logException(LOG, WARNING, e);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -195,7 +190,7 @@ class AndroidBluetoothPlugin extends BluetoothPlugin<BluetoothServerSocket> {
|
|||||||
s.connect();
|
s.connect();
|
||||||
return wrapSocket(s);
|
return wrapSocket(s);
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
tryToClose(s);
|
IoUtils.tryToClose(s, LOG, WARNING);
|
||||||
throw e;
|
throw e;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -268,14 +263,6 @@ class AndroidBluetoothPlugin extends BluetoothPlugin<BluetoothServerSocket> {
|
|||||||
return addresses;
|
return addresses;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void tryToClose(@Nullable Closeable c) {
|
|
||||||
try {
|
|
||||||
if (c != null) c.close();
|
|
||||||
} catch (IOException e) {
|
|
||||||
logException(LOG, WARNING, e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private class BluetoothStateReceiver extends BroadcastReceiver {
|
private class BluetoothStateReceiver extends BroadcastReceiver {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import android.content.pm.PackageManager;
|
|||||||
import android.content.pm.PackageManager.NameNotFoundException;
|
import android.content.pm.PackageManager.NameNotFoundException;
|
||||||
import android.os.PowerManager;
|
import android.os.PowerManager;
|
||||||
|
|
||||||
|
import org.briarproject.bramble.api.battery.BatteryManager;
|
||||||
import org.briarproject.bramble.api.network.NetworkManager;
|
import org.briarproject.bramble.api.network.NetworkManager;
|
||||||
import org.briarproject.bramble.api.nullsafety.MethodsNotNullByDefault;
|
import org.briarproject.bramble.api.nullsafety.MethodsNotNullByDefault;
|
||||||
import org.briarproject.bramble.api.nullsafety.ParametersNotNullByDefault;
|
import org.briarproject.bramble.api.nullsafety.ParametersNotNullByDefault;
|
||||||
@@ -31,9 +32,6 @@ 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;
|
||||||
|
|
||||||
@@ -41,19 +39,20 @@ class AndroidTorPlugin extends TorPlugin {
|
|||||||
Context appContext, NetworkManager networkManager,
|
Context appContext, NetworkManager networkManager,
|
||||||
LocationUtils locationUtils, SocketFactory torSocketFactory,
|
LocationUtils locationUtils, SocketFactory torSocketFactory,
|
||||||
Clock clock, ResourceProvider resourceProvider,
|
Clock clock, ResourceProvider resourceProvider,
|
||||||
CircumventionProvider circumventionProvider, Backoff backoff,
|
CircumventionProvider circumventionProvider,
|
||||||
|
BatteryManager batteryManager, Backoff backoff,
|
||||||
DuplexPluginCallback callback, String architecture, int maxLatency,
|
DuplexPluginCallback callback, String architecture, int maxLatency,
|
||||||
int maxIdleTime) {
|
int maxIdleTime) {
|
||||||
super(ioExecutor, networkManager, locationUtils, torSocketFactory,
|
super(ioExecutor, networkManager, locationUtils, torSocketFactory,
|
||||||
clock, resourceProvider, circumventionProvider, backoff,
|
clock, resourceProvider, circumventionProvider, batteryManager,
|
||||||
callback, architecture, maxLatency, maxIdleTime,
|
backoff, callback, architecture, maxLatency, maxIdleTime,
|
||||||
appContext.getDir("tor", MODE_PRIVATE));
|
appContext.getDir("tor", MODE_PRIVATE));
|
||||||
this.appContext = appContext;
|
this.appContext = appContext;
|
||||||
PowerManager pm = (PowerManager)
|
PowerManager pm = (PowerManager)
|
||||||
appContext.getSystemService(POWER_SERVICE);
|
appContext.getSystemService(POWER_SERVICE);
|
||||||
assert pm != null;
|
if (pm == null) throw new AssertionError();
|
||||||
wakeLock = new RenewableWakeLock(pm, scheduler, PARTIAL_WAKE_LOCK,
|
wakeLock = new RenewableWakeLock(pm, scheduler, PARTIAL_WAKE_LOCK,
|
||||||
WAKE_LOCK_TAG, 1, MINUTES);
|
getWakeLockTag(), 1, MINUTES);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -85,4 +84,17 @@ 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();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ package org.briarproject.bramble.plugin.tor;
|
|||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.os.Build;
|
import android.os.Build;
|
||||||
|
|
||||||
|
import org.briarproject.bramble.api.battery.BatteryManager;
|
||||||
import org.briarproject.bramble.api.event.EventBus;
|
import org.briarproject.bramble.api.event.EventBus;
|
||||||
import org.briarproject.bramble.api.network.NetworkManager;
|
import org.briarproject.bramble.api.network.NetworkManager;
|
||||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||||
@@ -48,6 +49,7 @@ public class AndroidTorPluginFactory implements DuplexPluginFactory {
|
|||||||
private final BackoffFactory backoffFactory;
|
private final BackoffFactory backoffFactory;
|
||||||
private final ResourceProvider resourceProvider;
|
private final ResourceProvider resourceProvider;
|
||||||
private final CircumventionProvider circumventionProvider;
|
private final CircumventionProvider circumventionProvider;
|
||||||
|
private final BatteryManager batteryManager;
|
||||||
private final Clock clock;
|
private final Clock clock;
|
||||||
|
|
||||||
public AndroidTorPluginFactory(Executor ioExecutor,
|
public AndroidTorPluginFactory(Executor ioExecutor,
|
||||||
@@ -55,7 +57,8 @@ public class AndroidTorPluginFactory implements DuplexPluginFactory {
|
|||||||
NetworkManager networkManager, LocationUtils locationUtils,
|
NetworkManager networkManager, LocationUtils locationUtils,
|
||||||
EventBus eventBus, SocketFactory torSocketFactory,
|
EventBus eventBus, SocketFactory torSocketFactory,
|
||||||
BackoffFactory backoffFactory, ResourceProvider resourceProvider,
|
BackoffFactory backoffFactory, ResourceProvider resourceProvider,
|
||||||
CircumventionProvider circumventionProvider, Clock clock) {
|
CircumventionProvider circumventionProvider,
|
||||||
|
BatteryManager batteryManager, Clock clock) {
|
||||||
this.ioExecutor = ioExecutor;
|
this.ioExecutor = ioExecutor;
|
||||||
this.scheduler = scheduler;
|
this.scheduler = scheduler;
|
||||||
this.appContext = appContext;
|
this.appContext = appContext;
|
||||||
@@ -66,6 +69,7 @@ public class AndroidTorPluginFactory implements DuplexPluginFactory {
|
|||||||
this.backoffFactory = backoffFactory;
|
this.backoffFactory = backoffFactory;
|
||||||
this.resourceProvider = resourceProvider;
|
this.resourceProvider = resourceProvider;
|
||||||
this.circumventionProvider = circumventionProvider;
|
this.circumventionProvider = circumventionProvider;
|
||||||
|
this.batteryManager = batteryManager;
|
||||||
this.clock = clock;
|
this.clock = clock;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -104,8 +108,8 @@ public class AndroidTorPluginFactory implements DuplexPluginFactory {
|
|||||||
MAX_POLLING_INTERVAL, BACKOFF_BASE);
|
MAX_POLLING_INTERVAL, BACKOFF_BASE);
|
||||||
AndroidTorPlugin plugin = new AndroidTorPlugin(ioExecutor, scheduler,
|
AndroidTorPlugin plugin = new AndroidTorPlugin(ioExecutor, scheduler,
|
||||||
appContext, networkManager, locationUtils, torSocketFactory,
|
appContext, networkManager, locationUtils, torSocketFactory,
|
||||||
clock, resourceProvider, circumventionProvider, backoff,
|
clock, resourceProvider, circumventionProvider, batteryManager,
|
||||||
callback, architecture, MAX_LATENCY, MAX_IDLE_TIME);
|
backoff, callback, architecture, MAX_LATENCY, MAX_IDLE_TIME);
|
||||||
eventBus.addListener(plugin);
|
eventBus.addListener(plugin);
|
||||||
return plugin;
|
return plugin;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
package org.briarproject.bramble.system;
|
package org.briarproject.bramble.system;
|
||||||
|
|
||||||
|
import android.annotation.SuppressLint;
|
||||||
import android.app.Application;
|
import android.app.Application;
|
||||||
import android.bluetooth.BluetoothAdapter;
|
import android.bluetooth.BluetoothAdapter;
|
||||||
import android.bluetooth.BluetoothDevice;
|
import android.bluetooth.BluetoothDevice;
|
||||||
@@ -26,7 +27,7 @@ import static android.provider.Settings.Secure.ANDROID_ID;
|
|||||||
|
|
||||||
@Immutable
|
@Immutable
|
||||||
@NotNullByDefault
|
@NotNullByDefault
|
||||||
class AndroidSecureRandomProvider extends LinuxSecureRandomProvider {
|
class AndroidSecureRandomProvider extends UnixSecureRandomProvider {
|
||||||
|
|
||||||
private static final int SEED_LENGTH = 32;
|
private static final int SEED_LENGTH = 32;
|
||||||
|
|
||||||
@@ -37,6 +38,7 @@ class AndroidSecureRandomProvider extends LinuxSecureRandomProvider {
|
|||||||
appContext = app.getApplicationContext();
|
appContext = app.getApplicationContext();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@SuppressLint("HardwareIds")
|
||||||
@Override
|
@Override
|
||||||
protected void writeToEntropyPool(DataOutputStream out) throws IOException {
|
protected void writeToEntropyPool(DataOutputStream out) throws IOException {
|
||||||
super.writeToEntropyPool(out);
|
super.writeToEntropyPool(out);
|
||||||
@@ -49,12 +51,14 @@ class AndroidSecureRandomProvider extends LinuxSecureRandomProvider {
|
|||||||
String id = Settings.Secure.getString(contentResolver, ANDROID_ID);
|
String id = Settings.Secure.getString(contentResolver, ANDROID_ID);
|
||||||
if (id != null) out.writeUTF(id);
|
if (id != null) out.writeUTF(id);
|
||||||
Parcel parcel = Parcel.obtain();
|
Parcel parcel = Parcel.obtain();
|
||||||
WifiManager wm =
|
WifiManager wm = (WifiManager) appContext.getApplicationContext()
|
||||||
(WifiManager) appContext.getSystemService(WIFI_SERVICE);
|
.getSystemService(WIFI_SERVICE);
|
||||||
List<WifiConfiguration> configs = wm.getConfiguredNetworks();
|
if (wm != null) {
|
||||||
if (configs != null) {
|
List<WifiConfiguration> configs = wm.getConfiguredNetworks();
|
||||||
for (WifiConfiguration config : configs)
|
if (configs != null) {
|
||||||
parcel.writeParcelable(config, 0);
|
for (WifiConfiguration config : configs)
|
||||||
|
parcel.writeParcelable(config, 0);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
BluetoothAdapter bt = BluetoothAdapter.getDefaultAdapter();
|
BluetoothAdapter bt = BluetoothAdapter.getDefaultAdapter();
|
||||||
if (bt != null) {
|
if (bt != null) {
|
||||||
@@ -77,13 +81,13 @@ class AndroidSecureRandomProvider extends LinuxSecureRandomProvider {
|
|||||||
|
|
||||||
// Based on https://android-developers.googleblog.com/2013/08/some-securerandom-thoughts.html
|
// Based on https://android-developers.googleblog.com/2013/08/some-securerandom-thoughts.html
|
||||||
private void applyOpenSslFix() {
|
private void applyOpenSslFix() {
|
||||||
byte[] seed = new LinuxSecureRandomSpi().engineGenerateSeed(
|
byte[] seed = new UnixSecureRandomSpi().engineGenerateSeed(
|
||||||
SEED_LENGTH);
|
SEED_LENGTH);
|
||||||
try {
|
try {
|
||||||
// Seed the OpenSSL PRNG
|
// Seed the OpenSSL PRNG
|
||||||
Class.forName("org.apache.harmony.xnet.provider.jsse.NativeCrypto")
|
Class.forName("org.apache.harmony.xnet.provider.jsse.NativeCrypto")
|
||||||
.getMethod("RAND_seed", byte[].class)
|
.getMethod("RAND_seed", byte[].class)
|
||||||
.invoke(null, seed);
|
.invoke(null, (Object) seed);
|
||||||
// Mix the output of the Linux PRNG into the OpenSSL PRNG
|
// Mix the output of the Linux PRNG into the OpenSSL PRNG
|
||||||
int bytesRead = (Integer) Class.forName(
|
int bytesRead = (Integer) Class.forName(
|
||||||
"org.apache.harmony.xnet.provider.jsse.NativeCrypto")
|
"org.apache.harmony.xnet.provider.jsse.NativeCrypto")
|
||||||
|
|||||||
@@ -1,10 +1,13 @@
|
|||||||
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;
|
||||||
@@ -32,6 +35,13 @@ 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) {
|
||||||
|
|||||||
@@ -11,15 +11,12 @@ import java.util.ArrayList;
|
|||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.logging.Logger;
|
|
||||||
|
|
||||||
import static android.content.Context.MODE_PRIVATE;
|
import static android.content.Context.MODE_PRIVATE;
|
||||||
|
import static android.os.Build.VERSION.SDK_INT;
|
||||||
|
|
||||||
public class AndroidUtils {
|
public class AndroidUtils {
|
||||||
|
|
||||||
private static final Logger LOG =
|
|
||||||
Logger.getLogger(AndroidUtils.class.getName());
|
|
||||||
|
|
||||||
// Fake Bluetooth address returned by BluetoothAdapter on API 23 and later
|
// Fake Bluetooth address returned by BluetoothAdapter on API 23 and later
|
||||||
private static final String FAKE_BLUETOOTH_ADDRESS = "02:00:00:00:00:00";
|
private static final String FAKE_BLUETOOTH_ADDRESS = "02:00:00:00:00:00";
|
||||||
|
|
||||||
@@ -28,7 +25,7 @@ public class AndroidUtils {
|
|||||||
@SuppressWarnings("deprecation")
|
@SuppressWarnings("deprecation")
|
||||||
public static Collection<String> getSupportedArchitectures() {
|
public static Collection<String> getSupportedArchitectures() {
|
||||||
List<String> abis = new ArrayList<>();
|
List<String> abis = new ArrayList<>();
|
||||||
if (Build.VERSION.SDK_INT >= 21) {
|
if (SDK_INT >= 21) {
|
||||||
abis.addAll(Arrays.asList(Build.SUPPORTED_ABIS));
|
abis.addAll(Arrays.asList(Build.SUPPORTED_ABIS));
|
||||||
} else {
|
} else {
|
||||||
abis.add(Build.CPU_ABI);
|
abis.add(Build.CPU_ABI);
|
||||||
|
|||||||
@@ -112,6 +112,8 @@ 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();
|
||||||
@@ -128,6 +130,12 @@ 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());
|
||||||
@@ -140,6 +148,8 @@ 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();
|
||||||
|
|
||||||
@@ -153,6 +163,8 @@ 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,46 +1,49 @@
|
|||||||
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.2.1:protos-26.2.1.jar:2f371f5b1f551e85ab08be4d6a2873471b3d44afd1ebf6aa3298f3b796bf691f',
|
'com.android.tools.analytics-library:protos:26.3.2:protos-26.3.2.jar:50238fb4298b297217b184b9cd93c14f83536fcee829eb0ca850bdb5b53251f0',
|
||||||
'com.android.tools.analytics-library:shared:26.2.1:shared-26.2.1.jar:4c1e4e705fa4d45f23aaea230557f6508155012d9c296337787c1d7b26a97f5a',
|
'com.android.tools.analytics-library:shared:26.3.2:shared-26.3.2.jar:ddd80dcf21905018b7c0583ba72b7282f446084d4952422609a09fbf8237ef71',
|
||||||
'com.android.tools.analytics-library:tracker:26.2.1:tracker-26.2.1.jar:4a624ecc976539f755ddb0bb8dfc2dd3d08326cfec59a098dbd70f701ca7fb75',
|
'com.android.tools.analytics-library:tracker:26.3.2:tracker-26.3.2.jar:28c575d2d1af003e96d7b375a668ee10b2673a2dd0f6438750aa8c3b42e7d0ad',
|
||||||
'com.android.tools.build:aapt2:3.2.1-4818971:aapt2-3.2.1-4818971-linux.jar:f431b6f96c91a2c155144b091a9c97d9805c589fe8efc9c930b6cd346cb60a1e',
|
'com.android.tools.build:apksig:3.3.2:apksig-3.3.2.jar:84c4aaa20127c6c1fe6bdd334b3f5df71f54ad080be9029c8a10f43b6a908acd',
|
||||||
'com.android.tools.build:apksig:3.2.1:apksig-3.2.1.jar:2b46f2feffea66037aab29e4261b2433c190194a6ef97b958511eb157f2ccba5',
|
'com.android.tools.build:apkzlib:3.3.2:apkzlib-3.3.2.jar:d34e523278e5dff565eba3ef3c089d515b2b5cc7b47dc77e2f3465e5e47176ac',
|
||||||
'com.android.tools.build:apkzlib:3.2.1:apkzlib-3.2.1.jar:c39ad0313905932431fe81c8899c2cf39a4d92ad6c4edcaa4b25432f461452aa',
|
'com.android.tools.build:builder-model:3.3.2:builder-model-3.3.2.jar:055e3db0ecee9e06b9f024034999a29cd92cb1885207b37542126bd8bcc57f46',
|
||||||
'com.android.tools.build:builder-model:3.2.1:builder-model-3.2.1.jar:a9f68e6abcec122f9cb5ad352d3f05a3eb03acbcdca95e4d25c16310c2c965ff',
|
'com.android.tools.build:builder-test-api:3.3.2:builder-test-api-3.3.2.jar:0b2e4cd7615bbcad14a3c91fe45ae26693508d06e40ba06c5968b8bc24416618',
|
||||||
'com.android.tools.build:builder-test-api:3.2.1:builder-test-api-3.2.1.jar:533ac6c2b5884bb54967a33791f2628dfdfac7981af39417a333b43d4379b6be',
|
'com.android.tools.build:builder:3.3.2:builder-3.3.2.jar:65649704da7aef0487235fd326f0f2e99ed5cf958e80f204496e6e08a42bd9f5',
|
||||||
'com.android.tools.build:builder:3.2.1:builder-3.2.1.jar:aedcbfd115dbe91d09b4113e66ef50589b558d0aa3b2f133b1d867c9b87fae83',
|
'com.android.tools.build:gradle-api:3.3.2:gradle-api-3.3.2.jar:3cbd47e41bb70330dd72ec2c9fe51e6173554b484a03829b5a2de9e00841e040',
|
||||||
'com.android.tools.build:gradle-api:3.2.1:gradle-api-3.2.1.jar:57cf0ac5ac1dca8afdb3f62b94265e776e7dcfa641cc3844fb53a05193de208d',
|
'com.android.tools.build:manifest-merger:26.3.2:manifest-merger-26.3.2.jar:05c4a6d8b02fb9f08744876477d0a68547c03a8a9069b1f086684fa04af97c33',
|
||||||
'com.android.tools.build:manifest-merger:26.2.1:manifest-merger-26.2.1.jar:8830573263361035d38cfdcb51e2db94029c93865b21334f5fbf8a27984281a6',
|
'com.android.tools.ddms:ddmlib:26.3.2:ddmlib-26.3.2.jar:d248da8a563d6e46d2c7ebbf371a4877e00510f4ca763c0bb272d5a281bf8b85',
|
||||||
'com.android.tools.ddms:ddmlib:26.2.1:ddmlib-26.2.1.jar:a4bf0a29a19980bf27269465cc782064656750b77c26728f82f9e148b705218b',
|
'com.android.tools.external.com-intellij:intellij-core:26.3.2:intellij-core-26.3.2.jar:6c5ecc968230e9f4dcd0fef28885379feace1f0cd8130de6f61d649c86139bf3',
|
||||||
'com.android.tools.external.com-intellij:intellij-core:26.2.1:intellij-core-26.2.1.jar:4925ad1892c2687cb1a63427d440ef519c8c59215fefe0dc5d541d5d411fcafe',
|
'com.android.tools.external.com-intellij:kotlin-compiler:26.3.2:kotlin-compiler-26.3.2.jar:1007d9b07ccb49cd8eaf30fda10ed4681d4714f2f9ab2ecda39b4e539cc51bbe',
|
||||||
'com.android.tools.external.com-intellij:kotlin-compiler:26.2.1:kotlin-compiler-26.2.1.jar:daa064fd708f340ee25fb9823c4c74104ac77f1370b76d907eb9ae6daec0a2ae',
|
'com.android.tools.external.org-jetbrains:uast:26.3.2:uast-26.3.2.jar:5d1833e562ea4f38a89708dfde695f0a162cbd39d003d3dde818c3fdc2b05317',
|
||||||
'com.android.tools.external.org-jetbrains:uast:26.2.1:uast-26.2.1.jar:f10f7258d2ab9189562cc0f9ad838c0378fdba439229173390a99de02ebac75b',
|
'com.android.tools.layoutlib:layoutlib-api:26.3.2:layoutlib-api-26.3.2.jar:d7e61e874ab95f5c350dd38b6a95b5c9dbe0083a02001884264cdb390cb255b8',
|
||||||
'com.android.tools.layoutlib:layoutlib-api:26.2.1:layoutlib-api-26.2.1.jar:ddbf4fca123733fa011595b1cc1f4ac2937ed327b60990711fafc33c775c2ade',
|
'com.android.tools.lint:lint-api:26.3.2:lint-api-26.3.2.jar:5867dfd7fb4a4e161a816a5d29d045f9b542d34594c00a1efec46fb4cd0e1033',
|
||||||
'com.android.tools.lint:lint-api:26.2.1:lint-api-26.2.1.jar:3b57e739de567b98bc9ab56c2c0ee66fc026b4adf5843e8f9804ca0666a6f66e',
|
'com.android.tools.lint:lint-checks:26.3.2:lint-checks-26.3.2.jar:4b163b9c93790d2771e92ba8de58a0d9e0671ffcf2ccef3cf496efd442e27517',
|
||||||
'com.android.tools.lint:lint-checks:26.2.1:lint-checks-26.2.1.jar:c86f4cc9aaee722ee4ad70062f7b5af91e9b041914af27adc09f545ab0fb3bc6',
|
'com.android.tools.lint:lint-gradle-api:26.3.2:lint-gradle-api-26.3.2.jar:54cb282e0c054f9bed3f51302ce08b003c8ab7961dfd5a4f6de26c23cc23062f',
|
||||||
'com.android.tools.lint:lint-gradle-api:26.2.1:lint-gradle-api-26.2.1.jar:2283e7af32e301565f2a797e531f0fc8c648077d457afb3ffdddbee638976c2f',
|
'com.android.tools.lint:lint-gradle:26.3.2:lint-gradle-26.3.2.jar:bb139615f4ce97d42cc394b9389b49b76a6eb85be6785a5d272991543b519013',
|
||||||
'com.android.tools.lint:lint-gradle:26.2.1:lint-gradle-26.2.1.jar:8fd90b2f3ec788cbb9801c07ab3e1ea2255aa31a6093157d7ea0ff13d0315ecb',
|
'com.android.tools.lint:lint:26.3.2:lint-26.3.2.jar:ef7b369f8a56a92ccb0f4c1c357666b9339e4a711a9d84747d446441746cfe4e',
|
||||||
'com.android.tools.lint:lint-kotlin:26.2.1:lint-kotlin-26.2.1.jar:7a6a5d2b18f69cf1b900d857c2632b4c683713c533295933b8b759f8cab4a877',
|
'com.android.tools:annotations:26.3.2:annotations-26.3.2.jar:5bcce8e98b6a2f5ccf13ebcefd8f734e0b35f8b19e456575665631442ce1f7a1',
|
||||||
'com.android.tools.lint:lint:26.2.1:lint-26.2.1.jar:7848b82ae988b90dee259ae7c7e86e05cbf52db6cd21c8bbd38ce7df08f3f8c5',
|
'com.android.tools:common:26.3.2:common-26.3.2.jar:d9f8e7f0669e9a701568e3db6a87c89cf12d8fa6811c9991e969f950215ecfac',
|
||||||
'com.android.tools:annotations:26.2.1:annotations-26.2.1.jar:7391c6a1e080174b96e64ceb078dadd31ce4d8a2d2fee0ec65be202126f90f24',
|
'com.android.tools:dvlib:26.3.2:dvlib-26.3.2.jar:d84aad56161c7773579303d69714ded6897c64c6ddfd7d456e453231e4dfe811',
|
||||||
'com.android.tools:common:26.2.1:common-26.2.1.jar:a50aab2d6411ff68f4004a87c7e93d87d8e980a0ec3b352246549897ea2d78e5',
|
'com.android.tools:repository:26.3.2:repository-26.3.2.jar:da611eeb06e9ab8750d25b9e2901e10db8e5ec6304eb4c8b7103d39e0921ea40',
|
||||||
'com.android.tools:dvlib:26.2.1:dvlib-26.2.1.jar:72a83bf2839b1df9b1fbf67ba45d1bfb9f966cd774da4320c762b2be8f1688aa',
|
'com.android.tools:sdk-common:26.3.2:sdk-common-26.3.2.jar:82823a3bf25e64fac33a286490f0cf5ac50c2cdb3c540149b030896bb44bf96c',
|
||||||
'com.android.tools:repository:26.2.1:repository-26.2.1.jar:fa74dae09103faef703df38550ad8fa244c5b6d1bf90d6198be932292b3d9cc1',
|
'com.android.tools:sdklib:26.3.2:sdklib-26.3.2.jar:424d15492af67321900963238646d27495ab60de2a5b19e6a416963bc5d6932b',
|
||||||
'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.0.2:dagger-compiler-2.0.2.jar:b74bc9de063dd4c6400b232231f2ef5056145b8fbecbf5382012007dd1c071b3',
|
'com.google.dagger:dagger-compiler:2.19:dagger-compiler-2.19.jar:27a4b202a2de908182edb261f8c0a264e08e5e4733d7514bc7fbf0d31da5c0fc',
|
||||||
'com.google.dagger:dagger-producers:2.0-beta:dagger-producers-2.0-beta.jar:99ec15e8a0507ba569e7655bc1165ee5e5ca5aa914b3c8f7e2c2458f724edd6b',
|
'com.google.dagger:dagger-producers:2.19:dagger-producers-2.19.jar:a17663abe0fc38b676026950907d4c5f5e2bf338375415861eaff6e3bdb0b768',
|
||||||
'com.google.dagger:dagger:2.0.2:dagger-2.0.2.jar:84c0282ed8be73a29e0475d639da030b55dee72369e58dd35ae7d4fe6243dcf9',
|
'com.google.dagger:dagger-spi:2.19:dagger-spi-2.19.jar:e7a6379d82c841f6aac2866948ad1eed716528707814602842a8d844ce04e2e1',
|
||||||
'com.google.errorprone:error_prone_annotations:2.0.18:error_prone_annotations-2.0.18.jar:cb4cfad870bf563a07199f3ebea5763f0dec440fcda0b318640b1feaa788656b',
|
'com.google.dagger:dagger:2.19:dagger-2.19.jar:514b6f1e0727c6572e1d65cb27e4ae668b7aeaeb93a29515182965265b609939',
|
||||||
'com.google.guava:guava:18.0:guava-18.0.jar:d664fbfc03d2e5ce9cab2a44fb01f1d0bf9dfebeccc1a473b1f9ea31f79f6f99',
|
'com.google.errorprone:error_prone_annotations:2.1.3:error_prone_annotations-2.1.3.jar:03d0329547c13da9e17c634d1049ea2ead093925e290567e1a364fd6b1fc7ff8',
|
||||||
'com.google.guava:guava:23.0:guava-23.0.jar:7baa80df284117e5b945b19b98d367a85ea7b7801bd358ff657946c3bd1b6596',
|
'com.google.errorprone:javac-shaded:9-dev-r4023-3:javac-shaded-9-dev-r4023-3.jar:65bfccf60986c47fbc17c9ebab0be626afc41741e0a6ec7109e0768817a36f30',
|
||||||
|
'com.google.googlejavaformat:google-java-format:1.5:google-java-format-1.5.jar:aa19ad7850fb85178aa22f2fddb163b84d6ce4d0035872f30d4408195ca1144e',
|
||||||
|
'com.google.guava:guava:25.0-jre:guava-25.0-jre.jar:3fd4341776428c7e0e5c18a7c10de129475b69ab9d30aeafbb5c277bb6074fa9',
|
||||||
|
'com.google.guava:guava:26.0-jre:guava-26.0-jre.jar:a0e9cabad665bc20bcd2b01f108e5fc03f756e13aea80abaadb9f407033bea2c',
|
||||||
'com.google.j2objc:j2objc-annotations:1.1:j2objc-annotations-1.1.jar:40ceb7157feb263949e0f503fe5f71689333a621021aa20ce0d0acee3badaa0f',
|
'com.google.j2objc:j2objc-annotations:1.1:j2objc-annotations-1.1.jar:40ceb7157feb263949e0f503fe5f71689333a621021aa20ce0d0acee3badaa0f',
|
||||||
'com.google.jimfs:jimfs:1.1:jimfs-1.1.jar:c4828e28d7c0a930af9387510b3bada7daa5c04d7c25a75c7b8b081f1c257ddd',
|
'com.google.jimfs:jimfs:1.1:jimfs-1.1.jar:c4828e28d7c0a930af9387510b3bada7daa5c04d7c25a75c7b8b081f1c257ddd',
|
||||||
'com.google.protobuf:protobuf-java:3.4.0:protobuf-java-3.4.0.jar:dce7e66b32456a1b1198da0caff3a8acb71548658391e798c79369241e6490a4',
|
'com.google.protobuf:protobuf-java:3.4.0:protobuf-java-3.4.0.jar:dce7e66b32456a1b1198da0caff3a8acb71548658391e798c79369241e6490a4',
|
||||||
'com.googlecode.json-simple:json-simple:1.1:json-simple-1.1.jar:2d9484f4c649f708f47f9a479465fc729770ee65617dca3011836602264f6439',
|
'com.googlecode.json-simple:json-simple:1.1:json-simple-1.1.jar:2d9484f4c649f708f47f9a479465fc729770ee65617dca3011836602264f6439',
|
||||||
|
'com.squareup:javapoet:1.11.1:javapoet-1.11.1.jar:9cbf2107be499ec6e95afd36b58e3ca122a24166cdd375732e51267d64058e90',
|
||||||
'com.squareup:javawriter:2.5.0:javawriter-2.5.0.jar:fcfb09fb0ea0aa97d3cfe7ea792398081348e468f126b3603cb3803f240197f0',
|
'com.squareup:javawriter:2.5.0:javawriter-2.5.0.jar:fcfb09fb0ea0aa97d3cfe7ea792398081348e468f126b3603cb3803f240197f0',
|
||||||
'com.sun.activation:javax.activation:1.2.0:javax.activation-1.2.0.jar:993302b16cd7056f21e779cc577d175a810bb4900ef73cd8fbf2b50f928ba9ce',
|
'com.sun.activation:javax.activation:1.2.0:javax.activation-1.2.0.jar:993302b16cd7056f21e779cc577d175a810bb4900ef73cd8fbf2b50f928ba9ce',
|
||||||
'com.sun.istack:istack-commons-runtime:2.21:istack-commons-runtime-2.21.jar:c33e67a0807095f02a0e2da139412dd7c4f9cc1a4c054b3e434f96831ba950f4',
|
'com.sun.istack:istack-commons-runtime:2.21:istack-commons-runtime-2.21.jar:c33e67a0807095f02a0e2da139412dd7c4f9cc1a4c054b3e434f96831ba950f4',
|
||||||
@@ -63,19 +66,22 @@ 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:tor-android:0.3.4.8:tor-android-0.3.4.8.zip:989a0352d9d8d8172cd6c2137654e165e5d2beb10ed1211bab3814e224ad1926',
|
'org.briarproject:obfs4proxy-android:0.0.9:obfs4proxy-android-0.0.9.zip:9b7e9181535ea8d8bbe8ae6338e08cf4c5fc1e357a779393e0ce49586d459ae0',
|
||||||
'org.codehaus.groovy:groovy-all:2.4.12:groovy-all-2.4.12.jar:6a56af4bd48903d56bec62821876cadefafd007360cc6bd0d8f7aa8d72b38be4',
|
'org.briarproject:tor-android:0.3.5.8:tor-android-0.3.5.8.zip:42a13a6f185be1a62f42e3f30ce66a3c099ac5ec890a65e7593111b65b44a54a',
|
||||||
|
'org.checkerframework:checker-compat-qual:2.5.3:checker-compat-qual-2.5.3.jar:d76b9afea61c7c082908023f0cbc1427fab9abd2df915c8b8a3e7a509bccbc6d',
|
||||||
|
'org.checkerframework:checker-qual:2.5.2:checker-qual-2.5.2.jar:64b02691c8b9d4e7700f8ee2e742dce7ea2c6e81e662b7522c9ee3bf568c040a',
|
||||||
|
'org.codehaus.groovy:groovy-all:2.4.15:groovy-all-2.4.15.jar:51d6c4e71782e85674239189499854359d380fb75e1a703756e3aaa5b98a5af0',
|
||||||
'org.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.2.0:kotlin-reflect-1.2.0.jar:4f48a872bad6e4d9c053f4ad610d11e4012ad7e58dc19a03dd5eb811f36069dd',
|
'org.jetbrains.kotlin:kotlin-reflect:1.3.21:kotlin-reflect-1.3.21.jar:a3065c822633191e0a3e3ee12a29bec234fc4b2864a6bb87ef48cce3e9e0c26a',
|
||||||
'org.jetbrains.kotlin:kotlin-stdlib-common:1.2.71:kotlin-stdlib-common-1.2.71.jar:63999687ff2fce8a592dd180ffbbf8f1d21c26b4044c55cdc74ff3cf3b3cf328',
|
'org.jetbrains.kotlin:kotlin-stdlib-common:1.3.21:kotlin-stdlib-common-1.3.21.jar:cea61f7b611895e64f58569a9757fc0ab0d582f107211e1930e0ce2a0add52a7',
|
||||||
'org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.2.71:kotlin-stdlib-jdk7-1.2.71.jar:b136bd61b240e07d4d92ce00d3bd1dbf584400a7bf5f220c2f3cd22446858082',
|
'org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.3.21:kotlin-stdlib-jdk7-1.3.21.jar:a87875604fd42140da6938ae4d35ee61081f4482536efc6d2615b8b626a198af',
|
||||||
'org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.2.71:kotlin-stdlib-jdk8-1.2.71.jar:ac3c8abf47790b64b4f7e2509a53f0c145e061ac1612a597520535d199946ea9',
|
'org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.3.21:kotlin-stdlib-jdk8-1.3.21.jar:5823ed66ac122a1c55442ebca5a209a843ccd87f562edc31a787f3d2e47f74d4',
|
||||||
'org.jetbrains.kotlin:kotlin-stdlib:1.2.71:kotlin-stdlib-1.2.71.jar:4c895c270b87f5fec2a2796e1d89c15407ee821de961527c28588bb46afbc68b',
|
'org.jetbrains.kotlin:kotlin-stdlib:1.3.21:kotlin-stdlib-1.3.21.jar:38ba2370d9f06f50433e06b2ca775b94473c2e2785f410926079ab793c72b034',
|
||||||
'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',
|
||||||
|
|||||||
@@ -7,15 +7,13 @@ apply plugin: 'witness'
|
|||||||
apply from: 'witness.gradle'
|
apply from: 'witness.gradle'
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
implementation "com.google.dagger:dagger:2.0.2"
|
implementation "com.google.dagger:dagger:2.19"
|
||||||
implementation 'com.google.code.findbugs:jsr305:3.0.2'
|
implementation 'com.google.code.findbugs:jsr305:3.0.2'
|
||||||
|
|
||||||
testImplementation 'junit:junit:4.12'
|
testImplementation 'junit:junit:4.12'
|
||||||
testImplementation "org.jmock:jmock:2.8.2"
|
testImplementation "org.jmock:jmock:2.8.2"
|
||||||
testImplementation "org.jmock:jmock-junit4:2.8.2"
|
testImplementation "org.jmock:jmock-junit4:2.8.2"
|
||||||
testImplementation "org.jmock:jmock-legacy:2.8.2"
|
testImplementation "org.jmock:jmock-legacy:2.8.2"
|
||||||
testImplementation "org.hamcrest:hamcrest-library:1.3"
|
|
||||||
testImplementation "org.hamcrest:hamcrest-core:1.3"
|
|
||||||
|
|
||||||
signature 'org.codehaus.mojo.signature:java16:1.1@signature'
|
signature 'org.codehaus.mojo.signature:java16:1.1@signature'
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,26 @@
|
|||||||
|
package org.briarproject.bramble.api;
|
||||||
|
|
||||||
|
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||||
|
|
||||||
|
import javax.annotation.concurrent.Immutable;
|
||||||
|
|
||||||
|
@Immutable
|
||||||
|
@NotNullByDefault
|
||||||
|
public class Pair<A, B> {
|
||||||
|
|
||||||
|
private final A first;
|
||||||
|
private final B second;
|
||||||
|
|
||||||
|
public Pair(A first, B second) {
|
||||||
|
this.first = first;
|
||||||
|
this.second = second;
|
||||||
|
}
|
||||||
|
|
||||||
|
public A getFirst() {
|
||||||
|
return first;
|
||||||
|
}
|
||||||
|
|
||||||
|
public B getSecond() {
|
||||||
|
return second;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
package org.briarproject.bramble.api.battery;
|
||||||
|
|
||||||
|
public interface BatteryManager {
|
||||||
|
|
||||||
|
boolean isCharging();
|
||||||
|
}
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
package org.briarproject.bramble.api.battery.event;
|
||||||
|
|
||||||
|
import org.briarproject.bramble.api.event.Event;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An event that is broadcast when the device starts or stops charging.
|
||||||
|
*/
|
||||||
|
public class BatteryEvent extends Event {
|
||||||
|
|
||||||
|
private final boolean charging;
|
||||||
|
|
||||||
|
public BatteryEvent(boolean charging) {
|
||||||
|
this.charging = charging;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isCharging() {
|
||||||
|
return charging;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,7 +1,6 @@
|
|||||||
package org.briarproject.briar.client;
|
package org.briarproject.bramble.api.client;
|
||||||
|
|
||||||
import org.briarproject.bramble.api.FormatException;
|
import org.briarproject.bramble.api.FormatException;
|
||||||
import org.briarproject.bramble.api.client.ClientHelper;
|
|
||||||
import org.briarproject.bramble.api.data.BdfDictionary;
|
import org.briarproject.bramble.api.data.BdfDictionary;
|
||||||
import org.briarproject.bramble.api.data.BdfList;
|
import org.briarproject.bramble.api.data.BdfList;
|
||||||
import org.briarproject.bramble.api.data.MetadataParser;
|
import org.briarproject.bramble.api.data.MetadataParser;
|
||||||
@@ -12,7 +11,7 @@ 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.sync.InvalidMessageException;
|
import org.briarproject.bramble.api.sync.InvalidMessageException;
|
||||||
import org.briarproject.bramble.api.sync.Message;
|
import org.briarproject.bramble.api.sync.Message;
|
||||||
import org.briarproject.bramble.api.sync.ValidationManager.IncomingMessageHook;
|
import org.briarproject.bramble.api.sync.validation.IncomingMessageHook;
|
||||||
|
|
||||||
import javax.annotation.concurrent.Immutable;
|
import javax.annotation.concurrent.Immutable;
|
||||||
|
|
||||||
@@ -62,5 +61,4 @@ public abstract class BdfIncomingMessageHook implements IncomingMessageHook {
|
|||||||
throw new InvalidMessageException(e);
|
throw new InvalidMessageException(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -9,7 +9,7 @@ import org.briarproject.bramble.api.sync.Group;
|
|||||||
import org.briarproject.bramble.api.sync.InvalidMessageException;
|
import org.briarproject.bramble.api.sync.InvalidMessageException;
|
||||||
import org.briarproject.bramble.api.sync.Message;
|
import org.briarproject.bramble.api.sync.Message;
|
||||||
import org.briarproject.bramble.api.sync.MessageContext;
|
import org.briarproject.bramble.api.sync.MessageContext;
|
||||||
import org.briarproject.bramble.api.sync.ValidationManager.MessageValidator;
|
import org.briarproject.bramble.api.sync.validation.MessageValidator;
|
||||||
import org.briarproject.bramble.api.system.Clock;
|
import org.briarproject.bramble.api.system.Clock;
|
||||||
|
|
||||||
import java.util.logging.Logger;
|
import java.util.logging.Logger;
|
||||||
|
|||||||
@@ -18,11 +18,10 @@ 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);
|
Contact contact, AuthorId local);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 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,24 +16,28 @@ 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;
|
||||||
private final boolean verified, active;
|
@Nullable
|
||||||
|
private final byte[] handshakePublicKey;
|
||||||
|
private final boolean verified;
|
||||||
|
|
||||||
public Contact(ContactId id, Author author, AuthorId localAuthorId,
|
public Contact(ContactId id, Author author, @Nullable String alias,
|
||||||
@Nullable String alias, boolean verified, boolean active) {
|
@Nullable byte[] handshakePublicKey, boolean verified) {
|
||||||
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() {
|
||||||
@@ -44,21 +48,18 @@ public class Contact {
|
|||||||
return author;
|
return author;
|
||||||
}
|
}
|
||||||
|
|
||||||
public AuthorId getLocalAuthorId() {
|
|
||||||
return localAuthorId;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
public String getAlias() {
|
public String getAlias() {
|
||||||
return alias;
|
return alias;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isVerified() {
|
@Nullable
|
||||||
return verified;
|
public byte[] getHandshakePublicKey() {
|
||||||
|
return handshakePublicKey;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isActive() {
|
public boolean isVerified() {
|
||||||
return active;
|
return verified;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -1,20 +0,0 @@
|
|||||||
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,31 +18,30 @@ public interface ContactExchangeTask {
|
|||||||
byte PROTOCOL_VERSION = 1;
|
byte PROTOCOL_VERSION = 1;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Label for deriving Alice's header key from the master secret.
|
* Label for deriving Alice's header key from the master key.
|
||||||
*/
|
*/
|
||||||
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 secret.
|
* Label for deriving Bob's header key from the master key.
|
||||||
*/
|
*/
|
||||||
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 secret.
|
* Label for deriving Alice's key binding nonce from the master key.
|
||||||
*/
|
*/
|
||||||
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 secret.
|
* Label for deriving Bob's key binding nonce from the master key.
|
||||||
*/
|
*/
|
||||||
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(ContactExchangeListener listener,
|
void startExchange(LocalAuthor localAuthor, SecretKey masterKey,
|
||||||
LocalAuthor localAuthor, SecretKey masterSecret,
|
|
||||||
DuplexTransportConnection conn, TransportId transportId,
|
DuplexTransportConnection conn, TransportId transportId,
|
||||||
boolean alice);
|
boolean alice);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,61 +24,80 @@ public interface ContactManager {
|
|||||||
void registerContactHook(ContactHook hook);
|
void registerContactHook(ContactHook hook);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Stores a contact associated with the given local and remote pseudonyms,
|
* Stores a contact with the given pseudonym, derives and stores transport
|
||||||
* derives and stores transport keys for each transport, and returns an ID
|
* keys for each transport, and returns an ID for the contact.
|
||||||
* 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 remote, AuthorId local,
|
ContactId addContact(Transaction txn, Author a, SecretKey rootKey,
|
||||||
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.
|
||||||
|
*/
|
||||||
|
String getRemoteContactLink();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns true if the given link is syntactically valid.
|
||||||
|
*/
|
||||||
|
boolean isValidRemoteContactLink(String link);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Requests a new contact to be added via the given {@code link}.
|
||||||
|
*
|
||||||
|
* @param link The link received from the contact we want to add.
|
||||||
|
* @param alias The alias the user has given this contact.
|
||||||
|
* @return A PendingContact representing the contact to be added.
|
||||||
|
*/
|
||||||
|
PendingContact addRemoteContactRequest(String link, String alias);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a list of {@link PendingContact}s.
|
||||||
|
*/
|
||||||
|
Collection<PendingContact> getPendingContacts();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes a {@link PendingContact} that is in state
|
||||||
|
* {@link PendingContactState FAILED}.
|
||||||
|
*/
|
||||||
|
void removePendingContact(PendingContact pendingContact);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the contact with the given ID.
|
* Returns the contact with the given ID.
|
||||||
*/
|
*/
|
||||||
Contact getContact(ContactId c) throws DbException;
|
Contact getContact(ContactId c) throws DbException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the contact with the given remoteAuthorId
|
* Returns the contact with the given ID.
|
||||||
* that was added by the LocalAuthor with the given localAuthorId
|
|
||||||
*
|
|
||||||
* @throws org.briarproject.bramble.api.db.NoSuchContactException
|
|
||||||
*/
|
*/
|
||||||
Contact getContact(AuthorId remoteAuthorId, AuthorId localAuthorId)
|
Contact getContact(AuthorId a) throws DbException;
|
||||||
throws DbException;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the contact with the given remoteAuthorId
|
* Returns the contact with the given ID.
|
||||||
* that was added by the LocalAuthor with the given localAuthorId
|
|
||||||
*
|
|
||||||
* @throws org.briarproject.bramble.api.db.NoSuchContactException
|
|
||||||
*/
|
*/
|
||||||
Contact getContact(Transaction txn, AuthorId remoteAuthorId,
|
Contact getContact(Transaction txn, AuthorId a) throws DbException;
|
||||||
AuthorId localAuthorId) throws DbException;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns all active contacts.
|
* Returns all active contacts.
|
||||||
*/
|
*/
|
||||||
Collection<Contact> getActiveContacts() throws DbException;
|
Collection<Contact> getContacts() throws DbException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Removes a contact and all associated state.
|
* Removes a contact and all associated state.
|
||||||
@@ -91,9 +110,9 @@ 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.
|
* Sets an alias name for the contact or unsets it if alias is null.
|
||||||
*/
|
*/
|
||||||
void setContactActive(Transaction txn, ContactId c, boolean active)
|
void setContactAlias(Transaction txn, ContactId c, @Nullable String alias)
|
||||||
throws DbException;
|
throws DbException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -103,16 +122,14 @@ public interface ContactManager {
|
|||||||
throws DbException;
|
throws DbException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return true if a contact with this name and public key already exists
|
* Returns true if a contact with this pseudonym already exists.
|
||||||
*/
|
*/
|
||||||
boolean contactExists(Transaction txn, AuthorId remoteAuthorId,
|
boolean contactExists(Transaction txn, AuthorId a) throws DbException;
|
||||||
AuthorId localAuthorId) throws DbException;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return true if a contact with this name and public key already exists
|
* Returns true if a contact with this pseudonym already exists.
|
||||||
*/
|
*/
|
||||||
boolean contactExists(AuthorId remoteAuthorId, AuthorId localAuthorId)
|
boolean contactExists(AuthorId a) throws DbException;
|
||||||
throws DbException;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the {@link AuthorInfo} for the given author.
|
* Returns the {@link AuthorInfo} for the given author.
|
||||||
|
|||||||
@@ -0,0 +1,56 @@
|
|||||||
|
package org.briarproject.bramble.api.contact;
|
||||||
|
|
||||||
|
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||||
|
|
||||||
|
import javax.annotation.concurrent.Immutable;
|
||||||
|
|
||||||
|
@Immutable
|
||||||
|
@NotNullByDefault
|
||||||
|
public class PendingContact {
|
||||||
|
|
||||||
|
private final PendingContactId id;
|
||||||
|
private final byte[] publicKey;
|
||||||
|
private final String alias;
|
||||||
|
private final PendingContactState state;
|
||||||
|
private final long timestamp;
|
||||||
|
|
||||||
|
public PendingContact(PendingContactId id, byte[] publicKey,
|
||||||
|
String alias, PendingContactState state, long timestamp) {
|
||||||
|
this.id = id;
|
||||||
|
this.publicKey = publicKey;
|
||||||
|
this.alias = alias;
|
||||||
|
this.state = state;
|
||||||
|
this.timestamp = timestamp;
|
||||||
|
}
|
||||||
|
|
||||||
|
public PendingContactId getId() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte[] getPublicKey() {
|
||||||
|
return publicKey;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getAlias() {
|
||||||
|
return alias;
|
||||||
|
}
|
||||||
|
|
||||||
|
public PendingContactState getState() {
|
||||||
|
return state;
|
||||||
|
}
|
||||||
|
|
||||||
|
public long getTimestamp() {
|
||||||
|
return timestamp;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
return id.hashCode();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object o) {
|
||||||
|
return o instanceof PendingContact &&
|
||||||
|
id.equals(((PendingContact) o).id);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
package org.briarproject.bramble.api.contact;
|
||||||
|
|
||||||
|
import org.briarproject.bramble.api.UniqueId;
|
||||||
|
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||||
|
|
||||||
|
import javax.annotation.concurrent.ThreadSafe;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Type-safe wrapper for a byte array that uniquely identifies a
|
||||||
|
* {@link PendingContact}.
|
||||||
|
*/
|
||||||
|
@ThreadSafe
|
||||||
|
@NotNullByDefault
|
||||||
|
public class PendingContactId extends UniqueId {
|
||||||
|
|
||||||
|
public PendingContactId(byte[] id) {
|
||||||
|
super(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object o) {
|
||||||
|
return o instanceof PendingContactId && super.equals(o);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,30 @@
|
|||||||
|
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,18 +14,12 @@ 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, boolean active) {
|
public ContactAddedEvent(ContactId contactId) {
|
||||||
this.contactId = contactId;
|
this.contactId = contactId;
|
||||||
this.active = active;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public ContactId getContactId() {
|
public ContactId getContactId() {
|
||||||
return contactId;
|
return contactId;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isActive() {
|
|
||||||
return active;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,32 @@
|
|||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -1,31 +0,0 @@
|
|||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,34 @@
|
|||||||
|
package org.briarproject.bramble.api.contact.event;
|
||||||
|
|
||||||
|
import org.briarproject.bramble.api.contact.PendingContactId;
|
||||||
|
import org.briarproject.bramble.api.contact.PendingContactState;
|
||||||
|
import org.briarproject.bramble.api.event.Event;
|
||||||
|
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||||
|
|
||||||
|
import javax.annotation.concurrent.Immutable;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An event that is broadcast when a pending contact's state is changed.
|
||||||
|
*/
|
||||||
|
@Immutable
|
||||||
|
@NotNullByDefault
|
||||||
|
public class PendingContactStateChangedEvent extends Event {
|
||||||
|
|
||||||
|
private final PendingContactId id;
|
||||||
|
private final PendingContactState state;
|
||||||
|
|
||||||
|
public PendingContactStateChangedEvent(PendingContactId id,
|
||||||
|
PendingContactState state) {
|
||||||
|
this.id = id;
|
||||||
|
this.state = state;
|
||||||
|
}
|
||||||
|
|
||||||
|
public PendingContactId getId() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public PendingContactState getPendingContactState() {
|
||||||
|
return state;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -2,7 +2,7 @@ package org.briarproject.bramble.api.crypto;
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Crypto operations for the key agreement protocol - see
|
* Crypto operations for the key agreement protocol - see
|
||||||
* https://code.briarproject.org/akwizgran/briar-spec/blob/master/protocols/BQP.md
|
* https://code.briarproject.org/briar/briar-spec/blob/master/protocols/BQP.md
|
||||||
*/
|
*/
|
||||||
public interface KeyAgreementCrypto {
|
public interface KeyAgreementCrypto {
|
||||||
|
|
||||||
|
|||||||
@@ -1,29 +1,45 @@
|
|||||||
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/akwizgran/briar-spec/blob/master/protocols/BTP.md
|
* https://code.briarproject.org/briar/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
|
||||||
* rotation period from the given master secret.
|
* time period from the given root key.
|
||||||
*
|
*
|
||||||
* @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 master,
|
TransportKeys deriveTransportKeys(TransportId t, SecretKey rootKey,
|
||||||
long rotationPeriod, boolean alice, boolean active);
|
long timePeriod, boolean alice, boolean active);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Rotates the given transport keys to the given rotation period. If the
|
* Rotates the given transport keys to the given time period. If the keys
|
||||||
* keys are for the given period or any later period they are not rotated.
|
* are for the given period or any later period they are not rotated.
|
||||||
*/
|
*/
|
||||||
TransportKeys rotateTransportKeys(TransportKeys k, long rotationPeriod);
|
TransportKeys rotateTransportKeys(TransportKeys k, long timePeriod);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Derives handshake keys for the given transport in the given time period
|
||||||
|
* from the given root key.
|
||||||
|
*
|
||||||
|
* @param alice whether the keys are for use by Alice or Bob.
|
||||||
|
*/
|
||||||
|
HandshakeKeys deriveHandshakeKeys(TransportId t, SecretKey rootKey,
|
||||||
|
long timePeriod, boolean alice);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Updates the given handshake keys to the given time period. If the keys
|
||||||
|
* are for the given period or any later period they are not updated.
|
||||||
|
*/
|
||||||
|
HandshakeKeys updateHandshakeKeys(HandshakeKeys k, long timePeriod);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Encodes the pseudo-random tag that is used to recognise a stream.
|
* Encodes the pseudo-random tag that is used to recognise a stream.
|
||||||
|
|||||||
@@ -0,0 +1,71 @@
|
|||||||
|
package org.briarproject.bramble.api.data;
|
||||||
|
|
||||||
|
import org.briarproject.bramble.api.Bytes;
|
||||||
|
import org.briarproject.bramble.api.FormatException;
|
||||||
|
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Map.Entry;
|
||||||
|
|
||||||
|
import javax.annotation.Nullable;
|
||||||
|
|
||||||
|
import static org.briarproject.bramble.api.data.BdfDictionary.NULL_VALUE;
|
||||||
|
import static org.briarproject.bramble.util.StringUtils.toHexString;
|
||||||
|
|
||||||
|
@NotNullByDefault
|
||||||
|
public class BdfStringUtils {
|
||||||
|
|
||||||
|
public static String toString(@Nullable Object o) throws FormatException {
|
||||||
|
return toString(o, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static String toString(@Nullable Object o, int indent)
|
||||||
|
throws FormatException {
|
||||||
|
if (o == null || o == NULL_VALUE) return "null";
|
||||||
|
if (o instanceof Boolean) return o.toString();
|
||||||
|
if (o instanceof Number) return o.toString();
|
||||||
|
if (o instanceof String) return "\"" + o + "\"";
|
||||||
|
if (o instanceof Bytes)
|
||||||
|
return "x" + toHexString(((Bytes) o).getBytes());
|
||||||
|
if (o instanceof byte[])
|
||||||
|
return "x" + toHexString((byte[]) o);
|
||||||
|
if (o instanceof List) {
|
||||||
|
List<?> list = (List) o;
|
||||||
|
StringBuilder sb = new StringBuilder();
|
||||||
|
sb.append("[\n");
|
||||||
|
int i = 0, size = list.size();
|
||||||
|
for (Object e : list) {
|
||||||
|
indent(sb, indent + 1);
|
||||||
|
sb.append(toString(e, indent + 1));
|
||||||
|
if (i++ < size - 1) sb.append(',');
|
||||||
|
sb.append('\n');
|
||||||
|
}
|
||||||
|
indent(sb, indent);
|
||||||
|
sb.append(']');
|
||||||
|
return sb.toString();
|
||||||
|
}
|
||||||
|
if (o instanceof Map) {
|
||||||
|
Map<?, ?> map = (Map) o;
|
||||||
|
StringBuilder sb = new StringBuilder();
|
||||||
|
sb.append("{\n");
|
||||||
|
int i = 0, size = map.size();
|
||||||
|
for (Entry e : map.entrySet()) {
|
||||||
|
indent(sb, indent + 1);
|
||||||
|
sb.append(toString(e.getKey(), indent + 1));
|
||||||
|
sb.append(": ");
|
||||||
|
sb.append(toString(e.getValue(), indent + 1));
|
||||||
|
if (i++ < size - 1) sb.append(',');
|
||||||
|
sb.append('\n');
|
||||||
|
}
|
||||||
|
indent(sb, indent);
|
||||||
|
sb.append('}');
|
||||||
|
return sb.toString();
|
||||||
|
}
|
||||||
|
throw new FormatException();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void indent(StringBuilder sb, int indent) {
|
||||||
|
for (int i = 0; i < indent; i++) sb.append('\t');
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
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,6 +2,8 @@ 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;
|
||||||
@@ -19,8 +21,12 @@ import org.briarproject.bramble.api.sync.MessageId;
|
|||||||
import org.briarproject.bramble.api.sync.MessageStatus;
|
import org.briarproject.bramble.api.sync.MessageStatus;
|
||||||
import org.briarproject.bramble.api.sync.Offer;
|
import org.briarproject.bramble.api.sync.Offer;
|
||||||
import org.briarproject.bramble.api.sync.Request;
|
import org.briarproject.bramble.api.sync.Request;
|
||||||
import org.briarproject.bramble.api.transport.KeySet;
|
import org.briarproject.bramble.api.sync.validation.MessageState;
|
||||||
import org.briarproject.bramble.api.transport.KeySetId;
|
import org.briarproject.bramble.api.transport.HandshakeKeySet;
|
||||||
|
import org.briarproject.bramble.api.transport.HandshakeKeySetId;
|
||||||
|
import org.briarproject.bramble.api.transport.HandshakeKeys;
|
||||||
|
import org.briarproject.bramble.api.transport.TransportKeySet;
|
||||||
|
import org.briarproject.bramble.api.transport.TransportKeySetId;
|
||||||
import org.briarproject.bramble.api.transport.TransportKeys;
|
import org.briarproject.bramble.api.transport.TransportKeys;
|
||||||
|
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
@@ -28,8 +34,6 @@ import java.util.Map;
|
|||||||
|
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
|
|
||||||
import static org.briarproject.bramble.api.sync.ValidationManager.State;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Encapsulates the database implementation and exposes high-level operations
|
* Encapsulates the database implementation and exposes high-level operations
|
||||||
* to other components.
|
* to other components.
|
||||||
@@ -90,17 +94,39 @@ public interface DatabaseComponent {
|
|||||||
DbCallable<R, E> task) throws DbException, E;
|
DbCallable<R, E> task) throws DbException, E;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Stores a contact associated with the given local and remote pseudonyms,
|
* Runs the given task within a transaction and returns the result of the
|
||||||
* and returns an ID for the contact.
|
* task, which may be null.
|
||||||
*/
|
*/
|
||||||
ContactId addContact(Transaction txn, Author remote, AuthorId local,
|
@Nullable
|
||||||
boolean verified, boolean active) throws DbException;
|
<R, E extends Exception> R transactionWithNullableResult(boolean readOnly,
|
||||||
|
NullableDbCallable<R, E> task) throws DbException, E;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Stores a contact with the given pseudonym and returns an ID for the
|
||||||
|
* contact.
|
||||||
|
*/
|
||||||
|
ContactId addContact(Transaction txn, Author a, boolean verified)
|
||||||
|
throws DbException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 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.
|
||||||
*/
|
*/
|
||||||
@@ -112,6 +138,12 @@ 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.
|
||||||
*/
|
*/
|
||||||
@@ -122,27 +154,39 @@ 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.
|
||||||
*/
|
*/
|
||||||
KeySetId addTransportKeys(Transaction txn, ContactId c,
|
TransportKeySetId addTransportKeys(Transaction txn, ContactId c,
|
||||||
TransportKeys k) throws DbException;
|
TransportKeys k) throws DbException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns true if the database contains the given contact for the given
|
* Returns true if the database contains the given contact.
|
||||||
* local pseudonym.
|
* <p/>
|
||||||
|
* Read-only.
|
||||||
*/
|
*/
|
||||||
boolean containsContact(Transaction txn, AuthorId remote, AuthorId local)
|
boolean containsContact(Transaction txn, AuthorId a) throws DbException;
|
||||||
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,
|
||||||
@@ -208,6 +252,13 @@ 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/>
|
||||||
@@ -215,22 +266,6 @@ 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/>
|
||||||
@@ -262,6 +297,14 @@ 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/>
|
||||||
@@ -366,12 +409,12 @@ public interface DatabaseComponent {
|
|||||||
/**
|
/**
|
||||||
* Returns the IDs and states of all dependencies of the given message.
|
* Returns the IDs and states of all dependencies of the given message.
|
||||||
* For missing dependencies and dependencies in other groups, the state
|
* For missing dependencies and dependencies in other groups, the state
|
||||||
* {@link State UNKNOWN} is returned.
|
* {@link MessageState UNKNOWN} is returned.
|
||||||
* <p/>
|
* <p/>
|
||||||
* Read-only.
|
* Read-only.
|
||||||
*/
|
*/
|
||||||
Map<MessageId, State> getMessageDependencies(Transaction txn, MessageId m)
|
Map<MessageId, MessageState> getMessageDependencies(Transaction txn,
|
||||||
throws DbException;
|
MessageId m) throws DbException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the IDs and states of all dependents of the given message.
|
* Returns the IDs and states of all dependents of the given message.
|
||||||
@@ -380,15 +423,16 @@ public interface DatabaseComponent {
|
|||||||
* <p/>
|
* <p/>
|
||||||
* Read-only.
|
* Read-only.
|
||||||
*/
|
*/
|
||||||
Map<MessageId, State> getMessageDependents(Transaction txn, MessageId m)
|
Map<MessageId, MessageState> getMessageDependents(Transaction txn,
|
||||||
throws DbException;
|
MessageId m) throws DbException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the validation and delivery state of the given message.
|
* Gets the validation and delivery state of the given message.
|
||||||
* <p/>
|
* <p/>
|
||||||
* Read-only.
|
* Read-only.
|
||||||
*/
|
*/
|
||||||
State getMessageState(Transaction txn, MessageId m) throws DbException;
|
MessageState getMessageState(Transaction txn, MessageId m)
|
||||||
|
throws DbException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the status of the given delivered message with respect to the
|
* Returns the status of the given delivered message with respect to the
|
||||||
@@ -409,6 +453,14 @@ 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/>
|
||||||
@@ -421,14 +473,20 @@ public interface DatabaseComponent {
|
|||||||
* <p/>
|
* <p/>
|
||||||
* Read-only.
|
* Read-only.
|
||||||
*/
|
*/
|
||||||
Collection<KeySet> getTransportKeys(Transaction txn, TransportId t)
|
Collection<TransportKeySet> 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, KeySetId k)
|
void incrementStreamCounter(Transaction txn, TransportId t,
|
||||||
throws DbException;
|
TransportKeySetId k) throws DbException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Merges the given metadata with the existing metadata for the given
|
* Merges the given metadata with the existing metadata for the given
|
||||||
@@ -483,6 +541,12 @@ 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.
|
||||||
*/
|
*/
|
||||||
@@ -493,6 +557,12 @@ 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.
|
||||||
*/
|
*/
|
||||||
@@ -501,20 +571,14 @@ 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, KeySetId k)
|
void removeTransportKeys(Transaction txn, TransportId t,
|
||||||
throws DbException;
|
TransportKeySetId k) 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.
|
||||||
*/
|
*/
|
||||||
@@ -535,7 +599,7 @@ public interface DatabaseComponent {
|
|||||||
/**
|
/**
|
||||||
* Sets the validation and delivery state of the given message.
|
* Sets the validation and delivery state of the given message.
|
||||||
*/
|
*/
|
||||||
void setMessageState(Transaction txn, MessageId m, State state)
|
void setMessageState(Transaction txn, MessageId m, MessageState state)
|
||||||
throws DbException;
|
throws DbException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -545,21 +609,36 @@ public interface DatabaseComponent {
|
|||||||
Collection<MessageId> dependencies) throws DbException;
|
Collection<MessageId> dependencies) throws DbException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the reordering window for the given key set and transport in the
|
* Sets the reordering window for the given transport key set in the given
|
||||||
* given rotation period.
|
* time period.
|
||||||
*/
|
*/
|
||||||
void setReorderingWindow(Transaction txn, KeySetId k, TransportId t,
|
void setReorderingWindow(Transaction txn, TransportKeySetId k,
|
||||||
long rotationPeriod, long base, byte[] bitmap) throws DbException;
|
TransportId t, long timePeriod, long base, byte[] bitmap)
|
||||||
|
throws DbException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the reordering window for the given handshake key set in the given
|
||||||
|
* time period.
|
||||||
|
*/
|
||||||
|
void setReorderingWindow(Transaction txn, HandshakeKeySetId k,
|
||||||
|
TransportId t, long timePeriod, long base, byte[] bitmap)
|
||||||
|
throws DbException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 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, KeySetId k)
|
void setTransportKeysActive(Transaction txn, TransportId t,
|
||||||
|
TransportKeySetId k) throws DbException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Stores the given handshake keys, deleting any keys they have replaced.
|
||||||
|
*/
|
||||||
|
void updateHandshakeKeys(Transaction txn, Collection<HandshakeKeySet> keys)
|
||||||
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<KeySet> keys)
|
void updateTransportKeys(Transaction txn, Collection<TransportKeySet> keys)
|
||||||
throws DbException;
|
throws DbException;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,6 +10,4 @@ public interface DatabaseConfig {
|
|||||||
File getDatabaseDirectory();
|
File getDatabaseDirectory();
|
||||||
|
|
||||||
File getDatabaseKeyDirectory();
|
File getDatabaseKeyDirectory();
|
||||||
|
|
||||||
long getMaxSize();
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,8 @@
|
|||||||
package org.briarproject.bramble.api.db;
|
package org.briarproject.bramble.api.db;
|
||||||
|
|
||||||
|
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||||
|
|
||||||
|
@NotNullByDefault
|
||||||
public interface DbCallable<R, E extends Exception> {
|
public interface DbCallable<R, E extends Exception> {
|
||||||
|
|
||||||
R call(Transaction txn) throws DbException, E;
|
R call(Transaction txn) throws DbException, E;
|
||||||
|
|||||||
@@ -1,5 +1,8 @@
|
|||||||
package org.briarproject.bramble.api.db;
|
package org.briarproject.bramble.api.db;
|
||||||
|
|
||||||
|
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||||
|
|
||||||
|
@NotNullByDefault
|
||||||
public interface DbRunnable<E extends Exception> {
|
public interface DbRunnable<E extends Exception> {
|
||||||
|
|
||||||
void run(Transaction txn) throws DbException, E;
|
void run(Transaction txn) throws DbException, E;
|
||||||
|
|||||||
@@ -0,0 +1,24 @@
|
|||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
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 {
|
||||||
|
}
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
package org.briarproject.bramble.api.db;
|
||||||
|
|
||||||
|
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||||
|
|
||||||
|
import javax.annotation.Nullable;
|
||||||
|
|
||||||
|
@NotNullByDefault
|
||||||
|
public interface NullableDbCallable<R, E extends Exception> {
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
R call(Transaction txn) throws DbException, E;
|
||||||
|
}
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
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 {
|
||||||
|
}
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
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,13 +1,15 @@
|
|||||||
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.
|
||||||
*/
|
*/
|
||||||
@@ -17,7 +19,7 @@ public class Transaction {
|
|||||||
private final Object txn;
|
private final Object txn;
|
||||||
private final boolean readOnly;
|
private final boolean readOnly;
|
||||||
|
|
||||||
private List<Event> events = null;
|
private List<CommitAction> actions = null;
|
||||||
private boolean committed = false;
|
private boolean committed = false;
|
||||||
|
|
||||||
public Transaction(Object txn, boolean readOnly) {
|
public Transaction(Object txn, boolean readOnly) {
|
||||||
@@ -42,19 +44,27 @@ 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.
|
* committed. The event will be broadcast on the {@link EventExecutor}.
|
||||||
*/
|
*/
|
||||||
public void attach(Event e) {
|
public void attach(Event e) {
|
||||||
if (events == null) events = new ArrayList<>();
|
if (actions == null) actions = new ArrayList<>();
|
||||||
events.add(e);
|
actions.add(new EventAction(e));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns any events attached to the transaction.
|
* Attaches a task to be executed when the transaction has been
|
||||||
|
* committed. The task will be run on the {@link EventExecutor}.
|
||||||
*/
|
*/
|
||||||
public List<Event> getEvents() {
|
public void attach(Runnable r) {
|
||||||
if (events == null) return Collections.emptyList();
|
if (actions == null) actions = new ArrayList<>();
|
||||||
return events;
|
actions.add(new TaskAction(r));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns any actions attached to the transaction.
|
||||||
|
*/
|
||||||
|
public List<CommitAction> getActions() {
|
||||||
|
return actions == null ? emptyList() : actions;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -16,7 +16,8 @@ public interface EventBus {
|
|||||||
void removeListener(EventListener l);
|
void removeListener(EventListener l);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Notifies all listeners of an event.
|
* Asynchronously notifies all listeners of an event. Listeners are
|
||||||
|
* notified on the {@link EventExecutor}.
|
||||||
*/
|
*/
|
||||||
void broadcast(Event e);
|
void broadcast(Event e);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,26 @@
|
|||||||
|
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,5 +12,6 @@ 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);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,7 +10,11 @@ import javax.annotation.concurrent.Immutable;
|
|||||||
public class AuthorInfo {
|
public class AuthorInfo {
|
||||||
|
|
||||||
public enum Status {
|
public enum Status {
|
||||||
NONE, ANONYMOUS, UNKNOWN, UNVERIFIED, VERIFIED, OURSELVES
|
NONE, ANONYMOUS, UNKNOWN, UNVERIFIED, VERIFIED, OURSELVES;
|
||||||
|
|
||||||
|
public boolean isContact() {
|
||||||
|
return this == UNVERIFIED || this == VERIFIED;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private final Status status;
|
private final Status status;
|
||||||
@@ -35,4 +39,18 @@ public class AuthorInfo {
|
|||||||
return alias;
|
return alias;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
int hashCode = status.ordinal();
|
||||||
|
if (alias != null) hashCode += alias.hashCode();
|
||||||
|
return hashCode;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object o) {
|
||||||
|
if (!(o instanceof AuthorInfo)) return false;
|
||||||
|
AuthorInfo info = (AuthorInfo) o;
|
||||||
|
return status == info.status &&
|
||||||
|
(alias == null ? info.alias == null : alias.equals(info.alias));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,8 +2,11 @@ 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.
|
||||||
*/
|
*/
|
||||||
@@ -12,6 +15,8 @@ import javax.annotation.concurrent.Immutable;
|
|||||||
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,
|
||||||
@@ -19,6 +24,22 @@ 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;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -28,6 +49,22 @@ 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 secret.
|
* Label for deriving the master key.
|
||||||
*/
|
*/
|
||||||
String MASTER_SECRET_LABEL =
|
String MASTER_KEY_LABEL =
|
||||||
"org.briarproject.bramble.keyagreement/MASTER_SECRET";
|
"org.briarproject.bramble.keyagreement/MASTER_SECRET";
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,15 @@
|
|||||||
|
package org.briarproject.bramble.api.nullsafety;
|
||||||
|
|
||||||
|
import javax.annotation.Nullable;
|
||||||
|
|
||||||
|
@NotNullByDefault
|
||||||
|
public class NullSafety {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Stand-in for `Objects.requireNonNull()`.
|
||||||
|
*/
|
||||||
|
public static <T> T requireNonNull(@Nullable T t) {
|
||||||
|
if (t == null) throw new NullPointerException();
|
||||||
|
return t;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -16,6 +16,7 @@ public interface TorConstants {
|
|||||||
String PREF_TOR_NETWORK = "network2";
|
String PREF_TOR_NETWORK = "network2";
|
||||||
String PREF_TOR_PORT = "port";
|
String PREF_TOR_PORT = "port";
|
||||||
String PREF_TOR_MOBILE = "useMobileData";
|
String PREF_TOR_MOBILE = "useMobileData";
|
||||||
|
String PREF_TOR_ONLY_WHEN_CHARGING = "onlyWhenCharging";
|
||||||
|
|
||||||
int PREF_TOR_NETWORK_AUTOMATIC = 0;
|
int PREF_TOR_NETWORK_AUTOMATIC = 0;
|
||||||
int PREF_TOR_NETWORK_WITHOUT_BRIDGES = 1;
|
int PREF_TOR_NETWORK_WITHOUT_BRIDGES = 1;
|
||||||
|
|||||||
@@ -1,87 +0,0 @@
|
|||||||
package org.briarproject.bramble.api.sync;
|
|
||||||
|
|
||||||
import org.briarproject.bramble.api.crypto.SecretKey;
|
|
||||||
import org.briarproject.bramble.api.db.DbException;
|
|
||||||
import org.briarproject.bramble.api.db.Metadata;
|
|
||||||
import org.briarproject.bramble.api.db.Transaction;
|
|
||||||
import org.briarproject.bramble.api.lifecycle.LifecycleManager;
|
|
||||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Responsible for managing message validators and passing them messages to
|
|
||||||
* validate.
|
|
||||||
*/
|
|
||||||
@NotNullByDefault
|
|
||||||
public interface ValidationManager {
|
|
||||||
|
|
||||||
enum State {
|
|
||||||
|
|
||||||
UNKNOWN(0), INVALID(1), PENDING(2), DELIVERED(3);
|
|
||||||
|
|
||||||
private final int value;
|
|
||||||
|
|
||||||
State(int value) {
|
|
||||||
this.value = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getValue() {
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static State fromValue(int value) {
|
|
||||||
for (State s : values()) if (s.value == value) return s;
|
|
||||||
throw new IllegalArgumentException();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Registers the message validator for the given client. This method
|
|
||||||
* should be called before
|
|
||||||
* {@link LifecycleManager#startServices(SecretKey)}.
|
|
||||||
*/
|
|
||||||
void registerMessageValidator(ClientId c, int majorVersion,
|
|
||||||
MessageValidator v);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Registers the incoming message hook for the given client. The hook will
|
|
||||||
* be called once for each incoming message that passes validation. This
|
|
||||||
* method should be called before
|
|
||||||
* {@link LifecycleManager#startServices(SecretKey)}.
|
|
||||||
*/
|
|
||||||
void registerIncomingMessageHook(ClientId c, int majorVersion,
|
|
||||||
IncomingMessageHook hook);
|
|
||||||
|
|
||||||
interface MessageValidator {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Validates the given message and returns its metadata and
|
|
||||||
* dependencies.
|
|
||||||
*/
|
|
||||||
MessageContext validateMessage(Message m, Group g)
|
|
||||||
throws InvalidMessageException;
|
|
||||||
}
|
|
||||||
|
|
||||||
interface IncomingMessageHook {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Called once for each incoming message that passes validation.
|
|
||||||
*
|
|
||||||
* @return whether or not this message should be shared
|
|
||||||
* @throws DbException Should only be used for real database errors.
|
|
||||||
* If this is thrown, delivery will be attempted again at next startup,
|
|
||||||
* whereas if an InvalidMessageException is thrown,
|
|
||||||
* the message will be permanently invalidated.
|
|
||||||
* @throws InvalidMessageException for any non-database error
|
|
||||||
* that occurs while handling remotely created data.
|
|
||||||
* This includes errors that occur while handling locally created data
|
|
||||||
* in a context controlled by remotely created data
|
|
||||||
* (for example, parsing the metadata of a dependency
|
|
||||||
* of an incoming message).
|
|
||||||
* Throwing this will delete the incoming message and its metadata
|
|
||||||
* marking it as invalid in the database.
|
|
||||||
* Never rethrow DbException as InvalidMessageException!
|
|
||||||
*/
|
|
||||||
boolean incomingMessage(Transaction txn, Message m, Metadata meta)
|
|
||||||
throws DbException, InvalidMessageException;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -3,11 +3,10 @@ package org.briarproject.bramble.api.sync.event;
|
|||||||
import org.briarproject.bramble.api.event.Event;
|
import org.briarproject.bramble.api.event.Event;
|
||||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||||
import org.briarproject.bramble.api.sync.MessageId;
|
import org.briarproject.bramble.api.sync.MessageId;
|
||||||
|
import org.briarproject.bramble.api.sync.validation.MessageState;
|
||||||
|
|
||||||
import javax.annotation.concurrent.Immutable;
|
import javax.annotation.concurrent.Immutable;
|
||||||
|
|
||||||
import static org.briarproject.bramble.api.sync.ValidationManager.State;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An event that is broadcast when a message state changed.
|
* An event that is broadcast when a message state changed.
|
||||||
*/
|
*/
|
||||||
@@ -17,10 +16,10 @@ public class MessageStateChangedEvent extends Event {
|
|||||||
|
|
||||||
private final MessageId messageId;
|
private final MessageId messageId;
|
||||||
private final boolean local;
|
private final boolean local;
|
||||||
private final State state;
|
private final MessageState state;
|
||||||
|
|
||||||
public MessageStateChangedEvent(MessageId messageId, boolean local,
|
public MessageStateChangedEvent(MessageId messageId, boolean local,
|
||||||
State state) {
|
MessageState state) {
|
||||||
this.messageId = messageId;
|
this.messageId = messageId;
|
||||||
this.local = local;
|
this.local = local;
|
||||||
this.state = state;
|
this.state = state;
|
||||||
@@ -34,7 +33,7 @@ public class MessageStateChangedEvent extends Event {
|
|||||||
return local;
|
return local;
|
||||||
}
|
}
|
||||||
|
|
||||||
public State getState() {
|
public MessageState getState() {
|
||||||
return state;
|
return state;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,31 @@
|
|||||||
|
package org.briarproject.bramble.api.sync.validation;
|
||||||
|
|
||||||
|
import org.briarproject.bramble.api.db.DbException;
|
||||||
|
import org.briarproject.bramble.api.db.Metadata;
|
||||||
|
import org.briarproject.bramble.api.db.Transaction;
|
||||||
|
import org.briarproject.bramble.api.sync.InvalidMessageException;
|
||||||
|
import org.briarproject.bramble.api.sync.Message;
|
||||||
|
|
||||||
|
public interface IncomingMessageHook {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called once for each incoming message that passes validation.
|
||||||
|
*
|
||||||
|
* @return whether or not this message should be shared
|
||||||
|
* @throws DbException Should only be used for real database errors.
|
||||||
|
* If this is thrown, delivery will be attempted again at next startup,
|
||||||
|
* whereas if an InvalidMessageException is thrown,
|
||||||
|
* the message will be permanently invalidated.
|
||||||
|
* @throws InvalidMessageException for any non-database error
|
||||||
|
* that occurs while handling remotely created data.
|
||||||
|
* This includes errors that occur while handling locally created data
|
||||||
|
* in a context controlled by remotely created data
|
||||||
|
* (for example, parsing the metadata of a dependency
|
||||||
|
* of an incoming message).
|
||||||
|
* Throwing this will delete the incoming message and its metadata
|
||||||
|
* marking it as invalid in the database.
|
||||||
|
* Never rethrow DbException as InvalidMessageException!
|
||||||
|
*/
|
||||||
|
boolean incomingMessage(Transaction txn, Message m, Metadata meta)
|
||||||
|
throws DbException, InvalidMessageException;
|
||||||
|
}
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
package org.briarproject.bramble.api.sync.validation;
|
||||||
|
|
||||||
|
public enum MessageState {
|
||||||
|
|
||||||
|
UNKNOWN(0), INVALID(1), PENDING(2), DELIVERED(3);
|
||||||
|
|
||||||
|
private final int value;
|
||||||
|
|
||||||
|
MessageState(int value) {
|
||||||
|
this.value = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getValue() {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static MessageState fromValue(int value) {
|
||||||
|
for (MessageState s : values()) if (s.value == value) return s;
|
||||||
|
throw new IllegalArgumentException();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
package org.briarproject.bramble.api.sync.validation;
|
||||||
|
|
||||||
|
import org.briarproject.bramble.api.sync.Group;
|
||||||
|
import org.briarproject.bramble.api.sync.InvalidMessageException;
|
||||||
|
import org.briarproject.bramble.api.sync.Message;
|
||||||
|
import org.briarproject.bramble.api.sync.MessageContext;
|
||||||
|
|
||||||
|
public interface MessageValidator {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Validates the given message and returns its metadata and
|
||||||
|
* dependencies.
|
||||||
|
*/
|
||||||
|
MessageContext validateMessage(Message m, Group g)
|
||||||
|
throws InvalidMessageException;
|
||||||
|
}
|
||||||
@@ -0,0 +1,31 @@
|
|||||||
|
package org.briarproject.bramble.api.sync.validation;
|
||||||
|
|
||||||
|
import org.briarproject.bramble.api.crypto.SecretKey;
|
||||||
|
import org.briarproject.bramble.api.lifecycle.LifecycleManager;
|
||||||
|
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||||
|
import org.briarproject.bramble.api.sync.ClientId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Responsible for managing message validators and passing them messages to
|
||||||
|
* validate.
|
||||||
|
*/
|
||||||
|
@NotNullByDefault
|
||||||
|
public interface ValidationManager {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Registers the {@link MessageValidator} for the given client. This method
|
||||||
|
* should be called before
|
||||||
|
* {@link LifecycleManager#startServices(SecretKey)}.
|
||||||
|
*/
|
||||||
|
void registerMessageValidator(ClientId c, int majorVersion,
|
||||||
|
MessageValidator v);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Registers the {@link IncomingMessageHook} for the given client. The hook
|
||||||
|
* will be called once for each incoming message that passes validation.
|
||||||
|
* This method should be called before
|
||||||
|
* {@link LifecycleManager#startServices(SecretKey)}.
|
||||||
|
*/
|
||||||
|
void registerIncomingMessageHook(ClientId c, int majorVersion,
|
||||||
|
IncomingMessageHook hook);
|
||||||
|
}
|
||||||
@@ -0,0 +1,57 @@
|
|||||||
|
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();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,70 @@
|
|||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,36 @@
|
|||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,36 @@
|
|||||||
|
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,30 +1,35 @@
|
|||||||
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 rotation period.
|
* given transport in a given time period.
|
||||||
*/
|
*/
|
||||||
|
@Immutable
|
||||||
|
@NotNullByDefault
|
||||||
public class IncomingKeys {
|
public class IncomingKeys {
|
||||||
|
|
||||||
private final SecretKey tagKey, headerKey;
|
private final SecretKey tagKey, headerKey;
|
||||||
private final long rotationPeriod, windowBase;
|
private final long timePeriod, windowBase;
|
||||||
private final byte[] windowBitmap;
|
private final byte[] windowBitmap;
|
||||||
|
|
||||||
public IncomingKeys(SecretKey tagKey, SecretKey headerKey,
|
public IncomingKeys(SecretKey tagKey, SecretKey headerKey,
|
||||||
long rotationPeriod) {
|
long timePeriod) {
|
||||||
this(tagKey, headerKey, rotationPeriod, 0,
|
this(tagKey, headerKey, timePeriod, 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 rotationPeriod, long windowBase, byte[] windowBitmap) {
|
long timePeriod, long windowBase, byte[] windowBitmap) {
|
||||||
this.tagKey = tagKey;
|
this.tagKey = tagKey;
|
||||||
this.headerKey = headerKey;
|
this.headerKey = headerKey;
|
||||||
this.rotationPeriod = rotationPeriod;
|
this.timePeriod = timePeriod;
|
||||||
this.windowBase = windowBase;
|
this.windowBase = windowBase;
|
||||||
this.windowBitmap = windowBitmap;
|
this.windowBitmap = windowBitmap;
|
||||||
}
|
}
|
||||||
@@ -37,8 +42,8 @@ public class IncomingKeys {
|
|||||||
return headerKey;
|
return headerKey;
|
||||||
}
|
}
|
||||||
|
|
||||||
public long getRotationPeriod() {
|
public long getTimePeriod() {
|
||||||
return rotationPeriod;
|
return timePeriod;
|
||||||
}
|
}
|
||||||
|
|
||||||
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, KeySetId> addContact(Transaction txn, ContactId c,
|
Map<TransportId, TransportKeySetId> addContact(Transaction txn, ContactId c,
|
||||||
SecretKey master, long timestamp, boolean alice, boolean active)
|
SecretKey rootKey, 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, KeySetId> keys)
|
void activateKeys(Transaction txn, Map<TransportId, TransportKeySetId> keys)
|
||||||
throws DbException;
|
throws DbException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -1,47 +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 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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,27 +1,32 @@
|
|||||||
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 rotation period.
|
* transport in a given time period.
|
||||||
*/
|
*/
|
||||||
|
@Immutable
|
||||||
|
@NotNullByDefault
|
||||||
public class OutgoingKeys {
|
public class OutgoingKeys {
|
||||||
|
|
||||||
private final SecretKey tagKey, headerKey;
|
private final SecretKey tagKey, headerKey;
|
||||||
private final long rotationPeriod, streamCounter;
|
private final long timePeriod, streamCounter;
|
||||||
private final boolean active;
|
private final boolean active;
|
||||||
|
|
||||||
public OutgoingKeys(SecretKey tagKey, SecretKey headerKey,
|
public OutgoingKeys(SecretKey tagKey, SecretKey headerKey,
|
||||||
long rotationPeriod, boolean active) {
|
long timePeriod, boolean active) {
|
||||||
this(tagKey, headerKey, rotationPeriod, 0, active);
|
this(tagKey, headerKey, timePeriod, 0, active);
|
||||||
}
|
}
|
||||||
|
|
||||||
public OutgoingKeys(SecretKey tagKey, SecretKey headerKey,
|
public OutgoingKeys(SecretKey tagKey, SecretKey headerKey,
|
||||||
long rotationPeriod, long streamCounter, boolean active) {
|
long timePeriod, long streamCounter, boolean active) {
|
||||||
this.tagKey = tagKey;
|
this.tagKey = tagKey;
|
||||||
this.headerKey = headerKey;
|
this.headerKey = headerKey;
|
||||||
this.rotationPeriod = rotationPeriod;
|
this.timePeriod = timePeriod;
|
||||||
this.streamCounter = streamCounter;
|
this.streamCounter = streamCounter;
|
||||||
this.active = active;
|
this.active = active;
|
||||||
}
|
}
|
||||||
@@ -34,8 +39,8 @@ public class OutgoingKeys {
|
|||||||
return headerKey;
|
return headerKey;
|
||||||
}
|
}
|
||||||
|
|
||||||
public long getRotationPeriod() {
|
public long getTimePeriod() {
|
||||||
return rotationPeriod;
|
return timePeriod;
|
||||||
}
|
}
|
||||||
|
|
||||||
public long getStreamCounter() {
|
public long getStreamCounter() {
|
||||||
|
|||||||
@@ -2,8 +2,13 @@ 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,30 +82,58 @@ public interface TransportConstants {
|
|||||||
int REORDERING_WINDOW_SIZE = 32;
|
int REORDERING_WINDOW_SIZE = 32;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Label for deriving Alice's initial tag key from the master secret.
|
* Label for deriving Alice's initial tag key from the root key in
|
||||||
|
* 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 master secret.
|
* Label for deriving Bob's initial tag key from the root key in rotation
|
||||||
|
* 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 master secret.
|
* Label for deriving Alice's initial header key from the root key in
|
||||||
|
* 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 master secret.
|
* Label for deriving Bob's initial header key from the root key in
|
||||||
|
* 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 key rotation.
|
* Label for deriving the next period's key in rotation mode.
|
||||||
*/
|
*/
|
||||||
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";
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,49 @@
|
|||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -5,18 +5,19 @@ 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 set of transport
|
* Type-safe wrapper for an integer that uniquely identifies a
|
||||||
* keys within the scope of the local device.
|
* {@link TransportKeySet set of transport keys} within the scope of the local
|
||||||
|
* 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 KeySetId {
|
public class TransportKeySetId {
|
||||||
|
|
||||||
private final int id;
|
private final int id;
|
||||||
|
|
||||||
public KeySetId(int id) {
|
public TransportKeySetId(int id) {
|
||||||
this.id = id;
|
this.id = id;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -31,6 +32,7 @@ public class KeySetId {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean equals(Object o) {
|
public boolean equals(Object o) {
|
||||||
return o instanceof KeySetId && id == ((KeySetId) o).id;
|
return o instanceof TransportKeySetId &&
|
||||||
|
id == ((TransportKeySetId) o).id;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,52 +1,20 @@
|
|||||||
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.
|
|
||||||
*/
|
|
||||||
public class TransportKeys {
|
|
||||||
|
|
||||||
private final TransportId transportId;
|
/**
|
||||||
private final IncomingKeys inPrev, inCurr, inNext;
|
* Keys for communicating with a given contact over a given transport. Unlike
|
||||||
private final OutgoingKeys outCurr;
|
* {@link HandshakeKeys} these keys provide forward secrecy.
|
||||||
|
*/
|
||||||
|
@Immutable
|
||||||
|
@NotNullByDefault
|
||||||
|
public class TransportKeys extends AbstractTransportKeys {
|
||||||
|
|
||||||
public TransportKeys(TransportId transportId, IncomingKeys inPrev,
|
public TransportKeys(TransportId transportId, IncomingKeys inPrev,
|
||||||
IncomingKeys inCurr, IncomingKeys inNext, OutgoingKeys outCurr) {
|
IncomingKeys inCurr, IncomingKeys inNext, OutgoingKeys outCurr) {
|
||||||
if (inPrev.getRotationPeriod() != inCurr.getRotationPeriod() - 1)
|
super(transportId, inPrev, inCurr, inNext, outCurr);
|
||||||
throw new IllegalArgumentException();
|
|
||||||
if (inNext.getRotationPeriod() != inCurr.getRotationPeriod() + 1)
|
|
||||||
throw new IllegalArgumentException();
|
|
||||||
if (outCurr.getRotationPeriod() != inCurr.getRotationPeriod())
|
|
||||||
throw new IllegalArgumentException();
|
|
||||||
this.transportId = transportId;
|
|
||||||
this.inPrev = inPrev;
|
|
||||||
this.inCurr = inCurr;
|
|
||||||
this.inNext = inNext;
|
|
||||||
this.outCurr = outCurr;
|
|
||||||
}
|
|
||||||
|
|
||||||
public TransportId getTransportId() {
|
|
||||||
return transportId;
|
|
||||||
}
|
|
||||||
|
|
||||||
public IncomingKeys getPreviousIncomingKeys() {
|
|
||||||
return inPrev;
|
|
||||||
}
|
|
||||||
|
|
||||||
public IncomingKeys getCurrentIncomingKeys() {
|
|
||||||
return inCurr;
|
|
||||||
}
|
|
||||||
|
|
||||||
public IncomingKeys getNextIncomingKeys() {
|
|
||||||
return inNext;
|
|
||||||
}
|
|
||||||
|
|
||||||
public OutgoingKeys getCurrentOutgoingKeys() {
|
|
||||||
return outCurr;
|
|
||||||
}
|
|
||||||
|
|
||||||
public long getRotationPeriod() {
|
|
||||||
return outCurr.getRotationPeriod();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -38,6 +38,13 @@ public interface ClientVersioningManager {
|
|||||||
Visibility getClientVisibility(Transaction txn, ContactId contactId,
|
Visibility getClientVisibility(Transaction txn, ContactId contactId,
|
||||||
ClientId clientId, int majorVersion) throws DbException;
|
ClientId clientId, int majorVersion) throws DbException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the minor version of the given client that is supported by the
|
||||||
|
* given contact, or -1 if the contact does not support the client.
|
||||||
|
*/
|
||||||
|
int getClientMinorVersion(Transaction txn, ContactId contactId,
|
||||||
|
ClientId clientId, int majorVersion) throws DbException;
|
||||||
|
|
||||||
interface ClientVersioningHook {
|
interface ClientVersioningHook {
|
||||||
|
|
||||||
void onClientVisibilityChanging(Transaction txn, Contact c,
|
void onClientVisibilityChanging(Transaction txn, Contact c,
|
||||||
|
|||||||
@@ -8,12 +8,15 @@ import java.io.File;
|
|||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.io.OutputStream;
|
import java.io.OutputStream;
|
||||||
|
import java.net.ServerSocket;
|
||||||
import java.net.Socket;
|
import java.net.Socket;
|
||||||
|
import java.util.logging.Level;
|
||||||
import java.util.logging.Logger;
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
|
|
||||||
import static java.util.logging.Level.WARNING;
|
import static java.util.logging.Level.WARNING;
|
||||||
|
import static org.briarproject.bramble.util.LogUtils.logException;
|
||||||
|
|
||||||
@NotNullByDefault
|
@NotNullByDefault
|
||||||
public class IoUtils {
|
public class IoUtils {
|
||||||
@@ -54,16 +57,35 @@ public class IoUtils {
|
|||||||
out.flush();
|
out.flush();
|
||||||
out.close();
|
out.close();
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
tryToClose(in);
|
tryToClose(in, LOG, WARNING);
|
||||||
tryToClose(out);
|
tryToClose(out, LOG, WARNING);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void tryToClose(@Nullable Closeable c) {
|
public static void tryToClose(@Nullable Closeable c, Logger logger,
|
||||||
|
Level level) {
|
||||||
try {
|
try {
|
||||||
if (c != null) c.close();
|
if (c != null) c.close();
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
// We did our best
|
logException(logger, level, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void tryToClose(@Nullable Socket s, Logger logger,
|
||||||
|
Level level) {
|
||||||
|
try {
|
||||||
|
if (s != null) s.close();
|
||||||
|
} catch (IOException e) {
|
||||||
|
logException(logger, level, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void tryToClose(@Nullable ServerSocket ss, Logger logger,
|
||||||
|
Level level) {
|
||||||
|
try {
|
||||||
|
if (ss != null) ss.close();
|
||||||
|
} catch (IOException e) {
|
||||||
|
logException(logger, level, e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -10,8 +10,6 @@ public class OsUtils {
|
|||||||
@Nullable
|
@Nullable
|
||||||
private static final String os = System.getProperty("os.name");
|
private static final String os = System.getProperty("os.name");
|
||||||
@Nullable
|
@Nullable
|
||||||
private static final String version = System.getProperty("os.version");
|
|
||||||
@Nullable
|
|
||||||
private static final String vendor = System.getProperty("java.vendor");
|
private static final String vendor = System.getProperty("java.vendor");
|
||||||
|
|
||||||
public static boolean isWindows() {
|
public static boolean isWindows() {
|
||||||
|
|||||||
@@ -47,7 +47,7 @@ public class StringUtils {
|
|||||||
try {
|
try {
|
||||||
return s.getBytes("UTF-8");
|
return s.getBytes("UTF-8");
|
||||||
} catch (UnsupportedEncodingException e) {
|
} catch (UnsupportedEncodingException e) {
|
||||||
throw new RuntimeException(e);
|
throw new AssertionError(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -63,7 +63,7 @@ public class StringUtils {
|
|||||||
try {
|
try {
|
||||||
return decoder.decode(buffer).toString();
|
return decoder.decode(buffer).toString();
|
||||||
} catch (CharacterCodingException e) {
|
} catch (CharacterCodingException e) {
|
||||||
throw new RuntimeException(e);
|
throw new AssertionError(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,42 @@
|
|||||||
|
package org.briarproject.bramble.api.identity;
|
||||||
|
|
||||||
|
import org.briarproject.bramble.test.BrambleTestCase;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import static org.briarproject.bramble.api.identity.AuthorInfo.Status.NONE;
|
||||||
|
import static org.briarproject.bramble.api.identity.AuthorInfo.Status.VERIFIED;
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
import static org.junit.Assert.assertNotEquals;
|
||||||
|
|
||||||
|
public class AuthorInfoTest extends BrambleTestCase {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testEquals() {
|
||||||
|
assertEquals(
|
||||||
|
new AuthorInfo(NONE),
|
||||||
|
new AuthorInfo(NONE, null)
|
||||||
|
);
|
||||||
|
assertEquals(
|
||||||
|
new AuthorInfo(NONE, "test"),
|
||||||
|
new AuthorInfo(NONE, "test")
|
||||||
|
);
|
||||||
|
|
||||||
|
assertNotEquals(
|
||||||
|
new AuthorInfo(NONE),
|
||||||
|
new AuthorInfo(VERIFIED)
|
||||||
|
);
|
||||||
|
assertNotEquals(
|
||||||
|
new AuthorInfo(NONE, "test"),
|
||||||
|
new AuthorInfo(NONE)
|
||||||
|
);
|
||||||
|
assertNotEquals(
|
||||||
|
new AuthorInfo(NONE),
|
||||||
|
new AuthorInfo(NONE, "test")
|
||||||
|
);
|
||||||
|
assertNotEquals(
|
||||||
|
new AuthorInfo(NONE, "a"),
|
||||||
|
new AuthorInfo(NONE, "b")
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -1,6 +1,10 @@
|
|||||||
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;
|
||||||
@@ -25,6 +29,7 @@ import java.util.Random;
|
|||||||
import java.util.concurrent.atomic.AtomicInteger;
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
|
|
||||||
import static java.util.Arrays.asList;
|
import static java.util.Arrays.asList;
|
||||||
|
import static 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;
|
||||||
@@ -41,6 +46,7 @@ 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();
|
||||||
@@ -140,6 +146,35 @@ 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();
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ dependencyVerification {
|
|||||||
verify = [
|
verify = [
|
||||||
'cglib:cglib:3.2.0:cglib-3.2.0.jar:adb13bab79712ad6bdf1bd59f2a3918018a8016e722e8a357065afb9e6690861',
|
'cglib:cglib:3.2.0:cglib-3.2.0.jar:adb13bab79712ad6bdf1bd59f2a3918018a8016e722e8a357065afb9e6690861',
|
||||||
'com.google.code.findbugs:jsr305:3.0.2:jsr305-3.0.2.jar:766ad2a0783f2687962c8ad74ceecc38a28b9f72a2d085ee438b7813e928d0c7',
|
'com.google.code.findbugs:jsr305:3.0.2:jsr305-3.0.2.jar:766ad2a0783f2687962c8ad74ceecc38a28b9f72a2d085ee438b7813e928d0c7',
|
||||||
'com.google.dagger:dagger:2.0.2:dagger-2.0.2.jar:84c0282ed8be73a29e0475d639da030b55dee72369e58dd35ae7d4fe6243dcf9',
|
'com.google.dagger:dagger:2.19:dagger-2.19.jar:514b6f1e0727c6572e1d65cb27e4ae668b7aeaeb93a29515182965265b609939',
|
||||||
'javax.inject:javax.inject:1:javax.inject-1.jar:91c77044a50c481636c32d916fd89c9118a72195390452c81065080f957de7ff',
|
'javax.inject:javax.inject:1:javax.inject-1.jar:91c77044a50c481636c32d916fd89c9118a72195390452c81065080f957de7ff',
|
||||||
'junit:junit:4.12:junit-4.12.jar:59721f0805e223d84b90677887d9ff567dc534d7c502ca903c0c2b17f05c116a',
|
'junit:junit:4.12:junit-4.12.jar:59721f0805e223d84b90677887d9ff567dc534d7c502ca903c0c2b17f05c116a',
|
||||||
'org.apache.ant:ant-launcher:1.9.4:ant-launcher-1.9.4.jar:7bccea20b41801ca17bcbc909a78c835d0f443f12d639c77bd6ae3d05861608d',
|
'org.apache.ant:ant-launcher:1.9.4:ant-launcher-1.9.4.jar:7bccea20b41801ca17bcbc909a78c835d0f443f12d639c77bd6ae3d05861608d',
|
||||||
|
|||||||
@@ -3,10 +3,10 @@ sourceCompatibility = 1.8
|
|||||||
targetCompatibility = 1.8
|
targetCompatibility = 1.8
|
||||||
|
|
||||||
apply plugin: 'ru.vyarus.animalsniffer'
|
apply plugin: 'ru.vyarus.animalsniffer'
|
||||||
apply plugin: 'net.ltgt.apt'
|
|
||||||
apply plugin: 'idea'
|
apply plugin: 'idea'
|
||||||
apply plugin: 'witness'
|
apply plugin: 'witness'
|
||||||
apply from: 'witness.gradle'
|
apply from: 'witness.gradle'
|
||||||
|
apply from: '../dagger.gradle'
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
implementation project(path: ':bramble-api', configuration: 'default')
|
implementation project(path: ':bramble-api', configuration: 'default')
|
||||||
@@ -17,7 +17,7 @@ dependencies {
|
|||||||
implementation 'org.whispersystems:curve25519-java:0.5.0'
|
implementation 'org.whispersystems:curve25519-java:0.5.0'
|
||||||
implementation 'org.briarproject:jtorctl:0.3'
|
implementation 'org.briarproject:jtorctl:0.3'
|
||||||
|
|
||||||
apt 'com.google.dagger:dagger-compiler:2.0.2'
|
annotationProcessor 'com.google.dagger:dagger-compiler:2.19'
|
||||||
|
|
||||||
testImplementation project(path: ':bramble-api', configuration: 'testOutput')
|
testImplementation project(path: ':bramble-api', configuration: 'testOutput')
|
||||||
testImplementation 'org.hsqldb:hsqldb:2.3.5' // The last version that supports Java 1.6
|
testImplementation 'org.hsqldb:hsqldb:2.3.5' // The last version that supports Java 1.6
|
||||||
@@ -25,10 +25,8 @@ dependencies {
|
|||||||
testImplementation "org.jmock:jmock:2.8.2"
|
testImplementation "org.jmock:jmock:2.8.2"
|
||||||
testImplementation "org.jmock:jmock-junit4:2.8.2"
|
testImplementation "org.jmock:jmock-junit4:2.8.2"
|
||||||
testImplementation "org.jmock:jmock-legacy:2.8.2"
|
testImplementation "org.jmock:jmock-legacy:2.8.2"
|
||||||
testImplementation "org.hamcrest:hamcrest-library:1.3"
|
|
||||||
testImplementation "org.hamcrest:hamcrest-core:1.3"
|
|
||||||
|
|
||||||
testApt 'com.google.dagger:dagger-compiler:2.0.2'
|
testAnnotationProcessor 'com.google.dagger:dagger-compiler:2.19'
|
||||||
|
|
||||||
signature 'org.codehaus.mojo.signature:java16:1.1@signature'
|
signature 'org.codehaus.mojo.signature:java16:1.1@signature'
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ import org.briarproject.bramble.lifecycle.LifecycleModule;
|
|||||||
import org.briarproject.bramble.plugin.PluginModule;
|
import org.briarproject.bramble.plugin.PluginModule;
|
||||||
import org.briarproject.bramble.properties.PropertiesModule;
|
import org.briarproject.bramble.properties.PropertiesModule;
|
||||||
import org.briarproject.bramble.reporting.ReportingModule;
|
import org.briarproject.bramble.reporting.ReportingModule;
|
||||||
import org.briarproject.bramble.sync.SyncModule;
|
import org.briarproject.bramble.sync.validation.ValidationModule;
|
||||||
import org.briarproject.bramble.system.SystemModule;
|
import org.briarproject.bramble.system.SystemModule;
|
||||||
import org.briarproject.bramble.transport.TransportModule;
|
import org.briarproject.bramble.transport.TransportModule;
|
||||||
import org.briarproject.bramble.versioning.VersioningModule;
|
import org.briarproject.bramble.versioning.VersioningModule;
|
||||||
@@ -31,11 +31,11 @@ public interface BrambleCoreEagerSingletons {
|
|||||||
|
|
||||||
void inject(ReportingModule.EagerSingletons init);
|
void inject(ReportingModule.EagerSingletons init);
|
||||||
|
|
||||||
void inject(SyncModule.EagerSingletons init);
|
|
||||||
|
|
||||||
void inject(SystemModule.EagerSingletons init);
|
void inject(SystemModule.EagerSingletons init);
|
||||||
|
|
||||||
void inject(TransportModule.EagerSingletons init);
|
void inject(TransportModule.EagerSingletons init);
|
||||||
|
|
||||||
|
void inject(ValidationModule.EagerSingletons init);
|
||||||
|
|
||||||
void inject(VersioningModule.EagerSingletons init);
|
void inject(VersioningModule.EagerSingletons init);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ import org.briarproject.bramble.reporting.ReportingModule;
|
|||||||
import org.briarproject.bramble.settings.SettingsModule;
|
import org.briarproject.bramble.settings.SettingsModule;
|
||||||
import org.briarproject.bramble.socks.SocksModule;
|
import org.briarproject.bramble.socks.SocksModule;
|
||||||
import org.briarproject.bramble.sync.SyncModule;
|
import org.briarproject.bramble.sync.SyncModule;
|
||||||
|
import org.briarproject.bramble.sync.validation.ValidationModule;
|
||||||
import org.briarproject.bramble.system.SystemModule;
|
import org.briarproject.bramble.system.SystemModule;
|
||||||
import org.briarproject.bramble.transport.TransportModule;
|
import org.briarproject.bramble.transport.TransportModule;
|
||||||
import org.briarproject.bramble.versioning.VersioningModule;
|
import org.briarproject.bramble.versioning.VersioningModule;
|
||||||
@@ -47,6 +48,7 @@ import dagger.Module;
|
|||||||
SyncModule.class,
|
SyncModule.class,
|
||||||
SystemModule.class,
|
SystemModule.class,
|
||||||
TransportModule.class,
|
TransportModule.class,
|
||||||
|
ValidationModule.class,
|
||||||
VersioningModule.class
|
VersioningModule.class
|
||||||
})
|
})
|
||||||
public class BrambleCoreModule {
|
public class BrambleCoreModule {
|
||||||
@@ -60,9 +62,9 @@ public class BrambleCoreModule {
|
|||||||
c.inject(new PluginModule.EagerSingletons());
|
c.inject(new PluginModule.EagerSingletons());
|
||||||
c.inject(new PropertiesModule.EagerSingletons());
|
c.inject(new PropertiesModule.EagerSingletons());
|
||||||
c.inject(new ReportingModule.EagerSingletons());
|
c.inject(new ReportingModule.EagerSingletons());
|
||||||
c.inject(new SyncModule.EagerSingletons());
|
|
||||||
c.inject(new SystemModule.EagerSingletons());
|
c.inject(new SystemModule.EagerSingletons());
|
||||||
c.inject(new TransportModule.EagerSingletons());
|
c.inject(new TransportModule.EagerSingletons());
|
||||||
|
c.inject(new ValidationModule.EagerSingletons());
|
||||||
c.inject(new VersioningModule.EagerSingletons());
|
c.inject(new VersioningModule.EagerSingletons());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,19 @@
|
|||||||
|
package org.briarproject.bramble.battery;
|
||||||
|
|
||||||
|
import org.briarproject.bramble.api.battery.BatteryManager;
|
||||||
|
|
||||||
|
import dagger.Module;
|
||||||
|
import dagger.Provides;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Provides a default implementation of {@link BatteryManager} for systems
|
||||||
|
* without batteries.
|
||||||
|
*/
|
||||||
|
@Module
|
||||||
|
public class DefaultBatteryManagerModule {
|
||||||
|
|
||||||
|
@Provides
|
||||||
|
BatteryManager provideBatteryManager() {
|
||||||
|
return () -> false;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -82,13 +82,7 @@ class ClientHelperImpl implements ClientHelper {
|
|||||||
@Override
|
@Override
|
||||||
public void addLocalMessage(Message m, BdfDictionary metadata,
|
public void addLocalMessage(Message m, BdfDictionary metadata,
|
||||||
boolean shared) throws DbException, FormatException {
|
boolean shared) throws DbException, FormatException {
|
||||||
Transaction txn = db.startTransaction(false);
|
db.transaction(false, txn -> addLocalMessage(txn, m, metadata, shared));
|
||||||
try {
|
|
||||||
addLocalMessage(txn, m, metadata, shared);
|
|
||||||
db.commitTransaction(txn);
|
|
||||||
} finally {
|
|
||||||
db.endTransaction(txn);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -113,15 +107,7 @@ class ClientHelperImpl implements ClientHelper {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Message getMessage(MessageId m) throws DbException {
|
public Message getMessage(MessageId m) throws DbException {
|
||||||
Message message;
|
return db.transactionWithResult(true, txn -> getMessage(txn, m));
|
||||||
Transaction txn = db.startTransaction(true);
|
|
||||||
try {
|
|
||||||
message = getMessage(txn, m);
|
|
||||||
db.commitTransaction(txn);
|
|
||||||
} finally {
|
|
||||||
db.endTransaction(txn);
|
|
||||||
}
|
|
||||||
return message;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -132,15 +118,7 @@ class ClientHelperImpl implements ClientHelper {
|
|||||||
@Override
|
@Override
|
||||||
public BdfList getMessageAsList(MessageId m) throws DbException,
|
public BdfList getMessageAsList(MessageId m) throws DbException,
|
||||||
FormatException {
|
FormatException {
|
||||||
BdfList list;
|
return db.transactionWithResult(true, txn -> getMessageAsList(txn, m));
|
||||||
Transaction txn = db.startTransaction(true);
|
|
||||||
try {
|
|
||||||
list = getMessageAsList(txn, m);
|
|
||||||
db.commitTransaction(txn);
|
|
||||||
} finally {
|
|
||||||
db.endTransaction(txn);
|
|
||||||
}
|
|
||||||
return list;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -152,15 +130,8 @@ class ClientHelperImpl implements ClientHelper {
|
|||||||
@Override
|
@Override
|
||||||
public BdfDictionary getGroupMetadataAsDictionary(GroupId g)
|
public BdfDictionary getGroupMetadataAsDictionary(GroupId g)
|
||||||
throws DbException, FormatException {
|
throws DbException, FormatException {
|
||||||
BdfDictionary dictionary;
|
return db.transactionWithResult(true, txn ->
|
||||||
Transaction txn = db.startTransaction(true);
|
getGroupMetadataAsDictionary(txn, g));
|
||||||
try {
|
|
||||||
dictionary = getGroupMetadataAsDictionary(txn, g);
|
|
||||||
db.commitTransaction(txn);
|
|
||||||
} finally {
|
|
||||||
db.endTransaction(txn);
|
|
||||||
}
|
|
||||||
return dictionary;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -173,15 +144,8 @@ class ClientHelperImpl implements ClientHelper {
|
|||||||
@Override
|
@Override
|
||||||
public BdfDictionary getMessageMetadataAsDictionary(MessageId m)
|
public BdfDictionary getMessageMetadataAsDictionary(MessageId m)
|
||||||
throws DbException, FormatException {
|
throws DbException, FormatException {
|
||||||
BdfDictionary dictionary;
|
return db.transactionWithResult(true, txn ->
|
||||||
Transaction txn = db.startTransaction(true);
|
getMessageMetadataAsDictionary(txn, m));
|
||||||
try {
|
|
||||||
dictionary = getMessageMetadataAsDictionary(txn, m);
|
|
||||||
db.commitTransaction(txn);
|
|
||||||
} finally {
|
|
||||||
db.endTransaction(txn);
|
|
||||||
}
|
|
||||||
return dictionary;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -194,15 +158,8 @@ class ClientHelperImpl implements ClientHelper {
|
|||||||
@Override
|
@Override
|
||||||
public Map<MessageId, BdfDictionary> getMessageMetadataAsDictionary(
|
public Map<MessageId, BdfDictionary> getMessageMetadataAsDictionary(
|
||||||
GroupId g) throws DbException, FormatException {
|
GroupId g) throws DbException, FormatException {
|
||||||
Map<MessageId, BdfDictionary> map;
|
return db.transactionWithResult(true, txn ->
|
||||||
Transaction txn = db.startTransaction(true);
|
getMessageMetadataAsDictionary(txn, g));
|
||||||
try {
|
|
||||||
map = getMessageMetadataAsDictionary(txn, g);
|
|
||||||
db.commitTransaction(txn);
|
|
||||||
} finally {
|
|
||||||
db.endTransaction(txn);
|
|
||||||
}
|
|
||||||
return map;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -219,15 +176,8 @@ class ClientHelperImpl implements ClientHelper {
|
|||||||
public Map<MessageId, BdfDictionary> getMessageMetadataAsDictionary(
|
public Map<MessageId, BdfDictionary> getMessageMetadataAsDictionary(
|
||||||
GroupId g, BdfDictionary query) throws DbException,
|
GroupId g, BdfDictionary query) throws DbException,
|
||||||
FormatException {
|
FormatException {
|
||||||
Map<MessageId, BdfDictionary> map;
|
return db.transactionWithResult(true, txn ->
|
||||||
Transaction txn = db.startTransaction(true);
|
getMessageMetadataAsDictionary(txn, g, query));
|
||||||
try {
|
|
||||||
map = getMessageMetadataAsDictionary(txn, g, query);
|
|
||||||
db.commitTransaction(txn);
|
|
||||||
} finally {
|
|
||||||
db.endTransaction(txn);
|
|
||||||
}
|
|
||||||
return map;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -245,13 +195,7 @@ class ClientHelperImpl implements ClientHelper {
|
|||||||
@Override
|
@Override
|
||||||
public void mergeGroupMetadata(GroupId g, BdfDictionary metadata)
|
public void mergeGroupMetadata(GroupId g, BdfDictionary metadata)
|
||||||
throws DbException, FormatException {
|
throws DbException, FormatException {
|
||||||
Transaction txn = db.startTransaction(false);
|
db.transaction(false, txn -> mergeGroupMetadata(txn, g, metadata));
|
||||||
try {
|
|
||||||
mergeGroupMetadata(txn, g, metadata);
|
|
||||||
db.commitTransaction(txn);
|
|
||||||
} finally {
|
|
||||||
db.endTransaction(txn);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -263,13 +207,7 @@ class ClientHelperImpl implements ClientHelper {
|
|||||||
@Override
|
@Override
|
||||||
public void mergeMessageMetadata(MessageId m, BdfDictionary metadata)
|
public void mergeMessageMetadata(MessageId m, BdfDictionary metadata)
|
||||||
throws DbException, FormatException {
|
throws DbException, FormatException {
|
||||||
Transaction txn = db.startTransaction(false);
|
db.transaction(false, txn -> mergeMessageMetadata(txn, m, metadata));
|
||||||
try {
|
|
||||||
mergeMessageMetadata(txn, m, metadata);
|
|
||||||
db.commitTransaction(txn);
|
|
||||||
} finally {
|
|
||||||
db.endTransaction(txn);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -39,8 +39,7 @@ class ContactGroupFactoryImpl implements ContactGroupFactory {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Group createContactGroup(ClientId clientId, int majorVersion,
|
public Group createContactGroup(ClientId clientId, int majorVersion,
|
||||||
Contact contact) {
|
Contact contact, AuthorId local) {
|
||||||
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,10 +2,11 @@ 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;
|
||||||
@@ -13,7 +14,7 @@ import org.briarproject.bramble.api.data.BdfList;
|
|||||||
import org.briarproject.bramble.api.db.ContactExistsException;
|
import org.briarproject.bramble.api.db.ContactExistsException;
|
||||||
import org.briarproject.bramble.api.db.DatabaseComponent;
|
import org.briarproject.bramble.api.db.DatabaseComponent;
|
||||||
import org.briarproject.bramble.api.db.DbException;
|
import org.briarproject.bramble.api.db.DbException;
|
||||||
import org.briarproject.bramble.api.db.Transaction;
|
import org.briarproject.bramble.api.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;
|
||||||
@@ -64,6 +65,7 @@ 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;
|
||||||
@@ -72,18 +74,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 masterSecret;
|
private volatile SecretKey masterKey;
|
||||||
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, Clock clock,
|
RecordWriterFactory recordWriterFactory, EventBus eventBus,
|
||||||
ConnectionManager connectionManager, ContactManager contactManager,
|
Clock clock, ConnectionManager connectionManager,
|
||||||
|
ContactManager contactManager,
|
||||||
TransportPropertyManager transportPropertyManager,
|
TransportPropertyManager transportPropertyManager,
|
||||||
CryptoComponent crypto, StreamReaderFactory streamReaderFactory,
|
CryptoComponent crypto, StreamReaderFactory streamReaderFactory,
|
||||||
StreamWriterFactory streamWriterFactory) {
|
StreamWriterFactory streamWriterFactory) {
|
||||||
@@ -91,6 +93,7 @@ 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;
|
||||||
@@ -101,15 +104,13 @@ class ContactExchangeTaskImpl extends Thread implements ContactExchangeTask {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void startExchange(ContactExchangeListener listener,
|
public void startExchange(LocalAuthor localAuthor, SecretKey masterKey,
|
||||||
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.masterSecret = masterSecret;
|
this.masterKey = masterKey;
|
||||||
this.alice = alice;
|
this.alice = alice;
|
||||||
start();
|
start();
|
||||||
}
|
}
|
||||||
@@ -124,8 +125,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;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -135,15 +136,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);
|
||||||
listener.contactExchangeFailed();
|
eventBus.broadcast(new ContactExchangeFailedEvent());
|
||||||
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,
|
SecretKey aliceHeaderKey = crypto.deriveKey(ALICE_KEY_LABEL, masterKey,
|
||||||
masterSecret, new byte[] {PROTOCOL_VERSION});
|
new byte[] {PROTOCOL_VERSION});
|
||||||
SecretKey bobHeaderKey = crypto.deriveKey(BOB_KEY_LABEL, masterSecret,
|
SecretKey bobHeaderKey = crypto.deriveKey(BOB_KEY_LABEL, masterKey,
|
||||||
new byte[] {PROTOCOL_VERSION});
|
new byte[] {PROTOCOL_VERSION});
|
||||||
|
|
||||||
// Create the readers
|
// Create the readers
|
||||||
@@ -158,12 +159,13 @@ class ContactExchangeTaskImpl extends Thread implements ContactExchangeTask {
|
|||||||
streamWriterFactory.createContactExchangeStreamWriter(out,
|
streamWriterFactory.createContactExchangeStreamWriter(out,
|
||||||
alice ? aliceHeaderKey : bobHeaderKey);
|
alice ? aliceHeaderKey : bobHeaderKey);
|
||||||
RecordWriter recordWriter =
|
RecordWriter recordWriter =
|
||||||
recordWriterFactory.createRecordWriter(streamWriter.getOutputStream());
|
recordWriterFactory
|
||||||
|
.createRecordWriter(streamWriter.getOutputStream());
|
||||||
|
|
||||||
// Derive the nonces to be signed
|
// Derive the nonces to be signed
|
||||||
byte[] aliceNonce = crypto.mac(ALICE_NONCE_LABEL, masterSecret,
|
byte[] aliceNonce = crypto.mac(ALICE_NONCE_LABEL, masterKey,
|
||||||
new byte[] {PROTOCOL_VERSION});
|
new byte[] {PROTOCOL_VERSION});
|
||||||
byte[] bobNonce = crypto.mac(BOB_NONCE_LABEL, masterSecret,
|
byte[] bobNonce = crypto.mac(BOB_NONCE_LABEL, masterKey,
|
||||||
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;
|
||||||
@@ -196,7 +198,7 @@ class ContactExchangeTaskImpl extends Thread implements ContactExchangeTask {
|
|||||||
}
|
}
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
logException(LOG, WARNING, e);
|
logException(LOG, WARNING, e);
|
||||||
listener.contactExchangeFailed();
|
eventBus.broadcast(new ContactExchangeFailedEvent());
|
||||||
tryToClose(conn);
|
tryToClose(conn);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -204,7 +206,7 @@ class ContactExchangeTaskImpl extends Thread implements ContactExchangeTask {
|
|||||||
// Verify the contact's signature
|
// Verify the contact's signature
|
||||||
if (!verify(remoteInfo.author, remoteNonce, remoteInfo.signature)) {
|
if (!verify(remoteInfo.author, remoteNonce, remoteInfo.signature)) {
|
||||||
LOG.warning("Invalid signature");
|
LOG.warning("Invalid signature");
|
||||||
listener.contactExchangeFailed();
|
eventBus.broadcast(new ContactExchangeFailedEvent());
|
||||||
tryToClose(conn);
|
tryToClose(conn);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -221,15 +223,17 @@ class ContactExchangeTaskImpl extends Thread implements ContactExchangeTask {
|
|||||||
conn);
|
conn);
|
||||||
// Pseudonym exchange succeeded
|
// Pseudonym exchange succeeded
|
||||||
LOG.info("Pseudonym exchange succeeded");
|
LOG.info("Pseudonym exchange succeeded");
|
||||||
listener.contactExchangeSucceeded(remoteInfo.author);
|
eventBus.broadcast(
|
||||||
|
new ContactExchangeSucceededEvent(remoteInfo.author));
|
||||||
} catch (ContactExistsException e) {
|
} catch (ContactExistsException e) {
|
||||||
logException(LOG, WARNING, e);
|
logException(LOG, WARNING, e);
|
||||||
tryToClose(conn);
|
tryToClose(conn);
|
||||||
listener.duplicateContact(remoteInfo.author);
|
eventBus.broadcast(
|
||||||
|
new ContactExchangeFailedEvent(remoteInfo.author));
|
||||||
} catch (DbException e) {
|
} catch (DbException e) {
|
||||||
logException(LOG, WARNING, e);
|
logException(LOG, WARNING, e);
|
||||||
tryToClose(conn);
|
tryToClose(conn);
|
||||||
listener.contactExchangeFailed();
|
eventBus.broadcast(new ContactExchangeFailedEvent());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -287,19 +291,13 @@ class ContactExchangeTaskImpl extends Thread implements ContactExchangeTask {
|
|||||||
private ContactId addContact(Author remoteAuthor, long timestamp,
|
private ContactId addContact(Author remoteAuthor, long timestamp,
|
||||||
Map<TransportId, TransportProperties> remoteProperties)
|
Map<TransportId, TransportProperties> remoteProperties)
|
||||||
throws DbException {
|
throws DbException {
|
||||||
ContactId contactId;
|
return db.transactionWithResult(false, txn -> {
|
||||||
Transaction txn = db.startTransaction(false);
|
ContactId contactId = contactManager.addContact(txn, remoteAuthor,
|
||||||
try {
|
masterKey, timestamp, alice, true, true);
|
||||||
contactId = contactManager.addContact(txn, remoteAuthor,
|
|
||||||
localAuthor.getId(), masterSecret, timestamp, alice,
|
|
||||||
true, true);
|
|
||||||
transportPropertyManager.addRemoteProperties(txn, contactId,
|
transportPropertyManager.addRemoteProperties(txn, contactId,
|
||||||
remoteProperties);
|
remoteProperties);
|
||||||
db.commitTransaction(txn);
|
return contactId;
|
||||||
} finally {
|
});
|
||||||
db.endTransaction(txn);
|
|
||||||
}
|
|
||||||
return contactId;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void tryToClose(DuplexTransportConnection conn) {
|
private void tryToClose(DuplexTransportConnection conn) {
|
||||||
|
|||||||
@@ -3,10 +3,11 @@ package org.briarproject.bramble.contact;
|
|||||||
import org.briarproject.bramble.api.contact.Contact;
|
import org.briarproject.bramble.api.contact.Contact;
|
||||||
import org.briarproject.bramble.api.contact.ContactId;
|
import org.briarproject.bramble.api.contact.ContactId;
|
||||||
import org.briarproject.bramble.api.contact.ContactManager;
|
import org.briarproject.bramble.api.contact.ContactManager;
|
||||||
|
import org.briarproject.bramble.api.contact.PendingContact;
|
||||||
|
import org.briarproject.bramble.api.contact.PendingContactId;
|
||||||
import org.briarproject.bramble.api.crypto.SecretKey;
|
import org.briarproject.bramble.api.crypto.SecretKey;
|
||||||
import org.briarproject.bramble.api.db.DatabaseComponent;
|
import org.briarproject.bramble.api.db.DatabaseComponent;
|
||||||
import org.briarproject.bramble.api.db.DbException;
|
import org.briarproject.bramble.api.db.DbException;
|
||||||
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;
|
||||||
@@ -16,16 +17,20 @@ 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.concurrent.CopyOnWriteArrayList;
|
import java.util.concurrent.CopyOnWriteArrayList;
|
||||||
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
import javax.annotation.concurrent.ThreadSafe;
|
import javax.annotation.concurrent.ThreadSafe;
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
|
|
||||||
|
import static java.util.Collections.emptyList;
|
||||||
|
import static org.briarproject.bramble.api.contact.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;
|
||||||
@@ -36,6 +41,12 @@ import static org.briarproject.bramble.util.StringUtils.toUtf8;
|
|||||||
@NotNullByDefault
|
@NotNullByDefault
|
||||||
class ContactManagerImpl implements ContactManager {
|
class ContactManagerImpl implements ContactManager {
|
||||||
|
|
||||||
|
private static final int LINK_LENGTH = 64;
|
||||||
|
private static final String REMOTE_CONTACT_LINK =
|
||||||
|
"briar://" + getRandomBase32String(LINK_LENGTH);
|
||||||
|
private static final Pattern LINK_REGEX =
|
||||||
|
Pattern.compile("(briar://)?([a-z2-7]{" + LINK_LENGTH + "})");
|
||||||
|
|
||||||
private final DatabaseComponent db;
|
private final DatabaseComponent db;
|
||||||
private final KeyManager keyManager;
|
private final KeyManager keyManager;
|
||||||
private final IdentityManager identityManager;
|
private final IdentityManager identityManager;
|
||||||
@@ -56,141 +67,127 @@ class ContactManagerImpl implements ContactManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ContactId addContact(Transaction txn, Author remote, AuthorId local,
|
public ContactId addContact(Transaction txn, Author a, SecretKey rootKey,
|
||||||
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;
|
ContactId c = db.addContact(txn, a, verified);
|
||||||
Transaction txn = db.startTransaction(false);
|
keyManager.addContact(txn, c, rootKey, timestamp, alice, active);
|
||||||
try {
|
Contact contact = db.getContact(txn, c);
|
||||||
c = addContact(txn, remote, local, master, timestamp, alice,
|
for (ContactHook hook : hooks) hook.addingContact(txn, contact);
|
||||||
verified, active);
|
|
||||||
db.commitTransaction(txn);
|
|
||||||
} finally {
|
|
||||||
db.endTransaction(txn);
|
|
||||||
}
|
|
||||||
return c;
|
return c;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ContactId addContact(Transaction txn, Author a, boolean verified)
|
||||||
|
throws DbException {
|
||||||
|
ContactId c = db.addContact(txn, a, verified);
|
||||||
|
Contact contact = db.getContact(txn, c);
|
||||||
|
for (ContactHook hook : hooks) hook.addingContact(txn, contact);
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ContactId addContact(Author a, SecretKey rootKey, long timestamp,
|
||||||
|
boolean alice, boolean verified, boolean active)
|
||||||
|
throws DbException {
|
||||||
|
return db.transactionWithResult(false, txn ->
|
||||||
|
addContact(txn, a, rootKey, timestamp, alice,
|
||||||
|
verified, active));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getRemoteContactLink() {
|
||||||
|
// TODO replace with real implementation
|
||||||
|
return REMOTE_CONTACT_LINK;
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("SameParameterValue")
|
||||||
|
private static String getRandomBase32String(int length) {
|
||||||
|
Random random = new Random();
|
||||||
|
char[] c = new char[length];
|
||||||
|
for (int i = 0; i < length; i++) {
|
||||||
|
int character = random.nextInt(32);
|
||||||
|
if (character < 26) c[i] = (char) ('a' + character);
|
||||||
|
else c[i] = (char) ('2' + (character - 26));
|
||||||
|
}
|
||||||
|
return new String(c);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isValidRemoteContactLink(String link) {
|
||||||
|
return LINK_REGEX.matcher(link).matches();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public PendingContact addRemoteContactRequest(String link, String alias) {
|
||||||
|
// TODO replace with real implementation
|
||||||
|
PendingContactId id = new PendingContactId(link.getBytes());
|
||||||
|
return new PendingContact(id, new byte[MAX_PUBLIC_KEY_LENGTH], alias,
|
||||||
|
WAITING_FOR_CONNECTION, System.currentTimeMillis());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Collection<PendingContact> getPendingContacts() {
|
||||||
|
// TODO replace with real implementation
|
||||||
|
return emptyList();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void removePendingContact(PendingContact pendingContact) {
|
||||||
|
// TODO replace with real implementation
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Contact getContact(ContactId c) throws DbException {
|
public Contact getContact(ContactId c) throws DbException {
|
||||||
Contact contact;
|
return db.transactionWithResult(true, txn -> db.getContact(txn, c));
|
||||||
Transaction txn = db.startTransaction(true);
|
|
||||||
try {
|
|
||||||
contact = db.getContact(txn, c);
|
|
||||||
db.commitTransaction(txn);
|
|
||||||
} finally {
|
|
||||||
db.endTransaction(txn);
|
|
||||||
}
|
|
||||||
return contact;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Contact getContact(AuthorId remoteAuthorId, AuthorId localAuthorId)
|
public Contact getContact(AuthorId a) throws DbException {
|
||||||
throws DbException {
|
return db.transactionWithResult(true, txn -> getContact(txn, a));
|
||||||
Transaction txn = db.startTransaction(true);
|
|
||||||
try {
|
|
||||||
Contact c = getContact(txn, remoteAuthorId, localAuthorId);
|
|
||||||
db.commitTransaction(txn);
|
|
||||||
return c;
|
|
||||||
} finally {
|
|
||||||
db.endTransaction(txn);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Contact getContact(Transaction txn, AuthorId remoteAuthorId,
|
public Contact getContact(Transaction txn, AuthorId a) throws DbException {
|
||||||
AuthorId localAuthorId) throws DbException {
|
return db.getContact(txn, a);
|
||||||
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> getActiveContacts() throws DbException {
|
public Collection<Contact> getContacts() throws DbException {
|
||||||
Collection<Contact> contacts;
|
return db.transactionWithResult(true, db::getContacts);
|
||||||
Transaction txn = db.startTransaction(true);
|
|
||||||
try {
|
|
||||||
contacts = db.getContacts(txn);
|
|
||||||
db.commitTransaction(txn);
|
|
||||||
} finally {
|
|
||||||
db.endTransaction(txn);
|
|
||||||
}
|
|
||||||
List<Contact> active = new ArrayList<>(contacts.size());
|
|
||||||
for (Contact c : contacts) if (c.isActive()) active.add(c);
|
|
||||||
return active;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void removeContact(ContactId c) throws DbException {
|
public void removeContact(ContactId c) throws DbException {
|
||||||
Transaction txn = db.startTransaction(false);
|
db.transaction(false, txn -> removeContact(txn, c));
|
||||||
try {
|
|
||||||
removeContact(txn, c);
|
|
||||||
db.commitTransaction(txn);
|
|
||||||
} finally {
|
|
||||||
db.endTransaction(txn);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setContactActive(Transaction txn, ContactId c, boolean active)
|
public void setContactAlias(Transaction txn, ContactId c,
|
||||||
throws DbException {
|
@Nullable String alias) throws DbException {
|
||||||
db.setContactActive(txn, c, active);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setContactAlias(ContactId c, @Nullable String alias)
|
|
||||||
throws DbException {
|
|
||||||
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();
|
||||||
}
|
}
|
||||||
db.transaction(false, txn -> db.setContactAlias(txn, c, alias));
|
db.setContactAlias(txn, c, alias);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean contactExists(Transaction txn, AuthorId remoteAuthorId,
|
public void setContactAlias(ContactId c, @Nullable String alias)
|
||||||
AuthorId localAuthorId) throws DbException {
|
throws DbException {
|
||||||
return db.containsContact(txn, remoteAuthorId, localAuthorId);
|
db.transaction(false, txn -> setContactAlias(txn, c, alias));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean contactExists(AuthorId remoteAuthorId,
|
public boolean contactExists(Transaction txn, AuthorId a)
|
||||||
AuthorId localAuthorId) throws DbException {
|
throws DbException {
|
||||||
boolean exists;
|
return db.containsContact(txn, a);
|
||||||
Transaction txn = db.startTransaction(true);
|
}
|
||||||
try {
|
|
||||||
exists = contactExists(txn, remoteAuthorId, localAuthorId);
|
@Override
|
||||||
db.commitTransaction(txn);
|
public boolean contactExists(AuthorId a) throws DbException {
|
||||||
} finally {
|
return db.transactionWithResult(true, txn -> contactExists(txn, a));
|
||||||
db.endTransaction(txn);
|
|
||||||
}
|
|
||||||
return exists;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -212,12 +209,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);
|
||||||
Collection<Contact> contacts = db.getContactsByAuthorId(txn, authorId);
|
if (db.containsContact(txn, authorId)) {
|
||||||
if (contacts.isEmpty()) return new AuthorInfo(UNKNOWN);
|
Contact c = db.getContact(txn, authorId);
|
||||||
if (contacts.size() > 1) throw new AssertionError();
|
if (c.isVerified()) return new AuthorInfo(VERIFIED, c.getAlias());
|
||||||
Contact c = contacts.iterator().next();
|
else return new AuthorInfo(UNVERIFIED, c.getAlias());
|
||||||
if (c.isVerified()) return new AuthorInfo(VERIFIED, c.getAlias());
|
}
|
||||||
else return new AuthorInfo(UNVERIFIED, c.getAlias());
|
return new AuthorInfo(UNKNOWN);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,18 +4,22 @@ 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;
|
||||||
@@ -24,6 +28,9 @@ import static org.briarproject.bramble.util.ByteUtils.INT_16_BYTES;
|
|||||||
import static org.briarproject.bramble.util.ByteUtils.INT_64_BYTES;
|
import static org.briarproject.bramble.util.ByteUtils.INT_64_BYTES;
|
||||||
import static org.briarproject.bramble.util.ByteUtils.MAX_16_BIT_UNSIGNED;
|
import static org.briarproject.bramble.util.ByteUtils.MAX_16_BIT_UNSIGNED;
|
||||||
import static org.briarproject.bramble.util.ByteUtils.MAX_32_BIT_UNSIGNED;
|
import static org.briarproject.bramble.util.ByteUtils.MAX_32_BIT_UNSIGNED;
|
||||||
|
import static org.briarproject.bramble.util.ByteUtils.writeUint16;
|
||||||
|
import static org.briarproject.bramble.util.ByteUtils.writeUint64;
|
||||||
|
import static org.briarproject.bramble.util.StringUtils.toUtf8;
|
||||||
|
|
||||||
class TransportCryptoImpl implements TransportCrypto {
|
class TransportCryptoImpl implements TransportCrypto {
|
||||||
|
|
||||||
@@ -36,45 +43,44 @@ class TransportCryptoImpl implements TransportCrypto {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public TransportKeys deriveTransportKeys(TransportId t,
|
public TransportKeys deriveTransportKeys(TransportId t,
|
||||||
SecretKey master, long rotationPeriod, boolean alice,
|
SecretKey rootKey, long timePeriod, boolean weAreAlice,
|
||||||
boolean active) {
|
boolean active) {
|
||||||
// Keys for the previous period are derived from the master secret
|
// Keys for the previous period are derived from the root key
|
||||||
SecretKey inTagPrev = deriveTagKey(master, t, !alice);
|
SecretKey inTagPrev = deriveTagKey(rootKey, t, !weAreAlice);
|
||||||
SecretKey inHeaderPrev = deriveHeaderKey(master, t, !alice);
|
SecretKey inHeaderPrev = deriveHeaderKey(rootKey, t, !weAreAlice);
|
||||||
SecretKey outTagPrev = deriveTagKey(master, t, alice);
|
SecretKey outTagPrev = deriveTagKey(rootKey, t, weAreAlice);
|
||||||
SecretKey outHeaderPrev = deriveHeaderKey(master, t, alice);
|
SecretKey outHeaderPrev = deriveHeaderKey(rootKey, t, weAreAlice);
|
||||||
// Derive the keys for the current and next periods
|
// Derive the keys for the current and next periods
|
||||||
SecretKey inTagCurr = rotateKey(inTagPrev, rotationPeriod);
|
SecretKey inTagCurr = rotateKey(inTagPrev, timePeriod);
|
||||||
SecretKey inHeaderCurr = rotateKey(inHeaderPrev, rotationPeriod);
|
SecretKey inHeaderCurr = rotateKey(inHeaderPrev, timePeriod);
|
||||||
SecretKey inTagNext = rotateKey(inTagCurr, rotationPeriod + 1);
|
SecretKey inTagNext = rotateKey(inTagCurr, timePeriod + 1);
|
||||||
SecretKey inHeaderNext = rotateKey(inHeaderCurr, rotationPeriod + 1);
|
SecretKey inHeaderNext = rotateKey(inHeaderCurr, timePeriod + 1);
|
||||||
SecretKey outTagCurr = rotateKey(outTagPrev, rotationPeriod);
|
SecretKey outTagCurr = rotateKey(outTagPrev, timePeriod);
|
||||||
SecretKey outHeaderCurr = rotateKey(outHeaderPrev, rotationPeriod);
|
SecretKey outHeaderCurr = rotateKey(outHeaderPrev, timePeriod);
|
||||||
// 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,
|
||||||
rotationPeriod - 1);
|
timePeriod - 1);
|
||||||
IncomingKeys inCurr = new IncomingKeys(inTagCurr, inHeaderCurr,
|
IncomingKeys inCurr = new IncomingKeys(inTagCurr, inHeaderCurr,
|
||||||
rotationPeriod);
|
timePeriod);
|
||||||
IncomingKeys inNext = new IncomingKeys(inTagNext, inHeaderNext,
|
IncomingKeys inNext = new IncomingKeys(inTagNext, inHeaderNext,
|
||||||
rotationPeriod + 1);
|
timePeriod + 1);
|
||||||
OutgoingKeys outCurr = new OutgoingKeys(outTagCurr, outHeaderCurr,
|
OutgoingKeys outCurr = new OutgoingKeys(outTagCurr, outHeaderCurr,
|
||||||
rotationPeriod, active);
|
timePeriod, 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,
|
public TransportKeys rotateTransportKeys(TransportKeys k, long timePeriod) {
|
||||||
long rotationPeriod) {
|
if (k.getTimePeriod() >= timePeriod) return k;
|
||||||
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.getRotationPeriod();
|
long startPeriod = outCurr.getTimePeriod();
|
||||||
boolean active = outCurr.isActive();
|
boolean active = outCurr.isActive();
|
||||||
// Rotate the keys
|
// Rotate the keys
|
||||||
for (long p = startPeriod + 1; p <= rotationPeriod; p++) {
|
for (long p = startPeriod + 1; p <= timePeriod; p++) {
|
||||||
inPrev = inCurr;
|
inPrev = inCurr;
|
||||||
inCurr = inNext;
|
inCurr = inNext;
|
||||||
SecretKey inNextTag = rotateKey(inNext.getTagKey(), p + 1);
|
SecretKey inNextTag = rotateKey(inNext.getTagKey(), p + 1);
|
||||||
@@ -89,24 +95,117 @@ class TransportCryptoImpl implements TransportCrypto {
|
|||||||
outCurr);
|
outCurr);
|
||||||
}
|
}
|
||||||
|
|
||||||
private SecretKey rotateKey(SecretKey k, long rotationPeriod) {
|
private SecretKey rotateKey(SecretKey k, long timePeriod) {
|
||||||
byte[] period = new byte[INT_64_BYTES];
|
byte[] period = new byte[INT_64_BYTES];
|
||||||
ByteUtils.writeUint64(rotationPeriod, period, 0);
|
writeUint64(timePeriod, period, 0);
|
||||||
return crypto.deriveKey(ROTATE_LABEL, k, period);
|
return crypto.deriveKey(ROTATE_LABEL, k, period);
|
||||||
}
|
}
|
||||||
|
|
||||||
private SecretKey deriveTagKey(SecretKey master, TransportId t,
|
private SecretKey deriveTagKey(SecretKey rootKey, TransportId t,
|
||||||
boolean alice) {
|
boolean keyBelongsToAlice) {
|
||||||
String label = alice ? ALICE_TAG_LABEL : BOB_TAG_LABEL;
|
String label = keyBelongsToAlice ? ALICE_TAG_LABEL : BOB_TAG_LABEL;
|
||||||
byte[] id = StringUtils.toUtf8(t.getString());
|
byte[] id = toUtf8(t.getString());
|
||||||
return crypto.deriveKey(label, master, id);
|
return crypto.deriveKey(label, rootKey, id);
|
||||||
}
|
}
|
||||||
|
|
||||||
private SecretKey deriveHeaderKey(SecretKey master, TransportId t,
|
private SecretKey deriveHeaderKey(SecretKey rootKey, TransportId t,
|
||||||
boolean alice) {
|
boolean keyBelongsToAlice) {
|
||||||
String label = alice ? ALICE_HEADER_LABEL : BOB_HEADER_LABEL;
|
String label = keyBelongsToAlice ? ALICE_HEADER_LABEL :
|
||||||
byte[] id = StringUtils.toUtf8(t.getString());
|
BOB_HEADER_LABEL;
|
||||||
return crypto.deriveKey(label, master, id);
|
byte[] id = toUtf8(t.getString());
|
||||||
|
return crypto.deriveKey(label, rootKey, id);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public HandshakeKeys deriveHandshakeKeys(TransportId t, SecretKey rootKey,
|
||||||
|
long timePeriod, boolean weAreAlice) {
|
||||||
|
if (timePeriod < 1) throw new IllegalArgumentException();
|
||||||
|
IncomingKeys inPrev = deriveIncomingHandshakeKeys(t, rootKey,
|
||||||
|
weAreAlice, timePeriod - 1);
|
||||||
|
IncomingKeys inCurr = deriveIncomingHandshakeKeys(t, rootKey,
|
||||||
|
weAreAlice, timePeriod);
|
||||||
|
IncomingKeys inNext = deriveIncomingHandshakeKeys(t, rootKey,
|
||||||
|
weAreAlice, timePeriod + 1);
|
||||||
|
OutgoingKeys outCurr = deriveOutgoingHandshakeKeys(t, rootKey,
|
||||||
|
weAreAlice, timePeriod);
|
||||||
|
return new HandshakeKeys(t, inPrev, inCurr, inNext, outCurr, rootKey,
|
||||||
|
weAreAlice);
|
||||||
|
}
|
||||||
|
|
||||||
|
private IncomingKeys deriveIncomingHandshakeKeys(TransportId t,
|
||||||
|
SecretKey rootKey, boolean weAreAlice, long timePeriod) {
|
||||||
|
SecretKey tag = deriveHandshakeTagKey(t, rootKey, !weAreAlice,
|
||||||
|
timePeriod);
|
||||||
|
SecretKey header = deriveHandshakeHeaderKey(t, rootKey, !weAreAlice,
|
||||||
|
timePeriod);
|
||||||
|
return new IncomingKeys(tag, header, timePeriod);
|
||||||
|
}
|
||||||
|
|
||||||
|
private OutgoingKeys deriveOutgoingHandshakeKeys(TransportId t,
|
||||||
|
SecretKey rootKey, boolean weAreAlice, long timePeriod) {
|
||||||
|
SecretKey tag = deriveHandshakeTagKey(t, rootKey, weAreAlice,
|
||||||
|
timePeriod);
|
||||||
|
SecretKey header = deriveHandshakeHeaderKey(t, rootKey, weAreAlice,
|
||||||
|
timePeriod);
|
||||||
|
return new OutgoingKeys(tag, header, timePeriod, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
private SecretKey deriveHandshakeTagKey(TransportId t, SecretKey rootKey,
|
||||||
|
boolean keyBelongsToAlice, long timePeriod) {
|
||||||
|
String label = keyBelongsToAlice ? ALICE_HANDSHAKE_TAG_LABEL :
|
||||||
|
BOB_HANDSHAKE_TAG_LABEL;
|
||||||
|
byte[] id = toUtf8(t.getString());
|
||||||
|
byte[] period = new byte[INT_64_BYTES];
|
||||||
|
writeUint64(timePeriod, period, 0);
|
||||||
|
return crypto.deriveKey(label, rootKey, id, period);
|
||||||
|
}
|
||||||
|
|
||||||
|
private SecretKey deriveHandshakeHeaderKey(TransportId t, SecretKey rootKey,
|
||||||
|
boolean keyBelongsToAlice, long timePeriod) {
|
||||||
|
String label = keyBelongsToAlice ? ALICE_HANDSHAKE_HEADER_LABEL :
|
||||||
|
BOB_HANDSHAKE_HEADER_LABEL;
|
||||||
|
byte[] id = toUtf8(t.getString());
|
||||||
|
byte[] period = new byte[INT_64_BYTES];
|
||||||
|
writeUint64(timePeriod, period, 0);
|
||||||
|
return crypto.deriveKey(label, rootKey, id, period);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public HandshakeKeys updateHandshakeKeys(HandshakeKeys k, long timePeriod) {
|
||||||
|
long elapsed = timePeriod - k.getTimePeriod();
|
||||||
|
TransportId t = k.getTransportId();
|
||||||
|
SecretKey rootKey = k.getRootKey();
|
||||||
|
boolean weAreAlice = k.isAlice();
|
||||||
|
if (elapsed <= 0) {
|
||||||
|
// The keys are for the given period or later - don't update them
|
||||||
|
return k;
|
||||||
|
} else if (elapsed == 1) {
|
||||||
|
// The keys are one period old - shift by one period, keeping the
|
||||||
|
// reordering windows for keys we retain
|
||||||
|
IncomingKeys inPrev = k.getCurrentIncomingKeys();
|
||||||
|
IncomingKeys inCurr = k.getNextIncomingKeys();
|
||||||
|
IncomingKeys inNext = deriveIncomingHandshakeKeys(t, rootKey,
|
||||||
|
weAreAlice, timePeriod + 1);
|
||||||
|
OutgoingKeys outCurr = deriveOutgoingHandshakeKeys(t, rootKey,
|
||||||
|
weAreAlice, timePeriod);
|
||||||
|
return new HandshakeKeys(t, inPrev, inCurr, inNext, outCurr,
|
||||||
|
rootKey, weAreAlice);
|
||||||
|
} else if (elapsed == 2) {
|
||||||
|
// The keys are two periods old - shift by two periods, keeping
|
||||||
|
// the reordering windows for keys we retain
|
||||||
|
IncomingKeys inPrev = k.getNextIncomingKeys();
|
||||||
|
IncomingKeys inCurr = deriveIncomingHandshakeKeys(t, rootKey,
|
||||||
|
weAreAlice, timePeriod);
|
||||||
|
IncomingKeys inNext = deriveIncomingHandshakeKeys(t, rootKey,
|
||||||
|
weAreAlice, timePeriod + 1);
|
||||||
|
OutgoingKeys outCurr = deriveOutgoingHandshakeKeys(t, rootKey,
|
||||||
|
weAreAlice, timePeriod);
|
||||||
|
return new HandshakeKeys(t, inPrev, inCurr, inNext, outCurr,
|
||||||
|
rootKey, weAreAlice);
|
||||||
|
} else {
|
||||||
|
// The keys are more than two periods old - derive fresh keys
|
||||||
|
return deriveHandshakeKeys(t, rootKey, timePeriod, weAreAlice);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -125,14 +224,14 @@ class TransportCryptoImpl implements TransportCrypto {
|
|||||||
// The input is the protocol version as a 16-bit integer, followed by
|
// The input is the protocol version as a 16-bit integer, followed by
|
||||||
// the stream number as a 64-bit integer
|
// the stream number as a 64-bit integer
|
||||||
byte[] protocolVersionBytes = new byte[INT_16_BYTES];
|
byte[] protocolVersionBytes = new byte[INT_16_BYTES];
|
||||||
ByteUtils.writeUint16(protocolVersion, protocolVersionBytes, 0);
|
writeUint16(protocolVersion, protocolVersionBytes, 0);
|
||||||
prf.update(protocolVersionBytes, 0, protocolVersionBytes.length);
|
prf.update(protocolVersionBytes, 0, protocolVersionBytes.length);
|
||||||
byte[] streamNumberBytes = new byte[INT_64_BYTES];
|
byte[] streamNumberBytes = new byte[INT_64_BYTES];
|
||||||
ByteUtils.writeUint64(streamNumber, streamNumberBytes, 0);
|
writeUint64(streamNumber, streamNumberBytes, 0);
|
||||||
prf.update(streamNumberBytes, 0, streamNumberBytes.length);
|
prf.update(streamNumberBytes, 0, streamNumberBytes.length);
|
||||||
byte[] mac = new byte[macLength];
|
byte[] mac = new byte[macLength];
|
||||||
prf.doFinal(mac, 0);
|
prf.doFinal(mac, 0);
|
||||||
// The output is the first TAG_LENGTH bytes of the MAC
|
// The output is the first TAG_LENGTH bytes of the MAC
|
||||||
System.arraycopy(mac, 0, tag, 0, TAG_LENGTH);
|
arraycopy(mac, 0, tag, 0, TAG_LENGTH);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -29,6 +29,7 @@ import static org.briarproject.bramble.data.Types.STRING_16;
|
|||||||
import static org.briarproject.bramble.data.Types.STRING_32;
|
import static org.briarproject.bramble.data.Types.STRING_32;
|
||||||
import static org.briarproject.bramble.data.Types.STRING_8;
|
import static org.briarproject.bramble.data.Types.STRING_8;
|
||||||
import static org.briarproject.bramble.data.Types.TRUE;
|
import static org.briarproject.bramble.data.Types.TRUE;
|
||||||
|
import static org.briarproject.bramble.util.StringUtils.fromUtf8;
|
||||||
|
|
||||||
@NotThreadSafe
|
@NotThreadSafe
|
||||||
@NotNullByDefault
|
@NotNullByDefault
|
||||||
@@ -253,7 +254,7 @@ class BdfReaderImpl implements BdfReader {
|
|||||||
if (length < 0 || length > maxBufferSize) throw new FormatException();
|
if (length < 0 || length > maxBufferSize) throw new FormatException();
|
||||||
if (length == 0) return "";
|
if (length == 0) return "";
|
||||||
readIntoBuffer(length);
|
readIntoBuffer(length);
|
||||||
return new String(buf, 0, length, "UTF-8");
|
return fromUtf8(buf, 0, length);
|
||||||
}
|
}
|
||||||
|
|
||||||
private int readStringLength() throws IOException {
|
private int readStringLength() throws IOException {
|
||||||
|
|||||||
@@ -2,9 +2,13 @@ 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;
|
||||||
@@ -22,9 +26,12 @@ import org.briarproject.bramble.api.sync.GroupId;
|
|||||||
import org.briarproject.bramble.api.sync.Message;
|
import org.briarproject.bramble.api.sync.Message;
|
||||||
import org.briarproject.bramble.api.sync.MessageId;
|
import org.briarproject.bramble.api.sync.MessageId;
|
||||||
import org.briarproject.bramble.api.sync.MessageStatus;
|
import org.briarproject.bramble.api.sync.MessageStatus;
|
||||||
import org.briarproject.bramble.api.sync.ValidationManager.State;
|
import org.briarproject.bramble.api.sync.validation.MessageState;
|
||||||
import org.briarproject.bramble.api.transport.KeySet;
|
import org.briarproject.bramble.api.transport.HandshakeKeySet;
|
||||||
import org.briarproject.bramble.api.transport.KeySetId;
|
import org.briarproject.bramble.api.transport.HandshakeKeySetId;
|
||||||
|
import org.briarproject.bramble.api.transport.HandshakeKeys;
|
||||||
|
import org.briarproject.bramble.api.transport.TransportKeySet;
|
||||||
|
import org.briarproject.bramble.api.transport.TransportKeySetId;
|
||||||
import org.briarproject.bramble.api.transport.TransportKeys;
|
import org.briarproject.bramble.api.transport.TransportKeys;
|
||||||
|
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
@@ -33,11 +40,14 @@ import java.util.Map;
|
|||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A low-level interface to the database (DatabaseComponent provides a
|
* A low-level interface to the database ({@link DatabaseComponent} provides a
|
||||||
* high-level interface). Most operations take a transaction argument, which is
|
* high-level interface).
|
||||||
* obtained by calling {@link #startTransaction()}. Every transaction must be
|
* <p/>
|
||||||
* terminated by calling either {@link #abortTransaction(Object) abortTransaction(T)} or
|
* Most operations take a transaction argument, which is obtained by calling
|
||||||
* {@link #commitTransaction(Object) commitTransaction(T)}, even if an exception is thrown.
|
* {@link #startTransaction()}. Every transaction must be terminated by calling
|
||||||
|
* either {@link #abortTransaction(Object) abortTransaction(T)} or
|
||||||
|
* {@link #commitTransaction(Object) commitTransaction(T)}, even if an
|
||||||
|
* exception is thrown.
|
||||||
*/
|
*/
|
||||||
@NotNullByDefault
|
@NotNullByDefault
|
||||||
interface Database<T> {
|
interface Database<T> {
|
||||||
@@ -77,11 +87,10 @@ interface Database<T> {
|
|||||||
void commitTransaction(T txn) throws DbException;
|
void commitTransaction(T txn) throws DbException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Stores a contact associated with the given local and remote pseudonyms,
|
* Stores a contact with the given pseudonym and returns an ID for the
|
||||||
* and returns an ID for the contact.
|
* contact.
|
||||||
*/
|
*/
|
||||||
ContactId addContact(T txn, Author remote, AuthorId local, boolean verified,
|
ContactId addContact(T txn, Author a, boolean verified) throws DbException;
|
||||||
boolean active) throws DbException;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Stores a group.
|
* Stores a group.
|
||||||
@@ -95,6 +104,20 @@ 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.
|
||||||
*/
|
*/
|
||||||
@@ -106,7 +129,7 @@ interface Database<T> {
|
|||||||
* @param sender the contact from whom the message was received, or null
|
* @param sender the contact from whom the message was received, or null
|
||||||
* if the message was created locally.
|
* if the message was created locally.
|
||||||
*/
|
*/
|
||||||
void addMessage(T txn, Message m, State state, boolean shared,
|
void addMessage(T txn, Message m, MessageState state, boolean shared,
|
||||||
@Nullable ContactId sender) throws DbException;
|
@Nullable ContactId sender) throws DbException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -114,13 +137,18 @@ interface Database<T> {
|
|||||||
* in the given state.
|
* in the given state.
|
||||||
*/
|
*/
|
||||||
void addMessageDependency(T txn, Message dependent, MessageId dependency,
|
void addMessageDependency(T txn, Message dependent, MessageId dependency,
|
||||||
State dependentState) throws DbException;
|
MessageState dependentState) throws DbException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Records that a message has been offered by the given contact.
|
* Records that a message has been offered by the given contact.
|
||||||
*/
|
*/
|
||||||
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.
|
||||||
*/
|
*/
|
||||||
@@ -131,17 +159,15 @@ 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.
|
||||||
*/
|
*/
|
||||||
KeySetId addTransportKeys(T txn, ContactId c, TransportKeys k)
|
TransportKeySetId addTransportKeys(T txn, ContactId c, TransportKeys k)
|
||||||
throws DbException;
|
throws DbException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns true if the database contains the given contact for the given
|
* Returns true if the database contains the given contact.
|
||||||
* local pseudonym.
|
|
||||||
* <p/>
|
* <p/>
|
||||||
* Read-only.
|
* Read-only.
|
||||||
*/
|
*/
|
||||||
boolean containsContact(T txn, AuthorId remote, AuthorId local)
|
boolean containsContact(T txn, AuthorId a) throws DbException;
|
||||||
throws DbException;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns true if the database contains the given contact.
|
* Returns true if the database contains the given contact.
|
||||||
@@ -171,6 +197,14 @@ 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/>
|
||||||
@@ -215,6 +249,13 @@ 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/>
|
||||||
@@ -222,28 +263,6 @@ 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/>
|
||||||
@@ -284,6 +303,14 @@ 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/>
|
||||||
@@ -310,11 +337,11 @@ interface Database<T> {
|
|||||||
/**
|
/**
|
||||||
* Returns the IDs and states of all dependencies of the given message.
|
* Returns the IDs and states of all dependencies of the given message.
|
||||||
* For missing dependencies and dependencies in other groups, the state
|
* For missing dependencies and dependencies in other groups, the state
|
||||||
* {@link State UNKNOWN} is returned.
|
* {@link MessageState UNKNOWN} is returned.
|
||||||
* <p/>
|
* <p/>
|
||||||
* Read-only.
|
* Read-only.
|
||||||
*/
|
*/
|
||||||
Map<MessageId, State> getMessageDependencies(T txn, MessageId m)
|
Map<MessageId, MessageState> getMessageDependencies(T txn, MessageId m)
|
||||||
throws DbException;
|
throws DbException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -324,7 +351,7 @@ interface Database<T> {
|
|||||||
* <p/>
|
* <p/>
|
||||||
* Read-only.
|
* Read-only.
|
||||||
*/
|
*/
|
||||||
Map<MessageId, State> getMessageDependents(T txn, MessageId m)
|
Map<MessageId, MessageState> getMessageDependents(T txn, MessageId m)
|
||||||
throws DbException;
|
throws DbException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -383,7 +410,7 @@ interface Database<T> {
|
|||||||
* <p/>
|
* <p/>
|
||||||
* Read-only.
|
* Read-only.
|
||||||
*/
|
*/
|
||||||
State getMessageState(T txn, MessageId m) throws DbException;
|
MessageState getMessageState(T txn, MessageId m) throws DbException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the status of all delivered messages in the given group with
|
* Returns the status of all delivered messages in the given group with
|
||||||
@@ -474,6 +501,13 @@ 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
|
||||||
@@ -496,13 +530,19 @@ interface Database<T> {
|
|||||||
* <p/>
|
* <p/>
|
||||||
* Read-only.
|
* Read-only.
|
||||||
*/
|
*/
|
||||||
Collection<KeySet> getTransportKeys(T txn, TransportId t)
|
Collection<TransportKeySet> getTransportKeys(T txn, TransportId t)
|
||||||
|
throws DbException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Increments the outgoing stream counter for the given handshake keys.
|
||||||
|
*/
|
||||||
|
void incrementStreamCounter(T txn, TransportId t, HandshakeKeySetId k)
|
||||||
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, KeySetId k)
|
void incrementStreamCounter(T txn, TransportId t, TransportKeySetId k)
|
||||||
throws DbException;
|
throws DbException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -571,6 +611,12 @@ 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.
|
||||||
*/
|
*/
|
||||||
@@ -588,6 +634,11 @@ 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.
|
||||||
*/
|
*/
|
||||||
@@ -596,7 +647,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, KeySetId k)
|
void removeTransportKeys(T txn, TransportId t, TransportKeySetId k)
|
||||||
throws DbException;
|
throws DbException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -610,12 +661,6 @@ 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.
|
||||||
*/
|
*/
|
||||||
@@ -637,19 +682,33 @@ interface Database<T> {
|
|||||||
/**
|
/**
|
||||||
* Sets the validation and delivery state of the given message.
|
* Sets the validation and delivery state of the given message.
|
||||||
*/
|
*/
|
||||||
void setMessageState(T txn, MessageId m, State state) throws DbException;
|
void setMessageState(T txn, MessageId m, MessageState state)
|
||||||
|
throws DbException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the reordering window for the given key set and transport in the
|
* Sets the state of the given pending contact.
|
||||||
* given rotation period.
|
|
||||||
*/
|
*/
|
||||||
void setReorderingWindow(T txn, KeySetId k, TransportId t,
|
void setPendingContactState(T txn, PendingContactId p,
|
||||||
long rotationPeriod, long base, byte[] bitmap) throws DbException;
|
PendingContactState state) throws DbException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the reordering window for the given transport key set in the given
|
||||||
|
* time period.
|
||||||
|
*/
|
||||||
|
void setReorderingWindow(T txn, TransportKeySetId k, TransportId t,
|
||||||
|
long timePeriod, long base, byte[] bitmap) throws DbException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the reordering window for the given handshake key set in the given
|
||||||
|
* time period.
|
||||||
|
*/
|
||||||
|
void setReorderingWindow(T txn, HandshakeKeySetId k, TransportId t,
|
||||||
|
long timePeriod, long base, byte[] bitmap) throws DbException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 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, KeySetId k)
|
void setTransportKeysActive(T txn, TransportId t, TransportKeySetId k)
|
||||||
throws DbException;
|
throws DbException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -660,8 +719,13 @@ 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, KeySet ks) throws DbException;
|
void updateTransportKeys(T txn, TransportKeySet ks) throws DbException;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,26 +2,34 @@ 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.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;
|
||||||
@@ -42,7 +50,6 @@ import org.briarproject.bramble.api.sync.MessageId;
|
|||||||
import org.briarproject.bramble.api.sync.MessageStatus;
|
import org.briarproject.bramble.api.sync.MessageStatus;
|
||||||
import org.briarproject.bramble.api.sync.Offer;
|
import org.briarproject.bramble.api.sync.Offer;
|
||||||
import org.briarproject.bramble.api.sync.Request;
|
import org.briarproject.bramble.api.sync.Request;
|
||||||
import org.briarproject.bramble.api.sync.ValidationManager.State;
|
|
||||||
import org.briarproject.bramble.api.sync.event.GroupAddedEvent;
|
import org.briarproject.bramble.api.sync.event.GroupAddedEvent;
|
||||||
import org.briarproject.bramble.api.sync.event.GroupRemovedEvent;
|
import org.briarproject.bramble.api.sync.event.GroupRemovedEvent;
|
||||||
import org.briarproject.bramble.api.sync.event.GroupVisibilityUpdatedEvent;
|
import org.briarproject.bramble.api.sync.event.GroupVisibilityUpdatedEvent;
|
||||||
@@ -54,8 +61,12 @@ 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.KeySet;
|
import org.briarproject.bramble.api.sync.validation.MessageState;
|
||||||
import org.briarproject.bramble.api.transport.KeySetId;
|
import org.briarproject.bramble.api.transport.HandshakeKeySet;
|
||||||
|
import org.briarproject.bramble.api.transport.HandshakeKeySetId;
|
||||||
|
import org.briarproject.bramble.api.transport.HandshakeKeys;
|
||||||
|
import org.briarproject.bramble.api.transport.TransportKeySet;
|
||||||
|
import org.briarproject.bramble.api.transport.TransportKeySetId;
|
||||||
import org.briarproject.bramble.api.transport.TransportKeys;
|
import org.briarproject.bramble.api.transport.TransportKeys;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
@@ -63,6 +74,7 @@ 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;
|
||||||
@@ -74,8 +86,8 @@ import javax.inject.Inject;
|
|||||||
import static java.util.logging.Level.WARNING;
|
import static java.util.logging.Level.WARNING;
|
||||||
import static org.briarproject.bramble.api.sync.Group.Visibility.INVISIBLE;
|
import static org.briarproject.bramble.api.sync.Group.Visibility.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.ValidationManager.State.DELIVERED;
|
import static org.briarproject.bramble.api.sync.validation.MessageState.DELIVERED;
|
||||||
import static org.briarproject.bramble.api.sync.ValidationManager.State.UNKNOWN;
|
import static org.briarproject.bramble.api.sync.validation.MessageState.UNKNOWN;
|
||||||
import static org.briarproject.bramble.db.DatabaseConstants.MAX_OFFERED_MESSAGES;
|
import static org.briarproject.bramble.db.DatabaseConstants.MAX_OFFERED_MESSAGES;
|
||||||
import static org.briarproject.bramble.util.LogUtils.logDuration;
|
import static org.briarproject.bramble.util.LogUtils.logDuration;
|
||||||
import static org.briarproject.bramble.util.LogUtils.logException;
|
import static org.briarproject.bramble.util.LogUtils.logException;
|
||||||
@@ -91,25 +103,29 @@ 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 ShutdownManager shutdown;
|
private final Executor eventExecutor;
|
||||||
|
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,
|
||||||
ShutdownManager shutdown) {
|
@EventExecutor Executor eventExecutor,
|
||||||
|
ShutdownManager shutdownManager) {
|
||||||
this.db = db;
|
this.db = db;
|
||||||
this.txnClass = txnClass;
|
this.txnClass = txnClass;
|
||||||
this.eventBus = eventBus;
|
this.eventBus = eventBus;
|
||||||
this.shutdown = shutdown;
|
this.eventExecutor = eventExecutor;
|
||||||
|
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);
|
||||||
shutdown.addShutdownHook(() -> {
|
shutdownManager.addShutdownHook(() -> {
|
||||||
try {
|
try {
|
||||||
close();
|
close();
|
||||||
} catch (DbException e) {
|
} catch (DbException e) {
|
||||||
@@ -159,13 +175,16 @@ 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()) db.abortTransaction(txn);
|
if (transaction.isCommitted()) {
|
||||||
|
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
|
||||||
@@ -193,26 +212,36 @@ class DatabaseComponentImpl<T> implements DatabaseComponent {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public <R, E extends Exception> R transactionWithNullableResult(
|
||||||
|
boolean readOnly, NullableDbCallable<R, E> task)
|
||||||
|
throws DbException, E {
|
||||||
|
Transaction txn = startTransaction(readOnly);
|
||||||
|
try {
|
||||||
|
R result = task.call(txn);
|
||||||
|
commitTransaction(txn);
|
||||||
|
return result;
|
||||||
|
} finally {
|
||||||
|
endTransaction(txn);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private T unbox(Transaction transaction) {
|
private T unbox(Transaction transaction) {
|
||||||
if (transaction.isCommitted()) throw new IllegalStateException();
|
if (transaction.isCommitted()) throw new IllegalStateException();
|
||||||
return txnClass.cast(transaction.unbox());
|
return txnClass.cast(transaction.unbox());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ContactId addContact(Transaction transaction, Author remote,
|
public ContactId addContact(Transaction transaction, Author a,
|
||||||
AuthorId local, boolean verified, boolean active)
|
boolean verified) 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.containsLocalAuthor(txn, local))
|
if (db.containsLocalAuthor(txn, a.getId()))
|
||||||
throw new NoSuchLocalAuthorException();
|
|
||||||
if (db.containsLocalAuthor(txn, remote.getId()))
|
|
||||||
throw new ContactExistsException();
|
throw new ContactExistsException();
|
||||||
if (db.containsContact(txn, remote.getId(), local))
|
if (db.containsContact(txn, a.getId()))
|
||||||
throw new ContactExistsException();
|
throw new ContactExistsException();
|
||||||
ContactId c = db.addContact(txn, remote, local, verified, active);
|
ContactId c = db.addContact(txn, a, verified);
|
||||||
transaction.attach(new ContactAddedEvent(c, active));
|
transaction.attach(new ContactAddedEvent(c));
|
||||||
if (active) transaction.attach(new ContactStatusChangedEvent(c, true));
|
|
||||||
return c;
|
return c;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -226,6 +255,30 @@ 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 {
|
||||||
@@ -254,6 +307,16 @@ 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 {
|
||||||
@@ -264,8 +327,8 @@ class DatabaseComponentImpl<T> implements DatabaseComponent {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public KeySetId addTransportKeys(Transaction transaction, ContactId c,
|
public TransportKeySetId addTransportKeys(Transaction transaction,
|
||||||
TransportKeys k) throws DbException {
|
ContactId c, 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))
|
||||||
@@ -276,12 +339,10 @@ class DatabaseComponentImpl<T> implements DatabaseComponent {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean containsContact(Transaction transaction, AuthorId remote,
|
public boolean containsContact(Transaction transaction, AuthorId a)
|
||||||
AuthorId local) throws DbException {
|
throws DbException {
|
||||||
T txn = unbox(transaction);
|
T txn = unbox(transaction);
|
||||||
if (!db.containsLocalAuthor(txn, local))
|
return db.containsContact(txn, a);
|
||||||
throw new NoSuchLocalAuthorException();
|
|
||||||
return db.containsContact(txn, remote, local);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -298,6 +359,13 @@ 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 {
|
||||||
@@ -414,6 +482,15 @@ 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 {
|
||||||
@@ -421,22 +498,6 @@ 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 {
|
||||||
@@ -471,6 +532,15 @@ 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 {
|
||||||
@@ -564,7 +634,7 @@ class DatabaseComponentImpl<T> implements DatabaseComponent {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public State getMessageState(Transaction transaction, MessageId m)
|
public MessageState getMessageState(Transaction transaction, MessageId m)
|
||||||
throws DbException {
|
throws DbException {
|
||||||
T txn = unbox(transaction);
|
T txn = unbox(transaction);
|
||||||
if (!db.containsMessage(txn, m))
|
if (!db.containsMessage(txn, m))
|
||||||
@@ -604,8 +674,8 @@ class DatabaseComponentImpl<T> implements DatabaseComponent {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Map<MessageId, State> getMessageDependencies(Transaction transaction,
|
public Map<MessageId, MessageState> getMessageDependencies(
|
||||||
MessageId m) throws DbException {
|
Transaction transaction, MessageId m) throws DbException {
|
||||||
T txn = unbox(transaction);
|
T txn = unbox(transaction);
|
||||||
if (!db.containsMessage(txn, m))
|
if (!db.containsMessage(txn, m))
|
||||||
throw new NoSuchMessageException();
|
throw new NoSuchMessageException();
|
||||||
@@ -613,8 +683,8 @@ class DatabaseComponentImpl<T> implements DatabaseComponent {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Map<MessageId, State> getMessageDependents(Transaction transaction,
|
public Map<MessageId, MessageState> getMessageDependents(
|
||||||
MessageId m) throws DbException {
|
Transaction transaction, MessageId m) throws DbException {
|
||||||
T txn = unbox(transaction);
|
T txn = unbox(transaction);
|
||||||
if (!db.containsMessage(txn, m))
|
if (!db.containsMessage(txn, m))
|
||||||
throw new NoSuchMessageException();
|
throw new NoSuchMessageException();
|
||||||
@@ -628,6 +698,13 @@ 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 {
|
||||||
@@ -636,7 +713,7 @@ class DatabaseComponentImpl<T> implements DatabaseComponent {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Collection<KeySet> getTransportKeys(Transaction transaction,
|
public Collection<TransportKeySet> 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))
|
||||||
@@ -646,7 +723,17 @@ class DatabaseComponentImpl<T> implements DatabaseComponent {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void incrementStreamCounter(Transaction transaction, TransportId t,
|
public void incrementStreamCounter(Transaction transaction, TransportId t,
|
||||||
KeySetId k) throws DbException {
|
HandshakeKeySetId k) throws DbException {
|
||||||
|
if (transaction.isReadOnly()) throw new IllegalArgumentException();
|
||||||
|
T txn = unbox(transaction);
|
||||||
|
if (!db.containsTransport(txn, t))
|
||||||
|
throw new NoSuchTransportException();
|
||||||
|
db.incrementStreamCounter(txn, t, k);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void incrementStreamCounter(Transaction transaction, TransportId t,
|
||||||
|
TransportKeySetId k) throws DbException {
|
||||||
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))
|
||||||
@@ -795,6 +882,16 @@ 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 {
|
||||||
@@ -817,6 +914,16 @@ 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 {
|
||||||
@@ -829,7 +936,7 @@ class DatabaseComponentImpl<T> implements DatabaseComponent {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void removeTransportKeys(Transaction transaction,
|
public void removeTransportKeys(Transaction transaction,
|
||||||
TransportId t, KeySetId k) throws DbException {
|
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))
|
||||||
@@ -848,20 +955,9 @@ 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,
|
||||||
String alias) throws DbException {
|
@Nullable String alias) 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))
|
||||||
@@ -903,7 +999,7 @@ class DatabaseComponentImpl<T> implements DatabaseComponent {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setMessageState(Transaction transaction, MessageId m,
|
public void setMessageState(Transaction transaction, MessageId m,
|
||||||
State state) throws DbException {
|
MessageState state) throws DbException {
|
||||||
if (transaction.isReadOnly()) throw new IllegalArgumentException();
|
if (transaction.isReadOnly()) throw new IllegalArgumentException();
|
||||||
T txn = unbox(transaction);
|
T txn = unbox(transaction);
|
||||||
if (!db.containsMessage(txn, m))
|
if (!db.containsMessage(txn, m))
|
||||||
@@ -920,27 +1016,38 @@ class DatabaseComponentImpl<T> implements DatabaseComponent {
|
|||||||
T txn = unbox(transaction);
|
T txn = unbox(transaction);
|
||||||
if (!db.containsMessage(txn, dependent.getId()))
|
if (!db.containsMessage(txn, dependent.getId()))
|
||||||
throw new NoSuchMessageException();
|
throw new NoSuchMessageException();
|
||||||
State dependentState = db.getMessageState(txn, dependent.getId());
|
MessageState dependentState =
|
||||||
|
db.getMessageState(txn, dependent.getId());
|
||||||
for (MessageId dependency : dependencies) {
|
for (MessageId dependency : dependencies) {
|
||||||
db.addMessageDependency(txn, dependent, dependency,
|
db.addMessageDependency(txn, dependent, dependency, dependentState);
|
||||||
dependentState);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setReorderingWindow(Transaction transaction, KeySetId k,
|
public void setReorderingWindow(Transaction transaction,
|
||||||
TransportId t, long rotationPeriod, long base, byte[] bitmap)
|
TransportKeySetId k, TransportId t, long timePeriod, long base,
|
||||||
throws DbException {
|
byte[] bitmap) 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, rotationPeriod, base, bitmap);
|
db.setReorderingWindow(txn, k, t, timePeriod, base, bitmap);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setReorderingWindow(Transaction transaction,
|
||||||
|
HandshakeKeySetId k, TransportId t, long timePeriod, long base,
|
||||||
|
byte[] bitmap) throws DbException {
|
||||||
|
if (transaction.isReadOnly()) throw new IllegalArgumentException();
|
||||||
|
T txn = unbox(transaction);
|
||||||
|
if (!db.containsTransport(txn, t))
|
||||||
|
throw new NoSuchTransportException();
|
||||||
|
db.setReorderingWindow(txn, k, t, timePeriod, base, bitmap);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setTransportKeysActive(Transaction transaction, TransportId t,
|
public void setTransportKeysActive(Transaction transaction, TransportId t,
|
||||||
KeySetId k) throws DbException {
|
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))
|
||||||
@@ -949,14 +1056,39 @@ class DatabaseComponentImpl<T> implements DatabaseComponent {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void updateTransportKeys(Transaction transaction,
|
public void updateHandshakeKeys(Transaction transaction,
|
||||||
Collection<KeySet> keys) throws DbException {
|
Collection<HandshakeKeySet> keys) throws DbException {
|
||||||
if (transaction.isReadOnly()) throw new IllegalArgumentException();
|
if (transaction.isReadOnly()) throw new IllegalArgumentException();
|
||||||
T txn = unbox(transaction);
|
T txn = unbox(transaction);
|
||||||
for (KeySet ks : keys) {
|
for (HandshakeKeySet ks : keys) {
|
||||||
TransportId t = ks.getTransportKeys().getTransportId();
|
TransportId t = ks.getKeys().getTransportId();
|
||||||
|
if (db.containsTransport(txn, t))
|
||||||
|
db.updateHandshakeKeys(txn, ks);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void updateTransportKeys(Transaction transaction,
|
||||||
|
Collection<TransportKeySet> keys) throws DbException {
|
||||||
|
if (transaction.isReadOnly()) throw new IllegalArgumentException();
|
||||||
|
T txn = unbox(transaction);
|
||||||
|
for (TransportKeySet ks : keys) {
|
||||||
|
TransportId t = ks.getKeys().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,11 +3,13 @@ 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;
|
||||||
|
|
||||||
@@ -27,8 +29,9 @@ public class DatabaseModule {
|
|||||||
@Provides
|
@Provides
|
||||||
@Singleton
|
@Singleton
|
||||||
DatabaseComponent provideDatabaseComponent(Database<Connection> db,
|
DatabaseComponent provideDatabaseComponent(Database<Connection> db,
|
||||||
EventBus eventBus, ShutdownManager shutdown) {
|
EventBus eventBus, @EventExecutor Executor eventExecutor,
|
||||||
|
ShutdownManager shutdownManager) {
|
||||||
return new DatabaseComponentImpl<>(db, Connection.class, eventBus,
|
return new DatabaseComponentImpl<>(db, Connection.class, eventBus,
|
||||||
shutdown);
|
eventExecutor, shutdownManager);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ package org.briarproject.bramble.db;
|
|||||||
class DatabaseTypes {
|
class DatabaseTypes {
|
||||||
|
|
||||||
private final String hashType, secretType, binaryType;
|
private final String hashType, secretType, binaryType;
|
||||||
private final String counterType, stringType;
|
private final String counterType, stringType;
|
||||||
|
|
||||||
public DatabaseTypes(String hashType, String secretType, String binaryType,
|
public DatabaseTypes(String hashType, String secretType, String binaryType,
|
||||||
String counterType, String stringType) {
|
String counterType, String stringType) {
|
||||||
@@ -17,11 +17,11 @@ class DatabaseTypes {
|
|||||||
/**
|
/**
|
||||||
* Replaces database type placeholders in a statement with the actual types.
|
* Replaces database type placeholders in a statement with the actual types.
|
||||||
* These placeholders are currently supported:
|
* These placeholders are currently supported:
|
||||||
* <li> _HASH
|
* <li> _HASH
|
||||||
* <li> _SECRET
|
* <li> _SECRET
|
||||||
* <li> _BINARY
|
* <li> _BINARY
|
||||||
* <li> _COUNTER
|
* <li> _COUNTER
|
||||||
* <li> _STRING
|
* <li> _STRING
|
||||||
*/
|
*/
|
||||||
String replaceTypes(String s) {
|
String replaceTypes(String s) {
|
||||||
s = s.replaceAll("_HASH", hashType);
|
s = s.replaceAll("_HASH", hashType);
|
||||||
|
|||||||
@@ -15,16 +15,23 @@ import java.sql.DriverManager;
|
|||||||
import java.sql.SQLException;
|
import java.sql.SQLException;
|
||||||
import java.sql.Statement;
|
import java.sql.Statement;
|
||||||
import java.util.Properties;
|
import java.util.Properties;
|
||||||
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
|
|
||||||
|
import static java.util.logging.Level.WARNING;
|
||||||
|
import static java.util.logging.Logger.getLogger;
|
||||||
|
import static org.briarproject.bramble.db.JdbcUtils.tryToClose;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Contains all the H2-specific code for the database.
|
* Contains all the H2-specific code for the database.
|
||||||
*/
|
*/
|
||||||
@NotNullByDefault
|
@NotNullByDefault
|
||||||
class H2Database extends JdbcDatabase {
|
class H2Database extends JdbcDatabase {
|
||||||
|
|
||||||
|
private static final Logger LOG = getLogger(H2Database.class.getName());
|
||||||
|
|
||||||
private static final String HASH_TYPE = "BINARY(32)";
|
private static final String HASH_TYPE = "BINARY(32)";
|
||||||
private static final String SECRET_TYPE = "BINARY(32)";
|
private static final String SECRET_TYPE = "BINARY(32)";
|
||||||
private static final String BINARY_TYPE = "BINARY";
|
private static final String BINARY_TYPE = "BINARY";
|
||||||
@@ -69,30 +76,6 @@ 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;
|
||||||
@@ -121,8 +104,8 @@ class H2Database extends JdbcDatabase {
|
|||||||
s.close();
|
s.close();
|
||||||
c.close();
|
c.close();
|
||||||
} catch (SQLException e) {
|
} catch (SQLException e) {
|
||||||
tryToClose(s);
|
tryToClose(s, LOG, WARNING);
|
||||||
tryToClose(c);
|
tryToClose(c, LOG, WARNING);
|
||||||
throw new DbException(e);
|
throw new DbException(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,16 +14,24 @@ import java.sql.Connection;
|
|||||||
import java.sql.DriverManager;
|
import java.sql.DriverManager;
|
||||||
import java.sql.SQLException;
|
import java.sql.SQLException;
|
||||||
import java.sql.Statement;
|
import java.sql.Statement;
|
||||||
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
|
|
||||||
|
import static java.util.logging.Level.WARNING;
|
||||||
|
import static java.util.logging.Logger.getLogger;
|
||||||
|
import static org.briarproject.bramble.db.JdbcUtils.tryToClose;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Contains all the HSQLDB-specific code for the database.
|
* Contains all the HSQLDB-specific code for the database.
|
||||||
*/
|
*/
|
||||||
@NotNullByDefault
|
@NotNullByDefault
|
||||||
class HyperSqlDatabase extends JdbcDatabase {
|
class HyperSqlDatabase extends JdbcDatabase {
|
||||||
|
|
||||||
|
private static final Logger LOG =
|
||||||
|
getLogger(HyperSqlDatabase.class.getName());
|
||||||
|
|
||||||
private static final String HASH_TYPE = "BINARY(32)";
|
private static final String HASH_TYPE = "BINARY(32)";
|
||||||
private static final String SECRET_TYPE = "BINARY(32)";
|
private static final String SECRET_TYPE = "BINARY(32)";
|
||||||
private static final String BINARY_TYPE = "BINARY";
|
private static final String BINARY_TYPE = "BINARY";
|
||||||
@@ -72,36 +80,12 @@ class HyperSqlDatabase extends JdbcDatabase {
|
|||||||
s.close();
|
s.close();
|
||||||
c.close();
|
c.close();
|
||||||
} catch (SQLException e) {
|
} catch (SQLException e) {
|
||||||
tryToClose(s);
|
tryToClose(s, LOG, WARNING);
|
||||||
tryToClose(c);
|
tryToClose(c, LOG, WARNING);
|
||||||
throw new DbException(e);
|
throw new DbException(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@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;
|
||||||
@@ -122,8 +106,8 @@ class HyperSqlDatabase extends JdbcDatabase {
|
|||||||
s.close();
|
s.close();
|
||||||
c.close();
|
c.close();
|
||||||
} catch (SQLException e) {
|
} catch (SQLException e) {
|
||||||
tryToClose(s);
|
tryToClose(s, LOG, WARNING);
|
||||||
tryToClose(c);
|
tryToClose(c, LOG, WARNING);
|
||||||
throw new DbException(e);
|
throw new DbException(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user