Compare commits

..

7 Commits

Author SHA1 Message Date
akwizgran
fb7d4076ab Use magic wake lock tag for Huawei devices. 2018-09-07 13:32:22 +01:00
akwizgran
a3083a6e73 Use a constant to enable the control condition. 2018-08-30 18:10:18 +01:00
akwizgran
c1fcae7de3 Add more logging for sleep and alarms. 2018-08-30 17:43:22 +01:00
Shannon Stork
35c1f50650 Added sleep and power status logging 2018-08-08 21:27:50 -04:00
Shannon Stork
f2c50b500e Acquire wakelock when alarm goes off 2018-08-07 10:38:57 -04:00
akwizgran
0776ab85b6 Use elapsed real time, postDelayed() instead of sleep(). 2018-07-26 10:51:00 +01:00
Shannon Stork
f77bde4edf Attempt to acquire wakelock when alarm goes off (DOES NOT WORK) 2018-07-25 19:20:54 -04:00
223 changed files with 2589 additions and 4418 deletions

1
.gitignore vendored
View File

@@ -23,6 +23,5 @@ local.properties
!.idea/codeStyles !.idea/codeStyles
.gradle .gradle
build/ build/
captures
*.iml *.iml
projectFilesBackup/ projectFilesBackup/

View File

@@ -11,8 +11,8 @@ test:
- .gradle/caches - .gradle/caches
script: script:
- ./gradlew --no-daemon -Djava.security.egd=file:/dev/urandom animalSnifferMain animalSnifferTest - ./gradlew --no-daemon animalSnifferMain animalSnifferTest
- ./gradlew --no-daemon -Djava.security.egd=file:/dev/urandom test - ./gradlew --no-daemon 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

View File

@@ -21,7 +21,6 @@
<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>

View File

@@ -1,23 +0,0 @@
<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>

View File

@@ -1,6 +1,5 @@
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
@@ -9,8 +8,8 @@ android {
defaultConfig { defaultConfig {
minSdkVersion 14 minSdkVersion 14
targetSdkVersion 26 targetSdkVersion 26
versionCode 10013 versionCode 10011
versionName "1.0.13" versionName "1.0.11"
consumerProguardFiles 'proguard-rules.txt' consumerProguardFiles 'proguard-rules.txt'
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
@@ -28,20 +27,13 @@ configurations {
dependencies { dependencies {
implementation project(path: ':bramble-core', configuration: 'default') implementation project(path: ':bramble-core', configuration: 'default')
tor 'org.briarproject:tor-android:0.2.9.16@zip' implementation 'org.briarproject:jtorctl:0.3'
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'
@@ -49,14 +41,89 @@ 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')
}

View File

@@ -1,6 +1,5 @@
package org.briarproject.bramble.test; package org.briarproject.bramble;
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;
@@ -13,13 +12,11 @@ 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 BrambleAndroidIntegrationTestComponent { public interface IntegrationTestComponent {
void inject(BridgeTest init); void inject(BridgeTest init);

View File

@@ -3,16 +3,14 @@ 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;
@@ -41,14 +39,8 @@ 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.getName()); Logger.getLogger(BridgeTest.class.getSimpleName());
@Inject
NetworkManager networkManager;
@Inject
ResourceProvider resourceProvider;
@Inject
CircumventionProvider circumventionProvider;
@Inject @Inject
EventBus eventBus; EventBus eventBus;
@Inject @Inject
@@ -56,27 +48,15 @@ public class BridgeTest extends BrambleTestCase {
@Inject @Inject
Clock clock; Clock clock;
private final Context appContext = private final Context appContext = getTargetContext();
getTargetContext().getApplicationContext(); private final CircumventionProvider circumventionProvider;
private final List<String> bridges;
private TorPluginFactory factory;
private volatile int currentBridge = 0;
private List<String> bridges; public BridgeTest() {
private AndroidTorPluginFactory factory; super();
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;
@@ -89,29 +69,45 @@ public class BridgeTest extends BrambleTestCase {
@Override @Override
public List<String> getBridges() { public List<String> getBridges() {
return singletonList(currentBridge); return singletonList(bridges.get(currentBridge));
} }
}; };
factory = new AndroidTorPluginFactory(ioExecutor, scheduler, appContext, bridges = new CircumventionProviderImpl(appContext).getBridges();
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 (String bridge : bridges) testBridge(bridge); for (int i = 0; i < bridges.size(); i++) {
testBridge(i);
}
} }
private void testBridge(String bridge) throws Exception { private void testBridge(int bridge) throws Exception {
DuplexPlugin duplexPlugin = DuplexPlugin duplexPlugin =
factory.createPlugin(new TorPluginCallBack()); factory.createPlugin(new TorPluginCallBack());
assertNotNull(duplexPlugin); assertNotNull(duplexPlugin);
AndroidTorPlugin plugin = (AndroidTorPlugin) duplexPlugin; TorPlugin plugin = (TorPlugin) duplexPlugin;
currentBridge = bridge; currentBridge = bridge;
LOG.warning("Testing " + bridge); LOG.warning("Testing " + bridges.get(currentBridge));
try { try {
plugin.start(); plugin.start();
long start = clock.currentTimeMillis(); long start = clock.currentTimeMillis();

View File

@@ -1,20 +0,0 @@
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();
}
}

View File

@@ -2,13 +2,14 @@
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" android:required="false"/> <uses-feature android:name="android.hardware.bluetooth"/>
<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

View File

@@ -1,16 +1,25 @@
package org.briarproject.bramble; package org.briarproject.bramble;
import org.briarproject.bramble.network.AndroidNetworkModule; import android.app.Application;
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 = {
AndroidNetworkModule.class, AndroidSystemModule.class
AndroidSystemModule.class,
CircumventionModule.class
}) })
public class BrambleAndroidModule { public class BrambleAndroidModule {
@Provides
@Singleton
CircumventionProvider provideCircumventionProvider(Application app) {
return new CircumventionProviderImpl(app.getApplicationContext());
}
} }

View File

@@ -0,0 +1,8 @@
package org.briarproject.bramble;
public interface PowerTestingConstants {
int WAKE_LOCK_DURATION = 5000;
int ALARM_DELAY = 5000;
boolean USE_TOR_WAKE_LOCK = true;
}

View File

@@ -1,108 +0,0 @@
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");
}
}

View File

@@ -1,142 +0,0 @@
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);
}
}
}

View File

@@ -1,21 +0,0 @@
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;
}
}

View File

@@ -1,16 +1,15 @@
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;
@@ -21,6 +20,7 @@ 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,13 +28,21 @@ 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 implements EventListener { class AndroidLanTcpPlugin extends LanTcpPlugin {
// 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};
@@ -52,20 +60,22 @@ class AndroidLanTcpPlugin extends LanTcpPlugin implements EventListener {
} }
} }
private final Executor connectionStatusExecutor; private final ScheduledExecutorService scheduler;
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, Context appContext, AndroidLanTcpPlugin(Executor ioExecutor, ScheduledExecutorService scheduler,
Backoff backoff, DuplexPluginCallback callback, int maxLatency, Backoff backoff, Context appContext, DuplexPluginCallback callback,
int maxIdleTime) { int maxLatency, int maxIdleTime) {
super(ioExecutor, backoff, callback, maxLatency, maxIdleTime); super(ioExecutor, backoff, callback, maxLatency, maxIdleTime);
// Don't execute more than one connection status check at a time this.scheduler = scheduler;
connectionStatusExecutor = this.appContext = appContext;
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();
@@ -79,12 +89,19 @@ class AndroidLanTcpPlugin extends LanTcpPlugin implements EventListener {
public void start() { public void start() {
if (used.getAndSet(true)) throw new IllegalStateException(); if (used.getAndSet(true)) throw new IllegalStateException();
running = true; running = true;
updateConnectionStatus(); // Register to receive network status events
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);
} }
@@ -103,7 +120,7 @@ class AndroidLanTcpPlugin extends LanTcpPlugin implements EventListener {
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();
} }
@@ -135,13 +152,21 @@ class AndroidLanTcpPlugin extends LanTcpPlugin implements EventListener {
return SocketFactory.getDefault(); return SocketFactory.getDefault();
} }
@Override private class NetworkStateReceiver extends BroadcastReceiver {
public void eventOccurred(Event e) {
if (e instanceof NetworkStatusEvent) updateConnectionStatus();
}
private void updateConnectionStatus() { @Override
connectionStatusExecutor.execute(() -> { public void onReceive(Context ctx, Intent i) {
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)) {
@@ -161,6 +186,11 @@ class AndroidLanTcpPlugin extends LanTcpPlugin implements EventListener {
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;
}
} }
} }

View File

@@ -2,7 +2,6 @@ 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;
@@ -12,6 +11,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 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,14 +28,15 @@ 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 EventBus eventBus; private final ScheduledExecutorService scheduler;
private final BackoffFactory backoffFactory; private final BackoffFactory backoffFactory;
private final Context appContext; private final Context appContext;
public AndroidLanTcpPluginFactory(Executor ioExecutor, EventBus eventBus, public AndroidLanTcpPluginFactory(Executor ioExecutor,
BackoffFactory backoffFactory, Context appContext) { ScheduledExecutorService scheduler, BackoffFactory backoffFactory,
Context appContext) {
this.ioExecutor = ioExecutor; this.ioExecutor = ioExecutor;
this.eventBus = eventBus; this.scheduler = scheduler;
this.backoffFactory = backoffFactory; this.backoffFactory = backoffFactory;
this.appContext = appContext; this.appContext = appContext;
} }
@@ -54,9 +55,7 @@ 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);
AndroidLanTcpPlugin plugin = new AndroidLanTcpPlugin(ioExecutor, return new AndroidLanTcpPlugin(ioExecutor, scheduler, backoff,
appContext, backoff, callback, MAX_LATENCY, MAX_IDLE_TIME); appContext, callback, MAX_LATENCY, MAX_IDLE_TIME);
eventBus.addListener(plugin);
return plugin;
} }
} }

View File

@@ -1,88 +0,0 @@
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();
}
}

View File

@@ -4,8 +4,6 @@ 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 {
/** /**

View File

@@ -1,10 +1,13 @@
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;
@@ -13,27 +16,24 @@ import java.util.Set;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import javax.inject.Inject; import javax.inject.Inject;
import static java.util.Arrays.asList; public class CircumventionProviderImpl implements CircumventionProvider {
class CircumventionProviderImpl implements CircumventionProvider {
private final static String BRIDGE_FILE_NAME = "bridges"; private final static String BRIDGE_FILE_NAME = "bridges";
private static final Set<String> BLOCKED_IN_COUNTRIES = private final Context ctx;
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
CircumventionProviderImpl(ResourceProvider resourceProvider) { public CircumventionProviderImpl(Context ctx) {
this.resourceProvider = resourceProvider; this.ctx = ctx;
} }
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,14 +47,15 @@ class CircumventionProviderImpl implements CircumventionProvider {
@Override @Override
@IoExecutor @IoExecutor
public List<String> getBridges() { public List<String> getBridges() {
List<String> bridges = this.bridges; if (this.bridges != null) return this.bridges;
if (bridges != null) return new ArrayList<>(bridges);
InputStream is = Resources res = ctx.getResources();
resourceProvider.getResourceInputStream(BRIDGE_FILE_NAME); int resId = res.getIdentifier(BRIDGE_FILE_NAME, "raw",
ctx.getPackageName());
InputStream is = ctx.getResources().openRawResource(resId);
Scanner scanner = new Scanner(is); Scanner scanner = new Scanner(is);
bridges = new ArrayList<>(); List<String> 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);

View File

@@ -1,5 +1,17 @@
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;
@@ -9,9 +21,6 @@ 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;
@@ -26,8 +35,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;
@@ -50,7 +59,10 @@ 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;
@@ -58,13 +70,24 @@ 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;
@@ -76,10 +99,7 @@ import static org.briarproject.bramble.util.PrivacyUtils.scrubOnion;
@MethodsNotNullByDefault @MethodsNotNullByDefault
@ParametersNotNullByDefault @ParametersNotNullByDefault
abstract class TorPlugin implements DuplexPlugin, EventHandler, EventListener { 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"
@@ -88,9 +108,14 @@ abstract 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 NetworkManager networkManager; private final ScheduledExecutorService scheduler;
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;
@@ -98,54 +123,55 @@ abstract 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 ConnectionStatus connectionStatus; private final RenewableWakeLock wakeLock;
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;
protected volatile boolean running = false; TorPlugin(Executor ioExecutor, ScheduledExecutorService scheduler,
Context appContext, LocationUtils locationUtils,
protected abstract int getProcessId(); SocketFactory torSocketFactory, Clock clock, Backoff backoff,
DuplexPluginCallback callback, String architecture,
protected abstract long getLastUpdateTime(); CircumventionProvider circumventionProvider, int maxLatency, int maxIdleTime) {
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.networkManager = networkManager; this.scheduler = scheduler;
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;
this.torDirectory = torDirectory; connectionStatus = new ConnectionStatus();
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 = connectionStatusExecutor = new PoliteExecutor("TorPlugin",
new PoliteExecutor("TorPlugin", ioExecutor, 1); ioExecutor, 1);
PowerManager pm = (PowerManager)
appContext.getSystemService(POWER_SERVICE);
wakeLock = new RenewableWakeLock(pm, scheduler, PARTIAL_WAKE_LOCK,
WAKE_LOCK_TAG, 1, MINUTES);
} }
@Override @Override
@@ -174,7 +200,7 @@ abstract 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(getProcessId()); String pid = String.valueOf(android.os.Process.myPid());
Process torProcess; Process torProcess;
ProcessBuilder pb = ProcessBuilder pb =
new ProcessBuilder(torPath, "-f", configPath, OWNER, pid); new ProcessBuilder(torPath, "-f", configPath, OWNER, pid);
@@ -246,14 +272,26 @@ abstract class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
} catch (IOException e) { } catch (IOException e) {
throw new PluginException(e); throw new PluginException(e);
} }
// Check whether we're online // Register to receive network status events
updateConnectionStatus(networkManager.getNetworkStatus()); networkStateReceiver = new NetworkStateReceiver();
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() {
return doneFile.lastModified() > getLastUpdateTime(); try {
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 {
@@ -286,22 +324,29 @@ abstract 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);
InputStream in = int resId = getResourceId("tor_" + architecture);
resourceProvider.getResourceInputStream("tor_" + architecture); 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 getGeoIpInputStream() throws IOException { private InputStream getGeoIpInputStream() throws IOException {
InputStream in = resourceProvider.getResourceInputStream("geoip"); int resId = getResourceId("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() {
return resourceProvider.getResourceInputStream("torrc"); int resId = getResourceId("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) {
@@ -447,11 +492,15 @@ abstract class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
} }
} }
protected void enableNetwork(boolean enable) throws IOException { private 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) callback.transportDisabled(); if (!enable) {
callback.transportDisabled();
if (USE_TOR_WAKE_LOCK) wakeLock.release();
}
} }
private void enableBridges(boolean enable) throws IOException { private void enableBridges(boolean enable) throws IOException {
@@ -469,6 +518,8 @@ abstract 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");
@@ -479,6 +530,7 @@ abstract class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
logException(LOG, WARNING, e); logException(LOG, WARNING, e);
} }
} }
if (USE_TOR_WAKE_LOCK) wakeLock.release();
} }
@Override @Override
@@ -529,6 +581,7 @@ abstract 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))
@@ -577,10 +630,8 @@ abstract 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"))
// Check whether we've lost connectivity updateConnectionStatus(); // Check whether we've lost connectivity
updateConnectionStatus(networkManager.getNetworkStatus());
}
} }
@Override @Override
@@ -613,25 +664,24 @@ abstract 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(networkManager.getNetworkStatus()); updateConnectionStatus();
} }
} else if (e instanceof NetworkStatusEvent) {
updateConnectionStatus(((NetworkStatusEvent) e).getStatus());
} }
} }
private void updateConnectionStatus(NetworkStatus status) { private void updateConnectionStatus() {
connectionStatusExecutor.execute(() -> { connectionStatusExecutor.execute(() -> {
if (!running) return; if (!running) return;
boolean online = status.isConnected(); Object o = appContext.getSystemService(CONNECTIVITY_SERVICE);
boolean wifi = status.isWifi(); ConnectivityManager cm = (ConnectivityManager) o;
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);
@@ -652,13 +702,9 @@ abstract 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 if (disableWhenBlocked) { } else {
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");
@@ -671,6 +717,29 @@ abstract 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

View File

@@ -4,7 +4,6 @@ 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;
@@ -15,7 +14,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 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;
@@ -27,10 +25,10 @@ import javax.net.SocketFactory;
@Immutable @Immutable
@NotNullByDefault @NotNullByDefault
public class AndroidTorPluginFactory implements DuplexPluginFactory { public class TorPluginFactory implements DuplexPluginFactory {
private static final Logger LOG = private static final Logger LOG =
Logger.getLogger(AndroidTorPluginFactory.class.getName()); Logger.getLogger(TorPluginFactory.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
@@ -41,30 +39,26 @@ public class AndroidTorPluginFactory 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 AndroidTorPluginFactory(Executor ioExecutor, public TorPluginFactory(Executor ioExecutor,
ScheduledExecutorService scheduler, Context appContext, ScheduledExecutorService scheduler, Context appContext,
NetworkManager networkManager, LocationUtils locationUtils, LocationUtils locationUtils, EventBus eventBus,
EventBus eventBus, SocketFactory torSocketFactory, SocketFactory torSocketFactory, BackoffFactory backoffFactory,
BackoffFactory backoffFactory, ResourceProvider resourceProvider, CircumventionProvider circumventionProvider,
CircumventionProvider circumventionProvider, Clock clock) { 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;
} }
@@ -102,10 +96,9 @@ public class AndroidTorPluginFactory 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);
AndroidTorPlugin plugin = new AndroidTorPlugin(ioExecutor, scheduler, TorPlugin plugin = new TorPlugin(ioExecutor, scheduler, appContext,
appContext, networkManager, locationUtils, torSocketFactory, locationUtils, torSocketFactory, clock, backoff, callback,
clock, resourceProvider, circumventionProvider, backoff, architecture, circumventionProvider, MAX_LATENCY, MAX_IDLE_TIME);
callback, architecture, MAX_LATENCY, MAX_IDLE_TIME);
eventBus.addListener(plugin); eventBus.addListener(plugin);
return plugin; return plugin;
} }

View File

@@ -1,30 +0,0 @@
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);
}
}

View File

@@ -1,8 +1,9 @@
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;
@@ -15,26 +16,18 @@ public class AndroidSystemModule {
@Provides @Provides
@Singleton @Singleton
SecureRandomProvider provideSecureRandomProvider( SecureRandomProvider provideSecureRandomProvider(Application app) {
AndroidSecureRandomProvider provider) { return new AndroidSecureRandomProvider(app);
return provider;
} }
@Provides @Provides
LocationUtils provideLocationUtils(AndroidLocationUtils locationUtils) { LocationUtils provideLocationUtils(Application app) {
return locationUtils; return new AndroidLocationUtils(app);
} }
@Provides @Provides
@Singleton @Singleton
AndroidExecutor provideAndroidExecutor( AndroidExecutor provideAndroidExecutor(Application app) {
AndroidExecutorImpl androidExecutor) { return new AndroidExecutorImpl(app);
return androidExecutor;
}
@Provides
@Singleton
ResourceProvider provideResourceProvider(AndroidResourceProvider provider) {
return provider;
} }
} }

View File

@@ -3,6 +3,7 @@ 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;
@@ -57,6 +58,30 @@ 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);
} }

View File

@@ -2,7 +2,4 @@ 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 195.91.239.8:9001 BA83F62551545655BBEBBFF353A45438D73FD45A #Bridge 128.105.214.161:8081 1E326AAFB3FCB515015250D8FCCC8E37F91A153B
Bridge 185.165.184.217:6429 64CC94BEC51254E4409AD059192833854CCB95F0
Bridge 45.55.1.74:8443 6F18FEFBB0CAECD5ABA755312FCCB34FC11A7AB8
Bridge 95.85.40.163:9001 40057BE9CF76B6C5BDBE713753468BE0A990DE9C

View File

@@ -1,162 +0,0 @@
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);
}
}

View File

@@ -1,94 +0,0 @@
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',
]
}

View File

@@ -4,7 +4,6 @@ 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"
@@ -20,6 +19,31 @@ 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)
@@ -31,8 +55,3 @@ 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')
}

View File

@@ -1,70 +0,0 @@
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);
}

View File

@@ -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(SecretKey)}. * {@link LifecycleManager#startServices(String)}.
*/ */
void registerContactHook(ContactHook hook); void registerContactHook(ContactHook hook);

View File

@@ -2,7 +2,6 @@ package org.briarproject.bramble.api.db;
import org.briarproject.bramble.api.contact.Contact; import org.briarproject.bramble.api.contact.Contact;
import org.briarproject.bramble.api.contact.ContactId; import org.briarproject.bramble.api.contact.ContactId;
import org.briarproject.bramble.api.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;
@@ -45,8 +44,7 @@ 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(SecretKey key, @Nullable MigrationListener listener) boolean open(@Nullable MigrationListener listener) throws DbException;
throws DbException;
/** /**
* Waits for any open transactions to finish and closes the database. * Waits for any open transactions to finish and closes the database.
@@ -269,7 +267,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.
@@ -489,7 +487,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.
@@ -536,7 +534,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.

View File

@@ -1,15 +1,30 @@
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();
} }

View File

@@ -1,6 +1,5 @@
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;
@@ -10,40 +9,29 @@ import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
public interface IdentityManager { public interface IdentityManager {
/** /**
* Creates a local identity with the given name. * Stores the local pseudonym.
*/ */
@CryptoExecutor void registerLocalAuthor(LocalAuthor a) throws DbException;
LocalAuthor createLocalAuthor(String name);
/** /**
* Registers the given local identity with the manager. The identity is * Returns the cached main local identity, non-blocking, or loads it from
* not stored until {@link #storeLocalAuthor()} is called. * the db, blocking
*/
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 local identity or loads it from the database. * Returns the cached main local identity, non-blocking, or loads it from
* the db, blocking, within the given Transaction.
*/ */
LocalAuthor getLocalAuthor(Transaction txn) throws DbException; LocalAuthor getLocalAuthor(Transaction txn) throws DbException;
/** /**
* Returns the {@link Status} of the given author. * Returns the trust-level status of the author
*/ */
Status getAuthorStatus(AuthorId a) throws DbException; Status getAuthorStatus(AuthorId a) throws DbException;
/** /**
* Returns the {@link Status} of the given author. * Returns the trust-level status of the author
*/ */
Status getAuthorStatus(Transaction txn, AuthorId a) throws DbException; Status getAuthorStatus(Transaction txn, AuthorId a) throws DbException;

View File

@@ -7,6 +7,16 @@ 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.
*/ */

View File

@@ -1,12 +1,13 @@
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
@@ -17,7 +18,7 @@ import java.util.concurrent.ExecutorService;
public interface LifecycleManager { public interface LifecycleManager {
/** /**
* The result of calling {@link #startServices(SecretKey)}. * The result of calling {@link #startServices(String)}.
*/ */
enum StartResult { enum StartResult {
ALREADY_RUNNING, ALREADY_RUNNING,
@@ -43,27 +44,28 @@ 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(SecretKey)}. * should be called before {@link #startServices(String)}.
*/ */
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(SecretKey)}. * before {@link #startServices(String)}.
*/ */
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(SecretKey)}. * should be called before {@link #startServices(String)}.
*/ */
void registerForShutdown(ExecutorService e); void registerForShutdown(ExecutorService e);
/** /**
* Opens the {@link DatabaseComponent} using the given key and starts any * Opens the {@link DatabaseComponent}, optionally creates a local author
* registered {@link Client Clients} and {@link Service Services}. * with the provided nickname, and starts any registered
* {@link Client Clients} and {@link Service Services}.
*/ */
StartResult startServices(SecretKey dbKey); StartResult startServices(@Nullable String nickname);
/** /**
* Stops any registered {@link Service Services}, shuts down any * Stops any registered {@link Service Services}, shuts down any

View File

@@ -1,9 +0,0 @@
package org.briarproject.bramble.api.network;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
@NotNullByDefault
public interface NetworkManager {
NetworkStatus getNetworkStatus();
}

View File

@@ -1,25 +0,0 @@
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;
}
}

View File

@@ -1,22 +0,0 @@
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;
}
}

View File

@@ -14,7 +14,6 @@ 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;

View File

@@ -1,6 +1,5 @@
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;
@@ -36,8 +35,7 @@ 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 * should be called before {@link LifecycleManager#startServices(String)}.
* {@link LifecycleManager#startServices(SecretKey)}.
*/ */
void registerMessageValidator(ClientId c, int majorVersion, void registerMessageValidator(ClientId c, int majorVersion,
MessageValidator v); MessageValidator v);
@@ -46,7 +44,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(SecretKey)}. * {@link LifecycleManager#startServices(String)}.
*/ */
void registerIncomingMessageHook(ClientId c, int majorVersion, void registerIncomingMessageHook(ClientId c, int majorVersion,
IncomingMessageHook hook); IncomingMessageHook hook);

View File

@@ -1,11 +0,0 @@
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);
}

View File

@@ -2,7 +2,6 @@ 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;
@@ -26,7 +25,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(SecretKey)}. * be called before {@link LifecycleManager#startServices(String)}.
*/ */
void registerClient(ClientId clientId, int majorVersion, int minorVersion, void registerClient(ClientId clientId, int majorVersion, int minorVersion,
ClientVersioningHook hook); ClientVersioningHook hook);

View File

@@ -1,24 +0,0 @@
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',
]
}

View File

@@ -6,7 +6,6 @@ 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')
@@ -15,7 +14,6 @@ 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'
@@ -33,6 +31,39 @@ 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)
@@ -44,8 +75,3 @@ 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')
}

View File

@@ -1,221 +0,0 @@
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);
}
}
}

View File

@@ -1,18 +0,0 @@
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;
}
}

View File

@@ -2,7 +2,6 @@ package org.briarproject.bramble.db;
import org.briarproject.bramble.api.contact.Contact; import org.briarproject.bramble.api.contact.Contact;
import org.briarproject.bramble.api.contact.ContactId; import org.briarproject.bramble.api.contact.ContactId;
import org.briarproject.bramble.api.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;
@@ -49,8 +48,7 @@ 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(SecretKey key, @Nullable MigrationListener listener) boolean open(@Nullable MigrationListener listener) throws DbException;
throws DbException;
/** /**
* Prevents new transactions from starting, waits for all current * Prevents new transactions from starting, waits for all current
@@ -643,7 +641,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

View File

@@ -6,7 +6,6 @@ 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;
@@ -104,9 +103,9 @@ class DatabaseComponentImpl<T> implements DatabaseComponent {
} }
@Override @Override
public boolean open(SecretKey key, @Nullable MigrationListener listener) public boolean open(@Nullable MigrationListener listener)
throws DbException { throws DbException {
boolean reopened = db.open(key, listener); boolean reopened = db.open(listener);
shutdown.addShutdownHook(() -> { shutdown.addShutdownHook(() -> {
try { try {
close(); close();

View File

@@ -32,9 +32,6 @@ 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,
@@ -47,11 +44,11 @@ class H2Database extends JdbcDatabase {
} }
@Override @Override
public boolean open(SecretKey key, @Nullable MigrationListener listener) public boolean open(@Nullable MigrationListener listener)
throws DbException { throws DbException {
this.key = key; boolean reopen = config.databaseExists();
boolean reopen = !config.getDatabaseDirectory().mkdirs(); if (!reopen) config.getDatabaseDirectory().mkdirs();
super.open("org.h2.Driver", reopen, key, listener); super.open("org.h2.Driver", reopen, listener);
return reopen; return reopen;
} }
@@ -66,7 +63,7 @@ class H2Database extends JdbcDatabase {
} }
@Override @Override
public long getFreeSpace() { public long getFreeSpace() throws DbException {
File dir = config.getDatabaseDirectory(); File dir = config.getDatabaseDirectory();
long maxSize = config.getMaxSize(); long maxSize = config.getMaxSize();
long free = dir.getFreeSpace(); long free = dir.getFreeSpace();
@@ -91,7 +88,7 @@ class H2Database extends JdbcDatabase {
@Override @Override
protected Connection createConnection() throws SQLException { protected Connection createConnection() throws SQLException {
SecretKey key = this.key; SecretKey key = config.getEncryptionKey();
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");

View File

@@ -33,9 +33,6 @@ 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,
@@ -49,11 +46,10 @@ class HyperSqlDatabase extends JdbcDatabase {
} }
@Override @Override
public boolean open(SecretKey key, @Nullable MigrationListener listener) public boolean open(@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.hsqldb.jdbc.JDBCDriver", reopen, listener);
super.open("org.hsqldb.jdbc.JDBCDriver", reopen, key, listener);
return reopen; return reopen;
} }
@@ -97,7 +93,7 @@ class HyperSqlDatabase extends JdbcDatabase {
@Override @Override
protected Connection createConnection() throws SQLException { protected Connection createConnection() throws SQLException {
SecretKey key = this.key; SecretKey key = config.getEncryptionKey();
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);

View File

@@ -328,7 +328,7 @@ abstract class JdbcDatabase implements Database<Connection> {
this.clock = clock; this.clock = clock;
} }
protected void open(String driverClass, boolean reopen, SecretKey key, protected void open(String driverClass, boolean reopen,
@Nullable MigrationListener listener) throws DbException { @Nullable MigrationListener listener) throws DbException {
// Load the JDBC driver // Load the JDBC driver
try { try {

View File

@@ -1,13 +1,10 @@
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;
@@ -24,8 +21,6 @@ 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
@@ -35,51 +30,25 @@ 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, CryptoComponent crypto, IdentityManagerImpl(DatabaseComponent db) {
AuthorFactory authorFactory) {
this.db = db; this.db = db;
this.crypto = crypto;
this.authorFactory = authorFactory;
} }
@Override @Override
public LocalAuthor createLocalAuthor(String name) { public void registerLocalAuthor(LocalAuthor localAuthor)
long start = now(); throws DbException {
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, cached); db.addLocalAuthor(txn, localAuthor);
db.commitTransaction(txn); db.commitTransaction(txn);
LOG.info("Local author stored"); cachedAuthor = localAuthor;
LOG.info("Local author registered");
} finally { } finally {
db.endTransaction(txn); db.endTransaction(txn);
} }

View File

@@ -1,6 +1,7 @@
package org.briarproject.bramble.lifecycle; package org.briarproject.bramble.lifecycle;
import org.briarproject.bramble.api.crypto.SecretKey; import org.briarproject.bramble.api.crypto.CryptoComponent;
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;
@@ -8,7 +9,9 @@ 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;
@@ -23,6 +26,7 @@ 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;
@@ -56,6 +60,8 @@ 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);
@@ -66,9 +72,12 @@ 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<>();
@@ -95,8 +104,25 @@ 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(SecretKey dbKey) { public StartResult startServices(@Nullable String nickname) {
if (!startStopSemaphore.tryAcquire()) { if (!startStopSemaphore.tryAcquire()) {
LOG.info("Already starting or stopping"); LOG.info("Already starting or stopping");
return ALREADY_RUNNING; return ALREADY_RUNNING;
@@ -105,10 +131,13 @@ class LifecycleManagerImpl implements LifecycleManager, MigrationListener {
LOG.info("Starting services"); LOG.info("Starting services");
long start = now(); long start = now();
boolean reopened = db.open(dbKey, this); boolean reopened = db.open(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();

View File

@@ -1,5 +1,10 @@
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;
@@ -49,9 +54,11 @@ public class LifecycleModule {
@Provides @Provides
@Singleton @Singleton
LifecycleManager provideLifecycleManager( LifecycleManager provideLifecycleManager(DatabaseComponent db,
LifecycleManagerImpl lifecycleManager) { EventBus eventBus, CryptoComponent crypto,
return lifecycleManager; AuthorFactory authorFactory, IdentityManager identityManager) {
return new LifecycleManagerImpl(db, eventBus, crypto, authorFactory,
identityManager);
} }
@Provides @Provides

View File

@@ -1,17 +0,0 @@
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;
}
}

View File

@@ -46,7 +46,7 @@ class SyncRecordReaderImpl implements SyncRecordReader {
} }
private void readRecord() throws IOException { private void readRecord() throws IOException {
if (nextRecord != null) throw new AssertionError(); assert nextRecord == null;
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() {
if (nextRecord == null) throw new AssertionError(); assert nextRecord != null;
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 {
if (nextRecord == null) throw new AssertionError(); assert nextRecord != null;
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();
if (nextRecord == null) throw new AssertionError(); assert nextRecord != null;
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

View File

@@ -1,341 +0,0 @@
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);
}
}

View File

@@ -89,7 +89,6 @@ 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;
@@ -142,7 +141,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(key, null); oneOf(database).open(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));
@@ -209,7 +208,7 @@ public class DatabaseComponentImplTest extends BrambleMockTestCase {
DatabaseComponent db = createDatabaseComponent(database, eventBus, DatabaseComponent db = createDatabaseComponent(database, eventBus,
shutdown); shutdown);
assertFalse(db.open(key, null)); assertFalse(db.open(null));
Transaction transaction = db.startTransaction(false); Transaction transaction = db.startTransaction(false);
try { try {
db.addLocalAuthor(transaction, localAuthor); db.addLocalAuthor(transaction, localAuthor);
@@ -1603,7 +1602,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(key, null); oneOf(database).open(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));
@@ -1647,7 +1646,7 @@ public class DatabaseComponentImplTest extends BrambleMockTestCase {
DatabaseComponent db = createDatabaseComponent(database, eventBus, DatabaseComponent db = createDatabaseComponent(database, eventBus,
shutdown); shutdown);
assertFalse(db.open(key, null)); assertFalse(db.open(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);

View File

@@ -1,6 +1,5 @@
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;
@@ -27,7 +26,6 @@ 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;
@@ -45,7 +43,6 @@ 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(
@@ -65,7 +62,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(key, null)); assertFalse(db.open(null));
assertEquals(CODE_SCHEMA_VERSION, getDataSchemaVersion(db)); assertEquals(CODE_SCHEMA_VERSION, getDataSchemaVersion(db));
db.close(); db.close();
} }
@@ -75,14 +72,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(key, null)); assertFalse(db.open(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(key, null); db.open(null);
} }
@Test @Test
@@ -90,12 +87,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(key, null)); assertFalse(db.open(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(key, null)); assertTrue(db.open(null));
assertEquals(CODE_SCHEMA_VERSION, getDataSchemaVersion(db)); assertEquals(CODE_SCHEMA_VERSION, getDataSchemaVersion(db));
db.close(); db.close();
} }
@@ -104,14 +101,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(key, null)); assertFalse(db.open(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(key, null); db.open(null);
} }
@Test(expected = DataTooOldException.class) @Test(expected = DataTooOldException.class)
@@ -119,13 +116,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(key, null)); assertFalse(db.open(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(key, null); db.open(null);
} }
@Test(expected = DataTooOldException.class) @Test(expected = DataTooOldException.class)
@@ -144,14 +141,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(key, null)); assertFalse(db.open(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(key, null); db.open(null);
} }
@Test @Test
@@ -173,14 +170,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(key, null)); assertFalse(db.open(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(key, null)); assertTrue(db.open(null));
assertEquals(CODE_SCHEMA_VERSION, getDataSchemaVersion(db)); assertEquals(CODE_SCHEMA_VERSION, getDataSchemaVersion(db));
db.close(); db.close();
} }
@@ -205,14 +202,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(key, null)); assertFalse(db.open(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(key, null)); assertTrue(db.open(null));
assertEquals(CODE_SCHEMA_VERSION, getDataSchemaVersion(db)); assertEquals(CODE_SCHEMA_VERSION, getDataSchemaVersion(db));
db.close(); db.close();
} }

View File

@@ -15,7 +15,6 @@ 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;
@@ -72,7 +71,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(getSecretKey(), null); db.open(null);
return db; return db;
} }

View File

@@ -16,7 +16,6 @@ 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 {
@@ -44,7 +43,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(getSecretKey(), null); db.open(null);
return db; return db;
} }

View File

@@ -9,8 +9,8 @@ import java.util.List;
public class H2MigrationTest extends DatabaseMigrationTest { public class H2MigrationTest extends DatabaseMigrationTest {
@Override @Override
Database<Connection> createDatabase( Database<Connection> createDatabase(List<Migration<Connection>> migrations)
List<Migration<Connection>> migrations) { throws Exception {
return new H2Database(config, clock) { return new H2Database(config, clock) {
@Override @Override
List<Migration<Connection>> getMigrations() { List<Migration<Connection>> getMigrations() {

View File

@@ -64,7 +64,6 @@ 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;
@@ -80,8 +79,7 @@ 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 SecretKey key = getSecretKey(); private final File testDir = TestUtils.getTestDirectory();
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;
@@ -98,7 +96,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() { JdbcDatabaseTest() throws Exception {
clientId = getClientId(); clientId = getClientId();
majorVersion = 123; majorVersion = 123;
group = getGroup(clientId, majorVersion); group = getGroup(clientId, majorVersion);
@@ -1821,7 +1819,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(key, null); db.open(null);
return db; return db;
} }

View File

@@ -13,7 +13,6 @@ 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
@@ -41,7 +40,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(getSecretKey(), null); db.open(null);
return db; return db;
} }

View File

@@ -2,21 +2,15 @@ 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;
@@ -33,48 +27,24 @@ 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;
@Before public IdentityManagerImplTest() {
public void setUp() { identityManager = new IdentityManagerImpl(db);
identityManager = new IdentityManagerImpl(db, crypto, authorFactory);
} }
@Test @Test
public void testCreateLocalAuthor() { public void testRegisterLocalAuthor() throws DbException {
context.checking(new Expectations() {{ expectRegisterLocalAuthor();
oneOf(crypto).generateSignatureKeyPair(); identityManager.registerLocalAuthor(localAuthor);
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));
} }
@Test private void expectRegisterLocalAuthor() throws DbException {
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));
@@ -82,10 +52,6 @@ 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
@@ -103,6 +69,7 @@ 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());
} }

View File

@@ -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.db.DatabaseConfig; import org.briarproject.bramble.api.db.DatabaseConfig;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault; import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
@@ -10,6 +11,7 @@ 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");
@@ -17,6 +19,13 @@ 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;
@@ -27,6 +36,26 @@ 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;

View File

@@ -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.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;
@@ -12,6 +11,7 @@ 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(SecretKey dbKey) { public StartResult startServices(@Nullable String nickname) {
return StartResult.SUCCESS; return StartResult.SUCCESS;
} }
@@ -49,15 +49,15 @@ public class TestLifecycleModule {
} }
@Override @Override
public void waitForDatabase() { public void waitForDatabase() throws InterruptedException {
} }
@Override @Override
public void waitForStartup() { public void waitForStartup() throws InterruptedException {
} }
@Override @Override
public void waitForShutdown() { public void waitForShutdown() throws InterruptedException {
} }
@Override @Override

View File

@@ -1,33 +0,0 @@
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',
]
}

View File

@@ -5,7 +5,6 @@ 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')
@@ -25,8 +24,31 @@ 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'
} }

View File

@@ -1,24 +0,0 @@
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',
]
}

View File

@@ -5,9 +5,3 @@ 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

View File

@@ -14,7 +14,7 @@
x="0px" x="0px"
y="0px" y="0px"
xml:space="preserve" xml:space="preserve"
inkscape:version="0.92.3 (2405546, 2018-03-11)" inkscape:version="0.91 r13725"
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="1020" inkscape:window-height="1021"
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="5.640316" inkscape:zoom="1.410079"
inkscape:cx="47.227033" inkscape:cx="96.786606"
inkscape:cy="7.5801079" inkscape:cy="117.77539"
inkscape:window-x="1440" inkscape:window-x="1443"
inkscape:window-y="24" inkscape:window-y="23"
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,7 +53,55 @@
.st3{fill:#95D220;} .st3{fill:#95D220;}
.st4{display:none;fill:#95D220;} .st4{display:none;fill:#95D220;}
.st5{fill:#FFFFFF;} .st5{fill:#FFFFFF;}
</style><path </style><rect
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: 5.5 KiB

After

Width:  |  Height:  |  Size: 8.7 KiB

View File

@@ -1,70 +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"
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>

Before

Width:  |  Height:  |  Size: 5.3 KiB

View File

@@ -1,70 +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"
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>

Before

Width:  |  Height:  |  Size: 5.3 KiB

View File

@@ -0,0 +1,57 @@
<?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>

After

Width:  |  Height:  |  Size: 4.1 KiB

View File

@@ -1,6 +1,5 @@
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')
@@ -41,25 +40,182 @@ 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.8' testImplementation 'org.robolectric:robolectric:3.5.1'
testImplementation 'org.robolectric:shadows-support-v4:3.3.2' testImplementation 'org.robolectric:shadows-support-v4:3.0'
testImplementation 'org.mockito:mockito-core:2.13.0' testImplementation 'org.mockito:mockito-core:2.8.9'
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"
}
def espressoVersion = '3.0.2' dependencyVerification {
androidTestImplementation "com.android.support.test.espresso:espresso-core:$espressoVersion" verify = [
androidTestImplementation "com.android.support.test.espresso:espresso-contrib:$espressoVersion" 'android.arch.core:common:1.1.0:common-1.1.0.jar:d34824b794bc92ff8f647a9bb13a7c73de920de5b47075b5d2c4f0770e9b8bfd',
androidTestImplementation "com.android.support.test.espresso:espresso-intents:$espressoVersion" 'android.arch.core:runtime:1.1.0:runtime-1.1.0.aar:83400f7575bcfb8a2eeec64e05590f037bfaed1e56aa3a4214d20e55878445e3',
androidTestImplementation "tools.fastlane:screengrab:1.1.0" 'android.arch.lifecycle:common:1.1.0:common-1.1.0.jar:614e31cfd33255dc4d5f5d8e62cfa6be2fbbc2a35643a79dc3ed008004c30807',
androidTestImplementation "com.android.support.test.uiautomator:uiautomator-v18:2.1.3" 'android.arch.lifecycle:livedata-core:1.1.0:livedata-core-1.1.0.aar:14e57ff8ffb65a80c7e72d91f2076acccdaf2970f234c6261e03a6127eb5206b',
androidTestAnnotationProcessor "com.google.dagger:dagger-compiler:2.0.2" 'android.arch.lifecycle:runtime:1.1.0:runtime-1.1.0.aar:094fd793924dd6a5136753e599ac8174a8147f4a401386b694ba7d818c223e2e',
androidTestCompileOnly 'javax.annotation:jsr250-api:1.0' 'android.arch.lifecycle:viewmodel:1.1.0:viewmodel-1.1.0.aar:6407c93a5ea9850661dca42a0068d6f3deccefd7228ee69bae1c35d70cbc2557',
androidTestImplementation 'junit:junit:4.12' 'backport-util-concurrent:backport-util-concurrent:3.1:backport-util-concurrent-3.1.jar:f5759b7fcdfc83a525a036deedcbd32e5b536b625ebc282426f16ca137eb5902',
'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 ->
@@ -82,25 +238,27 @@ android {
defaultConfig { defaultConfig {
minSdkVersion 14 minSdkVersion 14
targetSdkVersion 26 targetSdkVersion 26
versionCode 10013 versionCode 10011
versionName "1.0.13" versionName "1.0.11"
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
@@ -110,23 +268,6 @@ 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
@@ -186,7 +327,4 @@ 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')
}

View File

@@ -1,2 +0,0 @@
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")

View File

@@ -1,30 +0,0 @@
# 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

View File

@@ -1,9 +0,0 @@
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"

View File

@@ -1,7 +0,0 @@
#!/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

View File

@@ -1,2 +0,0 @@
#!/usr/bin/env bash
adb shell am broadcast -a com.android.systemui.demo -e command exit

View File

@@ -1,43 +0,0 @@
#!/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()

View File

@@ -1,15 +0,0 @@
-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

View File

@@ -1,20 +0,0 @@
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;
}
}

View File

@@ -1,29 +0,0 @@
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);
}

View File

@@ -1,106 +0,0 @@
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());
}
}

View File

@@ -1,48 +0,0 @@
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()));
}
}

View File

@@ -1,70 +0,0 @@
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");
}
}

View File

@@ -1,20 +0,0 @@
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);
}
}

View File

@@ -1,73 +0,0 @@
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);
}
}
}

View File

@@ -1,93 +0,0 @@
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);
}
}

View File

@@ -1,5 +0,0 @@
<?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>

View File

@@ -3,9 +3,8 @@
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" android:required="false"/> <uses-feature android:name="android.hardware.bluetooth"/>
<uses-feature android:name="android.hardware.camera" android:required="false"/> <uses-feature android:name="android.hardware.camera" />
<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" />
@@ -27,11 +26,10 @@
android:theme="@style/BriarTheme"> android:theme="@style/BriarTheme">
<receiver <receiver
android:name="org.briarproject.briar.android.login.SignInReminderReceiver" android:name="org.briarproject.briar.android.BootReceiver"
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>
@@ -402,11 +400,5 @@
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>

View File

@@ -1,33 +0,0 @@
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));
}
}
}

View File

@@ -1,18 +0,0 @@
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;
}
}

View File

@@ -1,14 +1,16 @@
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;
@@ -24,11 +26,9 @@ 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,7 +61,6 @@ 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
@@ -73,6 +72,10 @@ public interface AndroidComponent
PasswordStrengthEstimator passwordStrengthIndicator(); PasswordStrengthEstimator passwordStrengthIndicator();
CryptoComponent cryptoComponent();
DatabaseConfig databaseConfig();
@DatabaseExecutor @DatabaseExecutor
Executor databaseExecutor(); Executor databaseExecutor();
@@ -88,6 +91,8 @@ public interface AndroidComponent
AndroidNotificationManager androidNotificationManager(); AndroidNotificationManager androidNotificationManager();
SharedPreferences sharedPreferences();
ScreenFilterMonitor screenFilterMonitor(); ScreenFilterMonitor screenFilterMonitor();
ConnectionRegistry connectionRegistry(); ConnectionRegistry connectionRegistry();
@@ -145,11 +150,7 @@ public interface AndroidComponent
@IoExecutor @IoExecutor
Executor ioExecutor(); Executor ioExecutor();
AccountManager accountManager(); void inject(BootReceiver briarService);
LockManager lockManager();
void inject(SignInReminderReceiver briarService);
void inject(BriarService briarService); void inject(BriarService briarService);

View File

@@ -1,30 +1,99 @@
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;

View File

@@ -2,7 +2,6 @@ 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;
@@ -11,8 +10,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;
@@ -34,10 +33,8 @@ 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;
@@ -65,19 +62,13 @@ 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;
@@ -116,7 +107,6 @@ 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;
@@ -176,7 +166,8 @@ 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(getColor(appContext, R.color.briar_green_light)); nc.setLightColor(
ContextCompat.getColor(appContext, R.color.briar_green_light));
notificationManager.createNotificationChannel(nc); notificationManager.createNotificationChannel(nc);
} }
@@ -273,47 +264,6 @@ 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;
@@ -662,58 +612,6 @@ 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);

View File

@@ -11,8 +11,9 @@ 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.network.NetworkManager; import org.briarproject.bramble.api.nullsafety.MethodsNotNullByDefault;
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;
@@ -21,18 +22,15 @@ 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;
@@ -88,7 +86,11 @@ 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);
return new AndroidDatabaseConfig(dbDir, keyDir); @MethodsNotNullByDefault
@ParametersNotNullByDefault
DatabaseConfig databaseConfig =
new AndroidDatabaseConfig(dbDir, keyDir);
return databaseConfig;
} }
@Provides @Provides
@@ -96,20 +98,17 @@ 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, NetworkManager networkManager, Application app, LocationUtils locationUtils, EventBus eventBus,
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 AndroidTorPluginFactory(ioExecutor, DuplexPluginFactory tor = new TorPluginFactory(ioExecutor, scheduler,
scheduler, appContext, networkManager, locationUtils, eventBus, appContext, locationUtils, eventBus, torSocketFactory,
torSocketFactory, backoffFactory, resourceProvider, backoffFactory, circumventionProvider, clock);
circumventionProvider, clock);
DuplexPluginFactory lan = new AndroidLanTcpPluginFactory(ioExecutor, DuplexPluginFactory lan = new AndroidLanTcpPluginFactory(ioExecutor,
eventBus, backoffFactory, appContext); scheduler, 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() {
@@ -163,7 +162,6 @@ 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);
} }
@@ -202,13 +200,4 @@ 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