mirror of
https://code.briarproject.org/briar/briar.git
synced 2026-02-12 10:49:06 +01:00
Compare commits
133 Commits
Alarms
...
ci-debuggi
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b02d89967e | ||
|
|
65ce049737 | ||
|
|
335c360ef8 | ||
|
|
fc26aaa168 | ||
|
|
88224793c1 | ||
|
|
0bf74f6a69 | ||
|
|
4286621b02 | ||
|
|
b3e3b970ab | ||
|
|
ef10a08165 | ||
|
|
094e1f8b65 | ||
|
|
8b58bdb289 | ||
|
|
7f61061f15 | ||
|
|
cd127670bb | ||
|
|
a9b412be40 | ||
|
|
413360db09 | ||
|
|
e5112ae9ee | ||
|
|
f399ce9290 | ||
|
|
30e036c672 | ||
|
|
2896700e50 | ||
|
|
987baba3bc | ||
|
|
03191ff08f | ||
|
|
42031631dd | ||
|
|
64e30844b8 | ||
|
|
30a070dd13 | ||
|
|
4f18303a1f | ||
|
|
5c500fb740 | ||
|
|
4d63272c04 | ||
|
|
16b09b9380 | ||
|
|
a1599df712 | ||
|
|
afa3c3a70e | ||
|
|
0f37a43415 | ||
|
|
ef1d5d3233 | ||
|
|
feab825865 | ||
|
|
5d2c96f916 | ||
|
|
02ff37b187 | ||
|
|
6863727646 | ||
|
|
087d6e9931 | ||
|
|
d79f1b667a | ||
|
|
633f5a8bd7 | ||
|
|
90cb9a2fae | ||
|
|
fc86319e13 | ||
|
|
af1ed292ae | ||
|
|
5393127400 | ||
|
|
0e6c374d0e | ||
|
|
52efbcac8a | ||
|
|
acf6a45004 | ||
|
|
7ffcace228 | ||
|
|
e157fdfc7b | ||
|
|
f8a8c0d8b8 | ||
|
|
f53aeef0d6 | ||
|
|
f812acb00b | ||
|
|
004467e84e | ||
|
|
34c0a83e36 | ||
|
|
fd0dad8936 | ||
|
|
32420a0781 | ||
|
|
b6c85c8bf6 | ||
|
|
4163731ec3 | ||
|
|
8e732d880f | ||
|
|
0b2594a693 | ||
|
|
7e009ceaf2 | ||
|
|
b238b28ef9 | ||
|
|
edb8e8f9d0 | ||
|
|
cc6041e90c | ||
|
|
3ff6462899 | ||
|
|
6f7d0c6f77 | ||
|
|
412381f37e | ||
|
|
05fbb87c06 | ||
|
|
daf5db470f | ||
|
|
be2d695150 | ||
|
|
d0c2c03057 | ||
|
|
db11e0101a | ||
|
|
25b8932cde | ||
|
|
0d658513ba | ||
|
|
732bf6d4ec | ||
|
|
53762e7c93 | ||
|
|
5a145c9eb2 | ||
|
|
d8ce1d75ca | ||
|
|
77b2fa8acb | ||
|
|
f9d5873385 | ||
|
|
1de6c863df | ||
|
|
8c5c66fa9a | ||
|
|
82f939ecd4 | ||
|
|
1a5c02f8a9 | ||
|
|
16d56535ca | ||
|
|
dcd6fda046 | ||
|
|
2535445831 | ||
|
|
c0d5a3a5ea | ||
|
|
c1789a8e52 | ||
|
|
2a0ecc3f80 | ||
|
|
b176ec5844 | ||
|
|
f8df6b88ee | ||
|
|
55d8f853db | ||
|
|
004853a09b | ||
|
|
d815dd6ec9 | ||
|
|
f243ed39ab | ||
|
|
4aed0632b8 | ||
|
|
1860db10b4 | ||
|
|
cf4efbeef3 | ||
|
|
099e8ef4d5 | ||
|
|
05152eef0e | ||
|
|
481de00f90 | ||
|
|
277d045469 | ||
|
|
287f3760cd | ||
|
|
58d09d0742 | ||
|
|
14353653c7 | ||
|
|
adbfa26364 | ||
|
|
abaefacb69 | ||
|
|
6ca0339da2 | ||
|
|
4a9977fa58 | ||
|
|
f9d8c720ec | ||
|
|
1edf2bfa75 | ||
|
|
233af69909 | ||
|
|
6f6ba38de1 | ||
|
|
f9495b49d6 | ||
|
|
cb29c9bf32 | ||
|
|
8283760e8a | ||
|
|
e300245f8d | ||
|
|
81cbb7e843 | ||
|
|
bc0e529d89 | ||
|
|
c6b6bc307e | ||
|
|
b200dd9323 | ||
|
|
881d8034cb | ||
|
|
1bee58e70d | ||
|
|
ede33d9278 | ||
|
|
ce6293b1d3 | ||
|
|
912dd0eb4a | ||
|
|
06197295f8 | ||
|
|
6a163c0358 | ||
|
|
aa6b5511c2 | ||
|
|
1cbd76bbc9 | ||
|
|
ba4a4aea59 | ||
|
|
391e869d29 | ||
|
|
8925d6f5d7 |
1
.gitignore
vendored
1
.gitignore
vendored
@@ -23,5 +23,6 @@ local.properties
|
|||||||
!.idea/codeStyles
|
!.idea/codeStyles
|
||||||
.gradle
|
.gradle
|
||||||
build/
|
build/
|
||||||
|
captures
|
||||||
*.iml
|
*.iml
|
||||||
projectFilesBackup/
|
projectFilesBackup/
|
||||||
@@ -11,8 +11,8 @@ test:
|
|||||||
- .gradle/caches
|
- .gradle/caches
|
||||||
|
|
||||||
script:
|
script:
|
||||||
- ./gradlew --no-daemon animalSnifferMain animalSnifferTest
|
- ./gradlew --no-daemon -Djava.security.egd=file:/dev/urandom animalSnifferMain animalSnifferTest
|
||||||
- ./gradlew --no-daemon test
|
- ./gradlew --no-daemon -Djava.security.egd=file:/dev/urandom test
|
||||||
|
|
||||||
after_script:
|
after_script:
|
||||||
# these file change every time but should not be cached
|
# these file change every time but should not be cached
|
||||||
|
|||||||
1
.idea/runConfigurations/All_tests.xml
generated
1
.idea/runConfigurations/All_tests.xml
generated
@@ -21,6 +21,7 @@
|
|||||||
<method>
|
<method>
|
||||||
<option name="RunConfigurationTask" enabled="true" run_configuration_name="All tests in bramble-api" run_configuration_type="AndroidJUnit" />
|
<option name="RunConfigurationTask" enabled="true" run_configuration_name="All tests in bramble-api" run_configuration_type="AndroidJUnit" />
|
||||||
<option name="RunConfigurationTask" enabled="true" run_configuration_name="All tests in bramble-core" run_configuration_type="AndroidJUnit" />
|
<option name="RunConfigurationTask" enabled="true" run_configuration_name="All tests in bramble-core" run_configuration_type="AndroidJUnit" />
|
||||||
|
<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-j2se" run_configuration_type="AndroidJUnit" />
|
<option name="RunConfigurationTask" enabled="true" run_configuration_name="All tests in bramble-j2se" 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 tests in briar-core" run_configuration_type="AndroidJUnit" />
|
||||||
</method>
|
</method>
|
||||||
|
|||||||
23
.idea/runConfigurations/All_tests_in_bramble_android.xml
generated
Normal file
23
.idea/runConfigurations/All_tests_in_bramble_android.xml
generated
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
<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" />
|
||||||
|
<option name="PACKAGE_NAME" value="" />
|
||||||
|
<option name="MAIN_CLASS_NAME" value="" />
|
||||||
|
<option name="METHOD_NAME" value="" />
|
||||||
|
<option name="TEST_OBJECT" value="package" />
|
||||||
|
<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>
|
||||||
|
</component>
|
||||||
@@ -1,5 +1,6 @@
|
|||||||
apply plugin: 'com.android.library'
|
apply plugin: 'com.android.library'
|
||||||
apply plugin: 'witness'
|
apply plugin: 'witness'
|
||||||
|
apply from: 'witness.gradle'
|
||||||
|
|
||||||
android {
|
android {
|
||||||
compileSdkVersion 27
|
compileSdkVersion 27
|
||||||
@@ -8,8 +9,8 @@ android {
|
|||||||
defaultConfig {
|
defaultConfig {
|
||||||
minSdkVersion 14
|
minSdkVersion 14
|
||||||
targetSdkVersion 26
|
targetSdkVersion 26
|
||||||
versionCode 10011
|
versionCode 10013
|
||||||
versionName "1.0.11"
|
versionName "1.0.13"
|
||||||
consumerProguardFiles 'proguard-rules.txt'
|
consumerProguardFiles 'proguard-rules.txt'
|
||||||
|
|
||||||
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
|
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
|
||||||
@@ -27,13 +28,20 @@ configurations {
|
|||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
implementation project(path: ':bramble-core', configuration: 'default')
|
implementation project(path: ':bramble-core', configuration: 'default')
|
||||||
implementation 'org.briarproject:jtorctl:0.3'
|
tor 'org.briarproject:tor-android:0.2.9.16@zip'
|
||||||
tor 'org.briarproject:tor-android:0.2.9.15@zip'
|
|
||||||
|
|
||||||
annotationProcessor 'com.google.dagger:dagger-compiler:2.0.2'
|
annotationProcessor 'com.google.dagger:dagger-compiler:2.0.2'
|
||||||
|
|
||||||
compileOnly 'javax.annotation:jsr250-api:1.0'
|
compileOnly 'javax.annotation:jsr250-api:1.0'
|
||||||
|
|
||||||
|
testImplementation project(path: ':bramble-api', configuration: 'testOutput')
|
||||||
|
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"
|
||||||
|
|
||||||
androidTestImplementation project(path: ':bramble-api', configuration: 'testOutput')
|
androidTestImplementation project(path: ':bramble-api', configuration: 'testOutput')
|
||||||
androidTestImplementation project(path: ':bramble-core', configuration: 'testOutput')
|
androidTestImplementation project(path: ':bramble-core', configuration: 'testOutput')
|
||||||
androidTestImplementation 'com.android.support.test:runner:1.0.2'
|
androidTestImplementation 'com.android.support.test:runner:1.0.2'
|
||||||
@@ -41,89 +49,14 @@ dependencies {
|
|||||||
androidTestCompileOnly 'javax.annotation:jsr250-api:1.0'
|
androidTestCompileOnly 'javax.annotation:jsr250-api:1.0'
|
||||||
}
|
}
|
||||||
|
|
||||||
dependencyVerification {
|
|
||||||
verify = [
|
|
||||||
'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.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.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.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: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',
|
|
||||||
'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',
|
|
||||||
'javax.xml.bind:jaxb-api:2.2.12-b140109.1041:jaxb-api-2.2.12-b140109.1041.jar:b5e60cd8b7b5ff01ce4a74c5dd008f4fbd14ced3495d0b47b85cfedc182211f2',
|
|
||||||
'net.sf.jopt-simple:jopt-simple:4.9:jopt-simple-4.9.jar:26c5856e954b5f864db76f13b86919b59c6eecf9fd930b96baa8884626baf2f5',
|
|
||||||
'net.sf.kxml:kxml2:2.3.0:kxml2-2.3.0.jar:f264dd9f79a1fde10ce5ecc53221eff24be4c9331c830b7d52f2f08a7b633de2',
|
|
||||||
'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.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:jtorctl:0.3:jtorctl-0.3.jar:f2939238a097898998432effe93b0334d97a787972ab3a91a8973a1d309fc864',
|
|
||||||
'org.briarproject:tor-android:0.2.9.15:tor-android-0.2.9.15.zip:34a6474ee219ffa52e0f3393e917dda6ed03d320b02247d4fa5075aa4094ee6d',
|
|
||||||
'org.codehaus.groovy:groovy-all:2.4.12:groovy-all-2.4.12.jar:6a56af4bd48903d56bec62821876cadefafd007360cc6bd0d8f7aa8d72b38be4',
|
|
||||||
'org.codehaus.mojo:animal-sniffer-annotations:1.14:animal-sniffer-annotations-1.14.jar:2068320bd6bad744c3673ab048f67e30bef8f518996fa380033556600669905d',
|
|
||||||
'org.glassfish.jaxb:jaxb-core:2.2.11:jaxb-core-2.2.11.jar:37bcaee8ebb04362c8352a5bf6221b86967ecdab5164c696b10b9a2bb587b2aa',
|
|
||||||
'org.glassfish.jaxb:jaxb-runtime:2.2.11:jaxb-runtime-2.2.11.jar:a874f2351cfba8e2946be3002d10c18a6da8f21b52ba2acf52f2b85d5520ed70',
|
|
||||||
'org.glassfish.jaxb:txw2:2.2.11:txw2-2.2.11.jar:272a3ccad45a4511351920cd2a8633c53cab8d5220c7a92954da5526bb5eafea',
|
|
||||||
'org.jetbrains.kotlin:kotlin-reflect:1.2.0:kotlin-reflect-1.2.0.jar:4f48a872bad6e4d9c053f4ad610d11e4012ad7e58dc19a03dd5eb811f36069dd',
|
|
||||||
'org.jetbrains.kotlin:kotlin-stdlib-jre7:1.2.0:kotlin-stdlib-jre7-1.2.0.jar:c7a20fb951d437797afe8980aff6c1e5a03f310c661ba58ba1d4fa90cb0f2926',
|
|
||||||
'org.jetbrains.kotlin:kotlin-stdlib-jre8:1.2.0:kotlin-stdlib-jre8-1.2.0.jar:633524eee6ef1941f7cb1dab7ee3927b0a221ceee9047aeb5515f4cbb990c82a',
|
|
||||||
'org.jetbrains.kotlin:kotlin-stdlib:1.2.0:kotlin-stdlib-1.2.0.jar:05cfd9f5ac0b41910703a8925f7211a495909b27a2ffdd1c5106f1689aeafcd4',
|
|
||||||
'org.jetbrains.trove4j:trove4j:20160824:trove4j-20160824.jar:1917871c8deb468307a584680c87a44572f5a8b0b98c6d397fc0f5f86596dbe7',
|
|
||||||
'org.jetbrains:annotations:13.0:annotations-13.0.jar:ace2a10dc8e2d5fd34925ecac03e4988b2c0f851650c94b8cef49ba1bd111478',
|
|
||||||
'org.jvnet.staxex:stax-ex:1.7.7:stax-ex-1.7.7.jar:a31ff7d77163c0deb09e7fee59ad35ae44c2cee2cc8552a116ccd1583d813fb4',
|
|
||||||
'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:5.1:asm-5.1.jar:d2da399a9967c69f0a21739256fa79d284222c223082cacadc17372244764b54',
|
|
||||||
]
|
|
||||||
}
|
|
||||||
|
|
||||||
project.afterEvaluate {
|
project.afterEvaluate {
|
||||||
copy {
|
copy {
|
||||||
from configurations.tor.collect { zipTree(it) }
|
from configurations.tor.collect { zipTree(it) }
|
||||||
into 'src/main/res/raw'
|
into 'src/main/res/raw'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
tasks.withType(Test) {
|
||||||
|
// Use entropy-gathering device specified on command line, if any
|
||||||
|
systemProperty 'java.security.egd', System.getProperty('java.security.egd')
|
||||||
|
}
|
||||||
|
|||||||
@@ -3,14 +3,16 @@ package org.briarproject.bramble.plugin.tor;
|
|||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.support.test.runner.AndroidJUnit4;
|
import android.support.test.runner.AndroidJUnit4;
|
||||||
|
|
||||||
import org.briarproject.bramble.DaggerIntegrationTestComponent;
|
|
||||||
import org.briarproject.bramble.IntegrationTestComponent;
|
|
||||||
import org.briarproject.bramble.api.event.EventBus;
|
import org.briarproject.bramble.api.event.EventBus;
|
||||||
|
import org.briarproject.bramble.api.network.NetworkManager;
|
||||||
import org.briarproject.bramble.api.plugin.BackoffFactory;
|
import org.briarproject.bramble.api.plugin.BackoffFactory;
|
||||||
import org.briarproject.bramble.api.plugin.duplex.DuplexPlugin;
|
import org.briarproject.bramble.api.plugin.duplex.DuplexPlugin;
|
||||||
import org.briarproject.bramble.api.system.Clock;
|
import org.briarproject.bramble.api.system.Clock;
|
||||||
import org.briarproject.bramble.api.system.LocationUtils;
|
import org.briarproject.bramble.api.system.LocationUtils;
|
||||||
|
import org.briarproject.bramble.api.system.ResourceProvider;
|
||||||
|
import org.briarproject.bramble.test.BrambleAndroidIntegrationTestComponent;
|
||||||
import org.briarproject.bramble.test.BrambleTestCase;
|
import org.briarproject.bramble.test.BrambleTestCase;
|
||||||
|
import org.briarproject.bramble.test.DaggerBrambleAndroidIntegrationTestComponent;
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.junit.runner.RunWith;
|
import org.junit.runner.RunWith;
|
||||||
@@ -39,8 +41,14 @@ public class BridgeTest extends BrambleTestCase {
|
|||||||
private final static long TIMEOUT = SECONDS.toMillis(23);
|
private final static long TIMEOUT = SECONDS.toMillis(23);
|
||||||
|
|
||||||
private final static Logger LOG =
|
private final static Logger LOG =
|
||||||
Logger.getLogger(BridgeTest.class.getSimpleName());
|
Logger.getLogger(BridgeTest.class.getName());
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
NetworkManager networkManager;
|
||||||
|
@Inject
|
||||||
|
ResourceProvider resourceProvider;
|
||||||
|
@Inject
|
||||||
|
CircumventionProvider circumventionProvider;
|
||||||
@Inject
|
@Inject
|
||||||
EventBus eventBus;
|
EventBus eventBus;
|
||||||
@Inject
|
@Inject
|
||||||
@@ -48,15 +56,27 @@ public class BridgeTest extends BrambleTestCase {
|
|||||||
@Inject
|
@Inject
|
||||||
Clock clock;
|
Clock clock;
|
||||||
|
|
||||||
private final Context appContext = getTargetContext();
|
private final Context appContext =
|
||||||
private final CircumventionProvider circumventionProvider;
|
getTargetContext().getApplicationContext();
|
||||||
private final List<String> bridges;
|
|
||||||
private TorPluginFactory factory;
|
|
||||||
private volatile int currentBridge = 0;
|
|
||||||
|
|
||||||
public BridgeTest() {
|
private List<String> bridges;
|
||||||
super();
|
private AndroidTorPluginFactory factory;
|
||||||
circumventionProvider = new CircumventionProvider() {
|
|
||||||
|
private volatile String currentBridge = null;
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void setUp() {
|
||||||
|
BrambleAndroidIntegrationTestComponent component =
|
||||||
|
DaggerBrambleAndroidIntegrationTestComponent.builder().build();
|
||||||
|
component.inject(this);
|
||||||
|
|
||||||
|
Executor ioExecutor = Executors.newCachedThreadPool();
|
||||||
|
ScheduledExecutorService scheduler = new ScheduledThreadPoolExecutor(1);
|
||||||
|
LocationUtils locationUtils = () -> "US";
|
||||||
|
SocketFactory torSocketFactory = SocketFactory.getDefault();
|
||||||
|
|
||||||
|
bridges = circumventionProvider.getBridges();
|
||||||
|
CircumventionProvider bridgeProvider = new CircumventionProvider() {
|
||||||
@Override
|
@Override
|
||||||
public boolean isTorProbablyBlocked(String countryCode) {
|
public boolean isTorProbablyBlocked(String countryCode) {
|
||||||
return true;
|
return true;
|
||||||
@@ -69,45 +89,29 @@ public class BridgeTest extends BrambleTestCase {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<String> getBridges() {
|
public List<String> getBridges() {
|
||||||
return singletonList(bridges.get(currentBridge));
|
return singletonList(currentBridge);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
bridges = new CircumventionProviderImpl(appContext).getBridges();
|
factory = new AndroidTorPluginFactory(ioExecutor, scheduler, appContext,
|
||||||
}
|
networkManager, locationUtils, eventBus, torSocketFactory,
|
||||||
|
backoffFactory, resourceProvider, bridgeProvider, clock);
|
||||||
@Before
|
|
||||||
public void setUp() {
|
|
||||||
IntegrationTestComponent component =
|
|
||||||
DaggerIntegrationTestComponent.builder().build();
|
|
||||||
component.inject(this);
|
|
||||||
|
|
||||||
Executor ioExecutor = Executors.newCachedThreadPool();
|
|
||||||
ScheduledExecutorService scheduler = new ScheduledThreadPoolExecutor(1);
|
|
||||||
LocationUtils locationUtils = () -> "US";
|
|
||||||
SocketFactory torSocketFactory = SocketFactory.getDefault();
|
|
||||||
|
|
||||||
factory = new TorPluginFactory(ioExecutor, scheduler, appContext,
|
|
||||||
locationUtils, eventBus, torSocketFactory,
|
|
||||||
backoffFactory, circumventionProvider, clock);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testBridges() throws Exception {
|
public void testBridges() throws Exception {
|
||||||
assertTrue(bridges.size() > 0);
|
assertTrue(bridges.size() > 0);
|
||||||
|
|
||||||
for (int i = 0; i < bridges.size(); i++) {
|
for (String bridge : bridges) testBridge(bridge);
|
||||||
testBridge(i);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void testBridge(int bridge) throws Exception {
|
private void testBridge(String bridge) throws Exception {
|
||||||
DuplexPlugin duplexPlugin =
|
DuplexPlugin duplexPlugin =
|
||||||
factory.createPlugin(new TorPluginCallBack());
|
factory.createPlugin(new TorPluginCallBack());
|
||||||
assertNotNull(duplexPlugin);
|
assertNotNull(duplexPlugin);
|
||||||
TorPlugin plugin = (TorPlugin) duplexPlugin;
|
AndroidTorPlugin plugin = (AndroidTorPlugin) duplexPlugin;
|
||||||
|
|
||||||
currentBridge = bridge;
|
currentBridge = bridge;
|
||||||
LOG.warning("Testing " + bridges.get(currentBridge));
|
LOG.warning("Testing " + bridge);
|
||||||
try {
|
try {
|
||||||
plugin.start();
|
plugin.start();
|
||||||
long start = clock.currentTimeMillis();
|
long start = clock.currentTimeMillis();
|
||||||
|
|||||||
@@ -0,0 +1,20 @@
|
|||||||
|
package org.briarproject.bramble.test;
|
||||||
|
|
||||||
|
import android.app.Application;
|
||||||
|
|
||||||
|
import javax.inject.Singleton;
|
||||||
|
|
||||||
|
import dagger.Module;
|
||||||
|
import dagger.Provides;
|
||||||
|
|
||||||
|
import static android.support.test.InstrumentationRegistry.getTargetContext;
|
||||||
|
|
||||||
|
@Module
|
||||||
|
class ApplicationModule {
|
||||||
|
|
||||||
|
@Provides
|
||||||
|
@Singleton
|
||||||
|
Application provideApplication() {
|
||||||
|
return (Application) getTargetContext().getApplicationContext();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,5 +1,6 @@
|
|||||||
package org.briarproject.bramble;
|
package org.briarproject.bramble.test;
|
||||||
|
|
||||||
|
import org.briarproject.bramble.BrambleAndroidModule;
|
||||||
import org.briarproject.bramble.event.EventModule;
|
import org.briarproject.bramble.event.EventModule;
|
||||||
import org.briarproject.bramble.plugin.PluginModule;
|
import org.briarproject.bramble.plugin.PluginModule;
|
||||||
import org.briarproject.bramble.plugin.tor.BridgeTest;
|
import org.briarproject.bramble.plugin.tor.BridgeTest;
|
||||||
@@ -12,11 +13,13 @@ import dagger.Component;
|
|||||||
@Singleton
|
@Singleton
|
||||||
@Component(modules = {
|
@Component(modules = {
|
||||||
BrambleAndroidModule.class,
|
BrambleAndroidModule.class,
|
||||||
|
TestLifecycleModule.class,
|
||||||
|
ApplicationModule.class,
|
||||||
PluginModule.class, // needed for BackoffFactory
|
PluginModule.class, // needed for BackoffFactory
|
||||||
EventModule.class,
|
EventModule.class,
|
||||||
SystemModule.class,
|
SystemModule.class,
|
||||||
})
|
})
|
||||||
public interface IntegrationTestComponent {
|
public interface BrambleAndroidIntegrationTestComponent {
|
||||||
|
|
||||||
void inject(BridgeTest init);
|
void inject(BridgeTest init);
|
||||||
|
|
||||||
@@ -2,14 +2,13 @@
|
|||||||
package="org.briarproject.bramble"
|
package="org.briarproject.bramble"
|
||||||
xmlns:android="http://schemas.android.com/apk/res/android">
|
xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
|
||||||
<uses-feature android:name="android.hardware.bluetooth"/>
|
<uses-feature android:name="android.hardware.bluetooth" android:required="false"/>
|
||||||
|
|
||||||
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
|
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
|
||||||
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/>
|
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/>
|
||||||
<uses-permission android:name="android.permission.BLUETOOTH"/>
|
<uses-permission android:name="android.permission.BLUETOOTH"/>
|
||||||
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN"/>
|
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN"/>
|
||||||
<uses-permission android:name="android.permission.INTERNET"/>
|
<uses-permission android:name="android.permission.INTERNET"/>
|
||||||
<uses-permission android:name="android.permission.READ_LOGS"/>
|
|
||||||
<uses-permission android:name="android.permission.WAKE_LOCK"/>
|
<uses-permission android:name="android.permission.WAKE_LOCK"/>
|
||||||
|
|
||||||
<application
|
<application
|
||||||
|
|||||||
@@ -1,25 +1,16 @@
|
|||||||
package org.briarproject.bramble;
|
package org.briarproject.bramble;
|
||||||
|
|
||||||
import android.app.Application;
|
import org.briarproject.bramble.network.AndroidNetworkModule;
|
||||||
|
import org.briarproject.bramble.plugin.tor.CircumventionModule;
|
||||||
import org.briarproject.bramble.plugin.tor.CircumventionProvider;
|
|
||||||
import org.briarproject.bramble.plugin.tor.CircumventionProviderImpl;
|
|
||||||
import org.briarproject.bramble.system.AndroidSystemModule;
|
import org.briarproject.bramble.system.AndroidSystemModule;
|
||||||
|
|
||||||
import javax.inject.Singleton;
|
|
||||||
|
|
||||||
import dagger.Module;
|
import dagger.Module;
|
||||||
import dagger.Provides;
|
|
||||||
|
|
||||||
@Module(includes = {
|
@Module(includes = {
|
||||||
AndroidSystemModule.class
|
AndroidNetworkModule.class,
|
||||||
|
AndroidSystemModule.class,
|
||||||
|
CircumventionModule.class
|
||||||
})
|
})
|
||||||
public class BrambleAndroidModule {
|
public class BrambleAndroidModule {
|
||||||
|
|
||||||
@Provides
|
|
||||||
@Singleton
|
|
||||||
CircumventionProvider provideCircumventionProvider(Application app) {
|
|
||||||
return new CircumventionProviderImpl(app.getApplicationContext());
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,8 +0,0 @@
|
|||||||
package org.briarproject.bramble;
|
|
||||||
|
|
||||||
public interface PowerTestingConstants {
|
|
||||||
|
|
||||||
int WAKE_LOCK_DURATION = 5000;
|
|
||||||
int ALARM_DELAY = 5000;
|
|
||||||
boolean USE_TOR_WAKE_LOCK = true;
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,108 @@
|
|||||||
|
package org.briarproject.bramble.account;
|
||||||
|
|
||||||
|
import android.app.Application;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.content.SharedPreferences;
|
||||||
|
import android.preference.PreferenceManager;
|
||||||
|
|
||||||
|
import org.briarproject.bramble.api.account.AccountManager;
|
||||||
|
import org.briarproject.bramble.api.crypto.CryptoComponent;
|
||||||
|
import org.briarproject.bramble.api.db.DatabaseConfig;
|
||||||
|
import org.briarproject.bramble.api.identity.IdentityManager;
|
||||||
|
import org.briarproject.bramble.util.IoUtils;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
|
import javax.annotation.Nullable;
|
||||||
|
import javax.inject.Inject;
|
||||||
|
|
||||||
|
class AndroidAccountManager extends AccountManagerImpl
|
||||||
|
implements AccountManager {
|
||||||
|
|
||||||
|
private static final Logger LOG =
|
||||||
|
Logger.getLogger(AndroidAccountManager.class.getName());
|
||||||
|
|
||||||
|
private static final String PREF_DB_KEY = "key";
|
||||||
|
|
||||||
|
protected final Context appContext;
|
||||||
|
private final SharedPreferences prefs;
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
AndroidAccountManager(DatabaseConfig databaseConfig,
|
||||||
|
CryptoComponent crypto, IdentityManager identityManager,
|
||||||
|
SharedPreferences prefs, Application app) {
|
||||||
|
super(databaseConfig, crypto, identityManager);
|
||||||
|
this.prefs = prefs;
|
||||||
|
appContext = app.getApplicationContext();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Locking: stateChangeLock
|
||||||
|
@Override
|
||||||
|
@Nullable
|
||||||
|
protected String loadEncryptedDatabaseKey() {
|
||||||
|
String key = getDatabaseKeyFromPreferences();
|
||||||
|
if (key == null) key = super.loadEncryptedDatabaseKey();
|
||||||
|
else migrateDatabaseKeyToFile(key);
|
||||||
|
return key;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Locking: stateChangeLock
|
||||||
|
@Nullable
|
||||||
|
private String getDatabaseKeyFromPreferences() {
|
||||||
|
String key = prefs.getString(PREF_DB_KEY, null);
|
||||||
|
if (key == null) LOG.info("No database key in preferences");
|
||||||
|
else LOG.info("Found database key in preferences");
|
||||||
|
return key;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Locking: stateChangeLock
|
||||||
|
private void migrateDatabaseKeyToFile(String key) {
|
||||||
|
if (storeEncryptedDatabaseKey(key)) {
|
||||||
|
if (prefs.edit().remove(PREF_DB_KEY).commit())
|
||||||
|
LOG.info("Database key migrated to file");
|
||||||
|
else LOG.warning("Database key not removed from preferences");
|
||||||
|
} else {
|
||||||
|
LOG.warning("Database key not migrated to file");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void deleteAccount() {
|
||||||
|
synchronized (stateChangeLock) {
|
||||||
|
super.deleteAccount();
|
||||||
|
SharedPreferences defaultPrefs = getDefaultSharedPreferences();
|
||||||
|
deleteAppData(prefs, defaultPrefs);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Package access for testing
|
||||||
|
SharedPreferences getDefaultSharedPreferences() {
|
||||||
|
return PreferenceManager.getDefaultSharedPreferences(appContext);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Locking: stateChangeLock
|
||||||
|
private void deleteAppData(SharedPreferences... clear) {
|
||||||
|
// Clear and commit shared preferences
|
||||||
|
for (SharedPreferences prefs : clear) {
|
||||||
|
if (!prefs.edit().clear().commit())
|
||||||
|
LOG.warning("Could not clear shared preferences");
|
||||||
|
}
|
||||||
|
// Delete files, except lib and shared_prefs directories
|
||||||
|
File dataDir = new File(appContext.getApplicationInfo().dataDir);
|
||||||
|
File[] children = dataDir.listFiles();
|
||||||
|
if (children == null) {
|
||||||
|
LOG.warning("Could not list files in app data dir");
|
||||||
|
} else {
|
||||||
|
for (File child : children) {
|
||||||
|
String name = child.getName();
|
||||||
|
if (!name.equals("lib") && !name.equals("shared_prefs")) {
|
||||||
|
IoUtils.deleteFileOrDir(child);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Recreate the cache dir as some OpenGL drivers expect it to exist
|
||||||
|
if (!new File(dataDir, "cache").mkdir())
|
||||||
|
LOG.warning("Could not recreate cache dir");
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,142 @@
|
|||||||
|
package org.briarproject.bramble.network;
|
||||||
|
|
||||||
|
import android.app.Application;
|
||||||
|
import android.content.BroadcastReceiver;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.content.Intent;
|
||||||
|
import android.content.IntentFilter;
|
||||||
|
import android.net.ConnectivityManager;
|
||||||
|
import android.net.NetworkInfo;
|
||||||
|
|
||||||
|
import org.briarproject.bramble.api.event.EventBus;
|
||||||
|
import org.briarproject.bramble.api.lifecycle.Service;
|
||||||
|
import org.briarproject.bramble.api.network.NetworkManager;
|
||||||
|
import org.briarproject.bramble.api.network.NetworkStatus;
|
||||||
|
import org.briarproject.bramble.api.network.event.NetworkStatusEvent;
|
||||||
|
import org.briarproject.bramble.api.nullsafety.MethodsNotNullByDefault;
|
||||||
|
import org.briarproject.bramble.api.nullsafety.ParametersNotNullByDefault;
|
||||||
|
import org.briarproject.bramble.api.system.Scheduler;
|
||||||
|
|
||||||
|
import java.util.concurrent.Future;
|
||||||
|
import java.util.concurrent.ScheduledExecutorService;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
import java.util.concurrent.atomic.AtomicBoolean;
|
||||||
|
import java.util.concurrent.atomic.AtomicReference;
|
||||||
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
|
import javax.annotation.Nullable;
|
||||||
|
import javax.inject.Inject;
|
||||||
|
|
||||||
|
import static android.content.Context.CONNECTIVITY_SERVICE;
|
||||||
|
import static android.content.Intent.ACTION_SCREEN_OFF;
|
||||||
|
import static android.content.Intent.ACTION_SCREEN_ON;
|
||||||
|
import static android.net.ConnectivityManager.CONNECTIVITY_ACTION;
|
||||||
|
import static android.net.ConnectivityManager.TYPE_WIFI;
|
||||||
|
import static android.os.Build.VERSION.SDK_INT;
|
||||||
|
import static android.os.PowerManager.ACTION_DEVICE_IDLE_MODE_CHANGED;
|
||||||
|
import static java.util.concurrent.TimeUnit.MINUTES;
|
||||||
|
import static java.util.concurrent.TimeUnit.SECONDS;
|
||||||
|
import static java.util.logging.Level.INFO;
|
||||||
|
|
||||||
|
@MethodsNotNullByDefault
|
||||||
|
@ParametersNotNullByDefault
|
||||||
|
class AndroidNetworkManager implements NetworkManager, Service {
|
||||||
|
|
||||||
|
private static final Logger LOG =
|
||||||
|
Logger.getLogger(AndroidNetworkManager.class.getName());
|
||||||
|
|
||||||
|
// See android.net.wifi.WifiManager
|
||||||
|
private static final String WIFI_AP_STATE_CHANGED_ACTION =
|
||||||
|
"android.net.wifi.WIFI_AP_STATE_CHANGED";
|
||||||
|
|
||||||
|
private final ScheduledExecutorService scheduler;
|
||||||
|
private final EventBus eventBus;
|
||||||
|
private final Context appContext;
|
||||||
|
private final AtomicReference<Future<?>> connectivityCheck =
|
||||||
|
new AtomicReference<>();
|
||||||
|
private final AtomicBoolean used = new AtomicBoolean(false);
|
||||||
|
|
||||||
|
private volatile BroadcastReceiver networkStateReceiver = null;
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
AndroidNetworkManager(@Scheduler ScheduledExecutorService scheduler,
|
||||||
|
EventBus eventBus, Application app) {
|
||||||
|
this.scheduler = scheduler;
|
||||||
|
this.eventBus = eventBus;
|
||||||
|
this.appContext = app.getApplicationContext();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void startService() {
|
||||||
|
if (used.getAndSet(true)) throw new IllegalStateException();
|
||||||
|
// Register to receive network status events
|
||||||
|
networkStateReceiver = new NetworkStateReceiver();
|
||||||
|
IntentFilter filter = new IntentFilter();
|
||||||
|
filter.addAction(CONNECTIVITY_ACTION);
|
||||||
|
filter.addAction(ACTION_SCREEN_ON);
|
||||||
|
filter.addAction(ACTION_SCREEN_OFF);
|
||||||
|
filter.addAction(WIFI_AP_STATE_CHANGED_ACTION);
|
||||||
|
if (SDK_INT >= 23) filter.addAction(ACTION_DEVICE_IDLE_MODE_CHANGED);
|
||||||
|
appContext.registerReceiver(networkStateReceiver, filter);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void stopService() {
|
||||||
|
if (networkStateReceiver != null)
|
||||||
|
appContext.unregisterReceiver(networkStateReceiver);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public NetworkStatus getNetworkStatus() {
|
||||||
|
ConnectivityManager cm = (ConnectivityManager)
|
||||||
|
appContext.getSystemService(CONNECTIVITY_SERVICE);
|
||||||
|
if (cm == null) throw new AssertionError();
|
||||||
|
NetworkInfo net = cm.getActiveNetworkInfo();
|
||||||
|
boolean connected = net != null && net.isConnected();
|
||||||
|
boolean wifi = connected && net.getType() == TYPE_WIFI;
|
||||||
|
return new NetworkStatus(connected, wifi);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updateConnectionStatus() {
|
||||||
|
eventBus.broadcast(new NetworkStatusEvent(getNetworkStatus()));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void scheduleConnectionStatusUpdate(int delay, TimeUnit unit) {
|
||||||
|
Future<?> newConnectivityCheck =
|
||||||
|
scheduler.schedule(this::updateConnectionStatus, delay, unit);
|
||||||
|
Future<?> oldConnectivityCheck =
|
||||||
|
connectivityCheck.getAndSet(newConnectivityCheck);
|
||||||
|
if (oldConnectivityCheck != null) oldConnectivityCheck.cancel(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
private class NetworkStateReceiver extends BroadcastReceiver {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onReceive(Context ctx, Intent i) {
|
||||||
|
String action = i.getAction();
|
||||||
|
if (LOG.isLoggable(INFO)) LOG.info("Received broadcast " + action);
|
||||||
|
updateConnectionStatus();
|
||||||
|
if (isSleepOrDozeEvent(action)) {
|
||||||
|
// Allow time for the network to be enabled or disabled
|
||||||
|
scheduleConnectionStatusUpdate(1, MINUTES);
|
||||||
|
} else if (isApEvent(action)) {
|
||||||
|
// The state change may be broadcast before the AP address is
|
||||||
|
// visible, so delay handling the event
|
||||||
|
scheduleConnectionStatusUpdate(5, SECONDS);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isSleepOrDozeEvent(@Nullable String action) {
|
||||||
|
boolean isSleep = ACTION_SCREEN_ON.equals(action) ||
|
||||||
|
ACTION_SCREEN_OFF.equals(action);
|
||||||
|
boolean isDoze = SDK_INT >= 23 &&
|
||||||
|
ACTION_DEVICE_IDLE_MODE_CHANGED.equals(action);
|
||||||
|
return isSleep || isDoze;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isApEvent(@Nullable String action) {
|
||||||
|
return WIFI_AP_STATE_CHANGED_ACTION.equals(action);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
package org.briarproject.bramble.network;
|
||||||
|
|
||||||
|
import org.briarproject.bramble.api.lifecycle.LifecycleManager;
|
||||||
|
import org.briarproject.bramble.api.network.NetworkManager;
|
||||||
|
|
||||||
|
import javax.inject.Singleton;
|
||||||
|
|
||||||
|
import dagger.Module;
|
||||||
|
import dagger.Provides;
|
||||||
|
|
||||||
|
@Module
|
||||||
|
public class AndroidNetworkModule {
|
||||||
|
|
||||||
|
@Provides
|
||||||
|
@Singleton
|
||||||
|
NetworkManager provideNetworkManager(LifecycleManager lifecycleManager,
|
||||||
|
AndroidNetworkManager networkManager) {
|
||||||
|
lifecycleManager.registerService(networkManager);
|
||||||
|
return networkManager;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,15 +1,16 @@
|
|||||||
package org.briarproject.bramble.plugin.tcp;
|
package org.briarproject.bramble.plugin.tcp;
|
||||||
|
|
||||||
import android.content.BroadcastReceiver;
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.Intent;
|
|
||||||
import android.content.IntentFilter;
|
|
||||||
import android.net.ConnectivityManager;
|
import android.net.ConnectivityManager;
|
||||||
import android.net.Network;
|
import android.net.Network;
|
||||||
import android.net.NetworkInfo;
|
import android.net.NetworkInfo;
|
||||||
import android.net.wifi.WifiInfo;
|
import android.net.wifi.WifiInfo;
|
||||||
import android.net.wifi.WifiManager;
|
import android.net.wifi.WifiManager;
|
||||||
|
|
||||||
|
import org.briarproject.bramble.PoliteExecutor;
|
||||||
|
import org.briarproject.bramble.api.event.Event;
|
||||||
|
import org.briarproject.bramble.api.event.EventListener;
|
||||||
|
import org.briarproject.bramble.api.network.event.NetworkStatusEvent;
|
||||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||||
import org.briarproject.bramble.api.plugin.Backoff;
|
import org.briarproject.bramble.api.plugin.Backoff;
|
||||||
import org.briarproject.bramble.api.plugin.duplex.DuplexPluginCallback;
|
import org.briarproject.bramble.api.plugin.duplex.DuplexPluginCallback;
|
||||||
@@ -20,7 +21,6 @@ import java.net.Socket;
|
|||||||
import java.net.UnknownHostException;
|
import java.net.UnknownHostException;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.concurrent.Executor;
|
import java.util.concurrent.Executor;
|
||||||
import java.util.concurrent.ScheduledExecutorService;
|
|
||||||
import java.util.logging.Logger;
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
@@ -28,21 +28,13 @@ import javax.net.SocketFactory;
|
|||||||
|
|
||||||
import static android.content.Context.CONNECTIVITY_SERVICE;
|
import static android.content.Context.CONNECTIVITY_SERVICE;
|
||||||
import static android.content.Context.WIFI_SERVICE;
|
import static android.content.Context.WIFI_SERVICE;
|
||||||
import static android.net.ConnectivityManager.CONNECTIVITY_ACTION;
|
|
||||||
import static android.net.ConnectivityManager.TYPE_WIFI;
|
import static android.net.ConnectivityManager.TYPE_WIFI;
|
||||||
import static android.net.wifi.WifiManager.EXTRA_WIFI_STATE;
|
|
||||||
import static android.os.Build.VERSION.SDK_INT;
|
import static android.os.Build.VERSION.SDK_INT;
|
||||||
import static java.util.Collections.emptyList;
|
import static java.util.Collections.emptyList;
|
||||||
import static java.util.Collections.singletonList;
|
import static java.util.Collections.singletonList;
|
||||||
import static java.util.concurrent.TimeUnit.SECONDS;
|
|
||||||
|
|
||||||
@NotNullByDefault
|
@NotNullByDefault
|
||||||
class AndroidLanTcpPlugin extends LanTcpPlugin {
|
class AndroidLanTcpPlugin extends LanTcpPlugin implements EventListener {
|
||||||
|
|
||||||
// See android.net.wifi.WifiManager
|
|
||||||
private static final String WIFI_AP_STATE_CHANGED_ACTION =
|
|
||||||
"android.net.wifi.WIFI_AP_STATE_CHANGED";
|
|
||||||
private static final int WIFI_AP_STATE_ENABLED = 13;
|
|
||||||
|
|
||||||
private static final byte[] WIFI_AP_ADDRESS_BYTES =
|
private static final byte[] WIFI_AP_ADDRESS_BYTES =
|
||||||
{(byte) 192, (byte) 168, 43, 1};
|
{(byte) 192, (byte) 168, 43, 1};
|
||||||
@@ -60,22 +52,20 @@ class AndroidLanTcpPlugin extends LanTcpPlugin {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private final ScheduledExecutorService scheduler;
|
private final Executor connectionStatusExecutor;
|
||||||
private final Context appContext;
|
|
||||||
private final ConnectivityManager connectivityManager;
|
private final ConnectivityManager connectivityManager;
|
||||||
@Nullable
|
@Nullable
|
||||||
private final WifiManager wifiManager;
|
private final WifiManager wifiManager;
|
||||||
|
|
||||||
@Nullable
|
|
||||||
private volatile BroadcastReceiver networkStateReceiver = null;
|
|
||||||
private volatile SocketFactory socketFactory;
|
private volatile SocketFactory socketFactory;
|
||||||
|
|
||||||
AndroidLanTcpPlugin(Executor ioExecutor, ScheduledExecutorService scheduler,
|
AndroidLanTcpPlugin(Executor ioExecutor, Context appContext,
|
||||||
Backoff backoff, Context appContext, DuplexPluginCallback callback,
|
Backoff backoff, DuplexPluginCallback callback, int maxLatency,
|
||||||
int maxLatency, int maxIdleTime) {
|
int maxIdleTime) {
|
||||||
super(ioExecutor, backoff, callback, maxLatency, maxIdleTime);
|
super(ioExecutor, backoff, callback, maxLatency, maxIdleTime);
|
||||||
this.scheduler = scheduler;
|
// Don't execute more than one connection status check at a time
|
||||||
this.appContext = appContext;
|
connectionStatusExecutor =
|
||||||
|
new PoliteExecutor("AndroidLanTcpPlugin", ioExecutor, 1);
|
||||||
ConnectivityManager connectivityManager = (ConnectivityManager)
|
ConnectivityManager connectivityManager = (ConnectivityManager)
|
||||||
appContext.getSystemService(CONNECTIVITY_SERVICE);
|
appContext.getSystemService(CONNECTIVITY_SERVICE);
|
||||||
if (connectivityManager == null) throw new AssertionError();
|
if (connectivityManager == null) throw new AssertionError();
|
||||||
@@ -89,19 +79,12 @@ class AndroidLanTcpPlugin extends LanTcpPlugin {
|
|||||||
public void start() {
|
public void start() {
|
||||||
if (used.getAndSet(true)) throw new IllegalStateException();
|
if (used.getAndSet(true)) throw new IllegalStateException();
|
||||||
running = true;
|
running = true;
|
||||||
// Register to receive network status events
|
updateConnectionStatus();
|
||||||
networkStateReceiver = new NetworkStateReceiver();
|
|
||||||
IntentFilter filter = new IntentFilter();
|
|
||||||
filter.addAction(CONNECTIVITY_ACTION);
|
|
||||||
filter.addAction(WIFI_AP_STATE_CHANGED_ACTION);
|
|
||||||
appContext.registerReceiver(networkStateReceiver, filter);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void stop() {
|
public void stop() {
|
||||||
running = false;
|
running = false;
|
||||||
if (networkStateReceiver != null)
|
|
||||||
appContext.unregisterReceiver(networkStateReceiver);
|
|
||||||
tryToClose(socket);
|
tryToClose(socket);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -120,7 +103,7 @@ class AndroidLanTcpPlugin extends LanTcpPlugin {
|
|||||||
return singletonList(intToInetAddress(info.getIpAddress()));
|
return singletonList(intToInetAddress(info.getIpAddress()));
|
||||||
// If we're running an access point, return its address
|
// If we're running an access point, return its address
|
||||||
if (super.getLocalIpAddresses().contains(WIFI_AP_ADDRESS))
|
if (super.getLocalIpAddresses().contains(WIFI_AP_ADDRESS))
|
||||||
return singletonList(WIFI_AP_ADDRESS);
|
return singletonList(WIFI_AP_ADDRESS);
|
||||||
// No suitable addresses
|
// No suitable addresses
|
||||||
return emptyList();
|
return emptyList();
|
||||||
}
|
}
|
||||||
@@ -152,21 +135,13 @@ class AndroidLanTcpPlugin extends LanTcpPlugin {
|
|||||||
return SocketFactory.getDefault();
|
return SocketFactory.getDefault();
|
||||||
}
|
}
|
||||||
|
|
||||||
private class NetworkStateReceiver extends BroadcastReceiver {
|
@Override
|
||||||
|
public void eventOccurred(Event e) {
|
||||||
|
if (e instanceof NetworkStatusEvent) updateConnectionStatus();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
private void updateConnectionStatus() {
|
||||||
public void onReceive(Context ctx, Intent i) {
|
connectionStatusExecutor.execute(() -> {
|
||||||
if (!running) return;
|
|
||||||
if (isApEnabledEvent(i)) {
|
|
||||||
// The state change may be broadcast before the AP address is
|
|
||||||
// visible, so delay handling the event
|
|
||||||
scheduler.schedule(this::handleConnectivityChange, 1, SECONDS);
|
|
||||||
} else {
|
|
||||||
handleConnectivityChange();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void handleConnectivityChange() {
|
|
||||||
if (!running) return;
|
if (!running) return;
|
||||||
Collection<InetAddress> addrs = getLocalIpAddresses();
|
Collection<InetAddress> addrs = getLocalIpAddresses();
|
||||||
if (addrs.contains(WIFI_AP_ADDRESS)) {
|
if (addrs.contains(WIFI_AP_ADDRESS)) {
|
||||||
@@ -186,11 +161,6 @@ class AndroidLanTcpPlugin extends LanTcpPlugin {
|
|||||||
socketFactory = getSocketFactory();
|
socketFactory = getSocketFactory();
|
||||||
if (socket == null || socket.isClosed()) bind();
|
if (socket == null || socket.isClosed()) bind();
|
||||||
}
|
}
|
||||||
}
|
});
|
||||||
|
|
||||||
private boolean isApEnabledEvent(Intent i) {
|
|
||||||
return WIFI_AP_STATE_CHANGED_ACTION.equals(i.getAction()) &&
|
|
||||||
i.getIntExtra(EXTRA_WIFI_STATE, 0) == WIFI_AP_STATE_ENABLED;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -2,6 +2,7 @@ package org.briarproject.bramble.plugin.tcp;
|
|||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
|
|
||||||
|
import org.briarproject.bramble.api.event.EventBus;
|
||||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||||
import org.briarproject.bramble.api.plugin.Backoff;
|
import org.briarproject.bramble.api.plugin.Backoff;
|
||||||
import org.briarproject.bramble.api.plugin.BackoffFactory;
|
import org.briarproject.bramble.api.plugin.BackoffFactory;
|
||||||
@@ -11,7 +12,6 @@ import org.briarproject.bramble.api.plugin.duplex.DuplexPluginCallback;
|
|||||||
import org.briarproject.bramble.api.plugin.duplex.DuplexPluginFactory;
|
import org.briarproject.bramble.api.plugin.duplex.DuplexPluginFactory;
|
||||||
|
|
||||||
import java.util.concurrent.Executor;
|
import java.util.concurrent.Executor;
|
||||||
import java.util.concurrent.ScheduledExecutorService;
|
|
||||||
|
|
||||||
import javax.annotation.concurrent.Immutable;
|
import javax.annotation.concurrent.Immutable;
|
||||||
|
|
||||||
@@ -28,15 +28,14 @@ public class AndroidLanTcpPluginFactory implements DuplexPluginFactory {
|
|||||||
private static final double BACKOFF_BASE = 1.2;
|
private static final double BACKOFF_BASE = 1.2;
|
||||||
|
|
||||||
private final Executor ioExecutor;
|
private final Executor ioExecutor;
|
||||||
private final ScheduledExecutorService scheduler;
|
private final EventBus eventBus;
|
||||||
private final BackoffFactory backoffFactory;
|
private final BackoffFactory backoffFactory;
|
||||||
private final Context appContext;
|
private final Context appContext;
|
||||||
|
|
||||||
public AndroidLanTcpPluginFactory(Executor ioExecutor,
|
public AndroidLanTcpPluginFactory(Executor ioExecutor, EventBus eventBus,
|
||||||
ScheduledExecutorService scheduler, BackoffFactory backoffFactory,
|
BackoffFactory backoffFactory, Context appContext) {
|
||||||
Context appContext) {
|
|
||||||
this.ioExecutor = ioExecutor;
|
this.ioExecutor = ioExecutor;
|
||||||
this.scheduler = scheduler;
|
this.eventBus = eventBus;
|
||||||
this.backoffFactory = backoffFactory;
|
this.backoffFactory = backoffFactory;
|
||||||
this.appContext = appContext;
|
this.appContext = appContext;
|
||||||
}
|
}
|
||||||
@@ -55,7 +54,9 @@ public class AndroidLanTcpPluginFactory implements DuplexPluginFactory {
|
|||||||
public DuplexPlugin createPlugin(DuplexPluginCallback callback) {
|
public DuplexPlugin createPlugin(DuplexPluginCallback callback) {
|
||||||
Backoff backoff = backoffFactory.createBackoff(MIN_POLLING_INTERVAL,
|
Backoff backoff = backoffFactory.createBackoff(MIN_POLLING_INTERVAL,
|
||||||
MAX_POLLING_INTERVAL, BACKOFF_BASE);
|
MAX_POLLING_INTERVAL, BACKOFF_BASE);
|
||||||
return new AndroidLanTcpPlugin(ioExecutor, scheduler, backoff,
|
AndroidLanTcpPlugin plugin = new AndroidLanTcpPlugin(ioExecutor,
|
||||||
appContext, callback, MAX_LATENCY, MAX_IDLE_TIME);
|
appContext, backoff, callback, MAX_LATENCY, MAX_IDLE_TIME);
|
||||||
|
eventBus.addListener(plugin);
|
||||||
|
return plugin;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,88 @@
|
|||||||
|
package org.briarproject.bramble.plugin.tor;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.content.pm.PackageInfo;
|
||||||
|
import android.content.pm.PackageManager;
|
||||||
|
import android.content.pm.PackageManager.NameNotFoundException;
|
||||||
|
import android.os.PowerManager;
|
||||||
|
|
||||||
|
import org.briarproject.bramble.api.network.NetworkManager;
|
||||||
|
import org.briarproject.bramble.api.nullsafety.MethodsNotNullByDefault;
|
||||||
|
import org.briarproject.bramble.api.nullsafety.ParametersNotNullByDefault;
|
||||||
|
import org.briarproject.bramble.api.plugin.Backoff;
|
||||||
|
import org.briarproject.bramble.api.plugin.duplex.DuplexPluginCallback;
|
||||||
|
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.RenewableWakeLock;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.concurrent.Executor;
|
||||||
|
import java.util.concurrent.ScheduledExecutorService;
|
||||||
|
|
||||||
|
import javax.net.SocketFactory;
|
||||||
|
|
||||||
|
import static android.content.Context.MODE_PRIVATE;
|
||||||
|
import static android.content.Context.POWER_SERVICE;
|
||||||
|
import static android.os.PowerManager.PARTIAL_WAKE_LOCK;
|
||||||
|
import static java.util.concurrent.TimeUnit.MINUTES;
|
||||||
|
|
||||||
|
@MethodsNotNullByDefault
|
||||||
|
@ParametersNotNullByDefault
|
||||||
|
class AndroidTorPlugin extends TorPlugin {
|
||||||
|
|
||||||
|
// This tag may prevent Huawei's power manager from killing us
|
||||||
|
private static final String WAKE_LOCK_TAG = "LocationManagerService";
|
||||||
|
|
||||||
|
private final Context appContext;
|
||||||
|
private final RenewableWakeLock wakeLock;
|
||||||
|
|
||||||
|
AndroidTorPlugin(Executor ioExecutor, ScheduledExecutorService scheduler,
|
||||||
|
Context appContext, NetworkManager networkManager,
|
||||||
|
LocationUtils locationUtils, SocketFactory torSocketFactory,
|
||||||
|
Clock clock, ResourceProvider resourceProvider,
|
||||||
|
CircumventionProvider circumventionProvider, Backoff backoff,
|
||||||
|
DuplexPluginCallback callback, String architecture, int maxLatency,
|
||||||
|
int maxIdleTime) {
|
||||||
|
super(ioExecutor, networkManager, locationUtils, torSocketFactory,
|
||||||
|
clock, resourceProvider, circumventionProvider, backoff,
|
||||||
|
callback, architecture, maxLatency, maxIdleTime,
|
||||||
|
appContext.getDir("tor", MODE_PRIVATE));
|
||||||
|
this.appContext = appContext;
|
||||||
|
PowerManager pm = (PowerManager)
|
||||||
|
appContext.getSystemService(POWER_SERVICE);
|
||||||
|
assert pm != null;
|
||||||
|
wakeLock = new RenewableWakeLock(pm, scheduler, PARTIAL_WAKE_LOCK,
|
||||||
|
WAKE_LOCK_TAG, 1, MINUTES);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected int getProcessId() {
|
||||||
|
return android.os.Process.myPid();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected long getLastUpdateTime() {
|
||||||
|
try {
|
||||||
|
PackageManager pm = appContext.getPackageManager();
|
||||||
|
PackageInfo pi = pm.getPackageInfo(appContext.getPackageName(), 0);
|
||||||
|
return pi.lastUpdateTime;
|
||||||
|
} catch (NameNotFoundException e) {
|
||||||
|
throw new AssertionError(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void enableNetwork(boolean enable) throws IOException {
|
||||||
|
if (!running) return;
|
||||||
|
if (enable) wakeLock.acquire();
|
||||||
|
super.enableNetwork(enable);
|
||||||
|
if (!enable) wakeLock.release();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void stop() {
|
||||||
|
super.stop();
|
||||||
|
wakeLock.release();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -4,6 +4,7 @@ import android.content.Context;
|
|||||||
import android.os.Build;
|
import android.os.Build;
|
||||||
|
|
||||||
import org.briarproject.bramble.api.event.EventBus;
|
import org.briarproject.bramble.api.event.EventBus;
|
||||||
|
import org.briarproject.bramble.api.network.NetworkManager;
|
||||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||||
import org.briarproject.bramble.api.plugin.Backoff;
|
import org.briarproject.bramble.api.plugin.Backoff;
|
||||||
import org.briarproject.bramble.api.plugin.BackoffFactory;
|
import org.briarproject.bramble.api.plugin.BackoffFactory;
|
||||||
@@ -14,6 +15,7 @@ import org.briarproject.bramble.api.plugin.duplex.DuplexPluginCallback;
|
|||||||
import org.briarproject.bramble.api.plugin.duplex.DuplexPluginFactory;
|
import org.briarproject.bramble.api.plugin.duplex.DuplexPluginFactory;
|
||||||
import org.briarproject.bramble.api.system.Clock;
|
import org.briarproject.bramble.api.system.Clock;
|
||||||
import org.briarproject.bramble.api.system.LocationUtils;
|
import org.briarproject.bramble.api.system.LocationUtils;
|
||||||
|
import org.briarproject.bramble.api.system.ResourceProvider;
|
||||||
import org.briarproject.bramble.util.AndroidUtils;
|
import org.briarproject.bramble.util.AndroidUtils;
|
||||||
|
|
||||||
import java.util.concurrent.Executor;
|
import java.util.concurrent.Executor;
|
||||||
@@ -25,10 +27,10 @@ import javax.net.SocketFactory;
|
|||||||
|
|
||||||
@Immutable
|
@Immutable
|
||||||
@NotNullByDefault
|
@NotNullByDefault
|
||||||
public class TorPluginFactory implements DuplexPluginFactory {
|
public class AndroidTorPluginFactory implements DuplexPluginFactory {
|
||||||
|
|
||||||
private static final Logger LOG =
|
private static final Logger LOG =
|
||||||
Logger.getLogger(TorPluginFactory.class.getName());
|
Logger.getLogger(AndroidTorPluginFactory.class.getName());
|
||||||
|
|
||||||
private static final int MAX_LATENCY = 30 * 1000; // 30 seconds
|
private static final int MAX_LATENCY = 30 * 1000; // 30 seconds
|
||||||
private static final int MAX_IDLE_TIME = 30 * 1000; // 30 seconds
|
private static final int MAX_IDLE_TIME = 30 * 1000; // 30 seconds
|
||||||
@@ -39,26 +41,30 @@ public class TorPluginFactory implements DuplexPluginFactory {
|
|||||||
private final Executor ioExecutor;
|
private final Executor ioExecutor;
|
||||||
private final ScheduledExecutorService scheduler;
|
private final ScheduledExecutorService scheduler;
|
||||||
private final Context appContext;
|
private final Context appContext;
|
||||||
|
private final NetworkManager networkManager;
|
||||||
private final LocationUtils locationUtils;
|
private final LocationUtils locationUtils;
|
||||||
private final EventBus eventBus;
|
private final EventBus eventBus;
|
||||||
private final SocketFactory torSocketFactory;
|
private final SocketFactory torSocketFactory;
|
||||||
private final BackoffFactory backoffFactory;
|
private final BackoffFactory backoffFactory;
|
||||||
|
private final ResourceProvider resourceProvider;
|
||||||
private final CircumventionProvider circumventionProvider;
|
private final CircumventionProvider circumventionProvider;
|
||||||
private final Clock clock;
|
private final Clock clock;
|
||||||
|
|
||||||
public TorPluginFactory(Executor ioExecutor,
|
public AndroidTorPluginFactory(Executor ioExecutor,
|
||||||
ScheduledExecutorService scheduler, Context appContext,
|
ScheduledExecutorService scheduler, Context appContext,
|
||||||
LocationUtils locationUtils, EventBus eventBus,
|
NetworkManager networkManager, LocationUtils locationUtils,
|
||||||
SocketFactory torSocketFactory, BackoffFactory backoffFactory,
|
EventBus eventBus, SocketFactory torSocketFactory,
|
||||||
CircumventionProvider circumventionProvider,
|
BackoffFactory backoffFactory, ResourceProvider resourceProvider,
|
||||||
Clock clock) {
|
CircumventionProvider circumventionProvider, Clock clock) {
|
||||||
this.ioExecutor = ioExecutor;
|
this.ioExecutor = ioExecutor;
|
||||||
this.scheduler = scheduler;
|
this.scheduler = scheduler;
|
||||||
this.appContext = appContext;
|
this.appContext = appContext;
|
||||||
|
this.networkManager = networkManager;
|
||||||
this.locationUtils = locationUtils;
|
this.locationUtils = locationUtils;
|
||||||
this.eventBus = eventBus;
|
this.eventBus = eventBus;
|
||||||
this.torSocketFactory = torSocketFactory;
|
this.torSocketFactory = torSocketFactory;
|
||||||
this.backoffFactory = backoffFactory;
|
this.backoffFactory = backoffFactory;
|
||||||
|
this.resourceProvider = resourceProvider;
|
||||||
this.circumventionProvider = circumventionProvider;
|
this.circumventionProvider = circumventionProvider;
|
||||||
this.clock = clock;
|
this.clock = clock;
|
||||||
}
|
}
|
||||||
@@ -96,9 +102,10 @@ public class TorPluginFactory implements DuplexPluginFactory {
|
|||||||
|
|
||||||
Backoff backoff = backoffFactory.createBackoff(MIN_POLLING_INTERVAL,
|
Backoff backoff = backoffFactory.createBackoff(MIN_POLLING_INTERVAL,
|
||||||
MAX_POLLING_INTERVAL, BACKOFF_BASE);
|
MAX_POLLING_INTERVAL, BACKOFF_BASE);
|
||||||
TorPlugin plugin = new TorPlugin(ioExecutor, scheduler, appContext,
|
AndroidTorPlugin plugin = new AndroidTorPlugin(ioExecutor, scheduler,
|
||||||
locationUtils, torSocketFactory, clock, backoff, callback,
|
appContext, networkManager, locationUtils, torSocketFactory,
|
||||||
architecture, circumventionProvider, MAX_LATENCY, MAX_IDLE_TIME);
|
clock, resourceProvider, circumventionProvider, backoff,
|
||||||
|
callback, architecture, MAX_LATENCY, MAX_IDLE_TIME);
|
||||||
eventBus.addListener(plugin);
|
eventBus.addListener(plugin);
|
||||||
return plugin;
|
return plugin;
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,30 @@
|
|||||||
|
package org.briarproject.bramble.system;
|
||||||
|
|
||||||
|
import android.app.Application;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.content.res.Resources;
|
||||||
|
|
||||||
|
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||||
|
import org.briarproject.bramble.api.system.ResourceProvider;
|
||||||
|
|
||||||
|
import java.io.InputStream;
|
||||||
|
|
||||||
|
import javax.inject.Inject;
|
||||||
|
|
||||||
|
@NotNullByDefault
|
||||||
|
class AndroidResourceProvider implements ResourceProvider {
|
||||||
|
|
||||||
|
private final Context appContext;
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
AndroidResourceProvider(Application app) {
|
||||||
|
this.appContext = app.getApplicationContext();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public InputStream getResourceInputStream(String name) {
|
||||||
|
Resources res = appContext.getResources();
|
||||||
|
int resId = res.getIdentifier(name, "raw", appContext.getPackageName());
|
||||||
|
return res.openRawResource(resId);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,9 +1,8 @@
|
|||||||
package org.briarproject.bramble.system;
|
package org.briarproject.bramble.system;
|
||||||
|
|
||||||
import android.app.Application;
|
|
||||||
|
|
||||||
import org.briarproject.bramble.api.system.AndroidExecutor;
|
import org.briarproject.bramble.api.system.AndroidExecutor;
|
||||||
import org.briarproject.bramble.api.system.LocationUtils;
|
import org.briarproject.bramble.api.system.LocationUtils;
|
||||||
|
import org.briarproject.bramble.api.system.ResourceProvider;
|
||||||
import org.briarproject.bramble.api.system.SecureRandomProvider;
|
import org.briarproject.bramble.api.system.SecureRandomProvider;
|
||||||
|
|
||||||
import javax.inject.Singleton;
|
import javax.inject.Singleton;
|
||||||
@@ -16,18 +15,26 @@ public class AndroidSystemModule {
|
|||||||
|
|
||||||
@Provides
|
@Provides
|
||||||
@Singleton
|
@Singleton
|
||||||
SecureRandomProvider provideSecureRandomProvider(Application app) {
|
SecureRandomProvider provideSecureRandomProvider(
|
||||||
return new AndroidSecureRandomProvider(app);
|
AndroidSecureRandomProvider provider) {
|
||||||
|
return provider;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Provides
|
@Provides
|
||||||
LocationUtils provideLocationUtils(Application app) {
|
LocationUtils provideLocationUtils(AndroidLocationUtils locationUtils) {
|
||||||
return new AndroidLocationUtils(app);
|
return locationUtils;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Provides
|
@Provides
|
||||||
@Singleton
|
@Singleton
|
||||||
AndroidExecutor provideAndroidExecutor(Application app) {
|
AndroidExecutor provideAndroidExecutor(
|
||||||
return new AndroidExecutorImpl(app);
|
AndroidExecutorImpl androidExecutor) {
|
||||||
|
return androidExecutor;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Provides
|
||||||
|
@Singleton
|
||||||
|
ResourceProvider provideResourceProvider(AndroidResourceProvider provider) {
|
||||||
|
return provider;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,7 +3,6 @@ package org.briarproject.bramble.util;
|
|||||||
import android.annotation.SuppressLint;
|
import android.annotation.SuppressLint;
|
||||||
import android.bluetooth.BluetoothAdapter;
|
import android.bluetooth.BluetoothAdapter;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.SharedPreferences;
|
|
||||||
import android.os.Build;
|
import android.os.Build;
|
||||||
import android.provider.Settings;
|
import android.provider.Settings;
|
||||||
|
|
||||||
@@ -58,30 +57,6 @@ public class AndroidUtils {
|
|||||||
&& !address.equals(FAKE_BLUETOOTH_ADDRESS);
|
&& !address.equals(FAKE_BLUETOOTH_ADDRESS);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void deleteAppData(Context ctx, SharedPreferences... clear) {
|
|
||||||
// Clear and commit shared preferences
|
|
||||||
for (SharedPreferences prefs : clear) {
|
|
||||||
if (!prefs.edit().clear().commit())
|
|
||||||
LOG.warning("Could not clear shared preferences");
|
|
||||||
}
|
|
||||||
// Delete files, except lib and shared_prefs directories
|
|
||||||
File dataDir = new File(ctx.getApplicationInfo().dataDir);
|
|
||||||
File[] children = dataDir.listFiles();
|
|
||||||
if (children == null) {
|
|
||||||
LOG.warning("Could not list files in app data dir");
|
|
||||||
} else {
|
|
||||||
for (File child : children) {
|
|
||||||
String name = child.getName();
|
|
||||||
if (!name.equals("lib") && !name.equals("shared_prefs")) {
|
|
||||||
IoUtils.deleteFileOrDir(child);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Recreate the cache dir as some OpenGL drivers expect it to exist
|
|
||||||
if (!new File(dataDir, "cache").mkdir())
|
|
||||||
LOG.warning("Could not recreate cache dir");
|
|
||||||
}
|
|
||||||
|
|
||||||
public static File getReportDir(Context ctx) {
|
public static File getReportDir(Context ctx) {
|
||||||
return ctx.getDir(STORED_REPORTS, MODE_PRIVATE);
|
return ctx.getDir(STORED_REPORTS, MODE_PRIVATE);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,4 +2,7 @@ Bridge 131.252.210.150:8081 0E858AC201BF0F3FA3C462F64844CBFFC7297A42
|
|||||||
Bridge 67.205.189.122:8443 12D64D5D44E20169585E7378580C0D33A872AD98
|
Bridge 67.205.189.122:8443 12D64D5D44E20169585E7378580C0D33A872AD98
|
||||||
Bridge 45.32.148.146:8443 0CE016FB2462D8BF179AE71F7D702D09DEAC3F1D
|
Bridge 45.32.148.146:8443 0CE016FB2462D8BF179AE71F7D702D09DEAC3F1D
|
||||||
Bridge 148.251.90.59:7510 019F727CA6DCA6CA5C90B55E477B7D87981E75BC
|
Bridge 148.251.90.59:7510 019F727CA6DCA6CA5C90B55E477B7D87981E75BC
|
||||||
#Bridge 128.105.214.161:8081 1E326AAFB3FCB515015250D8FCCC8E37F91A153B
|
Bridge 195.91.239.8:9001 BA83F62551545655BBEBBFF353A45438D73FD45A
|
||||||
|
Bridge 185.165.184.217:6429 64CC94BEC51254E4409AD059192833854CCB95F0
|
||||||
|
Bridge 45.55.1.74:8443 6F18FEFBB0CAECD5ABA755312FCCB34FC11A7AB8
|
||||||
|
Bridge 95.85.40.163:9001 40057BE9CF76B6C5BDBE713753468BE0A990DE9C
|
||||||
@@ -0,0 +1,162 @@
|
|||||||
|
package org.briarproject.bramble.account;
|
||||||
|
|
||||||
|
import android.app.Application;
|
||||||
|
import android.content.SharedPreferences;
|
||||||
|
import android.content.pm.ApplicationInfo;
|
||||||
|
|
||||||
|
import org.briarproject.bramble.api.crypto.CryptoComponent;
|
||||||
|
import org.briarproject.bramble.api.db.DatabaseConfig;
|
||||||
|
import org.briarproject.bramble.api.identity.IdentityManager;
|
||||||
|
import org.briarproject.bramble.test.BrambleMockTestCase;
|
||||||
|
import org.jmock.Expectations;
|
||||||
|
import org.jmock.lib.legacy.ClassImposteriser;
|
||||||
|
import org.junit.After;
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
|
||||||
|
import static junit.framework.Assert.assertEquals;
|
||||||
|
import static junit.framework.Assert.assertFalse;
|
||||||
|
import static junit.framework.Assert.assertTrue;
|
||||||
|
import static org.briarproject.bramble.test.TestUtils.deleteTestDirectory;
|
||||||
|
import static org.briarproject.bramble.test.TestUtils.getRandomBytes;
|
||||||
|
import static org.briarproject.bramble.test.TestUtils.getTestDirectory;
|
||||||
|
import static org.briarproject.bramble.util.StringUtils.toHexString;
|
||||||
|
|
||||||
|
public class AndroidAccountManagerTest extends BrambleMockTestCase {
|
||||||
|
|
||||||
|
private final SharedPreferences prefs =
|
||||||
|
context.mock(SharedPreferences.class, "prefs");
|
||||||
|
private final SharedPreferences defaultPrefs =
|
||||||
|
context.mock(SharedPreferences.class, "defaultPrefs");
|
||||||
|
private final DatabaseConfig databaseConfig =
|
||||||
|
context.mock(DatabaseConfig.class);
|
||||||
|
private final CryptoComponent crypto = context.mock(CryptoComponent.class);
|
||||||
|
private final IdentityManager identityManager =
|
||||||
|
context.mock(IdentityManager.class);
|
||||||
|
private final SharedPreferences.Editor
|
||||||
|
editor = context.mock(SharedPreferences.Editor.class);
|
||||||
|
private final Application app;
|
||||||
|
private final ApplicationInfo applicationInfo;
|
||||||
|
|
||||||
|
private final String encryptedKeyHex = toHexString(getRandomBytes(123));
|
||||||
|
private final File testDir = getTestDirectory();
|
||||||
|
private final File keyDir = new File(testDir, "key");
|
||||||
|
private final File keyFile = new File(keyDir, "db.key");
|
||||||
|
private final File keyBackupFile = new File(keyDir, "db.key.bak");
|
||||||
|
private final File dbDir = new File(testDir, "db");
|
||||||
|
|
||||||
|
private AndroidAccountManager accountManager;
|
||||||
|
|
||||||
|
public AndroidAccountManagerTest() {
|
||||||
|
context.setImposteriser(ClassImposteriser.INSTANCE);
|
||||||
|
app = context.mock(Application.class);
|
||||||
|
applicationInfo = new ApplicationInfo();
|
||||||
|
applicationInfo.dataDir = testDir.getAbsolutePath();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void setUp() {
|
||||||
|
context.checking(new Expectations() {{
|
||||||
|
allowing(databaseConfig).getDatabaseDirectory();
|
||||||
|
will(returnValue(dbDir));
|
||||||
|
allowing(databaseConfig).getDatabaseKeyDirectory();
|
||||||
|
will(returnValue(keyDir));
|
||||||
|
allowing(app).getApplicationContext();
|
||||||
|
will(returnValue(app));
|
||||||
|
}});
|
||||||
|
accountManager = new AndroidAccountManager(databaseConfig, crypto,
|
||||||
|
identityManager, prefs, app) {
|
||||||
|
@Override
|
||||||
|
SharedPreferences getDefaultSharedPreferences() {
|
||||||
|
return defaultPrefs;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testDbKeyIsMigratedFromPreferencesToFile() {
|
||||||
|
context.checking(new Expectations() {{
|
||||||
|
oneOf(prefs).getString("key", null);
|
||||||
|
will(returnValue(encryptedKeyHex));
|
||||||
|
oneOf(prefs).edit();
|
||||||
|
will(returnValue(editor));
|
||||||
|
oneOf(editor).remove("key");
|
||||||
|
will(returnValue(editor));
|
||||||
|
oneOf(editor).commit();
|
||||||
|
will(returnValue(true));
|
||||||
|
}});
|
||||||
|
|
||||||
|
assertFalse(keyFile.exists());
|
||||||
|
assertFalse(keyBackupFile.exists());
|
||||||
|
|
||||||
|
assertEquals(encryptedKeyHex,
|
||||||
|
accountManager.loadEncryptedDatabaseKey());
|
||||||
|
|
||||||
|
assertTrue(keyFile.exists());
|
||||||
|
assertTrue(keyBackupFile.exists());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testDeleteAccountClearsSharedPrefsAndDeletesFiles()
|
||||||
|
throws Exception {
|
||||||
|
// Directories 'lib' and 'shared_prefs' should be spared
|
||||||
|
File libDir = new File(testDir, "lib");
|
||||||
|
File libFile = new File(libDir, "file");
|
||||||
|
File sharedPrefsDir = new File(testDir, "shared_prefs");
|
||||||
|
File sharedPrefsFile = new File(sharedPrefsDir, "file");
|
||||||
|
// Directory 'cache' should be emptied
|
||||||
|
File cacheDir = new File(testDir, "cache");
|
||||||
|
File cacheFile = new File(cacheDir, "file");
|
||||||
|
// Other directories should be deleted
|
||||||
|
File potatoDir = new File(testDir, ".potato");
|
||||||
|
File potatoFile = new File(potatoDir, "file");
|
||||||
|
|
||||||
|
context.checking(new Expectations() {{
|
||||||
|
oneOf(prefs).edit();
|
||||||
|
will(returnValue(editor));
|
||||||
|
oneOf(editor).clear();
|
||||||
|
will(returnValue(editor));
|
||||||
|
oneOf(editor).commit();
|
||||||
|
will(returnValue(true));
|
||||||
|
oneOf(defaultPrefs).edit();
|
||||||
|
will(returnValue(editor));
|
||||||
|
oneOf(editor).clear();
|
||||||
|
will(returnValue(editor));
|
||||||
|
oneOf(editor).commit();
|
||||||
|
will(returnValue(true));
|
||||||
|
oneOf(app).getApplicationInfo();
|
||||||
|
will(returnValue(applicationInfo));
|
||||||
|
}});
|
||||||
|
|
||||||
|
assertTrue(dbDir.mkdirs());
|
||||||
|
assertTrue(keyDir.mkdirs());
|
||||||
|
assertTrue(libDir.mkdirs());
|
||||||
|
assertTrue(libFile.createNewFile());
|
||||||
|
assertTrue(sharedPrefsDir.mkdirs());
|
||||||
|
assertTrue(sharedPrefsFile.createNewFile());
|
||||||
|
assertTrue(cacheDir.mkdirs());
|
||||||
|
assertTrue(cacheFile.createNewFile());
|
||||||
|
assertTrue(potatoDir.mkdirs());
|
||||||
|
assertTrue(potatoFile.createNewFile());
|
||||||
|
|
||||||
|
accountManager.deleteAccount();
|
||||||
|
|
||||||
|
assertFalse(dbDir.exists());
|
||||||
|
assertFalse(keyDir.exists());
|
||||||
|
assertTrue(libDir.exists());
|
||||||
|
assertTrue(libFile.exists());
|
||||||
|
assertTrue(sharedPrefsDir.exists());
|
||||||
|
assertTrue(sharedPrefsFile.exists());
|
||||||
|
assertTrue(cacheDir.exists());
|
||||||
|
assertFalse(cacheFile.exists());
|
||||||
|
assertFalse(potatoDir.exists());
|
||||||
|
assertFalse(potatoFile.exists());
|
||||||
|
}
|
||||||
|
|
||||||
|
@After
|
||||||
|
public void tearDown() {
|
||||||
|
deleteTestDirectory(testDir);
|
||||||
|
}
|
||||||
|
}
|
||||||
94
bramble-android/witness.gradle
Normal file
94
bramble-android/witness.gradle
Normal file
@@ -0,0 +1,94 @@
|
|||||||
|
dependencyVerification {
|
||||||
|
verify = [
|
||||||
|
'cglib:cglib:3.2.0:cglib-3.2.0.jar:adb13bab79712ad6bdf1bd59f2a3918018a8016e722e8a357065afb9e6690861',
|
||||||
|
'com.android.support.test:monitor:1.0.2:monitor-1.0.2.aar:38ef4fa98a32dc55550ff49bb36a583e178b3a9b830fcb8dcc27bfc4254bc2bc',
|
||||||
|
'com.android.support.test:runner:1.0.2:runner-1.0.2.aar:f04b9ae342975ba1cb3e4a06e13426e3e6b8a73faa45acba604493d83c9a4f00',
|
||||||
|
'com.android.support:support-annotations:27.1.1:support-annotations-27.1.1.jar:3365960206c3d2b09e845f555e7f88f8effc8d2f00b369e66c4be384029299cf',
|
||||||
|
'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.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.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.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: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',
|
||||||
|
'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',
|
||||||
|
'javax.xml.bind:jaxb-api:2.2.12-b140109.1041:jaxb-api-2.2.12-b140109.1041.jar:b5e60cd8b7b5ff01ce4a74c5dd008f4fbd14ced3495d0b47b85cfedc182211f2',
|
||||||
|
'junit:junit:4.12:junit-4.12.jar:59721f0805e223d84b90677887d9ff567dc534d7c502ca903c0c2b17f05c116a',
|
||||||
|
'net.sf.jopt-simple:jopt-simple:4.9:jopt-simple-4.9.jar:26c5856e954b5f864db76f13b86919b59c6eecf9fd930b96baa8884626baf2f5',
|
||||||
|
'net.sf.kxml:kxml2:2.3.0:kxml2-2.3.0.jar:f264dd9f79a1fde10ce5ecc53221eff24be4c9331c830b7d52f2f08a7b633de2',
|
||||||
|
'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.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.codehaus.groovy:groovy-all:2.4.12:groovy-all-2.4.12.jar:6a56af4bd48903d56bec62821876cadefafd007360cc6bd0d8f7aa8d72b38be4',
|
||||||
|
'org.codehaus.mojo:animal-sniffer-annotations:1.14:animal-sniffer-annotations-1.14.jar:2068320bd6bad744c3673ab048f67e30bef8f518996fa380033556600669905d',
|
||||||
|
'org.glassfish.jaxb:jaxb-core:2.2.11:jaxb-core-2.2.11.jar:37bcaee8ebb04362c8352a5bf6221b86967ecdab5164c696b10b9a2bb587b2aa',
|
||||||
|
'org.glassfish.jaxb:jaxb-runtime:2.2.11:jaxb-runtime-2.2.11.jar:a874f2351cfba8e2946be3002d10c18a6da8f21b52ba2acf52f2b85d5520ed70',
|
||||||
|
'org.glassfish.jaxb:txw2:2.2.11:txw2-2.2.11.jar:272a3ccad45a4511351920cd2a8633c53cab8d5220c7a92954da5526bb5eafea',
|
||||||
|
'org.hamcrest:hamcrest-core:1.3:hamcrest-core-1.3.jar:66fdef91e9739348df7a096aa384a5685f4e875584cce89386a7a47251c4d8e9',
|
||||||
|
'org.hamcrest:hamcrest-library:1.3:hamcrest-library-1.3.jar:711d64522f9ec410983bd310934296da134be4254a125080a0416ec178dfad1c',
|
||||||
|
'org.jetbrains.kotlin:kotlin-reflect:1.2.0:kotlin-reflect-1.2.0.jar:4f48a872bad6e4d9c053f4ad610d11e4012ad7e58dc19a03dd5eb811f36069dd',
|
||||||
|
'org.jetbrains.kotlin:kotlin-stdlib-jre7:1.2.0:kotlin-stdlib-jre7-1.2.0.jar:c7a20fb951d437797afe8980aff6c1e5a03f310c661ba58ba1d4fa90cb0f2926',
|
||||||
|
'org.jetbrains.kotlin:kotlin-stdlib-jre8:1.2.0:kotlin-stdlib-jre8-1.2.0.jar:633524eee6ef1941f7cb1dab7ee3927b0a221ceee9047aeb5515f4cbb990c82a',
|
||||||
|
'org.jetbrains.kotlin:kotlin-stdlib:1.2.0:kotlin-stdlib-1.2.0.jar:05cfd9f5ac0b41910703a8925f7211a495909b27a2ffdd1c5106f1689aeafcd4',
|
||||||
|
'org.jetbrains.trove4j:trove4j:20160824:trove4j-20160824.jar:1917871c8deb468307a584680c87a44572f5a8b0b98c6d397fc0f5f86596dbe7',
|
||||||
|
'org.jetbrains:annotations:13.0:annotations-13.0.jar:ace2a10dc8e2d5fd34925ecac03e4988b2c0f851650c94b8cef49ba1bd111478',
|
||||||
|
'org.jmock:jmock-junit4:2.8.2:jmock-junit4-2.8.2.jar:f7ee4df4f7bd7b7f1cafad3b99eb74d579f109d5992ff625347352edb55e674c',
|
||||||
|
'org.jmock:jmock-legacy:2.8.2:jmock-legacy-2.8.2.jar:f2b985a5c08a9edb7f37612330c058809da3f6a6d63ce792426ebf8ff0d6d31b',
|
||||||
|
'org.jmock:jmock-testjar:2.8.2:jmock-testjar-2.8.2.jar:8900860f72c474e027cf97fe78dcbf154a1aa7fc62b6845c5fb4e4f3c7bc8760',
|
||||||
|
'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:5.0.4:asm-5.0.4.jar:896618ed8ae62702521a78bc7be42b7c491a08e6920a15f89a3ecdec31e9a220',
|
||||||
|
'org.ow2.asm:asm:5.1:asm-5.1.jar:d2da399a9967c69f0a21739256fa79d284222c223082cacadc17372244764b54',
|
||||||
|
]
|
||||||
|
}
|
||||||
@@ -4,6 +4,7 @@ targetCompatibility = 1.8
|
|||||||
|
|
||||||
apply plugin: 'ru.vyarus.animalsniffer'
|
apply plugin: 'ru.vyarus.animalsniffer'
|
||||||
apply plugin: 'witness'
|
apply plugin: 'witness'
|
||||||
|
apply from: 'witness.gradle'
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
implementation "com.google.dagger:dagger:2.0.2"
|
implementation "com.google.dagger:dagger:2.0.2"
|
||||||
@@ -19,31 +20,6 @@ dependencies {
|
|||||||
signature 'org.codehaus.mojo.signature:java16:1.1@signature'
|
signature 'org.codehaus.mojo.signature:java16:1.1@signature'
|
||||||
}
|
}
|
||||||
|
|
||||||
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',
|
|
||||||
'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',
|
|
||||||
'org.apache.ant:ant:1.9.4:ant-1.9.4.jar:649ae0730251de07b8913f49286d46bba7b92d47c5f332610aa426c4f02161d8',
|
|
||||||
'org.beanshell:bsh:1.3.0:bsh-1.3.0.jar:9b04edc75d19db54f1b4e8b5355e9364384c6cf71eb0a1b9724c159d779879f8',
|
|
||||||
'org.codehaus.mojo.signature:java16:1.1:java16-1.1.signature:53799223a2c98dba2d0add810bed76315460df285c69e4f397ae6098f87dd619',
|
|
||||||
'org.codehaus.mojo:animal-sniffer-ant-tasks:1.16:animal-sniffer-ant-tasks-1.16.jar:890040976fbe2d584619a6a61b1fd2e925b3b5eb342a85eb2762c467c0d64e90',
|
|
||||||
'org.codehaus.mojo:animal-sniffer:1.16:animal-sniffer-1.16.jar:72be8bcc226ba43b937c722a08a07852bfa1b11400089265d5df0ee7b38b1d52',
|
|
||||||
'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.jmock:jmock-junit4:2.8.2:jmock-junit4-2.8.2.jar:f7ee4df4f7bd7b7f1cafad3b99eb74d579f109d5992ff625347352edb55e674c',
|
|
||||||
'org.jmock:jmock-legacy:2.8.2:jmock-legacy-2.8.2.jar:f2b985a5c08a9edb7f37612330c058809da3f6a6d63ce792426ebf8ff0d6d31b',
|
|
||||||
'org.jmock:jmock-testjar:2.8.2:jmock-testjar-2.8.2.jar:8900860f72c474e027cf97fe78dcbf154a1aa7fc62b6845c5fb4e4f3c7bc8760',
|
|
||||||
'org.jmock:jmock:2.8.2:jmock-2.8.2.jar:6c73cb4a2e6dbfb61fd99c9a768539c170ab6568e57846bd60dbf19596b65b16',
|
|
||||||
'org.objenesis:objenesis:2.1:objenesis-2.1.jar:c74330cc6b806c804fd37e74487b4fe5d7c2750c5e15fbc6efa13bdee1bdef80',
|
|
||||||
'org.ow2.asm:asm-all:5.2:asm-all-5.2.jar:7fbffbc1db3422e2101689fd88df8384b15817b52b9b2b267b9f6d2511dc198d',
|
|
||||||
'org.ow2.asm:asm:5.0.4:asm-5.0.4.jar:896618ed8ae62702521a78bc7be42b7c491a08e6920a15f89a3ecdec31e9a220',
|
|
||||||
]
|
|
||||||
}
|
|
||||||
|
|
||||||
// needed to make test output available to bramble-core and briar-core
|
// needed to make test output available to bramble-core and briar-core
|
||||||
configurations {
|
configurations {
|
||||||
testOutput.extendsFrom(testCompile)
|
testOutput.extendsFrom(testCompile)
|
||||||
@@ -55,3 +31,8 @@ task jarTest(type: Jar, dependsOn: testClasses) {
|
|||||||
artifacts {
|
artifacts {
|
||||||
testOutput jarTest
|
testOutput jarTest
|
||||||
}
|
}
|
||||||
|
|
||||||
|
tasks.withType(Test) {
|
||||||
|
// Use entropy-gathering device specified on command line, if any
|
||||||
|
systemProperty 'java.security.egd', System.getProperty('java.security.egd')
|
||||||
|
}
|
||||||
|
|||||||
@@ -0,0 +1,70 @@
|
|||||||
|
package org.briarproject.bramble.api.account;
|
||||||
|
|
||||||
|
import org.briarproject.bramble.api.crypto.SecretKey;
|
||||||
|
import org.briarproject.bramble.api.identity.IdentityManager;
|
||||||
|
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||||
|
|
||||||
|
import javax.annotation.Nullable;
|
||||||
|
|
||||||
|
@NotNullByDefault
|
||||||
|
public interface AccountManager {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns true if the manager has the database key. This will be false
|
||||||
|
* before {@link #createAccount(String, String)} or {@link #signIn(String)}
|
||||||
|
* has been called, and true after {@link #createAccount(String, String)}
|
||||||
|
* or {@link #signIn(String)} has returned true, until the process exits.
|
||||||
|
*/
|
||||||
|
boolean hasDatabaseKey();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the database key if the manager has it. This will be null
|
||||||
|
* before {@link #createAccount(String, String)} or {@link #signIn(String)}
|
||||||
|
* has been called, and non-null after
|
||||||
|
* {@link #createAccount(String, String)} or {@link #signIn(String)} has
|
||||||
|
* returned true, until the process exits.
|
||||||
|
*/
|
||||||
|
@Nullable
|
||||||
|
SecretKey getDatabaseKey();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns true if the encrypted database key can be loaded from disk, and
|
||||||
|
* the database directory exists and is a directory.
|
||||||
|
*/
|
||||||
|
boolean accountExists();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates an identity with the given name and registers it with the
|
||||||
|
* {@link IdentityManager}. Creates a database key, encrypts it with the
|
||||||
|
* given password and stores it on disk.
|
||||||
|
* <p/>
|
||||||
|
* This method does not create the database directory, so
|
||||||
|
* {@link #accountExists()} will continue to return false until the
|
||||||
|
* database directory is created.
|
||||||
|
*/
|
||||||
|
boolean createAccount(String name, String password);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Deletes all account state from disk. {@link #accountExists()} will
|
||||||
|
* return false after this method returns.
|
||||||
|
*/
|
||||||
|
void deleteAccount();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Loads the encrypted database key from disk and decrypts it with the
|
||||||
|
* given password.
|
||||||
|
*
|
||||||
|
* @return true if the database key was successfully loaded and decrypted.
|
||||||
|
*/
|
||||||
|
boolean signIn(String password);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Loads the encrypted database key from disk, decrypts it with the old
|
||||||
|
* password, encrypts it with the new password, and stores it on disk,
|
||||||
|
* replacing the old key.
|
||||||
|
*
|
||||||
|
* @return true if the database key was successfully loaded, re-encrypted
|
||||||
|
* and stored.
|
||||||
|
*/
|
||||||
|
boolean changePassword(String oldPassword, String newPassword);
|
||||||
|
}
|
||||||
@@ -16,7 +16,7 @@ public interface ContactManager {
|
|||||||
/**
|
/**
|
||||||
* Registers a hook to be called whenever a contact is added or removed.
|
* Registers a hook to be called whenever a contact is added or removed.
|
||||||
* This method should be called before
|
* This method should be called before
|
||||||
* {@link LifecycleManager#startServices(String)}.
|
* {@link LifecycleManager#startServices(SecretKey)}.
|
||||||
*/
|
*/
|
||||||
void registerContactHook(ContactHook hook);
|
void registerContactHook(ContactHook hook);
|
||||||
|
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ package org.briarproject.bramble.api.db;
|
|||||||
|
|
||||||
import org.briarproject.bramble.api.contact.Contact;
|
import org.briarproject.bramble.api.contact.Contact;
|
||||||
import org.briarproject.bramble.api.contact.ContactId;
|
import org.briarproject.bramble.api.contact.ContactId;
|
||||||
|
import org.briarproject.bramble.api.crypto.SecretKey;
|
||||||
import org.briarproject.bramble.api.identity.Author;
|
import org.briarproject.bramble.api.identity.Author;
|
||||||
import org.briarproject.bramble.api.identity.AuthorId;
|
import org.briarproject.bramble.api.identity.AuthorId;
|
||||||
import org.briarproject.bramble.api.identity.LocalAuthor;
|
import org.briarproject.bramble.api.identity.LocalAuthor;
|
||||||
@@ -44,7 +45,8 @@ public interface DatabaseComponent {
|
|||||||
* @throws DataTooOldException if the data uses an older schema than the
|
* @throws DataTooOldException if the data uses an older schema than the
|
||||||
* current code and cannot be migrated
|
* current code and cannot be migrated
|
||||||
*/
|
*/
|
||||||
boolean open(@Nullable MigrationListener listener) throws DbException;
|
boolean open(SecretKey key, @Nullable MigrationListener listener)
|
||||||
|
throws DbException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Waits for any open transactions to finish and closes the database.
|
* Waits for any open transactions to finish and closes the database.
|
||||||
@@ -267,7 +269,7 @@ public interface DatabaseComponent {
|
|||||||
* Read-only.
|
* Read-only.
|
||||||
*/
|
*/
|
||||||
Collection<MessageId> getMessageIds(Transaction txn, GroupId g)
|
Collection<MessageId> getMessageIds(Transaction txn, GroupId g)
|
||||||
throws DbException;
|
throws DbException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the IDs of any messages that need to be validated.
|
* Returns the IDs of any messages that need to be validated.
|
||||||
@@ -487,7 +489,7 @@ public interface DatabaseComponent {
|
|||||||
* Removes the given transport keys from the database.
|
* Removes the given transport keys from the database.
|
||||||
*/
|
*/
|
||||||
void removeTransportKeys(Transaction txn, TransportId t, KeySetId k)
|
void removeTransportKeys(Transaction txn, TransportId t, KeySetId k)
|
||||||
throws DbException;
|
throws DbException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Marks the given contact as verified.
|
* Marks the given contact as verified.
|
||||||
@@ -534,7 +536,7 @@ public interface DatabaseComponent {
|
|||||||
* Marks the given transport keys as usable for outgoing streams.
|
* Marks the given transport keys as usable for outgoing streams.
|
||||||
*/
|
*/
|
||||||
void setTransportKeysActive(Transaction txn, TransportId t, KeySetId k)
|
void setTransportKeysActive(Transaction txn, TransportId t, KeySetId k)
|
||||||
throws DbException;
|
throws DbException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Stores the given transport keys, deleting any keys they have replaced.
|
* Stores the given transport keys, deleting any keys they have replaced.
|
||||||
|
|||||||
@@ -1,30 +1,15 @@
|
|||||||
package org.briarproject.bramble.api.db;
|
package org.briarproject.bramble.api.db;
|
||||||
|
|
||||||
import org.briarproject.bramble.api.crypto.SecretKey;
|
|
||||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
|
|
||||||
import javax.annotation.Nullable;
|
|
||||||
|
|
||||||
@NotNullByDefault
|
@NotNullByDefault
|
||||||
public interface DatabaseConfig {
|
public interface DatabaseConfig {
|
||||||
|
|
||||||
boolean databaseExists();
|
|
||||||
|
|
||||||
File getDatabaseDirectory();
|
File getDatabaseDirectory();
|
||||||
|
|
||||||
File getDatabaseKeyDirectory();
|
File getDatabaseKeyDirectory();
|
||||||
|
|
||||||
void setEncryptionKey(SecretKey key);
|
|
||||||
|
|
||||||
@Nullable
|
|
||||||
SecretKey getEncryptionKey();
|
|
||||||
|
|
||||||
void setLocalAuthorName(String nickname);
|
|
||||||
|
|
||||||
@Nullable
|
|
||||||
String getLocalAuthorName();
|
|
||||||
|
|
||||||
long getMaxSize();
|
long getMaxSize();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
package org.briarproject.bramble.api.identity;
|
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.DbException;
|
||||||
import org.briarproject.bramble.api.db.Transaction;
|
import org.briarproject.bramble.api.db.Transaction;
|
||||||
import org.briarproject.bramble.api.identity.Author.Status;
|
import org.briarproject.bramble.api.identity.Author.Status;
|
||||||
@@ -9,29 +10,40 @@ import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
|||||||
public interface IdentityManager {
|
public interface IdentityManager {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Stores the local pseudonym.
|
* Creates a local identity with the given name.
|
||||||
*/
|
*/
|
||||||
void registerLocalAuthor(LocalAuthor a) throws DbException;
|
@CryptoExecutor
|
||||||
|
LocalAuthor createLocalAuthor(String name);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the cached main local identity, non-blocking, or loads it from
|
* Registers the given local identity with the manager. The identity is
|
||||||
* the db, blocking
|
* not stored until {@link #storeLocalAuthor()} is called.
|
||||||
|
*/
|
||||||
|
void registerLocalAuthor(LocalAuthor a);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Stores the local identity registered with
|
||||||
|
* {@link #registerLocalAuthor(LocalAuthor)}, if any.
|
||||||
|
*/
|
||||||
|
void storeLocalAuthor() throws DbException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the cached local identity or loads it from the database.
|
||||||
*/
|
*/
|
||||||
LocalAuthor getLocalAuthor() throws DbException;
|
LocalAuthor getLocalAuthor() throws DbException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the cached main local identity, non-blocking, or loads it from
|
* Returns the cached local identity or loads it from the database.
|
||||||
* the db, blocking, within the given Transaction.
|
|
||||||
*/
|
*/
|
||||||
LocalAuthor getLocalAuthor(Transaction txn) throws DbException;
|
LocalAuthor getLocalAuthor(Transaction txn) throws DbException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the trust-level status of the author
|
* Returns the {@link Status} of the given author.
|
||||||
*/
|
*/
|
||||||
Status getAuthorStatus(AuthorId a) throws DbException;
|
Status getAuthorStatus(AuthorId a) throws DbException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the trust-level status of the author
|
* Returns the {@link Status} of the given author.
|
||||||
*/
|
*/
|
||||||
Status getAuthorStatus(Transaction txn, AuthorId a) throws DbException;
|
Status getAuthorStatus(Transaction txn, AuthorId a) throws DbException;
|
||||||
|
|
||||||
|
|||||||
@@ -7,16 +7,6 @@ public interface KeyAgreementConstants {
|
|||||||
*/
|
*/
|
||||||
byte PROTOCOL_VERSION = 4;
|
byte PROTOCOL_VERSION = 4;
|
||||||
|
|
||||||
/**
|
|
||||||
* The length of the record header in bytes.
|
|
||||||
*/
|
|
||||||
int RECORD_HEADER_LENGTH = 4;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The offset of the payload length in the record header, in bytes.
|
|
||||||
*/
|
|
||||||
int RECORD_HEADER_PAYLOAD_LENGTH_OFFSET = 2;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The length of the BQP key commitment in bytes.
|
* The length of the BQP key commitment in bytes.
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -1,13 +1,12 @@
|
|||||||
package org.briarproject.bramble.api.lifecycle;
|
package org.briarproject.bramble.api.lifecycle;
|
||||||
|
|
||||||
|
import org.briarproject.bramble.api.crypto.SecretKey;
|
||||||
import org.briarproject.bramble.api.db.DatabaseComponent;
|
import org.briarproject.bramble.api.db.DatabaseComponent;
|
||||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||||
import org.briarproject.bramble.api.sync.Client;
|
import org.briarproject.bramble.api.sync.Client;
|
||||||
|
|
||||||
import java.util.concurrent.ExecutorService;
|
import java.util.concurrent.ExecutorService;
|
||||||
|
|
||||||
import javax.annotation.Nullable;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Manages the lifecycle of the app, starting {@link Client Clients}, starting
|
* Manages the lifecycle of the app, starting {@link Client Clients}, starting
|
||||||
* and stopping {@link Service Services}, shutting down
|
* and stopping {@link Service Services}, shutting down
|
||||||
@@ -18,7 +17,7 @@ import javax.annotation.Nullable;
|
|||||||
public interface LifecycleManager {
|
public interface LifecycleManager {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The result of calling {@link #startServices(String)}.
|
* The result of calling {@link #startServices(SecretKey)}.
|
||||||
*/
|
*/
|
||||||
enum StartResult {
|
enum StartResult {
|
||||||
ALREADY_RUNNING,
|
ALREADY_RUNNING,
|
||||||
@@ -44,28 +43,27 @@ public interface LifecycleManager {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Registers a {@link Service} to be started and stopped. This method
|
* Registers a {@link Service} to be started and stopped. This method
|
||||||
* should be called before {@link #startServices(String)}.
|
* should be called before {@link #startServices(SecretKey)}.
|
||||||
*/
|
*/
|
||||||
void registerService(Service s);
|
void registerService(Service s);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Registers a {@link Client} to be started. This method should be called
|
* Registers a {@link Client} to be started. This method should be called
|
||||||
* before {@link #startServices(String)}.
|
* before {@link #startServices(SecretKey)}.
|
||||||
*/
|
*/
|
||||||
void registerClient(Client c);
|
void registerClient(Client c);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Registers an {@link ExecutorService} to be shut down. This method
|
* Registers an {@link ExecutorService} to be shut down. This method
|
||||||
* should be called before {@link #startServices(String)}.
|
* should be called before {@link #startServices(SecretKey)}.
|
||||||
*/
|
*/
|
||||||
void registerForShutdown(ExecutorService e);
|
void registerForShutdown(ExecutorService e);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Opens the {@link DatabaseComponent}, optionally creates a local author
|
* Opens the {@link DatabaseComponent} using the given key and starts any
|
||||||
* with the provided nickname, and starts any registered
|
* registered {@link Client Clients} and {@link Service Services}.
|
||||||
* {@link Client Clients} and {@link Service Services}.
|
|
||||||
*/
|
*/
|
||||||
StartResult startServices(@Nullable String nickname);
|
StartResult startServices(SecretKey dbKey);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Stops any registered {@link Service Services}, shuts down any
|
* Stops any registered {@link Service Services}, shuts down any
|
||||||
|
|||||||
@@ -0,0 +1,9 @@
|
|||||||
|
package org.briarproject.bramble.api.network;
|
||||||
|
|
||||||
|
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||||
|
|
||||||
|
@NotNullByDefault
|
||||||
|
public interface NetworkManager {
|
||||||
|
|
||||||
|
NetworkStatus getNetworkStatus();
|
||||||
|
}
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
package org.briarproject.bramble.api.network;
|
||||||
|
|
||||||
|
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||||
|
|
||||||
|
import javax.annotation.concurrent.Immutable;
|
||||||
|
|
||||||
|
@Immutable
|
||||||
|
@NotNullByDefault
|
||||||
|
public class NetworkStatus {
|
||||||
|
|
||||||
|
private final boolean connected, wifi;
|
||||||
|
|
||||||
|
public NetworkStatus(boolean connected, boolean wifi) {
|
||||||
|
this.connected = connected;
|
||||||
|
this.wifi = wifi;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isConnected() {
|
||||||
|
return connected;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isWifi() {
|
||||||
|
return wifi;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
package org.briarproject.bramble.api.network.event;
|
||||||
|
|
||||||
|
import org.briarproject.bramble.api.event.Event;
|
||||||
|
import org.briarproject.bramble.api.network.NetworkStatus;
|
||||||
|
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||||
|
|
||||||
|
import javax.annotation.concurrent.Immutable;
|
||||||
|
|
||||||
|
@Immutable
|
||||||
|
@NotNullByDefault
|
||||||
|
public class NetworkStatusEvent extends Event {
|
||||||
|
|
||||||
|
private final NetworkStatus status;
|
||||||
|
|
||||||
|
public NetworkStatusEvent(NetworkStatus status) {
|
||||||
|
this.status = status;
|
||||||
|
}
|
||||||
|
|
||||||
|
public NetworkStatus getStatus() {
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -14,6 +14,7 @@ public interface TorConstants {
|
|||||||
|
|
||||||
String PREF_TOR_NETWORK = "network";
|
String PREF_TOR_NETWORK = "network";
|
||||||
String PREF_TOR_PORT = "port";
|
String PREF_TOR_PORT = "port";
|
||||||
|
String PREF_TOR_DISABLE_BLOCKED = "disableWhenBlocked";
|
||||||
|
|
||||||
int PREF_TOR_NETWORK_NEVER = 0;
|
int PREF_TOR_NETWORK_NEVER = 0;
|
||||||
int PREF_TOR_NETWORK_WIFI = 1;
|
int PREF_TOR_NETWORK_WIFI = 1;
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
package org.briarproject.bramble.api.sync;
|
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.DbException;
|
||||||
import org.briarproject.bramble.api.db.Metadata;
|
import org.briarproject.bramble.api.db.Metadata;
|
||||||
import org.briarproject.bramble.api.db.Transaction;
|
import org.briarproject.bramble.api.db.Transaction;
|
||||||
@@ -35,7 +36,8 @@ public interface ValidationManager {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Registers the message validator for the given client. This method
|
* Registers the message validator for the given client. This method
|
||||||
* should be called before {@link LifecycleManager#startServices(String)}.
|
* should be called before
|
||||||
|
* {@link LifecycleManager#startServices(SecretKey)}.
|
||||||
*/
|
*/
|
||||||
void registerMessageValidator(ClientId c, int majorVersion,
|
void registerMessageValidator(ClientId c, int majorVersion,
|
||||||
MessageValidator v);
|
MessageValidator v);
|
||||||
@@ -44,7 +46,7 @@ public interface ValidationManager {
|
|||||||
* Registers the incoming message hook for the given client. The hook will
|
* Registers the incoming message hook for the given client. The hook will
|
||||||
* be called once for each incoming message that passes validation. This
|
* be called once for each incoming message that passes validation. This
|
||||||
* method should be called before
|
* method should be called before
|
||||||
* {@link LifecycleManager#startServices(String)}.
|
* {@link LifecycleManager#startServices(SecretKey)}.
|
||||||
*/
|
*/
|
||||||
void registerIncomingMessageHook(ClientId c, int majorVersion,
|
void registerIncomingMessageHook(ClientId c, int majorVersion,
|
||||||
IncomingMessageHook hook);
|
IncomingMessageHook hook);
|
||||||
|
|||||||
@@ -0,0 +1,11 @@
|
|||||||
|
package org.briarproject.bramble.api.system;
|
||||||
|
|
||||||
|
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||||
|
|
||||||
|
import java.io.InputStream;
|
||||||
|
|
||||||
|
@NotNullByDefault
|
||||||
|
public interface ResourceProvider {
|
||||||
|
|
||||||
|
InputStream getResourceInputStream(String name);
|
||||||
|
}
|
||||||
@@ -2,6 +2,7 @@ package org.briarproject.bramble.api.versioning;
|
|||||||
|
|
||||||
import org.briarproject.bramble.api.contact.Contact;
|
import org.briarproject.bramble.api.contact.Contact;
|
||||||
import org.briarproject.bramble.api.contact.ContactId;
|
import org.briarproject.bramble.api.contact.ContactId;
|
||||||
|
import org.briarproject.bramble.api.crypto.SecretKey;
|
||||||
import org.briarproject.bramble.api.db.DbException;
|
import org.briarproject.bramble.api.db.DbException;
|
||||||
import org.briarproject.bramble.api.db.Transaction;
|
import org.briarproject.bramble.api.db.Transaction;
|
||||||
import org.briarproject.bramble.api.lifecycle.LifecycleManager;
|
import org.briarproject.bramble.api.lifecycle.LifecycleManager;
|
||||||
@@ -25,7 +26,7 @@ public interface ClientVersioningManager {
|
|||||||
/**
|
/**
|
||||||
* Registers a client that will be advertised to contacts. The hook will
|
* Registers a client that will be advertised to contacts. The hook will
|
||||||
* be called when the visibility of the client changes. This method should
|
* be called when the visibility of the client changes. This method should
|
||||||
* be called before {@link LifecycleManager#startServices(String)}.
|
* be called before {@link LifecycleManager#startServices(SecretKey)}.
|
||||||
*/
|
*/
|
||||||
void registerClient(ClientId clientId, int majorVersion, int minorVersion,
|
void registerClient(ClientId clientId, int majorVersion, int minorVersion,
|
||||||
ClientVersioningHook hook);
|
ClientVersioningHook hook);
|
||||||
|
|||||||
24
bramble-api/witness.gradle
Normal file
24
bramble-api/witness.gradle
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
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',
|
||||||
|
'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',
|
||||||
|
'org.apache.ant:ant:1.9.4:ant-1.9.4.jar:649ae0730251de07b8913f49286d46bba7b92d47c5f332610aa426c4f02161d8',
|
||||||
|
'org.beanshell:bsh:1.3.0:bsh-1.3.0.jar:9b04edc75d19db54f1b4e8b5355e9364384c6cf71eb0a1b9724c159d779879f8',
|
||||||
|
'org.codehaus.mojo.signature:java16:1.1:java16-1.1.signature:53799223a2c98dba2d0add810bed76315460df285c69e4f397ae6098f87dd619',
|
||||||
|
'org.codehaus.mojo:animal-sniffer-ant-tasks:1.16:animal-sniffer-ant-tasks-1.16.jar:890040976fbe2d584619a6a61b1fd2e925b3b5eb342a85eb2762c467c0d64e90',
|
||||||
|
'org.codehaus.mojo:animal-sniffer:1.16:animal-sniffer-1.16.jar:72be8bcc226ba43b937c722a08a07852bfa1b11400089265d5df0ee7b38b1d52',
|
||||||
|
'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.jmock:jmock-junit4:2.8.2:jmock-junit4-2.8.2.jar:f7ee4df4f7bd7b7f1cafad3b99eb74d579f109d5992ff625347352edb55e674c',
|
||||||
|
'org.jmock:jmock-legacy:2.8.2:jmock-legacy-2.8.2.jar:f2b985a5c08a9edb7f37612330c058809da3f6a6d63ce792426ebf8ff0d6d31b',
|
||||||
|
'org.jmock:jmock-testjar:2.8.2:jmock-testjar-2.8.2.jar:8900860f72c474e027cf97fe78dcbf154a1aa7fc62b6845c5fb4e4f3c7bc8760',
|
||||||
|
'org.jmock:jmock:2.8.2:jmock-2.8.2.jar:6c73cb4a2e6dbfb61fd99c9a768539c170ab6568e57846bd60dbf19596b65b16',
|
||||||
|
'org.objenesis:objenesis:2.1:objenesis-2.1.jar:c74330cc6b806c804fd37e74487b4fe5d7c2750c5e15fbc6efa13bdee1bdef80',
|
||||||
|
'org.ow2.asm:asm-all:5.2:asm-all-5.2.jar:7fbffbc1db3422e2101689fd88df8384b15817b52b9b2b267b9f6d2511dc198d',
|
||||||
|
'org.ow2.asm:asm:5.0.4:asm-5.0.4.jar:896618ed8ae62702521a78bc7be42b7c491a08e6920a15f89a3ecdec31e9a220',
|
||||||
|
]
|
||||||
|
}
|
||||||
@@ -6,6 +6,7 @@ apply plugin: 'ru.vyarus.animalsniffer'
|
|||||||
apply plugin: 'net.ltgt.apt'
|
apply plugin: 'net.ltgt.apt'
|
||||||
apply plugin: 'idea'
|
apply plugin: 'idea'
|
||||||
apply plugin: 'witness'
|
apply plugin: 'witness'
|
||||||
|
apply from: 'witness.gradle'
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
implementation project(path: ':bramble-api', configuration: 'default')
|
implementation project(path: ':bramble-api', configuration: 'default')
|
||||||
@@ -14,6 +15,7 @@ dependencies {
|
|||||||
implementation 'org.bitlet:weupnp:0.1.4'
|
implementation 'org.bitlet:weupnp:0.1.4'
|
||||||
implementation 'net.i2p.crypto:eddsa:0.2.0'
|
implementation 'net.i2p.crypto:eddsa:0.2.0'
|
||||||
implementation 'org.whispersystems:curve25519-java:0.4.1'
|
implementation 'org.whispersystems:curve25519-java:0.4.1'
|
||||||
|
implementation 'org.briarproject:jtorctl:0.3'
|
||||||
|
|
||||||
apt 'com.google.dagger:dagger-compiler:2.0.2'
|
apt 'com.google.dagger:dagger-compiler:2.0.2'
|
||||||
|
|
||||||
@@ -31,39 +33,6 @@ dependencies {
|
|||||||
signature 'org.codehaus.mojo.signature:java16:1.1@signature'
|
signature 'org.codehaus.mojo.signature:java16:1.1@signature'
|
||||||
}
|
}
|
||||||
|
|
||||||
dependencyVerification {
|
|
||||||
verify = [
|
|
||||||
'cglib:cglib:3.2.0:cglib-3.2.0.jar:adb13bab79712ad6bdf1bd59f2a3918018a8016e722e8a357065afb9e6690861',
|
|
||||||
'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.guava:guava:18.0:guava-18.0.jar:d664fbfc03d2e5ce9cab2a44fb01f1d0bf9dfebeccc1a473b1f9ea31f79f6f99',
|
|
||||||
'com.h2database:h2:1.4.192:h2-1.4.192.jar:225b22e9857235c46c93861410b60b8c81c10dc8985f4faf188985ba5445126c',
|
|
||||||
'com.madgag.spongycastle:core:1.58.0.0:core-1.58.0.0.jar:199617dd5698c5a9312b898c0a4cec7ce9dd8649d07f65d91629f58229d72728',
|
|
||||||
'javax.inject:javax.inject:1:javax.inject-1.jar:91c77044a50c481636c32d916fd89c9118a72195390452c81065080f957de7ff',
|
|
||||||
'junit:junit:4.12:junit-4.12.jar:59721f0805e223d84b90677887d9ff567dc534d7c502ca903c0c2b17f05c116a',
|
|
||||||
'net.i2p.crypto:eddsa:0.2.0:eddsa-0.2.0.jar:a7cb1b85c16e2f0730b9204106929a1d9aaae1df728adc7041a8b8b605692140',
|
|
||||||
'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.beanshell:bsh:1.3.0:bsh-1.3.0.jar:9b04edc75d19db54f1b4e8b5355e9364384c6cf71eb0a1b9724c159d779879f8',
|
|
||||||
'org.bitlet:weupnp:0.1.4:weupnp-0.1.4.jar:88df7e6504929d00bdb832863761385c68ab92af945b04f0770b126270a444fb',
|
|
||||||
'org.codehaus.mojo.signature:java16:1.1:java16-1.1.signature:53799223a2c98dba2d0add810bed76315460df285c69e4f397ae6098f87dd619',
|
|
||||||
'org.codehaus.mojo:animal-sniffer-ant-tasks:1.16:animal-sniffer-ant-tasks-1.16.jar:890040976fbe2d584619a6a61b1fd2e925b3b5eb342a85eb2762c467c0d64e90',
|
|
||||||
'org.codehaus.mojo:animal-sniffer:1.16:animal-sniffer-1.16.jar:72be8bcc226ba43b937c722a08a07852bfa1b11400089265d5df0ee7b38b1d52',
|
|
||||||
'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.hsqldb:hsqldb:2.3.5:hsqldb-2.3.5.jar:6676a6977ac98997a80f827ddbd3fe8ca1e0853dad1492512135fd1a222ccfad',
|
|
||||||
'org.jmock:jmock-junit4:2.8.2:jmock-junit4-2.8.2.jar:f7ee4df4f7bd7b7f1cafad3b99eb74d579f109d5992ff625347352edb55e674c',
|
|
||||||
'org.jmock:jmock-legacy:2.8.2:jmock-legacy-2.8.2.jar:f2b985a5c08a9edb7f37612330c058809da3f6a6d63ce792426ebf8ff0d6d31b',
|
|
||||||
'org.jmock:jmock-testjar:2.8.2:jmock-testjar-2.8.2.jar:8900860f72c474e027cf97fe78dcbf154a1aa7fc62b6845c5fb4e4f3c7bc8760',
|
|
||||||
'org.jmock:jmock:2.8.2:jmock-2.8.2.jar:6c73cb4a2e6dbfb61fd99c9a768539c170ab6568e57846bd60dbf19596b65b16',
|
|
||||||
'org.objenesis:objenesis:2.1:objenesis-2.1.jar:c74330cc6b806c804fd37e74487b4fe5d7c2750c5e15fbc6efa13bdee1bdef80',
|
|
||||||
'org.ow2.asm:asm-all:5.2:asm-all-5.2.jar:7fbffbc1db3422e2101689fd88df8384b15817b52b9b2b267b9f6d2511dc198d',
|
|
||||||
'org.ow2.asm:asm:5.0.4:asm-5.0.4.jar:896618ed8ae62702521a78bc7be42b7c491a08e6920a15f89a3ecdec31e9a220',
|
|
||||||
'org.whispersystems:curve25519-java:0.4.1:curve25519-java-0.4.1.jar:7dd659d8822c06c3aea1a47f18fac9e5761e29cab8100030b877db445005f03e',
|
|
||||||
]
|
|
||||||
}
|
|
||||||
|
|
||||||
// needed to make test output available to bramble-j2se
|
// needed to make test output available to bramble-j2se
|
||||||
configurations {
|
configurations {
|
||||||
testOutput.extendsFrom(testCompile)
|
testOutput.extendsFrom(testCompile)
|
||||||
@@ -75,3 +44,8 @@ task jarTest(type: Jar, dependsOn: testClasses) {
|
|||||||
artifacts {
|
artifacts {
|
||||||
testOutput jarTest
|
testOutput jarTest
|
||||||
}
|
}
|
||||||
|
|
||||||
|
tasks.withType(Test) {
|
||||||
|
// Use entropy-gathering device specified on command line, if any
|
||||||
|
systemProperty 'java.security.egd', System.getProperty('java.security.egd')
|
||||||
|
}
|
||||||
|
|||||||
@@ -0,0 +1,221 @@
|
|||||||
|
package org.briarproject.bramble.account;
|
||||||
|
|
||||||
|
import org.briarproject.bramble.api.account.AccountManager;
|
||||||
|
import org.briarproject.bramble.api.crypto.CryptoComponent;
|
||||||
|
import org.briarproject.bramble.api.crypto.SecretKey;
|
||||||
|
import org.briarproject.bramble.api.db.DatabaseConfig;
|
||||||
|
import org.briarproject.bramble.api.identity.IdentityManager;
|
||||||
|
import org.briarproject.bramble.api.identity.LocalAuthor;
|
||||||
|
import org.briarproject.bramble.api.nullsafety.MethodsNotNullByDefault;
|
||||||
|
import org.briarproject.bramble.api.nullsafety.ParametersNotNullByDefault;
|
||||||
|
import org.briarproject.bramble.util.IoUtils;
|
||||||
|
|
||||||
|
import java.io.BufferedReader;
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.FileInputStream;
|
||||||
|
import java.io.FileOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStreamReader;
|
||||||
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
|
import javax.annotation.Nullable;
|
||||||
|
import javax.inject.Inject;
|
||||||
|
|
||||||
|
import static java.util.logging.Level.WARNING;
|
||||||
|
import static org.briarproject.bramble.util.LogUtils.logException;
|
||||||
|
import static org.briarproject.bramble.util.StringUtils.fromHexString;
|
||||||
|
import static org.briarproject.bramble.util.StringUtils.toHexString;
|
||||||
|
|
||||||
|
@MethodsNotNullByDefault
|
||||||
|
@ParametersNotNullByDefault
|
||||||
|
class AccountManagerImpl implements AccountManager {
|
||||||
|
|
||||||
|
private static final Logger LOG =
|
||||||
|
Logger.getLogger(AccountManagerImpl.class.getName());
|
||||||
|
|
||||||
|
private static final String DB_KEY_FILENAME = "db.key";
|
||||||
|
private static final String DB_KEY_BACKUP_FILENAME = "db.key.bak";
|
||||||
|
|
||||||
|
private final DatabaseConfig databaseConfig;
|
||||||
|
private final CryptoComponent crypto;
|
||||||
|
private final IdentityManager identityManager;
|
||||||
|
private final File dbKeyFile, dbKeyBackupFile;
|
||||||
|
|
||||||
|
final Object stateChangeLock = new Object();
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
private volatile SecretKey databaseKey = null;
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
AccountManagerImpl(DatabaseConfig databaseConfig, CryptoComponent crypto,
|
||||||
|
IdentityManager identityManager) {
|
||||||
|
this.databaseConfig = databaseConfig;
|
||||||
|
this.crypto = crypto;
|
||||||
|
this.identityManager = identityManager;
|
||||||
|
File keyDir = databaseConfig.getDatabaseKeyDirectory();
|
||||||
|
dbKeyFile = new File(keyDir, DB_KEY_FILENAME);
|
||||||
|
dbKeyBackupFile = new File(keyDir, DB_KEY_BACKUP_FILENAME);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean hasDatabaseKey() {
|
||||||
|
return databaseKey != null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Nullable
|
||||||
|
public SecretKey getDatabaseKey() {
|
||||||
|
return databaseKey;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Locking: stateChangeLock
|
||||||
|
@Nullable
|
||||||
|
protected String loadEncryptedDatabaseKey() {
|
||||||
|
String key = readDbKeyFromFile(dbKeyFile);
|
||||||
|
if (key == null) {
|
||||||
|
LOG.info("No database key in primary file");
|
||||||
|
key = readDbKeyFromFile(dbKeyBackupFile);
|
||||||
|
if (key == null) LOG.info("No database key in backup file");
|
||||||
|
else LOG.warning("Found database key in backup file");
|
||||||
|
} else {
|
||||||
|
LOG.info("Found database key in primary file");
|
||||||
|
}
|
||||||
|
return key;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Locking: stateChangeLock
|
||||||
|
@Nullable
|
||||||
|
private String readDbKeyFromFile(File f) {
|
||||||
|
if (!f.exists()) {
|
||||||
|
LOG.info("Key file does not exist");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
BufferedReader reader = new BufferedReader(new InputStreamReader(
|
||||||
|
new FileInputStream(f), "UTF-8"));
|
||||||
|
String key = reader.readLine();
|
||||||
|
reader.close();
|
||||||
|
return key;
|
||||||
|
} catch (IOException e) {
|
||||||
|
logException(LOG, WARNING, e);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Locking: stateChangeLock
|
||||||
|
protected boolean storeEncryptedDatabaseKey(String hex) {
|
||||||
|
LOG.info("Storing database key in file");
|
||||||
|
// Create the directory if necessary
|
||||||
|
if (databaseConfig.getDatabaseKeyDirectory().mkdirs())
|
||||||
|
LOG.info("Created database key directory");
|
||||||
|
// If only the backup file exists, rename it so we don't overwrite it
|
||||||
|
if (dbKeyBackupFile.exists() && !dbKeyFile.exists()) {
|
||||||
|
if (dbKeyBackupFile.renameTo(dbKeyFile))
|
||||||
|
LOG.info("Renamed old backup");
|
||||||
|
else LOG.warning("Failed to rename old backup");
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
// Write to the backup file
|
||||||
|
writeDbKeyToFile(hex, dbKeyBackupFile);
|
||||||
|
LOG.info("Stored database key in backup file");
|
||||||
|
// Delete the old primary file, if it exists
|
||||||
|
if (dbKeyFile.exists()) {
|
||||||
|
if (dbKeyFile.delete()) LOG.info("Deleted primary file");
|
||||||
|
else LOG.warning("Failed to delete primary file");
|
||||||
|
}
|
||||||
|
// The backup file becomes the new primary
|
||||||
|
if (dbKeyBackupFile.renameTo(dbKeyFile)) {
|
||||||
|
LOG.info("Renamed backup file to primary");
|
||||||
|
} else {
|
||||||
|
LOG.warning("Failed to rename backup file to primary");
|
||||||
|
return false; // Don't overwrite our only copy
|
||||||
|
}
|
||||||
|
// Write a second copy to the backup file
|
||||||
|
writeDbKeyToFile(hex, dbKeyBackupFile);
|
||||||
|
LOG.info("Stored second copy of database key in backup file");
|
||||||
|
return true;
|
||||||
|
} catch (IOException e) {
|
||||||
|
logException(LOG, WARNING, e);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Locking: stateChangeLock
|
||||||
|
private void writeDbKeyToFile(String key, File f) throws IOException {
|
||||||
|
FileOutputStream out = new FileOutputStream(f);
|
||||||
|
out.write(key.getBytes("UTF-8"));
|
||||||
|
out.flush();
|
||||||
|
out.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean accountExists() {
|
||||||
|
synchronized (stateChangeLock) {
|
||||||
|
return loadEncryptedDatabaseKey() != null
|
||||||
|
&& databaseConfig.getDatabaseDirectory().isDirectory();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean createAccount(String name, String password) {
|
||||||
|
synchronized (stateChangeLock) {
|
||||||
|
LocalAuthor localAuthor = identityManager.createLocalAuthor(name);
|
||||||
|
identityManager.registerLocalAuthor(localAuthor);
|
||||||
|
SecretKey key = crypto.generateSecretKey();
|
||||||
|
if (!encryptAndStoreDatabaseKey(key, password)) return false;
|
||||||
|
databaseKey = key;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Locking: stateChangeLock
|
||||||
|
private boolean encryptAndStoreDatabaseKey(SecretKey key, String password) {
|
||||||
|
byte[] plaintext = key.getBytes();
|
||||||
|
byte[] ciphertext = crypto.encryptWithPassword(plaintext, password);
|
||||||
|
return storeEncryptedDatabaseKey(toHexString(ciphertext));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void deleteAccount() {
|
||||||
|
synchronized (stateChangeLock) {
|
||||||
|
LOG.info("Deleting account");
|
||||||
|
IoUtils.deleteFileOrDir(databaseConfig.getDatabaseKeyDirectory());
|
||||||
|
IoUtils.deleteFileOrDir(databaseConfig.getDatabaseDirectory());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean signIn(String password) {
|
||||||
|
synchronized (stateChangeLock) {
|
||||||
|
SecretKey key = loadAndDecryptDatabaseKey(password);
|
||||||
|
if (key == null) return false;
|
||||||
|
databaseKey = key;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Locking: stateChangeLock
|
||||||
|
@Nullable
|
||||||
|
private SecretKey loadAndDecryptDatabaseKey(String password) {
|
||||||
|
String hex = loadEncryptedDatabaseKey();
|
||||||
|
if (hex == null) {
|
||||||
|
LOG.warning("Failed to load encrypted database key");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
byte[] ciphertext = fromHexString(hex);
|
||||||
|
byte[] plaintext = crypto.decryptWithPassword(ciphertext, password);
|
||||||
|
if (plaintext == null) {
|
||||||
|
LOG.info("Failed to decrypt database key");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return new SecretKey(plaintext);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean changePassword(String oldPassword, String newPassword) {
|
||||||
|
synchronized (stateChangeLock) {
|
||||||
|
SecretKey key = loadAndDecryptDatabaseKey(oldPassword);
|
||||||
|
return key != null && encryptAndStoreDatabaseKey(key, newPassword);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
package org.briarproject.bramble.account;
|
||||||
|
|
||||||
|
import org.briarproject.bramble.api.account.AccountManager;
|
||||||
|
|
||||||
|
import javax.inject.Singleton;
|
||||||
|
|
||||||
|
import dagger.Module;
|
||||||
|
import dagger.Provides;
|
||||||
|
|
||||||
|
@Module
|
||||||
|
public class AccountModule {
|
||||||
|
|
||||||
|
@Provides
|
||||||
|
@Singleton
|
||||||
|
AccountManager provideAccountManager(AccountManagerImpl accountManager) {
|
||||||
|
return accountManager;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -2,6 +2,7 @@ package org.briarproject.bramble.db;
|
|||||||
|
|
||||||
import org.briarproject.bramble.api.contact.Contact;
|
import org.briarproject.bramble.api.contact.Contact;
|
||||||
import org.briarproject.bramble.api.contact.ContactId;
|
import org.briarproject.bramble.api.contact.ContactId;
|
||||||
|
import org.briarproject.bramble.api.crypto.SecretKey;
|
||||||
import org.briarproject.bramble.api.db.DataTooNewException;
|
import org.briarproject.bramble.api.db.DataTooNewException;
|
||||||
import org.briarproject.bramble.api.db.DataTooOldException;
|
import org.briarproject.bramble.api.db.DataTooOldException;
|
||||||
import org.briarproject.bramble.api.db.DbException;
|
import org.briarproject.bramble.api.db.DbException;
|
||||||
@@ -48,7 +49,8 @@ interface Database<T> {
|
|||||||
* @throws DataTooOldException if the data uses an older schema than the
|
* @throws DataTooOldException if the data uses an older schema than the
|
||||||
* current code and cannot be migrated
|
* current code and cannot be migrated
|
||||||
*/
|
*/
|
||||||
boolean open(@Nullable MigrationListener listener) throws DbException;
|
boolean open(SecretKey key, @Nullable MigrationListener listener)
|
||||||
|
throws DbException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Prevents new transactions from starting, waits for all current
|
* Prevents new transactions from starting, waits for all current
|
||||||
@@ -641,7 +643,7 @@ interface Database<T> {
|
|||||||
* Marks the given transport keys as usable for outgoing streams.
|
* Marks the given transport keys as usable for outgoing streams.
|
||||||
*/
|
*/
|
||||||
void setTransportKeysActive(T txn, TransportId t, KeySetId k)
|
void setTransportKeysActive(T txn, TransportId t, KeySetId k)
|
||||||
throws DbException;
|
throws DbException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Updates the transmission count and expiry time of the given message
|
* Updates the transmission count and expiry time of the given message
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import org.briarproject.bramble.api.contact.event.ContactAddedEvent;
|
|||||||
import org.briarproject.bramble.api.contact.event.ContactRemovedEvent;
|
import org.briarproject.bramble.api.contact.event.ContactRemovedEvent;
|
||||||
import org.briarproject.bramble.api.contact.event.ContactStatusChangedEvent;
|
import org.briarproject.bramble.api.contact.event.ContactStatusChangedEvent;
|
||||||
import org.briarproject.bramble.api.contact.event.ContactVerifiedEvent;
|
import org.briarproject.bramble.api.contact.event.ContactVerifiedEvent;
|
||||||
|
import org.briarproject.bramble.api.crypto.SecretKey;
|
||||||
import org.briarproject.bramble.api.db.ContactExistsException;
|
import org.briarproject.bramble.api.db.ContactExistsException;
|
||||||
import org.briarproject.bramble.api.db.DatabaseComponent;
|
import org.briarproject.bramble.api.db.DatabaseComponent;
|
||||||
import org.briarproject.bramble.api.db.DbException;
|
import org.briarproject.bramble.api.db.DbException;
|
||||||
@@ -103,9 +104,9 @@ class DatabaseComponentImpl<T> implements DatabaseComponent {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean open(@Nullable MigrationListener listener)
|
public boolean open(SecretKey key, @Nullable MigrationListener listener)
|
||||||
throws DbException {
|
throws DbException {
|
||||||
boolean reopened = db.open(listener);
|
boolean reopened = db.open(key, listener);
|
||||||
shutdown.addShutdownHook(() -> {
|
shutdown.addShutdownHook(() -> {
|
||||||
try {
|
try {
|
||||||
close();
|
close();
|
||||||
|
|||||||
@@ -32,6 +32,9 @@ class H2Database extends JdbcDatabase {
|
|||||||
private final DatabaseConfig config;
|
private final DatabaseConfig config;
|
||||||
private final String url;
|
private final String url;
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
private volatile SecretKey key = null;
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
H2Database(DatabaseConfig config, Clock clock) {
|
H2Database(DatabaseConfig config, Clock clock) {
|
||||||
super(HASH_TYPE, SECRET_TYPE, BINARY_TYPE, COUNTER_TYPE, STRING_TYPE,
|
super(HASH_TYPE, SECRET_TYPE, BINARY_TYPE, COUNTER_TYPE, STRING_TYPE,
|
||||||
@@ -44,11 +47,11 @@ class H2Database extends JdbcDatabase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean open(@Nullable MigrationListener listener)
|
public boolean open(SecretKey key, @Nullable MigrationListener listener)
|
||||||
throws DbException {
|
throws DbException {
|
||||||
boolean reopen = config.databaseExists();
|
this.key = key;
|
||||||
if (!reopen) config.getDatabaseDirectory().mkdirs();
|
boolean reopen = !config.getDatabaseDirectory().mkdirs();
|
||||||
super.open("org.h2.Driver", reopen, listener);
|
super.open("org.h2.Driver", reopen, key, listener);
|
||||||
return reopen;
|
return reopen;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -63,7 +66,7 @@ class H2Database extends JdbcDatabase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public long getFreeSpace() throws DbException {
|
public long getFreeSpace() {
|
||||||
File dir = config.getDatabaseDirectory();
|
File dir = config.getDatabaseDirectory();
|
||||||
long maxSize = config.getMaxSize();
|
long maxSize = config.getMaxSize();
|
||||||
long free = dir.getFreeSpace();
|
long free = dir.getFreeSpace();
|
||||||
@@ -88,7 +91,7 @@ class H2Database extends JdbcDatabase {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected Connection createConnection() throws SQLException {
|
protected Connection createConnection() throws SQLException {
|
||||||
SecretKey key = config.getEncryptionKey();
|
SecretKey key = this.key;
|
||||||
if (key == null) throw new IllegalStateException();
|
if (key == null) throw new IllegalStateException();
|
||||||
Properties props = new Properties();
|
Properties props = new Properties();
|
||||||
props.setProperty("user", "user");
|
props.setProperty("user", "user");
|
||||||
|
|||||||
@@ -33,6 +33,9 @@ class HyperSqlDatabase extends JdbcDatabase {
|
|||||||
private final DatabaseConfig config;
|
private final DatabaseConfig config;
|
||||||
private final String url;
|
private final String url;
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
private volatile SecretKey key = null;
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
HyperSqlDatabase(DatabaseConfig config, Clock clock) {
|
HyperSqlDatabase(DatabaseConfig config, Clock clock) {
|
||||||
super(HASH_TYPE, SECRET_TYPE, BINARY_TYPE, COUNTER_TYPE, STRING_TYPE,
|
super(HASH_TYPE, SECRET_TYPE, BINARY_TYPE, COUNTER_TYPE, STRING_TYPE,
|
||||||
@@ -46,10 +49,11 @@ class HyperSqlDatabase extends JdbcDatabase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean open(@Nullable MigrationListener listener) throws DbException {
|
public boolean open(SecretKey key, @Nullable MigrationListener listener)
|
||||||
boolean reopen = config.databaseExists();
|
throws DbException {
|
||||||
if (!reopen) config.getDatabaseDirectory().mkdirs();
|
this.key = key;
|
||||||
super.open("org.hsqldb.jdbc.JDBCDriver", reopen, listener);
|
boolean reopen = !config.getDatabaseDirectory().mkdirs();
|
||||||
|
super.open("org.hsqldb.jdbc.JDBCDriver", reopen, key, listener);
|
||||||
return reopen;
|
return reopen;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -93,7 +97,7 @@ class HyperSqlDatabase extends JdbcDatabase {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected Connection createConnection() throws SQLException {
|
protected Connection createConnection() throws SQLException {
|
||||||
SecretKey key = config.getEncryptionKey();
|
SecretKey key = this.key;
|
||||||
if (key == null) throw new IllegalStateException();
|
if (key == null) throw new IllegalStateException();
|
||||||
String hex = StringUtils.toHexString(key.getBytes());
|
String hex = StringUtils.toHexString(key.getBytes());
|
||||||
return DriverManager.getConnection(url + ";crypt_key=" + hex);
|
return DriverManager.getConnection(url + ";crypt_key=" + hex);
|
||||||
|
|||||||
@@ -328,7 +328,7 @@ abstract class JdbcDatabase implements Database<Connection> {
|
|||||||
this.clock = clock;
|
this.clock = clock;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void open(String driverClass, boolean reopen,
|
protected void open(String driverClass, boolean reopen, SecretKey key,
|
||||||
@Nullable MigrationListener listener) throws DbException {
|
@Nullable MigrationListener listener) throws DbException {
|
||||||
// Load the JDBC driver
|
// Load the JDBC driver
|
||||||
try {
|
try {
|
||||||
|
|||||||
@@ -1,10 +1,13 @@
|
|||||||
package org.briarproject.bramble.identity;
|
package org.briarproject.bramble.identity;
|
||||||
|
|
||||||
import org.briarproject.bramble.api.contact.Contact;
|
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.DatabaseComponent;
|
||||||
import org.briarproject.bramble.api.db.DbException;
|
import org.briarproject.bramble.api.db.DbException;
|
||||||
import org.briarproject.bramble.api.db.Transaction;
|
import org.briarproject.bramble.api.db.Transaction;
|
||||||
import org.briarproject.bramble.api.identity.Author.Status;
|
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.AuthorId;
|
||||||
import org.briarproject.bramble.api.identity.IdentityManager;
|
import org.briarproject.bramble.api.identity.IdentityManager;
|
||||||
import org.briarproject.bramble.api.identity.LocalAuthor;
|
import org.briarproject.bramble.api.identity.LocalAuthor;
|
||||||
@@ -21,6 +24,8 @@ 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.UNKNOWN;
|
||||||
import static org.briarproject.bramble.api.identity.Author.Status.UNVERIFIED;
|
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.api.identity.Author.Status.VERIFIED;
|
||||||
|
import static org.briarproject.bramble.util.LogUtils.logDuration;
|
||||||
|
import static org.briarproject.bramble.util.LogUtils.now;
|
||||||
|
|
||||||
@ThreadSafe
|
@ThreadSafe
|
||||||
@NotNullByDefault
|
@NotNullByDefault
|
||||||
@@ -30,25 +35,51 @@ class IdentityManagerImpl implements IdentityManager {
|
|||||||
Logger.getLogger(IdentityManagerImpl.class.getName());
|
Logger.getLogger(IdentityManagerImpl.class.getName());
|
||||||
|
|
||||||
private final DatabaseComponent db;
|
private final DatabaseComponent db;
|
||||||
|
private final CryptoComponent crypto;
|
||||||
|
private final AuthorFactory authorFactory;
|
||||||
|
|
||||||
// The local author is immutable so we can cache it
|
// The local author is immutable so we can cache it
|
||||||
@Nullable
|
@Nullable
|
||||||
private volatile LocalAuthor cachedAuthor;
|
private volatile LocalAuthor cachedAuthor;
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
IdentityManagerImpl(DatabaseComponent db) {
|
IdentityManagerImpl(DatabaseComponent db, CryptoComponent crypto,
|
||||||
|
AuthorFactory authorFactory) {
|
||||||
this.db = db;
|
this.db = db;
|
||||||
|
this.crypto = crypto;
|
||||||
|
this.authorFactory = authorFactory;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void registerLocalAuthor(LocalAuthor localAuthor)
|
public LocalAuthor createLocalAuthor(String name) {
|
||||||
throws DbException {
|
long start = now();
|
||||||
|
KeyPair keyPair = crypto.generateSignatureKeyPair();
|
||||||
|
byte[] publicKey = keyPair.getPublic().getEncoded();
|
||||||
|
byte[] privateKey = keyPair.getPrivate().getEncoded();
|
||||||
|
LocalAuthor localAuthor = authorFactory.createLocalAuthor(name,
|
||||||
|
publicKey, privateKey);
|
||||||
|
logDuration(LOG, "Creating local author", start);
|
||||||
|
return localAuthor;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void registerLocalAuthor(LocalAuthor a) {
|
||||||
|
cachedAuthor = a;
|
||||||
|
LOG.info("Local author registered");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void storeLocalAuthor() throws DbException {
|
||||||
|
LocalAuthor cached = cachedAuthor;
|
||||||
|
if (cached == null) {
|
||||||
|
LOG.info("No local author to store");
|
||||||
|
return;
|
||||||
|
}
|
||||||
Transaction txn = db.startTransaction(false);
|
Transaction txn = db.startTransaction(false);
|
||||||
try {
|
try {
|
||||||
db.addLocalAuthor(txn, localAuthor);
|
db.addLocalAuthor(txn, cached);
|
||||||
db.commitTransaction(txn);
|
db.commitTransaction(txn);
|
||||||
cachedAuthor = localAuthor;
|
LOG.info("Local author stored");
|
||||||
LOG.info("Local author registered");
|
|
||||||
} finally {
|
} finally {
|
||||||
db.endTransaction(txn);
|
db.endTransaction(txn);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
package org.briarproject.bramble.lifecycle;
|
package org.briarproject.bramble.lifecycle;
|
||||||
|
|
||||||
import org.briarproject.bramble.api.crypto.CryptoComponent;
|
import org.briarproject.bramble.api.crypto.SecretKey;
|
||||||
import org.briarproject.bramble.api.crypto.KeyPair;
|
|
||||||
import org.briarproject.bramble.api.db.DataTooNewException;
|
import org.briarproject.bramble.api.db.DataTooNewException;
|
||||||
import org.briarproject.bramble.api.db.DataTooOldException;
|
import org.briarproject.bramble.api.db.DataTooOldException;
|
||||||
import org.briarproject.bramble.api.db.DatabaseComponent;
|
import org.briarproject.bramble.api.db.DatabaseComponent;
|
||||||
@@ -9,9 +8,7 @@ import org.briarproject.bramble.api.db.DbException;
|
|||||||
import org.briarproject.bramble.api.db.MigrationListener;
|
import org.briarproject.bramble.api.db.MigrationListener;
|
||||||
import org.briarproject.bramble.api.db.Transaction;
|
import org.briarproject.bramble.api.db.Transaction;
|
||||||
import org.briarproject.bramble.api.event.EventBus;
|
import org.briarproject.bramble.api.event.EventBus;
|
||||||
import org.briarproject.bramble.api.identity.AuthorFactory;
|
|
||||||
import org.briarproject.bramble.api.identity.IdentityManager;
|
import org.briarproject.bramble.api.identity.IdentityManager;
|
||||||
import org.briarproject.bramble.api.identity.LocalAuthor;
|
|
||||||
import org.briarproject.bramble.api.lifecycle.LifecycleManager;
|
import org.briarproject.bramble.api.lifecycle.LifecycleManager;
|
||||||
import org.briarproject.bramble.api.lifecycle.Service;
|
import org.briarproject.bramble.api.lifecycle.Service;
|
||||||
import org.briarproject.bramble.api.lifecycle.ServiceException;
|
import org.briarproject.bramble.api.lifecycle.ServiceException;
|
||||||
@@ -26,7 +23,6 @@ import java.util.concurrent.ExecutorService;
|
|||||||
import java.util.concurrent.Semaphore;
|
import java.util.concurrent.Semaphore;
|
||||||
import java.util.logging.Logger;
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
import javax.annotation.Nullable;
|
|
||||||
import javax.annotation.concurrent.ThreadSafe;
|
import javax.annotation.concurrent.ThreadSafe;
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
|
|
||||||
@@ -60,8 +56,6 @@ class LifecycleManagerImpl implements LifecycleManager, MigrationListener {
|
|||||||
private final List<Service> services;
|
private final List<Service> services;
|
||||||
private final List<Client> clients;
|
private final List<Client> clients;
|
||||||
private final List<ExecutorService> executors;
|
private final List<ExecutorService> executors;
|
||||||
private final CryptoComponent crypto;
|
|
||||||
private final AuthorFactory authorFactory;
|
|
||||||
private final IdentityManager identityManager;
|
private final IdentityManager identityManager;
|
||||||
private final Semaphore startStopSemaphore = new Semaphore(1);
|
private final Semaphore startStopSemaphore = new Semaphore(1);
|
||||||
private final CountDownLatch dbLatch = new CountDownLatch(1);
|
private final CountDownLatch dbLatch = new CountDownLatch(1);
|
||||||
@@ -72,12 +66,9 @@ class LifecycleManagerImpl implements LifecycleManager, MigrationListener {
|
|||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
LifecycleManagerImpl(DatabaseComponent db, EventBus eventBus,
|
LifecycleManagerImpl(DatabaseComponent db, EventBus eventBus,
|
||||||
CryptoComponent crypto, AuthorFactory authorFactory,
|
|
||||||
IdentityManager identityManager) {
|
IdentityManager identityManager) {
|
||||||
this.db = db;
|
this.db = db;
|
||||||
this.eventBus = eventBus;
|
this.eventBus = eventBus;
|
||||||
this.crypto = crypto;
|
|
||||||
this.authorFactory = authorFactory;
|
|
||||||
this.identityManager = identityManager;
|
this.identityManager = identityManager;
|
||||||
services = new CopyOnWriteArrayList<>();
|
services = new CopyOnWriteArrayList<>();
|
||||||
clients = new CopyOnWriteArrayList<>();
|
clients = new CopyOnWriteArrayList<>();
|
||||||
@@ -104,25 +95,8 @@ class LifecycleManagerImpl implements LifecycleManager, MigrationListener {
|
|||||||
executors.add(e);
|
executors.add(e);
|
||||||
}
|
}
|
||||||
|
|
||||||
private LocalAuthor createLocalAuthor(String nickname) {
|
|
||||||
long start = now();
|
|
||||||
KeyPair keyPair = crypto.generateSignatureKeyPair();
|
|
||||||
byte[] publicKey = keyPair.getPublic().getEncoded();
|
|
||||||
byte[] privateKey = keyPair.getPrivate().getEncoded();
|
|
||||||
LocalAuthor localAuthor = authorFactory
|
|
||||||
.createLocalAuthor(nickname, publicKey, privateKey);
|
|
||||||
logDuration(LOG, "Creating local author", start);
|
|
||||||
return localAuthor;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void registerLocalAuthor(LocalAuthor author) throws DbException {
|
|
||||||
long start = now();
|
|
||||||
identityManager.registerLocalAuthor(author);
|
|
||||||
logDuration(LOG, "Registering local author", start);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public StartResult startServices(@Nullable String nickname) {
|
public StartResult startServices(SecretKey dbKey) {
|
||||||
if (!startStopSemaphore.tryAcquire()) {
|
if (!startStopSemaphore.tryAcquire()) {
|
||||||
LOG.info("Already starting or stopping");
|
LOG.info("Already starting or stopping");
|
||||||
return ALREADY_RUNNING;
|
return ALREADY_RUNNING;
|
||||||
@@ -131,13 +105,10 @@ class LifecycleManagerImpl implements LifecycleManager, MigrationListener {
|
|||||||
LOG.info("Starting services");
|
LOG.info("Starting services");
|
||||||
long start = now();
|
long start = now();
|
||||||
|
|
||||||
boolean reopened = db.open(this);
|
boolean reopened = db.open(dbKey, this);
|
||||||
if (reopened) logDuration(LOG, "Reopening database", start);
|
if (reopened) logDuration(LOG, "Reopening database", start);
|
||||||
else logDuration(LOG, "Creating database", start);
|
else logDuration(LOG, "Creating database", start);
|
||||||
|
identityManager.storeLocalAuthor();
|
||||||
if (nickname != null) {
|
|
||||||
registerLocalAuthor(createLocalAuthor(nickname));
|
|
||||||
}
|
|
||||||
|
|
||||||
state = STARTING_SERVICES;
|
state = STARTING_SERVICES;
|
||||||
dbLatch.countDown();
|
dbLatch.countDown();
|
||||||
|
|||||||
@@ -1,10 +1,5 @@
|
|||||||
package org.briarproject.bramble.lifecycle;
|
package org.briarproject.bramble.lifecycle;
|
||||||
|
|
||||||
import org.briarproject.bramble.api.crypto.CryptoComponent;
|
|
||||||
import org.briarproject.bramble.api.db.DatabaseComponent;
|
|
||||||
import org.briarproject.bramble.api.event.EventBus;
|
|
||||||
import org.briarproject.bramble.api.identity.AuthorFactory;
|
|
||||||
import org.briarproject.bramble.api.identity.IdentityManager;
|
|
||||||
import org.briarproject.bramble.api.lifecycle.IoExecutor;
|
import org.briarproject.bramble.api.lifecycle.IoExecutor;
|
||||||
import org.briarproject.bramble.api.lifecycle.LifecycleManager;
|
import org.briarproject.bramble.api.lifecycle.LifecycleManager;
|
||||||
import org.briarproject.bramble.api.lifecycle.ShutdownManager;
|
import org.briarproject.bramble.api.lifecycle.ShutdownManager;
|
||||||
@@ -54,11 +49,9 @@ public class LifecycleModule {
|
|||||||
|
|
||||||
@Provides
|
@Provides
|
||||||
@Singleton
|
@Singleton
|
||||||
LifecycleManager provideLifecycleManager(DatabaseComponent db,
|
LifecycleManager provideLifecycleManager(
|
||||||
EventBus eventBus, CryptoComponent crypto,
|
LifecycleManagerImpl lifecycleManager) {
|
||||||
AuthorFactory authorFactory, IdentityManager identityManager) {
|
return lifecycleManager;
|
||||||
return new LifecycleManagerImpl(db, eventBus, crypto, authorFactory,
|
|
||||||
identityManager);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Provides
|
@Provides
|
||||||
|
|||||||
@@ -0,0 +1,17 @@
|
|||||||
|
package org.briarproject.bramble.plugin.tor;
|
||||||
|
|
||||||
|
import javax.inject.Singleton;
|
||||||
|
|
||||||
|
import dagger.Module;
|
||||||
|
import dagger.Provides;
|
||||||
|
|
||||||
|
@Module
|
||||||
|
public class CircumventionModule {
|
||||||
|
|
||||||
|
@Provides
|
||||||
|
@Singleton
|
||||||
|
CircumventionProvider provideCircumventionProvider(
|
||||||
|
CircumventionProviderImpl provider) {
|
||||||
|
return provider;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -4,6 +4,8 @@ import org.briarproject.bramble.api.lifecycle.IoExecutor;
|
|||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
// TODO: Create a module for this so it doesn't have to be public
|
||||||
|
|
||||||
public interface CircumventionProvider {
|
public interface CircumventionProvider {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -1,13 +1,10 @@
|
|||||||
package org.briarproject.bramble.plugin.tor;
|
package org.briarproject.bramble.plugin.tor;
|
||||||
|
|
||||||
import android.content.Context;
|
|
||||||
import android.content.res.Resources;
|
|
||||||
|
|
||||||
import org.briarproject.bramble.api.lifecycle.IoExecutor;
|
import org.briarproject.bramble.api.lifecycle.IoExecutor;
|
||||||
|
import org.briarproject.bramble.api.system.ResourceProvider;
|
||||||
|
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Scanner;
|
import java.util.Scanner;
|
||||||
@@ -16,24 +13,27 @@ import java.util.Set;
|
|||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
|
|
||||||
public class CircumventionProviderImpl implements CircumventionProvider {
|
import static java.util.Arrays.asList;
|
||||||
|
|
||||||
|
class CircumventionProviderImpl implements CircumventionProvider {
|
||||||
|
|
||||||
private final static String BRIDGE_FILE_NAME = "bridges";
|
private final static String BRIDGE_FILE_NAME = "bridges";
|
||||||
|
|
||||||
private final Context ctx;
|
private static final Set<String> BLOCKED_IN_COUNTRIES =
|
||||||
|
new HashSet<>(asList(BLOCKED));
|
||||||
|
private static final Set<String> BRIDGES_WORK_IN_COUNTRIES =
|
||||||
|
new HashSet<>(asList(BRIDGES));
|
||||||
|
|
||||||
|
private final ResourceProvider resourceProvider;
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
private volatile List<String> bridges = null;
|
private volatile List<String> bridges = null;
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
public CircumventionProviderImpl(Context ctx) {
|
CircumventionProviderImpl(ResourceProvider resourceProvider) {
|
||||||
this.ctx = ctx;
|
this.resourceProvider = resourceProvider;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static final Set<String> BLOCKED_IN_COUNTRIES =
|
|
||||||
new HashSet<>(Arrays.asList(BLOCKED));
|
|
||||||
private static final Set<String> BRIDGES_WORK_IN_COUNTRIES =
|
|
||||||
new HashSet<>(Arrays.asList(BRIDGES));
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isTorProbablyBlocked(String countryCode) {
|
public boolean isTorProbablyBlocked(String countryCode) {
|
||||||
return BLOCKED_IN_COUNTRIES.contains(countryCode);
|
return BLOCKED_IN_COUNTRIES.contains(countryCode);
|
||||||
@@ -47,15 +47,14 @@ public class CircumventionProviderImpl implements CircumventionProvider {
|
|||||||
@Override
|
@Override
|
||||||
@IoExecutor
|
@IoExecutor
|
||||||
public List<String> getBridges() {
|
public List<String> getBridges() {
|
||||||
if (this.bridges != null) return this.bridges;
|
List<String> bridges = this.bridges;
|
||||||
|
if (bridges != null) return new ArrayList<>(bridges);
|
||||||
|
|
||||||
Resources res = ctx.getResources();
|
InputStream is =
|
||||||
int resId = res.getIdentifier(BRIDGE_FILE_NAME, "raw",
|
resourceProvider.getResourceInputStream(BRIDGE_FILE_NAME);
|
||||||
ctx.getPackageName());
|
|
||||||
InputStream is = ctx.getResources().openRawResource(resId);
|
|
||||||
Scanner scanner = new Scanner(is);
|
Scanner scanner = new Scanner(is);
|
||||||
|
|
||||||
List<String> bridges = new ArrayList<>();
|
bridges = new ArrayList<>();
|
||||||
while (scanner.hasNextLine()) {
|
while (scanner.hasNextLine()) {
|
||||||
String line = scanner.nextLine();
|
String line = scanner.nextLine();
|
||||||
if (!line.startsWith("#")) bridges.add(line);
|
if (!line.startsWith("#")) bridges.add(line);
|
||||||
@@ -1,17 +1,5 @@
|
|||||||
package org.briarproject.bramble.plugin.tor;
|
package org.briarproject.bramble.plugin.tor;
|
||||||
|
|
||||||
import android.content.BroadcastReceiver;
|
|
||||||
import android.content.Context;
|
|
||||||
import android.content.Intent;
|
|
||||||
import android.content.IntentFilter;
|
|
||||||
import android.content.pm.PackageInfo;
|
|
||||||
import android.content.pm.PackageManager;
|
|
||||||
import android.content.pm.PackageManager.NameNotFoundException;
|
|
||||||
import android.content.res.Resources;
|
|
||||||
import android.net.ConnectivityManager;
|
|
||||||
import android.net.NetworkInfo;
|
|
||||||
import android.os.PowerManager;
|
|
||||||
|
|
||||||
import net.freehaven.tor.control.EventHandler;
|
import net.freehaven.tor.control.EventHandler;
|
||||||
import net.freehaven.tor.control.TorControlConnection;
|
import net.freehaven.tor.control.TorControlConnection;
|
||||||
|
|
||||||
@@ -21,6 +9,9 @@ import org.briarproject.bramble.api.data.BdfList;
|
|||||||
import org.briarproject.bramble.api.event.Event;
|
import org.briarproject.bramble.api.event.Event;
|
||||||
import org.briarproject.bramble.api.event.EventListener;
|
import org.briarproject.bramble.api.event.EventListener;
|
||||||
import org.briarproject.bramble.api.keyagreement.KeyAgreementListener;
|
import org.briarproject.bramble.api.keyagreement.KeyAgreementListener;
|
||||||
|
import org.briarproject.bramble.api.network.NetworkManager;
|
||||||
|
import org.briarproject.bramble.api.network.NetworkStatus;
|
||||||
|
import org.briarproject.bramble.api.network.event.NetworkStatusEvent;
|
||||||
import org.briarproject.bramble.api.nullsafety.MethodsNotNullByDefault;
|
import org.briarproject.bramble.api.nullsafety.MethodsNotNullByDefault;
|
||||||
import org.briarproject.bramble.api.nullsafety.ParametersNotNullByDefault;
|
import org.briarproject.bramble.api.nullsafety.ParametersNotNullByDefault;
|
||||||
import org.briarproject.bramble.api.plugin.Backoff;
|
import org.briarproject.bramble.api.plugin.Backoff;
|
||||||
@@ -35,8 +26,8 @@ import org.briarproject.bramble.api.settings.Settings;
|
|||||||
import org.briarproject.bramble.api.settings.event.SettingsUpdatedEvent;
|
import org.briarproject.bramble.api.settings.event.SettingsUpdatedEvent;
|
||||||
import org.briarproject.bramble.api.system.Clock;
|
import org.briarproject.bramble.api.system.Clock;
|
||||||
import org.briarproject.bramble.api.system.LocationUtils;
|
import org.briarproject.bramble.api.system.LocationUtils;
|
||||||
|
import org.briarproject.bramble.api.system.ResourceProvider;
|
||||||
import org.briarproject.bramble.util.IoUtils;
|
import org.briarproject.bramble.util.IoUtils;
|
||||||
import org.briarproject.bramble.util.RenewableWakeLock;
|
|
||||||
import org.briarproject.bramble.util.StringUtils;
|
import org.briarproject.bramble.util.StringUtils;
|
||||||
|
|
||||||
import java.io.Closeable;
|
import java.io.Closeable;
|
||||||
@@ -59,10 +50,7 @@ import java.util.Map;
|
|||||||
import java.util.Map.Entry;
|
import java.util.Map.Entry;
|
||||||
import java.util.Scanner;
|
import java.util.Scanner;
|
||||||
import java.util.concurrent.Executor;
|
import java.util.concurrent.Executor;
|
||||||
import java.util.concurrent.Future;
|
|
||||||
import java.util.concurrent.ScheduledExecutorService;
|
|
||||||
import java.util.concurrent.atomic.AtomicBoolean;
|
import java.util.concurrent.atomic.AtomicBoolean;
|
||||||
import java.util.concurrent.atomic.AtomicReference;
|
|
||||||
import java.util.logging.Logger;
|
import java.util.logging.Logger;
|
||||||
import java.util.regex.Pattern;
|
import java.util.regex.Pattern;
|
||||||
import java.util.zip.ZipInputStream;
|
import java.util.zip.ZipInputStream;
|
||||||
@@ -70,24 +58,13 @@ import java.util.zip.ZipInputStream;
|
|||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
import javax.net.SocketFactory;
|
import javax.net.SocketFactory;
|
||||||
|
|
||||||
import static android.content.Context.CONNECTIVITY_SERVICE;
|
|
||||||
import static android.content.Context.MODE_PRIVATE;
|
|
||||||
import static android.content.Context.POWER_SERVICE;
|
|
||||||
import static android.content.Intent.ACTION_SCREEN_OFF;
|
|
||||||
import static android.content.Intent.ACTION_SCREEN_ON;
|
|
||||||
import static android.net.ConnectivityManager.CONNECTIVITY_ACTION;
|
|
||||||
import static android.net.ConnectivityManager.TYPE_WIFI;
|
|
||||||
import static android.os.Build.VERSION.SDK_INT;
|
|
||||||
import static android.os.PowerManager.ACTION_DEVICE_IDLE_MODE_CHANGED;
|
|
||||||
import static android.os.PowerManager.PARTIAL_WAKE_LOCK;
|
|
||||||
import static java.util.concurrent.TimeUnit.MINUTES;
|
|
||||||
import static java.util.logging.Level.INFO;
|
import static java.util.logging.Level.INFO;
|
||||||
import static java.util.logging.Level.WARNING;
|
import static java.util.logging.Level.WARNING;
|
||||||
import static net.freehaven.tor.control.TorControlCommands.HS_ADDRESS;
|
import static net.freehaven.tor.control.TorControlCommands.HS_ADDRESS;
|
||||||
import static net.freehaven.tor.control.TorControlCommands.HS_PRIVKEY;
|
import static net.freehaven.tor.control.TorControlCommands.HS_PRIVKEY;
|
||||||
import static org.briarproject.bramble.PowerTestingConstants.USE_TOR_WAKE_LOCK;
|
|
||||||
import static org.briarproject.bramble.api.plugin.TorConstants.CONTROL_PORT;
|
import static org.briarproject.bramble.api.plugin.TorConstants.CONTROL_PORT;
|
||||||
import static org.briarproject.bramble.api.plugin.TorConstants.ID;
|
import static org.briarproject.bramble.api.plugin.TorConstants.ID;
|
||||||
|
import static org.briarproject.bramble.api.plugin.TorConstants.PREF_TOR_DISABLE_BLOCKED;
|
||||||
import static org.briarproject.bramble.api.plugin.TorConstants.PREF_TOR_NETWORK;
|
import static org.briarproject.bramble.api.plugin.TorConstants.PREF_TOR_NETWORK;
|
||||||
import static org.briarproject.bramble.api.plugin.TorConstants.PREF_TOR_NETWORK_ALWAYS;
|
import static org.briarproject.bramble.api.plugin.TorConstants.PREF_TOR_NETWORK_ALWAYS;
|
||||||
import static org.briarproject.bramble.api.plugin.TorConstants.PREF_TOR_NETWORK_NEVER;
|
import static org.briarproject.bramble.api.plugin.TorConstants.PREF_TOR_NETWORK_NEVER;
|
||||||
@@ -99,7 +76,10 @@ import static org.briarproject.bramble.util.PrivacyUtils.scrubOnion;
|
|||||||
|
|
||||||
@MethodsNotNullByDefault
|
@MethodsNotNullByDefault
|
||||||
@ParametersNotNullByDefault
|
@ParametersNotNullByDefault
|
||||||
class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
|
abstract class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
|
||||||
|
|
||||||
|
private static final Logger LOG =
|
||||||
|
Logger.getLogger(TorPlugin.class.getName());
|
||||||
|
|
||||||
private static final String[] EVENTS = {
|
private static final String[] EVENTS = {
|
||||||
"CIRC", "ORCONN", "HS_DESC", "NOTICE", "WARN", "ERR"
|
"CIRC", "ORCONN", "HS_DESC", "NOTICE", "WARN", "ERR"
|
||||||
@@ -108,14 +88,9 @@ class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
|
|||||||
private static final int COOKIE_TIMEOUT_MS = 3000;
|
private static final int COOKIE_TIMEOUT_MS = 3000;
|
||||||
private static final int COOKIE_POLLING_INTERVAL_MS = 200;
|
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 = Pattern.compile("[a-z2-7]{16}");
|
||||||
// This tag may prevent Huawei's power manager from killing us
|
|
||||||
private static final String WAKE_LOCK_TAG = "LocationManagerService";
|
|
||||||
private static final Logger LOG =
|
|
||||||
Logger.getLogger(TorPlugin.class.getName());
|
|
||||||
|
|
||||||
private final Executor ioExecutor, connectionStatusExecutor;
|
private final Executor ioExecutor, connectionStatusExecutor;
|
||||||
private final ScheduledExecutorService scheduler;
|
private final NetworkManager networkManager;
|
||||||
private final Context appContext;
|
|
||||||
private final LocationUtils locationUtils;
|
private final LocationUtils locationUtils;
|
||||||
private final SocketFactory torSocketFactory;
|
private final SocketFactory torSocketFactory;
|
||||||
private final Clock clock;
|
private final Clock clock;
|
||||||
@@ -123,55 +98,54 @@ class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
|
|||||||
private final DuplexPluginCallback callback;
|
private final DuplexPluginCallback callback;
|
||||||
private final String architecture;
|
private final String architecture;
|
||||||
private final CircumventionProvider circumventionProvider;
|
private final CircumventionProvider circumventionProvider;
|
||||||
|
private final ResourceProvider resourceProvider;
|
||||||
private final int maxLatency, maxIdleTime, socketTimeout;
|
private final int maxLatency, maxIdleTime, socketTimeout;
|
||||||
private final ConnectionStatus connectionStatus;
|
|
||||||
private final File torDirectory, torFile, geoIpFile, configFile;
|
private final File torDirectory, torFile, geoIpFile, configFile;
|
||||||
private final File doneFile, cookieFile;
|
private final File doneFile, cookieFile;
|
||||||
private final RenewableWakeLock wakeLock;
|
private final ConnectionStatus connectionStatus;
|
||||||
private final AtomicReference<Future<?>> connectivityCheck =
|
|
||||||
new AtomicReference<>();
|
|
||||||
private final AtomicBoolean used = new AtomicBoolean(false);
|
private final AtomicBoolean used = new AtomicBoolean(false);
|
||||||
|
|
||||||
private volatile boolean running = false;
|
|
||||||
private volatile ServerSocket socket = null;
|
private volatile ServerSocket socket = null;
|
||||||
private volatile Socket controlSocket = null;
|
private volatile Socket controlSocket = null;
|
||||||
private volatile TorControlConnection controlConnection = null;
|
private volatile TorControlConnection controlConnection = null;
|
||||||
private volatile BroadcastReceiver networkStateReceiver = null;
|
|
||||||
|
|
||||||
TorPlugin(Executor ioExecutor, ScheduledExecutorService scheduler,
|
protected volatile boolean running = false;
|
||||||
Context appContext, LocationUtils locationUtils,
|
|
||||||
SocketFactory torSocketFactory, Clock clock, Backoff backoff,
|
protected abstract int getProcessId();
|
||||||
DuplexPluginCallback callback, String architecture,
|
|
||||||
CircumventionProvider circumventionProvider, int maxLatency, int maxIdleTime) {
|
protected abstract long getLastUpdateTime();
|
||||||
|
|
||||||
|
TorPlugin(Executor ioExecutor, NetworkManager networkManager,
|
||||||
|
LocationUtils locationUtils, SocketFactory torSocketFactory,
|
||||||
|
Clock clock, ResourceProvider resourceProvider,
|
||||||
|
CircumventionProvider circumventionProvider, Backoff backoff,
|
||||||
|
DuplexPluginCallback callback, String architecture, int maxLatency,
|
||||||
|
int maxIdleTime, File torDirectory) {
|
||||||
this.ioExecutor = ioExecutor;
|
this.ioExecutor = ioExecutor;
|
||||||
this.scheduler = scheduler;
|
this.networkManager = networkManager;
|
||||||
this.appContext = appContext;
|
|
||||||
this.locationUtils = locationUtils;
|
this.locationUtils = locationUtils;
|
||||||
this.torSocketFactory = torSocketFactory;
|
this.torSocketFactory = torSocketFactory;
|
||||||
this.clock = clock;
|
this.clock = clock;
|
||||||
|
this.resourceProvider = resourceProvider;
|
||||||
|
this.circumventionProvider = circumventionProvider;
|
||||||
this.backoff = backoff;
|
this.backoff = backoff;
|
||||||
this.callback = callback;
|
this.callback = callback;
|
||||||
this.architecture = architecture;
|
this.architecture = architecture;
|
||||||
this.circumventionProvider = circumventionProvider;
|
|
||||||
this.maxLatency = maxLatency;
|
this.maxLatency = maxLatency;
|
||||||
this.maxIdleTime = maxIdleTime;
|
this.maxIdleTime = maxIdleTime;
|
||||||
if (maxIdleTime > Integer.MAX_VALUE / 2)
|
if (maxIdleTime > Integer.MAX_VALUE / 2)
|
||||||
socketTimeout = Integer.MAX_VALUE;
|
socketTimeout = Integer.MAX_VALUE;
|
||||||
else socketTimeout = maxIdleTime * 2;
|
else socketTimeout = maxIdleTime * 2;
|
||||||
connectionStatus = new ConnectionStatus();
|
this.torDirectory = torDirectory;
|
||||||
torDirectory = appContext.getDir("tor", MODE_PRIVATE);
|
|
||||||
torFile = new File(torDirectory, "tor");
|
torFile = new File(torDirectory, "tor");
|
||||||
geoIpFile = new File(torDirectory, "geoip");
|
geoIpFile = new File(torDirectory, "geoip");
|
||||||
configFile = new File(torDirectory, "torrc");
|
configFile = new File(torDirectory, "torrc");
|
||||||
doneFile = new File(torDirectory, "done");
|
doneFile = new File(torDirectory, "done");
|
||||||
cookieFile = new File(torDirectory, ".tor/control_auth_cookie");
|
cookieFile = new File(torDirectory, ".tor/control_auth_cookie");
|
||||||
|
connectionStatus = new ConnectionStatus();
|
||||||
// Don't execute more than one connection status check at a time
|
// Don't execute more than one connection status check at a time
|
||||||
connectionStatusExecutor = new PoliteExecutor("TorPlugin",
|
connectionStatusExecutor =
|
||||||
ioExecutor, 1);
|
new PoliteExecutor("TorPlugin", ioExecutor, 1);
|
||||||
PowerManager pm = (PowerManager)
|
|
||||||
appContext.getSystemService(POWER_SERVICE);
|
|
||||||
wakeLock = new RenewableWakeLock(pm, scheduler, PARTIAL_WAKE_LOCK,
|
|
||||||
WAKE_LOCK_TAG, 1, MINUTES);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -200,7 +174,7 @@ class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
|
|||||||
LOG.info("Starting Tor");
|
LOG.info("Starting Tor");
|
||||||
String torPath = torFile.getAbsolutePath();
|
String torPath = torFile.getAbsolutePath();
|
||||||
String configPath = configFile.getAbsolutePath();
|
String configPath = configFile.getAbsolutePath();
|
||||||
String pid = String.valueOf(android.os.Process.myPid());
|
String pid = String.valueOf(getProcessId());
|
||||||
Process torProcess;
|
Process torProcess;
|
||||||
ProcessBuilder pb =
|
ProcessBuilder pb =
|
||||||
new ProcessBuilder(torPath, "-f", configPath, OWNER, pid);
|
new ProcessBuilder(torPath, "-f", configPath, OWNER, pid);
|
||||||
@@ -272,26 +246,14 @@ class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
|
|||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
throw new PluginException(e);
|
throw new PluginException(e);
|
||||||
}
|
}
|
||||||
// Register to receive network status events
|
// Check whether we're online
|
||||||
networkStateReceiver = new NetworkStateReceiver();
|
updateConnectionStatus(networkManager.getNetworkStatus());
|
||||||
IntentFilter filter = new IntentFilter();
|
|
||||||
filter.addAction(CONNECTIVITY_ACTION);
|
|
||||||
filter.addAction(ACTION_SCREEN_ON);
|
|
||||||
filter.addAction(ACTION_SCREEN_OFF);
|
|
||||||
if (SDK_INT >= 23) filter.addAction(ACTION_DEVICE_IDLE_MODE_CHANGED);
|
|
||||||
appContext.registerReceiver(networkStateReceiver, filter);
|
|
||||||
// Bind a server socket to receive incoming hidden service connections
|
// Bind a server socket to receive incoming hidden service connections
|
||||||
bind();
|
bind();
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean assetsAreUpToDate() {
|
private boolean assetsAreUpToDate() {
|
||||||
try {
|
return doneFile.lastModified() > getLastUpdateTime();
|
||||||
PackageManager pm = appContext.getPackageManager();
|
|
||||||
PackageInfo pi = pm.getPackageInfo(appContext.getPackageName(), 0);
|
|
||||||
return doneFile.lastModified() > pi.lastUpdateTime;
|
|
||||||
} catch (NameNotFoundException e) {
|
|
||||||
throw new RuntimeException(e);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void installAssets() throws PluginException {
|
private void installAssets() throws PluginException {
|
||||||
@@ -324,29 +286,22 @@ class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
|
|||||||
private InputStream getTorInputStream() throws IOException {
|
private InputStream getTorInputStream() throws IOException {
|
||||||
if (LOG.isLoggable(INFO))
|
if (LOG.isLoggable(INFO))
|
||||||
LOG.info("Installing Tor binary for " + architecture);
|
LOG.info("Installing Tor binary for " + architecture);
|
||||||
int resId = getResourceId("tor_" + architecture);
|
InputStream in =
|
||||||
InputStream in = appContext.getResources().openRawResource(resId);
|
resourceProvider.getResourceInputStream("tor_" + architecture);
|
||||||
ZipInputStream zin = new ZipInputStream(in);
|
ZipInputStream zin = new ZipInputStream(in);
|
||||||
if (zin.getNextEntry() == null) throw new IOException();
|
if (zin.getNextEntry() == null) throw new IOException();
|
||||||
return zin;
|
return zin;
|
||||||
}
|
}
|
||||||
|
|
||||||
private InputStream getGeoIpInputStream() throws IOException {
|
private InputStream getGeoIpInputStream() throws IOException {
|
||||||
int resId = getResourceId("geoip");
|
InputStream in = resourceProvider.getResourceInputStream("geoip");
|
||||||
InputStream in = appContext.getResources().openRawResource(resId);
|
|
||||||
ZipInputStream zin = new ZipInputStream(in);
|
ZipInputStream zin = new ZipInputStream(in);
|
||||||
if (zin.getNextEntry() == null) throw new IOException();
|
if (zin.getNextEntry() == null) throw new IOException();
|
||||||
return zin;
|
return zin;
|
||||||
}
|
}
|
||||||
|
|
||||||
private InputStream getConfigInputStream() {
|
private InputStream getConfigInputStream() {
|
||||||
int resId = getResourceId("torrc");
|
return resourceProvider.getResourceInputStream("torrc");
|
||||||
return appContext.getResources().openRawResource(resId);
|
|
||||||
}
|
|
||||||
|
|
||||||
private int getResourceId(String filename) {
|
|
||||||
Resources res = appContext.getResources();
|
|
||||||
return res.getIdentifier(filename, "raw", appContext.getPackageName());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void tryToClose(@Nullable Closeable c) {
|
private void tryToClose(@Nullable Closeable c) {
|
||||||
@@ -492,15 +447,11 @@ class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void enableNetwork(boolean enable) throws IOException {
|
protected void enableNetwork(boolean enable) throws IOException {
|
||||||
if (!running) return;
|
if (!running) return;
|
||||||
if (enable && USE_TOR_WAKE_LOCK) wakeLock.acquire();
|
|
||||||
connectionStatus.enableNetwork(enable);
|
connectionStatus.enableNetwork(enable);
|
||||||
controlConnection.setConf("DisableNetwork", enable ? "0" : "1");
|
controlConnection.setConf("DisableNetwork", enable ? "0" : "1");
|
||||||
if (!enable) {
|
if (!enable) callback.transportDisabled();
|
||||||
callback.transportDisabled();
|
|
||||||
if (USE_TOR_WAKE_LOCK) wakeLock.release();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void enableBridges(boolean enable) throws IOException {
|
private void enableBridges(boolean enable) throws IOException {
|
||||||
@@ -518,8 +469,6 @@ class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
|
|||||||
public void stop() {
|
public void stop() {
|
||||||
running = false;
|
running = false;
|
||||||
tryToClose(socket);
|
tryToClose(socket);
|
||||||
if (networkStateReceiver != null)
|
|
||||||
appContext.unregisterReceiver(networkStateReceiver);
|
|
||||||
if (controlSocket != null && controlConnection != null) {
|
if (controlSocket != null && controlConnection != null) {
|
||||||
try {
|
try {
|
||||||
LOG.info("Stopping Tor");
|
LOG.info("Stopping Tor");
|
||||||
@@ -530,7 +479,6 @@ class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
|
|||||||
logException(LOG, WARNING, e);
|
logException(LOG, WARNING, e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (USE_TOR_WAKE_LOCK) wakeLock.release();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -581,7 +529,6 @@ class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
|
|||||||
try {
|
try {
|
||||||
if (LOG.isLoggable(INFO))
|
if (LOG.isLoggable(INFO))
|
||||||
LOG.info("Connecting to " + scrubOnion(onion));
|
LOG.info("Connecting to " + scrubOnion(onion));
|
||||||
controlConnection.forgetHiddenService(onion);
|
|
||||||
s = torSocketFactory.createSocket(onion + ".onion", 80);
|
s = torSocketFactory.createSocket(onion + ".onion", 80);
|
||||||
s.setSoTimeout(socketTimeout);
|
s.setSoTimeout(socketTimeout);
|
||||||
if (LOG.isLoggable(INFO))
|
if (LOG.isLoggable(INFO))
|
||||||
@@ -630,8 +577,10 @@ class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
|
|||||||
@Override
|
@Override
|
||||||
public void orConnStatus(String status, String orName) {
|
public void orConnStatus(String status, String orName) {
|
||||||
if (LOG.isLoggable(INFO)) LOG.info("OR connection " + status);
|
if (LOG.isLoggable(INFO)) LOG.info("OR connection " + status);
|
||||||
if (status.equals("CLOSED") || status.equals("FAILED"))
|
if (status.equals("CLOSED") || status.equals("FAILED")) {
|
||||||
updateConnectionStatus(); // Check whether we've lost connectivity
|
// Check whether we've lost connectivity
|
||||||
|
updateConnectionStatus(networkManager.getNetworkStatus());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -664,24 +613,25 @@ class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
|
|||||||
SettingsUpdatedEvent s = (SettingsUpdatedEvent) e;
|
SettingsUpdatedEvent s = (SettingsUpdatedEvent) e;
|
||||||
if (s.getNamespace().equals(ID.getString())) {
|
if (s.getNamespace().equals(ID.getString())) {
|
||||||
LOG.info("Tor settings updated");
|
LOG.info("Tor settings updated");
|
||||||
updateConnectionStatus();
|
updateConnectionStatus(networkManager.getNetworkStatus());
|
||||||
}
|
}
|
||||||
|
} else if (e instanceof NetworkStatusEvent) {
|
||||||
|
updateConnectionStatus(((NetworkStatusEvent) e).getStatus());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void updateConnectionStatus() {
|
private void updateConnectionStatus(NetworkStatus status) {
|
||||||
connectionStatusExecutor.execute(() -> {
|
connectionStatusExecutor.execute(() -> {
|
||||||
if (!running) return;
|
if (!running) return;
|
||||||
Object o = appContext.getSystemService(CONNECTIVITY_SERVICE);
|
boolean online = status.isConnected();
|
||||||
ConnectivityManager cm = (ConnectivityManager) o;
|
boolean wifi = status.isWifi();
|
||||||
NetworkInfo net = cm.getActiveNetworkInfo();
|
|
||||||
boolean online = net != null && net.isConnected();
|
|
||||||
boolean wifi = online && net.getType() == TYPE_WIFI;
|
|
||||||
String country = locationUtils.getCurrentCountry();
|
String country = locationUtils.getCurrentCountry();
|
||||||
boolean blocked =
|
boolean blocked =
|
||||||
circumventionProvider.isTorProbablyBlocked(country);
|
circumventionProvider.isTorProbablyBlocked(country);
|
||||||
Settings s = callback.getSettings();
|
Settings s = callback.getSettings();
|
||||||
int network = s.getInt(PREF_TOR_NETWORK, PREF_TOR_NETWORK_ALWAYS);
|
int network = s.getInt(PREF_TOR_NETWORK, PREF_TOR_NETWORK_ALWAYS);
|
||||||
|
boolean disableWhenBlocked =
|
||||||
|
s.getBoolean(PREF_TOR_DISABLE_BLOCKED, true);
|
||||||
|
|
||||||
if (LOG.isLoggable(INFO)) {
|
if (LOG.isLoggable(INFO)) {
|
||||||
LOG.info("Online: " + online + ", wifi: " + wifi);
|
LOG.info("Online: " + online + ", wifi: " + wifi);
|
||||||
@@ -702,9 +652,13 @@ class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
|
|||||||
LOG.info("Enabling network, using bridges");
|
LOG.info("Enabling network, using bridges");
|
||||||
enableBridges(true);
|
enableBridges(true);
|
||||||
enableNetwork(true);
|
enableNetwork(true);
|
||||||
} else {
|
} else if (disableWhenBlocked) {
|
||||||
LOG.info("Disabling network, country is blocked");
|
LOG.info("Disabling network, country is blocked");
|
||||||
enableNetwork(false);
|
enableNetwork(false);
|
||||||
|
} else {
|
||||||
|
LOG.info("Enabling network but country is blocked");
|
||||||
|
enableBridges(false);
|
||||||
|
enableNetwork(true);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
LOG.info("Enabling network");
|
LOG.info("Enabling network");
|
||||||
@@ -717,29 +671,6 @@ class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private void scheduleConnectionStatusUpdate() {
|
|
||||||
Future<?> newConnectivityCheck =
|
|
||||||
scheduler.schedule(this::updateConnectionStatus, 1, MINUTES);
|
|
||||||
Future<?> oldConnectivityCheck =
|
|
||||||
connectivityCheck.getAndSet(newConnectivityCheck);
|
|
||||||
if (oldConnectivityCheck != null) oldConnectivityCheck.cancel(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
private class NetworkStateReceiver extends BroadcastReceiver {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onReceive(Context ctx, Intent i) {
|
|
||||||
if (!running) return;
|
|
||||||
String action = i.getAction();
|
|
||||||
if (LOG.isLoggable(INFO)) LOG.info("Received broadcast " + action);
|
|
||||||
updateConnectionStatus();
|
|
||||||
if (ACTION_SCREEN_ON.equals(action)
|
|
||||||
|| ACTION_SCREEN_OFF.equals(action)) {
|
|
||||||
scheduleConnectionStatusUpdate();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static class ConnectionStatus {
|
private static class ConnectionStatus {
|
||||||
|
|
||||||
// All of the following are locking: this
|
// All of the following are locking: this
|
||||||
@@ -46,7 +46,7 @@ class SyncRecordReaderImpl implements SyncRecordReader {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void readRecord() throws IOException {
|
private void readRecord() throws IOException {
|
||||||
assert nextRecord == null;
|
if (nextRecord != null) throw new AssertionError();
|
||||||
while (true) {
|
while (true) {
|
||||||
nextRecord = reader.readRecord();
|
nextRecord = reader.readRecord();
|
||||||
// Check the protocol version
|
// Check the protocol version
|
||||||
@@ -62,7 +62,7 @@ class SyncRecordReaderImpl implements SyncRecordReader {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private byte getNextRecordType() {
|
private byte getNextRecordType() {
|
||||||
assert nextRecord != null;
|
if (nextRecord == null) throw new AssertionError();
|
||||||
return nextRecord.getRecordType();
|
return nextRecord.getRecordType();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -100,7 +100,7 @@ class SyncRecordReaderImpl implements SyncRecordReader {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private List<MessageId> readMessageIds() throws IOException {
|
private List<MessageId> readMessageIds() throws IOException {
|
||||||
assert nextRecord != null;
|
if (nextRecord == null) throw new AssertionError();
|
||||||
byte[] payload = nextRecord.getPayload();
|
byte[] payload = nextRecord.getPayload();
|
||||||
if (payload.length == 0) throw new FormatException();
|
if (payload.length == 0) throw new FormatException();
|
||||||
if (payload.length % UniqueId.LENGTH != 0) throw new FormatException();
|
if (payload.length % UniqueId.LENGTH != 0) throw new FormatException();
|
||||||
@@ -122,7 +122,7 @@ class SyncRecordReaderImpl implements SyncRecordReader {
|
|||||||
@Override
|
@Override
|
||||||
public Message readMessage() throws IOException {
|
public Message readMessage() throws IOException {
|
||||||
if (!hasMessage()) throw new FormatException();
|
if (!hasMessage()) throw new FormatException();
|
||||||
assert nextRecord != null;
|
if (nextRecord == null) throw new AssertionError();
|
||||||
byte[] payload = nextRecord.getPayload();
|
byte[] payload = nextRecord.getPayload();
|
||||||
if (payload.length < MESSAGE_HEADER_LENGTH) throw new FormatException();
|
if (payload.length < MESSAGE_HEADER_LENGTH) throw new FormatException();
|
||||||
// Validate timestamp
|
// Validate timestamp
|
||||||
|
|||||||
@@ -0,0 +1,341 @@
|
|||||||
|
package org.briarproject.bramble.account;
|
||||||
|
|
||||||
|
import org.briarproject.bramble.api.crypto.CryptoComponent;
|
||||||
|
import org.briarproject.bramble.api.crypto.SecretKey;
|
||||||
|
import org.briarproject.bramble.api.db.DatabaseConfig;
|
||||||
|
import org.briarproject.bramble.api.identity.IdentityManager;
|
||||||
|
import org.briarproject.bramble.api.identity.LocalAuthor;
|
||||||
|
import org.briarproject.bramble.test.BrambleMockTestCase;
|
||||||
|
import org.jmock.Expectations;
|
||||||
|
import org.junit.After;
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import java.io.BufferedReader;
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.FileInputStream;
|
||||||
|
import java.io.FileOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStreamReader;
|
||||||
|
|
||||||
|
import javax.annotation.Nullable;
|
||||||
|
|
||||||
|
import static junit.framework.Assert.assertFalse;
|
||||||
|
import static junit.framework.Assert.assertNull;
|
||||||
|
import static junit.framework.Assert.assertTrue;
|
||||||
|
import static org.briarproject.bramble.test.TestUtils.deleteTestDirectory;
|
||||||
|
import static org.briarproject.bramble.test.TestUtils.getLocalAuthor;
|
||||||
|
import static org.briarproject.bramble.test.TestUtils.getRandomBytes;
|
||||||
|
import static org.briarproject.bramble.test.TestUtils.getSecretKey;
|
||||||
|
import static org.briarproject.bramble.test.TestUtils.getTestDirectory;
|
||||||
|
import static org.briarproject.bramble.util.StringUtils.getRandomString;
|
||||||
|
import static org.briarproject.bramble.util.StringUtils.toHexString;
|
||||||
|
import static org.junit.Assert.assertArrayEquals;
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
import static org.junit.Assert.assertNotNull;
|
||||||
|
|
||||||
|
public class AccountManagerImplTest extends BrambleMockTestCase {
|
||||||
|
|
||||||
|
private final DatabaseConfig databaseConfig =
|
||||||
|
context.mock(DatabaseConfig.class);
|
||||||
|
private final CryptoComponent crypto = context.mock(CryptoComponent.class);
|
||||||
|
private final IdentityManager identityManager =
|
||||||
|
context.mock(IdentityManager.class);
|
||||||
|
|
||||||
|
private final SecretKey key = getSecretKey();
|
||||||
|
private final byte[] encryptedKey = getRandomBytes(123);
|
||||||
|
private final String encryptedKeyHex = toHexString(encryptedKey);
|
||||||
|
private final byte[] newEncryptedKey = getRandomBytes(123);
|
||||||
|
private final String newEncryptedKeyHex = toHexString(newEncryptedKey);
|
||||||
|
private final LocalAuthor localAuthor = getLocalAuthor();
|
||||||
|
private final String authorName = localAuthor.getName();
|
||||||
|
private final String password = getRandomString(10);
|
||||||
|
private final String newPassword = getRandomString(10);
|
||||||
|
private final File testDir = getTestDirectory();
|
||||||
|
private final File dbDir = new File(testDir, "db");
|
||||||
|
private final File keyDir = new File(testDir, "key");
|
||||||
|
private final File keyFile = new File(keyDir, "db.key");
|
||||||
|
private final File keyBackupFile = new File(keyDir, "db.key.bak");
|
||||||
|
|
||||||
|
private AccountManagerImpl accountManager;
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void setUp() {
|
||||||
|
context.checking(new Expectations() {{
|
||||||
|
allowing(databaseConfig).getDatabaseDirectory();
|
||||||
|
will(returnValue(dbDir));
|
||||||
|
allowing(databaseConfig).getDatabaseKeyDirectory();
|
||||||
|
will(returnValue(keyDir));
|
||||||
|
}});
|
||||||
|
|
||||||
|
accountManager =
|
||||||
|
new AccountManagerImpl(databaseConfig, crypto, identityManager);
|
||||||
|
|
||||||
|
assertFalse(keyFile.exists());
|
||||||
|
assertFalse(keyBackupFile.exists());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testSignInReturnsFalseIfDbKeyCannotBeLoaded() {
|
||||||
|
assertFalse(accountManager.signIn(password));
|
||||||
|
assertFalse(accountManager.hasDatabaseKey());
|
||||||
|
|
||||||
|
assertFalse(keyFile.exists());
|
||||||
|
assertFalse(keyBackupFile.exists());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testSignInReturnsFalseIfPasswordIsWrong() throws Exception {
|
||||||
|
context.checking(new Expectations() {{
|
||||||
|
oneOf(crypto).decryptWithPassword(encryptedKey, password);
|
||||||
|
will(returnValue(null));
|
||||||
|
}});
|
||||||
|
|
||||||
|
storeDatabaseKey(keyFile, encryptedKeyHex);
|
||||||
|
storeDatabaseKey(keyBackupFile, encryptedKeyHex);
|
||||||
|
|
||||||
|
assertEquals(encryptedKeyHex, loadDatabaseKey(keyFile));
|
||||||
|
assertEquals(encryptedKeyHex, loadDatabaseKey(keyBackupFile));
|
||||||
|
|
||||||
|
assertFalse(accountManager.signIn(password));
|
||||||
|
assertFalse(accountManager.hasDatabaseKey());
|
||||||
|
|
||||||
|
assertEquals(encryptedKeyHex, loadDatabaseKey(keyFile));
|
||||||
|
assertEquals(encryptedKeyHex, loadDatabaseKey(keyBackupFile));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testSignInReturnsTrueIfPasswordIsRight() throws Exception {
|
||||||
|
context.checking(new Expectations() {{
|
||||||
|
oneOf(crypto).decryptWithPassword(encryptedKey, password);
|
||||||
|
will(returnValue(key.getBytes()));
|
||||||
|
}});
|
||||||
|
|
||||||
|
storeDatabaseKey(keyFile, encryptedKeyHex);
|
||||||
|
storeDatabaseKey(keyBackupFile, encryptedKeyHex);
|
||||||
|
|
||||||
|
assertEquals(encryptedKeyHex, loadDatabaseKey(keyFile));
|
||||||
|
assertEquals(encryptedKeyHex, loadDatabaseKey(keyBackupFile));
|
||||||
|
|
||||||
|
assertTrue(accountManager.signIn(password));
|
||||||
|
assertTrue(accountManager.hasDatabaseKey());
|
||||||
|
SecretKey decrypted = accountManager.getDatabaseKey();
|
||||||
|
assertNotNull(decrypted);
|
||||||
|
assertArrayEquals(key.getBytes(), decrypted.getBytes());
|
||||||
|
|
||||||
|
assertEquals(encryptedKeyHex, loadDatabaseKey(keyFile));
|
||||||
|
assertEquals(encryptedKeyHex, loadDatabaseKey(keyBackupFile));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testDbKeyIsLoadedFromPrimaryFile() throws Exception {
|
||||||
|
storeDatabaseKey(keyFile, encryptedKeyHex);
|
||||||
|
|
||||||
|
assertEquals(encryptedKeyHex, loadDatabaseKey(keyFile));
|
||||||
|
assertFalse(keyBackupFile.exists());
|
||||||
|
|
||||||
|
assertEquals(encryptedKeyHex,
|
||||||
|
accountManager.loadEncryptedDatabaseKey());
|
||||||
|
|
||||||
|
assertEquals(encryptedKeyHex, loadDatabaseKey(keyFile));
|
||||||
|
assertFalse(keyBackupFile.exists());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testDbKeyIsLoadedFromBackupFile() throws Exception {
|
||||||
|
storeDatabaseKey(keyBackupFile, encryptedKeyHex);
|
||||||
|
|
||||||
|
assertFalse(keyFile.exists());
|
||||||
|
assertEquals(encryptedKeyHex, loadDatabaseKey(keyBackupFile));
|
||||||
|
|
||||||
|
assertEquals(encryptedKeyHex,
|
||||||
|
accountManager.loadEncryptedDatabaseKey());
|
||||||
|
|
||||||
|
assertFalse(keyFile.exists());
|
||||||
|
assertEquals(encryptedKeyHex, loadDatabaseKey(keyBackupFile));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testDbKeyIsNullIfNotFound() {
|
||||||
|
assertNull(accountManager.loadEncryptedDatabaseKey());
|
||||||
|
|
||||||
|
assertFalse(keyFile.exists());
|
||||||
|
assertFalse(keyBackupFile.exists());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testStoringDbKeyOverwritesPrimary() throws Exception {
|
||||||
|
storeDatabaseKey(keyFile, encryptedKeyHex);
|
||||||
|
|
||||||
|
assertEquals(encryptedKeyHex, loadDatabaseKey(keyFile));
|
||||||
|
assertFalse(keyBackupFile.exists());
|
||||||
|
|
||||||
|
assertTrue(accountManager.storeEncryptedDatabaseKey(
|
||||||
|
newEncryptedKeyHex));
|
||||||
|
|
||||||
|
assertEquals(newEncryptedKeyHex, loadDatabaseKey(keyFile));
|
||||||
|
assertEquals(newEncryptedKeyHex, loadDatabaseKey(keyBackupFile));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testStoringDbKeyOverwritesBackup() throws Exception {
|
||||||
|
storeDatabaseKey(keyBackupFile, encryptedKeyHex);
|
||||||
|
|
||||||
|
assertFalse(keyFile.exists());
|
||||||
|
assertEquals(encryptedKeyHex, loadDatabaseKey(keyBackupFile));
|
||||||
|
|
||||||
|
assertTrue(accountManager.storeEncryptedDatabaseKey(
|
||||||
|
newEncryptedKeyHex));
|
||||||
|
|
||||||
|
assertEquals(newEncryptedKeyHex, loadDatabaseKey(keyFile));
|
||||||
|
assertEquals(newEncryptedKeyHex, loadDatabaseKey(keyBackupFile));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testAccountExistsReturnsFalseIfDbKeyCannotBeLoaded() {
|
||||||
|
assertFalse(accountManager.accountExists());
|
||||||
|
|
||||||
|
assertFalse(keyFile.exists());
|
||||||
|
assertFalse(keyBackupFile.exists());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testAccountExistsReturnsFalseIfDbDirectoryDoesNotExist()
|
||||||
|
throws Exception {
|
||||||
|
storeDatabaseKey(keyFile, encryptedKeyHex);
|
||||||
|
storeDatabaseKey(keyBackupFile, encryptedKeyHex);
|
||||||
|
|
||||||
|
assertFalse(dbDir.exists());
|
||||||
|
|
||||||
|
assertFalse(accountManager.accountExists());
|
||||||
|
|
||||||
|
assertEquals(encryptedKeyHex, loadDatabaseKey(keyFile));
|
||||||
|
assertEquals(encryptedKeyHex, loadDatabaseKey(keyBackupFile));
|
||||||
|
assertFalse(dbDir.exists());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testAccountExistsReturnsFalseIfDbDirectoryIsNotDirectory()
|
||||||
|
throws Exception {
|
||||||
|
storeDatabaseKey(keyFile, encryptedKeyHex);
|
||||||
|
storeDatabaseKey(keyBackupFile, encryptedKeyHex);
|
||||||
|
|
||||||
|
assertTrue(dbDir.createNewFile());
|
||||||
|
assertFalse(dbDir.isDirectory());
|
||||||
|
|
||||||
|
assertFalse(accountManager.accountExists());
|
||||||
|
|
||||||
|
assertEquals(encryptedKeyHex, loadDatabaseKey(keyFile));
|
||||||
|
assertEquals(encryptedKeyHex, loadDatabaseKey(keyBackupFile));
|
||||||
|
assertTrue(dbDir.exists());
|
||||||
|
assertFalse(dbDir.isDirectory());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testAccountExistsReturnsTrueIfDbDirectoryIsDirectory()
|
||||||
|
throws Exception {
|
||||||
|
storeDatabaseKey(keyFile, encryptedKeyHex);
|
||||||
|
storeDatabaseKey(keyBackupFile, encryptedKeyHex);
|
||||||
|
|
||||||
|
assertTrue(dbDir.mkdirs());
|
||||||
|
assertTrue(dbDir.isDirectory());
|
||||||
|
|
||||||
|
assertTrue(accountManager.accountExists());
|
||||||
|
|
||||||
|
assertEquals(encryptedKeyHex, loadDatabaseKey(keyFile));
|
||||||
|
assertEquals(encryptedKeyHex, loadDatabaseKey(keyBackupFile));
|
||||||
|
assertTrue(dbDir.exists());
|
||||||
|
assertTrue(dbDir.isDirectory());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testCreateAccountStoresDbKey() throws Exception {
|
||||||
|
context.checking(new Expectations() {{
|
||||||
|
oneOf(identityManager).createLocalAuthor(authorName);
|
||||||
|
will(returnValue(localAuthor));
|
||||||
|
oneOf(identityManager).registerLocalAuthor(localAuthor);
|
||||||
|
oneOf(crypto).generateSecretKey();
|
||||||
|
will(returnValue(key));
|
||||||
|
oneOf(crypto).encryptWithPassword(key.getBytes(), password);
|
||||||
|
will(returnValue(encryptedKey));
|
||||||
|
}});
|
||||||
|
|
||||||
|
assertFalse(accountManager.hasDatabaseKey());
|
||||||
|
|
||||||
|
assertTrue(accountManager.createAccount(authorName, password));
|
||||||
|
|
||||||
|
assertTrue(accountManager.hasDatabaseKey());
|
||||||
|
SecretKey dbKey = accountManager.getDatabaseKey();
|
||||||
|
assertNotNull(dbKey);
|
||||||
|
assertArrayEquals(key.getBytes(), dbKey.getBytes());
|
||||||
|
|
||||||
|
assertEquals(encryptedKeyHex, loadDatabaseKey(keyFile));
|
||||||
|
assertEquals(encryptedKeyHex, loadDatabaseKey(keyBackupFile));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testChangePasswordReturnsFalseIfDbKeyCannotBeLoaded() {
|
||||||
|
assertFalse(accountManager.changePassword(password, newPassword));
|
||||||
|
|
||||||
|
assertFalse(keyFile.exists());
|
||||||
|
assertFalse(keyBackupFile.exists());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testChangePasswordReturnsFalseIfPasswordIsWrong()
|
||||||
|
throws Exception {
|
||||||
|
context.checking(new Expectations() {{
|
||||||
|
oneOf(crypto).decryptWithPassword(encryptedKey, password);
|
||||||
|
will(returnValue(null));
|
||||||
|
}});
|
||||||
|
|
||||||
|
storeDatabaseKey(keyFile, encryptedKeyHex);
|
||||||
|
storeDatabaseKey(keyBackupFile, encryptedKeyHex);
|
||||||
|
|
||||||
|
assertFalse(accountManager.changePassword(password, newPassword));
|
||||||
|
|
||||||
|
assertEquals(encryptedKeyHex, loadDatabaseKey(keyFile));
|
||||||
|
assertEquals(encryptedKeyHex, loadDatabaseKey(keyBackupFile));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testChangePasswordReturnsTrueIfPasswordIsRight()
|
||||||
|
throws Exception {
|
||||||
|
context.checking(new Expectations() {{
|
||||||
|
oneOf(crypto).decryptWithPassword(encryptedKey, password);
|
||||||
|
will(returnValue(key.getBytes()));
|
||||||
|
oneOf(crypto).encryptWithPassword(key.getBytes(), newPassword);
|
||||||
|
will(returnValue(newEncryptedKey));
|
||||||
|
}});
|
||||||
|
|
||||||
|
storeDatabaseKey(keyFile, encryptedKeyHex);
|
||||||
|
storeDatabaseKey(keyBackupFile, encryptedKeyHex);
|
||||||
|
|
||||||
|
assertTrue(accountManager.changePassword(password, newPassword));
|
||||||
|
|
||||||
|
assertEquals(newEncryptedKeyHex, loadDatabaseKey(keyFile));
|
||||||
|
assertEquals(newEncryptedKeyHex, loadDatabaseKey(keyBackupFile));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void storeDatabaseKey(File f, String hex) throws IOException {
|
||||||
|
f.getParentFile().mkdirs();
|
||||||
|
FileOutputStream out = new FileOutputStream(f);
|
||||||
|
out.write(hex.getBytes("UTF-8"));
|
||||||
|
out.flush();
|
||||||
|
out.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
private String loadDatabaseKey(File f) throws IOException {
|
||||||
|
BufferedReader reader = new BufferedReader(new InputStreamReader(
|
||||||
|
new FileInputStream(f), "UTF-8"));
|
||||||
|
String hex = reader.readLine();
|
||||||
|
reader.close();
|
||||||
|
return hex;
|
||||||
|
}
|
||||||
|
|
||||||
|
@After
|
||||||
|
public void tearDown() {
|
||||||
|
deleteTestDirectory(testDir);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -89,6 +89,7 @@ public class DatabaseComponentImplTest extends BrambleMockTestCase {
|
|||||||
context.mock(ShutdownManager.class);
|
context.mock(ShutdownManager.class);
|
||||||
private final EventBus eventBus = context.mock(EventBus.class);
|
private final EventBus eventBus = context.mock(EventBus.class);
|
||||||
|
|
||||||
|
private final SecretKey key = getSecretKey();
|
||||||
private final Object txn = new Object();
|
private final Object txn = new Object();
|
||||||
private final ClientId clientId;
|
private final ClientId clientId;
|
||||||
private final int majorVersion;
|
private final int majorVersion;
|
||||||
@@ -141,7 +142,7 @@ public class DatabaseComponentImplTest extends BrambleMockTestCase {
|
|||||||
int shutdownHandle = 12345;
|
int shutdownHandle = 12345;
|
||||||
context.checking(new Expectations() {{
|
context.checking(new Expectations() {{
|
||||||
// open()
|
// open()
|
||||||
oneOf(database).open(null);
|
oneOf(database).open(key, null);
|
||||||
will(returnValue(false));
|
will(returnValue(false));
|
||||||
oneOf(shutdown).addShutdownHook(with(any(Runnable.class)));
|
oneOf(shutdown).addShutdownHook(with(any(Runnable.class)));
|
||||||
will(returnValue(shutdownHandle));
|
will(returnValue(shutdownHandle));
|
||||||
@@ -208,7 +209,7 @@ public class DatabaseComponentImplTest extends BrambleMockTestCase {
|
|||||||
DatabaseComponent db = createDatabaseComponent(database, eventBus,
|
DatabaseComponent db = createDatabaseComponent(database, eventBus,
|
||||||
shutdown);
|
shutdown);
|
||||||
|
|
||||||
assertFalse(db.open(null));
|
assertFalse(db.open(key, null));
|
||||||
Transaction transaction = db.startTransaction(false);
|
Transaction transaction = db.startTransaction(false);
|
||||||
try {
|
try {
|
||||||
db.addLocalAuthor(transaction, localAuthor);
|
db.addLocalAuthor(transaction, localAuthor);
|
||||||
@@ -1602,7 +1603,7 @@ public class DatabaseComponentImplTest extends BrambleMockTestCase {
|
|||||||
MessageId messageId2 = new MessageId(getRandomId());
|
MessageId messageId2 = new MessageId(getRandomId());
|
||||||
context.checking(new Expectations() {{
|
context.checking(new Expectations() {{
|
||||||
// open()
|
// open()
|
||||||
oneOf(database).open(null);
|
oneOf(database).open(key, null);
|
||||||
will(returnValue(false));
|
will(returnValue(false));
|
||||||
oneOf(shutdown).addShutdownHook(with(any(Runnable.class)));
|
oneOf(shutdown).addShutdownHook(with(any(Runnable.class)));
|
||||||
will(returnValue(shutdownHandle));
|
will(returnValue(shutdownHandle));
|
||||||
@@ -1646,7 +1647,7 @@ public class DatabaseComponentImplTest extends BrambleMockTestCase {
|
|||||||
DatabaseComponent db = createDatabaseComponent(database, eventBus,
|
DatabaseComponent db = createDatabaseComponent(database, eventBus,
|
||||||
shutdown);
|
shutdown);
|
||||||
|
|
||||||
assertFalse(db.open(null));
|
assertFalse(db.open(key, null));
|
||||||
Transaction transaction = db.startTransaction(false);
|
Transaction transaction = db.startTransaction(false);
|
||||||
try {
|
try {
|
||||||
db.addLocalMessage(transaction, message, metadata, true);
|
db.addLocalMessage(transaction, message, metadata, true);
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
package org.briarproject.bramble.db;
|
package org.briarproject.bramble.db;
|
||||||
|
|
||||||
|
import org.briarproject.bramble.api.crypto.SecretKey;
|
||||||
import org.briarproject.bramble.api.db.DataTooNewException;
|
import org.briarproject.bramble.api.db.DataTooNewException;
|
||||||
import org.briarproject.bramble.api.db.DataTooOldException;
|
import org.briarproject.bramble.api.db.DataTooOldException;
|
||||||
import org.briarproject.bramble.api.db.DatabaseConfig;
|
import org.briarproject.bramble.api.db.DatabaseConfig;
|
||||||
@@ -26,6 +27,7 @@ import static java.util.Collections.singletonList;
|
|||||||
import static org.briarproject.bramble.db.DatabaseConstants.DB_SETTINGS_NAMESPACE;
|
import static org.briarproject.bramble.db.DatabaseConstants.DB_SETTINGS_NAMESPACE;
|
||||||
import static org.briarproject.bramble.db.DatabaseConstants.SCHEMA_VERSION_KEY;
|
import static org.briarproject.bramble.db.DatabaseConstants.SCHEMA_VERSION_KEY;
|
||||||
import static org.briarproject.bramble.db.JdbcDatabase.CODE_SCHEMA_VERSION;
|
import static org.briarproject.bramble.db.JdbcDatabase.CODE_SCHEMA_VERSION;
|
||||||
|
import static org.briarproject.bramble.test.TestUtils.getSecretKey;
|
||||||
import static org.junit.Assert.assertEquals;
|
import static org.junit.Assert.assertEquals;
|
||||||
import static org.junit.Assert.assertFalse;
|
import static org.junit.Assert.assertFalse;
|
||||||
import static org.junit.Assert.assertTrue;
|
import static org.junit.Assert.assertTrue;
|
||||||
@@ -43,6 +45,7 @@ public abstract class DatabaseMigrationTest extends BrambleMockTestCase {
|
|||||||
|
|
||||||
protected final DatabaseConfig config =
|
protected final DatabaseConfig config =
|
||||||
new TestDatabaseConfig(testDir, 1024 * 1024);
|
new TestDatabaseConfig(testDir, 1024 * 1024);
|
||||||
|
protected final SecretKey key = getSecretKey();
|
||||||
protected final Clock clock = new SystemClock();
|
protected final Clock clock = new SystemClock();
|
||||||
|
|
||||||
abstract Database<Connection> createDatabase(
|
abstract Database<Connection> createDatabase(
|
||||||
@@ -62,7 +65,7 @@ public abstract class DatabaseMigrationTest extends BrambleMockTestCase {
|
|||||||
public void testDoesNotRunMigrationsWhenCreatingDatabase()
|
public void testDoesNotRunMigrationsWhenCreatingDatabase()
|
||||||
throws Exception {
|
throws Exception {
|
||||||
Database<Connection> db = createDatabase(singletonList(migration));
|
Database<Connection> db = createDatabase(singletonList(migration));
|
||||||
assertFalse(db.open(null));
|
assertFalse(db.open(key, null));
|
||||||
assertEquals(CODE_SCHEMA_VERSION, getDataSchemaVersion(db));
|
assertEquals(CODE_SCHEMA_VERSION, getDataSchemaVersion(db));
|
||||||
db.close();
|
db.close();
|
||||||
}
|
}
|
||||||
@@ -72,14 +75,14 @@ public abstract class DatabaseMigrationTest extends BrambleMockTestCase {
|
|||||||
throws Exception {
|
throws Exception {
|
||||||
// Open the DB for the first time
|
// Open the DB for the first time
|
||||||
Database<Connection> db = createDatabase(asList(migration, migration1));
|
Database<Connection> db = createDatabase(asList(migration, migration1));
|
||||||
assertFalse(db.open(null));
|
assertFalse(db.open(key, null));
|
||||||
assertEquals(CODE_SCHEMA_VERSION, getDataSchemaVersion(db));
|
assertEquals(CODE_SCHEMA_VERSION, getDataSchemaVersion(db));
|
||||||
// Override the data schema version
|
// Override the data schema version
|
||||||
setDataSchemaVersion(db, -1);
|
setDataSchemaVersion(db, -1);
|
||||||
db.close();
|
db.close();
|
||||||
// Reopen the DB - an exception should be thrown
|
// Reopen the DB - an exception should be thrown
|
||||||
db = createDatabase(asList(migration, migration1));
|
db = createDatabase(asList(migration, migration1));
|
||||||
db.open(null);
|
db.open(key, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -87,12 +90,12 @@ public abstract class DatabaseMigrationTest extends BrambleMockTestCase {
|
|||||||
throws Exception {
|
throws Exception {
|
||||||
// Open the DB for the first time
|
// Open the DB for the first time
|
||||||
Database<Connection> db = createDatabase(asList(migration, migration1));
|
Database<Connection> db = createDatabase(asList(migration, migration1));
|
||||||
assertFalse(db.open(null));
|
assertFalse(db.open(key, null));
|
||||||
assertEquals(CODE_SCHEMA_VERSION, getDataSchemaVersion(db));
|
assertEquals(CODE_SCHEMA_VERSION, getDataSchemaVersion(db));
|
||||||
db.close();
|
db.close();
|
||||||
// Reopen the DB - migrations should not be run
|
// Reopen the DB - migrations should not be run
|
||||||
db = createDatabase(asList(migration, migration1));
|
db = createDatabase(asList(migration, migration1));
|
||||||
assertTrue(db.open(null));
|
assertTrue(db.open(key, null));
|
||||||
assertEquals(CODE_SCHEMA_VERSION, getDataSchemaVersion(db));
|
assertEquals(CODE_SCHEMA_VERSION, getDataSchemaVersion(db));
|
||||||
db.close();
|
db.close();
|
||||||
}
|
}
|
||||||
@@ -101,14 +104,14 @@ public abstract class DatabaseMigrationTest extends BrambleMockTestCase {
|
|||||||
public void testThrowsExceptionIfDataIsNewerThanCode() throws Exception {
|
public void testThrowsExceptionIfDataIsNewerThanCode() throws Exception {
|
||||||
// Open the DB for the first time
|
// Open the DB for the first time
|
||||||
Database<Connection> db = createDatabase(asList(migration, migration1));
|
Database<Connection> db = createDatabase(asList(migration, migration1));
|
||||||
assertFalse(db.open(null));
|
assertFalse(db.open(key, null));
|
||||||
assertEquals(CODE_SCHEMA_VERSION, getDataSchemaVersion(db));
|
assertEquals(CODE_SCHEMA_VERSION, getDataSchemaVersion(db));
|
||||||
// Override the data schema version
|
// Override the data schema version
|
||||||
setDataSchemaVersion(db, CODE_SCHEMA_VERSION + 1);
|
setDataSchemaVersion(db, CODE_SCHEMA_VERSION + 1);
|
||||||
db.close();
|
db.close();
|
||||||
// Reopen the DB - an exception should be thrown
|
// Reopen the DB - an exception should be thrown
|
||||||
db = createDatabase(asList(migration, migration1));
|
db = createDatabase(asList(migration, migration1));
|
||||||
db.open(null);
|
db.open(key, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test(expected = DataTooOldException.class)
|
@Test(expected = DataTooOldException.class)
|
||||||
@@ -116,13 +119,13 @@ public abstract class DatabaseMigrationTest extends BrambleMockTestCase {
|
|||||||
throws Exception {
|
throws Exception {
|
||||||
// Open the DB for the first time
|
// Open the DB for the first time
|
||||||
Database<Connection> db = createDatabase(emptyList());
|
Database<Connection> db = createDatabase(emptyList());
|
||||||
assertFalse(db.open(null));
|
assertFalse(db.open(key, null));
|
||||||
assertEquals(CODE_SCHEMA_VERSION, getDataSchemaVersion(db));
|
assertEquals(CODE_SCHEMA_VERSION, getDataSchemaVersion(db));
|
||||||
setDataSchemaVersion(db, CODE_SCHEMA_VERSION - 1);
|
setDataSchemaVersion(db, CODE_SCHEMA_VERSION - 1);
|
||||||
db.close();
|
db.close();
|
||||||
// Reopen the DB - an exception should be thrown
|
// Reopen the DB - an exception should be thrown
|
||||||
db = createDatabase(emptyList());
|
db = createDatabase(emptyList());
|
||||||
db.open(null);
|
db.open(key, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test(expected = DataTooOldException.class)
|
@Test(expected = DataTooOldException.class)
|
||||||
@@ -141,14 +144,14 @@ public abstract class DatabaseMigrationTest extends BrambleMockTestCase {
|
|||||||
|
|
||||||
// Open the DB for the first time
|
// Open the DB for the first time
|
||||||
Database<Connection> db = createDatabase(asList(migration, migration1));
|
Database<Connection> db = createDatabase(asList(migration, migration1));
|
||||||
assertFalse(db.open(null));
|
assertFalse(db.open(key, null));
|
||||||
assertEquals(CODE_SCHEMA_VERSION, getDataSchemaVersion(db));
|
assertEquals(CODE_SCHEMA_VERSION, getDataSchemaVersion(db));
|
||||||
// Override the data schema version
|
// Override the data schema version
|
||||||
setDataSchemaVersion(db, CODE_SCHEMA_VERSION - 3);
|
setDataSchemaVersion(db, CODE_SCHEMA_VERSION - 3);
|
||||||
db.close();
|
db.close();
|
||||||
// Reopen the DB - an exception should be thrown
|
// Reopen the DB - an exception should be thrown
|
||||||
db = createDatabase(asList(migration, migration1));
|
db = createDatabase(asList(migration, migration1));
|
||||||
db.open(null);
|
db.open(key, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -170,14 +173,14 @@ public abstract class DatabaseMigrationTest extends BrambleMockTestCase {
|
|||||||
|
|
||||||
// Open the DB for the first time
|
// Open the DB for the first time
|
||||||
Database<Connection> db = createDatabase(asList(migration, migration1));
|
Database<Connection> db = createDatabase(asList(migration, migration1));
|
||||||
assertFalse(db.open(null));
|
assertFalse(db.open(key, null));
|
||||||
assertEquals(CODE_SCHEMA_VERSION, getDataSchemaVersion(db));
|
assertEquals(CODE_SCHEMA_VERSION, getDataSchemaVersion(db));
|
||||||
// Override the data schema version
|
// Override the data schema version
|
||||||
setDataSchemaVersion(db, CODE_SCHEMA_VERSION - 2);
|
setDataSchemaVersion(db, CODE_SCHEMA_VERSION - 2);
|
||||||
db.close();
|
db.close();
|
||||||
// Reopen the DB - the first migration should be run
|
// Reopen the DB - the first migration should be run
|
||||||
db = createDatabase(asList(migration, migration1));
|
db = createDatabase(asList(migration, migration1));
|
||||||
assertTrue(db.open(null));
|
assertTrue(db.open(key, null));
|
||||||
assertEquals(CODE_SCHEMA_VERSION, getDataSchemaVersion(db));
|
assertEquals(CODE_SCHEMA_VERSION, getDataSchemaVersion(db));
|
||||||
db.close();
|
db.close();
|
||||||
}
|
}
|
||||||
@@ -202,14 +205,14 @@ public abstract class DatabaseMigrationTest extends BrambleMockTestCase {
|
|||||||
|
|
||||||
// Open the DB for the first time
|
// Open the DB for the first time
|
||||||
Database<Connection> db = createDatabase(asList(migration, migration1));
|
Database<Connection> db = createDatabase(asList(migration, migration1));
|
||||||
assertFalse(db.open(null));
|
assertFalse(db.open(key, null));
|
||||||
assertEquals(CODE_SCHEMA_VERSION, getDataSchemaVersion(db));
|
assertEquals(CODE_SCHEMA_VERSION, getDataSchemaVersion(db));
|
||||||
// Override the data schema version
|
// Override the data schema version
|
||||||
setDataSchemaVersion(db, CODE_SCHEMA_VERSION - 2);
|
setDataSchemaVersion(db, CODE_SCHEMA_VERSION - 2);
|
||||||
db.close();
|
db.close();
|
||||||
// Reopen the DB - both migrations should be run
|
// Reopen the DB - both migrations should be run
|
||||||
db = createDatabase(asList(migration, migration1));
|
db = createDatabase(asList(migration, migration1));
|
||||||
assertTrue(db.open(null));
|
assertTrue(db.open(key, null));
|
||||||
assertEquals(CODE_SCHEMA_VERSION, getDataSchemaVersion(db));
|
assertEquals(CODE_SCHEMA_VERSION, getDataSchemaVersion(db));
|
||||||
db.close();
|
db.close();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ import java.util.List;
|
|||||||
import static org.briarproject.bramble.test.TestUtils.deleteTestDirectory;
|
import static org.briarproject.bramble.test.TestUtils.deleteTestDirectory;
|
||||||
import static org.briarproject.bramble.test.TestUtils.getMean;
|
import static org.briarproject.bramble.test.TestUtils.getMean;
|
||||||
import static org.briarproject.bramble.test.TestUtils.getMedian;
|
import static org.briarproject.bramble.test.TestUtils.getMedian;
|
||||||
|
import static org.briarproject.bramble.test.TestUtils.getSecretKey;
|
||||||
import static org.briarproject.bramble.test.TestUtils.getStandardDeviation;
|
import static org.briarproject.bramble.test.TestUtils.getStandardDeviation;
|
||||||
import static org.briarproject.bramble.test.UTest.Z_CRITICAL_0_01;
|
import static org.briarproject.bramble.test.UTest.Z_CRITICAL_0_01;
|
||||||
|
|
||||||
@@ -71,7 +72,7 @@ public abstract class DatabasePerformanceComparisonTest
|
|||||||
throws DbException {
|
throws DbException {
|
||||||
Database<Connection> db = createDatabase(conditionA,
|
Database<Connection> db = createDatabase(conditionA,
|
||||||
new TestDatabaseConfig(testDir, MAX_SIZE), new SystemClock());
|
new TestDatabaseConfig(testDir, MAX_SIZE), new SystemClock());
|
||||||
db.open(null);
|
db.open(getSecretKey(), null);
|
||||||
return db;
|
return db;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ import java.sql.Connection;
|
|||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
|
|
||||||
import static org.briarproject.bramble.test.TestUtils.deleteTestDirectory;
|
import static org.briarproject.bramble.test.TestUtils.deleteTestDirectory;
|
||||||
|
import static org.briarproject.bramble.test.TestUtils.getSecretKey;
|
||||||
|
|
||||||
public abstract class DatabaseTraceTest extends DatabasePerformanceTest {
|
public abstract class DatabaseTraceTest extends DatabasePerformanceTest {
|
||||||
|
|
||||||
@@ -43,7 +44,7 @@ public abstract class DatabaseTraceTest extends DatabasePerformanceTest {
|
|||||||
private Database<Connection> openDatabase() throws DbException {
|
private Database<Connection> openDatabase() throws DbException {
|
||||||
Database<Connection> db = createDatabase(
|
Database<Connection> db = createDatabase(
|
||||||
new TestDatabaseConfig(testDir, MAX_SIZE), new SystemClock());
|
new TestDatabaseConfig(testDir, MAX_SIZE), new SystemClock());
|
||||||
db.open(null);
|
db.open(getSecretKey(), null);
|
||||||
return db;
|
return db;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -9,8 +9,8 @@ import java.util.List;
|
|||||||
public class H2MigrationTest extends DatabaseMigrationTest {
|
public class H2MigrationTest extends DatabaseMigrationTest {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
Database<Connection> createDatabase(List<Migration<Connection>> migrations)
|
Database<Connection> createDatabase(
|
||||||
throws Exception {
|
List<Migration<Connection>> migrations) {
|
||||||
return new H2Database(config, clock) {
|
return new H2Database(config, clock) {
|
||||||
@Override
|
@Override
|
||||||
List<Migration<Connection>> getMigrations() {
|
List<Migration<Connection>> getMigrations() {
|
||||||
|
|||||||
@@ -64,6 +64,7 @@ import static org.briarproject.bramble.test.TestUtils.getLocalAuthor;
|
|||||||
import static org.briarproject.bramble.test.TestUtils.getRandomBytes;
|
import static org.briarproject.bramble.test.TestUtils.getRandomBytes;
|
||||||
import static org.briarproject.bramble.test.TestUtils.getRandomId;
|
import static org.briarproject.bramble.test.TestUtils.getRandomId;
|
||||||
import static org.briarproject.bramble.test.TestUtils.getSecretKey;
|
import static org.briarproject.bramble.test.TestUtils.getSecretKey;
|
||||||
|
import static org.briarproject.bramble.test.TestUtils.getTestDirectory;
|
||||||
import static org.briarproject.bramble.test.TestUtils.getTransportId;
|
import static org.briarproject.bramble.test.TestUtils.getTransportId;
|
||||||
import static org.junit.Assert.assertArrayEquals;
|
import static org.junit.Assert.assertArrayEquals;
|
||||||
import static org.junit.Assert.assertEquals;
|
import static org.junit.Assert.assertEquals;
|
||||||
@@ -79,7 +80,8 @@ public abstract class JdbcDatabaseTest extends BrambleTestCase {
|
|||||||
private static final int ONE_MEGABYTE = 1024 * 1024;
|
private static final int ONE_MEGABYTE = 1024 * 1024;
|
||||||
private static final int MAX_SIZE = 5 * ONE_MEGABYTE;
|
private static final int MAX_SIZE = 5 * ONE_MEGABYTE;
|
||||||
|
|
||||||
private final File testDir = TestUtils.getTestDirectory();
|
private final SecretKey key = getSecretKey();
|
||||||
|
private final File testDir = getTestDirectory();
|
||||||
private final GroupId groupId;
|
private final GroupId groupId;
|
||||||
private final ClientId clientId;
|
private final ClientId clientId;
|
||||||
private final int majorVersion;
|
private final int majorVersion;
|
||||||
@@ -96,7 +98,7 @@ public abstract class JdbcDatabaseTest extends BrambleTestCase {
|
|||||||
private final KeySetId keySetId, keySetId1;
|
private final KeySetId keySetId, keySetId1;
|
||||||
private final Random random = new Random();
|
private final Random random = new Random();
|
||||||
|
|
||||||
JdbcDatabaseTest() throws Exception {
|
JdbcDatabaseTest() {
|
||||||
clientId = getClientId();
|
clientId = getClientId();
|
||||||
majorVersion = 123;
|
majorVersion = 123;
|
||||||
group = getGroup(clientId, majorVersion);
|
group = getGroup(clientId, majorVersion);
|
||||||
@@ -1819,7 +1821,7 @@ public abstract class JdbcDatabaseTest extends BrambleTestCase {
|
|||||||
Database<Connection> db = createDatabase(
|
Database<Connection> db = createDatabase(
|
||||||
new TestDatabaseConfig(testDir, MAX_SIZE), clock);
|
new TestDatabaseConfig(testDir, MAX_SIZE), clock);
|
||||||
if (!resume) TestUtils.deleteTestDirectory(testDir);
|
if (!resume) TestUtils.deleteTestDirectory(testDir);
|
||||||
db.open(null);
|
db.open(key, null);
|
||||||
return db;
|
return db;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ import java.util.List;
|
|||||||
import static org.briarproject.bramble.test.TestUtils.deleteTestDirectory;
|
import static org.briarproject.bramble.test.TestUtils.deleteTestDirectory;
|
||||||
import static org.briarproject.bramble.test.TestUtils.getMean;
|
import static org.briarproject.bramble.test.TestUtils.getMean;
|
||||||
import static org.briarproject.bramble.test.TestUtils.getMedian;
|
import static org.briarproject.bramble.test.TestUtils.getMedian;
|
||||||
|
import static org.briarproject.bramble.test.TestUtils.getSecretKey;
|
||||||
import static org.briarproject.bramble.test.TestUtils.getStandardDeviation;
|
import static org.briarproject.bramble.test.TestUtils.getStandardDeviation;
|
||||||
|
|
||||||
public abstract class SingleDatabasePerformanceTest
|
public abstract class SingleDatabasePerformanceTest
|
||||||
@@ -40,7 +41,7 @@ public abstract class SingleDatabasePerformanceTest
|
|||||||
private Database<Connection> openDatabase() throws DbException {
|
private Database<Connection> openDatabase() throws DbException {
|
||||||
Database<Connection> db = createDatabase(
|
Database<Connection> db = createDatabase(
|
||||||
new TestDatabaseConfig(testDir, MAX_SIZE), new SystemClock());
|
new TestDatabaseConfig(testDir, MAX_SIZE), new SystemClock());
|
||||||
db.open(null);
|
db.open(getSecretKey(), null);
|
||||||
return db;
|
return db;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -2,15 +2,21 @@ package org.briarproject.bramble.identity;
|
|||||||
|
|
||||||
import org.briarproject.bramble.api.contact.Contact;
|
import org.briarproject.bramble.api.contact.Contact;
|
||||||
import org.briarproject.bramble.api.contact.ContactId;
|
import org.briarproject.bramble.api.contact.ContactId;
|
||||||
|
import org.briarproject.bramble.api.crypto.CryptoComponent;
|
||||||
|
import org.briarproject.bramble.api.crypto.KeyPair;
|
||||||
|
import org.briarproject.bramble.api.crypto.PrivateKey;
|
||||||
|
import org.briarproject.bramble.api.crypto.PublicKey;
|
||||||
import org.briarproject.bramble.api.db.DatabaseComponent;
|
import org.briarproject.bramble.api.db.DatabaseComponent;
|
||||||
import org.briarproject.bramble.api.db.DbException;
|
import org.briarproject.bramble.api.db.DbException;
|
||||||
import org.briarproject.bramble.api.db.Transaction;
|
import org.briarproject.bramble.api.db.Transaction;
|
||||||
import org.briarproject.bramble.api.identity.Author;
|
import org.briarproject.bramble.api.identity.Author;
|
||||||
|
import org.briarproject.bramble.api.identity.AuthorFactory;
|
||||||
import org.briarproject.bramble.api.identity.AuthorId;
|
import org.briarproject.bramble.api.identity.AuthorId;
|
||||||
import org.briarproject.bramble.api.identity.IdentityManager;
|
import org.briarproject.bramble.api.identity.IdentityManager;
|
||||||
import org.briarproject.bramble.api.identity.LocalAuthor;
|
import org.briarproject.bramble.api.identity.LocalAuthor;
|
||||||
import org.briarproject.bramble.test.BrambleMockTestCase;
|
import org.briarproject.bramble.test.BrambleMockTestCase;
|
||||||
import org.jmock.Expectations;
|
import org.jmock.Expectations;
|
||||||
|
import org.junit.Before;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
@@ -27,24 +33,48 @@ import static org.junit.Assert.assertEquals;
|
|||||||
|
|
||||||
public class IdentityManagerImplTest extends BrambleMockTestCase {
|
public class IdentityManagerImplTest extends BrambleMockTestCase {
|
||||||
|
|
||||||
private final IdentityManager identityManager;
|
|
||||||
private final DatabaseComponent db = context.mock(DatabaseComponent.class);
|
private final DatabaseComponent db = context.mock(DatabaseComponent.class);
|
||||||
|
private final CryptoComponent crypto = context.mock(CryptoComponent.class);
|
||||||
|
private final AuthorFactory authorFactory =
|
||||||
|
context.mock(AuthorFactory.class);
|
||||||
|
private final PublicKey publicKey = context.mock(PublicKey.class);
|
||||||
|
private final PrivateKey privateKey = context.mock(PrivateKey.class);
|
||||||
|
|
||||||
private final Transaction txn = new Transaction(null, false);
|
private final Transaction txn = new Transaction(null, false);
|
||||||
private final LocalAuthor localAuthor = getLocalAuthor();
|
private final LocalAuthor localAuthor = getLocalAuthor();
|
||||||
private final Collection<LocalAuthor> localAuthors =
|
private final Collection<LocalAuthor> localAuthors =
|
||||||
Collections.singletonList(localAuthor);
|
Collections.singletonList(localAuthor);
|
||||||
|
private final String authorName = localAuthor.getName();
|
||||||
|
private final KeyPair keyPair = new KeyPair(publicKey, privateKey);
|
||||||
|
private final byte[] publicKeyBytes = localAuthor.getPublicKey();
|
||||||
|
private final byte[] privateKeyBytes = localAuthor.getPrivateKey();
|
||||||
|
private IdentityManager identityManager;
|
||||||
|
|
||||||
public IdentityManagerImplTest() {
|
@Before
|
||||||
identityManager = new IdentityManagerImpl(db);
|
public void setUp() {
|
||||||
|
identityManager = new IdentityManagerImpl(db, crypto, authorFactory);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testRegisterLocalAuthor() throws DbException {
|
public void testCreateLocalAuthor() {
|
||||||
expectRegisterLocalAuthor();
|
context.checking(new Expectations() {{
|
||||||
identityManager.registerLocalAuthor(localAuthor);
|
oneOf(crypto).generateSignatureKeyPair();
|
||||||
|
will(returnValue(keyPair));
|
||||||
|
oneOf(publicKey).getEncoded();
|
||||||
|
will(returnValue(publicKeyBytes));
|
||||||
|
oneOf(privateKey).getEncoded();
|
||||||
|
will(returnValue(privateKeyBytes));
|
||||||
|
oneOf(authorFactory).createLocalAuthor(authorName,
|
||||||
|
publicKeyBytes, privateKeyBytes);
|
||||||
|
will(returnValue(localAuthor));
|
||||||
|
}});
|
||||||
|
|
||||||
|
assertEquals(localAuthor,
|
||||||
|
identityManager.createLocalAuthor(authorName));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void expectRegisterLocalAuthor() throws DbException {
|
@Test
|
||||||
|
public void testRegisterAndStoreLocalAuthor() throws DbException {
|
||||||
context.checking(new Expectations() {{
|
context.checking(new Expectations() {{
|
||||||
oneOf(db).startTransaction(false);
|
oneOf(db).startTransaction(false);
|
||||||
will(returnValue(txn));
|
will(returnValue(txn));
|
||||||
@@ -52,6 +82,10 @@ public class IdentityManagerImplTest extends BrambleMockTestCase {
|
|||||||
oneOf(db).commitTransaction(txn);
|
oneOf(db).commitTransaction(txn);
|
||||||
oneOf(db).endTransaction(txn);
|
oneOf(db).endTransaction(txn);
|
||||||
}});
|
}});
|
||||||
|
|
||||||
|
identityManager.registerLocalAuthor(localAuthor);
|
||||||
|
assertEquals(localAuthor, identityManager.getLocalAuthor());
|
||||||
|
identityManager.storeLocalAuthor();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -69,7 +103,6 @@ public class IdentityManagerImplTest extends BrambleMockTestCase {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testGetCachedLocalAuthor() throws DbException {
|
public void testGetCachedLocalAuthor() throws DbException {
|
||||||
expectRegisterLocalAuthor();
|
|
||||||
identityManager.registerLocalAuthor(localAuthor);
|
identityManager.registerLocalAuthor(localAuthor);
|
||||||
assertEquals(localAuthor, identityManager.getLocalAuthor());
|
assertEquals(localAuthor, identityManager.getLocalAuthor());
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
package org.briarproject.bramble.test;
|
package org.briarproject.bramble.test;
|
||||||
|
|
||||||
import org.briarproject.bramble.api.crypto.SecretKey;
|
|
||||||
import org.briarproject.bramble.api.db.DatabaseConfig;
|
import org.briarproject.bramble.api.db.DatabaseConfig;
|
||||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||||
|
|
||||||
@@ -11,7 +10,6 @@ public class TestDatabaseConfig implements DatabaseConfig {
|
|||||||
|
|
||||||
private final File dbDir, keyDir;
|
private final File dbDir, keyDir;
|
||||||
private final long maxSize;
|
private final long maxSize;
|
||||||
private volatile SecretKey key = new SecretKey(new byte[SecretKey.LENGTH]);
|
|
||||||
|
|
||||||
public TestDatabaseConfig(File testDir, long maxSize) {
|
public TestDatabaseConfig(File testDir, long maxSize) {
|
||||||
dbDir = new File(testDir, "db");
|
dbDir = new File(testDir, "db");
|
||||||
@@ -19,13 +17,6 @@ public class TestDatabaseConfig implements DatabaseConfig {
|
|||||||
this.maxSize = maxSize;
|
this.maxSize = maxSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean databaseExists() {
|
|
||||||
if (!dbDir.isDirectory()) return false;
|
|
||||||
File[] files = dbDir.listFiles();
|
|
||||||
return files != null && files.length > 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public File getDatabaseDirectory() {
|
public File getDatabaseDirectory() {
|
||||||
return dbDir;
|
return dbDir;
|
||||||
@@ -36,26 +27,6 @@ public class TestDatabaseConfig implements DatabaseConfig {
|
|||||||
return keyDir;
|
return keyDir;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setEncryptionKey(SecretKey key) {
|
|
||||||
this.key = key;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public SecretKey getEncryptionKey() {
|
|
||||||
return key;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setLocalAuthorName(String nickname) {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getLocalAuthorName() {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public long getMaxSize() {
|
public long getMaxSize() {
|
||||||
return maxSize;
|
return maxSize;
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
package org.briarproject.bramble.test;
|
package org.briarproject.bramble.test;
|
||||||
|
|
||||||
|
import org.briarproject.bramble.api.crypto.SecretKey;
|
||||||
import org.briarproject.bramble.api.lifecycle.IoExecutor;
|
import org.briarproject.bramble.api.lifecycle.IoExecutor;
|
||||||
import org.briarproject.bramble.api.lifecycle.LifecycleManager;
|
import org.briarproject.bramble.api.lifecycle.LifecycleManager;
|
||||||
import org.briarproject.bramble.api.lifecycle.Service;
|
import org.briarproject.bramble.api.lifecycle.Service;
|
||||||
@@ -11,7 +12,6 @@ import java.util.concurrent.Executor;
|
|||||||
import java.util.concurrent.ExecutorService;
|
import java.util.concurrent.ExecutorService;
|
||||||
import java.util.concurrent.Executors;
|
import java.util.concurrent.Executors;
|
||||||
|
|
||||||
import javax.annotation.Nullable;
|
|
||||||
import javax.inject.Singleton;
|
import javax.inject.Singleton;
|
||||||
|
|
||||||
import dagger.Module;
|
import dagger.Module;
|
||||||
@@ -40,7 +40,7 @@ public class TestLifecycleModule {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public StartResult startServices(@Nullable String nickname) {
|
public StartResult startServices(SecretKey dbKey) {
|
||||||
return StartResult.SUCCESS;
|
return StartResult.SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -49,15 +49,15 @@ public class TestLifecycleModule {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void waitForDatabase() throws InterruptedException {
|
public void waitForDatabase() {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void waitForStartup() throws InterruptedException {
|
public void waitForStartup() {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void waitForShutdown() throws InterruptedException {
|
public void waitForShutdown() {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
33
bramble-core/witness.gradle
Normal file
33
bramble-core/witness.gradle
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
dependencyVerification {
|
||||||
|
verify = [
|
||||||
|
'cglib:cglib:3.2.0:cglib-3.2.0.jar:adb13bab79712ad6bdf1bd59f2a3918018a8016e722e8a357065afb9e6690861',
|
||||||
|
'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.guava:guava:18.0:guava-18.0.jar:d664fbfc03d2e5ce9cab2a44fb01f1d0bf9dfebeccc1a473b1f9ea31f79f6f99',
|
||||||
|
'com.h2database:h2:1.4.192:h2-1.4.192.jar:225b22e9857235c46c93861410b60b8c81c10dc8985f4faf188985ba5445126c',
|
||||||
|
'com.madgag.spongycastle:core:1.58.0.0:core-1.58.0.0.jar:199617dd5698c5a9312b898c0a4cec7ce9dd8649d07f65d91629f58229d72728',
|
||||||
|
'javax.inject:javax.inject:1:javax.inject-1.jar:91c77044a50c481636c32d916fd89c9118a72195390452c81065080f957de7ff',
|
||||||
|
'junit:junit:4.12:junit-4.12.jar:59721f0805e223d84b90677887d9ff567dc534d7c502ca903c0c2b17f05c116a',
|
||||||
|
'net.i2p.crypto:eddsa:0.2.0:eddsa-0.2.0.jar:a7cb1b85c16e2f0730b9204106929a1d9aaae1df728adc7041a8b8b605692140',
|
||||||
|
'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.beanshell:bsh:1.3.0:bsh-1.3.0.jar:9b04edc75d19db54f1b4e8b5355e9364384c6cf71eb0a1b9724c159d779879f8',
|
||||||
|
'org.bitlet:weupnp:0.1.4:weupnp-0.1.4.jar:88df7e6504929d00bdb832863761385c68ab92af945b04f0770b126270a444fb',
|
||||||
|
'org.briarproject:jtorctl:0.3:jtorctl-0.3.jar:f2939238a097898998432effe93b0334d97a787972ab3a91a8973a1d309fc864',
|
||||||
|
'org.codehaus.mojo.signature:java16:1.1:java16-1.1.signature:53799223a2c98dba2d0add810bed76315460df285c69e4f397ae6098f87dd619',
|
||||||
|
'org.codehaus.mojo:animal-sniffer-ant-tasks:1.16:animal-sniffer-ant-tasks-1.16.jar:890040976fbe2d584619a6a61b1fd2e925b3b5eb342a85eb2762c467c0d64e90',
|
||||||
|
'org.codehaus.mojo:animal-sniffer:1.16:animal-sniffer-1.16.jar:72be8bcc226ba43b937c722a08a07852bfa1b11400089265d5df0ee7b38b1d52',
|
||||||
|
'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.hsqldb:hsqldb:2.3.5:hsqldb-2.3.5.jar:6676a6977ac98997a80f827ddbd3fe8ca1e0853dad1492512135fd1a222ccfad',
|
||||||
|
'org.jmock:jmock-junit4:2.8.2:jmock-junit4-2.8.2.jar:f7ee4df4f7bd7b7f1cafad3b99eb74d579f109d5992ff625347352edb55e674c',
|
||||||
|
'org.jmock:jmock-legacy:2.8.2:jmock-legacy-2.8.2.jar:f2b985a5c08a9edb7f37612330c058809da3f6a6d63ce792426ebf8ff0d6d31b',
|
||||||
|
'org.jmock:jmock-testjar:2.8.2:jmock-testjar-2.8.2.jar:8900860f72c474e027cf97fe78dcbf154a1aa7fc62b6845c5fb4e4f3c7bc8760',
|
||||||
|
'org.jmock:jmock:2.8.2:jmock-2.8.2.jar:6c73cb4a2e6dbfb61fd99c9a768539c170ab6568e57846bd60dbf19596b65b16',
|
||||||
|
'org.objenesis:objenesis:2.1:objenesis-2.1.jar:c74330cc6b806c804fd37e74487b4fe5d7c2750c5e15fbc6efa13bdee1bdef80',
|
||||||
|
'org.ow2.asm:asm-all:5.2:asm-all-5.2.jar:7fbffbc1db3422e2101689fd88df8384b15817b52b9b2b267b9f6d2511dc198d',
|
||||||
|
'org.ow2.asm:asm:5.0.4:asm-5.0.4.jar:896618ed8ae62702521a78bc7be42b7c491a08e6920a15f89a3ecdec31e9a220',
|
||||||
|
'org.whispersystems:curve25519-java:0.4.1:curve25519-java-0.4.1.jar:7dd659d8822c06c3aea1a47f18fac9e5761e29cab8100030b877db445005f03e',
|
||||||
|
]
|
||||||
|
}
|
||||||
@@ -5,6 +5,7 @@ targetCompatibility = 1.8
|
|||||||
apply plugin: 'net.ltgt.apt'
|
apply plugin: 'net.ltgt.apt'
|
||||||
apply plugin: 'idea'
|
apply plugin: 'idea'
|
||||||
apply plugin: 'witness'
|
apply plugin: 'witness'
|
||||||
|
apply from: 'witness.gradle'
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
implementation project(path: ':bramble-core', configuration: 'default')
|
implementation project(path: ':bramble-core', configuration: 'default')
|
||||||
@@ -24,31 +25,8 @@ dependencies {
|
|||||||
testImplementation "org.hamcrest:hamcrest-core:1.3"
|
testImplementation "org.hamcrest:hamcrest-core:1.3"
|
||||||
}
|
}
|
||||||
|
|
||||||
dependencyVerification {
|
|
||||||
verify = [
|
|
||||||
'cglib:cglib:3.2.0:cglib-3.2.0.jar:adb13bab79712ad6bdf1bd59f2a3918018a8016e722e8a357065afb9e6690861',
|
|
||||||
'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.guava:guava:18.0:guava-18.0.jar:d664fbfc03d2e5ce9cab2a44fb01f1d0bf9dfebeccc1a473b1f9ea31f79f6f99',
|
|
||||||
'javax.inject:javax.inject:1:javax.inject-1.jar:91c77044a50c481636c32d916fd89c9118a72195390452c81065080f957de7ff',
|
|
||||||
'junit:junit:4.12:junit-4.12.jar:59721f0805e223d84b90677887d9ff567dc534d7c502ca903c0c2b17f05c116a',
|
|
||||||
'net.java.dev.jna:jna-platform:4.4.0:jna-platform-4.4.0.jar:e9dda9e884fc107eb6367710540789a12dfa8ad28be9326b22ca6e352e325499',
|
|
||||||
'net.java.dev.jna:jna:4.4.0:jna-4.4.0.jar:c4dadeeecaa90c8847902082aee5eb107fcf59c5d0e63a17fcaf273c0e2d2bd1',
|
|
||||||
'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.beanshell:bsh:1.3.0:bsh-1.3.0.jar:9b04edc75d19db54f1b4e8b5355e9364384c6cf71eb0a1b9724c159d779879f8',
|
|
||||||
'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.jmock:jmock-junit4:2.8.2:jmock-junit4-2.8.2.jar:f7ee4df4f7bd7b7f1cafad3b99eb74d579f109d5992ff625347352edb55e674c',
|
|
||||||
'org.jmock:jmock-legacy:2.8.2:jmock-legacy-2.8.2.jar:f2b985a5c08a9edb7f37612330c058809da3f6a6d63ce792426ebf8ff0d6d31b',
|
|
||||||
'org.jmock:jmock-testjar:2.8.2:jmock-testjar-2.8.2.jar:8900860f72c474e027cf97fe78dcbf154a1aa7fc62b6845c5fb4e4f3c7bc8760',
|
|
||||||
'org.jmock:jmock:2.8.2:jmock-2.8.2.jar:6c73cb4a2e6dbfb61fd99c9a768539c170ab6568e57846bd60dbf19596b65b16',
|
|
||||||
'org.objenesis:objenesis:2.1:objenesis-2.1.jar:c74330cc6b806c804fd37e74487b4fe5d7c2750c5e15fbc6efa13bdee1bdef80',
|
|
||||||
'org.ow2.asm:asm:5.0.4:asm-5.0.4.jar:896618ed8ae62702521a78bc7be42b7c491a08e6920a15f89a3ecdec31e9a220',
|
|
||||||
]
|
|
||||||
}
|
|
||||||
|
|
||||||
tasks.withType(Test) {
|
tasks.withType(Test) {
|
||||||
|
// Use entropy-gathering device specified on command line, if any
|
||||||
|
systemProperty 'java.security.egd', System.getProperty('java.security.egd')
|
||||||
systemProperty 'java.library.path', 'libs'
|
systemProperty 'java.library.path', 'libs'
|
||||||
}
|
}
|
||||||
|
|||||||
24
bramble-j2se/witness.gradle
Normal file
24
bramble-j2se/witness.gradle
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
dependencyVerification {
|
||||||
|
verify = [
|
||||||
|
'cglib:cglib:3.2.0:cglib-3.2.0.jar:adb13bab79712ad6bdf1bd59f2a3918018a8016e722e8a357065afb9e6690861',
|
||||||
|
'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.guava:guava:18.0:guava-18.0.jar:d664fbfc03d2e5ce9cab2a44fb01f1d0bf9dfebeccc1a473b1f9ea31f79f6f99',
|
||||||
|
'javax.inject:javax.inject:1:javax.inject-1.jar:91c77044a50c481636c32d916fd89c9118a72195390452c81065080f957de7ff',
|
||||||
|
'junit:junit:4.12:junit-4.12.jar:59721f0805e223d84b90677887d9ff567dc534d7c502ca903c0c2b17f05c116a',
|
||||||
|
'net.java.dev.jna:jna-platform:4.4.0:jna-platform-4.4.0.jar:e9dda9e884fc107eb6367710540789a12dfa8ad28be9326b22ca6e352e325499',
|
||||||
|
'net.java.dev.jna:jna:4.4.0:jna-4.4.0.jar:c4dadeeecaa90c8847902082aee5eb107fcf59c5d0e63a17fcaf273c0e2d2bd1',
|
||||||
|
'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.beanshell:bsh:1.3.0:bsh-1.3.0.jar:9b04edc75d19db54f1b4e8b5355e9364384c6cf71eb0a1b9724c159d779879f8',
|
||||||
|
'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.jmock:jmock-junit4:2.8.2:jmock-junit4-2.8.2.jar:f7ee4df4f7bd7b7f1cafad3b99eb74d579f109d5992ff625347352edb55e674c',
|
||||||
|
'org.jmock:jmock-legacy:2.8.2:jmock-legacy-2.8.2.jar:f2b985a5c08a9edb7f37612330c058809da3f6a6d63ce792426ebf8ff0d6d31b',
|
||||||
|
'org.jmock:jmock-testjar:2.8.2:jmock-testjar-2.8.2.jar:8900860f72c474e027cf97fe78dcbf154a1aa7fc62b6845c5fb4e4f3c7bc8760',
|
||||||
|
'org.jmock:jmock:2.8.2:jmock-2.8.2.jar:6c73cb4a2e6dbfb61fd99c9a768539c170ab6568e57846bd60dbf19596b65b16',
|
||||||
|
'org.objenesis:objenesis:2.1:objenesis-2.1.jar:c74330cc6b806c804fd37e74487b4fe5d7c2750c5e15fbc6efa13bdee1bdef80',
|
||||||
|
'org.ow2.asm:asm:5.0.4:asm-5.0.4.jar:896618ed8ae62702521a78bc7be42b7c491a08e6920a15f89a3ecdec31e9a220',
|
||||||
|
]
|
||||||
|
}
|
||||||
6
briar-android/.gitignore
vendored
6
briar-android/.gitignore
vendored
@@ -5,3 +5,9 @@ local.properties
|
|||||||
.settings
|
.settings
|
||||||
src/main/assets/*.zip
|
src/main/assets/*.zip
|
||||||
src/main/res/values-iw
|
src/main/res/values-iw
|
||||||
|
|
||||||
|
# Fastlane Screenshots
|
||||||
|
/fastlane/metadata/android/screenshots.html
|
||||||
|
/fastlane/metadata/android/*/images
|
||||||
|
/fastlane/report.xml
|
||||||
|
/fastlane/README.md
|
||||||
@@ -14,7 +14,7 @@
|
|||||||
x="0px"
|
x="0px"
|
||||||
y="0px"
|
y="0px"
|
||||||
xml:space="preserve"
|
xml:space="preserve"
|
||||||
inkscape:version="0.91 r13725"
|
inkscape:version="0.92.3 (2405546, 2018-03-11)"
|
||||||
sodipodi:docname="logo_horizontal_white.svg"
|
sodipodi:docname="logo_horizontal_white.svg"
|
||||||
width="138"
|
width="138"
|
||||||
height="50"><metadata
|
height="50"><metadata
|
||||||
@@ -31,18 +31,18 @@
|
|||||||
inkscape:pageopacity="0"
|
inkscape:pageopacity="0"
|
||||||
inkscape:pageshadow="2"
|
inkscape:pageshadow="2"
|
||||||
inkscape:window-width="1920"
|
inkscape:window-width="1920"
|
||||||
inkscape:window-height="1021"
|
inkscape:window-height="1020"
|
||||||
id="namedview67"
|
id="namedview67"
|
||||||
showgrid="false"
|
showgrid="false"
|
||||||
fit-margin-top="0"
|
fit-margin-top="0"
|
||||||
fit-margin-left="0"
|
fit-margin-left="0"
|
||||||
fit-margin-right="0"
|
fit-margin-right="0"
|
||||||
fit-margin-bottom="0"
|
fit-margin-bottom="0"
|
||||||
inkscape:zoom="1.410079"
|
inkscape:zoom="5.640316"
|
||||||
inkscape:cx="96.786606"
|
inkscape:cx="47.227033"
|
||||||
inkscape:cy="117.77539"
|
inkscape:cy="7.5801079"
|
||||||
inkscape:window-x="1443"
|
inkscape:window-x="1440"
|
||||||
inkscape:window-y="23"
|
inkscape:window-y="24"
|
||||||
inkscape:window-maximized="0"
|
inkscape:window-maximized="0"
|
||||||
inkscape:current-layer="Ebene_1" /><style
|
inkscape:current-layer="Ebene_1" /><style
|
||||||
type="text/css"
|
type="text/css"
|
||||||
@@ -53,55 +53,7 @@
|
|||||||
.st3{fill:#95D220;}
|
.st3{fill:#95D220;}
|
||||||
.st4{display:none;fill:#95D220;}
|
.st4{display:none;fill:#95D220;}
|
||||||
.st5{fill:#FFFFFF;}
|
.st5{fill:#FFFFFF;}
|
||||||
</style><rect
|
</style><path
|
||||||
style="display:none;fill:#87c214"
|
|
||||||
id="rect11"
|
|
||||||
height="9.279274"
|
|
||||||
width="9.279274"
|
|
||||||
class="st0"
|
|
||||||
y="214.00124"
|
|
||||||
x="230.02246" /><path
|
|
||||||
class="st2"
|
|
||||||
d="m 235.54331,203.97877 c 2.05971,0 3.75843,1.69872 3.75843,3.75842 l 0,42.40437 c 0,2.05971 -1.69872,3.75843 -3.75843,3.75843 l -1.76242,0 c -2.0597,0 -3.75843,-1.69872 -3.75843,-3.75843 l 0,-42.40437 c 0,-2.0597 1.67749,-3.75842 3.73719,-3.75842 l 1.78366,0 m 0,-1.48638 -1.76242,0 c -2.90906,0 -5.24481,2.35697 -5.24481,5.2448 l 0,42.40437 c 0,2.88783 2.35698,5.24481 5.24481,5.24481 l 1.76242,0 c 2.88783,0 5.24481,-2.35698 5.24481,-5.24481 l 0,-42.40437 c -0.0212,-2.88783 -2.35698,-5.2448 -5.24481,-5.2448 l 0,0 z"
|
|
||||||
id="path17"
|
|
||||||
inkscape:connector-curvature="0"
|
|
||||||
style="display:none;fill:#ffffff" /><rect
|
|
||||||
style="display:none;fill:#87c214"
|
|
||||||
id="rect25"
|
|
||||||
height="9.279274"
|
|
||||||
width="9.279274"
|
|
||||||
class="st0"
|
|
||||||
y="234.59825"
|
|
||||||
x="250.61948" /><path
|
|
||||||
class="st2"
|
|
||||||
d="m 256.14033,203.97877 c 2.0597,0 3.75842,1.69872 3.75842,3.75842 l 0,42.40437 c 0,2.05971 -1.67749,3.75843 -3.75842,3.75843 l -1.76243,0 c -2.0597,0 -3.75842,-1.69872 -3.75842,-3.75843 l 0,-42.40437 c 0,-2.0597 1.69872,-3.75842 3.75842,-3.75842 l 1.76243,0 m 0,-1.48638 -1.76243,0 c -2.88783,0 -5.2448,2.35697 -5.2448,5.2448 l 0,42.40437 c 0,2.88783 2.35697,5.24481 5.2448,5.24481 l 1.76243,0 c 2.88783,0 5.24481,-2.35698 5.24481,-5.24481 l 0,-42.40437 c -0.0212,-2.88783 -2.35698,-5.2448 -5.24481,-5.2448 l 0,0 z"
|
|
||||||
id="path29"
|
|
||||||
inkscape:connector-curvature="0"
|
|
||||||
style="display:none;fill:#ffffff" /><rect
|
|
||||||
style="display:none;fill:#95d220"
|
|
||||||
id="rect37"
|
|
||||||
height="9.279274"
|
|
||||||
width="9.279274"
|
|
||||||
class="st4"
|
|
||||||
y="234.59825"
|
|
||||||
x="230.02246" /><path
|
|
||||||
class="st2"
|
|
||||||
d="m 266.14156,234.59825 c 2.0597,0 3.75842,1.67749 3.75842,3.75842 l 0,1.76243 c 0,2.0597 -1.69872,3.75842 -3.75842,3.75842 l -42.38314,0 c -2.0597,0 -3.75842,-1.69872 -3.75842,-3.75842 l 0,-1.76243 c 0,-2.0597 1.67749,-3.75842 3.75842,-3.75842 l 42.38314,0 m 0,-1.48638 -42.38314,0 c -2.88783,0 -5.2448,2.33574 -5.2448,5.22357 l 0,1.76242 c 0,2.88783 2.35697,5.24481 5.2448,5.24481 l 42.40437,0 c 2.88783,0 5.24481,-2.35698 5.24481,-5.24481 l 0,-1.76242 c -0.0212,-2.88783 -2.37821,-5.22357 -5.26604,-5.22357 l 0,0 z"
|
|
||||||
id="path41"
|
|
||||||
inkscape:connector-curvature="0"
|
|
||||||
style="display:none;fill:#ffffff" /><rect
|
|
||||||
style="display:none;fill:#95d220"
|
|
||||||
id="rect47"
|
|
||||||
height="9.279274"
|
|
||||||
width="9.279274"
|
|
||||||
class="st4"
|
|
||||||
y="214.00124"
|
|
||||||
x="250.61948" /><path
|
|
||||||
class="st2"
|
|
||||||
d="m 266.14156,214.00123 c 2.0597,0 3.75842,1.67749 3.75842,3.75843 l 0,1.76242 c 0,2.05971 -1.69872,3.75843 -3.75842,3.75843 l -42.38314,0 C 221.67749,223.25927 220,221.58179 220,219.52208 l 0,-1.76242 c 0,-2.0597 1.67749,-3.75843 3.75842,-3.75843 l 42.38314,0 m 0,-1.48638 -42.38314,0 c -2.88783,0 -5.2448,2.33575 -5.2448,5.22357 l 0,1.76243 c 0,2.88783 2.35697,5.24481 5.2448,5.24481 l 42.40437,0 c 2.88783,0 5.24481,-2.35698 5.24481,-5.24481 l 0,-1.76243 c -0.0212,-2.88782 -2.37821,-5.22357 -5.26604,-5.22357 l 0,0 z"
|
|
||||||
id="path53"
|
|
||||||
inkscape:connector-curvature="0"
|
|
||||||
style="display:none;fill:#ffffff" /><path
|
|
||||||
style="fill:#ffffff"
|
style="fill:#ffffff"
|
||||||
d="m 57.097656,30.69922 0,19.30078 9.06836,0 c 4.22557,0 6.474893,-2.12355 6.496093,-5.47852 0,-2.14464 -1.017672,-3.78004 -3.013671,-4.67187 l 0,-0.041 c 1.507609,-0.9343 2.166015,-2.10331 2.166015,-3.9082 0,-2.73919 -1.848098,-5.20117 -5.861328,-5.20117 l -8.855469,0 z m 18.75,0 0,19.30078 2.271485,0 0,-7.72852 -0.232422,-0.23437 4.585937,0 c 2.54808,0 4.012966,0.91391 4.947266,2.88867 L 89.820312,50 92.367188,50 89.4375,43.96875 c -0.63702,-1.35898 -1.614284,-2.20763 -2.527344,-2.58984 l 0,-0.043 c 2.1234,-0.55208 3.865235,-2.42042 3.865235,-4.94727 0,-3.80089 -2.951713,-5.68945 -6.476563,-5.68945 l -8.451172,0 z m 18.876953,0 0,19.30078 2.273438,0 0,-19.30078 -2.273438,0 z m 13.419921,0 L 99.650391,50 l 2.484379,0 2.03906,-4.65039 -0.12695,-0.23438 10.57421,0 -0.12695,0.23438 2.03906,4.65039 2.48438,0 -8.47266,-19.30078 -2.40039,0 z m 13.33594,0 0,19.30078 2.27148,0 0,-7.72852 -0.23437,-0.23437 4.58789,0 c 2.54808,0 4.01296,0.91391 4.94726,2.88867 L 135.45117,50 138,50 135.07031,43.96875 c -0.63702,-1.35898 -1.61427,-2.20763 -2.52734,-2.58984 l 0,-0.043 c 2.12341,-0.55208 3.86523,-2.42042 3.86523,-4.94727 0,-3.80089 -2.95171,-5.68945 -6.47656,-5.68945 l -8.45117,0 z m -62.322267,2.14453 6.560547,0 c 2.46315,0 3.759766,0.9967 3.759766,3.03516 0,1.71996 -0.999336,3.10156 -3.759766,3.10156 l -6.560547,0 0.234375,-0.23438 0,-5.66992 -0.234375,-0.23242 z m 18.728516,0 6.433593,0 c 2.378211,0 4.14091,0.97535 4.16211,3.52344 0,2.03846 -1.634356,3.5039 -4.416016,3.5039 l -6.179687,0 0.232422,-0.23242 0,-6.5625 -0.232422,-0.23242 z m 45.652341,0 6.4336,0 c 2.35698,0 4.14062,0.97535 4.14062,3.52344 0,2.03846 -1.61288,3.5039 -4.39453,3.5039 l -6.17969,0 0.23438,-0.23242 0,-6.5625 -0.23438,-0.23242 z m -14.20508,0.21094 0.043,0 0.57227,1.93359 3.39844,7.75 0.23242,0.23242 -8.4707,0 0.23242,-0.23242 3.39843,-7.75 0.59375,-1.93359 z m -50.197261,8.07031 7.007812,0 c 2.84536,0 4.16211,1.3153 4.16211,3.375 0,2.14464 -1.189095,3.33398 -4.140625,3.33398 l -7.029297,0 0.234375,-0.23437 0,-6.24219 -0.234375,-0.23242 z"
|
d="m 57.097656,30.69922 0,19.30078 9.06836,0 c 4.22557,0 6.474893,-2.12355 6.496093,-5.47852 0,-2.14464 -1.017672,-3.78004 -3.013671,-4.67187 l 0,-0.041 c 1.507609,-0.9343 2.166015,-2.10331 2.166015,-3.9082 0,-2.73919 -1.848098,-5.20117 -5.861328,-5.20117 l -8.855469,0 z m 18.75,0 0,19.30078 2.271485,0 0,-7.72852 -0.232422,-0.23437 4.585937,0 c 2.54808,0 4.012966,0.91391 4.947266,2.88867 L 89.820312,50 92.367188,50 89.4375,43.96875 c -0.63702,-1.35898 -1.614284,-2.20763 -2.527344,-2.58984 l 0,-0.043 c 2.1234,-0.55208 3.865235,-2.42042 3.865235,-4.94727 0,-3.80089 -2.951713,-5.68945 -6.476563,-5.68945 l -8.451172,0 z m 18.876953,0 0,19.30078 2.273438,0 0,-19.30078 -2.273438,0 z m 13.419921,0 L 99.650391,50 l 2.484379,0 2.03906,-4.65039 -0.12695,-0.23438 10.57421,0 -0.12695,0.23438 2.03906,4.65039 2.48438,0 -8.47266,-19.30078 -2.40039,0 z m 13.33594,0 0,19.30078 2.27148,0 0,-7.72852 -0.23437,-0.23437 4.58789,0 c 2.54808,0 4.01296,0.91391 4.94726,2.88867 L 135.45117,50 138,50 135.07031,43.96875 c -0.63702,-1.35898 -1.61427,-2.20763 -2.52734,-2.58984 l 0,-0.043 c 2.12341,-0.55208 3.86523,-2.42042 3.86523,-4.94727 0,-3.80089 -2.95171,-5.68945 -6.47656,-5.68945 l -8.45117,0 z m -62.322267,2.14453 6.560547,0 c 2.46315,0 3.759766,0.9967 3.759766,3.03516 0,1.71996 -0.999336,3.10156 -3.759766,3.10156 l -6.560547,0 0.234375,-0.23438 0,-5.66992 -0.234375,-0.23242 z m 18.728516,0 6.433593,0 c 2.378211,0 4.14091,0.97535 4.16211,3.52344 0,2.03846 -1.634356,3.5039 -4.416016,3.5039 l -6.179687,0 0.232422,-0.23242 0,-6.5625 -0.232422,-0.23242 z m 45.652341,0 6.4336,0 c 2.35698,0 4.14062,0.97535 4.14062,3.52344 0,2.03846 -1.61288,3.5039 -4.39453,3.5039 l -6.17969,0 0.23438,-0.23242 0,-6.5625 -0.23438,-0.23242 z m -14.20508,0.21094 0.043,0 0.57227,1.93359 3.39844,7.75 0.23242,0.23242 -8.4707,0 0.23242,-0.23242 3.39843,-7.75 0.59375,-1.93359 z m -50.197261,8.07031 7.007812,0 c 2.84536,0 4.16211,1.3153 4.16211,3.375 0,2.14464 -1.189095,3.33398 -4.140625,3.33398 l -7.029297,0 0.234375,-0.23437 0,-6.24219 -0.234375,-0.23242 z"
|
||||||
id="path57"
|
id="path57"
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 8.7 KiB After Width: | Height: | Size: 5.5 KiB |
70
briar-android/artwork/navigation_drawer_header.svg
Normal file
70
briar-android/artwork/navigation_drawer_header.svg
Normal file
@@ -0,0 +1,70 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<!-- Generator: Adobe Illustrator 19.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||||
|
|
||||||
|
<svg
|
||||||
|
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||||
|
xmlns:cc="http://creativecommons.org/ns#"
|
||||||
|
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||||
|
xmlns:svg="http://www.w3.org/2000/svg"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||||
|
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||||
|
version="1.1"
|
||||||
|
id="Ebene_1"
|
||||||
|
x="0px"
|
||||||
|
y="0px"
|
||||||
|
xml:space="preserve"
|
||||||
|
inkscape:version="0.92.3 (2405546, 2018-03-11)"
|
||||||
|
sodipodi:docname="navigation_drawer_header.svg"
|
||||||
|
width="146"
|
||||||
|
height="50"><metadata
|
||||||
|
id="metadata71"><rdf:RDF><cc:Work
|
||||||
|
rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
|
||||||
|
rdf:resource="http://purl.org/dc/dcmitype/StillImage" /><dc:title></dc:title></cc:Work></rdf:RDF></metadata><defs
|
||||||
|
id="defs69" /><sodipodi:namedview
|
||||||
|
pagecolor="#000000"
|
||||||
|
bordercolor="#666666"
|
||||||
|
borderopacity="1"
|
||||||
|
objecttolerance="10"
|
||||||
|
gridtolerance="10"
|
||||||
|
guidetolerance="10"
|
||||||
|
inkscape:pageopacity="0"
|
||||||
|
inkscape:pageshadow="2"
|
||||||
|
inkscape:window-width="1920"
|
||||||
|
inkscape:window-height="1020"
|
||||||
|
id="namedview67"
|
||||||
|
showgrid="false"
|
||||||
|
fit-margin-top="0"
|
||||||
|
fit-margin-left="0"
|
||||||
|
fit-margin-right="0"
|
||||||
|
fit-margin-bottom="0"
|
||||||
|
inkscape:zoom="3.9883057"
|
||||||
|
inkscape:cx="55.084459"
|
||||||
|
inkscape:cy="13.664636"
|
||||||
|
inkscape:window-x="1442"
|
||||||
|
inkscape:window-y="24"
|
||||||
|
inkscape:window-maximized="0"
|
||||||
|
inkscape:current-layer="Ebene_1"
|
||||||
|
showguides="true"
|
||||||
|
inkscape:guide-bbox="true" /><style
|
||||||
|
type="text/css"
|
||||||
|
id="style3">
|
||||||
|
.st0{display:none;fill:#87C214;}
|
||||||
|
.st1{fill:#87C214;}
|
||||||
|
.st2{display:none;fill:#FFFFFF;}
|
||||||
|
.st3{fill:#95D220;}
|
||||||
|
.st4{display:none;fill:#95D220;}
|
||||||
|
.st5{fill:#FFFFFF;}
|
||||||
|
</style><path
|
||||||
|
style="fill:#ffffff;fill-opacity:1"
|
||||||
|
d="m 65.097656,30.699216 v 19.30078 h 9.06836 c 4.22557,0 6.474893,-2.12355 6.496093,-5.47852 0,-2.14464 -1.017672,-3.78004 -3.013671,-4.67187 v -0.041 c 1.507609,-0.9343 2.166015,-2.10331 2.166015,-3.9082 0,-2.73919 -1.848098,-5.20117 -5.861328,-5.20117 h -8.855469 z m 18.75,0 v 19.30078 h 2.271485 v -7.72852 l -0.232422,-0.23437 h 4.585937 c 2.54808,0 4.012966,0.91391 4.947266,2.88867 l 2.40039,5.07422 h 2.546878 l -2.92969,-6.03125 c -0.63702,-1.35898 -1.614284,-2.20763 -2.527344,-2.58984 v -0.043 c 2.1234,-0.55208 3.865235,-2.42042 3.865235,-4.94727 0,-3.80089 -2.951713,-5.68945 -6.476563,-5.68945 h -8.451172 z m 18.876954,0 v 19.30078 h 2.27344 v -19.30078 z m 13.41992,0 -8.49414,19.30078 h 2.48438 l 2.03906,-4.65039 -0.12695,-0.23438 h 10.57421 l -0.12695,0.23438 2.03906,4.65039 h 2.48438 l -8.47266,-19.30078 z m 13.33594,0 v 19.30078 h 2.27148 v -7.72852 l -0.23437,-0.23437 h 4.58789 c 2.54808,0 4.01296,0.91391 4.94726,2.88867 l 2.39844,5.07422 H 146 l -2.92969,-6.03125 c -0.63702,-1.35898 -1.61427,-2.20763 -2.52734,-2.58984 v -0.043 c 2.12341,-0.55208 3.86523,-2.42042 3.86523,-4.94727 0,-3.80089 -2.95171,-5.68945 -6.47656,-5.68945 h -8.45117 z m -62.322267,2.14453 h 6.560547 c 2.46315,0 3.759766,0.9967 3.759766,3.03516 0,1.71996 -0.999336,3.10156 -3.759766,3.10156 h -6.560547 l 0.234375,-0.23438 v -5.66992 z m 18.728516,0 h 6.433593 c 2.378211,0 4.14091,0.97535 4.16211,3.52344 0,2.03846 -1.634356,3.5039 -4.416016,3.5039 h -6.179687 l 0.232422,-0.23242 v -6.5625 z m 45.652341,0 h 6.4336 c 2.35698,0 4.14062,0.97535 4.14062,3.52344 0,2.03846 -1.61288,3.5039 -4.39453,3.5039 h -6.17969 l 0.23438,-0.23242 v -6.5625 z m -14.20508,0.21094 h 0.043 l 0.57227,1.93359 3.39844,7.75 0.23242,0.23242 h -8.4707 l 0.23242,-0.23242 3.39843,-7.75 0.59375,-1.93359 z m -50.197261,8.07031 h 7.007812 c 2.84536,0 4.16211,1.3153 4.16211,3.375 0,2.14464 -1.189095,3.33398 -4.140625,3.33398 h -7.029297 l 0.234375,-0.23437 v -6.24219 z"
|
||||||
|
id="path57"
|
||||||
|
inkscape:connector-curvature="0" /><path
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
style="fill:#87c214;stroke-width:0.21276595"
|
||||||
|
d="m 13.808594,0 c -2.06383,0 -3.766207,1.7019614 -3.766207,3.7657911 V 8.553025 h 9.276928 V 3.7657911 C 19.319315,1.7019614 17.638132,0 15.574302,0 Z m 20.638297,0 c -2.06383,0 -3.766206,1.7019614 -3.766206,3.7657911 V 29.191323 h 9.276927 V 3.7657911 C 39.957612,1.7019614 38.276429,0 36.212599,0 Z M 10.042387,20.808676 v 25.425531 c 0,2.06383 1.681101,3.765791 3.766207,3.765791 h 1.765708 c 2.06383,0 3.766207,-1.701961 3.766207,-3.765791 V 20.808676 Z m 20.638298,20.638297 v 4.787234 c 0,2.06383 1.702376,3.765791 3.766206,3.765791 h 1.765708 c 2.06383,0 3.766206,-1.701961 3.766206,-3.765791 v -4.787234 z"
|
||||||
|
id="path13-3" /><path
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
style="fill:#95d220;stroke-width:0.21276595"
|
||||||
|
d="M 3.7657914,10.042387 C 1.7019617,10.042387 0,11.723487 0,13.808594 v 1.765708 c 0,2.063829 1.6806851,3.766206 3.7657914,3.766206 H 29.191323 v -9.298121 z m 37.6811826,0 v 9.298121 h 4.787233 c 2.06383,0 3.765792,-1.6811 3.765792,-3.766206 v -1.765708 c 0,-2.085107 -1.701962,-3.766207 -3.765792,-3.766207 z M 3.7657914,30.680684 C 1.7019617,30.680684 0,32.361784 0,34.44689 v 1.765709 c 0,2.06383 1.6806851,3.766206 3.7657914,3.766206 h 4.7872339 v -9.298121 z m 17.0428856,0 v 9.298121 h 25.42553 c 2.06383,0 3.765792,-1.702376 3.765792,-3.766206 V 34.44689 c 0,-2.085106 -1.701962,-3.766206 -3.765792,-3.766206 z"
|
||||||
|
id="path35" /></svg>
|
||||||
|
After Width: | Height: | Size: 5.3 KiB |
70
briar-android/artwork/navigation_drawer_header_night.svg
Normal file
70
briar-android/artwork/navigation_drawer_header_night.svg
Normal file
@@ -0,0 +1,70 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<!-- Generator: Adobe Illustrator 19.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||||
|
|
||||||
|
<svg
|
||||||
|
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||||
|
xmlns:cc="http://creativecommons.org/ns#"
|
||||||
|
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||||
|
xmlns:svg="http://www.w3.org/2000/svg"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||||
|
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||||
|
version="1.1"
|
||||||
|
id="Ebene_1"
|
||||||
|
x="0px"
|
||||||
|
y="0px"
|
||||||
|
xml:space="preserve"
|
||||||
|
inkscape:version="0.92.3 (2405546, 2018-03-11)"
|
||||||
|
sodipodi:docname="navigation_drawer_header_night.svg"
|
||||||
|
width="146"
|
||||||
|
height="50"><metadata
|
||||||
|
id="metadata71"><rdf:RDF><cc:Work
|
||||||
|
rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
|
||||||
|
rdf:resource="http://purl.org/dc/dcmitype/StillImage" /><dc:title></dc:title></cc:Work></rdf:RDF></metadata><defs
|
||||||
|
id="defs69" /><sodipodi:namedview
|
||||||
|
pagecolor="#000000"
|
||||||
|
bordercolor="#666666"
|
||||||
|
borderopacity="1"
|
||||||
|
objecttolerance="10"
|
||||||
|
gridtolerance="10"
|
||||||
|
guidetolerance="10"
|
||||||
|
inkscape:pageopacity="0"
|
||||||
|
inkscape:pageshadow="2"
|
||||||
|
inkscape:window-width="1920"
|
||||||
|
inkscape:window-height="1020"
|
||||||
|
id="namedview67"
|
||||||
|
showgrid="false"
|
||||||
|
fit-margin-top="0"
|
||||||
|
fit-margin-left="0"
|
||||||
|
fit-margin-right="0"
|
||||||
|
fit-margin-bottom="0"
|
||||||
|
inkscape:zoom="3.9883057"
|
||||||
|
inkscape:cx="110.49646"
|
||||||
|
inkscape:cy="13.664636"
|
||||||
|
inkscape:window-x="1442"
|
||||||
|
inkscape:window-y="24"
|
||||||
|
inkscape:window-maximized="0"
|
||||||
|
inkscape:current-layer="Ebene_1"
|
||||||
|
showguides="true"
|
||||||
|
inkscape:guide-bbox="true" /><style
|
||||||
|
type="text/css"
|
||||||
|
id="style3">
|
||||||
|
.st0{display:none;fill:#87C214;}
|
||||||
|
.st1{fill:#87C214;}
|
||||||
|
.st2{display:none;fill:#FFFFFF;}
|
||||||
|
.st3{fill:#95D220;}
|
||||||
|
.st4{display:none;fill:#95D220;}
|
||||||
|
.st5{fill:#FFFFFF;}
|
||||||
|
</style><path
|
||||||
|
style="fill:#95d220;fill-opacity:1"
|
||||||
|
d="m 65.097656,15.349623 v 19.30078 h 9.06836 c 4.22557,0 6.474893,-2.12355 6.496093,-5.47852 0,-2.14464 -1.017672,-3.78004 -3.013671,-4.67187 v -0.041 c 1.507609,-0.9343 2.166015,-2.10331 2.166015,-3.9082 0,-2.73919 -1.848098,-5.20117 -5.861328,-5.20117 h -8.855469 z m 18.75,0 v 19.30078 h 2.271485 v -7.72852 l -0.232422,-0.23437 h 4.585937 c 2.54808,0 4.012966,0.91391 4.947266,2.88867 l 2.40039,5.07422 h 2.546878 l -2.92969,-6.03125 c -0.63702,-1.35898 -1.614284,-2.20763 -2.527344,-2.58984 v -0.043 c 2.1234,-0.55208 3.865235,-2.42042 3.865235,-4.94727 0,-3.80089 -2.951713,-5.68945 -6.476563,-5.68945 h -8.451172 z m 18.876954,0 v 19.30078 h 2.27344 v -19.30078 z m 13.41992,0 -8.49414,19.30078 h 2.48438 l 2.03906,-4.65039 -0.12695,-0.23438 h 10.57421 l -0.12695,0.23438 2.03906,4.65039 h 2.48438 l -8.47266,-19.30078 z m 13.33594,0 v 19.30078 h 2.27148 v -7.72852 l -0.23437,-0.23437 h 4.58789 c 2.54808,0 4.01296,0.91391 4.94726,2.88867 l 2.39844,5.07422 H 146 l -2.92969,-6.03125 c -0.63702,-1.35898 -1.61427,-2.20763 -2.52734,-2.58984 v -0.043 c 2.12341,-0.55208 3.86523,-2.42042 3.86523,-4.94727 0,-3.80089 -2.95171,-5.68945 -6.47656,-5.68945 h -8.45117 z m -62.322267,2.14453 h 6.560547 c 2.46315,0 3.759766,0.9967 3.759766,3.03516 0,1.71996 -0.999336,3.10156 -3.759766,3.10156 h -6.560547 l 0.234375,-0.23438 v -5.66992 z m 18.728516,0 h 6.433593 c 2.378211,0 4.14091,0.97535 4.16211,3.52344 0,2.03846 -1.634356,3.5039 -4.416016,3.5039 h -6.179687 l 0.232422,-0.23242 v -6.5625 z m 45.652341,0 h 6.4336 c 2.35698,0 4.14062,0.97535 4.14062,3.52344 0,2.03846 -1.61288,3.5039 -4.39453,3.5039 h -6.17969 l 0.23438,-0.23242 v -6.5625 z m -14.20508,0.21094 h 0.043 l 0.57227,1.93359 3.39844,7.75 0.23242,0.23242 h -8.4707 l 0.23242,-0.23242 3.39843,-7.75 0.59375,-1.93359 z m -50.197261,8.07031 h 7.007812 c 2.84536,0 4.16211,1.3153 4.16211,3.375 0,2.14464 -1.189095,3.33398 -4.140625,3.33398 h -7.029297 l 0.234375,-0.23437 v -6.24219 z"
|
||||||
|
id="path57"
|
||||||
|
inkscape:connector-curvature="0" /><path
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
style="fill:#87c214;stroke-width:0.21276595"
|
||||||
|
d="m 13.808594,0 c -2.06383,0 -3.766207,1.7019614 -3.766207,3.7657911 V 8.553025 h 9.276928 V 3.7657911 C 19.319315,1.7019614 17.638132,0 15.574302,0 Z m 20.638297,0 c -2.06383,0 -3.766206,1.7019614 -3.766206,3.7657911 V 29.191323 h 9.276927 V 3.7657911 C 39.957612,1.7019614 38.276429,0 36.212599,0 Z M 10.042387,20.808676 v 25.425531 c 0,2.06383 1.681101,3.765791 3.766207,3.765791 h 1.765708 c 2.06383,0 3.766207,-1.701961 3.766207,-3.765791 V 20.808676 Z m 20.638298,20.638297 v 4.787234 c 0,2.06383 1.702376,3.765791 3.766206,3.765791 h 1.765708 c 2.06383,0 3.766206,-1.701961 3.766206,-3.765791 v -4.787234 z"
|
||||||
|
id="path13-3" /><path
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
style="fill:#95d220;stroke-width:0.21276595"
|
||||||
|
d="M 3.7657914,10.042387 C 1.7019617,10.042387 0,11.723487 0,13.808594 v 1.765708 c 0,2.063829 1.6806851,3.766206 3.7657914,3.766206 H 29.191323 v -9.298121 z m 37.6811826,0 v 9.298121 h 4.787233 c 2.06383,0 3.765792,-1.6811 3.765792,-3.766206 v -1.765708 c 0,-2.085107 -1.701962,-3.766207 -3.765792,-3.766207 z M 3.7657914,30.680684 C 1.7019617,30.680684 0,32.361784 0,34.44689 v 1.765709 c 0,2.06383 1.6806851,3.766206 3.7657914,3.766206 h 4.7872339 v -9.298121 z m 17.0428856,0 v 9.298121 h 25.42553 c 2.06383,0 3.765792,-1.702376 3.765792,-3.766206 V 34.44689 c 0,-2.085106 -1.701962,-3.766206 -3.765792,-3.766206 z"
|
||||||
|
id="path35" /></svg>
|
||||||
|
After Width: | Height: | Size: 5.3 KiB |
@@ -1,57 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
|
||||||
<!-- Generator: Adobe Illustrator 19.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
|
||||||
|
|
||||||
<svg
|
|
||||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
|
||||||
xmlns:cc="http://creativecommons.org/ns#"
|
|
||||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
|
||||||
xmlns:svg="http://www.w3.org/2000/svg"
|
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
|
||||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
|
||||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
|
||||||
version="1.1"
|
|
||||||
id="Ebene_1"
|
|
||||||
x="0px"
|
|
||||||
y="0px"
|
|
||||||
viewBox="0 0 24 24"
|
|
||||||
xml:space="preserve"
|
|
||||||
inkscape:version="0.92.3 (2405546, 2018-03-11)"
|
|
||||||
sodipodi:docname="notification_reminder.svg"
|
|
||||||
width="24"
|
|
||||||
height="24"><metadata
|
|
||||||
id="metadata61"><rdf:RDF><cc:Work
|
|
||||||
rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
|
|
||||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" /><dc:title /></cc:Work></rdf:RDF></metadata><defs
|
|
||||||
id="defs59" /><sodipodi:namedview
|
|
||||||
pagecolor="#000000"
|
|
||||||
bordercolor="#666666"
|
|
||||||
borderopacity="1"
|
|
||||||
objecttolerance="10"
|
|
||||||
gridtolerance="10"
|
|
||||||
guidetolerance="10"
|
|
||||||
inkscape:pageopacity="0"
|
|
||||||
inkscape:pageshadow="2"
|
|
||||||
inkscape:window-width="1920"
|
|
||||||
inkscape:window-height="1020"
|
|
||||||
id="namedview57"
|
|
||||||
showgrid="false"
|
|
||||||
inkscape:zoom="32.43286"
|
|
||||||
inkscape:cx="6.4172501"
|
|
||||||
inkscape:cy="12.231457"
|
|
||||||
inkscape:window-x="1442"
|
|
||||||
inkscape:window-y="24"
|
|
||||||
inkscape:window-maximized="0"
|
|
||||||
inkscape:current-layer="Ebene_1"
|
|
||||||
units="px" /><style
|
|
||||||
type="text/css"
|
|
||||||
id="style3">
|
|
||||||
.st0{fill:#FFFFFF;}
|
|
||||||
.st1{display:none;fill:#87C214;}
|
|
||||||
.st2{fill:#87C214;}
|
|
||||||
.st3{display:none;fill:#FFFFFF;}
|
|
||||||
.st4{fill:#95D220;}
|
|
||||||
.st5{display:none;fill:#95D220;}
|
|
||||||
</style><path
|
|
||||||
style="display:inline;fill:#ffffff;stroke-width:0.07272727"
|
|
||||||
d="M 12 0 A 12 12 0 0 0 4.875 2.3613281 L 6.9316406 4.4160156 C 7.0875805 3.8805807 7.5639651 3.4765625 8.1464844 3.4765625 L 8.7480469 3.4765625 C 9.4535014 3.4765625 10.035156 4.0582174 10.035156 4.7636719 L 10.035156 6.4003906 L 8.9140625 6.4003906 L 9.4238281 6.9101562 L 13.404297 6.9101562 L 13.404297 10.085938 L 12.601562 10.085938 L 13.914062 11.398438 L 13.914062 4.7636719 C 13.914062 4.0582174 14.495717 3.4765625 15.201172 3.4765625 L 15.802734 3.4765625 C 16.515461 3.4765625 17.089844 4.0582174 17.089844 4.7636719 L 17.089844 13.455078 L 15.96875 13.455078 L 16.478516 13.964844 L 19.236328 13.964844 C 19.941782 13.964844 20.516165 14.546498 20.523438 15.251953 L 20.523438 15.853516 C 20.523438 16.436036 20.119418 16.91242 19.583984 17.068359 L 21.638672 19.125 A 12 12 0 0 0 24 12 A 12 12 0 0 0 12 0 z M 1.2617188 1.3632812 L 0 2.6269531 L 2.3125 4.9472656 A 12 12 0 0 0 0 12 A 12 12 0 0 0 12 24 A 12 12 0 0 0 19.027344 21.707031 L 21.314453 24 L 22.576172 22.734375 L 2.7519531 2.8554688 L 1.9863281 2.0898438 L 1.2617188 1.3632812 z M 17.599609 6.9101562 L 19.236328 6.9101562 C 19.941782 6.9101562 20.516165 7.4918111 20.523438 8.1972656 L 20.523438 8.7988281 C 20.523438 9.511555 19.941782 10.085937 19.236328 10.085938 L 17.599609 10.085938 L 17.599609 6.9101562 z M 4.359375 6.9980469 L 7.4394531 10.085938 L 4.7128906 10.085938 C 4.0001632 10.085938 3.4257813 9.504282 3.4257812 8.7988281 L 3.4257812 8.1972656 C 3.4257812 7.6133228 3.8294199 7.1540656 4.359375 6.9980469 z M 6.859375 10.595703 L 7.9472656 10.595703 L 10.035156 12.689453 L 10.035156 19.287109 C 10.035156 19.992562 9.4535014 20.574219 8.7480469 20.574219 L 8.1464844 20.574219 C 7.4337573 20.574219 6.859375 19.992563 6.859375 19.287109 L 6.859375 10.595703 z M 4.7128906 13.964844 L 6.3496094 13.964844 L 6.3496094 17.140625 L 4.7128906 17.140625 C 4.0001632 17.140625 3.4257813 16.558971 3.4257812 15.853516 L 3.4257812 15.251953 C 3.4257812 14.539226 4.007436 13.964844 4.7128906 13.964844 z M 10.544922 13.964844 L 11.306641 13.964844 L 14.474609 17.140625 L 10.544922 17.140625 L 10.544922 13.964844 z M 13.914062 17.650391 L 14.982422 17.650391 L 16.992188 19.666016 C 16.827053 20.182975 16.371277 20.574219 15.802734 20.574219 L 15.201172 20.574219 C 14.495717 20.574219 13.914063 19.992563 13.914062 19.287109 L 13.914062 17.650391 z "
|
|
||||||
id="circle7" /></svg>
|
|
||||||
|
Before Width: | Height: | Size: 4.1 KiB |
@@ -1,5 +1,6 @@
|
|||||||
apply plugin: 'com.android.application'
|
apply plugin: 'com.android.application'
|
||||||
apply plugin: 'witness'
|
apply plugin: 'witness'
|
||||||
|
apply from: 'witness.gradle'
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
implementation project(path: ':briar-core', configuration: 'default')
|
implementation project(path: ':briar-core', configuration: 'default')
|
||||||
@@ -40,182 +41,25 @@ dependencies {
|
|||||||
|
|
||||||
testImplementation project(path: ':bramble-api', configuration: 'testOutput')
|
testImplementation project(path: ':bramble-api', configuration: 'testOutput')
|
||||||
testImplementation project(path: ':bramble-core', configuration: 'testOutput')
|
testImplementation project(path: ':bramble-core', configuration: 'testOutput')
|
||||||
testImplementation 'org.robolectric:robolectric:3.5.1'
|
testImplementation 'org.robolectric:robolectric:3.8'
|
||||||
testImplementation 'org.robolectric:shadows-support-v4:3.0'
|
testImplementation 'org.robolectric:shadows-support-v4:3.3.2'
|
||||||
testImplementation 'org.mockito:mockito-core:2.8.9'
|
testImplementation 'org.mockito:mockito-core:2.13.0'
|
||||||
testImplementation 'junit:junit:4.12'
|
testImplementation 'junit:junit:4.12'
|
||||||
testImplementation "org.jmock:jmock:2.8.2"
|
testImplementation "org.jmock:jmock:2.8.2"
|
||||||
testImplementation "org.jmock:jmock-junit4:2.8.2"
|
testImplementation "org.jmock:jmock-junit4:2.8.2"
|
||||||
testImplementation "org.jmock:jmock-legacy:2.8.2"
|
testImplementation "org.jmock:jmock-legacy:2.8.2"
|
||||||
testImplementation "org.hamcrest:hamcrest-library:1.3"
|
testImplementation "org.hamcrest:hamcrest-library:1.3"
|
||||||
testImplementation "org.hamcrest:hamcrest-core:1.3"
|
testImplementation "org.hamcrest:hamcrest-core:1.3"
|
||||||
}
|
|
||||||
|
|
||||||
dependencyVerification {
|
def espressoVersion = '3.0.2'
|
||||||
verify = [
|
androidTestImplementation "com.android.support.test.espresso:espresso-core:$espressoVersion"
|
||||||
'android.arch.core:common:1.1.0:common-1.1.0.jar:d34824b794bc92ff8f647a9bb13a7c73de920de5b47075b5d2c4f0770e9b8bfd',
|
androidTestImplementation "com.android.support.test.espresso:espresso-contrib:$espressoVersion"
|
||||||
'android.arch.core:runtime:1.1.0:runtime-1.1.0.aar:83400f7575bcfb8a2eeec64e05590f037bfaed1e56aa3a4214d20e55878445e3',
|
androidTestImplementation "com.android.support.test.espresso:espresso-intents:$espressoVersion"
|
||||||
'android.arch.lifecycle:common:1.1.0:common-1.1.0.jar:614e31cfd33255dc4d5f5d8e62cfa6be2fbbc2a35643a79dc3ed008004c30807',
|
androidTestImplementation "tools.fastlane:screengrab:1.1.0"
|
||||||
'android.arch.lifecycle:livedata-core:1.1.0:livedata-core-1.1.0.aar:14e57ff8ffb65a80c7e72d91f2076acccdaf2970f234c6261e03a6127eb5206b',
|
androidTestImplementation "com.android.support.test.uiautomator:uiautomator-v18:2.1.3"
|
||||||
'android.arch.lifecycle:runtime:1.1.0:runtime-1.1.0.aar:094fd793924dd6a5136753e599ac8174a8147f4a401386b694ba7d818c223e2e',
|
androidTestAnnotationProcessor "com.google.dagger:dagger-compiler:2.0.2"
|
||||||
'android.arch.lifecycle:viewmodel:1.1.0:viewmodel-1.1.0.aar:6407c93a5ea9850661dca42a0068d6f3deccefd7228ee69bae1c35d70cbc2557',
|
androidTestCompileOnly 'javax.annotation:jsr250-api:1.0'
|
||||||
'backport-util-concurrent:backport-util-concurrent:3.1:backport-util-concurrent-3.1.jar:f5759b7fcdfc83a525a036deedcbd32e5b536b625ebc282426f16ca137eb5902',
|
androidTestImplementation 'junit:junit:4.12'
|
||||||
'cglib:cglib:3.2.0:cglib-3.2.0.jar:adb13bab79712ad6bdf1bd59f2a3918018a8016e722e8a357065afb9e6690861',
|
|
||||||
'ch.acra:acra:4.9.1:acra-4.9.1.aar:d2762968c448757a7d6acc9f141881d9632f664988e9723ece33b5f7c79f3bc9',
|
|
||||||
'classworlds:classworlds:1.1-alpha-2:classworlds-1.1-alpha-2.jar:2bf4e59f3acd106fea6145a9a88fe8956509f8b9c0fdd11eb96fee757269e3f3',
|
|
||||||
'com.almworks.sqlite4java:sqlite4java:0.282:sqlite4java-0.282.jar:9e1d8dd83ca6003f841e3af878ce2dc7c22497493a7bb6d1b62ec1b0d0a83c05',
|
|
||||||
'com.android.support.constraint:constraint-layout-solver:1.1.0:constraint-layout-solver-1.1.0.jar:fcb4c7d705754ca3d69b1b2c3caf445a425599fda8caabbcf855d98ea0663e4e',
|
|
||||||
'com.android.support.constraint:constraint-layout:1.1.0:constraint-layout-1.1.0.aar:d490188709b7bb2f11609beadd7e5eb7538892f308828ec3ff261a74e6ecf47e',
|
|
||||||
'com.android.support:animated-vector-drawable:27.1.1:animated-vector-drawable-27.1.1.aar:59670473f6e98fda792f7bef25dd7292b0a3106031c7a5e30eb020bf26f077bd',
|
|
||||||
'com.android.support:appcompat-v7:27.1.1:appcompat-v7-27.1.1.aar:0c7808fbbc5838d831e32e3c0a6f84e1f2c981deb8f11e010650f2b57923a335',
|
|
||||||
'com.android.support:cardview-v7:27.1.1:cardview-v7-27.1.1.aar:8ed955dd037d82a7b4bbcaedb4f896523c3e4c1bf3ca698ce807c350767a2886',
|
|
||||||
'com.android.support:design:27.1.1:design-27.1.1.aar:7225973f7ee03765008a9c2f17a40b154c6885169fef022276e811c926a2202c',
|
|
||||||
'com.android.support:preference-v14:27.1.1:preference-v14-27.1.1.aar:dc058932e6fd93bf57d23fcc2f22351c21e5125e513721e4b0b03374341ad400',
|
|
||||||
'com.android.support:preference-v7:27.1.1:preference-v7-27.1.1.aar:a1798a826b4097d00e49280f412b21af08f9bf1179c2e3838dc339d9f843416d',
|
|
||||||
'com.android.support:recyclerview-v7:27.1.1:recyclerview-v7-27.1.1.aar:d735e4727878e99ef3980c10d15dc3468462fd509d4fb60cb8bd20b0f735085c',
|
|
||||||
'com.android.support:support-annotations:27.1.1:support-annotations-27.1.1.jar:3365960206c3d2b09e845f555e7f88f8effc8d2f00b369e66c4be384029299cf',
|
|
||||||
'com.android.support:support-compat:27.1.1:support-compat-27.1.1.aar:880ce01ff5be42b233ff8ec0c61cefb7dc3dc9500fea9e24423214813ac27ea2',
|
|
||||||
'com.android.support:support-core-ui:27.1.1:support-core-ui-27.1.1.aar:a3ae20e6d5dffba69ac97b99846d2738003af8563843d5f3c9dc4c35b4804241',
|
|
||||||
'com.android.support:support-core-utils:27.1.1:support-core-utils-27.1.1.aar:61036832c54e8701aae954fc3bf96d1d80bf8d9dd531bff77d72def456ba087a',
|
|
||||||
'com.android.support:support-fragment:27.1.1:support-fragment-27.1.1.aar:ec72d6ac36a1a0e6523bbddba33d73ffad070b9b3dd246cc44d8727a41ddb5e6',
|
|
||||||
'com.android.support:support-media-compat:27.1.1:support-media-compat-27.1.1.aar:55e9837dda88b74a8c812c63a78c63fd83c6c039a8c22d318492663a493585eb',
|
|
||||||
'com.android.support:support-v4:27.1.1:support-v4-27.1.1.aar:4f41dfc3e89f2738e45c86264a85c0934d055ee8ebe2020e23c97f303b80a48b',
|
|
||||||
'com.android.support:support-vector-drawable:27.1.1:support-vector-drawable-27.1.1.aar:1c0f421114cf4627cf208776d6eb4f76340c78b7e96fe6e12b3e6eb950caf1b9',
|
|
||||||
'com.android.support:transition:27.1.1:transition-27.1.1.aar:c0765b2f3c78696567ec5b3f519d22da1e3df11ac994625adf4bb4dc571caacc',
|
|
||||||
'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.github.bumptech.glide:glide:3.8.0:glide-3.8.0.jar:750d9e7b940dc0ee48f8680623b55d46e14e8727acc922d7b156e57e7c549655',
|
|
||||||
'com.google.android.apps.common.testing.accessibility.framework:accessibility-test-framework:2.1:accessibility-test-framework-2.1.jar:7b0aa6ed7553597ce0610684a9f7eca8021eee218f2e2f427c04a7fbf5f920bd',
|
|
||||||
'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.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:20.0:guava-20.0.jar:36a666e3b71ae7f0f0dca23654b67e086e6c93d192f60ba5dfd5519db6c288c8',
|
|
||||||
'com.google.guava:guava:22.0:guava-22.0.jar:1158e94c7de4da480873f0b4ab4a1da14c0d23d4b1902cc94a58a6f0f9ab579e',
|
|
||||||
'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:2.6.1:protobuf-java-2.6.1.jar:55aa554843983f431df5616112cf688d38aa17c132357afd1c109435bfdac4e6',
|
|
||||||
'com.google.protobuf:protobuf-java:3.4.0:protobuf-java-3.4.0.jar:dce7e66b32456a1b1198da0caff3a8acb71548658391e798c79369241e6490a4',
|
|
||||||
'com.google.zxing:core:3.3.0:core-3.3.0.jar:bba7724e02a997cec38213af77133ee8e24b0d5cf5fa7ecbc16a4fa93f11ee0d',
|
|
||||||
'com.googlecode.json-simple:json-simple:1.1:json-simple-1.1.jar:2d9484f4c649f708f47f9a479465fc729770ee65617dca3011836602264f6439',
|
|
||||||
'com.ibm.icu:icu4j:53.1:icu4j-53.1.jar:e37a4467bac5cdeb02c5c4b8e5063d2f4e67b69e3c7df6d6b610f13185572bab',
|
|
||||||
'com.jpardogo.materialtabstrip:library:1.1.0:library-1.1.0.aar:24d19232b319f8c73e25793432357919a7ed972186f57a3b2c9093ea74ad8311',
|
|
||||||
'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',
|
|
||||||
'com.thoughtworks.xstream:xstream:1.4.8:xstream-1.4.8.jar:a219a1abf948400b669d08be73a6f9209fb720d237e5ff74c223bffe5f9df93d',
|
|
||||||
'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',
|
|
||||||
'de.hdodenhof:circleimageview:2.2.0:circleimageview-2.2.0.aar:bc34761dcd5036229ac1ffed6b5b1bef722ad5b097a2c8bba1c5ed2cd4b5c82b',
|
|
||||||
'info.guardianproject.panic:panic:0.5:panic-0.5.jar:a7ed9439826db2e9901649892cf9afbe76f00991b768d8f4c26332d7c9406cb2',
|
|
||||||
'info.guardianproject.trustedintents:trustedintents:0.2:trustedintents-0.2.jar:6221456d8821a8d974c2acf86306900237cf6afaaa94a4c9c44e161350f80f3e',
|
|
||||||
'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',
|
|
||||||
'javax.xml.bind:jaxb-api:2.2.12-b140109.1041:jaxb-api-2.2.12-b140109.1041.jar:b5e60cd8b7b5ff01ce4a74c5dd008f4fbd14ced3495d0b47b85cfedc182211f2',
|
|
||||||
'junit:junit:4.12:junit-4.12.jar:59721f0805e223d84b90677887d9ff567dc534d7c502ca903c0c2b17f05c116a',
|
|
||||||
'nekohtml:nekohtml:1.9.6.2:nekohtml-1.9.6.2.jar:fdff6cfa9ed9cc911c842a5d2395f209ec621ef1239d46810e9e495809d3ae09',
|
|
||||||
'nekohtml:xercesMinimal:1.9.6.2:xercesMinimal-1.9.6.2.jar:95b8b357d19f63797dd7d67622fd3f18374d64acbc6584faba1c7759a31e8438',
|
|
||||||
'net.bytebuddy:byte-buddy-agent:1.6.14:byte-buddy-agent-1.6.14.jar:c141a2d6809c3eeff4a43d25992826abccebdd4b793af3e7a5f346e88ae73a33',
|
|
||||||
'net.bytebuddy:byte-buddy:1.6.14:byte-buddy-1.6.14.jar:917758b3c651e278a15a029ba1d42dbf802d8b0e1fe2aa4b81c5750c64f461c1',
|
|
||||||
'net.sf.jopt-simple:jopt-simple:4.9:jopt-simple-4.9.jar:26c5856e954b5f864db76f13b86919b59c6eecf9fd930b96baa8884626baf2f5',
|
|
||||||
'net.sf.kxml:kxml2:2.3.0:kxml2-2.3.0.jar:f264dd9f79a1fde10ce5ecc53221eff24be4c9331c830b7d52f2f08a7b633de2',
|
|
||||||
'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.maven.wagon:wagon-file:1.0-beta-6:wagon-file-1.0-beta-6.jar:7298feeb36ff14dd933c38e62585fb9973fea32fb3c4bc5379428cb1aac5dd3c',
|
|
||||||
'org.apache.maven.wagon:wagon-http-lightweight:1.0-beta-6:wagon-http-lightweight-1.0-beta-6.jar:be214032de23c6b520b79c1ccdb160948e0c67ed7c11984b7ec4ca5537867b4e',
|
|
||||||
'org.apache.maven.wagon:wagon-http-shared:1.0-beta-6:wagon-http-shared-1.0-beta-6.jar:f095c882716d49269a806685dcb256fa6a36389b2713ac56bb758bf8693565a2',
|
|
||||||
'org.apache.maven.wagon:wagon-provider-api:1.0-beta-6:wagon-provider-api-1.0-beta-6.jar:e116f32edcb77067289a3148143f2c0c97b27cf9a1342f8108ee37dec4868861',
|
|
||||||
'org.apache.maven:maven-ant-tasks:2.1.3:maven-ant-tasks-2.1.3.jar:f16b5ea711dfe0323454b880180aa832420ec039936e4aa75fb978748634808a',
|
|
||||||
'org.apache.maven:maven-artifact-manager:2.2.1:maven-artifact-manager-2.2.1.jar:d1e247c4ed3952385fd704ac9db2a222247cfe7d20508b4f3c76b90f857952ed',
|
|
||||||
'org.apache.maven:maven-artifact:2.2.1:maven-artifact-2.2.1.jar:d53062ffe8677a4f5e1ad3a1d1fa37ed600fab39166d39be7ed204635c5f839b',
|
|
||||||
'org.apache.maven:maven-error-diagnostics:2.2.1:maven-error-diagnostics-2.2.1.jar:b3005544708f8583e455c22b09a4940596a057108bccdadb9db4d8e048091fed',
|
|
||||||
'org.apache.maven:maven-model:2.2.1:maven-model-2.2.1.jar:153b32f474fd676ec36ad807c508885005139140fc92168bb76bf6be31f8efb8',
|
|
||||||
'org.apache.maven:maven-plugin-registry:2.2.1:maven-plugin-registry-2.2.1.jar:4ad0673155d7e0e5cf6d13689802d8d507f38e5ea00a6d2fb92aef206108213d',
|
|
||||||
'org.apache.maven:maven-profile:2.2.1:maven-profile-2.2.1.jar:ecaffef655fea6b138f0855a12f7dbb59fc0d6bffb5c1bfd31803cccb49ea08c',
|
|
||||||
'org.apache.maven:maven-project:2.2.1:maven-project-2.2.1.jar:24ddb65b7a6c3befb6267ce5f739f237c84eba99389265c30df67c3dd8396a40',
|
|
||||||
'org.apache.maven:maven-repository-metadata:2.2.1:maven-repository-metadata-2.2.1.jar:5fe283f47b0e7f7d95a4252af3fa7a0db4d8f080cd9df308608c0472b8f168a1',
|
|
||||||
'org.apache.maven:maven-settings:2.2.1:maven-settings-2.2.1.jar:9a9f556713a404e770c9dbdaed7eb086078014c989291960c76fdde6db4192f7',
|
|
||||||
'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.52:bcprov-jdk15on-1.52.jar:0dc4d181e4d347893c2ddbd2e6cd5d7287fc651c03648fa64b2341c7366b1773',
|
|
||||||
'org.bouncycastle:bcprov-jdk15on:1.56:bcprov-jdk15on-1.56.jar:963e1ee14f808ffb99897d848ddcdb28fa91ddda867eb18d303e82728f878349',
|
|
||||||
'org.codehaus.groovy:groovy-all:2.4.12:groovy-all-2.4.12.jar:6a56af4bd48903d56bec62821876cadefafd007360cc6bd0d8f7aa8d72b38be4',
|
|
||||||
'org.codehaus.mojo:animal-sniffer-annotations:1.14:animal-sniffer-annotations-1.14.jar:2068320bd6bad744c3673ab048f67e30bef8f518996fa380033556600669905d',
|
|
||||||
'org.codehaus.plexus:plexus-container-default:1.0-alpha-9-stable-1:plexus-container-default-1.0-alpha-9-stable-1.jar:7c758612888782ccfe376823aee7cdcc7e0cdafb097f7ef50295a0b0c3a16edf',
|
|
||||||
'org.codehaus.plexus:plexus-interpolation:1.11:plexus-interpolation-1.11.jar:fd9507feb858fa620d1b4aa4b7039fdea1a77e09d3fd28cfbddfff468d9d8c28',
|
|
||||||
'org.codehaus.plexus:plexus-utils:1.5.15:plexus-utils-1.5.15.jar:2ca121831e597b4d8f2cb22d17c5c041fc23a7777ceb6bfbdd4dfb34bbe7d997',
|
|
||||||
'org.glassfish.jaxb:jaxb-core:2.2.11:jaxb-core-2.2.11.jar:37bcaee8ebb04362c8352a5bf6221b86967ecdab5164c696b10b9a2bb587b2aa',
|
|
||||||
'org.glassfish.jaxb:jaxb-runtime:2.2.11:jaxb-runtime-2.2.11.jar:a874f2351cfba8e2946be3002d10c18a6da8f21b52ba2acf52f2b85d5520ed70',
|
|
||||||
'org.glassfish.jaxb:txw2:2.2.11:txw2-2.2.11.jar:272a3ccad45a4511351920cd2a8633c53cab8d5220c7a92954da5526bb5eafea',
|
|
||||||
'org.hamcrest:hamcrest-core:1.3:hamcrest-core-1.3.jar:66fdef91e9739348df7a096aa384a5685f4e875584cce89386a7a47251c4d8e9',
|
|
||||||
'org.hamcrest:hamcrest-library:1.3:hamcrest-library-1.3.jar:711d64522f9ec410983bd310934296da134be4254a125080a0416ec178dfad1c',
|
|
||||||
'org.jetbrains.kotlin:kotlin-reflect:1.2.0:kotlin-reflect-1.2.0.jar:4f48a872bad6e4d9c053f4ad610d11e4012ad7e58dc19a03dd5eb811f36069dd',
|
|
||||||
'org.jetbrains.kotlin:kotlin-stdlib-jre7:1.2.0:kotlin-stdlib-jre7-1.2.0.jar:c7a20fb951d437797afe8980aff6c1e5a03f310c661ba58ba1d4fa90cb0f2926',
|
|
||||||
'org.jetbrains.kotlin:kotlin-stdlib-jre8:1.2.0:kotlin-stdlib-jre8-1.2.0.jar:633524eee6ef1941f7cb1dab7ee3927b0a221ceee9047aeb5515f4cbb990c82a',
|
|
||||||
'org.jetbrains.kotlin:kotlin-stdlib:1.2.0:kotlin-stdlib-1.2.0.jar:05cfd9f5ac0b41910703a8925f7211a495909b27a2ffdd1c5106f1689aeafcd4',
|
|
||||||
'org.jetbrains.trove4j:trove4j:20160824:trove4j-20160824.jar:1917871c8deb468307a584680c87a44572f5a8b0b98c6d397fc0f5f86596dbe7',
|
|
||||||
'org.jetbrains:annotations:13.0:annotations-13.0.jar:ace2a10dc8e2d5fd34925ecac03e4988b2c0f851650c94b8cef49ba1bd111478',
|
|
||||||
'org.jmock:jmock-junit4:2.8.2:jmock-junit4-2.8.2.jar:f7ee4df4f7bd7b7f1cafad3b99eb74d579f109d5992ff625347352edb55e674c',
|
|
||||||
'org.jmock:jmock-legacy:2.8.2:jmock-legacy-2.8.2.jar:f2b985a5c08a9edb7f37612330c058809da3f6a6d63ce792426ebf8ff0d6d31b',
|
|
||||||
'org.jmock:jmock-testjar:2.8.2:jmock-testjar-2.8.2.jar:8900860f72c474e027cf97fe78dcbf154a1aa7fc62b6845c5fb4e4f3c7bc8760',
|
|
||||||
'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.mockito:mockito-core:2.8.9:mockito-core-2.8.9.jar:a2bb9b8b40d81bb02ccb84259524c0f4911f73c6577bfc7ddd940b8fc729b6e6',
|
|
||||||
'org.objenesis:objenesis:2.5:objenesis-2.5.jar:293328e1b0d31ed30bb89fca542b6c52fac00989bb0e62eb9d98d630c4dd6b7c',
|
|
||||||
'org.ow2.asm:asm-analysis:5.1:asm-analysis-5.1.jar:a34658f5c5de4b573eef21131cc32cc25f7b66407944f312b28ec2e56abb1fa9',
|
|
||||||
'org.ow2.asm:asm-commons:5.0.1:asm-commons-5.0.1.jar:fb1cb7fa27d892712ced8fbf8d027eb5052ecd3999dba1ba47824357accb40e7',
|
|
||||||
'org.ow2.asm:asm-commons:5.1:asm-commons-5.1.jar:97b3786e1f55e74bddf8ad102bf50e33bbcbc1f6b7fd7b36f0bbbb25cd4981be',
|
|
||||||
'org.ow2.asm:asm-tree:5.0.1:asm-tree-5.0.1.jar:ff2aceed10da9930a44f6c8f81c6372d5e55eb59c4e0ea9d37f77dfd765fa9fa',
|
|
||||||
'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:5.0.4:asm-5.0.4.jar:896618ed8ae62702521a78bc7be42b7c491a08e6920a15f89a3ecdec31e9a220',
|
|
||||||
'org.ow2.asm:asm:5.1:asm-5.1.jar:d2da399a9967c69f0a21739256fa79d284222c223082cacadc17372244764b54',
|
|
||||||
'org.robolectric:annotations:3.5.1:annotations-3.5.1.jar:14db0f7d2299c5400ff7764bb37b4fa80306582d8965fdf6999091723e2384ce',
|
|
||||||
'org.robolectric:junit:3.5.1:junit-3.5.1.jar:b2e81b7d5a22755f2ea76aa9bbbd4359d61c4cb9577193ccfbb8f97378ed293b',
|
|
||||||
'org.robolectric:resources:3.5.1:resources-3.5.1.jar:22a5564590c8bfd8df7efb2b0c7d9942b46a0beb59ba38899d59c1270f293b1c',
|
|
||||||
'org.robolectric:robolectric:3.5.1:robolectric-3.5.1.jar:603cf898f93b854f18021fab452aca3fe482368eeb2e720988ae82212ebcf4b6',
|
|
||||||
'org.robolectric:sandbox:3.5.1:sandbox-3.5.1.jar:beff8c3c1e840e0f7f78aadef170f347bae349f098babfc176765f499a4bcbb5',
|
|
||||||
'org.robolectric:shadowapi:3.5.1:shadowapi-3.5.1.jar:6d574f9ae0922791eb8f06979f0010997d4b862c7aec96d485ae797ddfc13278',
|
|
||||||
'org.robolectric:shadows-framework:3.5.1:shadows-framework-3.5.1.jar:597b54cc1a494799d783921c6ac04352f33e94fca8e00f299d4ca192db79e3fc',
|
|
||||||
'org.robolectric:shadows-support-v4:3.0:shadows-support-v4-3.0.jar:66bcc3257b037d72998e860d67b1bc58215b7eeac8ad860fcc3e613332d88619',
|
|
||||||
'org.robolectric:utils:3.5.1:utils-3.5.1.jar:d7d77326867e6d903156ebb18c244819b26aebe3aa82a1c57081081a0b6c4f63',
|
|
||||||
'uk.co.samuelwall:material-tap-target-prompt:2.8.0:material-tap-target-prompt-2.8.0.aar:ac70770c05bbc4675a1d5712c0e53d46ee4fa961b74947589fce50d8003065ec',
|
|
||||||
'xmlpull:xmlpull:1.1.3.1:xmlpull-1.1.3.1.jar:34e08ee62116071cbb69c0ed70d15a7a5b208d62798c59f2120bb8929324cb63',
|
|
||||||
'xpp3:xpp3_min:1.1.4c:xpp3_min-1.1.4c.jar:bfc90e9e32d0eab1f397fb974b5f150a815188382ac41f372a7149d5bc178008',
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
|
|
||||||
def getStdout = { command, defaultValue ->
|
def getStdout = { command, defaultValue ->
|
||||||
@@ -238,27 +82,25 @@ android {
|
|||||||
defaultConfig {
|
defaultConfig {
|
||||||
minSdkVersion 14
|
minSdkVersion 14
|
||||||
targetSdkVersion 26
|
targetSdkVersion 26
|
||||||
versionCode 10011
|
versionCode 10013
|
||||||
versionName "1.0.11"
|
versionName "1.0.13"
|
||||||
applicationId "org.briarproject.briar.android"
|
applicationId "org.briarproject.briar.android"
|
||||||
resValue "string", "app_package", "org.briarproject.briar.android"
|
|
||||||
resValue "string", "app_name", "Briar"
|
|
||||||
buildConfigField "String", "GitHash",
|
buildConfigField "String", "GitHash",
|
||||||
"\"${getStdout(['git', 'rev-parse', '--short=7', 'HEAD'], 'No commit hash')}\""
|
"\"${getStdout(['git', 'rev-parse', '--short=7', 'HEAD'], 'No commit hash')}\""
|
||||||
def now = (long) (System.currentTimeMillis() / 1000)
|
def now = (long) (System.currentTimeMillis() / 1000)
|
||||||
buildConfigField "Long", "BuildTimestamp",
|
buildConfigField "Long", "BuildTimestamp",
|
||||||
"${getStdout(['git', 'log', '-n', '1', '--format=%ct'], now)}000L"
|
"${getStdout(['git', 'log', '-n', '1', '--format=%ct'], now)}000L"
|
||||||
|
testInstrumentationRunner 'org.briarproject.briar.android.test.BriarTestRunner'
|
||||||
}
|
}
|
||||||
|
|
||||||
buildTypes {
|
buildTypes {
|
||||||
debug {
|
debug {
|
||||||
applicationIdSuffix ".debug"
|
applicationIdSuffix ".debug"
|
||||||
resValue "string", "app_package", "org.briarproject.briar.android.debug"
|
|
||||||
resValue "string", "app_name", "Briar Debug"
|
|
||||||
shrinkResources false
|
shrinkResources false
|
||||||
minifyEnabled true
|
minifyEnabled true
|
||||||
crunchPngs false
|
crunchPngs false
|
||||||
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.txt'
|
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.txt'
|
||||||
|
testProguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.txt', 'proguard-test.txt'
|
||||||
}
|
}
|
||||||
release {
|
release {
|
||||||
shrinkResources false
|
shrinkResources false
|
||||||
@@ -268,6 +110,23 @@ android {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
flavorDimensions "version"
|
||||||
|
productFlavors {
|
||||||
|
screenshot {
|
||||||
|
dimension "version"
|
||||||
|
minSdkVersion 18
|
||||||
|
applicationIdSuffix ".screenshot" // = org.briarproject.briar.android.screenshot.debug
|
||||||
|
}
|
||||||
|
official {
|
||||||
|
dimension "version"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
variantFilter { variant ->
|
||||||
|
if (variant.flavors*.name.contains("screenshot") && variant.buildType.name == "release") {
|
||||||
|
setIgnore(true)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
compileOptions {
|
compileOptions {
|
||||||
sourceCompatibility JavaVersion.VERSION_1_8
|
sourceCompatibility JavaVersion.VERSION_1_8
|
||||||
targetCompatibility JavaVersion.VERSION_1_8
|
targetCompatibility JavaVersion.VERSION_1_8
|
||||||
@@ -327,4 +186,7 @@ project.afterEvaluate {
|
|||||||
preBuild.dependsOn.add(verifyTranslations)
|
preBuild.dependsOn.add(verifyTranslations)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
tasks.withType(Test) {
|
||||||
|
// Use entropy-gathering device specified on command line, if any
|
||||||
|
systemProperty 'java.security.egd', System.getProperty('java.security.egd')
|
||||||
|
}
|
||||||
|
|||||||
2
briar-android/fastlane/Appfile
Normal file
2
briar-android/fastlane/Appfile
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
json_key_file("") # Path to the json secret file - Follow https://docs.fastlane.tools/actions/supply/#setup to get one
|
||||||
|
package_name("org.briarproject.briar.android")
|
||||||
30
briar-android/fastlane/Fastfile
Normal file
30
briar-android/fastlane/Fastfile
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
# This file contains the fastlane.tools configuration
|
||||||
|
# You can find the documentation at https://docs.fastlane.tools
|
||||||
|
#
|
||||||
|
# For a list of all available actions, check out
|
||||||
|
#
|
||||||
|
# https://docs.fastlane.tools/actions
|
||||||
|
#
|
||||||
|
# For a list of all available plugins, check out
|
||||||
|
#
|
||||||
|
# https://docs.fastlane.tools/plugins/available-plugins
|
||||||
|
#
|
||||||
|
|
||||||
|
# Uncomment the line if you want fastlane to automatically update itself
|
||||||
|
# update_fastlane
|
||||||
|
|
||||||
|
default_platform(:android)
|
||||||
|
|
||||||
|
platform :android do
|
||||||
|
desc "Takes screenshots for manual and Google Play"
|
||||||
|
lane :screenshots do
|
||||||
|
gradle(project_dir: "..", task: "assembleScreenshot assembleAndroidTest")
|
||||||
|
system './demo-mode-activate.sh'
|
||||||
|
capture_android_screenshots
|
||||||
|
system './demo-mode-deactivate.sh'
|
||||||
|
system './rename_screenshots.py'
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
# vi:syntax=ruby
|
||||||
9
briar-android/fastlane/Screengrabfile
Normal file
9
briar-android/fastlane/Screengrabfile
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
app_package_name "org.briarproject.briar.android.screenshot.debug"
|
||||||
|
locales ['en-US']
|
||||||
|
use_tests_in_classes([
|
||||||
|
'org.briarproject.briar.android.login.SetupActivityScreenshotTest',
|
||||||
|
'org.briarproject.briar.android.settings.SettingsActivityScreenshotTest',
|
||||||
|
])
|
||||||
|
app_apk_path "build/outputs/apk/screenshot/debug/briar-android-screenshot-debug.apk"
|
||||||
|
tests_apk_path "build/outputs/apk/androidTest/screenshot/debug/briar-android-screenshot-debug-androidTest.apk"
|
||||||
|
test_instrumentation_runner "org.briarproject.briar.android.test.BriarTestRunner"
|
||||||
7
briar-android/fastlane/demo-mode-activate.sh
Executable file
7
briar-android/fastlane/demo-mode-activate.sh
Executable file
@@ -0,0 +1,7 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
adb shell settings put global sysui_demo_allowed 1
|
||||||
|
adb shell am broadcast -a com.android.systemui.demo -e command enter
|
||||||
|
adb shell am broadcast -a com.android.systemui.demo -e command notifications -e visible false
|
||||||
|
adb shell am broadcast -a com.android.systemui.demo -e command battery -e level 100
|
||||||
|
adb shell am broadcast -a com.android.systemui.demo -e command network -e wifi show
|
||||||
|
adb shell am broadcast -a com.android.systemui.demo -e command clock -e hhmm 1337
|
||||||
2
briar-android/fastlane/demo-mode-deactivate.sh
Executable file
2
briar-android/fastlane/demo-mode-deactivate.sh
Executable file
@@ -0,0 +1,2 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
adb shell am broadcast -a com.android.systemui.demo -e command exit
|
||||||
43
briar-android/fastlane/rename_screenshots.py
Executable file
43
briar-android/fastlane/rename_screenshots.py
Executable file
@@ -0,0 +1,43 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
|
||||||
|
# Author: Torsten Grote
|
||||||
|
# License: GPLv3 or later
|
||||||
|
|
||||||
|
import os
|
||||||
|
import re
|
||||||
|
import glob
|
||||||
|
|
||||||
|
METADATA_PATH = 'metadata/android'
|
||||||
|
GLOB = '/*/images/phoneScreenshots/*.png'
|
||||||
|
|
||||||
|
REGEX = re.compile(r'(^\w+)_\d{13}\.png$')
|
||||||
|
REGEX_IN_FILE = re.compile(r'(\w+)_\d{13}\.png', re.MULTILINE)
|
||||||
|
PATH = os.path.dirname(os.path.realpath(__file__))
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
for path in glob.glob("%s%s" % (os.path.join(PATH, METADATA_PATH), GLOB)):
|
||||||
|
filename = os.path.basename(path)
|
||||||
|
match = REGEX.match(filename)
|
||||||
|
if match:
|
||||||
|
directory = os.path.dirname(path)
|
||||||
|
new_filename = "%s.png" % match.group(1)
|
||||||
|
new_path = os.path.join(directory, new_filename)
|
||||||
|
os.rename(path, new_path)
|
||||||
|
print("Renaming\n %s\nto\n %s\n" % (path, new_path))
|
||||||
|
else:
|
||||||
|
print("Warning: Path did not match %s" % path)
|
||||||
|
|
||||||
|
# rename fields also in screenshot overview file
|
||||||
|
overview = os.path.join(PATH, METADATA_PATH, 'screenshots.html')
|
||||||
|
with open(overview, 'r') as f:
|
||||||
|
file_data = f.read()
|
||||||
|
|
||||||
|
file_data = REGEX_IN_FILE.sub(r'\1.png', file_data)
|
||||||
|
|
||||||
|
with open(overview, 'w') as f:
|
||||||
|
f.write(file_data)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
15
briar-android/proguard-test.txt
Normal file
15
briar-android/proguard-test.txt
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
-dontwarn android.test.**
|
||||||
|
-dontwarn android.support.test.**
|
||||||
|
-dontnote android.support.test.**
|
||||||
|
-dontwarn com.googlecode.eyesfree.compat.CompatUtils
|
||||||
|
|
||||||
|
-keep class org.xmlpull.v1.** { *; }
|
||||||
|
-dontwarn org.xmlpull.v1.**
|
||||||
|
|
||||||
|
-keep class org.junit.** { *; }
|
||||||
|
-dontwarn org.junit.**
|
||||||
|
|
||||||
|
-keep class junit.** { *; }
|
||||||
|
-dontwarn junit.**
|
||||||
|
|
||||||
|
-dontwarn org.briarproject.briar.android.BriarTestComponentApplication
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
package org.briarproject.briar.android;
|
||||||
|
|
||||||
|
import org.briarproject.bramble.BrambleCoreModule;
|
||||||
|
import org.briarproject.briar.BriarCoreModule;
|
||||||
|
|
||||||
|
public class BriarTestComponentApplication extends BriarApplicationImpl {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected AndroidComponent createApplicationComponent() {
|
||||||
|
AndroidComponent component = DaggerBriarUiTestComponent.builder()
|
||||||
|
.appModule(new AppModule(this)).build();
|
||||||
|
// We need to load the eager singletons directly after making the
|
||||||
|
// dependency graphs
|
||||||
|
BrambleCoreModule.initEagerSingletons(component);
|
||||||
|
BriarCoreModule.initEagerSingletons(component);
|
||||||
|
AndroidEagerSingletons.initEagerSingletons(component);
|
||||||
|
return component;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,29 @@
|
|||||||
|
package org.briarproject.briar.android;
|
||||||
|
|
||||||
|
import org.briarproject.bramble.BrambleAndroidModule;
|
||||||
|
import org.briarproject.bramble.BrambleCoreModule;
|
||||||
|
import org.briarproject.bramble.account.BriarAccountModule;
|
||||||
|
import org.briarproject.briar.BriarCoreModule;
|
||||||
|
import org.briarproject.briar.android.login.SetupActivityScreenshotTest;
|
||||||
|
import org.briarproject.briar.android.navdrawer.NavDrawerActivityTest;
|
||||||
|
import org.briarproject.briar.android.settings.SettingsActivityScreenshotTest;
|
||||||
|
|
||||||
|
import javax.inject.Singleton;
|
||||||
|
|
||||||
|
import dagger.Component;
|
||||||
|
|
||||||
|
@Singleton
|
||||||
|
@Component(modules = {
|
||||||
|
AppModule.class,
|
||||||
|
BriarCoreModule.class,
|
||||||
|
BrambleAndroidModule.class,
|
||||||
|
BriarAccountModule.class,
|
||||||
|
BrambleCoreModule.class
|
||||||
|
})
|
||||||
|
public interface BriarUiTestComponent extends AndroidComponent {
|
||||||
|
|
||||||
|
void inject(SetupActivityScreenshotTest test);
|
||||||
|
void inject(NavDrawerActivityTest test);
|
||||||
|
void inject(SettingsActivityScreenshotTest test);
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,106 @@
|
|||||||
|
package org.briarproject.briar.android.login;
|
||||||
|
|
||||||
|
import android.support.test.espresso.intent.rule.IntentsTestRule;
|
||||||
|
import android.support.test.runner.AndroidJUnit4;
|
||||||
|
import android.support.test.uiautomator.UiDevice;
|
||||||
|
import android.support.test.uiautomator.UiObject;
|
||||||
|
import android.support.test.uiautomator.UiSelector;
|
||||||
|
|
||||||
|
import org.briarproject.briar.R;
|
||||||
|
import org.briarproject.briar.android.BriarUiTestComponent;
|
||||||
|
import org.briarproject.briar.android.test.ScreenshotTest;
|
||||||
|
import org.junit.Rule;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.junit.runner.RunWith;
|
||||||
|
|
||||||
|
import static android.support.test.InstrumentationRegistry.getInstrumentation;
|
||||||
|
import static android.support.test.InstrumentationRegistry.getTargetContext;
|
||||||
|
import static android.support.test.espresso.Espresso.onView;
|
||||||
|
import static android.support.test.espresso.action.ViewActions.click;
|
||||||
|
import static android.support.test.espresso.action.ViewActions.typeText;
|
||||||
|
import static android.support.test.espresso.assertion.ViewAssertions.matches;
|
||||||
|
import static android.support.test.espresso.intent.Intents.intended;
|
||||||
|
import static android.support.test.espresso.intent.matcher.IntentMatchers.hasComponent;
|
||||||
|
import static android.support.test.espresso.matcher.ViewMatchers.isDisplayed;
|
||||||
|
import static android.support.test.espresso.matcher.ViewMatchers.isRoot;
|
||||||
|
import static android.support.test.espresso.matcher.ViewMatchers.withId;
|
||||||
|
import static android.support.test.espresso.matcher.ViewMatchers.withText;
|
||||||
|
import static android.support.test.runner.lifecycle.Stage.PAUSED;
|
||||||
|
import static junit.framework.Assert.assertTrue;
|
||||||
|
import static org.briarproject.briar.android.test.ViewActions.waitForActivity;
|
||||||
|
import static org.briarproject.briar.android.test.ViewActions.waitUntilMatches;
|
||||||
|
import static org.briarproject.briar.android.util.UiUtils.needsDozeWhitelisting;
|
||||||
|
|
||||||
|
|
||||||
|
@RunWith(AndroidJUnit4.class)
|
||||||
|
public class SetupActivityScreenshotTest extends ScreenshotTest {
|
||||||
|
|
||||||
|
@Rule
|
||||||
|
public IntentsTestRule<SetupActivity> testRule =
|
||||||
|
new IntentsTestRule<SetupActivity>(SetupActivity.class) {
|
||||||
|
@Override
|
||||||
|
protected void beforeActivityLaunched() {
|
||||||
|
super.beforeActivityLaunched();
|
||||||
|
accountManager.deleteAccount();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void inject(BriarUiTestComponent component) {
|
||||||
|
component.inject(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void createAccount() throws Exception {
|
||||||
|
// Enter username
|
||||||
|
onView(withText(R.string.setup_title))
|
||||||
|
.check(matches(isDisplayed()));
|
||||||
|
onView(withId(R.id.nickname_entry))
|
||||||
|
.check(matches(isDisplayed()))
|
||||||
|
.perform(typeText(USERNAME));
|
||||||
|
onView(withId(R.id.nickname_entry))
|
||||||
|
.perform(waitUntilMatches(withText(USERNAME)));
|
||||||
|
|
||||||
|
screenshot("manual_create_account");
|
||||||
|
|
||||||
|
onView(withId(R.id.next))
|
||||||
|
.check(matches(isDisplayed()))
|
||||||
|
.perform(click());
|
||||||
|
|
||||||
|
// Enter password
|
||||||
|
onView(withId(R.id.password_entry))
|
||||||
|
.check(matches(isDisplayed()))
|
||||||
|
.perform(typeText(PASSWORD));
|
||||||
|
onView(withId(R.id.password_confirm))
|
||||||
|
.check(matches(isDisplayed()))
|
||||||
|
.perform(typeText(PASSWORD));
|
||||||
|
onView(withId(R.id.next))
|
||||||
|
.check(matches(isDisplayed()))
|
||||||
|
.perform(click());
|
||||||
|
|
||||||
|
// White-list Doze if needed
|
||||||
|
if (needsDozeWhitelisting(getTargetContext())) {
|
||||||
|
onView(withText(R.string.setup_doze_button))
|
||||||
|
.check(matches(isDisplayed()))
|
||||||
|
.perform(click());
|
||||||
|
UiDevice device = UiDevice.getInstance(getInstrumentation());
|
||||||
|
UiObject allowButton = device.findObject(
|
||||||
|
new UiSelector().className("android.widget.Button")
|
||||||
|
.index(1));
|
||||||
|
allowButton.click();
|
||||||
|
onView(withId(R.id.next))
|
||||||
|
.check(matches(isDisplayed()))
|
||||||
|
.perform(click());
|
||||||
|
}
|
||||||
|
|
||||||
|
// wait for OpenDatabaseActivity to show up
|
||||||
|
onView(withId(R.id.progress))
|
||||||
|
.check(matches(isDisplayed()));
|
||||||
|
onView(isRoot())
|
||||||
|
.perform(waitForActivity(testRule.getActivity(), PAUSED));
|
||||||
|
intended(hasComponent(OpenDatabaseActivity.class.getName()));
|
||||||
|
|
||||||
|
assertTrue(accountManager.hasDatabaseKey());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,48 @@
|
|||||||
|
package org.briarproject.briar.android.navdrawer;
|
||||||
|
|
||||||
|
import android.support.test.espresso.contrib.DrawerActions;
|
||||||
|
import android.support.test.runner.AndroidJUnit4;
|
||||||
|
import android.view.Gravity;
|
||||||
|
|
||||||
|
import org.briarproject.briar.R;
|
||||||
|
import org.briarproject.briar.android.BriarUiTestComponent;
|
||||||
|
import org.briarproject.briar.android.settings.SettingsActivity;
|
||||||
|
import org.briarproject.briar.android.test.ScreenshotTest;
|
||||||
|
import org.junit.Rule;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.junit.runner.RunWith;
|
||||||
|
|
||||||
|
import static android.support.test.espresso.Espresso.onView;
|
||||||
|
import static android.support.test.espresso.action.ViewActions.click;
|
||||||
|
import static android.support.test.espresso.assertion.ViewAssertions.matches;
|
||||||
|
import static android.support.test.espresso.contrib.DrawerMatchers.isClosed;
|
||||||
|
import static android.support.test.espresso.intent.Intents.intended;
|
||||||
|
import static android.support.test.espresso.intent.matcher.IntentMatchers.hasComponent;
|
||||||
|
import static android.support.test.espresso.matcher.ViewMatchers.isDisplayed;
|
||||||
|
import static android.support.test.espresso.matcher.ViewMatchers.withId;
|
||||||
|
import static android.support.test.espresso.matcher.ViewMatchers.withText;
|
||||||
|
|
||||||
|
@RunWith(AndroidJUnit4.class)
|
||||||
|
public class NavDrawerActivityTest extends ScreenshotTest {
|
||||||
|
|
||||||
|
@Rule
|
||||||
|
public CleanAccountTestRule<NavDrawerActivity> testRule =
|
||||||
|
new CleanAccountTestRule<>(NavDrawerActivity.class);
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void inject(BriarUiTestComponent component) {
|
||||||
|
component.inject(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void openSettings() {
|
||||||
|
onView(withId(R.id.drawer_layout))
|
||||||
|
.check(matches(isClosed(Gravity.START)))
|
||||||
|
.perform(DrawerActions.open());
|
||||||
|
onView(withText(R.string.settings_button))
|
||||||
|
.check(matches(isDisplayed()))
|
||||||
|
.perform(click());
|
||||||
|
intended(hasComponent(SettingsActivity.class.getName()));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,70 @@
|
|||||||
|
package org.briarproject.briar.android.settings;
|
||||||
|
|
||||||
|
import android.content.Intent;
|
||||||
|
import android.support.test.espresso.contrib.DrawerActions;
|
||||||
|
import android.support.test.runner.AndroidJUnit4;
|
||||||
|
import android.view.Gravity;
|
||||||
|
|
||||||
|
import org.briarproject.briar.R;
|
||||||
|
import org.briarproject.briar.android.BriarUiTestComponent;
|
||||||
|
import org.briarproject.briar.android.navdrawer.NavDrawerActivity;
|
||||||
|
import org.briarproject.briar.android.test.ScreenshotTest;
|
||||||
|
import org.junit.Rule;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.junit.runner.RunWith;
|
||||||
|
|
||||||
|
import static android.support.test.espresso.Espresso.onView;
|
||||||
|
import static android.support.test.espresso.action.ViewActions.click;
|
||||||
|
import static android.support.test.espresso.assertion.ViewAssertions.matches;
|
||||||
|
import static android.support.test.espresso.contrib.DrawerMatchers.isClosed;
|
||||||
|
import static android.support.test.espresso.matcher.ViewMatchers.isDisplayed;
|
||||||
|
import static android.support.test.espresso.matcher.ViewMatchers.withId;
|
||||||
|
import static android.support.test.espresso.matcher.ViewMatchers.withText;
|
||||||
|
|
||||||
|
@RunWith(AndroidJUnit4.class)
|
||||||
|
public class SettingsActivityScreenshotTest extends ScreenshotTest {
|
||||||
|
|
||||||
|
@Rule
|
||||||
|
public CleanAccountTestRule<SettingsActivity> testRule =
|
||||||
|
new CleanAccountTestRule<>(SettingsActivity.class);
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void inject(BriarUiTestComponent component) {
|
||||||
|
component.inject(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void changeTheme() {
|
||||||
|
onView(withText(R.string.settings_button))
|
||||||
|
.check(matches(isDisplayed()));
|
||||||
|
|
||||||
|
screenshot("manual_dark_theme_settings");
|
||||||
|
|
||||||
|
// switch to dark theme
|
||||||
|
onView(withText(R.string.pref_theme_title))
|
||||||
|
.check(matches(isDisplayed()))
|
||||||
|
.perform(click());
|
||||||
|
onView(withText(R.string.pref_theme_dark))
|
||||||
|
.check(matches(isDisplayed()))
|
||||||
|
.perform(click());
|
||||||
|
|
||||||
|
// start main activity
|
||||||
|
Intent i =
|
||||||
|
new Intent(testRule.getActivity(), NavDrawerActivity.class);
|
||||||
|
testRule.getActivity().startActivity(i);
|
||||||
|
|
||||||
|
// close expiry warning
|
||||||
|
onView(withId(R.id.expiryWarningClose))
|
||||||
|
.check(matches(isDisplayed()));
|
||||||
|
onView(withId(R.id.expiryWarningClose))
|
||||||
|
.perform(click());
|
||||||
|
|
||||||
|
// open navigation drawer
|
||||||
|
onView(withId(R.id.drawer_layout))
|
||||||
|
.check(matches(isClosed(Gravity.START)))
|
||||||
|
.perform(DrawerActions.open());
|
||||||
|
|
||||||
|
screenshot("manual_dark_theme_nav_drawer");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
package org.briarproject.briar.android.test;
|
||||||
|
|
||||||
|
import android.app.Application;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.support.test.runner.AndroidJUnitRunner;
|
||||||
|
|
||||||
|
import org.briarproject.briar.android.BriarTestComponentApplication;
|
||||||
|
|
||||||
|
public class BriarTestRunner extends AndroidJUnitRunner {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Application newApplication(ClassLoader cl, String className,
|
||||||
|
Context context)
|
||||||
|
throws InstantiationException, IllegalAccessException,
|
||||||
|
ClassNotFoundException {
|
||||||
|
return super.newApplication(cl, BriarTestComponentApplication.class.getName(),
|
||||||
|
context);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,73 @@
|
|||||||
|
package org.briarproject.briar.android.test;
|
||||||
|
|
||||||
|
import android.app.Activity;
|
||||||
|
import android.support.test.espresso.intent.rule.IntentsTestRule;
|
||||||
|
import android.util.Log;
|
||||||
|
|
||||||
|
import org.briarproject.bramble.api.account.AccountManager;
|
||||||
|
import org.briarproject.bramble.api.lifecycle.LifecycleManager;
|
||||||
|
import org.briarproject.briar.android.BriarTestComponentApplication;
|
||||||
|
import org.briarproject.briar.android.BriarUiTestComponent;
|
||||||
|
import org.junit.ClassRule;
|
||||||
|
|
||||||
|
import javax.inject.Inject;
|
||||||
|
|
||||||
|
import tools.fastlane.screengrab.Screengrab;
|
||||||
|
import tools.fastlane.screengrab.UiAutomatorScreenshotStrategy;
|
||||||
|
import tools.fastlane.screengrab.locale.LocaleTestRule;
|
||||||
|
|
||||||
|
import static android.support.test.InstrumentationRegistry.getTargetContext;
|
||||||
|
import static tools.fastlane.screengrab.Screengrab.setDefaultScreenshotStrategy;
|
||||||
|
|
||||||
|
public abstract class ScreenshotTest {
|
||||||
|
|
||||||
|
@ClassRule
|
||||||
|
public static final LocaleTestRule localeTestRule = new LocaleTestRule();
|
||||||
|
|
||||||
|
protected static final String USERNAME = "Alice";
|
||||||
|
protected static final String PASSWORD = "123456";
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
protected AccountManager accountManager;
|
||||||
|
@Inject
|
||||||
|
protected LifecycleManager lifecycleManager;
|
||||||
|
|
||||||
|
public ScreenshotTest() {
|
||||||
|
super();
|
||||||
|
setDefaultScreenshotStrategy(new UiAutomatorScreenshotStrategy());
|
||||||
|
BriarTestComponentApplication app =
|
||||||
|
(BriarTestComponentApplication) getTargetContext()
|
||||||
|
.getApplicationContext();
|
||||||
|
inject((BriarUiTestComponent) app.getApplicationComponent());
|
||||||
|
}
|
||||||
|
|
||||||
|
protected abstract void inject(BriarUiTestComponent component);
|
||||||
|
|
||||||
|
protected void screenshot(String name) {
|
||||||
|
try {
|
||||||
|
Screengrab.screenshot(name);
|
||||||
|
} catch (RuntimeException e) {
|
||||||
|
if (!e.getMessage().equals("Unable to capture screenshot."))
|
||||||
|
throw e;
|
||||||
|
// The tests should still pass when run from AndroidStudio
|
||||||
|
// without manually granting permissions like fastlane does.
|
||||||
|
Log.w("Screengrab", "Permission to write screenshot is missing.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected class CleanAccountTestRule<A extends Activity>
|
||||||
|
extends IntentsTestRule<A> {
|
||||||
|
|
||||||
|
public CleanAccountTestRule(Class<A> activityClass) {
|
||||||
|
super(activityClass);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void beforeActivityLaunched() {
|
||||||
|
super.beforeActivityLaunched();
|
||||||
|
accountManager.deleteAccount();
|
||||||
|
accountManager.createAccount(USERNAME, PASSWORD);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,93 @@
|
|||||||
|
package org.briarproject.briar.android.test;
|
||||||
|
|
||||||
|
import android.app.Activity;
|
||||||
|
import android.support.test.espresso.PerformException;
|
||||||
|
import android.support.test.espresso.UiController;
|
||||||
|
import android.support.test.espresso.ViewAction;
|
||||||
|
import android.support.test.runner.lifecycle.ActivityLifecycleMonitor;
|
||||||
|
import android.support.test.runner.lifecycle.ActivityLifecycleMonitorRegistry;
|
||||||
|
import android.support.test.runner.lifecycle.Stage;
|
||||||
|
import android.view.View;
|
||||||
|
|
||||||
|
import org.hamcrest.Matcher;
|
||||||
|
|
||||||
|
import java.util.concurrent.TimeoutException;
|
||||||
|
|
||||||
|
import static android.support.test.espresso.matcher.ViewMatchers.isDisplayed;
|
||||||
|
import static android.support.test.espresso.util.HumanReadables.describe;
|
||||||
|
import static android.support.test.espresso.util.TreeIterables.breadthFirstViewTraversal;
|
||||||
|
import static java.lang.System.currentTimeMillis;
|
||||||
|
import static java.util.concurrent.TimeUnit.SECONDS;
|
||||||
|
|
||||||
|
public class ViewActions {
|
||||||
|
|
||||||
|
private final static long TIMEOUT_MS = SECONDS.toMillis(10);
|
||||||
|
private final static long WAIT_MS = 50;
|
||||||
|
|
||||||
|
public static ViewAction waitUntilMatches(Matcher<View> viewMatcher) {
|
||||||
|
return waitUntilMatches(viewMatcher, TIMEOUT_MS);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static ViewAction waitUntilMatches(Matcher<View> viewMatcher,
|
||||||
|
long timeout) {
|
||||||
|
return new CustomViewAction() {
|
||||||
|
@Override
|
||||||
|
protected boolean exitConditionTrue(View view) {
|
||||||
|
for (View child : breadthFirstViewTraversal(view)) {
|
||||||
|
if (viewMatcher.matches(child)) return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getDescription() {
|
||||||
|
return "Wait for view matcher " + viewMatcher +
|
||||||
|
" to match within " + timeout + " milliseconds.";
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ViewAction waitForActivity(Activity activity, Stage stage) {
|
||||||
|
return new CustomViewAction() {
|
||||||
|
@Override
|
||||||
|
protected boolean exitConditionTrue(View view) {
|
||||||
|
ActivityLifecycleMonitor lifecycleMonitor =
|
||||||
|
ActivityLifecycleMonitorRegistry.getInstance();
|
||||||
|
return lifecycleMonitor.getLifecycleStageOf(activity) == stage;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getDescription() {
|
||||||
|
return "Wait for activity " + activity.getClass().getName() +
|
||||||
|
" to resume within " + TIMEOUT_MS + " milliseconds.";
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
private static abstract class CustomViewAction implements ViewAction {
|
||||||
|
@Override
|
||||||
|
public Matcher<View> getConstraints() {
|
||||||
|
return isDisplayed();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void perform(UiController uiController, View view) {
|
||||||
|
uiController.loopMainThreadUntilIdle();
|
||||||
|
long endTime = currentTimeMillis() + TIMEOUT_MS;
|
||||||
|
do {
|
||||||
|
if (exitConditionTrue(view)) return;
|
||||||
|
uiController.loopMainThreadForAtLeast(WAIT_MS);
|
||||||
|
}
|
||||||
|
while (currentTimeMillis() < endTime);
|
||||||
|
|
||||||
|
throw new PerformException.Builder()
|
||||||
|
.withActionDescription(getDescription())
|
||||||
|
.withViewDescription(describe(view))
|
||||||
|
.withCause(new TimeoutException())
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected abstract boolean exitConditionTrue(View view);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
5
briar-android/src/debug/res/values/strings.xml
Normal file
5
briar-android/src/debug/res/values/strings.xml
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<resources>
|
||||||
|
<string name="app_name" translatable="false">Briar Debug</string>
|
||||||
|
<string name="app_package" translatable="false">org.briarproject.briar.android.debug</string>
|
||||||
|
</resources>
|
||||||
@@ -3,8 +3,9 @@
|
|||||||
package="org.briarproject.briar"
|
package="org.briarproject.briar"
|
||||||
xmlns:android="http://schemas.android.com/apk/res/android">
|
xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
|
||||||
<uses-feature android:name="android.hardware.bluetooth"/>
|
<uses-feature android:name="android.hardware.bluetooth" android:required="false"/>
|
||||||
<uses-feature android:name="android.hardware.camera" />
|
<uses-feature android:name="android.hardware.camera" android:required="false"/>
|
||||||
|
<uses-feature android:name="android.hardware.touchscreen" android:required="false" />
|
||||||
|
|
||||||
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
|
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
|
||||||
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
|
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
|
||||||
@@ -26,10 +27,11 @@
|
|||||||
android:theme="@style/BriarTheme">
|
android:theme="@style/BriarTheme">
|
||||||
|
|
||||||
<receiver
|
<receiver
|
||||||
android:name="org.briarproject.briar.android.BootReceiver"
|
android:name="org.briarproject.briar.android.login.SignInReminderReceiver"
|
||||||
android:exported="false">
|
android:exported="false">
|
||||||
<intent-filter>
|
<intent-filter>
|
||||||
<action android:name="android.intent.action.BOOT_COMPLETED"/>
|
<action android:name="android.intent.action.BOOT_COMPLETED"/>
|
||||||
|
<action android:name="android.intent.action.MY_PACKAGE_REPLACED"/>
|
||||||
</intent-filter>
|
</intent-filter>
|
||||||
</receiver>
|
</receiver>
|
||||||
|
|
||||||
@@ -400,5 +402,11 @@
|
|||||||
android:theme="@android:style/Theme.NoDisplay">
|
android:theme="@android:style/Theme.NoDisplay">
|
||||||
</activity>
|
</activity>
|
||||||
|
|
||||||
|
<activity
|
||||||
|
android:name=".android.login.UnlockActivity"
|
||||||
|
android:label="@string/lock_unlock"
|
||||||
|
android:launchMode="singleTask"
|
||||||
|
android:theme="@style/BriarTheme.NoActionBar"/>
|
||||||
|
|
||||||
</application>
|
</application>
|
||||||
</manifest>
|
</manifest>
|
||||||
|
|||||||
@@ -0,0 +1,33 @@
|
|||||||
|
package org.briarproject.bramble.account;
|
||||||
|
|
||||||
|
import android.app.Application;
|
||||||
|
import android.content.SharedPreferences;
|
||||||
|
|
||||||
|
import org.briarproject.bramble.api.crypto.CryptoComponent;
|
||||||
|
import org.briarproject.bramble.api.db.DatabaseConfig;
|
||||||
|
import org.briarproject.bramble.api.identity.IdentityManager;
|
||||||
|
import org.briarproject.briar.R;
|
||||||
|
import org.briarproject.briar.android.Localizer;
|
||||||
|
import org.briarproject.briar.android.util.UiUtils;
|
||||||
|
|
||||||
|
import javax.inject.Inject;
|
||||||
|
|
||||||
|
class BriarAccountManager extends AndroidAccountManager {
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
BriarAccountManager(DatabaseConfig databaseConfig, CryptoComponent crypto,
|
||||||
|
IdentityManager identityManager, SharedPreferences prefs,
|
||||||
|
Application app) {
|
||||||
|
super(databaseConfig, crypto, identityManager, prefs, app);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void deleteAccount() {
|
||||||
|
synchronized (stateChangeLock) {
|
||||||
|
super.deleteAccount();
|
||||||
|
Localizer.reinitialize();
|
||||||
|
UiUtils.setTheme(appContext,
|
||||||
|
appContext.getString(R.string.pref_theme_light_value));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
package org.briarproject.bramble.account;
|
||||||
|
|
||||||
|
import org.briarproject.bramble.api.account.AccountManager;
|
||||||
|
|
||||||
|
import javax.inject.Singleton;
|
||||||
|
|
||||||
|
import dagger.Module;
|
||||||
|
import dagger.Provides;
|
||||||
|
|
||||||
|
@Module
|
||||||
|
public class BriarAccountModule {
|
||||||
|
|
||||||
|
@Provides
|
||||||
|
@Singleton
|
||||||
|
AccountManager provideAccountManager(BriarAccountManager accountManager) {
|
||||||
|
return accountManager;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,16 +1,14 @@
|
|||||||
package org.briarproject.briar.android;
|
package org.briarproject.briar.android;
|
||||||
|
|
||||||
import android.content.SharedPreferences;
|
|
||||||
|
|
||||||
import org.briarproject.bramble.BrambleAndroidModule;
|
import org.briarproject.bramble.BrambleAndroidModule;
|
||||||
import org.briarproject.bramble.BrambleCoreEagerSingletons;
|
import org.briarproject.bramble.BrambleCoreEagerSingletons;
|
||||||
import org.briarproject.bramble.BrambleCoreModule;
|
import org.briarproject.bramble.BrambleCoreModule;
|
||||||
|
import org.briarproject.bramble.account.BriarAccountModule;
|
||||||
|
import org.briarproject.bramble.api.account.AccountManager;
|
||||||
import org.briarproject.bramble.api.contact.ContactExchangeTask;
|
import org.briarproject.bramble.api.contact.ContactExchangeTask;
|
||||||
import org.briarproject.bramble.api.contact.ContactManager;
|
import org.briarproject.bramble.api.contact.ContactManager;
|
||||||
import org.briarproject.bramble.api.crypto.CryptoComponent;
|
|
||||||
import org.briarproject.bramble.api.crypto.CryptoExecutor;
|
import org.briarproject.bramble.api.crypto.CryptoExecutor;
|
||||||
import org.briarproject.bramble.api.crypto.PasswordStrengthEstimator;
|
import org.briarproject.bramble.api.crypto.PasswordStrengthEstimator;
|
||||||
import org.briarproject.bramble.api.db.DatabaseConfig;
|
|
||||||
import org.briarproject.bramble.api.db.DatabaseExecutor;
|
import org.briarproject.bramble.api.db.DatabaseExecutor;
|
||||||
import org.briarproject.bramble.api.event.EventBus;
|
import org.briarproject.bramble.api.event.EventBus;
|
||||||
import org.briarproject.bramble.api.identity.IdentityManager;
|
import org.briarproject.bramble.api.identity.IdentityManager;
|
||||||
@@ -26,9 +24,11 @@ import org.briarproject.bramble.api.system.AndroidExecutor;
|
|||||||
import org.briarproject.bramble.api.system.Clock;
|
import org.briarproject.bramble.api.system.Clock;
|
||||||
import org.briarproject.briar.BriarCoreEagerSingletons;
|
import org.briarproject.briar.BriarCoreEagerSingletons;
|
||||||
import org.briarproject.briar.BriarCoreModule;
|
import org.briarproject.briar.BriarCoreModule;
|
||||||
|
import org.briarproject.briar.android.login.SignInReminderReceiver;
|
||||||
import org.briarproject.briar.android.reporting.BriarReportSender;
|
import org.briarproject.briar.android.reporting.BriarReportSender;
|
||||||
import org.briarproject.briar.api.android.AndroidNotificationManager;
|
import org.briarproject.briar.api.android.AndroidNotificationManager;
|
||||||
import org.briarproject.briar.api.android.DozeWatchdog;
|
import org.briarproject.briar.api.android.DozeWatchdog;
|
||||||
|
import org.briarproject.briar.api.android.LockManager;
|
||||||
import org.briarproject.briar.api.android.ScreenFilterMonitor;
|
import org.briarproject.briar.api.android.ScreenFilterMonitor;
|
||||||
import org.briarproject.briar.api.blog.BlogManager;
|
import org.briarproject.briar.api.blog.BlogManager;
|
||||||
import org.briarproject.briar.api.blog.BlogPostFactory;
|
import org.briarproject.briar.api.blog.BlogPostFactory;
|
||||||
@@ -61,6 +61,7 @@ import dagger.Component;
|
|||||||
BrambleCoreModule.class,
|
BrambleCoreModule.class,
|
||||||
BriarCoreModule.class,
|
BriarCoreModule.class,
|
||||||
BrambleAndroidModule.class,
|
BrambleAndroidModule.class,
|
||||||
|
BriarAccountModule.class,
|
||||||
AppModule.class
|
AppModule.class
|
||||||
})
|
})
|
||||||
public interface AndroidComponent
|
public interface AndroidComponent
|
||||||
@@ -72,10 +73,6 @@ public interface AndroidComponent
|
|||||||
|
|
||||||
PasswordStrengthEstimator passwordStrengthIndicator();
|
PasswordStrengthEstimator passwordStrengthIndicator();
|
||||||
|
|
||||||
CryptoComponent cryptoComponent();
|
|
||||||
|
|
||||||
DatabaseConfig databaseConfig();
|
|
||||||
|
|
||||||
@DatabaseExecutor
|
@DatabaseExecutor
|
||||||
Executor databaseExecutor();
|
Executor databaseExecutor();
|
||||||
|
|
||||||
@@ -91,8 +88,6 @@ public interface AndroidComponent
|
|||||||
|
|
||||||
AndroidNotificationManager androidNotificationManager();
|
AndroidNotificationManager androidNotificationManager();
|
||||||
|
|
||||||
SharedPreferences sharedPreferences();
|
|
||||||
|
|
||||||
ScreenFilterMonitor screenFilterMonitor();
|
ScreenFilterMonitor screenFilterMonitor();
|
||||||
|
|
||||||
ConnectionRegistry connectionRegistry();
|
ConnectionRegistry connectionRegistry();
|
||||||
@@ -150,7 +145,11 @@ public interface AndroidComponent
|
|||||||
@IoExecutor
|
@IoExecutor
|
||||||
Executor ioExecutor();
|
Executor ioExecutor();
|
||||||
|
|
||||||
void inject(BootReceiver briarService);
|
AccountManager accountManager();
|
||||||
|
|
||||||
|
LockManager lockManager();
|
||||||
|
|
||||||
|
void inject(SignInReminderReceiver briarService);
|
||||||
|
|
||||||
void inject(BriarService briarService);
|
void inject(BriarService briarService);
|
||||||
|
|
||||||
|
|||||||
@@ -1,99 +1,30 @@
|
|||||||
package org.briarproject.briar.android;
|
package org.briarproject.briar.android;
|
||||||
|
|
||||||
import org.briarproject.bramble.api.crypto.SecretKey;
|
|
||||||
import org.briarproject.bramble.api.db.DatabaseConfig;
|
import org.briarproject.bramble.api.db.DatabaseConfig;
|
||||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.util.logging.Logger;
|
|
||||||
|
|
||||||
import javax.annotation.Nullable;
|
|
||||||
|
|
||||||
import static java.util.logging.Level.INFO;
|
|
||||||
|
|
||||||
@NotNullByDefault
|
@NotNullByDefault
|
||||||
class AndroidDatabaseConfig implements DatabaseConfig {
|
class AndroidDatabaseConfig implements DatabaseConfig {
|
||||||
|
|
||||||
private static final Logger LOG =
|
|
||||||
Logger.getLogger(AndroidDatabaseConfig.class.getName());
|
|
||||||
|
|
||||||
private final File dbDir, keyDir;
|
private final File dbDir, keyDir;
|
||||||
|
|
||||||
@Nullable
|
|
||||||
private volatile SecretKey key = null;
|
|
||||||
@Nullable
|
|
||||||
private volatile String nickname = null;
|
|
||||||
|
|
||||||
AndroidDatabaseConfig(File dbDir, File keyDir) {
|
AndroidDatabaseConfig(File dbDir, File keyDir) {
|
||||||
this.dbDir = dbDir;
|
this.dbDir = dbDir;
|
||||||
this.keyDir = keyDir;
|
this.keyDir = keyDir;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean databaseExists() {
|
|
||||||
// FIXME should not run on UiThread #620
|
|
||||||
if (!dbDir.isDirectory()) {
|
|
||||||
if (LOG.isLoggable(INFO))
|
|
||||||
LOG.info(dbDir.getAbsolutePath() + " is not a directory");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
File[] files = dbDir.listFiles();
|
|
||||||
if (LOG.isLoggable(INFO)) {
|
|
||||||
if (files == null) {
|
|
||||||
LOG.info("Could not list files in " + dbDir.getAbsolutePath());
|
|
||||||
} else {
|
|
||||||
LOG.info("Files in " + dbDir.getAbsolutePath() + ":");
|
|
||||||
for (File f : files) LOG.info(f.getName());
|
|
||||||
}
|
|
||||||
LOG.info("Database exists: " + (files != null && files.length > 0));
|
|
||||||
}
|
|
||||||
return files != null && files.length > 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public File getDatabaseDirectory() {
|
public File getDatabaseDirectory() {
|
||||||
if (LOG.isLoggable(INFO))
|
|
||||||
LOG.info("Database directory: " + dbDir.getAbsolutePath());
|
|
||||||
return dbDir;
|
return dbDir;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public File getDatabaseKeyDirectory() {
|
public File getDatabaseKeyDirectory() {
|
||||||
if (LOG.isLoggable(INFO))
|
|
||||||
LOG.info("Database key directory: " + keyDir.getAbsolutePath());
|
|
||||||
return keyDir;
|
return keyDir;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setEncryptionKey(SecretKey key) {
|
|
||||||
LOG.info("Setting database key");
|
|
||||||
this.key = key;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setLocalAuthorName(String nickname) {
|
|
||||||
LOG.info("Setting local author name");
|
|
||||||
this.nickname = nickname;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
@Nullable
|
|
||||||
public String getLocalAuthorName() {
|
|
||||||
String nickname = this.nickname;
|
|
||||||
if (LOG.isLoggable(INFO))
|
|
||||||
LOG.info("Local author name has been set: " + (nickname != null));
|
|
||||||
return nickname;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
@Nullable
|
|
||||||
public SecretKey getEncryptionKey() {
|
|
||||||
SecretKey key = this.key;
|
|
||||||
if (LOG.isLoggable(INFO))
|
|
||||||
LOG.info("Database key has been set: " + (key != null));
|
|
||||||
return key;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public long getMaxSize() {
|
public long getMaxSize() {
|
||||||
return Long.MAX_VALUE;
|
return Long.MAX_VALUE;
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ package org.briarproject.briar.android;
|
|||||||
|
|
||||||
import android.annotation.TargetApi;
|
import android.annotation.TargetApi;
|
||||||
import android.app.Application;
|
import android.app.Application;
|
||||||
|
import android.app.Notification;
|
||||||
import android.app.NotificationChannel;
|
import android.app.NotificationChannel;
|
||||||
import android.app.NotificationManager;
|
import android.app.NotificationManager;
|
||||||
import android.app.PendingIntent;
|
import android.app.PendingIntent;
|
||||||
@@ -10,8 +11,8 @@ import android.content.Intent;
|
|||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
import android.support.annotation.StringRes;
|
import android.support.annotation.StringRes;
|
||||||
import android.support.annotation.UiThread;
|
import android.support.annotation.UiThread;
|
||||||
|
import android.support.v4.app.NotificationCompat;
|
||||||
import android.support.v4.app.TaskStackBuilder;
|
import android.support.v4.app.TaskStackBuilder;
|
||||||
import android.support.v4.content.ContextCompat;
|
|
||||||
|
|
||||||
import org.briarproject.bramble.api.Multiset;
|
import org.briarproject.bramble.api.Multiset;
|
||||||
import org.briarproject.bramble.api.contact.ContactId;
|
import org.briarproject.bramble.api.contact.ContactId;
|
||||||
@@ -33,8 +34,10 @@ import org.briarproject.bramble.util.StringUtils;
|
|||||||
import org.briarproject.briar.R;
|
import org.briarproject.briar.R;
|
||||||
import org.briarproject.briar.android.contact.ConversationActivity;
|
import org.briarproject.briar.android.contact.ConversationActivity;
|
||||||
import org.briarproject.briar.android.forum.ForumActivity;
|
import org.briarproject.briar.android.forum.ForumActivity;
|
||||||
|
import org.briarproject.briar.android.login.SignInReminderReceiver;
|
||||||
import org.briarproject.briar.android.navdrawer.NavDrawerActivity;
|
import org.briarproject.briar.android.navdrawer.NavDrawerActivity;
|
||||||
import org.briarproject.briar.android.privategroup.conversation.GroupActivity;
|
import org.briarproject.briar.android.privategroup.conversation.GroupActivity;
|
||||||
|
import org.briarproject.briar.android.splash.SplashScreenActivity;
|
||||||
import org.briarproject.briar.android.util.BriarNotificationBuilder;
|
import org.briarproject.briar.android.util.BriarNotificationBuilder;
|
||||||
import org.briarproject.briar.api.android.AndroidNotificationManager;
|
import org.briarproject.briar.api.android.AndroidNotificationManager;
|
||||||
import org.briarproject.briar.api.blog.event.BlogPostAddedEvent;
|
import org.briarproject.briar.api.blog.event.BlogPostAddedEvent;
|
||||||
@@ -62,13 +65,19 @@ import javax.inject.Inject;
|
|||||||
import static android.app.Notification.DEFAULT_LIGHTS;
|
import static android.app.Notification.DEFAULT_LIGHTS;
|
||||||
import static android.app.Notification.DEFAULT_SOUND;
|
import static android.app.Notification.DEFAULT_SOUND;
|
||||||
import static android.app.Notification.DEFAULT_VIBRATE;
|
import static android.app.Notification.DEFAULT_VIBRATE;
|
||||||
import static android.app.Notification.VISIBILITY_SECRET;
|
|
||||||
import static android.app.NotificationManager.IMPORTANCE_DEFAULT;
|
import static android.app.NotificationManager.IMPORTANCE_DEFAULT;
|
||||||
|
import static android.app.NotificationManager.IMPORTANCE_LOW;
|
||||||
import static android.content.Context.NOTIFICATION_SERVICE;
|
import static android.content.Context.NOTIFICATION_SERVICE;
|
||||||
import static android.content.Intent.FLAG_ACTIVITY_CLEAR_TOP;
|
import static android.content.Intent.FLAG_ACTIVITY_CLEAR_TOP;
|
||||||
|
import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
|
||||||
import static android.os.Build.VERSION.SDK_INT;
|
import static android.os.Build.VERSION.SDK_INT;
|
||||||
import static android.support.v4.app.NotificationCompat.CATEGORY_MESSAGE;
|
import static android.support.v4.app.NotificationCompat.CATEGORY_MESSAGE;
|
||||||
|
import static android.support.v4.app.NotificationCompat.CATEGORY_SERVICE;
|
||||||
import static android.support.v4.app.NotificationCompat.CATEGORY_SOCIAL;
|
import static android.support.v4.app.NotificationCompat.CATEGORY_SOCIAL;
|
||||||
|
import static android.support.v4.app.NotificationCompat.PRIORITY_LOW;
|
||||||
|
import static android.support.v4.app.NotificationCompat.PRIORITY_MIN;
|
||||||
|
import static android.support.v4.app.NotificationCompat.VISIBILITY_SECRET;
|
||||||
|
import static android.support.v4.content.ContextCompat.getColor;
|
||||||
import static java.util.logging.Level.WARNING;
|
import static java.util.logging.Level.WARNING;
|
||||||
import static org.briarproject.bramble.util.LogUtils.logException;
|
import static org.briarproject.bramble.util.LogUtils.logException;
|
||||||
import static org.briarproject.briar.android.activity.BriarActivity.GROUP_ID;
|
import static org.briarproject.briar.android.activity.BriarActivity.GROUP_ID;
|
||||||
@@ -107,6 +116,7 @@ class AndroidNotificationManagerImpl implements AndroidNotificationManager,
|
|||||||
private int nextRequestId = 0;
|
private int nextRequestId = 0;
|
||||||
private ContactId blockedContact = null;
|
private ContactId blockedContact = null;
|
||||||
private GroupId blockedGroup = null;
|
private GroupId blockedGroup = null;
|
||||||
|
private boolean blockSignInReminder = false;
|
||||||
private boolean blockContacts = false, blockGroups = false;
|
private boolean blockContacts = false, blockGroups = false;
|
||||||
private boolean blockForums = false, blockBlogs = false;
|
private boolean blockForums = false, blockBlogs = false;
|
||||||
private boolean blockIntroductions = false;
|
private boolean blockIntroductions = false;
|
||||||
@@ -166,8 +176,7 @@ class AndroidNotificationManagerImpl implements AndroidNotificationManager,
|
|||||||
nc.setLockscreenVisibility(VISIBILITY_SECRET);
|
nc.setLockscreenVisibility(VISIBILITY_SECRET);
|
||||||
nc.enableVibration(true);
|
nc.enableVibration(true);
|
||||||
nc.enableLights(true);
|
nc.enableLights(true);
|
||||||
nc.setLightColor(
|
nc.setLightColor(getColor(appContext, R.color.briar_green_light));
|
||||||
ContextCompat.getColor(appContext, R.color.briar_green_light));
|
|
||||||
notificationManager.createNotificationChannel(nc);
|
notificationManager.createNotificationChannel(nc);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -264,6 +273,47 @@ class AndroidNotificationManagerImpl implements AndroidNotificationManager,
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@UiThread
|
||||||
|
@Override
|
||||||
|
public Notification getForegroundNotification() {
|
||||||
|
return getForegroundNotification(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
@UiThread
|
||||||
|
private Notification getForegroundNotification(boolean locked) {
|
||||||
|
int title = locked ? R.string.lock_is_locked :
|
||||||
|
R.string.ongoing_notification_title;
|
||||||
|
int text = locked ? R.string.lock_tap_to_unlock :
|
||||||
|
R.string.ongoing_notification_text;
|
||||||
|
int icon = locked ? R.drawable.startup_lock :
|
||||||
|
R.drawable.notification_ongoing;
|
||||||
|
// Ongoing foreground notification that shows BriarService is running
|
||||||
|
NotificationCompat.Builder b =
|
||||||
|
new NotificationCompat.Builder(appContext, ONGOING_CHANNEL_ID);
|
||||||
|
b.setSmallIcon(icon);
|
||||||
|
b.setColor(getColor(appContext, R.color.briar_primary));
|
||||||
|
b.setContentTitle(appContext.getText(title));
|
||||||
|
b.setContentText(appContext.getText(text));
|
||||||
|
b.setWhen(0); // Don't show the time
|
||||||
|
b.setOngoing(true);
|
||||||
|
Intent i = new Intent(appContext, NavDrawerActivity.class);
|
||||||
|
i.setFlags(FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_CLEAR_TOP);
|
||||||
|
b.setContentIntent(PendingIntent.getActivity(appContext, 0, i, 0));
|
||||||
|
if (SDK_INT >= 21) {
|
||||||
|
b.setCategory(CATEGORY_SERVICE);
|
||||||
|
b.setVisibility(VISIBILITY_SECRET);
|
||||||
|
}
|
||||||
|
b.setPriority(PRIORITY_MIN);
|
||||||
|
return b.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
@UiThread
|
||||||
|
@Override
|
||||||
|
public void updateForegroundNotification(boolean locked) {
|
||||||
|
Notification n = getForegroundNotification(locked);
|
||||||
|
notificationManager.notify(ONGOING_NOTIFICATION_ID, n);
|
||||||
|
}
|
||||||
|
|
||||||
private void showContactNotification(ContactId c) {
|
private void showContactNotification(ContactId c) {
|
||||||
androidExecutor.runOnUiThread(() -> {
|
androidExecutor.runOnUiThread(() -> {
|
||||||
if (blockContacts) return;
|
if (blockContacts) return;
|
||||||
@@ -612,6 +662,58 @@ class AndroidNotificationManagerImpl implements AndroidNotificationManager,
|
|||||||
this::clearIntroductionSuccessNotification);
|
this::clearIntroductionSuccessNotification);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void showSignInNotification() {
|
||||||
|
if (blockSignInReminder) return;
|
||||||
|
if (SDK_INT >= 26) {
|
||||||
|
NotificationChannel channel =
|
||||||
|
new NotificationChannel(REMINDER_CHANNEL_ID, appContext
|
||||||
|
.getString(
|
||||||
|
R.string.reminder_notification_channel_title),
|
||||||
|
IMPORTANCE_LOW);
|
||||||
|
channel.setLockscreenVisibility(
|
||||||
|
NotificationCompat.VISIBILITY_SECRET);
|
||||||
|
notificationManager.createNotificationChannel(channel);
|
||||||
|
}
|
||||||
|
|
||||||
|
NotificationCompat.Builder b =
|
||||||
|
new NotificationCompat.Builder(appContext, REMINDER_CHANNEL_ID);
|
||||||
|
b.setSmallIcon(R.drawable.ic_signout);
|
||||||
|
b.setColor(getColor(appContext, R.color.briar_primary));
|
||||||
|
b.setContentTitle(
|
||||||
|
appContext.getText(R.string.reminder_notification_title));
|
||||||
|
b.setContentText(
|
||||||
|
appContext.getText(R.string.reminder_notification_text));
|
||||||
|
b.setAutoCancel(true);
|
||||||
|
b.setWhen(0); // Don't show the time
|
||||||
|
b.setPriority(PRIORITY_LOW);
|
||||||
|
|
||||||
|
// Add a 'Dismiss' action
|
||||||
|
String actionTitle =
|
||||||
|
appContext.getString(R.string.reminder_notification_dismiss);
|
||||||
|
Intent i1 = new Intent(appContext, SignInReminderReceiver.class);
|
||||||
|
i1.setAction(ACTION_DISMISS_REMINDER);
|
||||||
|
PendingIntent actionIntent =
|
||||||
|
PendingIntent.getBroadcast(appContext, 0, i1, 0);
|
||||||
|
b.addAction(0, actionTitle, actionIntent);
|
||||||
|
|
||||||
|
Intent i = new Intent(appContext, SplashScreenActivity.class);
|
||||||
|
i.setFlags(FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_CLEAR_TOP);
|
||||||
|
b.setContentIntent(PendingIntent.getActivity(appContext, 0, i, 0));
|
||||||
|
|
||||||
|
notificationManager.notify(REMINDER_NOTIFICATION_ID, b.build());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void clearSignInNotification() {
|
||||||
|
notificationManager.cancel(REMINDER_NOTIFICATION_ID);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void blockSignInNotification() {
|
||||||
|
blockSignInReminder = true;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void blockNotification(GroupId g) {
|
public void blockNotification(GroupId g) {
|
||||||
androidExecutor.runOnUiThread((Runnable) () -> blockedGroup = g);
|
androidExecutor.runOnUiThread((Runnable) () -> blockedGroup = g);
|
||||||
|
|||||||
@@ -11,9 +11,8 @@ import org.briarproject.bramble.api.db.DatabaseConfig;
|
|||||||
import org.briarproject.bramble.api.event.EventBus;
|
import org.briarproject.bramble.api.event.EventBus;
|
||||||
import org.briarproject.bramble.api.lifecycle.IoExecutor;
|
import org.briarproject.bramble.api.lifecycle.IoExecutor;
|
||||||
import org.briarproject.bramble.api.lifecycle.LifecycleManager;
|
import org.briarproject.bramble.api.lifecycle.LifecycleManager;
|
||||||
import org.briarproject.bramble.api.nullsafety.MethodsNotNullByDefault;
|
import org.briarproject.bramble.api.network.NetworkManager;
|
||||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||||
import org.briarproject.bramble.api.nullsafety.ParametersNotNullByDefault;
|
|
||||||
import org.briarproject.bramble.api.plugin.BackoffFactory;
|
import org.briarproject.bramble.api.plugin.BackoffFactory;
|
||||||
import org.briarproject.bramble.api.plugin.PluginConfig;
|
import org.briarproject.bramble.api.plugin.PluginConfig;
|
||||||
import org.briarproject.bramble.api.plugin.duplex.DuplexPluginFactory;
|
import org.briarproject.bramble.api.plugin.duplex.DuplexPluginFactory;
|
||||||
@@ -22,15 +21,18 @@ import org.briarproject.bramble.api.reporting.DevConfig;
|
|||||||
import org.briarproject.bramble.api.system.AndroidExecutor;
|
import org.briarproject.bramble.api.system.AndroidExecutor;
|
||||||
import org.briarproject.bramble.api.system.Clock;
|
import org.briarproject.bramble.api.system.Clock;
|
||||||
import org.briarproject.bramble.api.system.LocationUtils;
|
import org.briarproject.bramble.api.system.LocationUtils;
|
||||||
|
import org.briarproject.bramble.api.system.ResourceProvider;
|
||||||
import org.briarproject.bramble.api.system.Scheduler;
|
import org.briarproject.bramble.api.system.Scheduler;
|
||||||
import org.briarproject.bramble.plugin.bluetooth.AndroidBluetoothPluginFactory;
|
import org.briarproject.bramble.plugin.bluetooth.AndroidBluetoothPluginFactory;
|
||||||
import org.briarproject.bramble.plugin.tcp.AndroidLanTcpPluginFactory;
|
import org.briarproject.bramble.plugin.tcp.AndroidLanTcpPluginFactory;
|
||||||
|
import org.briarproject.bramble.plugin.tor.AndroidTorPluginFactory;
|
||||||
import org.briarproject.bramble.plugin.tor.CircumventionProvider;
|
import org.briarproject.bramble.plugin.tor.CircumventionProvider;
|
||||||
import org.briarproject.bramble.plugin.tor.TorPluginFactory;
|
|
||||||
import org.briarproject.bramble.util.AndroidUtils;
|
import org.briarproject.bramble.util.AndroidUtils;
|
||||||
import org.briarproject.bramble.util.StringUtils;
|
import org.briarproject.bramble.util.StringUtils;
|
||||||
|
import org.briarproject.briar.android.account.LockManagerImpl;
|
||||||
import org.briarproject.briar.api.android.AndroidNotificationManager;
|
import org.briarproject.briar.api.android.AndroidNotificationManager;
|
||||||
import org.briarproject.briar.api.android.DozeWatchdog;
|
import org.briarproject.briar.api.android.DozeWatchdog;
|
||||||
|
import org.briarproject.briar.api.android.LockManager;
|
||||||
import org.briarproject.briar.api.android.ScreenFilterMonitor;
|
import org.briarproject.briar.api.android.ScreenFilterMonitor;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
@@ -86,11 +88,7 @@ public class AppModule {
|
|||||||
File dbDir = app.getApplicationContext().getDir("db", MODE_PRIVATE);
|
File dbDir = app.getApplicationContext().getDir("db", MODE_PRIVATE);
|
||||||
File keyDir = app.getApplicationContext().getDir("key", MODE_PRIVATE);
|
File keyDir = app.getApplicationContext().getDir("key", MODE_PRIVATE);
|
||||||
StrictMode.setThreadPolicy(tp);
|
StrictMode.setThreadPolicy(tp);
|
||||||
@MethodsNotNullByDefault
|
return new AndroidDatabaseConfig(dbDir, keyDir);
|
||||||
@ParametersNotNullByDefault
|
|
||||||
DatabaseConfig databaseConfig =
|
|
||||||
new AndroidDatabaseConfig(dbDir, keyDir);
|
|
||||||
return databaseConfig;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Provides
|
@Provides
|
||||||
@@ -98,17 +96,20 @@ public class AppModule {
|
|||||||
@Scheduler ScheduledExecutorService scheduler,
|
@Scheduler ScheduledExecutorService scheduler,
|
||||||
AndroidExecutor androidExecutor, SecureRandom random,
|
AndroidExecutor androidExecutor, SecureRandom random,
|
||||||
SocketFactory torSocketFactory, BackoffFactory backoffFactory,
|
SocketFactory torSocketFactory, BackoffFactory backoffFactory,
|
||||||
Application app, LocationUtils locationUtils, EventBus eventBus,
|
Application app, NetworkManager networkManager,
|
||||||
|
LocationUtils locationUtils, EventBus eventBus,
|
||||||
|
ResourceProvider resourceProvider,
|
||||||
CircumventionProvider circumventionProvider, Clock clock) {
|
CircumventionProvider circumventionProvider, Clock clock) {
|
||||||
Context appContext = app.getApplicationContext();
|
Context appContext = app.getApplicationContext();
|
||||||
DuplexPluginFactory bluetooth =
|
DuplexPluginFactory bluetooth =
|
||||||
new AndroidBluetoothPluginFactory(ioExecutor, androidExecutor,
|
new AndroidBluetoothPluginFactory(ioExecutor, androidExecutor,
|
||||||
appContext, random, eventBus, backoffFactory);
|
appContext, random, eventBus, backoffFactory);
|
||||||
DuplexPluginFactory tor = new TorPluginFactory(ioExecutor, scheduler,
|
DuplexPluginFactory tor = new AndroidTorPluginFactory(ioExecutor,
|
||||||
appContext, locationUtils, eventBus, torSocketFactory,
|
scheduler, appContext, networkManager, locationUtils, eventBus,
|
||||||
backoffFactory, circumventionProvider, clock);
|
torSocketFactory, backoffFactory, resourceProvider,
|
||||||
|
circumventionProvider, clock);
|
||||||
DuplexPluginFactory lan = new AndroidLanTcpPluginFactory(ioExecutor,
|
DuplexPluginFactory lan = new AndroidLanTcpPluginFactory(ioExecutor,
|
||||||
scheduler, backoffFactory, appContext);
|
eventBus, backoffFactory, appContext);
|
||||||
Collection<DuplexPluginFactory> duplex = asList(bluetooth, tor, lan);
|
Collection<DuplexPluginFactory> duplex = asList(bluetooth, tor, lan);
|
||||||
@NotNullByDefault
|
@NotNullByDefault
|
||||||
PluginConfig pluginConfig = new PluginConfig() {
|
PluginConfig pluginConfig = new PluginConfig() {
|
||||||
@@ -162,6 +163,7 @@ public class AppModule {
|
|||||||
|
|
||||||
@Provides
|
@Provides
|
||||||
SharedPreferences provideSharedPreferences(Application app) {
|
SharedPreferences provideSharedPreferences(Application app) {
|
||||||
|
// FIXME unify this with getDefaultSharedPreferences()
|
||||||
return app.getSharedPreferences("db", MODE_PRIVATE);
|
return app.getSharedPreferences("db", MODE_PRIVATE);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -200,4 +202,13 @@ public class AppModule {
|
|||||||
return dozeWatchdog;
|
return dozeWatchdog;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Provides
|
||||||
|
@Singleton
|
||||||
|
LockManager provideLockManager(LifecycleManager lifecycleManager,
|
||||||
|
EventBus eventBus, LockManagerImpl lockManager) {
|
||||||
|
lifecycleManager.registerService(lockManager);
|
||||||
|
eventBus.addListener(lockManager);
|
||||||
|
return lockManager;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user