mirror of
https://code.briarproject.org/briar/briar.git
synced 2026-02-12 10:49:06 +01:00
Compare commits
254 Commits
release-1.
...
test-immed
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
33bfef12e4 | ||
|
|
92163d6a99 | ||
|
|
c09abdb088 | ||
|
|
45a11badd5 | ||
|
|
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 | ||
|
|
baf64e1129 | ||
|
|
88adfabe09 | ||
|
|
6565172e10 | ||
|
|
7447468ce5 | ||
|
|
2db2a1a208 | ||
|
|
0d7e4feaf2 | ||
|
|
eb3983f6b2 | ||
|
|
e2ce49c30e | ||
|
|
adc6fb2fd5 | ||
|
|
969150bff0 | ||
|
|
8fc622f85d | ||
|
|
22eed91019 | ||
|
|
fcb88ed58c | ||
|
|
0d940fc7d7 | ||
|
|
ca6dc33cdd | ||
|
|
53da13794f | ||
|
|
2ab03f48cc | ||
|
|
436f45554d | ||
|
|
51209b5eec | ||
|
|
822597b4c6 | ||
|
|
7c01bc59c0 | ||
|
|
825d342f9b | ||
|
|
34955fecbb | ||
|
|
5c28b60a6b | ||
|
|
389b2b5b8e | ||
|
|
78abfa3698 | ||
|
|
9c4fb4fd34 | ||
|
|
3d6a336f6d | ||
|
|
e47d41596a | ||
|
|
8cf54bcedb | ||
|
|
89d5145665 | ||
|
|
0706498b03 | ||
|
|
b296500e7a | ||
|
|
60a8b03344 | ||
|
|
ae16a93522 | ||
|
|
c9a2ff71ae | ||
|
|
16f4c60a56 | ||
|
|
76121eb871 | ||
|
|
47c91a96ae | ||
|
|
14befb957b | ||
|
|
4b7a81177c | ||
|
|
b464fe1653 | ||
|
|
09c6f09805 | ||
|
|
a93093182d | ||
|
|
9515e93857 | ||
|
|
efe15df940 | ||
|
|
de611857cf | ||
|
|
8935ec2c2e | ||
|
|
bd00fb1c04 | ||
|
|
3192015cfd | ||
|
|
e776ee02b0 | ||
|
|
c0553ec11f | ||
|
|
75a871a2f8 | ||
|
|
d6d3d5acef | ||
|
|
a361a2613c | ||
|
|
b68dbd6a75 | ||
|
|
f1e89a3ff4 | ||
|
|
056c23167d | ||
|
|
79d5612645 | ||
|
|
a030f92275 | ||
|
|
b3615b4a77 | ||
|
|
8a15fb242a | ||
|
|
e3686186ee | ||
|
|
18ae388137 | ||
|
|
775031e893 | ||
|
|
9f91b91a4f | ||
|
|
280f3ba1fc | ||
|
|
66619fd3a4 | ||
|
|
c7eb0cbb6d | ||
|
|
1617a95bb9 | ||
|
|
6f54718756 | ||
|
|
ea749f2128 | ||
|
|
b4b0d3daa6 | ||
|
|
609c90f57e | ||
|
|
5cf68fa134 | ||
|
|
61c9c6b8eb | ||
|
|
e97608da40 | ||
|
|
0bb80b1a15 | ||
|
|
bda52ea548 | ||
|
|
cf033dc29d | ||
|
|
c12cedc371 | ||
|
|
4b5e9bd64f | ||
|
|
8d55911dab | ||
|
|
e381f83512 | ||
|
|
e4c7f13832 | ||
|
|
b089a204d3 | ||
|
|
85fcb34997 | ||
|
|
d6d132a9cf | ||
|
|
98d1ea7730 | ||
|
|
159fd34c0c | ||
|
|
9e7a387ea4 | ||
|
|
138e520e6c | ||
|
|
5783c1dfd8 | ||
|
|
348968018a | ||
|
|
33c509cd1f | ||
|
|
bea77151bd | ||
|
|
787e62345f | ||
|
|
48f6a3b91f | ||
|
|
a798e25bf2 | ||
|
|
31e4045cf7 | ||
|
|
5334a8c9ca | ||
|
|
d11f1d2805 | ||
|
|
0d1ebddcd2 | ||
|
|
6c296c1348 | ||
|
|
87701e5f07 | ||
|
|
3aae01d152 | ||
|
|
bc298ba68a | ||
|
|
2623eaa149 | ||
|
|
7359b6942a | ||
|
|
3bcc532b4b | ||
|
|
4d08c69779 | ||
|
|
a6cd8937f7 | ||
|
|
e8566906ef | ||
|
|
929102ed60 | ||
|
|
3b871f5932 | ||
|
|
b972d1fc13 | ||
|
|
ccbeee60a7 | ||
|
|
074b10e177 | ||
|
|
031516ccce | ||
|
|
7d2f1abb94 | ||
|
|
00b9c76bb8 | ||
|
|
4d9fab85cb | ||
|
|
bd2514a299 | ||
|
|
e795efc7fc | ||
|
|
6691d2164f | ||
|
|
a384450c36 | ||
|
|
b375e9873c | ||
|
|
cb30c3885a | ||
|
|
6ee81eb24c | ||
|
|
c14ebe82ce | ||
|
|
00e9f894b1 | ||
|
|
499c586a59 | ||
|
|
64f9ce7306 | ||
|
|
071d961ed1 | ||
|
|
cb9efc5fec | ||
|
|
f9e292f734 |
@@ -12,7 +12,7 @@ test:
|
||||
|
||||
script:
|
||||
- ./gradlew --no-daemon -Djava.security.egd=file:/dev/urandom animalSnifferMain animalSnifferTest
|
||||
- ./gradlew --no-daemon -Djava.security.egd=file:/dev/urandom test
|
||||
- ./gradlew --no-daemon -Djava.security.egd=file:/dev/urandom test --continue
|
||||
|
||||
after_script:
|
||||
# these file change every time but should not be cached
|
||||
|
||||
9
.idea/codeStyles/Project.xml
generated
9
.idea/codeStyles/Project.xml
generated
@@ -36,6 +36,9 @@
|
||||
<option name="JD_ALIGN_PARAM_COMMENTS" value="false" />
|
||||
<option name="JD_ALIGN_EXCEPTION_COMMENTS" value="false" />
|
||||
</JavaCodeStyleSettings>
|
||||
<JetCodeStyleSettings>
|
||||
<option name="CODE_STYLE_DEFAULTS" value="KOTLIN_OFFICIAL" />
|
||||
</JetCodeStyleSettings>
|
||||
<Objective-C-extensions>
|
||||
<file>
|
||||
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Import" />
|
||||
@@ -257,5 +260,11 @@
|
||||
</rules>
|
||||
</arrangement>
|
||||
</codeStyleSettings>
|
||||
<codeStyleSettings language="kotlin">
|
||||
<option name="CODE_STYLE_DEFAULTS" value="KOTLIN_OFFICIAL" />
|
||||
<option name="PARAMETER_ANNOTATION_WRAP" value="1" />
|
||||
<option name="VARIABLE_ANNOTATION_WRAP" value="1" />
|
||||
<option name="ENUM_CONSTANTS_WRAP" value="1" />
|
||||
</codeStyleSettings>
|
||||
</code_scheme>
|
||||
</component>
|
||||
20
.idea/runConfigurations/All_in_briar_headless.xml
generated
Normal file
20
.idea/runConfigurations/All_in_briar_headless.xml
generated
Normal file
@@ -0,0 +1,20 @@
|
||||
<component name="ProjectRunConfigurationManager">
|
||||
<configuration default="false" name="All in briar-headless" type="AndroidJUnit" factoryName="Android JUnit" nameIsGenerated="true">
|
||||
<module name="briar-headless" />
|
||||
<option name="ALTERNATIVE_JRE_PATH_ENABLED" value="false" />
|
||||
<option name="ALTERNATIVE_JRE_PATH" />
|
||||
<option name="PACKAGE_NAME" value="org.briarproject.briar.headless" />
|
||||
<option name="MAIN_CLASS_NAME" value="" />
|
||||
<option name="METHOD_NAME" value="" />
|
||||
<option name="TEST_OBJECT" value="package" />
|
||||
<option name="VM_PARAMETERS" value="" />
|
||||
<option name="PARAMETERS" value="" />
|
||||
<option name="WORKING_DIRECTORY" value="file://$PROJECT_DIR$/briar-headless" />
|
||||
<option name="PASS_PARENT_ENVS" value="true" />
|
||||
<option name="TEST_SEARCH_SCOPE">
|
||||
<value defaultName="singleModule" />
|
||||
</option>
|
||||
<patterns />
|
||||
<method />
|
||||
</configuration>
|
||||
</component>
|
||||
3
.idea/runConfigurations/All_tests.xml
generated
3
.idea/runConfigurations/All_tests.xml
generated
@@ -24,6 +24,7 @@
|
||||
<option name="RunConfigurationTask" enabled="true" run_configuration_name="All tests in bramble-android" run_configuration_type="AndroidJUnit" />
|
||||
<option name="RunConfigurationTask" enabled="true" run_configuration_name="All tests in bramble-java" run_configuration_type="AndroidJUnit" />
|
||||
<option name="RunConfigurationTask" enabled="true" run_configuration_name="All tests in briar-core" run_configuration_type="AndroidJUnit" />
|
||||
<option name="RunConfigurationTask" enabled="true" run_configuration_name="All in briar-headless" run_configuration_type="AndroidJUnit" />
|
||||
</method>
|
||||
</configuration>
|
||||
</component>
|
||||
</component>
|
||||
@@ -1,6 +1,5 @@
|
||||
<component name="ProjectRunConfigurationManager">
|
||||
<configuration default="false" name="All tests in bramble-android" type="AndroidJUnit" factoryName="Android JUnit">
|
||||
<extension name="coverage" enabled="false" merge="false" sample_coverage="true" runner="idea" />
|
||||
<module name="bramble-android" />
|
||||
<option name="ALTERNATIVE_JRE_PATH_ENABLED" value="false" />
|
||||
<option name="ALTERNATIVE_JRE_PATH" />
|
||||
@@ -11,12 +10,10 @@
|
||||
<option name="VM_PARAMETERS" value="-ea" />
|
||||
<option name="PARAMETERS" value="" />
|
||||
<option name="WORKING_DIRECTORY" value="file://$PROJECT_DIR$/bramble-android" />
|
||||
<option name="ENV_VARIABLES" />
|
||||
<option name="PASS_PARENT_ENVS" value="true" />
|
||||
<option name="TEST_SEARCH_SCOPE">
|
||||
<value defaultName="singleModule" />
|
||||
</option>
|
||||
<envs />
|
||||
<patterns />
|
||||
<method />
|
||||
</configuration>
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
<component name="ProjectRunConfigurationManager">
|
||||
<configuration default="false" name="All tests in bramble-api" type="AndroidJUnit" factoryName="Android JUnit">
|
||||
<extension name="coverage" enabled="false" merge="false" sample_coverage="true" runner="idea" />
|
||||
<module name="bramble-api" />
|
||||
<option name="ALTERNATIVE_JRE_PATH_ENABLED" value="false" />
|
||||
<option name="ALTERNATIVE_JRE_PATH" />
|
||||
@@ -11,12 +10,10 @@
|
||||
<option name="VM_PARAMETERS" value="-ea" />
|
||||
<option name="PARAMETERS" value="" />
|
||||
<option name="WORKING_DIRECTORY" value="file://$PROJECT_DIR$/bramble-api" />
|
||||
<option name="ENV_VARIABLES" />
|
||||
<option name="PASS_PARENT_ENVS" value="true" />
|
||||
<option name="TEST_SEARCH_SCOPE">
|
||||
<value defaultName="singleModule" />
|
||||
</option>
|
||||
<envs />
|
||||
<patterns />
|
||||
<method />
|
||||
</configuration>
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
<component name="ProjectRunConfigurationManager">
|
||||
<configuration default="false" name="All tests in bramble-core" type="AndroidJUnit" factoryName="Android JUnit">
|
||||
<extension name="coverage" enabled="false" merge="false" sample_coverage="true" runner="idea" />
|
||||
<module name="bramble-core" />
|
||||
<option name="ALTERNATIVE_JRE_PATH_ENABLED" value="false" />
|
||||
<option name="ALTERNATIVE_JRE_PATH" />
|
||||
@@ -11,12 +10,10 @@
|
||||
<option name="VM_PARAMETERS" value="-ea" />
|
||||
<option name="PARAMETERS" value="" />
|
||||
<option name="WORKING_DIRECTORY" value="file://$PROJECT_DIR$/bramble-core" />
|
||||
<option name="ENV_VARIABLES" />
|
||||
<option name="PASS_PARENT_ENVS" value="true" />
|
||||
<option name="TEST_SEARCH_SCOPE">
|
||||
<value defaultName="singleModule" />
|
||||
</option>
|
||||
<envs />
|
||||
<patterns />
|
||||
<method />
|
||||
</configuration>
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
<component name="ProjectRunConfigurationManager">
|
||||
<configuration default="false" name="All tests in bramble-java" type="AndroidJUnit" factoryName="Android JUnit">
|
||||
<extension name="coverage" enabled="false" merge="false" sample_coverage="true" runner="idea" />
|
||||
<module name="bramble-java" />
|
||||
<option name="ALTERNATIVE_JRE_PATH_ENABLED" value="false" />
|
||||
<option name="ALTERNATIVE_JRE_PATH" />
|
||||
@@ -11,12 +10,10 @@
|
||||
<option name="VM_PARAMETERS" value="-ea -Djava.library.path=libs" />
|
||||
<option name="PARAMETERS" value="" />
|
||||
<option name="WORKING_DIRECTORY" value="file://$PROJECT_DIR$/bramble-java" />
|
||||
<option name="ENV_VARIABLES" />
|
||||
<option name="PASS_PARENT_ENVS" value="true" />
|
||||
<option name="TEST_SEARCH_SCOPE">
|
||||
<value defaultName="singleModule" />
|
||||
</option>
|
||||
<envs />
|
||||
<patterns />
|
||||
<method />
|
||||
</configuration>
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
<component name="ProjectRunConfigurationManager">
|
||||
<configuration default="false" name="All tests in briar-android" type="AndroidJUnit" factoryName="Android JUnit">
|
||||
<extension name="coverage" enabled="false" merge="false" sample_coverage="true" runner="idea" />
|
||||
<module name="briar-android" />
|
||||
<option name="ALTERNATIVE_JRE_PATH_ENABLED" value="false" />
|
||||
<option name="ALTERNATIVE_JRE_PATH" />
|
||||
@@ -11,12 +10,10 @@
|
||||
<option name="VM_PARAMETERS" value="-ea" />
|
||||
<option name="PARAMETERS" value="" />
|
||||
<option name="WORKING_DIRECTORY" value="file://$PROJECT_DIR$/briar-android" />
|
||||
<option name="ENV_VARIABLES" />
|
||||
<option name="PASS_PARENT_ENVS" value="true" />
|
||||
<option name="TEST_SEARCH_SCOPE">
|
||||
<value defaultName="singleModule" />
|
||||
</option>
|
||||
<envs />
|
||||
<patterns />
|
||||
<method />
|
||||
</configuration>
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
<component name="ProjectRunConfigurationManager">
|
||||
<configuration default="false" name="All tests in briar-core" type="AndroidJUnit" factoryName="Android JUnit">
|
||||
<extension name="coverage" enabled="false" merge="false" sample_coverage="true" runner="idea" />
|
||||
<module name="briar-core" />
|
||||
<option name="ALTERNATIVE_JRE_PATH_ENABLED" value="false" />
|
||||
<option name="ALTERNATIVE_JRE_PATH" />
|
||||
@@ -11,12 +10,10 @@
|
||||
<option name="VM_PARAMETERS" value="-ea" />
|
||||
<option name="PARAMETERS" value="" />
|
||||
<option name="WORKING_DIRECTORY" value="file://$PROJECT_DIR$/briar-core" />
|
||||
<option name="ENV_VARIABLES" />
|
||||
<option name="PASS_PARENT_ENVS" value="true" />
|
||||
<option name="TEST_SEARCH_SCOPE">
|
||||
<value defaultName="singleModule" />
|
||||
</option>
|
||||
<envs />
|
||||
<patterns />
|
||||
<method />
|
||||
</configuration>
|
||||
|
||||
3
.idea/runConfigurations/H2_Performance_Test.xml
generated
3
.idea/runConfigurations/H2_Performance_Test.xml
generated
@@ -1,6 +1,5 @@
|
||||
<component name="ProjectRunConfigurationManager">
|
||||
<configuration default="false" name="H2 Performance Test" type="AndroidJUnit" factoryName="Android JUnit">
|
||||
<extension name="coverage" enabled="false" merge="false" sample_coverage="true" runner="idea" />
|
||||
<module name="bramble-core" />
|
||||
<option name="ALTERNATIVE_JRE_PATH_ENABLED" value="false" />
|
||||
<option name="ALTERNATIVE_JRE_PATH" />
|
||||
@@ -11,12 +10,10 @@
|
||||
<option name="VM_PARAMETERS" value="-ea" />
|
||||
<option name="PARAMETERS" value="" />
|
||||
<option name="WORKING_DIRECTORY" value="" />
|
||||
<option name="ENV_VARIABLES" />
|
||||
<option name="PASS_PARENT_ENVS" value="true" />
|
||||
<option name="TEST_SEARCH_SCOPE">
|
||||
<value defaultName="singleModule" />
|
||||
</option>
|
||||
<envs />
|
||||
<patterns />
|
||||
<method />
|
||||
</configuration>
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
<component name="ProjectRunConfigurationManager">
|
||||
<configuration default="false" name="HyperSQL Performance Test" type="AndroidJUnit" factoryName="Android JUnit">
|
||||
<extension name="coverage" enabled="false" merge="false" sample_coverage="true" runner="idea" />
|
||||
<module name="bramble-core" />
|
||||
<option name="ALTERNATIVE_JRE_PATH_ENABLED" value="false" />
|
||||
<option name="ALTERNATIVE_JRE_PATH" />
|
||||
@@ -11,12 +10,10 @@
|
||||
<option name="VM_PARAMETERS" value="-ea" />
|
||||
<option name="PARAMETERS" value="" />
|
||||
<option name="WORKING_DIRECTORY" value="" />
|
||||
<option name="ENV_VARIABLES" />
|
||||
<option name="PASS_PARENT_ENVS" value="true" />
|
||||
<option name="TEST_SEARCH_SCOPE">
|
||||
<value defaultName="singleModule" />
|
||||
</option>
|
||||
<envs />
|
||||
<patterns />
|
||||
<method />
|
||||
</configuration>
|
||||
|
||||
17
.idea/runConfigurations/briar_headless.xml
generated
Normal file
17
.idea/runConfigurations/briar_headless.xml
generated
Normal file
@@ -0,0 +1,17 @@
|
||||
<component name="ProjectRunConfigurationManager">
|
||||
<configuration default="false" name="briar-headless" type="JetRunConfigurationType" factoryName="Kotlin" singleton="true">
|
||||
<extension name="coverage" enabled="false" merge="false" sample_coverage="true" runner="idea" />
|
||||
<option name="VM_PARAMETERS" value="" />
|
||||
<option name="PROGRAM_PARAMETERS" value="-v" />
|
||||
<option name="ALTERNATIVE_JRE_PATH_ENABLED" value="false" />
|
||||
<option name="ALTERNATIVE_JRE_PATH" />
|
||||
<option name="PASS_PARENT_ENVS" value="true" />
|
||||
<option name="MAIN_CLASS_NAME" value="org.briarproject.briar.headless.MainKt" />
|
||||
<option name="WORKING_DIRECTORY" value="" />
|
||||
<module name="briar-headless" />
|
||||
<envs />
|
||||
<method>
|
||||
<option name="Gradle.BeforeRunTask" enabled="true" tasks="jar" externalProjectPath="$PROJECT_DIR$/briar-headless" vmOptions="" scriptParameters="" />
|
||||
</method>
|
||||
</configuration>
|
||||
</component>
|
||||
@@ -1,16 +1,18 @@
|
||||
import com.android.build.gradle.tasks.MergeResources
|
||||
|
||||
apply plugin: 'com.android.library'
|
||||
apply plugin: 'witness'
|
||||
apply from: 'witness.gradle'
|
||||
|
||||
android {
|
||||
compileSdkVersion 27
|
||||
buildToolsVersion '27.0.3'
|
||||
compileSdkVersion 28
|
||||
buildToolsVersion '28.0.3'
|
||||
|
||||
defaultConfig {
|
||||
minSdkVersion 14
|
||||
targetSdkVersion 26
|
||||
versionCode 10102
|
||||
versionName "1.1.2"
|
||||
versionCode 10105
|
||||
versionName "1.1.5"
|
||||
consumerProguardFiles 'proguard-rules.txt'
|
||||
|
||||
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
|
||||
@@ -28,9 +30,10 @@ configurations {
|
||||
|
||||
dependencies {
|
||||
implementation project(path: ':bramble-core', configuration: 'default')
|
||||
tor 'org.briarproject:tor-android:0.2.9.16@zip'
|
||||
tor 'org.briarproject:tor-android:0.3.4.8@zip'
|
||||
tor 'org.briarproject:obfs4proxy-android:0.0.7@zip'
|
||||
|
||||
annotationProcessor 'com.google.dagger:dagger-compiler:2.0.2'
|
||||
annotationProcessor 'com.google.dagger:dagger-compiler:2.19'
|
||||
|
||||
compileOnly 'javax.annotation:jsr250-api:1.0'
|
||||
|
||||
@@ -39,13 +42,29 @@ dependencies {
|
||||
testImplementation "org.jmock:jmock:2.8.2"
|
||||
testImplementation "org.jmock:jmock-junit4:2.8.2"
|
||||
testImplementation "org.jmock:jmock-legacy:2.8.2"
|
||||
testImplementation "org.hamcrest:hamcrest-library:1.3"
|
||||
testImplementation "org.hamcrest:hamcrest-core:1.3"
|
||||
}
|
||||
|
||||
project.afterEvaluate {
|
||||
copy {
|
||||
from configurations.tor.collect { zipTree(it) }
|
||||
into 'src/main/res/raw'
|
||||
def torBinariesDir = 'src/main/res/raw'
|
||||
|
||||
task cleanTorBinaries {
|
||||
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;
|
||||
|
||||
import org.briarproject.bramble.battery.AndroidBatteryModule;
|
||||
import org.briarproject.bramble.network.AndroidNetworkModule;
|
||||
import org.briarproject.bramble.plugin.tor.CircumventionModule;
|
||||
import org.briarproject.bramble.system.AndroidSystemModule;
|
||||
@@ -7,10 +8,15 @@ import org.briarproject.bramble.system.AndroidSystemModule;
|
||||
import dagger.Module;
|
||||
|
||||
@Module(includes = {
|
||||
AndroidBatteryModule.class,
|
||||
AndroidNetworkModule.class,
|
||||
AndroidSystemModule.class,
|
||||
CircumventionModule.class
|
||||
})
|
||||
public class BrambleAndroidModule {
|
||||
|
||||
public static void initEagerSingletons(BrambleAndroidEagerSingletons c) {
|
||||
c.inject(new AndroidBatteryModule.EagerSingletons());
|
||||
c.inject(new AndroidNetworkModule.EagerSingletons());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,84 @@
|
||||
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.BATTERY_STATUS_CHARGING;
|
||||
import static android.os.BatteryManager.BATTERY_STATUS_FULL;
|
||||
import static android.os.BatteryManager.EXTRA_STATUS;
|
||||
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_STATUS, -1);
|
||||
return status == BATTERY_STATUS_CHARGING ||
|
||||
status == BATTERY_STATUS_FULL;
|
||||
}
|
||||
|
||||
@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.network.NetworkManager;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Singleton;
|
||||
|
||||
import dagger.Module;
|
||||
@@ -11,6 +12,11 @@ import dagger.Provides;
|
||||
@Module
|
||||
public class AndroidNetworkModule {
|
||||
|
||||
public static class EagerSingletons {
|
||||
@Inject
|
||||
NetworkManager networkManager;
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
NetworkManager provideNetworkManager(LifecycleManager lifecycleManager,
|
||||
|
||||
@@ -16,18 +16,27 @@ import org.briarproject.bramble.api.plugin.PluginException;
|
||||
import org.briarproject.bramble.api.plugin.duplex.DuplexPluginCallback;
|
||||
import org.briarproject.bramble.api.plugin.duplex.DuplexTransportConnection;
|
||||
import org.briarproject.bramble.api.system.AndroidExecutor;
|
||||
import org.briarproject.bramble.api.system.Clock;
|
||||
import org.briarproject.bramble.util.AndroidUtils;
|
||||
|
||||
import java.io.Closeable;
|
||||
import java.io.IOException;
|
||||
import java.security.SecureRandom;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.BlockingQueue;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.Executor;
|
||||
import java.util.concurrent.LinkedBlockingQueue;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import static android.bluetooth.BluetoothAdapter.ACTION_DISCOVERY_FINISHED;
|
||||
import static android.bluetooth.BluetoothAdapter.ACTION_DISCOVERY_STARTED;
|
||||
import static android.bluetooth.BluetoothAdapter.ACTION_SCAN_MODE_CHANGED;
|
||||
import static android.bluetooth.BluetoothAdapter.ACTION_STATE_CHANGED;
|
||||
import static android.bluetooth.BluetoothAdapter.EXTRA_SCAN_MODE;
|
||||
@@ -37,8 +46,13 @@ import static android.bluetooth.BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERA
|
||||
import static android.bluetooth.BluetoothAdapter.SCAN_MODE_NONE;
|
||||
import static android.bluetooth.BluetoothAdapter.STATE_OFF;
|
||||
import static android.bluetooth.BluetoothAdapter.STATE_ON;
|
||||
import static android.bluetooth.BluetoothDevice.ACTION_FOUND;
|
||||
import static android.bluetooth.BluetoothDevice.EXTRA_DEVICE;
|
||||
import static java.util.concurrent.TimeUnit.MILLISECONDS;
|
||||
import static java.util.logging.Level.INFO;
|
||||
import static java.util.logging.Level.WARNING;
|
||||
import static org.briarproject.bramble.util.LogUtils.logException;
|
||||
import static org.briarproject.bramble.util.PrivacyUtils.scrubMacAddress;
|
||||
|
||||
@MethodsNotNullByDefault
|
||||
@ParametersNotNullByDefault
|
||||
@@ -47,8 +61,11 @@ class AndroidBluetoothPlugin extends BluetoothPlugin<BluetoothServerSocket> {
|
||||
private static final Logger LOG =
|
||||
Logger.getLogger(AndroidBluetoothPlugin.class.getName());
|
||||
|
||||
private static final int MAX_DISCOVERY_MS = 10_000;
|
||||
|
||||
private final AndroidExecutor androidExecutor;
|
||||
private final Context appContext;
|
||||
private final Clock clock;
|
||||
|
||||
private volatile boolean wasEnabledByUs = false;
|
||||
private volatile BluetoothStateReceiver receiver = null;
|
||||
@@ -58,12 +75,13 @@ class AndroidBluetoothPlugin extends BluetoothPlugin<BluetoothServerSocket> {
|
||||
|
||||
AndroidBluetoothPlugin(BluetoothConnectionLimiter connectionLimiter,
|
||||
Executor ioExecutor, AndroidExecutor androidExecutor,
|
||||
Context appContext, SecureRandom secureRandom, Backoff backoff,
|
||||
DuplexPluginCallback callback, int maxLatency) {
|
||||
Context appContext, SecureRandom secureRandom, Clock clock,
|
||||
Backoff backoff, DuplexPluginCallback callback, int maxLatency) {
|
||||
super(connectionLimiter, ioExecutor, secureRandom, backoff, callback,
|
||||
maxLatency);
|
||||
this.androidExecutor = androidExecutor;
|
||||
this.appContext = appContext;
|
||||
this.clock = clock;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -182,6 +200,74 @@ class AndroidBluetoothPlugin extends BluetoothPlugin<BluetoothServerSocket> {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
DuplexTransportConnection discoverAndConnect(String uuid) {
|
||||
if (adapter == null) return null;
|
||||
for (String address : discoverDevices()) {
|
||||
try {
|
||||
if (LOG.isLoggable(INFO))
|
||||
LOG.info("Connecting to " + scrubMacAddress(address));
|
||||
return connectTo(address, uuid);
|
||||
} catch (IOException e) {
|
||||
if (LOG.isLoggable(INFO)) {
|
||||
LOG.info("Could not connect to "
|
||||
+ scrubMacAddress(address));
|
||||
}
|
||||
}
|
||||
}
|
||||
LOG.info("Could not connect to any devices");
|
||||
return null;
|
||||
}
|
||||
|
||||
private Collection<String> discoverDevices() {
|
||||
List<String> addresses = new ArrayList<>();
|
||||
BlockingQueue<Intent> intents = new LinkedBlockingQueue<>();
|
||||
DiscoveryReceiver receiver = new DiscoveryReceiver(intents);
|
||||
IntentFilter filter = new IntentFilter();
|
||||
filter.addAction(ACTION_DISCOVERY_STARTED);
|
||||
filter.addAction(ACTION_DISCOVERY_FINISHED);
|
||||
filter.addAction(ACTION_FOUND);
|
||||
appContext.registerReceiver(receiver, filter);
|
||||
try {
|
||||
if (adapter.startDiscovery()) {
|
||||
long now = clock.currentTimeMillis();
|
||||
long end = now + MAX_DISCOVERY_MS;
|
||||
while (now < end) {
|
||||
Intent i = intents.poll(end - now, MILLISECONDS);
|
||||
if (i == null) break;
|
||||
String action = i.getAction();
|
||||
if (ACTION_DISCOVERY_STARTED.equals(action)) {
|
||||
LOG.info("Discovery started");
|
||||
} else if (ACTION_DISCOVERY_FINISHED.equals(action)) {
|
||||
LOG.info("Discovery finished");
|
||||
break;
|
||||
} else if (ACTION_FOUND.equals(action)) {
|
||||
BluetoothDevice d = i.getParcelableExtra(EXTRA_DEVICE);
|
||||
String address = d.getAddress();
|
||||
if (LOG.isLoggable(INFO))
|
||||
LOG.info("Discovered " + scrubMacAddress(address));
|
||||
if (!addresses.contains(address))
|
||||
addresses.add(address);
|
||||
}
|
||||
now = clock.currentTimeMillis();
|
||||
}
|
||||
} else {
|
||||
LOG.info("Could not start discovery");
|
||||
}
|
||||
} catch (InterruptedException e) {
|
||||
LOG.info("Interrupted while discovering devices");
|
||||
Thread.currentThread().interrupt();
|
||||
} finally {
|
||||
LOG.info("Cancelling discovery");
|
||||
adapter.cancelDiscovery();
|
||||
appContext.unregisterReceiver(receiver);
|
||||
}
|
||||
// Shuffle the addresses so we don't always try the same one first
|
||||
Collections.shuffle(addresses);
|
||||
return addresses;
|
||||
}
|
||||
|
||||
private void tryToClose(@Nullable Closeable c) {
|
||||
try {
|
||||
if (c != null) c.close();
|
||||
@@ -207,4 +293,18 @@ class AndroidBluetoothPlugin extends BluetoothPlugin<BluetoothServerSocket> {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static class DiscoveryReceiver extends BroadcastReceiver {
|
||||
|
||||
private final BlockingQueue<Intent> intents;
|
||||
|
||||
private DiscoveryReceiver(BlockingQueue<Intent> intents) {
|
||||
this.intents = intents;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onReceive(Context ctx, Intent intent) {
|
||||
intents.add(intent);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,6 +11,7 @@ import org.briarproject.bramble.api.plugin.duplex.DuplexPlugin;
|
||||
import org.briarproject.bramble.api.plugin.duplex.DuplexPluginCallback;
|
||||
import org.briarproject.bramble.api.plugin.duplex.DuplexPluginFactory;
|
||||
import org.briarproject.bramble.api.system.AndroidExecutor;
|
||||
import org.briarproject.bramble.api.system.Clock;
|
||||
|
||||
import java.security.SecureRandom;
|
||||
import java.util.concurrent.Executor;
|
||||
@@ -33,17 +34,19 @@ public class AndroidBluetoothPluginFactory implements DuplexPluginFactory {
|
||||
private final Context appContext;
|
||||
private final SecureRandom secureRandom;
|
||||
private final EventBus eventBus;
|
||||
private final Clock clock;
|
||||
private final BackoffFactory backoffFactory;
|
||||
|
||||
public AndroidBluetoothPluginFactory(Executor ioExecutor,
|
||||
AndroidExecutor androidExecutor, Context appContext,
|
||||
SecureRandom secureRandom, EventBus eventBus,
|
||||
SecureRandom secureRandom, EventBus eventBus, Clock clock,
|
||||
BackoffFactory backoffFactory) {
|
||||
this.ioExecutor = ioExecutor;
|
||||
this.androidExecutor = androidExecutor;
|
||||
this.appContext = appContext;
|
||||
this.secureRandom = secureRandom;
|
||||
this.eventBus = eventBus;
|
||||
this.clock = clock;
|
||||
this.backoffFactory = backoffFactory;
|
||||
}
|
||||
|
||||
@@ -65,7 +68,7 @@ public class AndroidBluetoothPluginFactory implements DuplexPluginFactory {
|
||||
MAX_POLLING_INTERVAL, BACKOFF_BASE);
|
||||
AndroidBluetoothPlugin plugin = new AndroidBluetoothPlugin(
|
||||
connectionLimiter, ioExecutor, androidExecutor, appContext,
|
||||
secureRandom, backoff, callback, MAX_LATENCY);
|
||||
secureRandom, clock, backoff, callback, MAX_LATENCY);
|
||||
eventBus.addListener(plugin);
|
||||
return plugin;
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@ import android.content.pm.PackageManager;
|
||||
import android.content.pm.PackageManager.NameNotFoundException;
|
||||
import android.os.PowerManager;
|
||||
|
||||
import org.briarproject.bramble.api.battery.BatteryManager;
|
||||
import org.briarproject.bramble.api.network.NetworkManager;
|
||||
import org.briarproject.bramble.api.nullsafety.MethodsNotNullByDefault;
|
||||
import org.briarproject.bramble.api.nullsafety.ParametersNotNullByDefault;
|
||||
@@ -41,17 +42,18 @@ class AndroidTorPlugin extends TorPlugin {
|
||||
Context appContext, NetworkManager networkManager,
|
||||
LocationUtils locationUtils, SocketFactory torSocketFactory,
|
||||
Clock clock, ResourceProvider resourceProvider,
|
||||
CircumventionProvider circumventionProvider, Backoff backoff,
|
||||
CircumventionProvider circumventionProvider,
|
||||
BatteryManager batteryManager, Backoff backoff,
|
||||
DuplexPluginCallback callback, String architecture, int maxLatency,
|
||||
int maxIdleTime) {
|
||||
super(ioExecutor, networkManager, locationUtils, torSocketFactory,
|
||||
clock, resourceProvider, circumventionProvider, backoff,
|
||||
callback, architecture, maxLatency, maxIdleTime,
|
||||
clock, resourceProvider, circumventionProvider, batteryManager,
|
||||
backoff, callback, architecture, maxLatency, maxIdleTime,
|
||||
appContext.getDir("tor", MODE_PRIVATE));
|
||||
this.appContext = appContext;
|
||||
PowerManager pm = (PowerManager)
|
||||
appContext.getSystemService(POWER_SERVICE);
|
||||
assert pm != null;
|
||||
if (pm == null) throw new AssertionError();
|
||||
wakeLock = new RenewableWakeLock(pm, scheduler, PARTIAL_WAKE_LOCK,
|
||||
WAKE_LOCK_TAG, 1, MINUTES);
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@ package org.briarproject.bramble.plugin.tor;
|
||||
import android.content.Context;
|
||||
import android.os.Build;
|
||||
|
||||
import org.briarproject.bramble.api.battery.BatteryManager;
|
||||
import org.briarproject.bramble.api.event.EventBus;
|
||||
import org.briarproject.bramble.api.network.NetworkManager;
|
||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||
@@ -48,6 +49,7 @@ public class AndroidTorPluginFactory implements DuplexPluginFactory {
|
||||
private final BackoffFactory backoffFactory;
|
||||
private final ResourceProvider resourceProvider;
|
||||
private final CircumventionProvider circumventionProvider;
|
||||
private final BatteryManager batteryManager;
|
||||
private final Clock clock;
|
||||
|
||||
public AndroidTorPluginFactory(Executor ioExecutor,
|
||||
@@ -55,7 +57,8 @@ public class AndroidTorPluginFactory implements DuplexPluginFactory {
|
||||
NetworkManager networkManager, LocationUtils locationUtils,
|
||||
EventBus eventBus, SocketFactory torSocketFactory,
|
||||
BackoffFactory backoffFactory, ResourceProvider resourceProvider,
|
||||
CircumventionProvider circumventionProvider, Clock clock) {
|
||||
CircumventionProvider circumventionProvider,
|
||||
BatteryManager batteryManager, Clock clock) {
|
||||
this.ioExecutor = ioExecutor;
|
||||
this.scheduler = scheduler;
|
||||
this.appContext = appContext;
|
||||
@@ -66,6 +69,7 @@ public class AndroidTorPluginFactory implements DuplexPluginFactory {
|
||||
this.backoffFactory = backoffFactory;
|
||||
this.resourceProvider = resourceProvider;
|
||||
this.circumventionProvider = circumventionProvider;
|
||||
this.batteryManager = batteryManager;
|
||||
this.clock = clock;
|
||||
}
|
||||
|
||||
@@ -104,8 +108,8 @@ public class AndroidTorPluginFactory implements DuplexPluginFactory {
|
||||
MAX_POLLING_INTERVAL, BACKOFF_BASE);
|
||||
AndroidTorPlugin plugin = new AndroidTorPlugin(ioExecutor, scheduler,
|
||||
appContext, networkManager, locationUtils, torSocketFactory,
|
||||
clock, resourceProvider, circumventionProvider, backoff,
|
||||
callback, architecture, MAX_LATENCY, MAX_IDLE_TIME);
|
||||
clock, resourceProvider, circumventionProvider, batteryManager,
|
||||
backoff, callback, architecture, MAX_LATENCY, MAX_IDLE_TIME);
|
||||
eventBus.addListener(plugin);
|
||||
return plugin;
|
||||
}
|
||||
|
||||
@@ -11,15 +11,12 @@ import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import static android.content.Context.MODE_PRIVATE;
|
||||
import static android.os.Build.VERSION.SDK_INT;
|
||||
|
||||
public class AndroidUtils {
|
||||
|
||||
private static final Logger LOG =
|
||||
Logger.getLogger(AndroidUtils.class.getName());
|
||||
|
||||
// Fake Bluetooth address returned by BluetoothAdapter on API 23 and later
|
||||
private static final String FAKE_BLUETOOTH_ADDRESS = "02:00:00:00:00:00";
|
||||
|
||||
@@ -28,7 +25,7 @@ public class AndroidUtils {
|
||||
@SuppressWarnings("deprecation")
|
||||
public static Collection<String> getSupportedArchitectures() {
|
||||
List<String> abis = new ArrayList<>();
|
||||
if (Build.VERSION.SDK_INT >= 21) {
|
||||
if (SDK_INT >= 21) {
|
||||
abis.addAll(Arrays.asList(Build.SUPPORTED_ABIS));
|
||||
} else {
|
||||
abis.add(Build.CPU_ABI);
|
||||
|
||||
@@ -1,50 +1,57 @@
|
||||
dependencyVerification {
|
||||
verify = [
|
||||
'cglib:cglib:3.2.0:cglib-3.2.0.jar:adb13bab79712ad6bdf1bd59f2a3918018a8016e722e8a357065afb9e6690861',
|
||||
'com.android.tools.analytics-library:protos:26.1.3:protos-26.1.3.jar:818c9f256f141d9dafec03a1aa2b94d240b2c140acfd7ee31a8b3e6c2b9479e3',
|
||||
'com.android.tools.analytics-library:shared:26.1.3:shared-26.1.3.jar:7110706c7ada96c8b6f5ca80c478291bc7899d46277de2c48527e045442401a3',
|
||||
'com.android.tools.analytics-library:tracker:26.1.3:tracker-26.1.3.jar:4155424bf2ce4872da83332579a1707252bc66cbd77c5144fdc4483d0f2e1418',
|
||||
'com.android.tools.build:apksig:3.1.3:apksig-3.1.3.jar:7e1f8e675a6e768e5b56405e41d6c3cc05befe62e601b04177de1029902c9c89',
|
||||
'com.android.tools.build:builder-model:3.1.3:builder-model-3.1.3.jar:06ad1c422d679fc698451479cb40ba863849d67bfd1de23f6d2c16d78b024b0b',
|
||||
'com.android.tools.build:builder-test-api:3.1.3:builder-test-api-3.1.3.jar:4d989f780436794f0f8b2f50e9e079b786571eac90f26c208ab2ae6d4012f389',
|
||||
'com.android.tools.build:builder:3.1.3:builder-3.1.3.jar:8a1092012c89d0ec1ee2eff09c5708c71ef4482a6862df8d3a44a67fccace01c',
|
||||
'com.android.tools.build:gradle-api:3.1.3:gradle-api-3.1.3.jar:01e4df521456aef66514336f1d492346730dd1fb8f6433a89f62da834941ed72',
|
||||
'com.android.tools.build:manifest-merger:26.1.3:manifest-merger-26.1.3.jar:1e4fc7e932adb4607082409800e5e6fccb42e6c5360ae5990094bf522f3ada55',
|
||||
'com.android.tools.ddms:ddmlib:26.1.3:ddmlib-26.1.3.jar:c54931cd68df5d1ea2923b3b320eae47cd2307a5a916bb8674c0acf93cd1d3cd',
|
||||
'com.android.tools.external.com-intellij:intellij-core:26.1.3:intellij-core-26.1.3.jar:af67f5535fef2e1a28b1007a4acb8c5deb6a1e33b8afe7b11d012c9e778ebcec',
|
||||
'com.android.tools.external.com-intellij:kotlin-compiler:26.1.3:kotlin-compiler-26.1.3.jar:c746d2859dc11cc05c84b692b3498d3a621e0929511f8440ee009c6557838fd4',
|
||||
'com.android.tools.external.org-jetbrains:uast:26.1.3:uast-26.1.3.jar:3f3f6651d0c7685a77ecb22e9c82d6b49fdf24322c17360768dc530678f43265',
|
||||
'com.android.tools.layoutlib:layoutlib-api:26.1.3:layoutlib-api-26.1.3.jar:10bc73ce706c45629872d6a999dbe12116df64e24f47ff93b7b13121ff57b4b0',
|
||||
'com.android.tools.lint:lint-api:26.1.3:lint-api-26.1.3.jar:6f97323f9af8deda86278717885b5c927f3766757db89709f52d11d42b6fb751',
|
||||
'com.android.tools.lint:lint-checks:26.1.3:lint-checks-26.1.3.jar:73c3d53784c9ce3e6d5968506581918e0179645d20809927ca4a001dd766b001',
|
||||
'com.android.tools.lint:lint-gradle-api:26.1.3:lint-gradle-api-26.1.3.jar:7ca3c4866ec21dc21d53a9d86f752b77ace6f6c610a0c9dc877313856c733d9d',
|
||||
'com.android.tools.lint:lint-gradle:26.1.3:lint-gradle-26.1.3.jar:db0c354b8f4b6f6637e31f91c564785a59ff896325331fcbc3de7458e0b6c067',
|
||||
'com.android.tools.lint:lint-kotlin:26.1.3:lint-kotlin-26.1.3.jar:94e2b0f4565a241561cfb8fc1222bb3f132a3b98d2a90421dbb72ee8358e7d68',
|
||||
'com.android.tools.lint:lint:26.1.3:lint-26.1.3.jar:8d5f32c989c6d191d712e90ad3ca2d1c409313599551d04d834caa44d26c78df',
|
||||
'com.android.tools:annotations:26.1.3:annotations-26.1.3.jar:c950430b24ac5d58fc97e7283b8f0115f99587e76e08b4e1e2aaa780f2d77323',
|
||||
'com.android.tools:common:26.1.3:common-26.1.3.jar:7c31a90581a148ab219f615a59667f0dded7fa39b248529784474da3c2274ef2',
|
||||
'com.android.tools:dvlib:26.1.3:dvlib-26.1.3.jar:0cae87906f53d3f1088366a916ed180a7312b6d9919b90797f238875c8492855',
|
||||
'com.android.tools:repository:26.1.3:repository-26.1.3.jar:52d4539cc68db91b261e2a33b2c8206b26e05539078758dc28cfb3854adb4f59',
|
||||
'com.android.tools:sdk-common:26.1.3:sdk-common-26.1.3.jar:1948603ca9ff22c7ebb3178000bffa3a9dd2ca1cc5cb0c793cae08468b8fcfc1',
|
||||
'com.android.tools:sdklib:26.1.3:sdklib-26.1.3.jar:4adcfaad9514607098d2c51503c39811112d3050f4d1e744c01c7f08f591032b',
|
||||
'com.android.tools.analytics-library:protos:26.2.1:protos-26.2.1.jar:2f371f5b1f551e85ab08be4d6a2873471b3d44afd1ebf6aa3298f3b796bf691f',
|
||||
'com.android.tools.analytics-library:shared:26.2.1:shared-26.2.1.jar:4c1e4e705fa4d45f23aaea230557f6508155012d9c296337787c1d7b26a97f5a',
|
||||
'com.android.tools.analytics-library:tracker:26.2.1:tracker-26.2.1.jar:4a624ecc976539f755ddb0bb8dfc2dd3d08326cfec59a098dbd70f701ca7fb75',
|
||||
'com.android.tools.build:aapt2:3.2.1-4818971:aapt2-3.2.1-4818971-linux.jar:f431b6f96c91a2c155144b091a9c97d9805c589fe8efc9c930b6cd346cb60a1e',
|
||||
'com.android.tools.build:apksig:3.2.1:apksig-3.2.1.jar:2b46f2feffea66037aab29e4261b2433c190194a6ef97b958511eb157f2ccba5',
|
||||
'com.android.tools.build:apkzlib:3.2.1:apkzlib-3.2.1.jar:c39ad0313905932431fe81c8899c2cf39a4d92ad6c4edcaa4b25432f461452aa',
|
||||
'com.android.tools.build:builder-model:3.2.1:builder-model-3.2.1.jar:a9f68e6abcec122f9cb5ad352d3f05a3eb03acbcdca95e4d25c16310c2c965ff',
|
||||
'com.android.tools.build:builder-test-api:3.2.1:builder-test-api-3.2.1.jar:533ac6c2b5884bb54967a33791f2628dfdfac7981af39417a333b43d4379b6be',
|
||||
'com.android.tools.build:builder:3.2.1:builder-3.2.1.jar:aedcbfd115dbe91d09b4113e66ef50589b558d0aa3b2f133b1d867c9b87fae83',
|
||||
'com.android.tools.build:gradle-api:3.2.1:gradle-api-3.2.1.jar:57cf0ac5ac1dca8afdb3f62b94265e776e7dcfa641cc3844fb53a05193de208d',
|
||||
'com.android.tools.build:manifest-merger:26.2.1:manifest-merger-26.2.1.jar:8830573263361035d38cfdcb51e2db94029c93865b21334f5fbf8a27984281a6',
|
||||
'com.android.tools.ddms:ddmlib:26.2.1:ddmlib-26.2.1.jar:a4bf0a29a19980bf27269465cc782064656750b77c26728f82f9e148b705218b',
|
||||
'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.2.1:kotlin-compiler-26.2.1.jar:daa064fd708f340ee25fb9823c4c74104ac77f1370b76d907eb9ae6daec0a2ae',
|
||||
'com.android.tools.external.org-jetbrains:uast:26.2.1:uast-26.2.1.jar:f10f7258d2ab9189562cc0f9ad838c0378fdba439229173390a99de02ebac75b',
|
||||
'com.android.tools.layoutlib:layoutlib-api:26.2.1:layoutlib-api-26.2.1.jar:ddbf4fca123733fa011595b1cc1f4ac2937ed327b60990711fafc33c775c2ade',
|
||||
'com.android.tools.lint:lint-api:26.2.1:lint-api-26.2.1.jar:3b57e739de567b98bc9ab56c2c0ee66fc026b4adf5843e8f9804ca0666a6f66e',
|
||||
'com.android.tools.lint:lint-checks:26.2.1:lint-checks-26.2.1.jar:c86f4cc9aaee722ee4ad70062f7b5af91e9b041914af27adc09f545ab0fb3bc6',
|
||||
'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.2.1:lint-gradle-26.2.1.jar:8fd90b2f3ec788cbb9801c07ab3e1ea2255aa31a6093157d7ea0ff13d0315ecb',
|
||||
'com.android.tools.lint:lint-kotlin:26.2.1:lint-kotlin-26.2.1.jar:7a6a5d2b18f69cf1b900d857c2632b4c683713c533295933b8b759f8cab4a877',
|
||||
'com.android.tools.lint:lint:26.2.1:lint-26.2.1.jar:7848b82ae988b90dee259ae7c7e86e05cbf52db6cd21c8bbd38ce7df08f3f8c5',
|
||||
'com.android.tools:annotations:26.2.1:annotations-26.2.1.jar:7391c6a1e080174b96e64ceb078dadd31ce4d8a2d2fee0ec65be202126f90f24',
|
||||
'com.android.tools:common:26.2.1:common-26.2.1.jar:a50aab2d6411ff68f4004a87c7e93d87d8e980a0ec3b352246549897ea2d78e5',
|
||||
'com.android.tools:dvlib:26.2.1:dvlib-26.2.1.jar:72a83bf2839b1df9b1fbf67ba45d1bfb9f966cd774da4320c762b2be8f1688aa',
|
||||
'com.android.tools:repository:26.2.1:repository-26.2.1.jar:fa74dae09103faef703df38550ad8fa244c5b6d1bf90d6198be932292b3d9cc1',
|
||||
'com.android.tools:sdk-common:26.2.1:sdk-common-26.2.1.jar:759d4b292ca69a35cf961fca377b54158fc6c88108978006999442e80a011cf4',
|
||||
'com.android.tools:sdklib:26.2.1:sdklib-26.2.1.jar:248df7ad5eac4aeb6f96c394c76760de4b7b89ac056e54d0c21a739368b91b45',
|
||||
'com.google.code.findbugs:jsr305:1.3.9:jsr305-1.3.9.jar:905721a0eea90a81534abb7ee6ef4ea2e5e645fa1def0a5cd88402df1b46c9ed',
|
||||
'com.google.code.gson:gson:2.7:gson-2.7.jar:2d43eb5ea9e133d2ee2405cc14f5ee08951b8361302fdd93494a3a997b508d32',
|
||||
'com.google.dagger:dagger-compiler:2.0.2:dagger-compiler-2.0.2.jar:b74bc9de063dd4c6400b232231f2ef5056145b8fbecbf5382012007dd1c071b3',
|
||||
'com.google.dagger:dagger-producers:2.0-beta:dagger-producers-2.0-beta.jar:99ec15e8a0507ba569e7655bc1165ee5e5ca5aa914b3c8f7e2c2458f724edd6b',
|
||||
'com.google.dagger:dagger:2.0.2:dagger-2.0.2.jar:84c0282ed8be73a29e0475d639da030b55dee72369e58dd35ae7d4fe6243dcf9',
|
||||
'com.google.code.gson:gson:2.8.0:gson-2.8.0.jar:c6221763bd79c4f1c3dc7f750b5f29a0bb38b367b81314c4f71896e340c40825',
|
||||
'com.google.dagger:dagger-compiler:2.19:dagger-compiler-2.19.jar:27a4b202a2de908182edb261f8c0a264e08e5e4733d7514bc7fbf0d31da5c0fc',
|
||||
'com.google.dagger:dagger-producers:2.19:dagger-producers-2.19.jar:a17663abe0fc38b676026950907d4c5f5e2bf338375415861eaff6e3bdb0b768',
|
||||
'com.google.dagger:dagger-spi:2.19:dagger-spi-2.19.jar:e7a6379d82c841f6aac2866948ad1eed716528707814602842a8d844ce04e2e1',
|
||||
'com.google.dagger:dagger:2.19:dagger-2.19.jar:514b6f1e0727c6572e1d65cb27e4ae668b7aeaeb93a29515182965265b609939',
|
||||
'com.google.errorprone:error_prone_annotations:2.0.18:error_prone_annotations-2.0.18.jar:cb4cfad870bf563a07199f3ebea5763f0dec440fcda0b318640b1feaa788656b',
|
||||
'com.google.guava:guava:18.0:guava-18.0.jar:d664fbfc03d2e5ce9cab2a44fb01f1d0bf9dfebeccc1a473b1f9ea31f79f6f99',
|
||||
'com.google.guava:guava:22.0:guava-22.0.jar:1158e94c7de4da480873f0b4ab4a1da14c0d23d4b1902cc94a58a6f0f9ab579e',
|
||||
'com.google.errorprone:error_prone_annotations:2.1.3:error_prone_annotations-2.1.3.jar:03d0329547c13da9e17c634d1049ea2ead093925e290567e1a364fd6b1fc7ff8',
|
||||
'com.google.errorprone:javac-shaded:9-dev-r4023-3:javac-shaded-9-dev-r4023-3.jar:65bfccf60986c47fbc17c9ebab0be626afc41741e0a6ec7109e0768817a36f30',
|
||||
'com.google.googlejavaformat:google-java-format:1.5:google-java-format-1.5.jar:aa19ad7850fb85178aa22f2fddb163b84d6ce4d0035872f30d4408195ca1144e',
|
||||
'com.google.guava:guava:23.0:guava-23.0.jar:7baa80df284117e5b945b19b98d367a85ea7b7801bd358ff657946c3bd1b6596',
|
||||
'com.google.guava:guava:25.0-jre:guava-25.0-jre.jar:3fd4341776428c7e0e5c18a7c10de129475b69ab9d30aeafbb5c277bb6074fa9',
|
||||
'com.google.j2objc:j2objc-annotations:1.1:j2objc-annotations-1.1.jar:40ceb7157feb263949e0f503fe5f71689333a621021aa20ce0d0acee3badaa0f',
|
||||
'com.google.jimfs:jimfs:1.1:jimfs-1.1.jar:c4828e28d7c0a930af9387510b3bada7daa5c04d7c25a75c7b8b081f1c257ddd',
|
||||
'com.google.protobuf:protobuf-java:3.4.0:protobuf-java-3.4.0.jar:dce7e66b32456a1b1198da0caff3a8acb71548658391e798c79369241e6490a4',
|
||||
'com.googlecode.json-simple:json-simple:1.1:json-simple-1.1.jar:2d9484f4c649f708f47f9a479465fc729770ee65617dca3011836602264f6439',
|
||||
'com.squareup:javapoet:1.11.1:javapoet-1.11.1.jar:9cbf2107be499ec6e95afd36b58e3ca122a24166cdd375732e51267d64058e90',
|
||||
'com.squareup:javawriter:2.5.0:javawriter-2.5.0.jar:fcfb09fb0ea0aa97d3cfe7ea792398081348e468f126b3603cb3803f240197f0',
|
||||
'com.sun.activation:javax.activation:1.2.0:javax.activation-1.2.0.jar:993302b16cd7056f21e779cc577d175a810bb4900ef73cd8fbf2b50f928ba9ce',
|
||||
'com.sun.istack:istack-commons-runtime:2.21:istack-commons-runtime-2.21.jar:c33e67a0807095f02a0e2da139412dd7c4f9cc1a4c054b3e434f96831ba950f4',
|
||||
'com.sun.xml.fastinfoset:FastInfoset:1.2.13:FastInfoset-1.2.13.jar:27a77db909f3c2833c0b1a37c55af1db06045118ad2eed96ce567b6632bce038',
|
||||
'commons-codec:commons-codec:1.6:commons-codec-1.6.jar:54b34e941b8e1414bd3e40d736efd3481772dc26db3296f6aa45cec9f6203d86',
|
||||
'commons-logging:commons-logging:1.1.1:commons-logging-1.1.1.jar:ce6f913cad1f0db3aad70186d65c5bc7ffcc9a99e3fe8e0b137312819f7c362f',
|
||||
'commons-codec:commons-codec:1.9:commons-codec-1.9.jar:ad19d2601c3abf0b946b5c3a4113e226a8c1e3305e395b90013b78dd94a723ce',
|
||||
'commons-logging:commons-logging:1.2:commons-logging-1.2.jar:daddea1ea0be0f56978ab3006b8ac92834afeefbd9b7e4e6316fca57df0fa636',
|
||||
'it.unimi.dsi:fastutil:7.2.0:fastutil-7.2.0.jar:74fa208043740642f7e6eb09faba15965218ad2f50ce3020efb100136e4b591c',
|
||||
'javax.annotation:jsr250-api:1.0:jsr250-api-1.0.jar:a1a922d0d9b6d183ed3800dfac01d1e1eb159f0e8c6f94736931c1def54a941f',
|
||||
'javax.inject:javax.inject:1:javax.inject-1.jar:91c77044a50c481636c32d916fd89c9118a72195390452c81065080f957de7ff',
|
||||
@@ -55,13 +62,15 @@ dependencyVerification {
|
||||
'org.apache.ant:ant-launcher:1.9.4:ant-launcher-1.9.4.jar:7bccea20b41801ca17bcbc909a78c835d0f443f12d639c77bd6ae3d05861608d',
|
||||
'org.apache.ant:ant:1.9.4:ant-1.9.4.jar:649ae0730251de07b8913f49286d46bba7b92d47c5f332610aa426c4f02161d8',
|
||||
'org.apache.commons:commons-compress:1.12:commons-compress-1.12.jar:2c1542faf343185b7cab9c3d55c8ae5471d6d095d3887a4adefdbdf2984dc0b6',
|
||||
'org.apache.httpcomponents:httpclient:4.2.6:httpclient-4.2.6.jar:362e9324ee7c697e21279e20077b52737ddef3f1b2c1a7abe5ad34b465145550',
|
||||
'org.apache.httpcomponents:httpcore:4.2.5:httpcore-4.2.5.jar:e5e82da4cc66c8d917bbf743e3c0752efe8522735e7fc9dbddb65bccea81cfe9',
|
||||
'org.apache.httpcomponents:httpmime:4.1:httpmime-4.1.jar:31629566148e8a47688ae43b420abc3ecd783ed15b33bebc00824bf24c9b15aa',
|
||||
'org.apache.httpcomponents:httpclient:4.5.2:httpclient-4.5.2.jar:0dffc621400d6c632f55787d996b8aeca36b30746a716e079a985f24d8074057',
|
||||
'org.apache.httpcomponents:httpcore:4.4.5:httpcore-4.4.5.jar:64d5453874cab7e40a7065cb01a9a9ca1053845a9786b478878b679e0580cec3',
|
||||
'org.apache.httpcomponents:httpmime:4.5.2:httpmime-4.5.2.jar:231a3f7e4962053db2be8461d5422e68fc458a3a7dd7d8ada803a348e21f8f07',
|
||||
'org.beanshell:bsh:1.3.0:bsh-1.3.0.jar:9b04edc75d19db54f1b4e8b5355e9364384c6cf71eb0a1b9724c159d779879f8',
|
||||
'org.bouncycastle:bcpkix-jdk15on:1.56:bcpkix-jdk15on-1.56.jar:7043dee4e9e7175e93e0b36f45b1ec1ecb893c5f755667e8b916eb8dd201c6ca',
|
||||
'org.bouncycastle:bcprov-jdk15on:1.56:bcprov-jdk15on-1.56.jar:963e1ee14f808ffb99897d848ddcdb28fa91ddda867eb18d303e82728f878349',
|
||||
'org.briarproject:tor-android:0.2.9.16:tor-android-0.2.9.16.zip:515e33dda6a30853c885a2de2c79ae1ab9ad8b6db44f5db8890333ec2e24f4ae',
|
||||
'org.briarproject:obfs4proxy-android:0.0.7:obfs4proxy-android-0.0.7.zip:abdfb5d889d848de9bf214f9276abbf454808a505b870819eccc9a9e985bf617',
|
||||
'org.briarproject:tor-android:0.3.4.8:tor-android-0.3.4.8.zip:989a0352d9d8d8172cd6c2137654e165e5d2beb10ed1211bab3814e224ad1926',
|
||||
'org.checkerframework:checker-compat-qual:2.5.3:checker-compat-qual-2.5.3.jar:d76b9afea61c7c082908023f0cbc1427fab9abd2df915c8b8a3e7a509bccbc6d',
|
||||
'org.codehaus.groovy:groovy-all:2.4.12:groovy-all-2.4.12.jar:6a56af4bd48903d56bec62821876cadefafd007360cc6bd0d8f7aa8d72b38be4',
|
||||
'org.codehaus.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',
|
||||
@@ -70,9 +79,10 @@ dependencyVerification {
|
||||
'org.hamcrest:hamcrest-core:1.3:hamcrest-core-1.3.jar:66fdef91e9739348df7a096aa384a5685f4e875584cce89386a7a47251c4d8e9',
|
||||
'org.hamcrest:hamcrest-library:1.3:hamcrest-library-1.3.jar:711d64522f9ec410983bd310934296da134be4254a125080a0416ec178dfad1c',
|
||||
'org.jetbrains.kotlin:kotlin-reflect:1.2.0:kotlin-reflect-1.2.0.jar:4f48a872bad6e4d9c053f4ad610d11e4012ad7e58dc19a03dd5eb811f36069dd',
|
||||
'org.jetbrains.kotlin:kotlin-stdlib-jre7:1.2.0:kotlin-stdlib-jre7-1.2.0.jar:c7a20fb951d437797afe8980aff6c1e5a03f310c661ba58ba1d4fa90cb0f2926',
|
||||
'org.jetbrains.kotlin:kotlin-stdlib-jre8:1.2.0:kotlin-stdlib-jre8-1.2.0.jar:633524eee6ef1941f7cb1dab7ee3927b0a221ceee9047aeb5515f4cbb990c82a',
|
||||
'org.jetbrains.kotlin:kotlin-stdlib:1.2.0:kotlin-stdlib-1.2.0.jar:05cfd9f5ac0b41910703a8925f7211a495909b27a2ffdd1c5106f1689aeafcd4',
|
||||
'org.jetbrains.kotlin:kotlin-stdlib-common:1.2.71:kotlin-stdlib-common-1.2.71.jar:63999687ff2fce8a592dd180ffbbf8f1d21c26b4044c55cdc74ff3cf3b3cf328',
|
||||
'org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.2.71:kotlin-stdlib-jdk7-1.2.71.jar:b136bd61b240e07d4d92ce00d3bd1dbf584400a7bf5f220c2f3cd22446858082',
|
||||
'org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.2.71:kotlin-stdlib-jdk8-1.2.71.jar:ac3c8abf47790b64b4f7e2509a53f0c145e061ac1612a597520535d199946ea9',
|
||||
'org.jetbrains.kotlin:kotlin-stdlib:1.2.71:kotlin-stdlib-1.2.71.jar:4c895c270b87f5fec2a2796e1d89c15407ee821de961527c28588bb46afbc68b',
|
||||
'org.jetbrains.trove4j:trove4j:20160824:trove4j-20160824.jar:1917871c8deb468307a584680c87a44572f5a8b0b98c6d397fc0f5f86596dbe7',
|
||||
'org.jetbrains:annotations:13.0:annotations-13.0.jar:ace2a10dc8e2d5fd34925ecac03e4988b2c0f851650c94b8cef49ba1bd111478',
|
||||
'org.jmock:jmock-junit4:2.8.2:jmock-junit4-2.8.2.jar:f7ee4df4f7bd7b7f1cafad3b99eb74d579f109d5992ff625347352edb55e674c',
|
||||
@@ -81,11 +91,11 @@ dependencyVerification {
|
||||
'org.jmock:jmock:2.8.2:jmock-2.8.2.jar:6c73cb4a2e6dbfb61fd99c9a768539c170ab6568e57846bd60dbf19596b65b16',
|
||||
'org.jvnet.staxex:stax-ex:1.7.7:stax-ex-1.7.7.jar:a31ff7d77163c0deb09e7fee59ad35ae44c2cee2cc8552a116ccd1583d813fb4',
|
||||
'org.objenesis:objenesis:2.1:objenesis-2.1.jar:c74330cc6b806c804fd37e74487b4fe5d7c2750c5e15fbc6efa13bdee1bdef80',
|
||||
'org.ow2.asm:asm-analysis:5.1:asm-analysis-5.1.jar:a34658f5c5de4b573eef21131cc32cc25f7b66407944f312b28ec2e56abb1fa9',
|
||||
'org.ow2.asm:asm-commons:5.1:asm-commons-5.1.jar:97b3786e1f55e74bddf8ad102bf50e33bbcbc1f6b7fd7b36f0bbbb25cd4981be',
|
||||
'org.ow2.asm:asm-tree:5.1:asm-tree-5.1.jar:c0de2bbc4cb8297419659813ecd4ed1d077ed1dd5c1f5544cc5143e493e84c10',
|
||||
'org.ow2.asm:asm-util:5.1:asm-util-5.1.jar:ee032c39ae5e3cd099148fbba9a2124f9ed613e5cb93e03ee0fa8808ce364040',
|
||||
'org.ow2.asm:asm-analysis:6.0:asm-analysis-6.0.jar:2f1a6387219c3a6cc4856481f221b03bd9f2408a326d416af09af5d6f608c1f4',
|
||||
'org.ow2.asm:asm-commons:6.0:asm-commons-6.0.jar:f1bce5c648a96a017bdcd01fe5d59af9845297fd7b79b81c015a6fbbd9719abf',
|
||||
'org.ow2.asm:asm-tree:6.0:asm-tree-6.0.jar:887998fb69727c8759e4d253f856822801e33f9fd4caa566b3ac58ee92106215',
|
||||
'org.ow2.asm:asm-util:6.0:asm-util-6.0.jar:356afebdb0f870175262e5188f8709a3b17aa2a5a6a4b0340b04d4b449bca5f6',
|
||||
'org.ow2.asm:asm:5.0.4:asm-5.0.4.jar:896618ed8ae62702521a78bc7be42b7c491a08e6920a15f89a3ecdec31e9a220',
|
||||
'org.ow2.asm:asm:5.1:asm-5.1.jar:d2da399a9967c69f0a21739256fa79d284222c223082cacadc17372244764b54',
|
||||
'org.ow2.asm:asm:6.0:asm-6.0.jar:dd8971c74a4e697899a8e95caae4ea8760ea6c486dc6b97b1795e75760420461',
|
||||
]
|
||||
}
|
||||
|
||||
@@ -7,15 +7,13 @@ apply plugin: 'witness'
|
||||
apply from: 'witness.gradle'
|
||||
|
||||
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'
|
||||
|
||||
testImplementation 'junit:junit:4.12'
|
||||
testImplementation "org.jmock:jmock:2.8.2"
|
||||
testImplementation "org.jmock:jmock-junit4:2.8.2"
|
||||
testImplementation "org.jmock:jmock-legacy:2.8.2"
|
||||
testImplementation "org.hamcrest:hamcrest-library:1.3"
|
||||
testImplementation "org.hamcrest:hamcrest-core:1.3"
|
||||
|
||||
signature 'org.codehaus.mojo.signature:java16:1.1@signature'
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -38,4 +38,18 @@ public abstract class StringMap extends Hashtable<String, String> {
|
||||
public void putInt(String key, int value) {
|
||||
put(key, String.valueOf(value));
|
||||
}
|
||||
|
||||
public long getLong(String key, long defaultValue) {
|
||||
String s = get(key);
|
||||
if (s == null) return defaultValue;
|
||||
try {
|
||||
return Long.valueOf(s);
|
||||
} catch (NumberFormatException e) {
|
||||
return defaultValue;
|
||||
}
|
||||
}
|
||||
|
||||
public void putLong(String key, long value) {
|
||||
put(key, String.valueOf(value));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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.client.ClientHelper;
|
||||
import org.briarproject.bramble.api.data.BdfDictionary;
|
||||
import org.briarproject.bramble.api.data.BdfList;
|
||||
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.sync.InvalidMessageException;
|
||||
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;
|
||||
|
||||
@@ -62,5 +61,4 @@ public abstract class BdfIncomingMessageHook implements IncomingMessageHook {
|
||||
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.Message;
|
||||
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 java.util.logging.Logger;
|
||||
@@ -48,12 +48,8 @@ public abstract class BdfMessageValidator implements MessageValidator {
|
||||
throw new InvalidMessageException(
|
||||
"Timestamp is too far in the future");
|
||||
}
|
||||
byte[] body = m.getBody();
|
||||
if (body.length == 0) {
|
||||
throw new InvalidMessageException("Message is too short");
|
||||
}
|
||||
try {
|
||||
BdfList bodyList = clientHelper.toList(body);
|
||||
BdfList bodyList = clientHelper.toList(m.getBody());
|
||||
BdfMessageContext result = validateMessage(m, g, bodyList);
|
||||
Metadata meta = metadataEncoder.encode(result.getDictionary());
|
||||
return new MessageContext(meta, result.getDependencies());
|
||||
|
||||
@@ -4,8 +4,12 @@ import org.briarproject.bramble.api.identity.Author;
|
||||
import org.briarproject.bramble.api.identity.AuthorId;
|
||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import javax.annotation.concurrent.Immutable;
|
||||
|
||||
import static org.briarproject.bramble.api.identity.AuthorConstants.MAX_AUTHOR_NAME_LENGTH;
|
||||
import static org.briarproject.bramble.util.StringUtils.toUtf8;
|
||||
|
||||
@Immutable
|
||||
@NotNullByDefault
|
||||
public class Contact {
|
||||
@@ -13,13 +17,21 @@ public class Contact {
|
||||
private final ContactId id;
|
||||
private final Author author;
|
||||
private final AuthorId localAuthorId;
|
||||
@Nullable
|
||||
private final String alias;
|
||||
private final boolean verified, active;
|
||||
|
||||
public Contact(ContactId id, Author author, AuthorId localAuthorId,
|
||||
boolean verified, boolean active) {
|
||||
@Nullable String alias, boolean verified, boolean active) {
|
||||
if (alias != null) {
|
||||
int aliasLength = toUtf8(alias).length;
|
||||
if (aliasLength == 0 || aliasLength > MAX_AUTHOR_NAME_LENGTH)
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
this.id = id;
|
||||
this.author = author;
|
||||
this.localAuthorId = localAuthorId;
|
||||
this.alias = alias;
|
||||
this.verified = verified;
|
||||
this.active = active;
|
||||
}
|
||||
@@ -36,6 +48,11 @@ public class Contact {
|
||||
return localAuthorId;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public String getAlias() {
|
||||
return alias;
|
||||
}
|
||||
|
||||
public boolean isVerified() {
|
||||
return verified;
|
||||
}
|
||||
|
||||
@@ -5,11 +5,14 @@ import org.briarproject.bramble.api.db.DbException;
|
||||
import org.briarproject.bramble.api.db.Transaction;
|
||||
import org.briarproject.bramble.api.identity.Author;
|
||||
import org.briarproject.bramble.api.identity.AuthorId;
|
||||
import org.briarproject.bramble.api.identity.AuthorInfo;
|
||||
import org.briarproject.bramble.api.lifecycle.LifecycleManager;
|
||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
@NotNullByDefault
|
||||
public interface ContactManager {
|
||||
|
||||
@@ -93,6 +96,18 @@ public interface ContactManager {
|
||||
void setContactActive(Transaction txn, ContactId c, boolean active)
|
||||
throws DbException;
|
||||
|
||||
/**
|
||||
* Sets an alias name for the contact or unsets it if alias is null.
|
||||
*/
|
||||
void setContactAlias(Transaction txn, ContactId c, @Nullable String alias)
|
||||
throws DbException;
|
||||
|
||||
/**
|
||||
* Sets an alias name for the contact or unsets it if alias is null.
|
||||
*/
|
||||
void setContactAlias(ContactId c, @Nullable String alias)
|
||||
throws DbException;
|
||||
|
||||
/**
|
||||
* Return true if a contact with this name and public key already exists
|
||||
*/
|
||||
@@ -105,6 +120,16 @@ public interface ContactManager {
|
||||
boolean contactExists(AuthorId remoteAuthorId, AuthorId localAuthorId)
|
||||
throws DbException;
|
||||
|
||||
/**
|
||||
* Returns the {@link AuthorInfo} for the given author.
|
||||
*/
|
||||
AuthorInfo getAuthorInfo(AuthorId a) throws DbException;
|
||||
|
||||
/**
|
||||
* Returns the {@link AuthorInfo} for the given author.
|
||||
*/
|
||||
AuthorInfo getAuthorInfo(Transaction txn, AuthorId a) throws DbException;
|
||||
|
||||
interface ContactHook {
|
||||
|
||||
void addingContact(Transaction txn, Contact c) throws DbException;
|
||||
|
||||
@@ -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');
|
||||
}
|
||||
}
|
||||
@@ -19,6 +19,7 @@ import org.briarproject.bramble.api.sync.MessageId;
|
||||
import org.briarproject.bramble.api.sync.MessageStatus;
|
||||
import org.briarproject.bramble.api.sync.Offer;
|
||||
import org.briarproject.bramble.api.sync.Request;
|
||||
import org.briarproject.bramble.api.sync.validation.MessageState;
|
||||
import org.briarproject.bramble.api.transport.KeySet;
|
||||
import org.briarproject.bramble.api.transport.KeySetId;
|
||||
import org.briarproject.bramble.api.transport.TransportKeys;
|
||||
@@ -28,8 +29,6 @@ import java.util.Map;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import static org.briarproject.bramble.api.sync.ValidationManager.State;
|
||||
|
||||
/**
|
||||
* Encapsulates the database implementation and exposes high-level operations
|
||||
* to other components.
|
||||
@@ -76,6 +75,27 @@ public interface DatabaseComponent {
|
||||
*/
|
||||
void endTransaction(Transaction txn);
|
||||
|
||||
/**
|
||||
* Runs the given task within a transaction.
|
||||
*/
|
||||
<E extends Exception> void transaction(boolean readOnly,
|
||||
DbRunnable<E> task) throws DbException, E;
|
||||
|
||||
/**
|
||||
* Runs the given task within a transaction and returns the result of the
|
||||
* task.
|
||||
*/
|
||||
<R, E extends Exception> R transactionWithResult(boolean readOnly,
|
||||
DbCallable<R, E> task) throws DbException, E;
|
||||
|
||||
/**
|
||||
* Runs the given task within a transaction and returns the result of the
|
||||
* task, which may be null.
|
||||
*/
|
||||
@Nullable
|
||||
<R, E extends Exception> R transactionWithNullableResult(boolean readOnly,
|
||||
NullableDbCallable<R, E> task) throws DbException, E;
|
||||
|
||||
/**
|
||||
* Stores a contact associated with the given local and remote pseudonyms,
|
||||
* and returns an ID for the contact.
|
||||
@@ -353,12 +373,12 @@ public interface DatabaseComponent {
|
||||
/**
|
||||
* Returns the IDs and states of all dependencies of the given message.
|
||||
* For missing dependencies and dependencies in other groups, the state
|
||||
* {@link State UNKNOWN} is returned.
|
||||
* {@link MessageState UNKNOWN} is returned.
|
||||
* <p/>
|
||||
* Read-only.
|
||||
*/
|
||||
Map<MessageId, State> getMessageDependencies(Transaction txn, MessageId m)
|
||||
throws DbException;
|
||||
Map<MessageId, MessageState> getMessageDependencies(Transaction txn,
|
||||
MessageId m) throws DbException;
|
||||
|
||||
/**
|
||||
* Returns the IDs and states of all dependents of the given message.
|
||||
@@ -367,15 +387,16 @@ public interface DatabaseComponent {
|
||||
* <p/>
|
||||
* Read-only.
|
||||
*/
|
||||
Map<MessageId, State> getMessageDependents(Transaction txn, MessageId m)
|
||||
throws DbException;
|
||||
Map<MessageId, MessageState> getMessageDependents(Transaction txn,
|
||||
MessageId m) throws DbException;
|
||||
|
||||
/**
|
||||
* Gets the validation and delivery state of the given message.
|
||||
* <p/>
|
||||
* 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
|
||||
@@ -502,6 +523,12 @@ public interface DatabaseComponent {
|
||||
void setContactActive(Transaction txn, ContactId c, boolean active)
|
||||
throws DbException;
|
||||
|
||||
/**
|
||||
* Sets an alias name for the contact or unsets it if alias is null.
|
||||
*/
|
||||
void setContactAlias(Transaction txn, ContactId c, @Nullable String alias)
|
||||
throws DbException;
|
||||
|
||||
/**
|
||||
* Sets the given group's visibility to the given contact.
|
||||
*/
|
||||
@@ -516,7 +543,7 @@ public interface DatabaseComponent {
|
||||
/**
|
||||
* 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;
|
||||
|
||||
/**
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
package org.briarproject.bramble.api.db;
|
||||
|
||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||
|
||||
@NotNullByDefault
|
||||
public interface DbCallable<R, E extends Exception> {
|
||||
|
||||
R call(Transaction txn) throws DbException, E;
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
package org.briarproject.bramble.api.db;
|
||||
|
||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||
|
||||
@NotNullByDefault
|
||||
public interface DbRunnable<E extends Exception> {
|
||||
|
||||
void run(Transaction txn) throws DbException, E;
|
||||
}
|
||||
@@ -6,6 +6,10 @@ public interface MigrationListener {
|
||||
* This is called when a migration is started while opening the database.
|
||||
* It will be called once for each migration being applied.
|
||||
*/
|
||||
void onMigrationRun();
|
||||
void onDatabaseMigration();
|
||||
|
||||
/**
|
||||
* This is called when compaction is started while opening the database.
|
||||
*/
|
||||
void onDatabaseCompaction();
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -16,10 +16,6 @@ import static org.briarproject.bramble.api.identity.AuthorConstants.MAX_PUBLIC_K
|
||||
@NotNullByDefault
|
||||
public class Author implements Nameable {
|
||||
|
||||
public enum Status {
|
||||
NONE, ANONYMOUS, UNKNOWN, UNVERIFIED, VERIFIED, OURSELVES
|
||||
}
|
||||
|
||||
/**
|
||||
* The current version of the author structure.
|
||||
*/
|
||||
|
||||
@@ -0,0 +1,56 @@
|
||||
package org.briarproject.bramble.api.identity;
|
||||
|
||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import javax.annotation.concurrent.Immutable;
|
||||
|
||||
@Immutable
|
||||
@NotNullByDefault
|
||||
public class AuthorInfo {
|
||||
|
||||
public enum Status {
|
||||
NONE, ANONYMOUS, UNKNOWN, UNVERIFIED, VERIFIED, OURSELVES;
|
||||
|
||||
public boolean isContact() {
|
||||
return this == UNVERIFIED || this == VERIFIED;
|
||||
}
|
||||
}
|
||||
|
||||
private final Status status;
|
||||
@Nullable
|
||||
private final String alias;
|
||||
|
||||
public AuthorInfo(Status status, @Nullable String alias) {
|
||||
this.status = status;
|
||||
this.alias = alias;
|
||||
}
|
||||
|
||||
public AuthorInfo(Status status) {
|
||||
this(status, null);
|
||||
}
|
||||
|
||||
public Status getStatus() {
|
||||
return status;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public String getAlias() {
|
||||
return alias;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int hashCode = status.ordinal();
|
||||
if (alias != null) hashCode += alias.hashCode();
|
||||
return hashCode;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (!(o instanceof AuthorInfo)) return false;
|
||||
AuthorInfo info = (AuthorInfo) o;
|
||||
return status == info.status &&
|
||||
(alias == null ? info.alias == null : alias.equals(info.alias));
|
||||
}
|
||||
}
|
||||
@@ -3,7 +3,6 @@ package org.briarproject.bramble.api.identity;
|
||||
import org.briarproject.bramble.api.crypto.CryptoExecutor;
|
||||
import org.briarproject.bramble.api.db.DbException;
|
||||
import org.briarproject.bramble.api.db.Transaction;
|
||||
import org.briarproject.bramble.api.identity.Author.Status;
|
||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||
|
||||
@NotNullByDefault
|
||||
@@ -37,14 +36,4 @@ public interface IdentityManager {
|
||||
*/
|
||||
LocalAuthor getLocalAuthor(Transaction txn) throws DbException;
|
||||
|
||||
/**
|
||||
* Returns the {@link Status} of the given author.
|
||||
*/
|
||||
Status getAuthorStatus(AuthorId a) throws DbException;
|
||||
|
||||
/**
|
||||
* Returns the {@link Status} of the given author.
|
||||
*/
|
||||
Status getAuthorStatus(Transaction txn, AuthorId a) throws DbException;
|
||||
|
||||
}
|
||||
|
||||
@@ -21,7 +21,7 @@ public interface KeyAgreementConstants {
|
||||
/**
|
||||
* The connection timeout in milliseconds.
|
||||
*/
|
||||
long CONNECTION_TIMEOUT = 20 * 1000;
|
||||
long CONNECTION_TIMEOUT = 60_000;
|
||||
|
||||
/**
|
||||
* The transport identifier for Bluetooth.
|
||||
|
||||
@@ -34,7 +34,8 @@ public interface LifecycleManager {
|
||||
*/
|
||||
enum LifecycleState {
|
||||
|
||||
STARTING, MIGRATING_DATABASE, STARTING_SERVICES, RUNNING, STOPPING;
|
||||
STARTING, MIGRATING_DATABASE, COMPACTING_DATABASE, STARTING_SERVICES,
|
||||
RUNNING, STOPPING;
|
||||
|
||||
public boolean isAfter(LifecycleState state) {
|
||||
return ordinal() > state.ordinal();
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -4,7 +4,8 @@ public interface TorConstants {
|
||||
|
||||
TransportId ID = new TransportId("org.briarproject.bramble.tor");
|
||||
|
||||
String PROP_ONION = "onion";
|
||||
String PROP_ONION_V2 = "onion";
|
||||
String PROP_ONION_V3 = "onion3";
|
||||
|
||||
int SOCKS_PORT = 59050;
|
||||
int CONTROL_PORT = 59051;
|
||||
|
||||
@@ -16,6 +16,7 @@ public class Message {
|
||||
private final byte[] body;
|
||||
|
||||
public Message(MessageId id, GroupId groupId, long timestamp, byte[] body) {
|
||||
if (body.length == 0) throw new IllegalArgumentException();
|
||||
if (body.length > MAX_MESSAGE_BODY_LENGTH)
|
||||
throw new IllegalArgumentException();
|
||||
this.id = id;
|
||||
|
||||
@@ -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.nullsafety.NotNullByDefault;
|
||||
import org.briarproject.bramble.api.sync.MessageId;
|
||||
import org.briarproject.bramble.api.sync.validation.MessageState;
|
||||
|
||||
import javax.annotation.concurrent.Immutable;
|
||||
|
||||
import static org.briarproject.bramble.api.sync.ValidationManager.State;
|
||||
|
||||
/**
|
||||
* An event that is broadcast when a message state changed.
|
||||
*/
|
||||
@@ -17,10 +16,10 @@ public class MessageStateChangedEvent extends Event {
|
||||
|
||||
private final MessageId messageId;
|
||||
private final boolean local;
|
||||
private final State state;
|
||||
private final MessageState state;
|
||||
|
||||
public MessageStateChangedEvent(MessageId messageId, boolean local,
|
||||
State state) {
|
||||
MessageState state) {
|
||||
this.messageId = messageId;
|
||||
this.local = local;
|
||||
this.state = state;
|
||||
@@ -34,7 +33,7 @@ public class MessageStateChangedEvent extends Event {
|
||||
return local;
|
||||
}
|
||||
|
||||
public State getState() {
|
||||
public MessageState getState() {
|
||||
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);
|
||||
}
|
||||
@@ -47,7 +47,7 @@ public class StringUtils {
|
||||
try {
|
||||
return s.getBytes("UTF-8");
|
||||
} catch (UnsupportedEncodingException e) {
|
||||
throw new RuntimeException(e);
|
||||
throw new AssertionError(e);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -63,7 +63,7 @@ public class StringUtils {
|
||||
try {
|
||||
return decoder.decode(buffer).toString();
|
||||
} 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")
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
package org.briarproject.bramble.test;
|
||||
|
||||
import org.briarproject.bramble.api.system.Clock;
|
||||
|
||||
import java.util.concurrent.atomic.AtomicLong;
|
||||
|
||||
public class SettableClock implements Clock {
|
||||
|
||||
private final AtomicLong time;
|
||||
|
||||
public SettableClock(AtomicLong time) {
|
||||
this.time = time;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long currentTimeMillis() {
|
||||
return time.get();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sleep(long milliseconds) throws InterruptedException {
|
||||
Thread.sleep(milliseconds);
|
||||
}
|
||||
}
|
||||
@@ -2,7 +2,7 @@ dependencyVerification {
|
||||
verify = [
|
||||
'cglib:cglib:3.2.0:cglib-3.2.0.jar:adb13bab79712ad6bdf1bd59f2a3918018a8016e722e8a357065afb9e6690861',
|
||||
'com.google.code.findbugs:jsr305:3.0.2:jsr305-3.0.2.jar:766ad2a0783f2687962c8ad74ceecc38a28b9f72a2d085ee438b7813e928d0c7',
|
||||
'com.google.dagger:dagger:2.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',
|
||||
'junit:junit:4.12:junit-4.12.jar:59721f0805e223d84b90677887d9ff567dc534d7c502ca903c0c2b17f05c116a',
|
||||
'org.apache.ant:ant-launcher:1.9.4:ant-launcher-1.9.4.jar:7bccea20b41801ca17bcbc909a78c835d0f443f12d639c77bd6ae3d05861608d',
|
||||
|
||||
@@ -3,10 +3,10 @@ sourceCompatibility = 1.8
|
||||
targetCompatibility = 1.8
|
||||
|
||||
apply plugin: 'ru.vyarus.animalsniffer'
|
||||
apply plugin: 'net.ltgt.apt'
|
||||
apply plugin: 'idea'
|
||||
apply plugin: 'witness'
|
||||
apply from: 'witness.gradle'
|
||||
apply from: '../dagger.gradle'
|
||||
|
||||
dependencies {
|
||||
implementation project(path: ':bramble-api', configuration: 'default')
|
||||
@@ -14,10 +14,10 @@ dependencies {
|
||||
implementation 'com.h2database:h2:1.4.192' // The last version that supports Java 1.6
|
||||
implementation 'org.bitlet:weupnp:0.1.4'
|
||||
implementation 'net.i2p.crypto:eddsa:0.2.0'
|
||||
implementation 'org.whispersystems:curve25519-java:0.4.1'
|
||||
implementation 'org.whispersystems:curve25519-java:0.5.0'
|
||||
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 '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-junit4:2.8.2"
|
||||
testImplementation "org.jmock:jmock-legacy:2.8.2"
|
||||
testImplementation "org.hamcrest:hamcrest-library:1.3"
|
||||
testImplementation "org.hamcrest:hamcrest-core:1.3"
|
||||
|
||||
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'
|
||||
}
|
||||
|
||||
@@ -8,7 +8,7 @@ import org.briarproject.bramble.lifecycle.LifecycleModule;
|
||||
import org.briarproject.bramble.plugin.PluginModule;
|
||||
import org.briarproject.bramble.properties.PropertiesModule;
|
||||
import org.briarproject.bramble.reporting.ReportingModule;
|
||||
import org.briarproject.bramble.sync.SyncModule;
|
||||
import org.briarproject.bramble.sync.validation.ValidationModule;
|
||||
import org.briarproject.bramble.system.SystemModule;
|
||||
import org.briarproject.bramble.transport.TransportModule;
|
||||
import org.briarproject.bramble.versioning.VersioningModule;
|
||||
@@ -31,11 +31,11 @@ public interface BrambleCoreEagerSingletons {
|
||||
|
||||
void inject(ReportingModule.EagerSingletons init);
|
||||
|
||||
void inject(SyncModule.EagerSingletons init);
|
||||
|
||||
void inject(SystemModule.EagerSingletons init);
|
||||
|
||||
void inject(TransportModule.EagerSingletons init);
|
||||
|
||||
void inject(ValidationModule.EagerSingletons init);
|
||||
|
||||
void inject(VersioningModule.EagerSingletons init);
|
||||
}
|
||||
|
||||
@@ -19,6 +19,7 @@ import org.briarproject.bramble.reporting.ReportingModule;
|
||||
import org.briarproject.bramble.settings.SettingsModule;
|
||||
import org.briarproject.bramble.socks.SocksModule;
|
||||
import org.briarproject.bramble.sync.SyncModule;
|
||||
import org.briarproject.bramble.sync.validation.ValidationModule;
|
||||
import org.briarproject.bramble.system.SystemModule;
|
||||
import org.briarproject.bramble.transport.TransportModule;
|
||||
import org.briarproject.bramble.versioning.VersioningModule;
|
||||
@@ -47,6 +48,7 @@ import dagger.Module;
|
||||
SyncModule.class,
|
||||
SystemModule.class,
|
||||
TransportModule.class,
|
||||
ValidationModule.class,
|
||||
VersioningModule.class
|
||||
})
|
||||
public class BrambleCoreModule {
|
||||
@@ -60,9 +62,9 @@ public class BrambleCoreModule {
|
||||
c.inject(new PluginModule.EagerSingletons());
|
||||
c.inject(new PropertiesModule.EagerSingletons());
|
||||
c.inject(new ReportingModule.EagerSingletons());
|
||||
c.inject(new SyncModule.EagerSingletons());
|
||||
c.inject(new SystemModule.EagerSingletons());
|
||||
c.inject(new TransportModule.EagerSingletons());
|
||||
c.inject(new ValidationModule.EagerSingletons());
|
||||
c.inject(new VersioningModule.EagerSingletons());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
public void addLocalMessage(Message m, BdfDictionary metadata,
|
||||
boolean shared) throws DbException, FormatException {
|
||||
Transaction txn = db.startTransaction(false);
|
||||
try {
|
||||
addLocalMessage(txn, m, metadata, shared);
|
||||
db.commitTransaction(txn);
|
||||
} finally {
|
||||
db.endTransaction(txn);
|
||||
}
|
||||
db.transaction(false, txn -> addLocalMessage(txn, m, metadata, shared));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -113,15 +107,7 @@ class ClientHelperImpl implements ClientHelper {
|
||||
|
||||
@Override
|
||||
public Message getMessage(MessageId m) throws DbException {
|
||||
Message message;
|
||||
Transaction txn = db.startTransaction(true);
|
||||
try {
|
||||
message = getMessage(txn, m);
|
||||
db.commitTransaction(txn);
|
||||
} finally {
|
||||
db.endTransaction(txn);
|
||||
}
|
||||
return message;
|
||||
return db.transactionWithResult(true, txn -> getMessage(txn, m));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -132,15 +118,7 @@ class ClientHelperImpl implements ClientHelper {
|
||||
@Override
|
||||
public BdfList getMessageAsList(MessageId m) throws DbException,
|
||||
FormatException {
|
||||
BdfList list;
|
||||
Transaction txn = db.startTransaction(true);
|
||||
try {
|
||||
list = getMessageAsList(txn, m);
|
||||
db.commitTransaction(txn);
|
||||
} finally {
|
||||
db.endTransaction(txn);
|
||||
}
|
||||
return list;
|
||||
return db.transactionWithResult(true, txn -> getMessageAsList(txn, m));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -152,15 +130,8 @@ class ClientHelperImpl implements ClientHelper {
|
||||
@Override
|
||||
public BdfDictionary getGroupMetadataAsDictionary(GroupId g)
|
||||
throws DbException, FormatException {
|
||||
BdfDictionary dictionary;
|
||||
Transaction txn = db.startTransaction(true);
|
||||
try {
|
||||
dictionary = getGroupMetadataAsDictionary(txn, g);
|
||||
db.commitTransaction(txn);
|
||||
} finally {
|
||||
db.endTransaction(txn);
|
||||
}
|
||||
return dictionary;
|
||||
return db.transactionWithResult(true, txn ->
|
||||
getGroupMetadataAsDictionary(txn, g));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -173,15 +144,8 @@ class ClientHelperImpl implements ClientHelper {
|
||||
@Override
|
||||
public BdfDictionary getMessageMetadataAsDictionary(MessageId m)
|
||||
throws DbException, FormatException {
|
||||
BdfDictionary dictionary;
|
||||
Transaction txn = db.startTransaction(true);
|
||||
try {
|
||||
dictionary = getMessageMetadataAsDictionary(txn, m);
|
||||
db.commitTransaction(txn);
|
||||
} finally {
|
||||
db.endTransaction(txn);
|
||||
}
|
||||
return dictionary;
|
||||
return db.transactionWithResult(true, txn ->
|
||||
getMessageMetadataAsDictionary(txn, m));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -194,15 +158,8 @@ class ClientHelperImpl implements ClientHelper {
|
||||
@Override
|
||||
public Map<MessageId, BdfDictionary> getMessageMetadataAsDictionary(
|
||||
GroupId g) throws DbException, FormatException {
|
||||
Map<MessageId, BdfDictionary> map;
|
||||
Transaction txn = db.startTransaction(true);
|
||||
try {
|
||||
map = getMessageMetadataAsDictionary(txn, g);
|
||||
db.commitTransaction(txn);
|
||||
} finally {
|
||||
db.endTransaction(txn);
|
||||
}
|
||||
return map;
|
||||
return db.transactionWithResult(true, txn ->
|
||||
getMessageMetadataAsDictionary(txn, g));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -219,15 +176,8 @@ class ClientHelperImpl implements ClientHelper {
|
||||
public Map<MessageId, BdfDictionary> getMessageMetadataAsDictionary(
|
||||
GroupId g, BdfDictionary query) throws DbException,
|
||||
FormatException {
|
||||
Map<MessageId, BdfDictionary> map;
|
||||
Transaction txn = db.startTransaction(true);
|
||||
try {
|
||||
map = getMessageMetadataAsDictionary(txn, g, query);
|
||||
db.commitTransaction(txn);
|
||||
} finally {
|
||||
db.endTransaction(txn);
|
||||
}
|
||||
return map;
|
||||
return db.transactionWithResult(true, txn ->
|
||||
getMessageMetadataAsDictionary(txn, g, query));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -245,13 +195,7 @@ class ClientHelperImpl implements ClientHelper {
|
||||
@Override
|
||||
public void mergeGroupMetadata(GroupId g, BdfDictionary metadata)
|
||||
throws DbException, FormatException {
|
||||
Transaction txn = db.startTransaction(false);
|
||||
try {
|
||||
mergeGroupMetadata(txn, g, metadata);
|
||||
db.commitTransaction(txn);
|
||||
} finally {
|
||||
db.endTransaction(txn);
|
||||
}
|
||||
db.transaction(false, txn -> mergeGroupMetadata(txn, g, metadata));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -263,13 +207,7 @@ class ClientHelperImpl implements ClientHelper {
|
||||
@Override
|
||||
public void mergeMessageMetadata(MessageId m, BdfDictionary metadata)
|
||||
throws DbException, FormatException {
|
||||
Transaction txn = db.startTransaction(false);
|
||||
try {
|
||||
mergeMessageMetadata(txn, m, metadata);
|
||||
db.commitTransaction(txn);
|
||||
} finally {
|
||||
db.endTransaction(txn);
|
||||
}
|
||||
db.transaction(false, txn -> mergeMessageMetadata(txn, m, metadata));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -13,7 +13,6 @@ import org.briarproject.bramble.api.data.BdfList;
|
||||
import org.briarproject.bramble.api.db.ContactExistsException;
|
||||
import org.briarproject.bramble.api.db.DatabaseComponent;
|
||||
import org.briarproject.bramble.api.db.DbException;
|
||||
import org.briarproject.bramble.api.db.Transaction;
|
||||
import org.briarproject.bramble.api.identity.Author;
|
||||
import org.briarproject.bramble.api.identity.LocalAuthor;
|
||||
import org.briarproject.bramble.api.nullsafety.MethodsNotNullByDefault;
|
||||
@@ -158,7 +157,8 @@ class ContactExchangeTaskImpl extends Thread implements ContactExchangeTask {
|
||||
streamWriterFactory.createContactExchangeStreamWriter(out,
|
||||
alice ? aliceHeaderKey : bobHeaderKey);
|
||||
RecordWriter recordWriter =
|
||||
recordWriterFactory.createRecordWriter(streamWriter.getOutputStream());
|
||||
recordWriterFactory
|
||||
.createRecordWriter(streamWriter.getOutputStream());
|
||||
|
||||
// Derive the nonces to be signed
|
||||
byte[] aliceNonce = crypto.mac(ALICE_NONCE_LABEL, masterSecret,
|
||||
@@ -287,19 +287,14 @@ class ContactExchangeTaskImpl extends Thread implements ContactExchangeTask {
|
||||
private ContactId addContact(Author remoteAuthor, long timestamp,
|
||||
Map<TransportId, TransportProperties> remoteProperties)
|
||||
throws DbException {
|
||||
ContactId contactId;
|
||||
Transaction txn = db.startTransaction(false);
|
||||
try {
|
||||
contactId = contactManager.addContact(txn, remoteAuthor,
|
||||
return db.transactionWithResult(false, txn -> {
|
||||
ContactId contactId = contactManager.addContact(txn, remoteAuthor,
|
||||
localAuthor.getId(), masterSecret, timestamp, alice,
|
||||
true, true);
|
||||
transportPropertyManager.addRemoteProperties(txn, contactId,
|
||||
remoteProperties);
|
||||
db.commitTransaction(txn);
|
||||
} finally {
|
||||
db.endTransaction(txn);
|
||||
}
|
||||
return contactId;
|
||||
return contactId;
|
||||
});
|
||||
}
|
||||
|
||||
private void tryToClose(DuplexTransportConnection conn) {
|
||||
|
||||
@@ -10,6 +10,9 @@ import org.briarproject.bramble.api.db.NoSuchContactException;
|
||||
import org.briarproject.bramble.api.db.Transaction;
|
||||
import org.briarproject.bramble.api.identity.Author;
|
||||
import org.briarproject.bramble.api.identity.AuthorId;
|
||||
import org.briarproject.bramble.api.identity.AuthorInfo;
|
||||
import org.briarproject.bramble.api.identity.IdentityManager;
|
||||
import org.briarproject.bramble.api.identity.LocalAuthor;
|
||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||
import org.briarproject.bramble.api.transport.KeyManager;
|
||||
|
||||
@@ -18,21 +21,32 @@ import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.CopyOnWriteArrayList;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import javax.annotation.concurrent.ThreadSafe;
|
||||
import javax.inject.Inject;
|
||||
|
||||
import static org.briarproject.bramble.api.identity.AuthorConstants.MAX_AUTHOR_NAME_LENGTH;
|
||||
import static org.briarproject.bramble.api.identity.AuthorInfo.Status.OURSELVES;
|
||||
import static org.briarproject.bramble.api.identity.AuthorInfo.Status.UNKNOWN;
|
||||
import static org.briarproject.bramble.api.identity.AuthorInfo.Status.UNVERIFIED;
|
||||
import static org.briarproject.bramble.api.identity.AuthorInfo.Status.VERIFIED;
|
||||
import static org.briarproject.bramble.util.StringUtils.toUtf8;
|
||||
|
||||
@ThreadSafe
|
||||
@NotNullByDefault
|
||||
class ContactManagerImpl implements ContactManager {
|
||||
|
||||
private final DatabaseComponent db;
|
||||
private final KeyManager keyManager;
|
||||
private final IdentityManager identityManager;
|
||||
private final List<ContactHook> hooks;
|
||||
|
||||
@Inject
|
||||
ContactManagerImpl(DatabaseComponent db, KeyManager keyManager) {
|
||||
ContactManagerImpl(DatabaseComponent db, KeyManager keyManager,
|
||||
IdentityManager identityManager) {
|
||||
this.db = db;
|
||||
this.keyManager = keyManager;
|
||||
this.identityManager = identityManager;
|
||||
hooks = new CopyOnWriteArrayList<>();
|
||||
}
|
||||
|
||||
@@ -65,42 +79,21 @@ class ContactManagerImpl implements ContactManager {
|
||||
public ContactId addContact(Author remote, AuthorId local, SecretKey master,
|
||||
long timestamp, boolean alice, boolean verified, boolean active)
|
||||
throws DbException {
|
||||
ContactId c;
|
||||
Transaction txn = db.startTransaction(false);
|
||||
try {
|
||||
c = addContact(txn, remote, local, master, timestamp, alice,
|
||||
verified, active);
|
||||
db.commitTransaction(txn);
|
||||
} finally {
|
||||
db.endTransaction(txn);
|
||||
}
|
||||
return c;
|
||||
return db.transactionWithResult(false, txn ->
|
||||
addContact(txn, remote, local, master, timestamp, alice,
|
||||
verified, active));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Contact getContact(ContactId c) throws DbException {
|
||||
Contact contact;
|
||||
Transaction txn = db.startTransaction(true);
|
||||
try {
|
||||
contact = db.getContact(txn, c);
|
||||
db.commitTransaction(txn);
|
||||
} finally {
|
||||
db.endTransaction(txn);
|
||||
}
|
||||
return contact;
|
||||
return db.transactionWithResult(true, txn -> db.getContact(txn, c));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Contact getContact(AuthorId remoteAuthorId, AuthorId localAuthorId)
|
||||
throws DbException {
|
||||
Transaction txn = db.startTransaction(true);
|
||||
try {
|
||||
Contact c = getContact(txn, remoteAuthorId, localAuthorId);
|
||||
db.commitTransaction(txn);
|
||||
return c;
|
||||
} finally {
|
||||
db.endTransaction(txn);
|
||||
}
|
||||
return db.transactionWithResult(true, txn ->
|
||||
getContact(txn, remoteAuthorId, localAuthorId));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -118,14 +111,8 @@ class ContactManagerImpl implements ContactManager {
|
||||
|
||||
@Override
|
||||
public Collection<Contact> getActiveContacts() throws DbException {
|
||||
Collection<Contact> contacts;
|
||||
Transaction txn = db.startTransaction(true);
|
||||
try {
|
||||
contacts = db.getContacts(txn);
|
||||
db.commitTransaction(txn);
|
||||
} finally {
|
||||
db.endTransaction(txn);
|
||||
}
|
||||
Collection<Contact> contacts =
|
||||
db.transactionWithResult(true, db::getContacts);
|
||||
List<Contact> active = new ArrayList<>(contacts.size());
|
||||
for (Contact c : contacts) if (c.isActive()) active.add(c);
|
||||
return active;
|
||||
@@ -133,13 +120,7 @@ class ContactManagerImpl implements ContactManager {
|
||||
|
||||
@Override
|
||||
public void removeContact(ContactId c) throws DbException {
|
||||
Transaction txn = db.startTransaction(false);
|
||||
try {
|
||||
removeContact(txn, c);
|
||||
db.commitTransaction(txn);
|
||||
} finally {
|
||||
db.endTransaction(txn);
|
||||
}
|
||||
db.transaction(false, txn -> removeContact(txn, c));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -148,6 +129,23 @@ class ContactManagerImpl implements ContactManager {
|
||||
db.setContactActive(txn, c, active);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setContactAlias(Transaction txn, ContactId c,
|
||||
@Nullable String alias) throws DbException {
|
||||
if (alias != null) {
|
||||
int aliasLength = toUtf8(alias).length;
|
||||
if (aliasLength == 0 || aliasLength > MAX_AUTHOR_NAME_LENGTH)
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
db.setContactAlias(txn, c, alias);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setContactAlias(ContactId c, @Nullable String alias)
|
||||
throws DbException {
|
||||
db.transaction(false, txn -> setContactAlias(txn, c, alias));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean contactExists(Transaction txn, AuthorId remoteAuthorId,
|
||||
AuthorId localAuthorId) throws DbException {
|
||||
@@ -157,15 +155,8 @@ class ContactManagerImpl implements ContactManager {
|
||||
@Override
|
||||
public boolean contactExists(AuthorId remoteAuthorId,
|
||||
AuthorId localAuthorId) throws DbException {
|
||||
boolean exists;
|
||||
Transaction txn = db.startTransaction(true);
|
||||
try {
|
||||
exists = contactExists(txn, remoteAuthorId, localAuthorId);
|
||||
db.commitTransaction(txn);
|
||||
} finally {
|
||||
db.endTransaction(txn);
|
||||
}
|
||||
return exists;
|
||||
return db.transactionWithResult(true, txn ->
|
||||
contactExists(txn, remoteAuthorId, localAuthorId));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -176,4 +167,23 @@ class ContactManagerImpl implements ContactManager {
|
||||
db.removeContact(txn, c);
|
||||
}
|
||||
|
||||
@Override
|
||||
public AuthorInfo getAuthorInfo(AuthorId a) throws DbException {
|
||||
return db.transactionWithResult(true, txn -> getAuthorInfo(txn, a));
|
||||
}
|
||||
|
||||
@Override
|
||||
public AuthorInfo getAuthorInfo(Transaction txn, AuthorId authorId)
|
||||
throws DbException {
|
||||
LocalAuthor localAuthor = identityManager.getLocalAuthor(txn);
|
||||
if (localAuthor.getId().equals(authorId))
|
||||
return new AuthorInfo(OURSELVES);
|
||||
Collection<Contact> contacts = db.getContactsByAuthorId(txn, authorId);
|
||||
if (contacts.isEmpty()) return new AuthorInfo(UNKNOWN);
|
||||
if (contacts.size() > 1) throw new AssertionError();
|
||||
Contact c = contacts.iterator().next();
|
||||
if (c.isVerified()) return new AuthorInfo(VERIFIED, c.getAlias());
|
||||
else return new AuthorInfo(UNVERIFIED, c.getAlias());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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_8;
|
||||
import static org.briarproject.bramble.data.Types.TRUE;
|
||||
import static org.briarproject.bramble.util.StringUtils.fromUtf8;
|
||||
|
||||
@NotThreadSafe
|
||||
@NotNullByDefault
|
||||
@@ -253,7 +254,7 @@ class BdfReaderImpl implements BdfReader {
|
||||
if (length < 0 || length > maxBufferSize) throw new FormatException();
|
||||
if (length == 0) return "";
|
||||
readIntoBuffer(length);
|
||||
return new String(buf, 0, length, "UTF-8");
|
||||
return fromUtf8(buf, 0, length);
|
||||
}
|
||||
|
||||
private int readStringLength() throws IOException {
|
||||
|
||||
@@ -22,7 +22,7 @@ import org.briarproject.bramble.api.sync.GroupId;
|
||||
import org.briarproject.bramble.api.sync.Message;
|
||||
import org.briarproject.bramble.api.sync.MessageId;
|
||||
import org.briarproject.bramble.api.sync.MessageStatus;
|
||||
import org.briarproject.bramble.api.sync.ValidationManager.State;
|
||||
import org.briarproject.bramble.api.sync.validation.MessageState;
|
||||
import org.briarproject.bramble.api.transport.KeySet;
|
||||
import org.briarproject.bramble.api.transport.KeySetId;
|
||||
import org.briarproject.bramble.api.transport.TransportKeys;
|
||||
@@ -106,7 +106,7 @@ interface Database<T> {
|
||||
* @param sender the contact from whom the message was received, or null
|
||||
* 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;
|
||||
|
||||
/**
|
||||
@@ -114,7 +114,7 @@ interface Database<T> {
|
||||
* in the given state.
|
||||
*/
|
||||
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.
|
||||
@@ -310,11 +310,11 @@ interface Database<T> {
|
||||
/**
|
||||
* Returns the IDs and states of all dependencies of the given message.
|
||||
* For missing dependencies and dependencies in other groups, the state
|
||||
* {@link State UNKNOWN} is returned.
|
||||
* {@link MessageState UNKNOWN} is returned.
|
||||
* <p/>
|
||||
* Read-only.
|
||||
*/
|
||||
Map<MessageId, State> getMessageDependencies(T txn, MessageId m)
|
||||
Map<MessageId, MessageState> getMessageDependencies(T txn, MessageId m)
|
||||
throws DbException;
|
||||
|
||||
/**
|
||||
@@ -324,7 +324,7 @@ interface Database<T> {
|
||||
* <p/>
|
||||
* Read-only.
|
||||
*/
|
||||
Map<MessageId, State> getMessageDependents(T txn, MessageId m)
|
||||
Map<MessageId, MessageState> getMessageDependents(T txn, MessageId m)
|
||||
throws DbException;
|
||||
|
||||
/**
|
||||
@@ -383,7 +383,7 @@ interface Database<T> {
|
||||
* <p/>
|
||||
* 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
|
||||
@@ -616,6 +616,12 @@ interface Database<T> {
|
||||
void setContactActive(T txn, ContactId c, boolean active)
|
||||
throws DbException;
|
||||
|
||||
/**
|
||||
* Sets an alias name for a contact.
|
||||
*/
|
||||
void setContactAlias(T txn, ContactId c, @Nullable String alias)
|
||||
throws DbException;
|
||||
|
||||
/**
|
||||
* Sets the given group's visibility to the given contact to either
|
||||
* {@link Visibility VISIBLE} or {@link Visibility SHARED}.
|
||||
@@ -631,7 +637,8 @@ interface Database<T> {
|
||||
/**
|
||||
* 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
|
||||
|
||||
@@ -9,7 +9,9 @@ import org.briarproject.bramble.api.contact.event.ContactVerifiedEvent;
|
||||
import org.briarproject.bramble.api.crypto.SecretKey;
|
||||
import org.briarproject.bramble.api.db.ContactExistsException;
|
||||
import org.briarproject.bramble.api.db.DatabaseComponent;
|
||||
import org.briarproject.bramble.api.db.DbCallable;
|
||||
import org.briarproject.bramble.api.db.DbException;
|
||||
import org.briarproject.bramble.api.db.DbRunnable;
|
||||
import org.briarproject.bramble.api.db.Metadata;
|
||||
import org.briarproject.bramble.api.db.MigrationListener;
|
||||
import org.briarproject.bramble.api.db.NoSuchContactException;
|
||||
@@ -17,6 +19,7 @@ import org.briarproject.bramble.api.db.NoSuchGroupException;
|
||||
import org.briarproject.bramble.api.db.NoSuchLocalAuthorException;
|
||||
import org.briarproject.bramble.api.db.NoSuchMessageException;
|
||||
import org.briarproject.bramble.api.db.NoSuchTransportException;
|
||||
import org.briarproject.bramble.api.db.NullableDbCallable;
|
||||
import org.briarproject.bramble.api.db.Transaction;
|
||||
import org.briarproject.bramble.api.event.Event;
|
||||
import org.briarproject.bramble.api.event.EventBus;
|
||||
@@ -40,7 +43,6 @@ import org.briarproject.bramble.api.sync.MessageId;
|
||||
import org.briarproject.bramble.api.sync.MessageStatus;
|
||||
import org.briarproject.bramble.api.sync.Offer;
|
||||
import org.briarproject.bramble.api.sync.Request;
|
||||
import org.briarproject.bramble.api.sync.ValidationManager.State;
|
||||
import org.briarproject.bramble.api.sync.event.GroupAddedEvent;
|
||||
import org.briarproject.bramble.api.sync.event.GroupRemovedEvent;
|
||||
import org.briarproject.bramble.api.sync.event.GroupVisibilityUpdatedEvent;
|
||||
@@ -52,6 +54,7 @@ import org.briarproject.bramble.api.sync.event.MessageToAckEvent;
|
||||
import org.briarproject.bramble.api.sync.event.MessageToRequestEvent;
|
||||
import org.briarproject.bramble.api.sync.event.MessagesAckedEvent;
|
||||
import org.briarproject.bramble.api.sync.event.MessagesSentEvent;
|
||||
import org.briarproject.bramble.api.sync.validation.MessageState;
|
||||
import org.briarproject.bramble.api.transport.KeySet;
|
||||
import org.briarproject.bramble.api.transport.KeySetId;
|
||||
import org.briarproject.bramble.api.transport.TransportKeys;
|
||||
@@ -72,8 +75,8 @@ import javax.inject.Inject;
|
||||
import static java.util.logging.Level.WARNING;
|
||||
import static org.briarproject.bramble.api.sync.Group.Visibility.INVISIBLE;
|
||||
import static org.briarproject.bramble.api.sync.Group.Visibility.SHARED;
|
||||
import static org.briarproject.bramble.api.sync.ValidationManager.State.DELIVERED;
|
||||
import static org.briarproject.bramble.api.sync.ValidationManager.State.UNKNOWN;
|
||||
import static org.briarproject.bramble.api.sync.validation.MessageState.DELIVERED;
|
||||
import static org.briarproject.bramble.api.sync.validation.MessageState.UNKNOWN;
|
||||
import static org.briarproject.bramble.db.DatabaseConstants.MAX_OFFERED_MESSAGES;
|
||||
import static org.briarproject.bramble.util.LogUtils.logDuration;
|
||||
import static org.briarproject.bramble.util.LogUtils.logException;
|
||||
@@ -166,6 +169,45 @@ class DatabaseComponentImpl<T> implements DatabaseComponent {
|
||||
for (Event e : transaction.getEvents()) eventBus.broadcast(e);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <E extends Exception> void transaction(boolean readOnly,
|
||||
DbRunnable<E> task) throws DbException, E {
|
||||
Transaction txn = startTransaction(readOnly);
|
||||
try {
|
||||
task.run(txn);
|
||||
commitTransaction(txn);
|
||||
} finally {
|
||||
endTransaction(txn);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public <R, E extends Exception> R transactionWithResult(boolean readOnly,
|
||||
DbCallable<R, E> task) throws DbException, E {
|
||||
Transaction txn = startTransaction(readOnly);
|
||||
try {
|
||||
R result = task.call(txn);
|
||||
commitTransaction(txn);
|
||||
return result;
|
||||
} finally {
|
||||
endTransaction(txn);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public <R, E extends Exception> R transactionWithNullableResult(
|
||||
boolean readOnly, NullableDbCallable<R, E> task)
|
||||
throws DbException, E {
|
||||
Transaction txn = startTransaction(readOnly);
|
||||
try {
|
||||
R result = task.call(txn);
|
||||
commitTransaction(txn);
|
||||
return result;
|
||||
} finally {
|
||||
endTransaction(txn);
|
||||
}
|
||||
}
|
||||
|
||||
private T unbox(Transaction transaction) {
|
||||
if (transaction.isCommitted()) throw new IllegalStateException();
|
||||
return txnClass.cast(transaction.unbox());
|
||||
@@ -537,7 +579,7 @@ class DatabaseComponentImpl<T> implements DatabaseComponent {
|
||||
}
|
||||
|
||||
@Override
|
||||
public State getMessageState(Transaction transaction, MessageId m)
|
||||
public MessageState getMessageState(Transaction transaction, MessageId m)
|
||||
throws DbException {
|
||||
T txn = unbox(transaction);
|
||||
if (!db.containsMessage(txn, m))
|
||||
@@ -577,8 +619,8 @@ class DatabaseComponentImpl<T> implements DatabaseComponent {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<MessageId, State> getMessageDependencies(Transaction transaction,
|
||||
MessageId m) throws DbException {
|
||||
public Map<MessageId, MessageState> getMessageDependencies(
|
||||
Transaction transaction, MessageId m) throws DbException {
|
||||
T txn = unbox(transaction);
|
||||
if (!db.containsMessage(txn, m))
|
||||
throw new NoSuchMessageException();
|
||||
@@ -586,8 +628,8 @@ class DatabaseComponentImpl<T> implements DatabaseComponent {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<MessageId, State> getMessageDependents(Transaction transaction,
|
||||
MessageId m) throws DbException {
|
||||
public Map<MessageId, MessageState> getMessageDependents(
|
||||
Transaction transaction, MessageId m) throws DbException {
|
||||
T txn = unbox(transaction);
|
||||
if (!db.containsMessage(txn, m))
|
||||
throw new NoSuchMessageException();
|
||||
@@ -832,6 +874,16 @@ class DatabaseComponentImpl<T> implements DatabaseComponent {
|
||||
transaction.attach(new ContactStatusChangedEvent(c, active));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setContactAlias(Transaction transaction, ContactId c,
|
||||
@Nullable String alias) throws DbException {
|
||||
if (transaction.isReadOnly()) throw new IllegalArgumentException();
|
||||
T txn = unbox(transaction);
|
||||
if (!db.containsContact(txn, c))
|
||||
throw new NoSuchContactException();
|
||||
db.setContactAlias(txn, c, alias);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setGroupVisibility(Transaction transaction, ContactId c,
|
||||
GroupId g, Visibility v) throws DbException {
|
||||
@@ -866,7 +918,7 @@ class DatabaseComponentImpl<T> implements DatabaseComponent {
|
||||
|
||||
@Override
|
||||
public void setMessageState(Transaction transaction, MessageId m,
|
||||
State state) throws DbException {
|
||||
MessageState state) throws DbException {
|
||||
if (transaction.isReadOnly()) throw new IllegalArgumentException();
|
||||
T txn = unbox(transaction);
|
||||
if (!db.containsMessage(txn, m))
|
||||
@@ -883,10 +935,10 @@ class DatabaseComponentImpl<T> implements DatabaseComponent {
|
||||
T txn = unbox(transaction);
|
||||
if (!db.containsMessage(txn, dependent.getId()))
|
||||
throw new NoSuchMessageException();
|
||||
State dependentState = db.getMessageState(txn, dependent.getId());
|
||||
MessageState dependentState =
|
||||
db.getMessageState(txn, dependent.getId());
|
||||
for (MessageId dependency : dependencies) {
|
||||
db.addMessageDependency(txn, dependent, dependency,
|
||||
dependentState);
|
||||
db.addMessageDependency(txn, dependent, dependency, dependentState);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -2,6 +2,8 @@ package org.briarproject.bramble.db;
|
||||
|
||||
import org.briarproject.bramble.api.settings.Settings;
|
||||
|
||||
import static java.util.concurrent.TimeUnit.DAYS;
|
||||
|
||||
interface DatabaseConstants {
|
||||
|
||||
/**
|
||||
@@ -23,4 +25,16 @@ interface DatabaseConstants {
|
||||
*/
|
||||
String SCHEMA_VERSION_KEY = "schemaVersion";
|
||||
|
||||
/**
|
||||
* The {@link Settings} key under which the time of the last database
|
||||
* compaction is stored.
|
||||
*/
|
||||
String LAST_COMPACTED_KEY = "lastCompacted";
|
||||
|
||||
/**
|
||||
* The maximum time between database compactions in milliseconds. When the
|
||||
* database is opened it will be compacted if more than this amount of time
|
||||
* has passed since the last compaction.
|
||||
*/
|
||||
long MAX_COMPACTION_INTERVAL_MS = DAYS.toMillis(30);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
package org.briarproject.bramble.db;
|
||||
|
||||
class DatabaseTypes {
|
||||
|
||||
private final String hashType, secretType, binaryType;
|
||||
private final String counterType, stringType;
|
||||
|
||||
public DatabaseTypes(String hashType, String secretType, String binaryType,
|
||||
String counterType, String stringType) {
|
||||
this.hashType = hashType;
|
||||
this.secretType = secretType;
|
||||
this.binaryType = binaryType;
|
||||
this.counterType = counterType;
|
||||
this.stringType = stringType;
|
||||
}
|
||||
|
||||
/**
|
||||
* Replaces database type placeholders in a statement with the actual types.
|
||||
* These placeholders are currently supported:
|
||||
* <li> _HASH
|
||||
* <li> _SECRET
|
||||
* <li> _BINARY
|
||||
* <li> _COUNTER
|
||||
* <li> _STRING
|
||||
*/
|
||||
String replaceTypes(String s) {
|
||||
s = s.replaceAll("_HASH", hashType);
|
||||
s = s.replaceAll("_SECRET", secretType);
|
||||
s = s.replaceAll("_BINARY", binaryType);
|
||||
s = s.replaceAll("_COUNTER", counterType);
|
||||
s = s.replaceAll("_STRING", stringType);
|
||||
return s;
|
||||
}
|
||||
}
|
||||
@@ -13,6 +13,7 @@ import java.io.File;
|
||||
import java.sql.Connection;
|
||||
import java.sql.DriverManager;
|
||||
import java.sql.SQLException;
|
||||
import java.sql.Statement;
|
||||
import java.util.Properties;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
@@ -29,6 +30,8 @@ class H2Database extends JdbcDatabase {
|
||||
private static final String BINARY_TYPE = "BINARY";
|
||||
private static final String COUNTER_TYPE = "INT NOT NULL AUTO_INCREMENT";
|
||||
private static final String STRING_TYPE = "VARCHAR";
|
||||
private static final DatabaseTypes dbTypes = new DatabaseTypes(HASH_TYPE,
|
||||
SECRET_TYPE, BINARY_TYPE, COUNTER_TYPE, STRING_TYPE);
|
||||
|
||||
private final DatabaseConfig config;
|
||||
private final String url;
|
||||
@@ -39,8 +42,7 @@ class H2Database extends JdbcDatabase {
|
||||
@Inject
|
||||
H2Database(DatabaseConfig config, MessageFactory messageFactory,
|
||||
Clock clock) {
|
||||
super(HASH_TYPE, SECRET_TYPE, BINARY_TYPE, COUNTER_TYPE, STRING_TYPE,
|
||||
messageFactory, clock);
|
||||
super(dbTypes, messageFactory, clock);
|
||||
this.config = config;
|
||||
File dir = config.getDatabaseDirectory();
|
||||
String path = new File(dir, "db").getAbsolutePath();
|
||||
@@ -106,4 +108,22 @@ class H2Database extends JdbcDatabase {
|
||||
String getUrl() {
|
||||
return url;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void compactAndClose() throws DbException {
|
||||
Connection c = null;
|
||||
Statement s = null;
|
||||
try {
|
||||
c = createConnection();
|
||||
closeAllConnections();
|
||||
s = c.createStatement();
|
||||
s.execute("SHUTDOWN COMPACT");
|
||||
s.close();
|
||||
c.close();
|
||||
} catch (SQLException e) {
|
||||
tryToClose(s);
|
||||
tryToClose(c);
|
||||
throw new DbException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -30,6 +30,8 @@ class HyperSqlDatabase extends JdbcDatabase {
|
||||
private static final String COUNTER_TYPE =
|
||||
"INTEGER NOT NULL GENERATED ALWAYS AS IDENTITY(START WITH 1)";
|
||||
private static final String STRING_TYPE = "VARCHAR";
|
||||
private static final DatabaseTypes dbTypes = new DatabaseTypes(HASH_TYPE,
|
||||
SECRET_TYPE, BINARY_TYPE, COUNTER_TYPE, STRING_TYPE);
|
||||
|
||||
private final DatabaseConfig config;
|
||||
private final String url;
|
||||
@@ -40,8 +42,7 @@ class HyperSqlDatabase extends JdbcDatabase {
|
||||
@Inject
|
||||
HyperSqlDatabase(DatabaseConfig config, MessageFactory messageFactory,
|
||||
Clock clock) {
|
||||
super(HASH_TYPE, SECRET_TYPE, BINARY_TYPE, COUNTER_TYPE, STRING_TYPE,
|
||||
messageFactory, clock);
|
||||
super(dbTypes, messageFactory, clock);
|
||||
this.config = config;
|
||||
File dir = config.getDatabaseDirectory();
|
||||
String path = new File(dir, "db").getAbsolutePath();
|
||||
@@ -61,20 +62,24 @@ class HyperSqlDatabase extends JdbcDatabase {
|
||||
|
||||
@Override
|
||||
public void close() throws DbException {
|
||||
Connection c = null;
|
||||
Statement s = null;
|
||||
try {
|
||||
super.closeAllConnections();
|
||||
Connection c = createConnection();
|
||||
Statement s = c.createStatement();
|
||||
c = createConnection();
|
||||
s = c.createStatement();
|
||||
s.executeQuery("SHUTDOWN");
|
||||
s.close();
|
||||
c.close();
|
||||
} catch (SQLException e) {
|
||||
tryToClose(s);
|
||||
tryToClose(c);
|
||||
throw new DbException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getFreeSpace() throws DbException {
|
||||
public long getFreeSpace() {
|
||||
File dir = config.getDatabaseDirectory();
|
||||
long maxSize = config.getMaxSize();
|
||||
long free = dir.getFreeSpace();
|
||||
@@ -104,4 +109,22 @@ class HyperSqlDatabase extends JdbcDatabase {
|
||||
String hex = StringUtils.toHexString(key.getBytes());
|
||||
return DriverManager.getConnection(url + ";crypt_key=" + hex);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void compactAndClose() throws DbException {
|
||||
Connection c = null;
|
||||
Statement s = null;
|
||||
try {
|
||||
super.closeAllConnections();
|
||||
c = createConnection();
|
||||
s = c.createStatement();
|
||||
s.executeQuery("SHUTDOWN COMPACT");
|
||||
s.close();
|
||||
c.close();
|
||||
} catch (SQLException e) {
|
||||
tryToClose(s);
|
||||
tryToClose(c);
|
||||
throw new DbException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,7 +24,7 @@ import org.briarproject.bramble.api.sync.Message;
|
||||
import org.briarproject.bramble.api.sync.MessageFactory;
|
||||
import org.briarproject.bramble.api.sync.MessageId;
|
||||
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.system.Clock;
|
||||
import org.briarproject.bramble.api.transport.IncomingKeys;
|
||||
import org.briarproject.bramble.api.transport.KeySet;
|
||||
@@ -56,6 +56,7 @@ import java.util.logging.Logger;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import static java.sql.Types.INTEGER;
|
||||
import static java.sql.Types.VARCHAR;
|
||||
import static java.util.logging.Level.INFO;
|
||||
import static java.util.logging.Level.WARNING;
|
||||
import static org.briarproject.bramble.api.db.Metadata.REMOVE;
|
||||
@@ -63,13 +64,17 @@ 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.VISIBLE;
|
||||
import static org.briarproject.bramble.api.sync.SyncConstants.MESSAGE_HEADER_LENGTH;
|
||||
import static org.briarproject.bramble.api.sync.ValidationManager.State.DELIVERED;
|
||||
import static org.briarproject.bramble.api.sync.ValidationManager.State.PENDING;
|
||||
import static org.briarproject.bramble.api.sync.ValidationManager.State.UNKNOWN;
|
||||
import static org.briarproject.bramble.api.sync.validation.MessageState.DELIVERED;
|
||||
import static org.briarproject.bramble.api.sync.validation.MessageState.PENDING;
|
||||
import static org.briarproject.bramble.api.sync.validation.MessageState.UNKNOWN;
|
||||
import static org.briarproject.bramble.db.DatabaseConstants.DB_SETTINGS_NAMESPACE;
|
||||
import static org.briarproject.bramble.db.DatabaseConstants.LAST_COMPACTED_KEY;
|
||||
import static org.briarproject.bramble.db.DatabaseConstants.MAX_COMPACTION_INTERVAL_MS;
|
||||
import static org.briarproject.bramble.db.DatabaseConstants.SCHEMA_VERSION_KEY;
|
||||
import static org.briarproject.bramble.db.ExponentialBackoff.calculateExpiry;
|
||||
import static org.briarproject.bramble.util.LogUtils.logDuration;
|
||||
import static org.briarproject.bramble.util.LogUtils.logException;
|
||||
import static org.briarproject.bramble.util.LogUtils.now;
|
||||
|
||||
/**
|
||||
* A generic database implementation that can be used with any JDBC-compatible
|
||||
@@ -79,7 +84,7 @@ import static org.briarproject.bramble.util.LogUtils.logException;
|
||||
abstract class JdbcDatabase implements Database<Connection> {
|
||||
|
||||
// Package access for testing
|
||||
static final int CODE_SCHEMA_VERSION = 40;
|
||||
static final int CODE_SCHEMA_VERSION = 41;
|
||||
|
||||
// Rotation period offsets for incoming transport keys
|
||||
private static final int OFFSET_PREV = -1;
|
||||
@@ -109,6 +114,7 @@ abstract class JdbcDatabase implements Database<Connection> {
|
||||
+ " authorId _HASH NOT NULL,"
|
||||
+ " formatVersion INT NOT NULL,"
|
||||
+ " name _STRING NOT NULL,"
|
||||
+ " alias _STRING," // Null if no alias exists
|
||||
+ " publicKey _BINARY NOT NULL,"
|
||||
+ " localAuthorId _HASH NOT NULL,"
|
||||
+ " verified BOOLEAN NOT NULL,"
|
||||
@@ -306,10 +312,9 @@ abstract class JdbcDatabase implements Database<Connection> {
|
||||
Logger.getLogger(JdbcDatabase.class.getName());
|
||||
|
||||
// Different database libraries use different names for certain types
|
||||
private final String hashType, secretType, binaryType;
|
||||
private final String counterType, stringType;
|
||||
private final MessageFactory messageFactory;
|
||||
private final Clock clock;
|
||||
private final DatabaseTypes dbTypes;
|
||||
|
||||
// Locking: connectionsLock
|
||||
private final LinkedList<Connection> connections = new LinkedList<>();
|
||||
@@ -317,20 +322,16 @@ abstract class JdbcDatabase implements Database<Connection> {
|
||||
private int openConnections = 0; // Locking: connectionsLock
|
||||
private boolean closed = false; // Locking: connectionsLock
|
||||
|
||||
@Nullable
|
||||
protected abstract Connection createConnection() throws SQLException;
|
||||
|
||||
protected abstract void compactAndClose() throws DbException;
|
||||
|
||||
private final Lock connectionsLock = new ReentrantLock();
|
||||
private final Condition connectionsChanged = connectionsLock.newCondition();
|
||||
|
||||
JdbcDatabase(String hashType, String secretType, String binaryType,
|
||||
String counterType, String stringType,
|
||||
MessageFactory messageFactory, Clock clock) {
|
||||
this.hashType = hashType;
|
||||
this.secretType = secretType;
|
||||
this.binaryType = binaryType;
|
||||
this.counterType = counterType;
|
||||
this.stringType = stringType;
|
||||
JdbcDatabase(DatabaseTypes databaseTypes, MessageFactory messageFactory,
|
||||
Clock clock) {
|
||||
this.dbTypes = databaseTypes;
|
||||
this.messageFactory = messageFactory;
|
||||
this.clock = clock;
|
||||
}
|
||||
@@ -344,13 +345,16 @@ abstract class JdbcDatabase implements Database<Connection> {
|
||||
throw new DbException(e);
|
||||
}
|
||||
// Open the database and create the tables and indexes if necessary
|
||||
boolean compact;
|
||||
Connection txn = startTransaction();
|
||||
try {
|
||||
if (reopen) {
|
||||
checkSchemaVersion(txn, listener);
|
||||
Settings s = getSettings(txn, DB_SETTINGS_NAMESPACE);
|
||||
compact = migrateSchema(txn, s, listener) || isCompactionDue(s);
|
||||
} else {
|
||||
createTables(txn);
|
||||
storeSchemaVersion(txn, CODE_SCHEMA_VERSION);
|
||||
initialiseSettings(txn);
|
||||
compact = false;
|
||||
}
|
||||
createIndexes(txn);
|
||||
commitTransaction(txn);
|
||||
@@ -358,6 +362,25 @@ abstract class JdbcDatabase implements Database<Connection> {
|
||||
abortTransaction(txn);
|
||||
throw e;
|
||||
}
|
||||
// Compact the database if necessary
|
||||
if (compact) {
|
||||
if (listener != null) listener.onDatabaseCompaction();
|
||||
long start = now();
|
||||
compactAndClose();
|
||||
logDuration(LOG, "Compacting database", start);
|
||||
// Allow the next transaction to reopen the DB
|
||||
synchronized (connectionsLock) {
|
||||
closed = false;
|
||||
}
|
||||
txn = startTransaction();
|
||||
try {
|
||||
storeLastCompacted(txn);
|
||||
commitTransaction(txn);
|
||||
} catch (DbException e) {
|
||||
abortTransaction(txn);
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -365,17 +388,18 @@ abstract class JdbcDatabase implements Database<Connection> {
|
||||
* version used by the current code and applies any suitable migrations to
|
||||
* the data if necessary.
|
||||
*
|
||||
* @return true if any migrations were applied, false if the schema was
|
||||
* already current
|
||||
* @throws DataTooNewException if the data uses a newer schema than the
|
||||
* current code
|
||||
* @throws DataTooOldException if the data uses an older schema than the
|
||||
* current code and cannot be migrated
|
||||
*/
|
||||
private void checkSchemaVersion(Connection txn,
|
||||
private boolean migrateSchema(Connection txn, Settings s,
|
||||
@Nullable MigrationListener listener) throws DbException {
|
||||
Settings s = getSettings(txn, DB_SETTINGS_NAMESPACE);
|
||||
int dataSchemaVersion = s.getInt(SCHEMA_VERSION_KEY, -1);
|
||||
if (dataSchemaVersion == -1) throw new DbException();
|
||||
if (dataSchemaVersion == CODE_SCHEMA_VERSION) return;
|
||||
if (dataSchemaVersion == CODE_SCHEMA_VERSION) return false;
|
||||
if (CODE_SCHEMA_VERSION < dataSchemaVersion)
|
||||
throw new DataTooNewException();
|
||||
// Apply any suitable migrations in order
|
||||
@@ -384,7 +408,7 @@ abstract class JdbcDatabase implements Database<Connection> {
|
||||
if (start == dataSchemaVersion) {
|
||||
if (LOG.isLoggable(INFO))
|
||||
LOG.info("Migrating from schema " + start + " to " + end);
|
||||
if (listener != null) listener.onMigrationRun();
|
||||
if (listener != null) listener.onDatabaseMigration();
|
||||
// Apply the migration
|
||||
m.migrate(txn);
|
||||
// Store the new schema version
|
||||
@@ -394,11 +418,24 @@ abstract class JdbcDatabase implements Database<Connection> {
|
||||
}
|
||||
if (dataSchemaVersion != CODE_SCHEMA_VERSION)
|
||||
throw new DataTooOldException();
|
||||
return true;
|
||||
}
|
||||
|
||||
// Package access for testing
|
||||
List<Migration<Connection>> getMigrations() {
|
||||
return Arrays.asList(new Migration38_39(), new Migration39_40());
|
||||
return Arrays.asList(
|
||||
new Migration38_39(),
|
||||
new Migration39_40(),
|
||||
new Migration40_41(dbTypes)
|
||||
);
|
||||
}
|
||||
|
||||
private boolean isCompactionDue(Settings s) {
|
||||
long lastCompacted = s.getLong(LAST_COMPACTED_KEY, 0);
|
||||
long elapsed = clock.currentTimeMillis() - lastCompacted;
|
||||
if (LOG.isLoggable(INFO))
|
||||
LOG.info(elapsed + " ms since last compaction");
|
||||
return elapsed > MAX_COMPACTION_INTERVAL_MS;
|
||||
}
|
||||
|
||||
private void storeSchemaVersion(Connection txn, int version)
|
||||
@@ -408,6 +445,19 @@ abstract class JdbcDatabase implements Database<Connection> {
|
||||
mergeSettings(txn, s, DB_SETTINGS_NAMESPACE);
|
||||
}
|
||||
|
||||
private void storeLastCompacted(Connection txn) throws DbException {
|
||||
Settings s = new Settings();
|
||||
s.putLong(LAST_COMPACTED_KEY, clock.currentTimeMillis());
|
||||
mergeSettings(txn, s, DB_SETTINGS_NAMESPACE);
|
||||
}
|
||||
|
||||
private void initialiseSettings(Connection txn) throws DbException {
|
||||
Settings s = new Settings();
|
||||
s.putInt(SCHEMA_VERSION_KEY, CODE_SCHEMA_VERSION);
|
||||
s.putLong(LAST_COMPACTED_KEY, clock.currentTimeMillis());
|
||||
mergeSettings(txn, s, DB_SETTINGS_NAMESPACE);
|
||||
}
|
||||
|
||||
private void tryToClose(@Nullable ResultSet rs) {
|
||||
try {
|
||||
if (rs != null) rs.close();
|
||||
@@ -416,7 +466,7 @@ abstract class JdbcDatabase implements Database<Connection> {
|
||||
}
|
||||
}
|
||||
|
||||
private void tryToClose(@Nullable Statement s) {
|
||||
protected void tryToClose(@Nullable Statement s) {
|
||||
try {
|
||||
if (s != null) s.close();
|
||||
} catch (SQLException e) {
|
||||
@@ -424,24 +474,32 @@ abstract class JdbcDatabase implements Database<Connection> {
|
||||
}
|
||||
}
|
||||
|
||||
protected void tryToClose(@Nullable Connection c) {
|
||||
try {
|
||||
if (c != null) c.close();
|
||||
} catch (SQLException e) {
|
||||
logException(LOG, WARNING, e);
|
||||
}
|
||||
}
|
||||
|
||||
private void createTables(Connection txn) throws DbException {
|
||||
Statement s = null;
|
||||
try {
|
||||
s = txn.createStatement();
|
||||
s.executeUpdate(insertTypeNames(CREATE_SETTINGS));
|
||||
s.executeUpdate(insertTypeNames(CREATE_LOCAL_AUTHORS));
|
||||
s.executeUpdate(insertTypeNames(CREATE_CONTACTS));
|
||||
s.executeUpdate(insertTypeNames(CREATE_GROUPS));
|
||||
s.executeUpdate(insertTypeNames(CREATE_GROUP_METADATA));
|
||||
s.executeUpdate(insertTypeNames(CREATE_GROUP_VISIBILITIES));
|
||||
s.executeUpdate(insertTypeNames(CREATE_MESSAGES));
|
||||
s.executeUpdate(insertTypeNames(CREATE_MESSAGE_METADATA));
|
||||
s.executeUpdate(insertTypeNames(CREATE_MESSAGE_DEPENDENCIES));
|
||||
s.executeUpdate(insertTypeNames(CREATE_OFFERS));
|
||||
s.executeUpdate(insertTypeNames(CREATE_STATUSES));
|
||||
s.executeUpdate(insertTypeNames(CREATE_TRANSPORTS));
|
||||
s.executeUpdate(insertTypeNames(CREATE_OUTGOING_KEYS));
|
||||
s.executeUpdate(insertTypeNames(CREATE_INCOMING_KEYS));
|
||||
s.executeUpdate(dbTypes.replaceTypes(CREATE_SETTINGS));
|
||||
s.executeUpdate(dbTypes.replaceTypes(CREATE_LOCAL_AUTHORS));
|
||||
s.executeUpdate(dbTypes.replaceTypes(CREATE_CONTACTS));
|
||||
s.executeUpdate(dbTypes.replaceTypes(CREATE_GROUPS));
|
||||
s.executeUpdate(dbTypes.replaceTypes(CREATE_GROUP_METADATA));
|
||||
s.executeUpdate(dbTypes.replaceTypes(CREATE_GROUP_VISIBILITIES));
|
||||
s.executeUpdate(dbTypes.replaceTypes(CREATE_MESSAGES));
|
||||
s.executeUpdate(dbTypes.replaceTypes(CREATE_MESSAGE_METADATA));
|
||||
s.executeUpdate(dbTypes.replaceTypes(CREATE_MESSAGE_DEPENDENCIES));
|
||||
s.executeUpdate(dbTypes.replaceTypes(CREATE_OFFERS));
|
||||
s.executeUpdate(dbTypes.replaceTypes(CREATE_STATUSES));
|
||||
s.executeUpdate(dbTypes.replaceTypes(CREATE_TRANSPORTS));
|
||||
s.executeUpdate(dbTypes.replaceTypes(CREATE_OUTGOING_KEYS));
|
||||
s.executeUpdate(dbTypes.replaceTypes(CREATE_INCOMING_KEYS));
|
||||
s.close();
|
||||
} catch (SQLException e) {
|
||||
tryToClose(s);
|
||||
@@ -466,15 +524,6 @@ abstract class JdbcDatabase implements Database<Connection> {
|
||||
}
|
||||
}
|
||||
|
||||
private String insertTypeNames(String s) {
|
||||
s = s.replaceAll("_HASH", hashType);
|
||||
s = s.replaceAll("_SECRET", secretType);
|
||||
s = s.replaceAll("_BINARY", binaryType);
|
||||
s = s.replaceAll("_COUNTER", counterType);
|
||||
s = s.replaceAll("_STRING", stringType);
|
||||
return s;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Connection startTransaction() throws DbException {
|
||||
Connection txn;
|
||||
@@ -489,7 +538,6 @@ abstract class JdbcDatabase implements Database<Connection> {
|
||||
if (txn == null) {
|
||||
// Open a new connection
|
||||
txn = createConnection();
|
||||
if (txn == null) throw new DbException();
|
||||
txn.setAutoCommit(false);
|
||||
connectionsLock.lock();
|
||||
try {
|
||||
@@ -676,7 +724,7 @@ abstract class JdbcDatabase implements Database<Connection> {
|
||||
while (rs.next()) {
|
||||
MessageId id = new MessageId(rs.getBytes(1));
|
||||
long timestamp = rs.getLong(2);
|
||||
State state = State.fromValue(rs.getInt(3));
|
||||
MessageState state = MessageState.fromValue(rs.getInt(3));
|
||||
boolean messageShared = rs.getBoolean(4);
|
||||
int length = rs.getInt(5);
|
||||
boolean deleted = rs.getBoolean(6);
|
||||
@@ -719,7 +767,7 @@ abstract class JdbcDatabase implements Database<Connection> {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addMessage(Connection txn, Message m, State state,
|
||||
public void addMessage(Connection txn, Message m, MessageState state,
|
||||
boolean messageShared, @Nullable ContactId sender)
|
||||
throws DbException {
|
||||
PreparedStatement ps = null;
|
||||
@@ -799,7 +847,7 @@ abstract class JdbcDatabase implements Database<Connection> {
|
||||
}
|
||||
|
||||
private void addStatus(Connection txn, MessageId m, ContactId c, GroupId g,
|
||||
long timestamp, int length, State state, boolean groupShared,
|
||||
long timestamp, int length, MessageState state, boolean groupShared,
|
||||
boolean messageShared, boolean deleted, boolean seen)
|
||||
throws DbException {
|
||||
PreparedStatement ps = null;
|
||||
@@ -832,7 +880,8 @@ abstract class JdbcDatabase implements Database<Connection> {
|
||||
|
||||
@Override
|
||||
public void addMessageDependency(Connection txn, Message dependent,
|
||||
MessageId dependency, State dependentState) throws DbException {
|
||||
MessageId dependency, MessageState dependentState)
|
||||
throws DbException {
|
||||
PreparedStatement ps = null;
|
||||
ResultSet rs = null;
|
||||
try {
|
||||
@@ -843,9 +892,9 @@ abstract class JdbcDatabase implements Database<Connection> {
|
||||
ps.setBytes(1, dependency.getBytes());
|
||||
ps.setBytes(2, dependent.getGroupId().getBytes());
|
||||
rs = ps.executeQuery();
|
||||
State dependencyState = null;
|
||||
MessageState dependencyState = null;
|
||||
if (rs.next()) {
|
||||
dependencyState = State.fromValue(rs.getInt(1));
|
||||
dependencyState = MessageState.fromValue(rs.getInt(1));
|
||||
if (rs.next()) throw new DbStateException();
|
||||
}
|
||||
rs.close();
|
||||
@@ -1201,8 +1250,8 @@ abstract class JdbcDatabase implements Database<Connection> {
|
||||
PreparedStatement ps = null;
|
||||
ResultSet rs = null;
|
||||
try {
|
||||
String sql = "SELECT authorId, formatVersion, name, publicKey,"
|
||||
+ " localAuthorId, verified, active"
|
||||
String sql = "SELECT authorId, formatVersion, name, alias,"
|
||||
+ " publicKey, localAuthorId, verified, active"
|
||||
+ " FROM contacts"
|
||||
+ " WHERE contactId = ?";
|
||||
ps = txn.prepareStatement(sql);
|
||||
@@ -1212,15 +1261,17 @@ abstract class JdbcDatabase implements Database<Connection> {
|
||||
AuthorId authorId = new AuthorId(rs.getBytes(1));
|
||||
int formatVersion = rs.getInt(2);
|
||||
String name = rs.getString(3);
|
||||
byte[] publicKey = rs.getBytes(4);
|
||||
AuthorId localAuthorId = new AuthorId(rs.getBytes(5));
|
||||
boolean verified = rs.getBoolean(6);
|
||||
boolean active = rs.getBoolean(7);
|
||||
String alias = rs.getString(4);
|
||||
byte[] publicKey = rs.getBytes(5);
|
||||
AuthorId localAuthorId = new AuthorId(rs.getBytes(6));
|
||||
boolean verified = rs.getBoolean(7);
|
||||
boolean active = rs.getBoolean(8);
|
||||
rs.close();
|
||||
ps.close();
|
||||
Author author =
|
||||
new Author(authorId, formatVersion, name, publicKey);
|
||||
return new Contact(c, author, localAuthorId, verified, active);
|
||||
return new Contact(c, author, localAuthorId, alias, verified,
|
||||
active);
|
||||
} catch (SQLException e) {
|
||||
tryToClose(rs);
|
||||
tryToClose(ps);
|
||||
@@ -1235,7 +1286,7 @@ abstract class JdbcDatabase implements Database<Connection> {
|
||||
ResultSet rs = null;
|
||||
try {
|
||||
String sql = "SELECT contactId, authorId, formatVersion, name,"
|
||||
+ " publicKey, localAuthorId, verified, active"
|
||||
+ " alias, publicKey, localAuthorId, verified, active"
|
||||
+ " FROM contacts";
|
||||
ps = txn.prepareStatement(sql);
|
||||
rs = ps.executeQuery();
|
||||
@@ -1245,14 +1296,15 @@ abstract class JdbcDatabase implements Database<Connection> {
|
||||
AuthorId authorId = new AuthorId(rs.getBytes(2));
|
||||
int formatVersion = rs.getInt(3);
|
||||
String name = rs.getString(4);
|
||||
byte[] publicKey = rs.getBytes(5);
|
||||
String alias = rs.getString(5);
|
||||
byte[] publicKey = rs.getBytes(6);
|
||||
Author author =
|
||||
new Author(authorId, formatVersion, name, publicKey);
|
||||
AuthorId localAuthorId = new AuthorId(rs.getBytes(6));
|
||||
boolean verified = rs.getBoolean(7);
|
||||
boolean active = rs.getBoolean(8);
|
||||
AuthorId localAuthorId = new AuthorId(rs.getBytes(7));
|
||||
boolean verified = rs.getBoolean(8);
|
||||
boolean active = rs.getBoolean(9);
|
||||
contacts.add(new Contact(contactId, author, localAuthorId,
|
||||
verified, active));
|
||||
alias, verified, active));
|
||||
}
|
||||
rs.close();
|
||||
ps.close();
|
||||
@@ -1293,8 +1345,8 @@ abstract class JdbcDatabase implements Database<Connection> {
|
||||
PreparedStatement ps = null;
|
||||
ResultSet rs = null;
|
||||
try {
|
||||
String sql = "SELECT contactId, formatVersion, name, publicKey,"
|
||||
+ " localAuthorId, verified, active"
|
||||
String sql = "SELECT contactId, formatVersion, name, alias,"
|
||||
+ " publicKey, localAuthorId, verified, active"
|
||||
+ " FROM contacts"
|
||||
+ " WHERE authorId = ?";
|
||||
ps = txn.prepareStatement(sql);
|
||||
@@ -1305,14 +1357,15 @@ abstract class JdbcDatabase implements Database<Connection> {
|
||||
ContactId c = new ContactId(rs.getInt(1));
|
||||
int formatVersion = rs.getInt(2);
|
||||
String name = rs.getString(3);
|
||||
byte[] publicKey = rs.getBytes(4);
|
||||
AuthorId localAuthorId = new AuthorId(rs.getBytes(5));
|
||||
boolean verified = rs.getBoolean(6);
|
||||
boolean active = rs.getBoolean(7);
|
||||
String alias = rs.getString(4);
|
||||
byte[] publicKey = rs.getBytes(5);
|
||||
AuthorId localAuthorId = new AuthorId(rs.getBytes(6));
|
||||
boolean verified = rs.getBoolean(7);
|
||||
boolean active = rs.getBoolean(8);
|
||||
Author author =
|
||||
new Author(remote, formatVersion, name, publicKey);
|
||||
contacts.add(new Contact(c, author, localAuthorId, verified,
|
||||
active));
|
||||
contacts.add(new Contact(c, author, localAuthorId, alias,
|
||||
verified, active));
|
||||
}
|
||||
rs.close();
|
||||
ps.close();
|
||||
@@ -1508,7 +1561,7 @@ abstract class JdbcDatabase implements Database<Connection> {
|
||||
rs.close();
|
||||
ps.close();
|
||||
if (raw == null) throw new MessageDeletedException();
|
||||
if (raw.length < MESSAGE_HEADER_LENGTH) throw new AssertionError();
|
||||
if (raw.length <= MESSAGE_HEADER_LENGTH) throw new AssertionError();
|
||||
byte[] body = new byte[raw.length - MESSAGE_HEADER_LENGTH];
|
||||
System.arraycopy(raw, MESSAGE_HEADER_LENGTH, body, 0, body.length);
|
||||
return new Message(m, g, timestamp, body);
|
||||
@@ -1761,7 +1814,7 @@ abstract class JdbcDatabase implements Database<Connection> {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<MessageId, State> getMessageDependencies(Connection txn,
|
||||
public Map<MessageId, MessageState> getMessageDependencies(Connection txn,
|
||||
MessageId m) throws DbException {
|
||||
PreparedStatement ps = null;
|
||||
ResultSet rs = null;
|
||||
@@ -1772,10 +1825,10 @@ abstract class JdbcDatabase implements Database<Connection> {
|
||||
ps = txn.prepareStatement(sql);
|
||||
ps.setBytes(1, m.getBytes());
|
||||
rs = ps.executeQuery();
|
||||
Map<MessageId, State> dependencies = new HashMap<>();
|
||||
Map<MessageId, MessageState> dependencies = new HashMap<>();
|
||||
while (rs.next()) {
|
||||
MessageId dependency = new MessageId(rs.getBytes(1));
|
||||
State state = State.fromValue(rs.getInt(2));
|
||||
MessageState state = MessageState.fromValue(rs.getInt(2));
|
||||
if (rs.wasNull())
|
||||
state = UNKNOWN; // Missing or in a different group
|
||||
dependencies.put(dependency, state);
|
||||
@@ -1791,7 +1844,7 @@ abstract class JdbcDatabase implements Database<Connection> {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<MessageId, State> getMessageDependents(Connection txn,
|
||||
public Map<MessageId, MessageState> getMessageDependents(Connection txn,
|
||||
MessageId m) throws DbException {
|
||||
PreparedStatement ps = null;
|
||||
ResultSet rs = null;
|
||||
@@ -1805,10 +1858,10 @@ abstract class JdbcDatabase implements Database<Connection> {
|
||||
ps = txn.prepareStatement(sql);
|
||||
ps.setBytes(1, m.getBytes());
|
||||
rs = ps.executeQuery();
|
||||
Map<MessageId, State> dependents = new HashMap<>();
|
||||
Map<MessageId, MessageState> dependents = new HashMap<>();
|
||||
while (rs.next()) {
|
||||
MessageId dependent = new MessageId(rs.getBytes(1));
|
||||
State state = State.fromValue(rs.getInt(2));
|
||||
MessageState state = MessageState.fromValue(rs.getInt(2));
|
||||
dependents.put(dependent, state);
|
||||
}
|
||||
rs.close();
|
||||
@@ -1822,7 +1875,7 @@ abstract class JdbcDatabase implements Database<Connection> {
|
||||
}
|
||||
|
||||
@Override
|
||||
public State getMessageState(Connection txn, MessageId m)
|
||||
public MessageState getMessageState(Connection txn, MessageId m)
|
||||
throws DbException {
|
||||
PreparedStatement ps = null;
|
||||
ResultSet rs = null;
|
||||
@@ -1832,7 +1885,7 @@ abstract class JdbcDatabase implements Database<Connection> {
|
||||
ps.setBytes(1, m.getBytes());
|
||||
rs = ps.executeQuery();
|
||||
if (!rs.next()) throw new DbStateException();
|
||||
State state = State.fromValue(rs.getInt(1));
|
||||
MessageState state = MessageState.fromValue(rs.getInt(1));
|
||||
if (rs.next()) throw new DbStateException();
|
||||
rs.close();
|
||||
ps.close();
|
||||
@@ -1980,7 +2033,7 @@ abstract class JdbcDatabase implements Database<Connection> {
|
||||
}
|
||||
|
||||
private Collection<MessageId> getMessagesInState(Connection txn,
|
||||
State state) throws DbException {
|
||||
MessageState state) throws DbException {
|
||||
PreparedStatement ps = null;
|
||||
ResultSet rs = null;
|
||||
try {
|
||||
@@ -2307,7 +2360,7 @@ abstract class JdbcDatabase implements Database<Connection> {
|
||||
rs = ps.executeQuery();
|
||||
if (!rs.next()) throw new DbStateException();
|
||||
GroupId g = new GroupId(rs.getBytes(1));
|
||||
State state = State.fromValue(rs.getInt(2));
|
||||
MessageState state = MessageState.fromValue(rs.getInt(2));
|
||||
rs.close();
|
||||
ps.close();
|
||||
// Insert any keys that don't already exist
|
||||
@@ -2737,6 +2790,25 @@ abstract class JdbcDatabase implements Database<Connection> {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setContactAlias(Connection txn, ContactId c,
|
||||
@Nullable String alias) throws DbException {
|
||||
PreparedStatement ps = null;
|
||||
try {
|
||||
String sql = "UPDATE contacts SET alias = ? WHERE contactId = ?";
|
||||
ps = txn.prepareStatement(sql);
|
||||
if (alias == null) ps.setNull(1, VARCHAR);
|
||||
else ps.setString(1, alias);
|
||||
ps.setInt(2, c.getInt());
|
||||
int affected = ps.executeUpdate();
|
||||
if (affected < 0 || affected > 1) throw new DbStateException();
|
||||
ps.close();
|
||||
} catch (SQLException e) {
|
||||
tryToClose(ps);
|
||||
throw new DbException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setGroupVisibility(Connection txn, ContactId c, GroupId g,
|
||||
boolean shared) throws DbException {
|
||||
@@ -2794,7 +2866,7 @@ abstract class JdbcDatabase implements Database<Connection> {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setMessageState(Connection txn, MessageId m, State state)
|
||||
public void setMessageState(Connection txn, MessageId m, MessageState state)
|
||||
throws DbException {
|
||||
PreparedStatement ps = null;
|
||||
try {
|
||||
|
||||
@@ -0,0 +1,56 @@
|
||||
package org.briarproject.bramble.db;
|
||||
|
||||
import org.briarproject.bramble.api.db.DbException;
|
||||
|
||||
import java.sql.Connection;
|
||||
import java.sql.SQLException;
|
||||
import java.sql.Statement;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import static java.util.logging.Level.WARNING;
|
||||
import static java.util.logging.Logger.getLogger;
|
||||
import static org.briarproject.bramble.util.LogUtils.logException;
|
||||
|
||||
class Migration40_41 implements Migration<Connection> {
|
||||
|
||||
private static final Logger LOG = getLogger(Migration40_41.class.getName());
|
||||
|
||||
private final DatabaseTypes dbTypes;
|
||||
|
||||
public Migration40_41(DatabaseTypes databaseTypes) {
|
||||
this.dbTypes = databaseTypes;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getStartVersion() {
|
||||
return 40;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getEndVersion() {
|
||||
return 41;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void migrate(Connection txn) throws DbException {
|
||||
Statement s = null;
|
||||
try {
|
||||
s = txn.createStatement();
|
||||
s.execute("ALTER TABLE contacts"
|
||||
+ dbTypes.replaceTypes(" ADD alias _STRING"));
|
||||
} catch (SQLException e) {
|
||||
tryToClose(s);
|
||||
throw new DbException(e);
|
||||
}
|
||||
}
|
||||
|
||||
private void tryToClose(@Nullable Statement s) {
|
||||
try {
|
||||
if (s != null) s.close();
|
||||
} catch (SQLException e) {
|
||||
logException(LOG, WARNING, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,29 +1,21 @@
|
||||
package org.briarproject.bramble.identity;
|
||||
|
||||
import org.briarproject.bramble.api.contact.Contact;
|
||||
import org.briarproject.bramble.api.crypto.CryptoComponent;
|
||||
import org.briarproject.bramble.api.crypto.KeyPair;
|
||||
import org.briarproject.bramble.api.db.DatabaseComponent;
|
||||
import org.briarproject.bramble.api.db.DbException;
|
||||
import org.briarproject.bramble.api.db.Transaction;
|
||||
import org.briarproject.bramble.api.identity.Author.Status;
|
||||
import org.briarproject.bramble.api.identity.AuthorFactory;
|
||||
import org.briarproject.bramble.api.identity.AuthorId;
|
||||
import org.briarproject.bramble.api.identity.IdentityManager;
|
||||
import org.briarproject.bramble.api.identity.LocalAuthor;
|
||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import javax.annotation.concurrent.ThreadSafe;
|
||||
import javax.inject.Inject;
|
||||
|
||||
import static org.briarproject.bramble.api.identity.Author.Status.OURSELVES;
|
||||
import static org.briarproject.bramble.api.identity.Author.Status.UNKNOWN;
|
||||
import static org.briarproject.bramble.api.identity.Author.Status.UNVERIFIED;
|
||||
import static org.briarproject.bramble.api.identity.Author.Status.VERIFIED;
|
||||
import static org.briarproject.bramble.util.LogUtils.logDuration;
|
||||
import static org.briarproject.bramble.util.LogUtils.now;
|
||||
|
||||
@@ -75,27 +67,16 @@ class IdentityManagerImpl implements IdentityManager {
|
||||
LOG.info("No local author to store");
|
||||
return;
|
||||
}
|
||||
Transaction txn = db.startTransaction(false);
|
||||
try {
|
||||
db.addLocalAuthor(txn, cached);
|
||||
db.commitTransaction(txn);
|
||||
LOG.info("Local author stored");
|
||||
} finally {
|
||||
db.endTransaction(txn);
|
||||
}
|
||||
db.transaction(false, txn -> db.addLocalAuthor(txn, cached));
|
||||
LOG.info("Local author stored");
|
||||
}
|
||||
|
||||
@Override
|
||||
public LocalAuthor getLocalAuthor() throws DbException {
|
||||
if (cachedAuthor == null) {
|
||||
Transaction txn = db.startTransaction(true);
|
||||
try {
|
||||
cachedAuthor = loadLocalAuthor(txn);
|
||||
LOG.info("Local author loaded");
|
||||
db.commitTransaction(txn);
|
||||
} finally {
|
||||
db.endTransaction(txn);
|
||||
}
|
||||
cachedAuthor =
|
||||
db.transactionWithResult(true, this::loadLocalAuthor);
|
||||
LOG.info("Local author loaded");
|
||||
}
|
||||
LocalAuthor cached = cachedAuthor;
|
||||
if (cached == null) throw new AssertionError();
|
||||
@@ -118,26 +99,4 @@ class IdentityManagerImpl implements IdentityManager {
|
||||
return db.getLocalAuthors(txn).iterator().next();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Status getAuthorStatus(AuthorId authorId) throws DbException {
|
||||
Transaction txn = db.startTransaction(true);
|
||||
try {
|
||||
return getAuthorStatus(txn, authorId);
|
||||
} finally {
|
||||
db.endTransaction(txn);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Status getAuthorStatus(Transaction txn, AuthorId authorId)
|
||||
throws DbException {
|
||||
if (getLocalAuthor(txn).getId().equals(authorId)) return OURSELVES;
|
||||
Collection<Contact> contacts = db.getContactsByAuthorId(txn, authorId);
|
||||
if (contacts.isEmpty()) return UNKNOWN;
|
||||
for (Contact c : contacts) {
|
||||
if (c.isVerified()) return VERIFIED;
|
||||
}
|
||||
return UNVERIFIED;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -6,7 +6,6 @@ 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.MigrationListener;
|
||||
import org.briarproject.bramble.api.db.Transaction;
|
||||
import org.briarproject.bramble.api.event.EventBus;
|
||||
import org.briarproject.bramble.api.identity.IdentityManager;
|
||||
import org.briarproject.bramble.api.lifecycle.LifecycleManager;
|
||||
@@ -29,6 +28,7 @@ import javax.inject.Inject;
|
||||
import static java.util.logging.Level.FINE;
|
||||
import static java.util.logging.Level.INFO;
|
||||
import static java.util.logging.Level.WARNING;
|
||||
import static org.briarproject.bramble.api.lifecycle.LifecycleManager.LifecycleState.COMPACTING_DATABASE;
|
||||
import static org.briarproject.bramble.api.lifecycle.LifecycleManager.LifecycleState.MIGRATING_DATABASE;
|
||||
import static org.briarproject.bramble.api.lifecycle.LifecycleManager.LifecycleState.RUNNING;
|
||||
import static org.briarproject.bramble.api.lifecycle.LifecycleManager.LifecycleState.STARTING;
|
||||
@@ -114,20 +114,16 @@ class LifecycleManagerImpl implements LifecycleManager, MigrationListener {
|
||||
dbLatch.countDown();
|
||||
eventBus.broadcast(new LifecycleEvent(STARTING_SERVICES));
|
||||
|
||||
Transaction txn = db.startTransaction(false);
|
||||
try {
|
||||
db.transaction(false, txn -> {
|
||||
for (Client c : clients) {
|
||||
start = now();
|
||||
long start1 = now();
|
||||
c.createLocalState(txn);
|
||||
if (LOG.isLoggable(FINE)) {
|
||||
logDuration(LOG, "Starting client "
|
||||
+ c.getClass().getSimpleName(), start);
|
||||
+ c.getClass().getSimpleName(), start1);
|
||||
}
|
||||
}
|
||||
db.commitTransaction(txn);
|
||||
} finally {
|
||||
db.endTransaction(txn);
|
||||
}
|
||||
});
|
||||
for (Service s : services) {
|
||||
start = now();
|
||||
s.startService();
|
||||
@@ -159,11 +155,17 @@ class LifecycleManagerImpl implements LifecycleManager, MigrationListener {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onMigrationRun() {
|
||||
public void onDatabaseMigration() {
|
||||
state = MIGRATING_DATABASE;
|
||||
eventBus.broadcast(new LifecycleEvent(MIGRATING_DATABASE));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDatabaseCompaction() {
|
||||
state = COMPACTING_DATABASE;
|
||||
eventBus.broadcast(new LifecycleEvent(COMPACTING_DATABASE));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void stopServices() {
|
||||
try {
|
||||
|
||||
@@ -23,7 +23,6 @@ import org.briarproject.bramble.api.plugin.event.EnableBluetoothEvent;
|
||||
import org.briarproject.bramble.api.properties.TransportProperties;
|
||||
import org.briarproject.bramble.api.settings.Settings;
|
||||
import org.briarproject.bramble.api.settings.event.SettingsUpdatedEvent;
|
||||
import org.briarproject.bramble.util.StringUtils;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.security.SecureRandom;
|
||||
@@ -46,6 +45,9 @@ import static org.briarproject.bramble.api.plugin.BluetoothConstants.PROP_UUID;
|
||||
import static org.briarproject.bramble.api.plugin.BluetoothConstants.UUID_BYTES;
|
||||
import static org.briarproject.bramble.util.LogUtils.logException;
|
||||
import static org.briarproject.bramble.util.PrivacyUtils.scrubMacAddress;
|
||||
import static org.briarproject.bramble.util.StringUtils.isNullOrEmpty;
|
||||
import static org.briarproject.bramble.util.StringUtils.macToBytes;
|
||||
import static org.briarproject.bramble.util.StringUtils.macToString;
|
||||
|
||||
@MethodsNotNullByDefault
|
||||
@ParametersNotNullByDefault
|
||||
@@ -96,6 +98,9 @@ abstract class BluetoothPlugin<SS> implements DuplexPlugin, EventListener {
|
||||
abstract DuplexTransportConnection connectTo(String address, String uuid)
|
||||
throws IOException;
|
||||
|
||||
@Nullable
|
||||
abstract DuplexTransportConnection discoverAndConnect(String uuid);
|
||||
|
||||
BluetoothPlugin(BluetoothConnectionLimiter connectionLimiter,
|
||||
Executor ioExecutor, SecureRandom secureRandom,
|
||||
Backoff backoff, DuplexPluginCallback callback, int maxLatency) {
|
||||
@@ -193,7 +198,7 @@ abstract class BluetoothPlugin<SS> implements DuplexPlugin, EventListener {
|
||||
address = getBluetoothAddress();
|
||||
if (LOG.isLoggable(INFO))
|
||||
LOG.info("Local address " + scrubMacAddress(address));
|
||||
if (!StringUtils.isNullOrEmpty(address)) {
|
||||
if (!isNullOrEmpty(address)) {
|
||||
p.put(PROP_ADDRESS, address);
|
||||
changed = true;
|
||||
}
|
||||
@@ -256,9 +261,9 @@ abstract class BluetoothPlugin<SS> implements DuplexPlugin, EventListener {
|
||||
// Try to connect to known devices in parallel
|
||||
for (Entry<ContactId, TransportProperties> e : contacts.entrySet()) {
|
||||
String address = e.getValue().get(PROP_ADDRESS);
|
||||
if (StringUtils.isNullOrEmpty(address)) continue;
|
||||
if (isNullOrEmpty(address)) continue;
|
||||
String uuid = e.getValue().get(PROP_UUID);
|
||||
if (StringUtils.isNullOrEmpty(uuid)) continue;
|
||||
if (isNullOrEmpty(uuid)) continue;
|
||||
ContactId c = e.getKey();
|
||||
ioExecutor.execute(() -> {
|
||||
if (!isRunning() || !shouldAllowContactConnections()) return;
|
||||
@@ -309,9 +314,9 @@ abstract class BluetoothPlugin<SS> implements DuplexPlugin, EventListener {
|
||||
if (!isRunning() || !shouldAllowContactConnections()) return null;
|
||||
if (!connectionLimiter.canOpenContactConnection()) return null;
|
||||
String address = p.get(PROP_ADDRESS);
|
||||
if (StringUtils.isNullOrEmpty(address)) return null;
|
||||
if (isNullOrEmpty(address)) return null;
|
||||
String uuid = p.get(PROP_UUID);
|
||||
if (StringUtils.isNullOrEmpty(uuid)) return null;
|
||||
if (isNullOrEmpty(uuid)) return null;
|
||||
DuplexTransportConnection conn = connect(address, uuid);
|
||||
if (conn == null) return null;
|
||||
// TODO: Why don't we reset the backoff here?
|
||||
@@ -326,9 +331,6 @@ abstract class BluetoothPlugin<SS> implements DuplexPlugin, EventListener {
|
||||
@Override
|
||||
public KeyAgreementListener createKeyAgreementListener(byte[] commitment) {
|
||||
if (!isRunning()) return null;
|
||||
// There's no point listening if we can't discover our own address
|
||||
String address = getBluetoothAddress();
|
||||
if (address == null) return null;
|
||||
// No truncation necessary because COMMIT_LENGTH = 16
|
||||
String uuid = UUID.nameUUIDFromBytes(commitment).toString();
|
||||
if (LOG.isLoggable(INFO)) LOG.info("Key agreement UUID " + uuid);
|
||||
@@ -346,7 +348,8 @@ abstract class BluetoothPlugin<SS> implements DuplexPlugin, EventListener {
|
||||
}
|
||||
BdfList descriptor = new BdfList();
|
||||
descriptor.add(TRANSPORT_ID_BLUETOOTH);
|
||||
descriptor.add(StringUtils.macToBytes(address));
|
||||
String address = getBluetoothAddress();
|
||||
if (address != null) descriptor.add(macToBytes(address));
|
||||
return new BluetoothKeyAgreementListener(descriptor, ss);
|
||||
}
|
||||
|
||||
@@ -354,18 +357,25 @@ abstract class BluetoothPlugin<SS> implements DuplexPlugin, EventListener {
|
||||
public DuplexTransportConnection createKeyAgreementConnection(
|
||||
byte[] commitment, BdfList descriptor) {
|
||||
if (!isRunning()) return null;
|
||||
String address;
|
||||
try {
|
||||
address = parseAddress(descriptor);
|
||||
} catch (FormatException e) {
|
||||
LOG.info("Invalid address in key agreement descriptor");
|
||||
return null;
|
||||
}
|
||||
// No truncation necessary because COMMIT_LENGTH = 16
|
||||
String uuid = UUID.nameUUIDFromBytes(commitment).toString();
|
||||
if (LOG.isLoggable(INFO))
|
||||
LOG.info("Connecting to key agreement UUID " + uuid);
|
||||
DuplexTransportConnection conn = connect(address, uuid);
|
||||
DuplexTransportConnection conn;
|
||||
if (descriptor.size() == 1) {
|
||||
if (LOG.isLoggable(INFO))
|
||||
LOG.info("Discovering address for key agreement UUID " + uuid);
|
||||
conn = discoverAndConnect(uuid);
|
||||
} else {
|
||||
String address;
|
||||
try {
|
||||
address = parseAddress(descriptor);
|
||||
} catch (FormatException e) {
|
||||
LOG.info("Invalid address in key agreement descriptor");
|
||||
return null;
|
||||
}
|
||||
if (LOG.isLoggable(INFO))
|
||||
LOG.info("Connecting to key agreement UUID " + uuid);
|
||||
conn = connect(address, uuid);
|
||||
}
|
||||
if (conn != null) connectionLimiter.keyAgreementConnectionOpened(conn);
|
||||
return conn;
|
||||
}
|
||||
@@ -373,7 +383,7 @@ abstract class BluetoothPlugin<SS> implements DuplexPlugin, EventListener {
|
||||
private String parseAddress(BdfList descriptor) throws FormatException {
|
||||
byte[] mac = descriptor.getRaw(1);
|
||||
if (mac.length != 6) throw new FormatException();
|
||||
return StringUtils.macToString(mac);
|
||||
return macToString(mac);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -4,6 +4,8 @@ import net.freehaven.tor.control.EventHandler;
|
||||
import net.freehaven.tor.control.TorControlConnection;
|
||||
|
||||
import org.briarproject.bramble.PoliteExecutor;
|
||||
import org.briarproject.bramble.api.battery.BatteryManager;
|
||||
import org.briarproject.bramble.api.battery.event.BatteryEvent;
|
||||
import org.briarproject.bramble.api.contact.ContactId;
|
||||
import org.briarproject.bramble.api.data.BdfList;
|
||||
import org.briarproject.bramble.api.event.Event;
|
||||
@@ -28,7 +30,6 @@ import org.briarproject.bramble.api.system.Clock;
|
||||
import org.briarproject.bramble.api.system.LocationUtils;
|
||||
import org.briarproject.bramble.api.system.ResourceProvider;
|
||||
import org.briarproject.bramble.util.IoUtils;
|
||||
import org.briarproject.bramble.util.StringUtils;
|
||||
|
||||
import java.io.Closeable;
|
||||
import java.io.EOFException;
|
||||
@@ -70,9 +71,11 @@ import static org.briarproject.bramble.api.plugin.TorConstants.PREF_TOR_NETWORK_
|
||||
import static org.briarproject.bramble.api.plugin.TorConstants.PREF_TOR_NETWORK_NEVER;
|
||||
import static org.briarproject.bramble.api.plugin.TorConstants.PREF_TOR_NETWORK_WITH_BRIDGES;
|
||||
import static org.briarproject.bramble.api.plugin.TorConstants.PREF_TOR_PORT;
|
||||
import static org.briarproject.bramble.api.plugin.TorConstants.PROP_ONION;
|
||||
import static org.briarproject.bramble.api.plugin.TorConstants.PROP_ONION_V2;
|
||||
import static org.briarproject.bramble.api.plugin.TorConstants.PROP_ONION_V3;
|
||||
import static org.briarproject.bramble.util.LogUtils.logException;
|
||||
import static org.briarproject.bramble.util.PrivacyUtils.scrubOnion;
|
||||
import static org.briarproject.bramble.util.StringUtils.isNullOrEmpty;
|
||||
|
||||
@MethodsNotNullByDefault
|
||||
@ParametersNotNullByDefault
|
||||
@@ -87,20 +90,22 @@ abstract class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
|
||||
private static final String OWNER = "__OwningControllerProcess";
|
||||
private static final int COOKIE_TIMEOUT_MS = 3000;
|
||||
private static final int COOKIE_POLLING_INTERVAL_MS = 200;
|
||||
private static final Pattern ONION = Pattern.compile("[a-z2-7]{16}");
|
||||
private static final Pattern ONION_V2 = Pattern.compile("[a-z2-7]{16}");
|
||||
private static final Pattern ONION_V3 = Pattern.compile("[a-z2-7]{56}");
|
||||
|
||||
private final Executor ioExecutor, connectionStatusExecutor;
|
||||
private final NetworkManager networkManager;
|
||||
private final LocationUtils locationUtils;
|
||||
private final SocketFactory torSocketFactory;
|
||||
private final Clock clock;
|
||||
private final BatteryManager batteryManager;
|
||||
private final Backoff backoff;
|
||||
private final DuplexPluginCallback callback;
|
||||
private final String architecture;
|
||||
private final CircumventionProvider circumventionProvider;
|
||||
private final ResourceProvider resourceProvider;
|
||||
private final int maxLatency, maxIdleTime, socketTimeout;
|
||||
private final File torDirectory, torFile, geoIpFile, configFile;
|
||||
private final File torDirectory, torFile, geoIpFile, obfs4File, configFile;
|
||||
private final File doneFile, cookieFile;
|
||||
private final ConnectionStatus connectionStatus;
|
||||
private final AtomicBoolean used = new AtomicBoolean(false);
|
||||
@@ -119,7 +124,8 @@ abstract class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
|
||||
TorPlugin(Executor ioExecutor, NetworkManager networkManager,
|
||||
LocationUtils locationUtils, SocketFactory torSocketFactory,
|
||||
Clock clock, ResourceProvider resourceProvider,
|
||||
CircumventionProvider circumventionProvider, Backoff backoff,
|
||||
CircumventionProvider circumventionProvider,
|
||||
BatteryManager batteryManager, Backoff backoff,
|
||||
DuplexPluginCallback callback, String architecture, int maxLatency,
|
||||
int maxIdleTime, File torDirectory) {
|
||||
this.ioExecutor = ioExecutor;
|
||||
@@ -129,6 +135,7 @@ abstract class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
|
||||
this.clock = clock;
|
||||
this.resourceProvider = resourceProvider;
|
||||
this.circumventionProvider = circumventionProvider;
|
||||
this.batteryManager = batteryManager;
|
||||
this.backoff = backoff;
|
||||
this.callback = callback;
|
||||
this.architecture = architecture;
|
||||
@@ -140,6 +147,7 @@ abstract class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
|
||||
this.torDirectory = torDirectory;
|
||||
torFile = new File(torDirectory, "tor");
|
||||
geoIpFile = new File(torDirectory, "geoip");
|
||||
obfs4File = new File(torDirectory, "obfs4proxy");
|
||||
configFile = new File(torDirectory, "torrc");
|
||||
doneFile = new File(torDirectory, "done");
|
||||
cookieFile = new File(torDirectory, ".tor/control_auth_cookie");
|
||||
@@ -258,7 +266,8 @@ abstract class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
|
||||
throw new PluginException(e);
|
||||
}
|
||||
// Check whether we're online
|
||||
updateConnectionStatus(networkManager.getNetworkStatus());
|
||||
updateConnectionStatus(networkManager.getNetworkStatus(),
|
||||
batteryManager.isCharging());
|
||||
// Bind a server socket to receive incoming hidden service connections
|
||||
bind();
|
||||
}
|
||||
@@ -282,6 +291,12 @@ abstract class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
|
||||
in = getGeoIpInputStream();
|
||||
out = new FileOutputStream(geoIpFile);
|
||||
IoUtils.copyAndClose(in, out);
|
||||
// Unzip the Obfs4 proxy to the filesystem
|
||||
in = getObfs4InputStream();
|
||||
out = new FileOutputStream(obfs4File);
|
||||
IoUtils.copyAndClose(in, out);
|
||||
// Make the Obfs4 proxy executable
|
||||
if (!obfs4File.setExecutable(true, true)) throw new IOException();
|
||||
// Copy the config file to the filesystem
|
||||
in = getConfigInputStream();
|
||||
out = new FileOutputStream(configFile);
|
||||
@@ -312,6 +327,16 @@ abstract class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
|
||||
return zin;
|
||||
}
|
||||
|
||||
private InputStream getObfs4InputStream() throws IOException {
|
||||
if (LOG.isLoggable(INFO))
|
||||
LOG.info("Installing obfs4proxy binary for " + architecture);
|
||||
InputStream in = resourceProvider
|
||||
.getResourceInputStream("obfs4proxy_" + architecture, ".zip");
|
||||
ZipInputStream zin = new ZipInputStream(in);
|
||||
if (zin.getNextEntry() == null) throw new IOException();
|
||||
return zin;
|
||||
}
|
||||
|
||||
private InputStream getConfigInputStream() {
|
||||
return getClass().getClassLoader().getResourceAsStream("torrc");
|
||||
}
|
||||
@@ -362,7 +387,7 @@ abstract class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
|
||||
// If there's already a port number stored in config, reuse it
|
||||
String portString = settings.get(PREF_TOR_PORT);
|
||||
int port;
|
||||
if (StringUtils.isNullOrEmpty(portString)) port = 0;
|
||||
if (isNullOrEmpty(portString)) port = 0;
|
||||
else port = Integer.parseInt(portString);
|
||||
// Bind a server socket to receive connections from Tor
|
||||
ServerSocket ss = null;
|
||||
@@ -427,11 +452,11 @@ abstract class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
|
||||
return;
|
||||
}
|
||||
// Publish the hidden service's onion hostname in transport properties
|
||||
String hostname = response.get(HS_ADDRESS);
|
||||
String onion2 = response.get(HS_ADDRESS);
|
||||
if (LOG.isLoggable(INFO))
|
||||
LOG.info("Hidden service " + scrubOnion(hostname));
|
||||
LOG.info("Hidden service " + scrubOnion(onion2));
|
||||
TransportProperties p = new TransportProperties();
|
||||
p.put(PROP_ONION, hostname);
|
||||
p.put(PROP_ONION_V2, onion2);
|
||||
callback.mergeLocalProperties(p);
|
||||
if (privKey == null) {
|
||||
// Save the hidden service's private key for next time
|
||||
@@ -470,6 +495,8 @@ abstract class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
|
||||
if (enable) {
|
||||
Collection<String> conf = new ArrayList<>();
|
||||
conf.add("UseBridges 1");
|
||||
conf.add("ClientTransportPlugin obfs4 exec " +
|
||||
obfs4File.getAbsolutePath());
|
||||
conf.addAll(circumventionProvider.getBridges());
|
||||
controlConnection.setConf(conf);
|
||||
} else {
|
||||
@@ -530,26 +557,41 @@ abstract class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
|
||||
@Override
|
||||
public DuplexTransportConnection createConnection(TransportProperties p) {
|
||||
if (!isRunning()) return null;
|
||||
String onion = p.get(PROP_ONION);
|
||||
if (StringUtils.isNullOrEmpty(onion)) return null;
|
||||
if (!ONION.matcher(onion).matches()) {
|
||||
// not scrubbing this address, so we are able to find the problem
|
||||
if (LOG.isLoggable(INFO)) LOG.info("Invalid hostname: " + onion);
|
||||
return null;
|
||||
String bestOnion = null;
|
||||
String onion2 = p.get(PROP_ONION_V2);
|
||||
String onion3 = p.get(PROP_ONION_V3);
|
||||
if (!isNullOrEmpty(onion2)) {
|
||||
if (ONION_V2.matcher(onion2).matches()) {
|
||||
bestOnion = onion2;
|
||||
} else {
|
||||
// Don't scrub the address so we can find the problem
|
||||
if (LOG.isLoggable(INFO))
|
||||
LOG.info("Invalid v2 hostname: " + onion2);
|
||||
}
|
||||
}
|
||||
if (!isNullOrEmpty(onion3)) {
|
||||
if (ONION_V3.matcher(onion3).matches()) {
|
||||
bestOnion = onion3;
|
||||
} else {
|
||||
// Don't scrub the address so we can find the problem
|
||||
if (LOG.isLoggable(INFO))
|
||||
LOG.info("Invalid v3 hostname: " + onion3);
|
||||
}
|
||||
}
|
||||
if (bestOnion == null) return null;
|
||||
Socket s = null;
|
||||
try {
|
||||
if (LOG.isLoggable(INFO))
|
||||
LOG.info("Connecting to " + scrubOnion(onion));
|
||||
s = torSocketFactory.createSocket(onion + ".onion", 80);
|
||||
LOG.info("Connecting to " + scrubOnion(bestOnion));
|
||||
s = torSocketFactory.createSocket(bestOnion + ".onion", 80);
|
||||
s.setSoTimeout(socketTimeout);
|
||||
if (LOG.isLoggable(INFO))
|
||||
LOG.info("Connected to " + scrubOnion(onion));
|
||||
LOG.info("Connected to " + scrubOnion(bestOnion));
|
||||
return new TorTransportConnection(this, s);
|
||||
} catch (IOException e) {
|
||||
if (LOG.isLoggable(INFO)) {
|
||||
LOG.info("Could not connect to " + scrubOnion(onion) + ": " +
|
||||
e.toString());
|
||||
LOG.info("Could not connect to " + scrubOnion(bestOnion)
|
||||
+ ": " + e.toString());
|
||||
}
|
||||
tryToClose(s);
|
||||
return null;
|
||||
@@ -592,7 +634,8 @@ abstract class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
|
||||
LOG.info("OR connection " + status + " " + orName);
|
||||
if (status.equals("CLOSED") || status.equals("FAILED")) {
|
||||
// Check whether we've lost connectivity
|
||||
updateConnectionStatus(networkManager.getNetworkStatus());
|
||||
updateConnectionStatus(networkManager.getNetworkStatus(),
|
||||
batteryManager.isCharging());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -627,14 +670,33 @@ abstract class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
|
||||
if (s.getNamespace().equals(ID.getString())) {
|
||||
LOG.info("Tor settings updated");
|
||||
settings = s.getSettings();
|
||||
updateConnectionStatus(networkManager.getNetworkStatus());
|
||||
// Works around a bug introduced in Tor 0.3.4.8. Could be
|
||||
// replaced with callback.transportDisabled() when fixed.
|
||||
disableNetwork();
|
||||
updateConnectionStatus(networkManager.getNetworkStatus(),
|
||||
batteryManager.isCharging());
|
||||
}
|
||||
} else if (e instanceof NetworkStatusEvent) {
|
||||
updateConnectionStatus(((NetworkStatusEvent) e).getStatus());
|
||||
updateConnectionStatus(((NetworkStatusEvent) e).getStatus(),
|
||||
batteryManager.isCharging());
|
||||
} else if (e instanceof BatteryEvent) {
|
||||
updateConnectionStatus(networkManager.getNetworkStatus(),
|
||||
((BatteryEvent) e).isCharging());
|
||||
}
|
||||
}
|
||||
|
||||
private void updateConnectionStatus(NetworkStatus status) {
|
||||
private void disableNetwork() {
|
||||
connectionStatusExecutor.execute(() -> {
|
||||
try {
|
||||
enableNetwork(false);
|
||||
} catch (IOException ex) {
|
||||
logException(LOG, WARNING, ex);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void updateConnectionStatus(NetworkStatus status,
|
||||
boolean charging) {
|
||||
connectionStatusExecutor.execute(() -> {
|
||||
if (!running) return;
|
||||
boolean online = status.isConnected();
|
||||
@@ -652,6 +714,7 @@ abstract class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
|
||||
LOG.info("Online: " + online + ", wifi: " + wifi);
|
||||
if ("".equals(country)) LOG.info("Country code unknown");
|
||||
else LOG.info("Country code: " + country);
|
||||
LOG.info("Charging: " + charging);
|
||||
}
|
||||
|
||||
try {
|
||||
@@ -675,12 +738,24 @@ abstract class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
|
||||
enableBridges(false);
|
||||
enableNetwork(true);
|
||||
}
|
||||
if (online && wifi && charging) {
|
||||
LOG.info("Enabling connection padding");
|
||||
enableConnectionPadding(true);
|
||||
} else {
|
||||
LOG.info("Disabling connection padding");
|
||||
enableConnectionPadding(false);
|
||||
}
|
||||
} catch (IOException e) {
|
||||
logException(LOG, WARNING, e);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void enableConnectionPadding(boolean enable) throws IOException {
|
||||
if (!running) return;
|
||||
controlConnection.setConf("ConnectionPadding", enable ? "1" : "0");
|
||||
}
|
||||
|
||||
// TODO remove when sufficient time has passed. Added 2018-08-15
|
||||
private void migrateSettings() {
|
||||
Settings sOld = callback.getSettings();
|
||||
|
||||
@@ -5,7 +5,7 @@ import org.briarproject.bramble.api.contact.ContactManager;
|
||||
import org.briarproject.bramble.api.data.MetadataEncoder;
|
||||
import org.briarproject.bramble.api.lifecycle.LifecycleManager;
|
||||
import org.briarproject.bramble.api.properties.TransportPropertyManager;
|
||||
import org.briarproject.bramble.api.sync.ValidationManager;
|
||||
import org.briarproject.bramble.api.sync.validation.ValidationManager;
|
||||
import org.briarproject.bramble.api.system.Clock;
|
||||
import org.briarproject.bramble.api.versioning.ClientVersioningManager;
|
||||
|
||||
|
||||
@@ -24,7 +24,7 @@ import org.briarproject.bramble.api.sync.GroupId;
|
||||
import org.briarproject.bramble.api.sync.InvalidMessageException;
|
||||
import org.briarproject.bramble.api.sync.Message;
|
||||
import org.briarproject.bramble.api.sync.MessageId;
|
||||
import org.briarproject.bramble.api.sync.ValidationManager.IncomingMessageHook;
|
||||
import org.briarproject.bramble.api.sync.validation.IncomingMessageHook;
|
||||
import org.briarproject.bramble.api.system.Clock;
|
||||
import org.briarproject.bramble.api.versioning.ClientVersioningManager;
|
||||
import org.briarproject.bramble.api.versioning.ClientVersioningManager.ClientVersioningHook;
|
||||
@@ -142,15 +142,7 @@ class TransportPropertyManagerImpl implements TransportPropertyManager,
|
||||
@Override
|
||||
public Map<TransportId, TransportProperties> getLocalProperties()
|
||||
throws DbException {
|
||||
Map<TransportId, TransportProperties> local;
|
||||
Transaction txn = db.startTransaction(true);
|
||||
try {
|
||||
local = getLocalProperties(txn);
|
||||
db.commitTransaction(txn);
|
||||
} finally {
|
||||
db.endTransaction(txn);
|
||||
}
|
||||
return local;
|
||||
return db.transactionWithResult(true, this::getLocalProperties);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -176,9 +168,8 @@ class TransportPropertyManagerImpl implements TransportPropertyManager,
|
||||
public TransportProperties getLocalProperties(TransportId t)
|
||||
throws DbException {
|
||||
try {
|
||||
TransportProperties p = null;
|
||||
Transaction txn = db.startTransaction(true);
|
||||
try {
|
||||
return db.transactionWithResult(true, txn -> {
|
||||
TransportProperties p = null;
|
||||
// Find the latest local update
|
||||
LatestUpdate latest = findLatest(txn, localGroup.getId(), t,
|
||||
true);
|
||||
@@ -188,11 +179,8 @@ class TransportPropertyManagerImpl implements TransportPropertyManager,
|
||||
latest.messageId);
|
||||
p = parseProperties(message);
|
||||
}
|
||||
db.commitTransaction(txn);
|
||||
} finally {
|
||||
db.endTransaction(txn);
|
||||
}
|
||||
return p == null ? new TransportProperties() : p;
|
||||
return p == null ? new TransportProperties() : p;
|
||||
});
|
||||
} catch (FormatException e) {
|
||||
throw new DbException(e);
|
||||
}
|
||||
@@ -201,16 +189,12 @@ class TransportPropertyManagerImpl implements TransportPropertyManager,
|
||||
@Override
|
||||
public Map<ContactId, TransportProperties> getRemoteProperties(
|
||||
TransportId t) throws DbException {
|
||||
Map<ContactId, TransportProperties> remote = new HashMap<>();
|
||||
Transaction txn = db.startTransaction(true);
|
||||
try {
|
||||
return db.transactionWithResult(true, txn -> {
|
||||
Map<ContactId, TransportProperties> remote = new HashMap<>();
|
||||
for (Contact c : db.getContacts(txn))
|
||||
remote.put(c.getId(), getRemoteProperties(txn, c, t));
|
||||
db.commitTransaction(txn);
|
||||
} finally {
|
||||
db.endTransaction(txn);
|
||||
}
|
||||
return remote;
|
||||
return remote;
|
||||
});
|
||||
}
|
||||
|
||||
private TransportProperties getRemoteProperties(Transaction txn, Contact c,
|
||||
@@ -234,23 +218,15 @@ class TransportPropertyManagerImpl implements TransportPropertyManager,
|
||||
@Override
|
||||
public TransportProperties getRemoteProperties(ContactId c, TransportId t)
|
||||
throws DbException {
|
||||
TransportProperties p;
|
||||
Transaction txn = db.startTransaction(true);
|
||||
try {
|
||||
p = getRemoteProperties(txn, db.getContact(txn, c), t);
|
||||
db.commitTransaction(txn);
|
||||
} finally {
|
||||
db.endTransaction(txn);
|
||||
}
|
||||
return p;
|
||||
return db.transactionWithResult(true, txn ->
|
||||
getRemoteProperties(txn, db.getContact(txn, c), t));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void mergeLocalProperties(TransportId t, TransportProperties p)
|
||||
throws DbException {
|
||||
try {
|
||||
Transaction txn = db.startTransaction(false);
|
||||
try {
|
||||
db.transaction(false, txn -> {
|
||||
// Merge the new properties with any existing properties
|
||||
TransportProperties merged;
|
||||
boolean changed;
|
||||
@@ -287,10 +263,7 @@ class TransportPropertyManagerImpl implements TransportPropertyManager,
|
||||
db.removeMessage(txn, latest.messageId);
|
||||
}
|
||||
}
|
||||
db.commitTransaction(txn);
|
||||
} finally {
|
||||
db.endTransaction(txn);
|
||||
}
|
||||
});
|
||||
} catch (FormatException e) {
|
||||
throw new DbException(e);
|
||||
}
|
||||
|
||||
@@ -23,15 +23,8 @@ class SettingsManagerImpl implements SettingsManager {
|
||||
|
||||
@Override
|
||||
public Settings getSettings(String namespace) throws DbException {
|
||||
Settings s;
|
||||
Transaction txn = db.startTransaction(true);
|
||||
try {
|
||||
s = db.getSettings(txn, namespace);
|
||||
db.commitTransaction(txn);
|
||||
} finally {
|
||||
db.endTransaction(txn);
|
||||
}
|
||||
return s;
|
||||
return db.transactionWithResult(true, txn ->
|
||||
db.getSettings(txn, namespace));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -42,12 +35,6 @@ class SettingsManagerImpl implements SettingsManager {
|
||||
|
||||
@Override
|
||||
public void mergeSettings(Settings s, String namespace) throws DbException {
|
||||
Transaction txn = db.startTransaction(false);
|
||||
try {
|
||||
db.mergeSettings(txn, s, namespace);
|
||||
db.commitTransaction(txn);
|
||||
} finally {
|
||||
db.endTransaction(txn);
|
||||
}
|
||||
db.transaction(false, txn -> db.mergeSettings(txn, s, namespace));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,7 +5,6 @@ import org.briarproject.bramble.api.contact.event.ContactRemovedEvent;
|
||||
import org.briarproject.bramble.api.db.DatabaseComponent;
|
||||
import org.briarproject.bramble.api.db.DatabaseExecutor;
|
||||
import org.briarproject.bramble.api.db.DbException;
|
||||
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.EventListener;
|
||||
@@ -230,14 +229,8 @@ class DuplexOutgoingSession implements SyncSession, EventListener {
|
||||
if (interrupted) return;
|
||||
if (!generateAckQueued.getAndSet(false)) throw new AssertionError();
|
||||
try {
|
||||
Ack a;
|
||||
Transaction txn = db.startTransaction(false);
|
||||
try {
|
||||
a = db.generateAck(txn, contactId, MAX_MESSAGE_IDS);
|
||||
db.commitTransaction(txn);
|
||||
} finally {
|
||||
db.endTransaction(txn);
|
||||
}
|
||||
Ack a = db.transactionWithNullableResult(false, txn ->
|
||||
db.generateAck(txn, contactId, MAX_MESSAGE_IDS));
|
||||
if (LOG.isLoggable(INFO))
|
||||
LOG.info("Generated ack: " + (a != null));
|
||||
if (a != null) writerTasks.add(new WriteAck(a));
|
||||
@@ -275,16 +268,15 @@ class DuplexOutgoingSession implements SyncSession, EventListener {
|
||||
if (!generateBatchQueued.getAndSet(false))
|
||||
throw new AssertionError();
|
||||
try {
|
||||
Collection<Message> b;
|
||||
Transaction txn = db.startTransaction(false);
|
||||
try {
|
||||
b = db.generateRequestedBatch(txn, contactId,
|
||||
MAX_RECORD_PAYLOAD_BYTES, maxLatency);
|
||||
setNextSendTime(db.getNextSendTime(txn, contactId));
|
||||
db.commitTransaction(txn);
|
||||
} finally {
|
||||
db.endTransaction(txn);
|
||||
}
|
||||
Collection<Message> b =
|
||||
db.transactionWithNullableResult(false, txn -> {
|
||||
Collection<Message> batch =
|
||||
db.generateRequestedBatch(txn, contactId,
|
||||
MAX_RECORD_PAYLOAD_BYTES,
|
||||
maxLatency);
|
||||
setNextSendTime(db.getNextSendTime(txn, contactId));
|
||||
return batch;
|
||||
});
|
||||
if (LOG.isLoggable(INFO))
|
||||
LOG.info("Generated batch: " + (b != null));
|
||||
if (b != null) writerTasks.add(new WriteBatch(b));
|
||||
@@ -322,16 +314,12 @@ class DuplexOutgoingSession implements SyncSession, EventListener {
|
||||
if (!generateOfferQueued.getAndSet(false))
|
||||
throw new AssertionError();
|
||||
try {
|
||||
Offer o;
|
||||
Transaction txn = db.startTransaction(false);
|
||||
try {
|
||||
o = db.generateOffer(txn, contactId, MAX_MESSAGE_IDS,
|
||||
maxLatency);
|
||||
Offer o = db.transactionWithNullableResult(false, txn -> {
|
||||
Offer offer = db.generateOffer(txn, contactId,
|
||||
MAX_MESSAGE_IDS, maxLatency);
|
||||
setNextSendTime(db.getNextSendTime(txn, contactId));
|
||||
db.commitTransaction(txn);
|
||||
} finally {
|
||||
db.endTransaction(txn);
|
||||
}
|
||||
return offer;
|
||||
});
|
||||
if (LOG.isLoggable(INFO))
|
||||
LOG.info("Generated offer: " + (o != null));
|
||||
if (o != null) writerTasks.add(new WriteOffer(o));
|
||||
@@ -369,14 +357,8 @@ class DuplexOutgoingSession implements SyncSession, EventListener {
|
||||
if (!generateRequestQueued.getAndSet(false))
|
||||
throw new AssertionError();
|
||||
try {
|
||||
Request r;
|
||||
Transaction txn = db.startTransaction(false);
|
||||
try {
|
||||
r = db.generateRequest(txn, contactId, MAX_MESSAGE_IDS);
|
||||
db.commitTransaction(txn);
|
||||
} finally {
|
||||
db.endTransaction(txn);
|
||||
}
|
||||
Request r = db.transactionWithNullableResult(false, txn ->
|
||||
db.generateRequest(txn, contactId, MAX_MESSAGE_IDS));
|
||||
if (LOG.isLoggable(INFO))
|
||||
LOG.info("Generated request: " + (r != null));
|
||||
if (r != null) writerTasks.add(new WriteRequest(r));
|
||||
|
||||
@@ -6,7 +6,6 @@ import org.briarproject.bramble.api.contact.event.ContactRemovedEvent;
|
||||
import org.briarproject.bramble.api.db.DatabaseComponent;
|
||||
import org.briarproject.bramble.api.db.DatabaseExecutor;
|
||||
import org.briarproject.bramble.api.db.DbException;
|
||||
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.EventListener;
|
||||
@@ -120,13 +119,8 @@ class IncomingSession implements SyncSession, EventListener {
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
Transaction txn = db.startTransaction(false);
|
||||
try {
|
||||
db.receiveAck(txn, contactId, ack);
|
||||
db.commitTransaction(txn);
|
||||
} finally {
|
||||
db.endTransaction(txn);
|
||||
}
|
||||
db.transaction(false, txn ->
|
||||
db.receiveAck(txn, contactId, ack));
|
||||
} catch (DbException e) {
|
||||
logException(LOG, WARNING, e);
|
||||
interrupt();
|
||||
@@ -146,13 +140,8 @@ class IncomingSession implements SyncSession, EventListener {
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
Transaction txn = db.startTransaction(false);
|
||||
try {
|
||||
db.receiveMessage(txn, contactId, message);
|
||||
db.commitTransaction(txn);
|
||||
} finally {
|
||||
db.endTransaction(txn);
|
||||
}
|
||||
db.transaction(false, txn ->
|
||||
db.receiveMessage(txn, contactId, message));
|
||||
} catch (DbException e) {
|
||||
logException(LOG, WARNING, e);
|
||||
interrupt();
|
||||
@@ -172,13 +161,8 @@ class IncomingSession implements SyncSession, EventListener {
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
Transaction txn = db.startTransaction(false);
|
||||
try {
|
||||
db.receiveOffer(txn, contactId, offer);
|
||||
db.commitTransaction(txn);
|
||||
} finally {
|
||||
db.endTransaction(txn);
|
||||
}
|
||||
db.transaction(false, txn ->
|
||||
db.receiveOffer(txn, contactId, offer));
|
||||
} catch (DbException e) {
|
||||
logException(LOG, WARNING, e);
|
||||
interrupt();
|
||||
@@ -198,13 +182,8 @@ class IncomingSession implements SyncSession, EventListener {
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
Transaction txn = db.startTransaction(false);
|
||||
try {
|
||||
db.receiveRequest(txn, contactId, request);
|
||||
db.commitTransaction(txn);
|
||||
} finally {
|
||||
db.endTransaction(txn);
|
||||
}
|
||||
db.transaction(false, txn ->
|
||||
db.receiveRequest(txn, contactId, request));
|
||||
} catch (DbException e) {
|
||||
logException(LOG, WARNING, e);
|
||||
interrupt();
|
||||
|
||||
@@ -36,6 +36,7 @@ class MessageFactoryImpl implements MessageFactory {
|
||||
|
||||
@Override
|
||||
public Message createMessage(GroupId g, long timestamp, byte[] body) {
|
||||
if (body.length == 0) throw new IllegalArgumentException();
|
||||
if (body.length > MAX_MESSAGE_BODY_LENGTH)
|
||||
throw new IllegalArgumentException();
|
||||
MessageId id = getMessageId(g, timestamp, body);
|
||||
@@ -54,7 +55,7 @@ class MessageFactoryImpl implements MessageFactory {
|
||||
|
||||
@Override
|
||||
public Message createMessage(byte[] raw) {
|
||||
if (raw.length < MESSAGE_HEADER_LENGTH)
|
||||
if (raw.length <= MESSAGE_HEADER_LENGTH)
|
||||
throw new IllegalArgumentException();
|
||||
if (raw.length > MAX_MESSAGE_LENGTH)
|
||||
throw new IllegalArgumentException();
|
||||
|
||||
@@ -5,7 +5,6 @@ import org.briarproject.bramble.api.contact.event.ContactRemovedEvent;
|
||||
import org.briarproject.bramble.api.db.DatabaseComponent;
|
||||
import org.briarproject.bramble.api.db.DatabaseExecutor;
|
||||
import org.briarproject.bramble.api.db.DbException;
|
||||
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.EventListener;
|
||||
@@ -47,7 +46,8 @@ class SimplexOutgoingSession implements SyncSession, EventListener {
|
||||
private static final Logger LOG =
|
||||
Logger.getLogger(SimplexOutgoingSession.class.getName());
|
||||
|
||||
private static final ThrowingRunnable<IOException> CLOSE = () -> {};
|
||||
private static final ThrowingRunnable<IOException> CLOSE = () -> {
|
||||
};
|
||||
|
||||
private final DatabaseComponent db;
|
||||
private final Executor dbExecutor;
|
||||
@@ -128,14 +128,8 @@ class SimplexOutgoingSession implements SyncSession, EventListener {
|
||||
public void run() {
|
||||
if (interrupted) return;
|
||||
try {
|
||||
Ack a;
|
||||
Transaction txn = db.startTransaction(false);
|
||||
try {
|
||||
a = db.generateAck(txn, contactId, MAX_MESSAGE_IDS);
|
||||
db.commitTransaction(txn);
|
||||
} finally {
|
||||
db.endTransaction(txn);
|
||||
}
|
||||
Ack a = db.transactionWithNullableResult(false, txn ->
|
||||
db.generateAck(txn, contactId, MAX_MESSAGE_IDS));
|
||||
if (LOG.isLoggable(INFO))
|
||||
LOG.info("Generated ack: " + (a != null));
|
||||
if (a == null) decrementOutstandingQueries();
|
||||
@@ -172,15 +166,10 @@ class SimplexOutgoingSession implements SyncSession, EventListener {
|
||||
public void run() {
|
||||
if (interrupted) return;
|
||||
try {
|
||||
Collection<Message> b;
|
||||
Transaction txn = db.startTransaction(false);
|
||||
try {
|
||||
b = db.generateBatch(txn, contactId,
|
||||
MAX_RECORD_PAYLOAD_BYTES, maxLatency);
|
||||
db.commitTransaction(txn);
|
||||
} finally {
|
||||
db.endTransaction(txn);
|
||||
}
|
||||
Collection<Message> b =
|
||||
db.transactionWithNullableResult(false, txn ->
|
||||
db.generateBatch(txn, contactId,
|
||||
MAX_RECORD_PAYLOAD_BYTES, maxLatency));
|
||||
if (LOG.isLoggable(INFO))
|
||||
LOG.info("Generated batch: " + (b != null));
|
||||
if (b == null) decrementOutstandingQueries();
|
||||
|
||||
@@ -1,23 +1,11 @@
|
||||
package org.briarproject.bramble.sync;
|
||||
|
||||
import org.briarproject.bramble.PoliteExecutor;
|
||||
import org.briarproject.bramble.api.crypto.CryptoComponent;
|
||||
import org.briarproject.bramble.api.crypto.CryptoExecutor;
|
||||
import org.briarproject.bramble.api.db.DatabaseComponent;
|
||||
import org.briarproject.bramble.api.db.DatabaseExecutor;
|
||||
import org.briarproject.bramble.api.event.EventBus;
|
||||
import org.briarproject.bramble.api.lifecycle.LifecycleManager;
|
||||
import org.briarproject.bramble.api.sync.GroupFactory;
|
||||
import org.briarproject.bramble.api.sync.MessageFactory;
|
||||
import org.briarproject.bramble.api.sync.SyncRecordReaderFactory;
|
||||
import org.briarproject.bramble.api.sync.SyncRecordWriterFactory;
|
||||
import org.briarproject.bramble.api.sync.SyncSessionFactory;
|
||||
import org.briarproject.bramble.api.sync.ValidationManager;
|
||||
import org.briarproject.bramble.api.system.Clock;
|
||||
|
||||
import java.util.concurrent.Executor;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Singleton;
|
||||
|
||||
import dagger.Module;
|
||||
@@ -26,29 +14,14 @@ import dagger.Provides;
|
||||
@Module
|
||||
public class SyncModule {
|
||||
|
||||
public static class EagerSingletons {
|
||||
@Inject
|
||||
ValidationManager validationManager;
|
||||
}
|
||||
|
||||
/**
|
||||
* The maximum number of validation tasks to delegate to the crypto
|
||||
* executor concurrently.
|
||||
* <p>
|
||||
* The number of available processors can change during the lifetime of the
|
||||
* JVM, so this is just a reasonable guess.
|
||||
*/
|
||||
private static final int MAX_CONCURRENT_VALIDATION_TASKS =
|
||||
Math.max(1, Runtime.getRuntime().availableProcessors() - 1);
|
||||
|
||||
@Provides
|
||||
GroupFactory provideGroupFactory(CryptoComponent crypto) {
|
||||
return new GroupFactoryImpl(crypto);
|
||||
GroupFactory provideGroupFactory(GroupFactoryImpl groupFactory) {
|
||||
return groupFactory;
|
||||
}
|
||||
|
||||
@Provides
|
||||
MessageFactory provideMessageFactory(CryptoComponent crypto) {
|
||||
return new MessageFactoryImpl(crypto);
|
||||
MessageFactory provideMessageFactory(MessageFactoryImpl messageFactory) {
|
||||
return messageFactory;
|
||||
}
|
||||
|
||||
@Provides
|
||||
@@ -65,30 +38,8 @@ public class SyncModule {
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
SyncSessionFactory provideSyncSessionFactory(DatabaseComponent db,
|
||||
@DatabaseExecutor Executor dbExecutor, EventBus eventBus,
|
||||
Clock clock, SyncRecordReaderFactory recordReaderFactory,
|
||||
SyncRecordWriterFactory recordWriterFactory) {
|
||||
return new SyncSessionFactoryImpl(db, dbExecutor, eventBus, clock,
|
||||
recordReaderFactory, recordWriterFactory);
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
ValidationManager provideValidationManager(
|
||||
LifecycleManager lifecycleManager, EventBus eventBus,
|
||||
ValidationManagerImpl validationManager) {
|
||||
lifecycleManager.registerService(validationManager);
|
||||
eventBus.addListener(validationManager);
|
||||
return validationManager;
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
@ValidationExecutor
|
||||
Executor provideValidationExecutor(
|
||||
@CryptoExecutor Executor cryptoExecutor) {
|
||||
return new PoliteExecutor("ValidationExecutor", cryptoExecutor,
|
||||
MAX_CONCURRENT_VALIDATION_TASKS);
|
||||
SyncSessionFactory provideSyncSessionFactory(
|
||||
SyncSessionFactoryImpl syncSessionFactory) {
|
||||
return syncSessionFactory;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -124,7 +124,8 @@ class SyncRecordReaderImpl implements SyncRecordReader {
|
||||
if (!hasMessage()) throw new FormatException();
|
||||
if (nextRecord == null) throw new AssertionError();
|
||||
byte[] payload = nextRecord.getPayload();
|
||||
if (payload.length < MESSAGE_HEADER_LENGTH) throw new FormatException();
|
||||
if (payload.length <= MESSAGE_HEADER_LENGTH)
|
||||
throw new FormatException();
|
||||
// Validate timestamp
|
||||
long timestamp = ByteUtils.readUint64(payload, UniqueId.LENGTH);
|
||||
if (timestamp < 0) throw new FormatException();
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
package org.briarproject.bramble.sync;
|
||||
package org.briarproject.bramble.sync.validation;
|
||||
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.Target;
|
||||
@@ -1,5 +1,6 @@
|
||||
package org.briarproject.bramble.sync;
|
||||
package org.briarproject.bramble.sync.validation;
|
||||
|
||||
import org.briarproject.bramble.api.Pair;
|
||||
import org.briarproject.bramble.api.db.DatabaseComponent;
|
||||
import org.briarproject.bramble.api.db.DatabaseExecutor;
|
||||
import org.briarproject.bramble.api.db.DbException;
|
||||
@@ -17,8 +18,11 @@ import org.briarproject.bramble.api.sync.InvalidMessageException;
|
||||
import org.briarproject.bramble.api.sync.Message;
|
||||
import org.briarproject.bramble.api.sync.MessageContext;
|
||||
import org.briarproject.bramble.api.sync.MessageId;
|
||||
import org.briarproject.bramble.api.sync.ValidationManager;
|
||||
import org.briarproject.bramble.api.sync.event.MessageAddedEvent;
|
||||
import org.briarproject.bramble.api.sync.validation.IncomingMessageHook;
|
||||
import org.briarproject.bramble.api.sync.validation.MessageState;
|
||||
import org.briarproject.bramble.api.sync.validation.MessageValidator;
|
||||
import org.briarproject.bramble.api.sync.validation.ValidationManager;
|
||||
import org.briarproject.bramble.api.versioning.ClientMajorVersion;
|
||||
|
||||
import java.util.Collection;
|
||||
@@ -36,9 +40,9 @@ import javax.inject.Inject;
|
||||
|
||||
import static java.util.logging.Level.INFO;
|
||||
import static java.util.logging.Level.WARNING;
|
||||
import static org.briarproject.bramble.api.sync.ValidationManager.State.DELIVERED;
|
||||
import static org.briarproject.bramble.api.sync.ValidationManager.State.INVALID;
|
||||
import static org.briarproject.bramble.api.sync.ValidationManager.State.PENDING;
|
||||
import static org.briarproject.bramble.api.sync.validation.MessageState.DELIVERED;
|
||||
import static org.briarproject.bramble.api.sync.validation.MessageState.INVALID;
|
||||
import static org.briarproject.bramble.api.sync.validation.MessageState.PENDING;
|
||||
import static org.briarproject.bramble.util.LogUtils.logException;
|
||||
|
||||
@ThreadSafe
|
||||
@@ -97,14 +101,8 @@ class ValidationManagerImpl implements ValidationManager, Service,
|
||||
@DatabaseExecutor
|
||||
private void validateOutstandingMessages() {
|
||||
try {
|
||||
Queue<MessageId> unvalidated = new LinkedList<>();
|
||||
Transaction txn = db.startTransaction(true);
|
||||
try {
|
||||
unvalidated.addAll(db.getMessagesToValidate(txn));
|
||||
db.commitTransaction(txn);
|
||||
} finally {
|
||||
db.endTransaction(txn);
|
||||
}
|
||||
Queue<MessageId> unvalidated = new LinkedList<>(
|
||||
db.transactionWithResult(true, db::getMessagesToValidate));
|
||||
validateNextMessageAsync(unvalidated);
|
||||
} catch (DbException e) {
|
||||
logException(LOG, WARNING, e);
|
||||
@@ -119,18 +117,14 @@ class ValidationManagerImpl implements ValidationManager, Service,
|
||||
@DatabaseExecutor
|
||||
private void validateNextMessage(Queue<MessageId> unvalidated) {
|
||||
try {
|
||||
Message m;
|
||||
Group g;
|
||||
Transaction txn = db.startTransaction(true);
|
||||
try {
|
||||
Pair<Message, Group> mg = db.transactionWithResult(true, txn -> {
|
||||
MessageId id = unvalidated.poll();
|
||||
m = db.getMessage(txn, id);
|
||||
g = db.getGroup(txn, m.getGroupId());
|
||||
db.commitTransaction(txn);
|
||||
} finally {
|
||||
db.endTransaction(txn);
|
||||
}
|
||||
validateMessageAsync(m, g);
|
||||
if (id == null) throw new AssertionError();
|
||||
Message m = db.getMessage(txn, id);
|
||||
Group g = db.getGroup(txn, m.getGroupId());
|
||||
return new Pair<>(m, g);
|
||||
});
|
||||
validateMessageAsync(mg.getFirst(), mg.getSecond());
|
||||
validateNextMessageAsync(unvalidated);
|
||||
} catch (NoSuchMessageException e) {
|
||||
LOG.info("Message removed before validation");
|
||||
@@ -150,14 +144,8 @@ class ValidationManagerImpl implements ValidationManager, Service,
|
||||
@DatabaseExecutor
|
||||
private void deliverOutstandingMessages() {
|
||||
try {
|
||||
Queue<MessageId> pending = new LinkedList<>();
|
||||
Transaction txn = db.startTransaction(true);
|
||||
try {
|
||||
pending.addAll(db.getPendingMessages(txn));
|
||||
db.commitTransaction(txn);
|
||||
} finally {
|
||||
db.endTransaction(txn);
|
||||
}
|
||||
Queue<MessageId> pending = new LinkedList<>(
|
||||
db.transactionWithResult(true, db::getPendingMessages));
|
||||
deliverNextPendingMessageAsync(pending);
|
||||
} catch (DbException e) {
|
||||
logException(LOG, WARNING, e);
|
||||
@@ -172,24 +160,24 @@ class ValidationManagerImpl implements ValidationManager, Service,
|
||||
@DatabaseExecutor
|
||||
private void deliverNextPendingMessage(Queue<MessageId> pending) {
|
||||
try {
|
||||
boolean anyInvalid = false, allDelivered = true;
|
||||
Queue<MessageId> toShare = null;
|
||||
Queue<MessageId> invalidate = null;
|
||||
Transaction txn = db.startTransaction(false);
|
||||
try {
|
||||
Queue<MessageId> toShare = new LinkedList<>();
|
||||
Queue<MessageId> invalidate = new LinkedList<>();
|
||||
db.transaction(false, txn -> {
|
||||
boolean anyInvalid = false, allDelivered = true;
|
||||
MessageId id = pending.poll();
|
||||
if (id == null) throw new AssertionError();
|
||||
// Check if message is still pending
|
||||
if (db.getMessageState(txn, id) == PENDING) {
|
||||
// Check if dependencies are valid and delivered
|
||||
Map<MessageId, State> states =
|
||||
Map<MessageId, MessageState> states =
|
||||
db.getMessageDependencies(txn, id);
|
||||
for (Entry<MessageId, State> e : states.entrySet()) {
|
||||
for (Entry<MessageId, MessageState> e : states.entrySet()) {
|
||||
if (e.getValue() == INVALID) anyInvalid = true;
|
||||
if (e.getValue() != DELIVERED) allDelivered = false;
|
||||
}
|
||||
if (anyInvalid) {
|
||||
invalidateMessage(txn, id);
|
||||
invalidate = getDependentsToInvalidate(txn, id);
|
||||
addDependentsToInvalidate(txn, id, invalidate);
|
||||
} else if (allDelivered) {
|
||||
Message m = db.getMessage(txn, id);
|
||||
Group g = db.getGroup(txn, m.getGroupId());
|
||||
@@ -200,22 +188,19 @@ class ValidationManagerImpl implements ValidationManager, Service,
|
||||
DeliveryResult result =
|
||||
deliverMessage(txn, m, c, majorVersion, meta);
|
||||
if (result.valid) {
|
||||
pending.addAll(getPendingDependents(txn, id));
|
||||
addPendingDependents(txn, id, pending);
|
||||
if (result.share) {
|
||||
db.setMessageShared(txn, id);
|
||||
toShare = new LinkedList<>(states.keySet());
|
||||
toShare.addAll(states.keySet());
|
||||
}
|
||||
} else {
|
||||
invalidate = getDependentsToInvalidate(txn, id);
|
||||
addDependentsToInvalidate(txn, id, invalidate);
|
||||
}
|
||||
}
|
||||
}
|
||||
db.commitTransaction(txn);
|
||||
} finally {
|
||||
db.endTransaction(txn);
|
||||
}
|
||||
if (invalidate != null) invalidateNextMessageAsync(invalidate);
|
||||
if (toShare != null) shareNextMessageAsync(toShare);
|
||||
});
|
||||
if (!invalidate.isEmpty()) invalidateNextMessageAsync(invalidate);
|
||||
if (!toShare.isEmpty()) shareNextMessageAsync(toShare);
|
||||
deliverNextPendingMessageAsync(pending);
|
||||
} catch (NoSuchMessageException e) {
|
||||
LOG.info("Message removed before delivery");
|
||||
@@ -264,20 +249,19 @@ class ValidationManagerImpl implements ValidationManager, Service,
|
||||
MessageContext context) {
|
||||
try {
|
||||
MessageId id = m.getId();
|
||||
boolean anyInvalid = false, allDelivered = true;
|
||||
Queue<MessageId> invalidate = null;
|
||||
Queue<MessageId> pending = null;
|
||||
Queue<MessageId> toShare = null;
|
||||
Transaction txn = db.startTransaction(false);
|
||||
try {
|
||||
Queue<MessageId> invalidate = new LinkedList<>();
|
||||
Queue<MessageId> pending = new LinkedList<>();
|
||||
Queue<MessageId> toShare = new LinkedList<>();
|
||||
db.transaction(false, txn -> {
|
||||
boolean anyInvalid = false, allDelivered = true;
|
||||
// Check if message has any dependencies
|
||||
Collection<MessageId> dependencies = context.getDependencies();
|
||||
if (!dependencies.isEmpty()) {
|
||||
db.addMessageDependencies(txn, m, dependencies);
|
||||
// Check if dependencies are valid and delivered
|
||||
Map<MessageId, State> states =
|
||||
Map<MessageId, MessageState> states =
|
||||
db.getMessageDependencies(txn, id);
|
||||
for (Entry<MessageId, State> e : states.entrySet()) {
|
||||
for (Entry<MessageId, MessageState> e : states.entrySet()) {
|
||||
if (e.getValue() == INVALID) anyInvalid = true;
|
||||
if (e.getValue() != DELIVERED) allDelivered = false;
|
||||
}
|
||||
@@ -285,7 +269,7 @@ class ValidationManagerImpl implements ValidationManager, Service,
|
||||
if (anyInvalid) {
|
||||
if (db.getMessageState(txn, id) != INVALID) {
|
||||
invalidateMessage(txn, id);
|
||||
invalidate = getDependentsToInvalidate(txn, id);
|
||||
addDependentsToInvalidate(txn, id, invalidate);
|
||||
}
|
||||
} else {
|
||||
Metadata meta = context.getMetadata();
|
||||
@@ -294,25 +278,22 @@ class ValidationManagerImpl implements ValidationManager, Service,
|
||||
DeliveryResult result =
|
||||
deliverMessage(txn, m, c, majorVersion, meta);
|
||||
if (result.valid) {
|
||||
pending = getPendingDependents(txn, id);
|
||||
addPendingDependents(txn, id, pending);
|
||||
if (result.share) {
|
||||
db.setMessageShared(txn, id);
|
||||
toShare = new LinkedList<>(dependencies);
|
||||
toShare.addAll(dependencies);
|
||||
}
|
||||
} else {
|
||||
invalidate = getDependentsToInvalidate(txn, id);
|
||||
addDependentsToInvalidate(txn, id, invalidate);
|
||||
}
|
||||
} else {
|
||||
db.setMessageState(txn, id, PENDING);
|
||||
}
|
||||
}
|
||||
db.commitTransaction(txn);
|
||||
} finally {
|
||||
db.endTransaction(txn);
|
||||
}
|
||||
if (invalidate != null) invalidateNextMessageAsync(invalidate);
|
||||
if (pending != null) deliverNextPendingMessageAsync(pending);
|
||||
if (toShare != null) shareNextMessageAsync(toShare);
|
||||
});
|
||||
if (!invalidate.isEmpty()) invalidateNextMessageAsync(invalidate);
|
||||
if (!pending.isEmpty()) deliverNextPendingMessageAsync(pending);
|
||||
if (!toShare.isEmpty()) shareNextMessageAsync(toShare);
|
||||
} catch (NoSuchMessageException e) {
|
||||
LOG.info("Message removed during validation");
|
||||
} catch (NoSuchGroupException e) {
|
||||
@@ -342,14 +323,12 @@ class ValidationManagerImpl implements ValidationManager, Service,
|
||||
}
|
||||
|
||||
@DatabaseExecutor
|
||||
private Queue<MessageId> getPendingDependents(Transaction txn, MessageId m)
|
||||
throws DbException {
|
||||
Queue<MessageId> pending = new LinkedList<>();
|
||||
Map<MessageId, State> states = db.getMessageDependents(txn, m);
|
||||
for (Entry<MessageId, State> e : states.entrySet()) {
|
||||
private void addPendingDependents(Transaction txn, MessageId m,
|
||||
Queue<MessageId> pending) throws DbException {
|
||||
Map<MessageId, MessageState> states = db.getMessageDependents(txn, m);
|
||||
for (Entry<MessageId, MessageState> e : states.entrySet()) {
|
||||
if (e.getValue() == PENDING) pending.add(e.getKey());
|
||||
}
|
||||
return pending;
|
||||
}
|
||||
|
||||
private void shareOutstandingMessagesAsync() {
|
||||
@@ -359,14 +338,8 @@ class ValidationManagerImpl implements ValidationManager, Service,
|
||||
@DatabaseExecutor
|
||||
private void shareOutstandingMessages() {
|
||||
try {
|
||||
Queue<MessageId> toShare = new LinkedList<>();
|
||||
Transaction txn = db.startTransaction(true);
|
||||
try {
|
||||
toShare.addAll(db.getMessagesToShare(txn));
|
||||
db.commitTransaction(txn);
|
||||
} finally {
|
||||
db.endTransaction(txn);
|
||||
}
|
||||
Queue<MessageId> toShare = new LinkedList<>(
|
||||
db.transactionWithResult(true, db::getMessagesToShare));
|
||||
shareNextMessageAsync(toShare);
|
||||
} catch (DbException e) {
|
||||
logException(LOG, WARNING, e);
|
||||
@@ -387,15 +360,12 @@ class ValidationManagerImpl implements ValidationManager, Service,
|
||||
@DatabaseExecutor
|
||||
private void shareNextMessage(Queue<MessageId> toShare) {
|
||||
try {
|
||||
Transaction txn = db.startTransaction(false);
|
||||
try {
|
||||
db.transaction(false, txn -> {
|
||||
MessageId id = toShare.poll();
|
||||
if (id == null) throw new AssertionError();
|
||||
db.setMessageShared(txn, id);
|
||||
toShare.addAll(db.getMessageDependencies(txn, id).keySet());
|
||||
db.commitTransaction(txn);
|
||||
} finally {
|
||||
db.endTransaction(txn);
|
||||
}
|
||||
});
|
||||
shareNextMessageAsync(toShare);
|
||||
} catch (NoSuchMessageException e) {
|
||||
LOG.info("Message removed before sharing");
|
||||
@@ -416,17 +386,14 @@ class ValidationManagerImpl implements ValidationManager, Service,
|
||||
@DatabaseExecutor
|
||||
private void invalidateNextMessage(Queue<MessageId> invalidate) {
|
||||
try {
|
||||
Transaction txn = db.startTransaction(false);
|
||||
try {
|
||||
db.transaction(false, txn -> {
|
||||
MessageId id = invalidate.poll();
|
||||
if (id == null) throw new AssertionError();
|
||||
if (db.getMessageState(txn, id) != INVALID) {
|
||||
invalidateMessage(txn, id);
|
||||
invalidate.addAll(getDependentsToInvalidate(txn, id));
|
||||
addDependentsToInvalidate(txn, id, invalidate);
|
||||
}
|
||||
db.commitTransaction(txn);
|
||||
} finally {
|
||||
db.endTransaction(txn);
|
||||
}
|
||||
});
|
||||
invalidateNextMessageAsync(invalidate);
|
||||
} catch (NoSuchMessageException e) {
|
||||
LOG.info("Message removed before invalidation");
|
||||
@@ -445,14 +412,12 @@ class ValidationManagerImpl implements ValidationManager, Service,
|
||||
}
|
||||
|
||||
@DatabaseExecutor
|
||||
private Queue<MessageId> getDependentsToInvalidate(Transaction txn,
|
||||
MessageId m) throws DbException {
|
||||
Queue<MessageId> invalidate = new LinkedList<>();
|
||||
Map<MessageId, State> states = db.getMessageDependents(txn, m);
|
||||
for (Entry<MessageId, State> e : states.entrySet()) {
|
||||
private void addDependentsToInvalidate(Transaction txn,
|
||||
MessageId m, Queue<MessageId> invalidate) throws DbException {
|
||||
Map<MessageId, MessageState> states = db.getMessageDependents(txn, m);
|
||||
for (Entry<MessageId, MessageState> e : states.entrySet()) {
|
||||
if (e.getValue() != INVALID) invalidate.add(e.getKey());
|
||||
}
|
||||
return invalidate;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -472,14 +437,8 @@ class ValidationManagerImpl implements ValidationManager, Service,
|
||||
@DatabaseExecutor
|
||||
private void loadGroupAndValidate(Message m) {
|
||||
try {
|
||||
Group g;
|
||||
Transaction txn = db.startTransaction(true);
|
||||
try {
|
||||
g = db.getGroup(txn, m.getGroupId());
|
||||
db.commitTransaction(txn);
|
||||
} finally {
|
||||
db.endTransaction(txn);
|
||||
}
|
||||
Group g = db.transactionWithResult(true, txn ->
|
||||
db.getGroup(txn, m.getGroupId()));
|
||||
validateMessageAsync(m, g);
|
||||
} catch (NoSuchGroupException e) {
|
||||
LOG.info("Group removed before validation");
|
||||
@@ -0,0 +1,53 @@
|
||||
package org.briarproject.bramble.sync.validation;
|
||||
|
||||
import org.briarproject.bramble.PoliteExecutor;
|
||||
import org.briarproject.bramble.api.crypto.CryptoExecutor;
|
||||
import org.briarproject.bramble.api.event.EventBus;
|
||||
import org.briarproject.bramble.api.lifecycle.LifecycleManager;
|
||||
import org.briarproject.bramble.api.sync.validation.ValidationManager;
|
||||
|
||||
import java.util.concurrent.Executor;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Singleton;
|
||||
|
||||
import dagger.Module;
|
||||
import dagger.Provides;
|
||||
|
||||
@Module
|
||||
public class ValidationModule {
|
||||
|
||||
public static class EagerSingletons {
|
||||
@Inject
|
||||
ValidationManager validationManager;
|
||||
}
|
||||
|
||||
/**
|
||||
* The maximum number of validation tasks to delegate to the crypto
|
||||
* executor concurrently.
|
||||
* <p>
|
||||
* The number of available processors can change during the lifetime of the
|
||||
* JVM, so this is just a reasonable guess.
|
||||
*/
|
||||
private static final int MAX_CONCURRENT_VALIDATION_TASKS =
|
||||
Math.max(1, Runtime.getRuntime().availableProcessors() - 1);
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
ValidationManager provideValidationManager(
|
||||
LifecycleManager lifecycleManager, EventBus eventBus,
|
||||
ValidationManagerImpl validationManager) {
|
||||
lifecycleManager.registerService(validationManager);
|
||||
eventBus.addListener(validationManager);
|
||||
return validationManager;
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
@ValidationExecutor
|
||||
Executor provideValidationExecutor(
|
||||
@CryptoExecutor Executor cryptoExecutor) {
|
||||
return new PoliteExecutor("ValidationExecutor", cryptoExecutor,
|
||||
MAX_CONCURRENT_VALIDATION_TASKS);
|
||||
}
|
||||
}
|
||||
@@ -72,8 +72,7 @@ class KeyManagerImpl implements KeyManager, Service, EventListener {
|
||||
for (DuplexPluginFactory f : pluginConfig.getDuplexFactories())
|
||||
transports.put(f.getId(), f.getMaxLatency());
|
||||
try {
|
||||
Transaction txn = db.startTransaction(false);
|
||||
try {
|
||||
db.transaction(false, txn -> {
|
||||
for (Contact c : db.getContacts(txn))
|
||||
if (c.isActive()) activeContacts.put(c.getId(), true);
|
||||
for (Entry<TransportId, Integer> e : transports.entrySet())
|
||||
@@ -85,10 +84,7 @@ class KeyManagerImpl implements KeyManager, Service, EventListener {
|
||||
managers.put(e.getKey(), m);
|
||||
m.start(txn);
|
||||
}
|
||||
db.commitTransaction(txn);
|
||||
} finally {
|
||||
db.endTransaction(txn);
|
||||
}
|
||||
});
|
||||
} catch (DbException e) {
|
||||
throw new ServiceException(e);
|
||||
}
|
||||
@@ -141,15 +137,8 @@ class KeyManagerImpl implements KeyManager, Service, EventListener {
|
||||
if (LOG.isLoggable(INFO)) LOG.info("No key manager for " + t);
|
||||
return null;
|
||||
}
|
||||
StreamContext ctx;
|
||||
Transaction txn = db.startTransaction(false);
|
||||
try {
|
||||
ctx = m.getStreamContext(txn, c);
|
||||
db.commitTransaction(txn);
|
||||
} finally {
|
||||
db.endTransaction(txn);
|
||||
}
|
||||
return ctx;
|
||||
return db.transactionWithNullableResult(false, txn ->
|
||||
m.getStreamContext(txn, c));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -160,15 +149,8 @@ class KeyManagerImpl implements KeyManager, Service, EventListener {
|
||||
if (LOG.isLoggable(INFO)) LOG.info("No key manager for " + t);
|
||||
return null;
|
||||
}
|
||||
StreamContext ctx;
|
||||
Transaction txn = db.startTransaction(false);
|
||||
try {
|
||||
ctx = m.getStreamContext(txn, tag);
|
||||
db.commitTransaction(txn);
|
||||
} finally {
|
||||
db.endTransaction(txn);
|
||||
}
|
||||
return ctx;
|
||||
return db.transactionWithNullableResult(false, txn ->
|
||||
m.getStreamContext(txn, tag));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -162,13 +162,7 @@ class TransportKeyManagerImpl implements TransportKeyManager {
|
||||
private void rotateKeys() {
|
||||
dbExecutor.execute(() -> {
|
||||
try {
|
||||
Transaction txn = db.startTransaction(false);
|
||||
try {
|
||||
rotateKeys(txn);
|
||||
db.commitTransaction(txn);
|
||||
} finally {
|
||||
db.endTransaction(txn);
|
||||
}
|
||||
db.transaction(false, this::rotateKeys);
|
||||
} catch (DbException e) {
|
||||
logException(LOG, WARNING, e);
|
||||
}
|
||||
|
||||
@@ -23,7 +23,7 @@ import org.briarproject.bramble.api.sync.GroupId;
|
||||
import org.briarproject.bramble.api.sync.InvalidMessageException;
|
||||
import org.briarproject.bramble.api.sync.Message;
|
||||
import org.briarproject.bramble.api.sync.MessageId;
|
||||
import org.briarproject.bramble.api.sync.ValidationManager.IncomingMessageHook;
|
||||
import org.briarproject.bramble.api.sync.validation.IncomingMessageHook;
|
||||
import org.briarproject.bramble.api.system.Clock;
|
||||
import org.briarproject.bramble.api.versioning.ClientMajorVersion;
|
||||
import org.briarproject.bramble.api.versioning.ClientVersioningManager;
|
||||
@@ -123,16 +123,12 @@ class ClientVersioningManagerImpl implements ClientVersioningManager, Client,
|
||||
List<ClientVersion> versions = new ArrayList<>(clients);
|
||||
Collections.sort(versions);
|
||||
try {
|
||||
Transaction txn = db.startTransaction(false);
|
||||
try {
|
||||
db.transaction(false, txn -> {
|
||||
if (updateClientVersions(txn, versions)) {
|
||||
for (Contact c : db.getContacts(txn))
|
||||
clientVersionsUpdated(txn, c, versions);
|
||||
}
|
||||
db.commitTransaction(txn);
|
||||
} finally {
|
||||
db.endTransaction(txn);
|
||||
}
|
||||
});
|
||||
} catch (DbException e) {
|
||||
throw new ServiceException(e);
|
||||
}
|
||||
|
||||
@@ -4,7 +4,7 @@ import org.briarproject.bramble.api.client.ClientHelper;
|
||||
import org.briarproject.bramble.api.contact.ContactManager;
|
||||
import org.briarproject.bramble.api.data.MetadataEncoder;
|
||||
import org.briarproject.bramble.api.lifecycle.LifecycleManager;
|
||||
import org.briarproject.bramble.api.sync.ValidationManager;
|
||||
import org.briarproject.bramble.api.sync.validation.ValidationManager;
|
||||
import org.briarproject.bramble.api.system.Clock;
|
||||
import org.briarproject.bramble.api.versioning.ClientVersioningManager;
|
||||
|
||||
|
||||
@@ -1,8 +1,4 @@
|
||||
Bridge 131.252.210.150:8081 0E858AC201BF0F3FA3C462F64844CBFFC7297A42
|
||||
Bridge 67.205.189.122:8443 12D64D5D44E20169585E7378580C0D33A872AD98
|
||||
Bridge 45.32.148.146:8443 0CE016FB2462D8BF179AE71F7D702D09DEAC3F1D
|
||||
Bridge 148.251.90.59:7510 019F727CA6DCA6CA5C90B55E477B7D87981E75BC
|
||||
Bridge 45.55.1.74:8443 6F18FEFBB0CAECD5ABA755312FCCB34FC11A7AB8
|
||||
Bridge 85.229.131.78:444 50E433CCC5FEC11CC34CB4D92033561E065EA106
|
||||
Bridge 178.62.62.193:8443 391B1F9B6A28A1C5FAE1872283985F975E5DB029
|
||||
Bridge 45.76.29.92:8443 ECF1DD51A46FDEF2C50CED992EEEAE8DED18DA0C
|
||||
Bridge obfs4 78.46.188.239:37356 5A2D2F4158D0453E00C7C176978D3F41D69C45DB cert=3c0SwxpOisbohNxEc4tb875RVW8eOu1opRTVXJhafaKA/PNNtI7ElQIVOVZg1AdL5bxGCw iat-mode=0
|
||||
Bridge obfs4 52.15.78.72:9443 02069A3C5362476936B62BA6F5ACC41ABD573A9B cert=ijYG/OKc7kqu2YzKNFfeXN7/BG2BOgfEP2KyYEiGDQthnHbsOiTWHeIG0WJVW+BckzDgKw iat-mode=0
|
||||
Bridge obfs4 13.58.29.242:9443 0C58939A77DA6B6B29D4B5236A75865659607AE0 cert=OylWIEHb/ezpq1zWxW0sgKRn+9ARH2eOcQOZ8/Gew+4l+oKOhQ2jUX/Y+FSl61JorXZUWA iat-mode=0
|
||||
Bridge obfs4 45.33.37.112:9443 60A609BB4ABE8D46E634AE81ED29ADAB7776B399 cert=t5v19WmNv5Sc2YPNr8RQids365W7MY8zJwQVkOxBjUMFomMWARDzsbYpcWLLcw0J9Gm+BQ iat-mode=0
|
||||
@@ -79,18 +79,6 @@ public class BdfMessageValidatorTest extends ValidatorTestCase {
|
||||
assertSame(meta, messageContext.getMetadata());
|
||||
}
|
||||
|
||||
@Test(expected = InvalidMessageException.class)
|
||||
public void testRejectsTooShortMessage() throws Exception {
|
||||
Message invalidMessage = getMessage(groupId, 0);
|
||||
|
||||
context.checking(new Expectations() {{
|
||||
oneOf(clock).currentTimeMillis();
|
||||
will(returnValue(timestamp));
|
||||
}});
|
||||
|
||||
failIfSubclassIsCalled.validateMessage(invalidMessage, group);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAcceptsMinLengthMessage() throws Exception {
|
||||
Message shortMessage = getMessage(groupId, 1);
|
||||
|
||||
@@ -22,6 +22,7 @@ import org.briarproject.bramble.api.sync.Message;
|
||||
import org.briarproject.bramble.api.sync.MessageFactory;
|
||||
import org.briarproject.bramble.api.sync.MessageId;
|
||||
import org.briarproject.bramble.test.BrambleTestCase;
|
||||
import org.briarproject.bramble.test.DbExpectations;
|
||||
import org.briarproject.bramble.util.StringUtils;
|
||||
import org.jmock.Expectations;
|
||||
import org.jmock.Mockery;
|
||||
@@ -85,14 +86,11 @@ public class ClientHelperImplTest extends BrambleTestCase {
|
||||
boolean shared = new Random().nextBoolean();
|
||||
Transaction txn = new Transaction(null, false);
|
||||
|
||||
context.checking(new Expectations() {{
|
||||
oneOf(db).startTransaction(false);
|
||||
will(returnValue(txn));
|
||||
context.checking(new DbExpectations() {{
|
||||
oneOf(db).transaction(with(false), withDbRunnable(txn));
|
||||
oneOf(metadataEncoder).encode(dictionary);
|
||||
will(returnValue(metadata));
|
||||
oneOf(db).addLocalMessage(txn, message, metadata, shared);
|
||||
oneOf(db).commitTransaction(txn);
|
||||
oneOf(db).endTransaction(txn);
|
||||
}});
|
||||
|
||||
clientHelper.addLocalMessage(message, dictionary, shared);
|
||||
@@ -116,13 +114,10 @@ public class ClientHelperImplTest extends BrambleTestCase {
|
||||
Transaction txn = new Transaction(null, true);
|
||||
|
||||
expectToList(true);
|
||||
context.checking(new Expectations() {{
|
||||
oneOf(db).startTransaction(true);
|
||||
will(returnValue(txn));
|
||||
context.checking(new DbExpectations() {{
|
||||
oneOf(db).transactionWithResult(with(true), withDbCallable(txn));
|
||||
oneOf(db).getMessage(txn, messageId);
|
||||
will(returnValue(message));
|
||||
oneOf(db).commitTransaction(txn);
|
||||
oneOf(db).endTransaction(txn);
|
||||
}});
|
||||
|
||||
clientHelper.getMessageAsList(messageId);
|
||||
@@ -133,15 +128,12 @@ public class ClientHelperImplTest extends BrambleTestCase {
|
||||
public void testGetGroupMetadataAsDictionary() throws Exception {
|
||||
Transaction txn = new Transaction(null, true);
|
||||
|
||||
context.checking(new Expectations() {{
|
||||
oneOf(db).startTransaction(true);
|
||||
will(returnValue(txn));
|
||||
context.checking(new DbExpectations() {{
|
||||
oneOf(db).transactionWithResult(with(true), withDbCallable(txn));
|
||||
oneOf(db).getGroupMetadata(txn, groupId);
|
||||
will(returnValue(metadata));
|
||||
oneOf(metadataParser).parse(metadata);
|
||||
will(returnValue(dictionary));
|
||||
oneOf(db).commitTransaction(txn);
|
||||
oneOf(db).endTransaction(txn);
|
||||
}});
|
||||
|
||||
assertEquals(dictionary,
|
||||
@@ -153,15 +145,12 @@ public class ClientHelperImplTest extends BrambleTestCase {
|
||||
public void testGetMessageMetadataAsDictionary() throws Exception {
|
||||
Transaction txn = new Transaction(null, true);
|
||||
|
||||
context.checking(new Expectations() {{
|
||||
oneOf(db).startTransaction(true);
|
||||
will(returnValue(txn));
|
||||
context.checking(new DbExpectations() {{
|
||||
oneOf(db).transactionWithResult(with(true), withDbCallable(txn));
|
||||
oneOf(db).getMessageMetadata(txn, messageId);
|
||||
will(returnValue(metadata));
|
||||
oneOf(metadataParser).parse(metadata);
|
||||
will(returnValue(dictionary));
|
||||
oneOf(db).commitTransaction(txn);
|
||||
oneOf(db).endTransaction(txn);
|
||||
}});
|
||||
|
||||
assertEquals(dictionary,
|
||||
@@ -175,15 +164,12 @@ public class ClientHelperImplTest extends BrambleTestCase {
|
||||
map.put(messageId, dictionary);
|
||||
Transaction txn = new Transaction(null, true);
|
||||
|
||||
context.checking(new Expectations() {{
|
||||
oneOf(db).startTransaction(true);
|
||||
will(returnValue(txn));
|
||||
context.checking(new DbExpectations() {{
|
||||
oneOf(db).transactionWithResult(with(true), withDbCallable(txn));
|
||||
oneOf(db).getMessageMetadata(txn, groupId);
|
||||
will(returnValue(Collections.singletonMap(messageId, metadata)));
|
||||
oneOf(metadataParser).parse(metadata);
|
||||
will(returnValue(dictionary));
|
||||
oneOf(db).commitTransaction(txn);
|
||||
oneOf(db).endTransaction(txn);
|
||||
}});
|
||||
|
||||
assertEquals(map, clientHelper.getMessageMetadataAsDictionary(groupId));
|
||||
@@ -200,17 +186,14 @@ public class ClientHelperImplTest extends BrambleTestCase {
|
||||
queryMetadata.put("query", getRandomBytes(42));
|
||||
Transaction txn = new Transaction(null, true);
|
||||
|
||||
context.checking(new Expectations() {{
|
||||
oneOf(db).startTransaction(true);
|
||||
will(returnValue(txn));
|
||||
context.checking(new DbExpectations() {{
|
||||
oneOf(db).transactionWithResult(with(true), withDbCallable(txn));
|
||||
oneOf(metadataEncoder).encode(query);
|
||||
will(returnValue(queryMetadata));
|
||||
oneOf(db).getMessageMetadata(txn, groupId, queryMetadata);
|
||||
will(returnValue(Collections.singletonMap(messageId, metadata)));
|
||||
oneOf(metadataParser).parse(metadata);
|
||||
will(returnValue(dictionary));
|
||||
oneOf(db).commitTransaction(txn);
|
||||
oneOf(db).endTransaction(txn);
|
||||
}});
|
||||
|
||||
assertEquals(map,
|
||||
@@ -222,14 +205,11 @@ public class ClientHelperImplTest extends BrambleTestCase {
|
||||
public void testMergeGroupMetadata() throws Exception {
|
||||
Transaction txn = new Transaction(null, false);
|
||||
|
||||
context.checking(new Expectations() {{
|
||||
oneOf(db).startTransaction(false);
|
||||
will(returnValue(txn));
|
||||
context.checking(new DbExpectations() {{
|
||||
oneOf(db).transaction(with(false), withDbRunnable(txn));
|
||||
oneOf(metadataEncoder).encode(dictionary);
|
||||
will(returnValue(metadata));
|
||||
oneOf(db).mergeGroupMetadata(txn, groupId, metadata);
|
||||
oneOf(db).commitTransaction(txn);
|
||||
oneOf(db).endTransaction(txn);
|
||||
}});
|
||||
|
||||
clientHelper.mergeGroupMetadata(groupId, dictionary);
|
||||
@@ -240,14 +220,11 @@ public class ClientHelperImplTest extends BrambleTestCase {
|
||||
public void testMergeMessageMetadata() throws Exception {
|
||||
Transaction txn = new Transaction(null, false);
|
||||
|
||||
context.checking(new Expectations() {{
|
||||
oneOf(db).startTransaction(false);
|
||||
will(returnValue(txn));
|
||||
context.checking(new DbExpectations() {{
|
||||
oneOf(db).transaction(with(false), withDbRunnable(txn));
|
||||
oneOf(metadataEncoder).encode(dictionary);
|
||||
will(returnValue(metadata));
|
||||
oneOf(db).mergeMessageMetadata(txn, messageId, metadata);
|
||||
oneOf(db).commitTransaction(txn);
|
||||
oneOf(db).endTransaction(txn);
|
||||
}});
|
||||
|
||||
clientHelper.mergeMessageMetadata(messageId, dictionary);
|
||||
|
||||
@@ -5,12 +5,17 @@ import org.briarproject.bramble.api.contact.ContactId;
|
||||
import org.briarproject.bramble.api.contact.ContactManager;
|
||||
import org.briarproject.bramble.api.crypto.SecretKey;
|
||||
import org.briarproject.bramble.api.db.DatabaseComponent;
|
||||
import org.briarproject.bramble.api.db.DbException;
|
||||
import org.briarproject.bramble.api.db.NoSuchContactException;
|
||||
import org.briarproject.bramble.api.db.Transaction;
|
||||
import org.briarproject.bramble.api.identity.Author;
|
||||
import org.briarproject.bramble.api.identity.AuthorId;
|
||||
import org.briarproject.bramble.api.identity.AuthorInfo;
|
||||
import org.briarproject.bramble.api.identity.IdentityManager;
|
||||
import org.briarproject.bramble.api.identity.LocalAuthor;
|
||||
import org.briarproject.bramble.api.transport.KeyManager;
|
||||
import org.briarproject.bramble.test.BrambleMockTestCase;
|
||||
import org.briarproject.bramble.test.DbExpectations;
|
||||
import org.jmock.Expectations;
|
||||
import org.jmock.Mockery;
|
||||
import org.junit.Test;
|
||||
@@ -20,10 +25,20 @@ import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.Random;
|
||||
|
||||
import static java.util.Collections.emptyList;
|
||||
import static java.util.Collections.singletonList;
|
||||
import static org.briarproject.bramble.api.identity.AuthorConstants.MAX_AUTHOR_NAME_LENGTH;
|
||||
import static org.briarproject.bramble.api.identity.AuthorInfo.Status.OURSELVES;
|
||||
import static org.briarproject.bramble.api.identity.AuthorInfo.Status.UNKNOWN;
|
||||
import static org.briarproject.bramble.api.identity.AuthorInfo.Status.UNVERIFIED;
|
||||
import static org.briarproject.bramble.api.identity.AuthorInfo.Status.VERIFIED;
|
||||
import static org.briarproject.bramble.test.TestUtils.getAuthor;
|
||||
import static org.briarproject.bramble.test.TestUtils.getLocalAuthor;
|
||||
import static org.briarproject.bramble.test.TestUtils.getRandomId;
|
||||
import static org.briarproject.bramble.test.TestUtils.getSecretKey;
|
||||
import static org.briarproject.bramble.util.StringUtils.getRandomString;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNull;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
public class ContactManagerImplTest extends BrambleMockTestCase {
|
||||
@@ -31,16 +46,20 @@ public class ContactManagerImplTest extends BrambleMockTestCase {
|
||||
private final Mockery context = new Mockery();
|
||||
private final DatabaseComponent db = context.mock(DatabaseComponent.class);
|
||||
private final KeyManager keyManager = context.mock(KeyManager.class);
|
||||
private final IdentityManager identityManager =
|
||||
context.mock(IdentityManager.class);
|
||||
private final ContactManager contactManager;
|
||||
private final ContactId contactId = new ContactId(42);
|
||||
private final Author remote = getAuthor();
|
||||
private final AuthorId local = new AuthorId(getRandomId());
|
||||
private final LocalAuthor localAuthor = getLocalAuthor();
|
||||
private final String alias = getRandomString(MAX_AUTHOR_NAME_LENGTH);
|
||||
private final boolean verified = false, active = true;
|
||||
private final Contact contact =
|
||||
new Contact(contactId, remote, local, verified, active);
|
||||
new Contact(contactId, remote, local, alias, verified, active);
|
||||
|
||||
public ContactManagerImplTest() {
|
||||
contactManager = new ContactManagerImpl(db, keyManager);
|
||||
contactManager = new ContactManagerImpl(db, keyManager, identityManager);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -50,17 +69,14 @@ public class ContactManagerImplTest extends BrambleMockTestCase {
|
||||
boolean alice = new Random().nextBoolean();
|
||||
Transaction txn = new Transaction(null, false);
|
||||
|
||||
context.checking(new Expectations() {{
|
||||
oneOf(db).startTransaction(false);
|
||||
will(returnValue(txn));
|
||||
context.checking(new DbExpectations() {{
|
||||
oneOf(db).transactionWithResult(with(false), withDbCallable(txn));
|
||||
oneOf(db).addContact(txn, remote, local, verified, active);
|
||||
will(returnValue(contactId));
|
||||
oneOf(keyManager).addContact(txn, contactId, master, timestamp,
|
||||
alice, active);
|
||||
oneOf(db).getContact(txn, contactId);
|
||||
will(returnValue(contact));
|
||||
oneOf(db).commitTransaction(txn);
|
||||
oneOf(db).endTransaction(txn);
|
||||
}});
|
||||
|
||||
assertEquals(contactId, contactManager.addContact(remote, local,
|
||||
@@ -70,13 +86,10 @@ public class ContactManagerImplTest extends BrambleMockTestCase {
|
||||
@Test
|
||||
public void testGetContact() throws Exception {
|
||||
Transaction txn = new Transaction(null, true);
|
||||
context.checking(new Expectations() {{
|
||||
oneOf(db).startTransaction(true);
|
||||
will(returnValue(txn));
|
||||
context.checking(new DbExpectations() {{
|
||||
oneOf(db).transactionWithResult(with(true), withDbCallable(txn));
|
||||
oneOf(db).getContact(txn, contactId);
|
||||
will(returnValue(contact));
|
||||
oneOf(db).commitTransaction(txn);
|
||||
oneOf(db).endTransaction(txn);
|
||||
}});
|
||||
|
||||
assertEquals(contact, contactManager.getContact(contactId));
|
||||
@@ -86,13 +99,10 @@ public class ContactManagerImplTest extends BrambleMockTestCase {
|
||||
public void testGetContactByAuthor() throws Exception {
|
||||
Transaction txn = new Transaction(null, true);
|
||||
Collection<Contact> contacts = Collections.singleton(contact);
|
||||
context.checking(new Expectations() {{
|
||||
oneOf(db).startTransaction(true);
|
||||
will(returnValue(txn));
|
||||
context.checking(new DbExpectations() {{
|
||||
oneOf(db).transactionWithResult(with(true), withDbCallable(txn));
|
||||
oneOf(db).getContactsByAuthorId(txn, remote.getId());
|
||||
will(returnValue(contacts));
|
||||
oneOf(db).commitTransaction(txn);
|
||||
oneOf(db).endTransaction(txn);
|
||||
}});
|
||||
|
||||
assertEquals(contact, contactManager.getContact(remote.getId(), local));
|
||||
@@ -101,12 +111,10 @@ public class ContactManagerImplTest extends BrambleMockTestCase {
|
||||
@Test(expected = NoSuchContactException.class)
|
||||
public void testGetContactByUnknownAuthor() throws Exception {
|
||||
Transaction txn = new Transaction(null, true);
|
||||
context.checking(new Expectations() {{
|
||||
oneOf(db).startTransaction(true);
|
||||
will(returnValue(txn));
|
||||
context.checking(new DbExpectations() {{
|
||||
oneOf(db).transactionWithResult(with(true), withDbCallable(txn));
|
||||
oneOf(db).getContactsByAuthorId(txn, remote.getId());
|
||||
will(returnValue(Collections.emptyList()));
|
||||
oneOf(db).endTransaction(txn);
|
||||
will(returnValue(emptyList()));
|
||||
}});
|
||||
|
||||
contactManager.getContact(remote.getId(), local);
|
||||
@@ -116,30 +124,26 @@ public class ContactManagerImplTest extends BrambleMockTestCase {
|
||||
public void testGetContactByUnknownLocalAuthor() throws Exception {
|
||||
Transaction txn = new Transaction(null, true);
|
||||
Collection<Contact> contacts = Collections.singleton(contact);
|
||||
context.checking(new Expectations() {{
|
||||
oneOf(db).startTransaction(true);
|
||||
will(returnValue(txn));
|
||||
context.checking(new DbExpectations() {{
|
||||
oneOf(db).transactionWithResult(with(true), withDbCallable(txn));
|
||||
oneOf(db).getContactsByAuthorId(txn, remote.getId());
|
||||
will(returnValue(contacts));
|
||||
oneOf(db).endTransaction(txn);
|
||||
}});
|
||||
|
||||
contactManager.getContact(remote.getId(), new AuthorId(getRandomId()));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testActiveContacts() throws Exception {
|
||||
public void testGetActiveContacts() throws Exception {
|
||||
Collection<Contact> activeContacts = Collections.singletonList(contact);
|
||||
Collection<Contact> contacts = new ArrayList<>(activeContacts);
|
||||
contacts.add(new Contact(new ContactId(3), remote, local, true, false));
|
||||
contacts.add(new Contact(new ContactId(3), remote, local, alias, true,
|
||||
false));
|
||||
Transaction txn = new Transaction(null, true);
|
||||
context.checking(new Expectations() {{
|
||||
oneOf(db).startTransaction(true);
|
||||
will(returnValue(txn));
|
||||
context.checking(new DbExpectations() {{
|
||||
oneOf(db).transactionWithResult(with(true), withDbCallable(txn));
|
||||
oneOf(db).getContacts(txn);
|
||||
will(returnValue(contacts));
|
||||
oneOf(db).commitTransaction(txn);
|
||||
oneOf(db).endTransaction(txn);
|
||||
}});
|
||||
|
||||
assertEquals(activeContacts, contactManager.getActiveContacts());
|
||||
@@ -148,14 +152,11 @@ public class ContactManagerImplTest extends BrambleMockTestCase {
|
||||
@Test
|
||||
public void testRemoveContact() throws Exception {
|
||||
Transaction txn = new Transaction(null, false);
|
||||
context.checking(new Expectations() {{
|
||||
oneOf(db).startTransaction(false);
|
||||
will(returnValue(txn));
|
||||
context.checking(new DbExpectations() {{
|
||||
oneOf(db).transaction(with(false), withDbRunnable(txn));
|
||||
oneOf(db).getContact(txn, contactId);
|
||||
will(returnValue(contact));
|
||||
oneOf(db).removeContact(txn, contactId);
|
||||
oneOf(db).commitTransaction(txn);
|
||||
oneOf(db).endTransaction(txn);
|
||||
}});
|
||||
|
||||
contactManager.removeContact(contactId);
|
||||
@@ -171,19 +172,108 @@ public class ContactManagerImplTest extends BrambleMockTestCase {
|
||||
contactManager.setContactActive(txn, contactId, active);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSetContactAlias() throws Exception {
|
||||
Transaction txn = new Transaction(null, false);
|
||||
context.checking(new DbExpectations() {{
|
||||
oneOf(db).transaction(with(false), withDbRunnable(txn));
|
||||
oneOf(db).setContactAlias(txn, contactId, alias);
|
||||
}});
|
||||
|
||||
contactManager.setContactAlias(contactId, alias);
|
||||
}
|
||||
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void testSetContactAliasTooLong() throws Exception {
|
||||
Transaction txn = new Transaction(null, false);
|
||||
contactManager.setContactAlias(txn, contactId,
|
||||
getRandomString(MAX_AUTHOR_NAME_LENGTH + 1));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testContactExists() throws Exception {
|
||||
Transaction txn = new Transaction(null, true);
|
||||
context.checking(new Expectations() {{
|
||||
oneOf(db).startTransaction(true);
|
||||
will(returnValue(txn));
|
||||
context.checking(new DbExpectations() {{
|
||||
oneOf(db).transactionWithResult(with(true), withDbCallable(txn));
|
||||
oneOf(db).containsContact(txn, remote.getId(), local);
|
||||
will(returnValue(true));
|
||||
oneOf(db).commitTransaction(txn);
|
||||
oneOf(db).endTransaction(txn);
|
||||
}});
|
||||
|
||||
assertTrue(contactManager.contactExists(remote.getId(), local));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetAuthorInfo() throws Exception {
|
||||
Transaction txn = new Transaction(null, true);
|
||||
Collection<Contact> contacts = singletonList(
|
||||
new Contact(new ContactId(1), remote, localAuthor.getId(),
|
||||
alias, false, true));
|
||||
|
||||
context.checking(new DbExpectations() {{
|
||||
oneOf(db).transactionWithResult(with(true), withDbCallable(txn));
|
||||
oneOf(identityManager).getLocalAuthor(txn);
|
||||
will(returnValue(localAuthor));
|
||||
oneOf(db).getContactsByAuthorId(txn, remote.getId());
|
||||
will(returnValue(contacts));
|
||||
}});
|
||||
AuthorInfo authorInfo =
|
||||
contactManager.getAuthorInfo(txn, remote.getId());
|
||||
assertEquals(UNVERIFIED, authorInfo.getStatus());
|
||||
assertEquals(alias, contact.getAlias());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetAuthorInfoTransaction() throws DbException {
|
||||
Transaction txn = new Transaction(null, true);
|
||||
|
||||
// check unknown author
|
||||
context.checking(new Expectations() {{
|
||||
oneOf(identityManager).getLocalAuthor(txn);
|
||||
will(returnValue(localAuthor));
|
||||
oneOf(db).getContactsByAuthorId(txn, remote.getId());
|
||||
will(returnValue(emptyList()));
|
||||
}});
|
||||
AuthorInfo authorInfo =
|
||||
contactManager.getAuthorInfo(txn, remote.getId());
|
||||
assertEquals(UNKNOWN, authorInfo.getStatus());
|
||||
assertNull(authorInfo.getAlias());
|
||||
|
||||
// check unverified contact
|
||||
Collection<Contact> contacts = singletonList(
|
||||
new Contact(new ContactId(1), remote, localAuthor.getId(),
|
||||
alias, false, true));
|
||||
checkAuthorInfoContext(txn, remote.getId(), contacts);
|
||||
authorInfo = contactManager.getAuthorInfo(txn, remote.getId());
|
||||
assertEquals(UNVERIFIED, authorInfo.getStatus());
|
||||
assertEquals(alias, contact.getAlias());
|
||||
|
||||
// check verified contact
|
||||
contacts = singletonList(new Contact(new ContactId(1), remote,
|
||||
localAuthor.getId(), alias, true, true));
|
||||
checkAuthorInfoContext(txn, remote.getId(), contacts);
|
||||
authorInfo = contactManager.getAuthorInfo(txn, remote.getId());
|
||||
assertEquals(VERIFIED, authorInfo.getStatus());
|
||||
assertEquals(alias, contact.getAlias());
|
||||
|
||||
// check ourselves
|
||||
context.checking(new Expectations() {{
|
||||
oneOf(identityManager).getLocalAuthor(txn);
|
||||
will(returnValue(localAuthor));
|
||||
never(db).getContactsByAuthorId(txn, remote.getId());
|
||||
}});
|
||||
authorInfo = contactManager.getAuthorInfo(txn, localAuthor.getId());
|
||||
assertEquals(OURSELVES, authorInfo.getStatus());
|
||||
assertNull(authorInfo.getAlias());
|
||||
}
|
||||
|
||||
private void checkAuthorInfoContext(Transaction txn, AuthorId authorId,
|
||||
Collection<Contact> contacts) throws DbException {
|
||||
context.checking(new Expectations() {{
|
||||
oneOf(identityManager).getLocalAuthor(txn);
|
||||
will(returnValue(localAuthor));
|
||||
oneOf(db).getContactsByAuthorId(txn, authorId);
|
||||
will(returnValue(contacts));
|
||||
}});
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,41 @@
|
||||
package org.briarproject.bramble.data;
|
||||
|
||||
import org.briarproject.bramble.test.BrambleTestCase;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.util.Random;
|
||||
|
||||
import static org.briarproject.bramble.api.data.BdfReader.DEFAULT_MAX_BUFFER_SIZE;
|
||||
import static org.briarproject.bramble.api.data.BdfReader.DEFAULT_NESTED_LIMIT;
|
||||
import static org.briarproject.bramble.test.TestUtils.isOptionalTestEnabled;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.junit.Assume.assumeTrue;
|
||||
|
||||
public class BdfReaderImplFuzzingTest extends BrambleTestCase {
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
assumeTrue(isOptionalTestEnabled(BdfReaderImplFuzzingTest.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testStringFuzzing() throws Exception {
|
||||
Random random = new Random();
|
||||
byte[] buf = new byte[22];
|
||||
ByteArrayInputStream in = new ByteArrayInputStream(buf);
|
||||
for (int i = 0; i < 100_000_000; i++) {
|
||||
random.nextBytes(buf);
|
||||
buf[0] = 0x41; // String with 1-byte length
|
||||
buf[1] = 0x14; // Length 20 bytes
|
||||
in.reset();
|
||||
BdfReaderImpl r = new BdfReaderImpl(in, DEFAULT_NESTED_LIMIT,
|
||||
DEFAULT_MAX_BUFFER_SIZE);
|
||||
int length = r.readString().length();
|
||||
assertTrue(length >= 0);
|
||||
assertTrue(length <= 20);
|
||||
assertTrue(r.eof());
|
||||
}
|
||||
}
|
||||
}
|
||||
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