Compare commits

..

1 Commits

Author SHA1 Message Date
akwizgran
327e12e9f8 Don't allow multiple messages to be queued in memory for validation at startup. 2020-09-24 15:42:18 +01:00
1381 changed files with 19230 additions and 74594 deletions

1
.gitignore vendored
View File

@@ -18,7 +18,6 @@ local.properties
# Android Studio # Android Studio
.idea/* .idea/*
!.idea/inspectionProfiles/
!.idea/runConfigurations/ !.idea/runConfigurations/
!.idea/codeStyleSettings.xml !.idea/codeStyleSettings.xml
!.idea/codeStyles !.idea/codeStyles

View File

@@ -1,80 +1,29 @@
image: briar/ci-image-android:latest image: briar/ci-image-android:latest
stages: stages:
- test - test
- optional_tests - check_reproducibility
- check_reproducibility
workflow: test:
# when to create a CI pipeline stage: test
rules:
- if: '$CI_PIPELINE_SOURCE == "merge_request_event"'
- if: '$CI_COMMIT_BRANCH && $CI_OPEN_MERGE_REQUESTS'
when: never # avoids duplicate jobs for branch and MR
- if: '$CI_COMMIT_BRANCH'
- if: '$CI_COMMIT_TAG'
.base-test:
before_script: before_script:
- set -e - set -e
- export GRADLE_USER_HOME=$PWD/.gradle - export GRADLE_USER_HOME=$PWD/.gradle
cache: cache:
key: "$CI_COMMIT_REF_SLUG"
paths: paths:
- .gradle/wrapper - .gradle/wrapper
- .gradle/caches - .gradle/caches
script:
- ./gradlew --no-daemon -Djava.security.egd=file:/dev/urandom animalSnifferMain animalSnifferTest
- ./gradlew --no-daemon -Djava.security.egd=file:/dev/urandom check compileOfficialDebugAndroidTestSources compileScreenshotDebugAndroidTestSources
after_script: after_script:
# these file change every time and should not be cached # these file change every time but should not be cached
- rm -f $GRADLE_USER_HOME/caches/modules-2/modules-2.lock - rm -f $GRADLE_USER_HOME/caches/modules-2/modules-2.lock
- rm -fr $GRADLE_USER_HOME/caches/*/plugin-resolution/ - rm -fr $GRADLE_USER_HOME/caches/*/plugin-resolution/
test:
extends: .base-test
stage: test
script:
- ./gradlew -Djava.security.egd=file:/dev/urandom animalSnifferMain animalSnifferTest
- ./gradlew -Djava.security.egd=file:/dev/urandom assembleOfficialDebug :briar-headless:linuxJars
- ./gradlew -Djava.security.egd=file:/dev/urandom compileOfficialDebugAndroidTestSources compileScreenshotDebugAndroidTestSources check
rules:
- if: '$CI_PIPELINE_SOURCE == "merge_request_event"'
when: always
- when: always
android test:
extends: .base-test
stage: optional_tests
image: briar/ci-image-android-emulator:latest
script:
# start emulator first, so it can fail early
- start-emulator.sh
# run normal and screenshot tests together (exclude Large tests)
- ./gradlew -Djava.security.egd=file:/dev/urandom connectedAndroidTest -Pandroid.testInstrumentationRunnerArguments.package=org.briarproject.briar.android -Pandroid.testInstrumentationRunnerArguments.notAnnotation=androidx.test.filters.LargeTest
after_script:
- adb pull /sdcard/Pictures/screenshots
artifacts:
name: "${CI_PROJECT_PATH}_${CI_JOB_STAGE}_${CI_COMMIT_REF_NAME}_${CI_COMMIT_SHA}"
paths:
- kernel.log
- logcat.txt
- briar-android/build/reports/androidTests/connected/flavors/*
- screenshots
expire_in: 3 days
when: on_failure
rules:
- if: '$CI_PIPELINE_SOURCE == "schedule"'
when: manual
- if: '$CI_PIPELINE_SOURCE == "merge_request_event"'
changes:
- briar-android/**/*
when: manual
allow_failure: true
- if: '$CI_COMMIT_TAG == null'
when: manual
allow_failure: true
retry:
max: 1
tags:
- kvm
test_reproducible: test_reproducible:
stage: check_reproducibility stage: check_reproducibility
@@ -82,39 +31,3 @@ test_reproducible:
- "curl -X POST -F token=${RELEASE_CHECK_TOKEN} -F ref=master -F variables[RELEASE_TAG]=${CI_COMMIT_REF_NAME} https://code.briarproject.org/api/v4/projects/61/trigger/pipeline" - "curl -X POST -F token=${RELEASE_CHECK_TOKEN} -F ref=master -F variables[RELEASE_TAG]=${CI_COMMIT_REF_NAME} https://code.briarproject.org/api/v4/projects/61/trigger/pipeline"
only: only:
- tags - tags
.optional_tests:
stage: optional_tests
extends: .base-test
bridge test:
extends: .optional_tests
rules:
- if: '$CI_PIPELINE_SOURCE == "schedule"'
when: on_success
allow_failure: false
- if: '$CI_COMMIT_TAG == null'
when: manual
allow_failure: true
script:
- OPTIONAL_TESTS=org.briarproject.bramble.plugin.tor.BridgeTest ./gradlew --info bramble-java:test --tests BridgeTest
timeout: 3h
mailbox integration test:
extends: .optional_tests
rules:
- if: '$CI_PIPELINE_SOURCE == "schedule"'
when: on_success
- if: '$CI_COMMIT_TAG == null'
when: manual
allow_failure: true # TODO figure out how not to allow failure while leaving this optional
script:
# start mailbox
- cd /opt && git clone --depth 1 https://code.briarproject.org/briar/briar-mailbox.git briar-mailbox
- cd briar-mailbox
- mkdir -p /root/.local/share # create directory that mailbox (currently) expects to exist
- ./gradlew run --args="--debug --setup-token 54686973206973206120736574757020746f6b656e20666f722042726961722e" &
# run mailbox integration test once mailbox has started
- cd "$CI_PROJECT_DIR"
- bramble-core/src/test/bash/wait-for-mailbox.sh
- OPTIONAL_TESTS=org.briarproject.bramble.mailbox.MailboxIntegrationTest ./gradlew --info bramble-core:test --tests MailboxIntegrationTest

View File

@@ -28,11 +28,6 @@
<option name="JD_ALIGN_EXCEPTION_COMMENTS" value="false" /> <option name="JD_ALIGN_EXCEPTION_COMMENTS" value="false" />
</JavaCodeStyleSettings> </JavaCodeStyleSettings>
<JetCodeStyleSettings> <JetCodeStyleSettings>
<option name="PACKAGES_TO_USE_STAR_IMPORTS">
<value />
</option>
<option name="NAME_COUNT_TO_USE_STAR_IMPORT" value="2147483647" />
<option name="NAME_COUNT_TO_USE_STAR_IMPORT_FOR_MEMBERS" value="2147483647" />
<option name="CODE_STYLE_DEFAULTS" value="KOTLIN_OFFICIAL" /> <option name="CODE_STYLE_DEFAULTS" value="KOTLIN_OFFICIAL" />
</JetCodeStyleSettings> </JetCodeStyleSettings>
<XML> <XML>
@@ -188,9 +183,9 @@
</codeStyleSettings> </codeStyleSettings>
<codeStyleSettings language="kotlin"> <codeStyleSettings language="kotlin">
<option name="CODE_STYLE_DEFAULTS" value="KOTLIN_OFFICIAL" /> <option name="CODE_STYLE_DEFAULTS" value="KOTLIN_OFFICIAL" />
<indentOptions> <option name="PARAMETER_ANNOTATION_WRAP" value="1" />
<option name="CONTINUATION_INDENT_SIZE" value="4" /> <option name="VARIABLE_ANNOTATION_WRAP" value="1" />
</indentOptions> <option name="ENUM_CONSTANTS_WRAP" value="1" />
</codeStyleSettings> </codeStyleSettings>
</code_scheme> </code_scheme>
</component> </component>

View File

@@ -1,15 +0,0 @@
<component name="ProjectDictionaryState">
<dictionary name="briar">
<words>
<w>briar</w>
<w>briarproject</w>
<w>emoji</w>
<w>encrypter</w>
<w>identicon</w>
<w>introducee</w>
<w>introducees</w>
<w>introducer</w>
<w>onboarding</w>
</words>
</dictionary>
</component>

View File

@@ -1,14 +0,0 @@
<component name="InspectionProjectProfileManager">
<profile version="1.0">
<option name="myName" value="Project Default" />
<inspection_tool class="MissingOverrideAnnotation" enabled="true" level="WARNING" enabled_by_default="true">
<option name="ignoreObjectMethods" value="true" />
<option name="ignoreAnonymousClassMethods" value="false" />
</inspection_tool>
<inspection_tool class="WeakerAccess" enabled="true" level="WARNING" enabled_by_default="true">
<option name="SUGGEST_PACKAGE_LOCAL_FOR_MEMBERS" value="true" />
<option name="SUGGEST_PACKAGE_LOCAL_FOR_TOP_CLASSES" value="true" />
<option name="SUGGEST_PRIVATE_FOR_INNERS" value="true" />
</inspection_tool>
</profile>
</component>

View File

@@ -1,32 +1,20 @@
<component name="ProjectRunConfigurationManager"> <component name="ProjectRunConfigurationManager">
<configuration default="false" name="All tests" type="GradleRunConfiguration" factoryName="Gradle"> <configuration default="false" name="All tests" type="AndroidJUnit" factoryName="Android JUnit">
<ExternalSystemSettings> <module name="briar-android" />
<option name="executionName" /> <option name="PACKAGE_NAME" value="" />
<option name="externalProjectPath" value="$PROJECT_DIR$" /> <option name="MAIN_CLASS_NAME" value="" />
<option name="externalSystemIdString" value="GRADLE" /> <option name="METHOD_NAME" value="" />
<option name="scriptParameters" value="" /> <option name="TEST_OBJECT" value="package" />
<option name="taskDescriptions"> <option name="PARAMETERS" value="" />
<list /> <option name="WORKING_DIRECTORY" value="$PROJECT_DIR$/briar-android" />
</option>
<option name="taskNames">
<list>
<option value=":briar-android:testOfficialDebugUnitTest" />
<option value=":briar-android:testScreenshotDebugUnitTest" />
</list>
</option>
<option name="vmOptions" value="" />
</ExternalSystemSettings>
<ExternalSystemDebugServerProcess>false</ExternalSystemDebugServerProcess>
<ExternalSystemReattachDebugProcess>true</ExternalSystemReattachDebugProcess>
<DebugAllEnabled>false</DebugAllEnabled>
<method v="2"> <method v="2">
<option name="RunConfigurationTask" enabled="true" run_configuration_name="All tests in bramble-api" run_configuration_type="GradleRunConfiguration" /> <option name="Android.Gradle.BeforeRunTask" enabled="true" />
<option name="RunConfigurationTask" enabled="true" run_configuration_name="All tests in bramble-core" run_configuration_type="GradleRunConfiguration" /> <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-java" run_configuration_type="GradleRunConfiguration" /> <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="GradleRunConfiguration" /> <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 briar-api" run_configuration_type="GradleRunConfiguration" /> <option name="RunConfigurationTask" enabled="true" run_configuration_name="All tests in bramble-java" run_configuration_type="AndroidJUnit" />
<option name="RunConfigurationTask" enabled="true" run_configuration_name="All tests in briar-core" run_configuration_type="GradleRunConfiguration" /> <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-headless" run_configuration_type="GradleRunConfiguration" /> <option name="RunConfigurationTask" enabled="true" run_configuration_name="All tests in briar-headless" run_configuration_type="AndroidJUnit" />
</method> </method>
</configuration> </configuration>
</component> </component>

View File

@@ -1,23 +1,20 @@
<component name="ProjectRunConfigurationManager"> <component name="ProjectRunConfigurationManager">
<configuration default="false" name="All tests in bramble-android" type="GradleRunConfiguration" factoryName="Gradle"> <configuration default="false" name="All tests in bramble-android" type="AndroidJUnit" factoryName="Android JUnit">
<ExternalSystemSettings> <module name="bramble-android" />
<option name="executionName" /> <option name="ALTERNATIVE_JRE_PATH_ENABLED" value="false" />
<option name="externalProjectPath" value="$PROJECT_DIR$" /> <option name="ALTERNATIVE_JRE_PATH" />
<option name="externalSystemIdString" value="GRADLE" /> <option name="PACKAGE_NAME" value="" />
<option name="scriptParameters" value="" /> <option name="MAIN_CLASS_NAME" value="" />
<option name="taskDescriptions"> <option name="METHOD_NAME" value="" />
<list /> <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="PASS_PARENT_ENVS" value="true" />
<option name="TEST_SEARCH_SCOPE">
<value defaultName="singleModule" />
</option> </option>
<option name="taskNames"> <patterns />
<list> <method />
<option value=":bramble-android:testDebugUnitTest" />
</list>
</option>
<option name="vmOptions" value="" />
</ExternalSystemSettings>
<ExternalSystemDebugServerProcess>false</ExternalSystemDebugServerProcess>
<ExternalSystemReattachDebugProcess>true</ExternalSystemReattachDebugProcess>
<DebugAllEnabled>false</DebugAllEnabled>
<method v="2" />
</configuration> </configuration>
</component> </component>

View File

@@ -1,25 +1,20 @@
<component name="ProjectRunConfigurationManager"> <component name="ProjectRunConfigurationManager">
<configuration default="false" name="All tests in bramble-api" type="GradleRunConfiguration" factoryName="Gradle"> <configuration default="false" name="All tests in bramble-api" type="AndroidJUnit" factoryName="Android JUnit">
<ExternalSystemSettings> <module name="bramble-api" />
<option name="executionName" /> <option name="ALTERNATIVE_JRE_PATH_ENABLED" value="false" />
<option name="externalProjectPath" value="$PROJECT_DIR$" /> <option name="ALTERNATIVE_JRE_PATH" />
<option name="externalSystemIdString" value="GRADLE" /> <option name="PACKAGE_NAME" value="" />
<option name="scriptParameters" value="" /> <option name="MAIN_CLASS_NAME" value="" />
<option name="taskDescriptions"> <option name="METHOD_NAME" value="" />
<list /> <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-api" />
<option name="PASS_PARENT_ENVS" value="true" />
<option name="TEST_SEARCH_SCOPE">
<value defaultName="singleModule" />
</option> </option>
<option name="taskNames"> <patterns />
<list> <method />
<option value=":bramble-api:animalSnifferMain" />
<option value=":bramble-api:animalSnifferTest" />
<option value=":bramble-api:test" />
</list>
</option>
<option name="vmOptions" value="" />
</ExternalSystemSettings>
<ExternalSystemDebugServerProcess>false</ExternalSystemDebugServerProcess>
<ExternalSystemReattachDebugProcess>true</ExternalSystemReattachDebugProcess>
<DebugAllEnabled>false</DebugAllEnabled>
<method v="2" />
</configuration> </configuration>
</component> </component>

View File

@@ -1,25 +1,20 @@
<component name="ProjectRunConfigurationManager"> <component name="ProjectRunConfigurationManager">
<configuration default="false" name="All tests in bramble-core" type="GradleRunConfiguration" factoryName="Gradle"> <configuration default="false" name="All tests in bramble-core" type="AndroidJUnit" factoryName="Android JUnit">
<ExternalSystemSettings> <module name="bramble-core" />
<option name="executionName" /> <option name="ALTERNATIVE_JRE_PATH_ENABLED" value="false" />
<option name="externalProjectPath" value="$PROJECT_DIR$" /> <option name="ALTERNATIVE_JRE_PATH" />
<option name="externalSystemIdString" value="GRADLE" /> <option name="PACKAGE_NAME" value="" />
<option name="scriptParameters" value="" /> <option name="MAIN_CLASS_NAME" value="" />
<option name="taskDescriptions"> <option name="METHOD_NAME" value="" />
<list /> <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-core" />
<option name="PASS_PARENT_ENVS" value="true" />
<option name="TEST_SEARCH_SCOPE">
<value defaultName="singleModule" />
</option> </option>
<option name="taskNames"> <patterns />
<list> <method />
<option value=":bramble-core:animalSnifferMain" />
<option value=":bramble-core:animalSnifferTest" />
<option value=":bramble-core:test" />
</list>
</option>
<option name="vmOptions" value="" />
</ExternalSystemSettings>
<ExternalSystemDebugServerProcess>false</ExternalSystemDebugServerProcess>
<ExternalSystemReattachDebugProcess>true</ExternalSystemReattachDebugProcess>
<DebugAllEnabled>false</DebugAllEnabled>
<method v="2" />
</configuration> </configuration>
</component> </component>

View File

@@ -1,23 +1,20 @@
<component name="ProjectRunConfigurationManager"> <component name="ProjectRunConfigurationManager">
<configuration default="false" name="All tests in bramble-java" type="GradleRunConfiguration" factoryName="Gradle"> <configuration default="false" name="All tests in bramble-java" type="AndroidJUnit" factoryName="Android JUnit">
<ExternalSystemSettings> <module name="bramble-java" />
<option name="executionName" /> <option name="ALTERNATIVE_JRE_PATH_ENABLED" value="false" />
<option name="externalProjectPath" value="$PROJECT_DIR$" /> <option name="ALTERNATIVE_JRE_PATH" />
<option name="externalSystemIdString" value="GRADLE" /> <option name="PACKAGE_NAME" value="" />
<option name="scriptParameters" value="" /> <option name="MAIN_CLASS_NAME" value="" />
<option name="taskDescriptions"> <option name="METHOD_NAME" value="" />
<list /> <option name="TEST_OBJECT" value="package" />
<option name="VM_PARAMETERS" value="-ea -Djava.library.path=libs" />
<option name="PARAMETERS" value="" />
<option name="WORKING_DIRECTORY" value="file://$PROJECT_DIR$/bramble-java" />
<option name="PASS_PARENT_ENVS" value="true" />
<option name="TEST_SEARCH_SCOPE">
<value defaultName="singleModule" />
</option> </option>
<option name="taskNames"> <patterns />
<list> <method />
<option value=":bramble-java:test" />
</list>
</option>
<option name="vmOptions" value="" />
</ExternalSystemSettings>
<ExternalSystemDebugServerProcess>false</ExternalSystemDebugServerProcess>
<ExternalSystemReattachDebugProcess>true</ExternalSystemReattachDebugProcess>
<DebugAllEnabled>false</DebugAllEnabled>
<method v="2" />
</configuration> </configuration>
</component> </component>

View File

@@ -1,24 +1,20 @@
<component name="ProjectRunConfigurationManager"> <component name="ProjectRunConfigurationManager">
<configuration default="false" name="All tests in briar-android" type="GradleRunConfiguration" factoryName="Gradle"> <configuration default="false" name="All tests in briar-android" type="AndroidJUnit" factoryName="Android JUnit">
<ExternalSystemSettings> <module name="briar-android" />
<option name="executionName" /> <option name="ALTERNATIVE_JRE_PATH_ENABLED" value="false" />
<option name="externalProjectPath" value="$PROJECT_DIR$" /> <option name="ALTERNATIVE_JRE_PATH" />
<option name="externalSystemIdString" value="GRADLE" /> <option name="PACKAGE_NAME" value="" />
<option name="scriptParameters" value="" /> <option name="MAIN_CLASS_NAME" value="" />
<option name="taskDescriptions"> <option name="METHOD_NAME" value="" />
<list /> <option name="TEST_OBJECT" value="package" />
<option name="VM_PARAMETERS" value="-ea" />
<option name="PARAMETERS" value="" />
<option name="WORKING_DIRECTORY" value="file://$PROJECT_DIR$/briar-android" />
<option name="PASS_PARENT_ENVS" value="true" />
<option name="TEST_SEARCH_SCOPE">
<value defaultName="singleModule" />
</option> </option>
<option name="taskNames"> <patterns />
<list> <method />
<option value=":briar-android:testOfficialDebugUnitTest" />
<option value=":briar-android:testScreenshotDebugUnitTest" />
</list>
</option>
<option name="vmOptions" value="" />
</ExternalSystemSettings>
<ExternalSystemDebugServerProcess>false</ExternalSystemDebugServerProcess>
<ExternalSystemReattachDebugProcess>true</ExternalSystemReattachDebugProcess>
<DebugAllEnabled>false</DebugAllEnabled>
<method v="2" />
</configuration> </configuration>
</component> </component>

View File

@@ -1,25 +0,0 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="All tests in briar-api" type="GradleRunConfiguration" factoryName="Gradle">
<ExternalSystemSettings>
<option name="executionName" />
<option name="externalProjectPath" value="$PROJECT_DIR$" />
<option name="externalSystemIdString" value="GRADLE" />
<option name="scriptParameters" value="" />
<option name="taskDescriptions">
<list />
</option>
<option name="taskNames">
<list>
<option value=":briar-api:animalSnifferMain" />
<option value=":briar-api:animalSnifferTest" />
<option value=":briar-api:test" />
</list>
</option>
<option name="vmOptions" value="" />
</ExternalSystemSettings>
<ExternalSystemDebugServerProcess>false</ExternalSystemDebugServerProcess>
<ExternalSystemReattachDebugProcess>true</ExternalSystemReattachDebugProcess>
<DebugAllEnabled>false</DebugAllEnabled>
<method v="2" />
</configuration>
</component>

View File

@@ -1,25 +1,20 @@
<component name="ProjectRunConfigurationManager"> <component name="ProjectRunConfigurationManager">
<configuration default="false" name="All tests in briar-core" type="GradleRunConfiguration" factoryName="Gradle"> <configuration default="false" name="All tests in briar-core" type="AndroidJUnit" factoryName="Android JUnit">
<ExternalSystemSettings> <module name="briar-core" />
<option name="executionName" /> <option name="ALTERNATIVE_JRE_PATH_ENABLED" value="false" />
<option name="externalProjectPath" value="$PROJECT_DIR$" /> <option name="ALTERNATIVE_JRE_PATH" />
<option name="externalSystemIdString" value="GRADLE" /> <option name="PACKAGE_NAME" value="" />
<option name="scriptParameters" value="" /> <option name="MAIN_CLASS_NAME" value="" />
<option name="taskDescriptions"> <option name="METHOD_NAME" value="" />
<list /> <option name="TEST_OBJECT" value="package" />
<option name="VM_PARAMETERS" value="-ea" />
<option name="PARAMETERS" value="" />
<option name="WORKING_DIRECTORY" value="file://$PROJECT_DIR$/briar-core" />
<option name="PASS_PARENT_ENVS" value="true" />
<option name="TEST_SEARCH_SCOPE">
<value defaultName="singleModule" />
</option> </option>
<option name="taskNames"> <patterns />
<list> <method />
<option value=":briar-core:animalSnifferMain" />
<option value=":briar-core:animalSnifferTest" />
<option value=":briar-core:test" />
</list>
</option>
<option name="vmOptions" value="" />
</ExternalSystemSettings>
<ExternalSystemDebugServerProcess>false</ExternalSystemDebugServerProcess>
<ExternalSystemReattachDebugProcess>true</ExternalSystemReattachDebugProcess>
<DebugAllEnabled>false</DebugAllEnabled>
<method v="2" />
</configuration> </configuration>
</component> </component>

View File

@@ -1,23 +1,15 @@
<component name="ProjectRunConfigurationManager"> <component name="ProjectRunConfigurationManager">
<configuration default="false" name="All tests in briar-headless" type="GradleRunConfiguration" factoryName="Gradle"> <configuration default="false" name="All tests in briar-headless" type="AndroidJUnit" factoryName="Android JUnit">
<ExternalSystemSettings> <module name="briar-headless" />
<option name="executionName" /> <option name="PACKAGE_NAME" value="org.briarproject.briar.headless" />
<option name="externalProjectPath" value="$PROJECT_DIR$" /> <option name="MAIN_CLASS_NAME" value="" />
<option name="externalSystemIdString" value="GRADLE" /> <option name="METHOD_NAME" value="" />
<option name="scriptParameters" value="" /> <option name="TEST_OBJECT" value="package" />
<option name="taskDescriptions"> <option name="VM_PARAMETERS" />
<list /> <option name="PARAMETERS" value="" />
</option> <option name="WORKING_DIRECTORY" value="$PROJECT_DIR$/briar-headless" />
<option name="taskNames"> <method v="2">
<list> <option name="Android.Gradle.BeforeRunTask" enabled="true" />
<option value=":briar-headless:test" /> </method>
</list>
</option>
<option name="vmOptions" value="" />
</ExternalSystemSettings>
<ExternalSystemDebugServerProcess>false</ExternalSystemDebugServerProcess>
<ExternalSystemReattachDebugProcess>true</ExternalSystemReattachDebugProcess>
<DebugAllEnabled>false</DebugAllEnabled>
<method v="2" />
</configuration> </configuration>
</component> </component>

View File

@@ -1,28 +0,0 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="BridgeTest" type="GradleRunConfiguration" factoryName="Gradle">
<ExternalSystemSettings>
<option name="env">
<map>
<entry key="OPTIONAL_TESTS" value="org.briarproject.bramble.plugin.tor.BridgeTest" />
</map>
</option>
<option name="executionName" />
<option name="externalProjectPath" value="$PROJECT_DIR$" />
<option name="externalSystemIdString" value="GRADLE" />
<option name="scriptParameters" value="--tests &quot;org.briarproject.bramble.plugin.tor.BridgeTest&quot;" />
<option name="taskDescriptions">
<list />
</option>
<option name="taskNames">
<list>
<option value=":bramble-java:test" />
</list>
</option>
<option name="vmOptions" value="" />
</ExternalSystemSettings>
<ExternalSystemDebugServerProcess>false</ExternalSystemDebugServerProcess>
<ExternalSystemReattachDebugProcess>true</ExternalSystemReattachDebugProcess>
<DebugAllEnabled>false</DebugAllEnabled>
<method v="2" />
</configuration>
</component>

View File

@@ -0,0 +1,20 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="H2 Performance Test" type="AndroidJUnit" factoryName="Android JUnit">
<module name="bramble-core" />
<option name="ALTERNATIVE_JRE_PATH_ENABLED" value="false" />
<option name="ALTERNATIVE_JRE_PATH" />
<option name="PACKAGE_NAME" value="org.briarproject.bramble.db" />
<option name="MAIN_CLASS_NAME" value="org.briarproject.bramble.db.H2DatabasePerformanceTest" />
<option name="METHOD_NAME" value="" />
<option name="TEST_OBJECT" value="class" />
<option name="VM_PARAMETERS" value="-ea" />
<option name="PARAMETERS" value="" />
<option name="WORKING_DIRECTORY" value="" />
<option name="PASS_PARENT_ENVS" value="true" />
<option name="TEST_SEARCH_SCOPE">
<value defaultName="singleModule" />
</option>
<patterns />
<method />
</configuration>
</component>

View File

@@ -0,0 +1,20 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="HyperSQL Performance Test" type="AndroidJUnit" factoryName="Android JUnit">
<module name="bramble-core" />
<option name="ALTERNATIVE_JRE_PATH_ENABLED" value="false" />
<option name="ALTERNATIVE_JRE_PATH" />
<option name="PACKAGE_NAME" value="org.briarproject.bramble.db" />
<option name="MAIN_CLASS_NAME" value="org.briarproject.bramble.db.HyperSqlDatabasePerformanceTest" />
<option name="METHOD_NAME" value="" />
<option name="TEST_OBJECT" value="class" />
<option name="VM_PARAMETERS" value="-ea" />
<option name="PARAMETERS" value="" />
<option name="WORKING_DIRECTORY" value="" />
<option name="PASS_PARENT_ENVS" value="true" />
<option name="TEST_SEARCH_SCOPE">
<value defaultName="singleModule" />
</option>
<patterns />
<method />
</configuration>
</component>

View File

@@ -1,51 +0,0 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="Instrumentation Tests (destroys DB)" type="AndroidTestRunConfigurationType" factoryName="Android Instrumented Tests">
<module name="briar.briar-android" />
<option name="TESTING_TYPE" value="1" />
<option name="METHOD_NAME" value="" />
<option name="CLASS_NAME" value="" />
<option name="PACKAGE_NAME" value="org.briarproject.briar.android" />
<option name="INSTRUMENTATION_RUNNER_CLASS" value="" />
<option name="EXTRA_OPTIONS" value="-e notAnnotation androidx.test.filters.LargeTest" />
<option name="INCLUDE_GRADLE_EXTRA_OPTIONS" value="true" />
<option name="CLEAR_LOGCAT" value="false" />
<option name="SHOW_LOGCAT_AUTOMATICALLY" value="false" />
<option name="SKIP_NOOP_APK_INSTALLATIONS" value="true" />
<option name="FORCE_STOP_RUNNING_APP" value="true" />
<option name="TARGET_SELECTION_MODE" value="DEVICE_AND_SNAPSHOT_COMBO_BOX" />
<option name="DEBUGGER_TYPE" value="Auto" />
<Auto>
<option name="USE_JAVA_AWARE_DEBUGGER" value="false" />
<option name="SHOW_STATIC_VARS" value="true" />
<option name="WORKING_DIR" value="" />
<option name="TARGET_LOGGING_CHANNELS" value="lldb process:gdb-remote packets" />
<option name="SHOW_OPTIMIZED_WARNING" value="true" />
</Auto>
<Hybrid>
<option name="USE_JAVA_AWARE_DEBUGGER" value="false" />
<option name="SHOW_STATIC_VARS" value="true" />
<option name="WORKING_DIR" value="" />
<option name="TARGET_LOGGING_CHANNELS" value="lldb process:gdb-remote packets" />
<option name="SHOW_OPTIMIZED_WARNING" value="true" />
</Hybrid>
<Java />
<Native>
<option name="USE_JAVA_AWARE_DEBUGGER" value="false" />
<option name="SHOW_STATIC_VARS" value="true" />
<option name="WORKING_DIR" value="" />
<option name="TARGET_LOGGING_CHANNELS" value="lldb process:gdb-remote packets" />
<option name="SHOW_OPTIMIZED_WARNING" value="true" />
</Native>
<Profilers>
<option name="ADVANCED_PROFILING_ENABLED" value="false" />
<option name="STARTUP_PROFILING_ENABLED" value="false" />
<option name="STARTUP_CPU_PROFILING_ENABLED" value="false" />
<option name="STARTUP_CPU_PROFILING_CONFIGURATION_NAME" value="Sample Java Methods" />
<option name="STARTUP_NATIVE_MEMORY_PROFILING_ENABLED" value="false" />
<option name="NATIVE_MEMORY_SAMPLE_RATE_BYTES" value="2048" />
</Profilers>
<method v="2">
<option name="Android.Gradle.BeforeRunTask" enabled="true" />
</method>
</configuration>
</component>

View File

@@ -1,6 +1,6 @@
<component name="ProjectRunConfigurationManager"> <component name="ProjectRunConfigurationManager">
<configuration default="false" name="briar-headless" type="JetRunConfigurationType" singleton="true"> <configuration default="false" name="briar-headless" type="JetRunConfigurationType" factoryName="Kotlin" singleton="true">
<module name="briar.briar-headless" /> <extension name="coverage" enabled="false" merge="false" sample_coverage="true" runner="idea" />
<option name="VM_PARAMETERS" value="" /> <option name="VM_PARAMETERS" value="" />
<option name="PROGRAM_PARAMETERS" value="-v" /> <option name="PROGRAM_PARAMETERS" value="-v" />
<option name="ALTERNATIVE_JRE_PATH_ENABLED" value="false" /> <option name="ALTERNATIVE_JRE_PATH_ENABLED" value="false" />
@@ -8,8 +8,9 @@
<option name="PASS_PARENT_ENVS" value="true" /> <option name="PASS_PARENT_ENVS" value="true" />
<option name="MAIN_CLASS_NAME" value="org.briarproject.briar.headless.MainKt" /> <option name="MAIN_CLASS_NAME" value="org.briarproject.briar.headless.MainKt" />
<option name="WORKING_DIRECTORY" value="" /> <option name="WORKING_DIRECTORY" value="" />
<method v="2"> <module name="briar-headless" />
<option name="Make" enabled="true" /> <envs />
<method>
<option name="Gradle.BeforeRunTask" enabled="true" tasks="jar" externalProjectPath="$PROJECT_DIR$/briar-headless" vmOptions="" scriptParameters="" /> <option name="Gradle.BeforeRunTask" enabled="true" tasks="jar" externalProjectPath="$PROJECT_DIR$/briar-headless" vmOptions="" scriptParameters="" />
</method> </method>
</configuration> </configuration>

View File

@@ -1,10 +0,0 @@
Folder-Description:
===================
* `briar-*`: Specifically for the Briar app (Phone/Desktop/Headless)
* `bramble-*`: The protocol stack - not necessarily Briar-dependent
---
* `*-api`: public stuff that can be referenced from other packages and modules - mostly interfaces + a few utility classes
* `*-core`: implementations of api that are portable across Android/Desktop/Headless
* `*-java`: implementations of api that are specific to Desktop & Headless

View File

@@ -1,37 +1 @@
# Briar Briar is a messaging app designed for activists, journalists, and anyone else who needs a safe, easy and robust way to communicate. Unlike traditional messaging tools such as email, Twitter or Telegram, Briar doesn't rely on a central server - messages are synchronized directly between the users' devices. If the Internet's down, Briar can sync via Bluetooth or Wi-Fi, keeping the information flowing in a crisis. If the Internet's up, Briar can sync via the Tor network, protecting users and their relationships from surveillance.
Briar is a messaging app designed for activists, journalists, and anyone else who needs a safe, easy and robust way to communicate.
Unlike traditional messaging tools such as email, Twitter or Telegram, Briar doesn't rely on a central server - messages are synchronized directly between the users' devices.
If the Internet's down, Briar can sync via Bluetooth or Wi-Fi, keeping information flowing in a crisis. If the Internet's up, Briar can sync via the Tor network, protecting users and their relationships from surveillance.
## Download Briar
[<img src="https://briarproject.org//img/fdroid_badge.png" width="240">](https://briarproject.org/fdroid)
[<img src="https://briarproject.org/img/google_play_badge_web_generic.png" width="240">](https://play.google.com/store/apps/details?id=org.briarproject.briar.android)
You can also [download the APK file](https://briarproject.org/apk) directly from
our site.
## Useful links
[briarproject.org](https://briarproject.org/)
[Source code](https://code.briarproject.org/briar/briar/tree/master)
[Manual](https://briarproject.org/manual/)
[Wiki](https://code.briarproject.org/briar/briar/-/wikis/home)
## Reproducible builds
We provide [docker images](https://code.briarproject.org/briar/briar-reproducer#briar-reproducer)
to ease the task of verifying that the published APK binaries
include nothing but our publicly available source code.
You can either use those images or use them as a blueprint to build your own environment
for reproduction.
## Donate
[![Donate using Liberapay](https://briarproject.org/img/liberapay.svg)](https://liberapay.com/Briar/donate) [![Flattr this](https://briarproject.org/img/flattr-badge-large.png "Flattr this")](https://flattr.com/t/592836/)
Bitcoin and BCH: 1NZCKkUCtJV2U2Y9hDb9uq8S7ksFCFGR6K

View File

@@ -3,4 +3,3 @@ gen
build build
.settings .settings
src/main/res/raw/*.zip src/main/res/raw/*.zip
src/main/jniLibs

View File

@@ -5,18 +5,14 @@ apply plugin: 'witness'
apply from: 'witness.gradle' apply from: 'witness.gradle'
android { android {
compileSdkVersion 30 compileSdkVersion 29
buildToolsVersion '30.0.3' buildToolsVersion '29.0.2'
packagingOptions {
doNotStrip '**/*.so'
}
defaultConfig { defaultConfig {
minSdkVersion 16 minSdkVersion 16
targetSdkVersion 30 targetSdkVersion 28
versionCode 10411 versionCode 10209
versionName "1.4.11" versionName "1.2.9"
consumerProguardFiles 'proguard-rules.txt' consumerProguardFiles 'proguard-rules.txt'
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
@@ -42,27 +38,25 @@ configurations {
dependencies { dependencies {
implementation project(path: ':bramble-core', configuration: 'default') implementation project(path: ':bramble-core', configuration: 'default')
tor "org.briarproject:tor-android:$tor_version" tor 'org.briarproject:tor-android:0.3.5.10@zip'
tor "org.briarproject:obfs4proxy-android:$obfs4proxy_version" tor 'org.briarproject:obfs4proxy-android:0.0.11-2@zip'
annotationProcessor "com.google.dagger:dagger-compiler:$dagger_version" annotationProcessor 'com.google.dagger:dagger-compiler:2.24'
compileOnly 'javax.annotation:jsr250-api:1.0' compileOnly 'javax.annotation:jsr250-api:1.0'
testImplementation project(path: ':bramble-api', configuration: 'testOutput') testImplementation project(path: ':bramble-api', configuration: 'testOutput')
testImplementation "junit:junit:$junit_version" testImplementation 'junit:junit:4.12'
testImplementation "org.jmock:jmock:$jmock_version" testImplementation "org.jmock:jmock:2.8.2"
testImplementation "org.jmock:jmock-junit4:$jmock_version" testImplementation "org.jmock:jmock-junit4:2.8.2"
testImplementation "org.jmock:jmock-imposters:$jmock_version" testImplementation "org.jmock:jmock-legacy:2.8.2"
} }
def torBinariesDir = 'src/main/res/raw' def torBinariesDir = 'src/main/res/raw'
def torLibsDir = 'src/main/jniLibs'
task cleanTorBinaries { task cleanTorBinaries {
doLast { doLast {
delete fileTree(torBinariesDir) { include '*.zip' } delete fileTree(torBinariesDir) { include '*.zip' }
delete fileTree(torLibsDir) { include '**/*.so' }
} }
} }
@@ -70,34 +64,11 @@ clean.dependsOn cleanTorBinaries
task unpackTorBinaries { task unpackTorBinaries {
doLast { doLast {
configurations.tor.each { outer ->
zipTree(outer).each { inner ->
if (inner.name.endsWith('_arm_pie.zip')) {
copy { copy {
from zipTree(inner) from configurations.tor.collect { zipTree(it) }
into torLibsDir into torBinariesDir
rename '(.*)', 'armeabi-v7a/lib$1.so' // TODO: Remove after next Tor upgrade, which won't include non-PIE binaries
} include 'geoip.zip', '*_pie.zip'
} else if (inner.name.endsWith('_arm64_pie.zip')) {
copy {
from zipTree(inner)
into torLibsDir
rename '(.*)', 'arm64-v8a/lib$1.so'
}
} else if (inner.name.endsWith('_x86_pie.zip')) {
copy {
from zipTree(inner)
into torLibsDir
rename '(.*)', 'x86/lib$1.so'
}
} else if (inner.name.endsWith('_x86_64_pie.zip')) {
copy {
from zipTree(inner)
into torLibsDir
rename '(.*)', 'x86_64/lib$1.so'
}
}
}
} }
} }
dependsOn cleanTorBinaries dependsOn cleanTorBinaries
@@ -105,6 +76,5 @@ task unpackTorBinaries {
tasks.withType(MergeResources) { tasks.withType(MergeResources) {
inputs.dir torBinariesDir inputs.dir torBinariesDir
inputs.dir torLibsDir
dependsOn unpackTorBinaries dependsOn unpackTorBinaries
} }

View File

@@ -1,8 +1,6 @@
# Keep the H2 classes that are loaded via reflection -keep,includedescriptorclasses class org.briarproject.** { *; }
-keep class org.h2.Driver { *; }
-keep class org.h2.engine.Engine { *; } -keep class org.h2.** { *; }
-keep class org.h2.store.fs.** { *; }
# Don't warn about unused dependencies of H2 classes
-dontwarn org.h2.** -dontwarn org.h2.**
-dontnote org.h2.** -dontnote org.h2.**
@@ -17,8 +15,5 @@
-dontwarn sun.misc.Unsafe -dontwarn sun.misc.Unsafe
-dontnote com.google.common.** -dontnote com.google.common.**
-dontwarn com.fasterxml.jackson.databind.ext.Java7SupportImpl # UPnP library isn't used
-dontwarn org.bitlet.weupnp.**
# Keep all Jackson-serialisable classes and their members
-keep interface com.fasterxml.jackson.databind.annotation.JsonSerialize
-keep @com.fasterxml.jackson.databind.annotation.JsonSerialize class * { *; }

View File

@@ -1,7 +1,6 @@
package org.briarproject.bramble; package org.briarproject.bramble;
import org.briarproject.bramble.battery.AndroidBatteryModule; import org.briarproject.bramble.battery.AndroidBatteryModule;
import org.briarproject.bramble.io.DnsModule;
import org.briarproject.bramble.network.AndroidNetworkModule; import org.briarproject.bramble.network.AndroidNetworkModule;
import org.briarproject.bramble.plugin.tor.CircumventionModule; import org.briarproject.bramble.plugin.tor.CircumventionModule;
import org.briarproject.bramble.reporting.ReportingModule; import org.briarproject.bramble.reporting.ReportingModule;
@@ -19,7 +18,6 @@ import dagger.Module;
AndroidTaskSchedulerModule.class, AndroidTaskSchedulerModule.class,
AndroidWakefulIoExecutorModule.class, AndroidWakefulIoExecutorModule.class,
CircumventionModule.class, CircumventionModule.class,
DnsModule.class,
ReportingModule.class, ReportingModule.class,
SocksModule.class SocksModule.class
}) })

View File

@@ -1,20 +1,13 @@
package org.briarproject.bramble.network; package org.briarproject.bramble.network;
import android.annotation.TargetApi;
import android.app.Application; import android.app.Application;
import android.content.BroadcastReceiver; import android.content.BroadcastReceiver;
import android.content.Context; import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.content.IntentFilter; import android.content.IntentFilter;
import android.net.ConnectivityManager; import android.net.ConnectivityManager;
import android.net.LinkAddress;
import android.net.LinkProperties;
import android.net.Network;
import android.net.NetworkInfo; import android.net.NetworkInfo;
import android.net.wifi.WifiInfo;
import android.net.wifi.WifiManager;
import org.briarproject.bramble.api.Cancellable;
import org.briarproject.bramble.api.event.EventBus; import org.briarproject.bramble.api.event.EventBus;
import org.briarproject.bramble.api.event.EventExecutor; import org.briarproject.bramble.api.event.EventExecutor;
import org.briarproject.bramble.api.lifecycle.Service; import org.briarproject.bramble.api.lifecycle.Service;
@@ -24,12 +17,8 @@ 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.system.TaskScheduler; import org.briarproject.bramble.api.system.TaskScheduler;
import org.briarproject.bramble.api.system.TaskScheduler.Cancellable;
import java.net.Inet4Address;
import java.net.InetAddress;
import java.net.NetworkInterface;
import java.net.SocketException;
import java.util.Enumeration;
import java.util.concurrent.Executor; import java.util.concurrent.Executor;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicBoolean;
@@ -40,7 +29,6 @@ import javax.annotation.Nullable;
import javax.inject.Inject; import javax.inject.Inject;
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.Intent.ACTION_SCREEN_OFF; import static android.content.Intent.ACTION_SCREEN_OFF;
import static android.content.Intent.ACTION_SCREEN_ON; import static android.content.Intent.ACTION_SCREEN_ON;
import static android.net.ConnectivityManager.CONNECTIVITY_ACTION; import static android.net.ConnectivityManager.CONNECTIVITY_ACTION;
@@ -48,22 +36,16 @@ import static android.net.ConnectivityManager.TYPE_WIFI;
import static android.net.wifi.p2p.WifiP2pManager.WIFI_P2P_THIS_DEVICE_CHANGED_ACTION; import static android.net.wifi.p2p.WifiP2pManager.WIFI_P2P_THIS_DEVICE_CHANGED_ACTION;
import static android.os.Build.VERSION.SDK_INT; import static android.os.Build.VERSION.SDK_INT;
import static android.os.PowerManager.ACTION_DEVICE_IDLE_MODE_CHANGED; import static android.os.PowerManager.ACTION_DEVICE_IDLE_MODE_CHANGED;
import static java.net.NetworkInterface.getNetworkInterfaces;
import static java.util.Collections.list;
import static java.util.concurrent.TimeUnit.MINUTES; import static java.util.concurrent.TimeUnit.MINUTES;
import static java.util.concurrent.TimeUnit.SECONDS; import static java.util.concurrent.TimeUnit.SECONDS;
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.Logger.getLogger;
import static org.briarproject.bramble.api.nullsafety.NullSafety.requireNonNull;
import static org.briarproject.bramble.util.LogUtils.logException;
@MethodsNotNullByDefault @MethodsNotNullByDefault
@ParametersNotNullByDefault @ParametersNotNullByDefault
class AndroidNetworkManager implements NetworkManager, Service { class AndroidNetworkManager implements NetworkManager, Service {
private static final Logger LOG = private static final Logger LOG =
getLogger(AndroidNetworkManager.class.getName()); Logger.getLogger(AndroidNetworkManager.class.getName());
// See android.net.wifi.WifiManager // See android.net.wifi.WifiManager
private static final String WIFI_AP_STATE_CHANGED_ACTION = private static final String WIFI_AP_STATE_CHANGED_ACTION =
@@ -72,8 +54,7 @@ class AndroidNetworkManager implements NetworkManager, Service {
private final TaskScheduler scheduler; private final TaskScheduler scheduler;
private final EventBus eventBus; private final EventBus eventBus;
private final Executor eventExecutor; private final Executor eventExecutor;
private final Application app; private final Context appContext;
private final ConnectivityManager connectivityManager;
private final AtomicReference<Cancellable> connectivityCheck = private final AtomicReference<Cancellable> connectivityCheck =
new AtomicReference<>(); new AtomicReference<>();
private final AtomicBoolean used = new AtomicBoolean(false); private final AtomicBoolean used = new AtomicBoolean(false);
@@ -86,9 +67,7 @@ class AndroidNetworkManager implements NetworkManager, Service {
this.scheduler = scheduler; this.scheduler = scheduler;
this.eventBus = eventBus; this.eventBus = eventBus;
this.eventExecutor = eventExecutor; this.eventExecutor = eventExecutor;
this.app = app; this.appContext = app.getApplicationContext();
connectivityManager = (ConnectivityManager)
requireNonNull(app.getSystemService(CONNECTIVITY_SERVICE));
} }
@Override @Override
@@ -103,110 +82,24 @@ class AndroidNetworkManager implements NetworkManager, Service {
filter.addAction(WIFI_AP_STATE_CHANGED_ACTION); filter.addAction(WIFI_AP_STATE_CHANGED_ACTION);
filter.addAction(WIFI_P2P_THIS_DEVICE_CHANGED_ACTION); filter.addAction(WIFI_P2P_THIS_DEVICE_CHANGED_ACTION);
if (SDK_INT >= 23) filter.addAction(ACTION_DEVICE_IDLE_MODE_CHANGED); if (SDK_INT >= 23) filter.addAction(ACTION_DEVICE_IDLE_MODE_CHANGED);
app.registerReceiver(networkStateReceiver, filter); appContext.registerReceiver(networkStateReceiver, filter);
} }
@Override @Override
public void stopService() { public void stopService() {
if (networkStateReceiver != null) if (networkStateReceiver != null)
app.unregisterReceiver(networkStateReceiver); appContext.unregisterReceiver(networkStateReceiver);
} }
@Override @Override
public NetworkStatus getNetworkStatus() { public NetworkStatus getNetworkStatus() {
// https://issuetracker.google.com/issues/175055271 ConnectivityManager cm = (ConnectivityManager)
try { appContext.getSystemService(CONNECTIVITY_SERVICE);
NetworkInfo net = connectivityManager.getActiveNetworkInfo(); if (cm == null) throw new AssertionError();
NetworkInfo net = cm.getActiveNetworkInfo();
boolean connected = net != null && net.isConnected(); boolean connected = net != null && net.isConnected();
boolean wifi = false, ipv6Only = false; boolean wifi = connected && net.getType() == TYPE_WIFI;
if (connected) { return new NetworkStatus(connected, wifi);
wifi = net.getType() == TYPE_WIFI;
if (SDK_INT >= 23) ipv6Only = isActiveNetworkIpv6Only();
else ipv6Only = areAllAvailableNetworksIpv6Only();
}
return new NetworkStatus(connected, wifi, ipv6Only);
} catch (SecurityException e) {
logException(LOG, WARNING, e);
// Without the ConnectivityManager we can't detect whether we have
// internet access. Assume we do, which is probably less harmful
// than assuming we don't. Likewise, assume the connection is
// IPv6-only. Fall back to the WifiManager to detect whether we
// have a wifi connection.
LOG.info("ConnectivityManager is broken, guessing connectivity");
boolean connected = true, wifi = false, ipv6Only = true;
WifiManager wm = (WifiManager) app.getSystemService(WIFI_SERVICE);
if (wm != null) {
WifiInfo info = wm.getConnectionInfo();
if (info != null && info.getIpAddress() != 0) {
LOG.info("Connected to wifi");
wifi = true;
ipv6Only = false;
}
}
return new NetworkStatus(connected, wifi, ipv6Only);
}
}
/**
* Returns true if the
* {@link ConnectivityManager#getActiveNetwork() active network} has an
* IPv6 unicast address and no IPv4 addresses. The active network is
* assumed not to be a loopback interface.
*/
@TargetApi(23)
private boolean isActiveNetworkIpv6Only() {
// https://issuetracker.google.com/issues/175055271
try {
Network net = connectivityManager.getActiveNetwork();
if (net == null) {
LOG.info("No active network");
return false;
}
LinkProperties props = connectivityManager.getLinkProperties(net);
if (props == null) {
LOG.info("No link properties for active network");
return false;
}
boolean hasIpv6Unicast = false;
for (LinkAddress linkAddress : props.getLinkAddresses()) {
InetAddress addr = linkAddress.getAddress();
if (addr instanceof Inet4Address) return false;
if (!addr.isMulticastAddress()) hasIpv6Unicast = true;
}
return hasIpv6Unicast;
} catch (SecurityException e) {
logException(LOG, WARNING, e);
return false;
}
}
/**
* Returns true if the device has at least one network interface with an
* IPv6 unicast address and no interfaces with IPv4 addresses, excluding
* loopback interfaces and interfaces that are
* {@link NetworkInterface#isUp() down}. If this method returns true and
* the device has internet access then it's via IPv6 only.
*/
private boolean areAllAvailableNetworksIpv6Only() {
try {
Enumeration<NetworkInterface> interfaces = getNetworkInterfaces();
if (interfaces == null) {
LOG.info("No network interfaces");
return false;
}
boolean hasIpv6Unicast = false;
for (NetworkInterface i : list(interfaces)) {
if (i.isLoopback() || !i.isUp()) continue;
for (InetAddress addr : list(i.getInetAddresses())) {
if (addr instanceof Inet4Address) return false;
if (!addr.isMulticastAddress()) hasIpv6Unicast = true;
}
}
return hasIpv6Unicast;
} catch (SocketException e) {
logException(LOG, WARNING, e);
return false;
}
} }
private void updateConnectionStatus() { private void updateConnectionStatus() {

View File

@@ -59,8 +59,8 @@ import static org.briarproject.bramble.util.PrivacyUtils.scrubMacAddress;
@MethodsNotNullByDefault @MethodsNotNullByDefault
@ParametersNotNullByDefault @ParametersNotNullByDefault
class AndroidBluetoothPlugin extends class AndroidBluetoothPlugin
AbstractBluetoothPlugin<BluetoothSocket, BluetoothServerSocket> { extends BluetoothPlugin<BluetoothSocket, BluetoothServerSocket> {
private static final Logger LOG = private static final Logger LOG =
getLogger(AndroidBluetoothPlugin.class.getName()); getLogger(AndroidBluetoothPlugin.class.getName());
@@ -75,7 +75,6 @@ class AndroidBluetoothPlugin extends
// Non-null if the plugin started successfully // Non-null if the plugin started successfully
private volatile BluetoothAdapter adapter = null; private volatile BluetoothAdapter adapter = null;
private volatile boolean stopDiscoverAndConnect;
AndroidBluetoothPlugin(BluetoothConnectionLimiter connectionLimiter, AndroidBluetoothPlugin(BluetoothConnectionLimiter connectionLimiter,
BluetoothConnectionFactory<BluetoothSocket> connectionFactory, BluetoothConnectionFactory<BluetoothSocket> connectionFactory,
@@ -87,7 +86,7 @@ class AndroidBluetoothPlugin extends
Clock clock, Clock clock,
Backoff backoff, Backoff backoff,
PluginCallback callback, PluginCallback callback,
long maxLatency, int maxLatency,
int maxIdleTime) { int maxIdleTime) {
super(connectionLimiter, connectionFactory, ioExecutor, super(connectionLimiter, connectionFactory, ioExecutor,
wakefulIoExecutor, secureRandom, backoff, callback, wakefulIoExecutor, secureRandom, backoff, callback,
@@ -136,7 +135,6 @@ class AndroidBluetoothPlugin extends
@Override @Override
@Nullable @Nullable
String getBluetoothAddress() { String getBluetoothAddress() {
if (adapter == null) return null;
String address = AndroidUtils.getBluetoothAddress(app, adapter); String address = AndroidUtils.getBluetoothAddress(app, adapter);
return address.isEmpty() ? null : address; return address.isEmpty() ? null : address;
} }
@@ -176,11 +174,6 @@ class AndroidBluetoothPlugin extends
} catch (IOException e) { } catch (IOException e) {
IoUtils.tryToClose(s, LOG, WARNING); IoUtils.tryToClose(s, LOG, WARNING);
throw e; throw e;
} catch (NullPointerException e) {
// BluetoothSocket#connect() may throw an NPE under unknown
// circumstances
IoUtils.tryToClose(s, LOG, WARNING);
throw new IOException(e);
} }
} }
@@ -188,16 +181,7 @@ class AndroidBluetoothPlugin extends
@Nullable @Nullable
DuplexTransportConnection discoverAndConnect(String uuid) { DuplexTransportConnection discoverAndConnect(String uuid) {
if (adapter == null) return null; if (adapter == null) return null;
if (!discoverSemaphore.tryAcquire()) {
LOG.info("Discover already running");
return null;
}
try {
stopDiscoverAndConnect = false;
for (String address : discoverDevices()) { for (String address : discoverDevices()) {
if (stopDiscoverAndConnect) {
break;
}
try { try {
if (LOG.isLoggable(INFO)) if (LOG.isLoggable(INFO))
LOG.info("Connecting to " + scrubMacAddress(address)); LOG.info("Connecting to " + scrubMacAddress(address));
@@ -209,19 +193,10 @@ class AndroidBluetoothPlugin extends
} }
} }
} }
} finally {
discoverSemaphore.release();
}
LOG.info("Could not connect to any devices"); LOG.info("Could not connect to any devices");
return null; return null;
} }
@Override
public void stopDiscoverAndConnect() {
stopDiscoverAndConnect = true;
adapter.cancelDiscovery();
}
private Collection<String> discoverDevices() { private Collection<String> discoverDevices() {
List<String> addresses = new ArrayList<>(); List<String> addresses = new ArrayList<>();
BlockingQueue<Intent> intents = new LinkedBlockingQueue<>(); BlockingQueue<Intent> intents = new LinkedBlockingQueue<>();

View File

@@ -47,7 +47,7 @@ public class AndroidBluetoothPluginFactory implements DuplexPluginFactory {
private final BackoffFactory backoffFactory; private final BackoffFactory backoffFactory;
@Inject @Inject
AndroidBluetoothPluginFactory(@IoExecutor Executor ioExecutor, public AndroidBluetoothPluginFactory(@IoExecutor Executor ioExecutor,
@WakefulIoExecutor Executor wakefulIoExecutor, @WakefulIoExecutor Executor wakefulIoExecutor,
AndroidExecutor androidExecutor, AndroidExecutor androidExecutor,
AndroidWakeLockManager wakeLockManager, AndroidWakeLockManager wakeLockManager,
@@ -75,7 +75,7 @@ public class AndroidBluetoothPluginFactory implements DuplexPluginFactory {
} }
@Override @Override
public long getMaxLatency() { public int getMaxLatency() {
return MAX_LATENCY; return MAX_LATENCY;
} }

View File

@@ -1,53 +0,0 @@
package org.briarproject.bramble.plugin.file;
import android.app.Application;
import android.net.Uri;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import org.briarproject.bramble.api.plugin.PluginCallback;
import org.briarproject.bramble.api.properties.TransportProperties;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import javax.annotation.concurrent.Immutable;
import static org.briarproject.bramble.api.plugin.file.RemovableDriveConstants.PROP_URI;
import static org.briarproject.bramble.util.StringUtils.isNullOrEmpty;
@Immutable
@NotNullByDefault
class AndroidRemovableDrivePlugin extends RemovableDrivePlugin {
private final Application app;
AndroidRemovableDrivePlugin(Application app, PluginCallback callback,
long maxLatency) {
super(callback, maxLatency);
this.app = app;
}
@Override
InputStream openInputStream(TransportProperties p) throws IOException {
String uri = p.get(PROP_URI);
if (isNullOrEmpty(uri)) throw new IllegalArgumentException();
try {
return app.getContentResolver().openInputStream(Uri.parse(uri));
} catch (SecurityException e) {
throw new IOException(e);
}
}
@Override
OutputStream openOutputStream(TransportProperties p) throws IOException {
String uri = p.get(PROP_URI);
if (isNullOrEmpty(uri)) throw new IllegalArgumentException();
try {
return app.getContentResolver()
.openOutputStream(Uri.parse(uri), "wt");
} catch (SecurityException e) {
throw new IOException(e);
}
}
}

View File

@@ -1,47 +0,0 @@
package org.briarproject.bramble.plugin.file;
import android.app.Application;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import org.briarproject.bramble.api.plugin.PluginCallback;
import org.briarproject.bramble.api.plugin.TransportId;
import org.briarproject.bramble.api.plugin.simplex.SimplexPlugin;
import org.briarproject.bramble.api.plugin.simplex.SimplexPluginFactory;
import javax.annotation.Nullable;
import javax.annotation.concurrent.Immutable;
import javax.inject.Inject;
import static java.util.concurrent.TimeUnit.DAYS;
import static org.briarproject.bramble.api.plugin.file.RemovableDriveConstants.ID;
@Immutable
@NotNullByDefault
public class AndroidRemovableDrivePluginFactory implements
SimplexPluginFactory {
private static final long MAX_LATENCY = DAYS.toMillis(28);
private final Application app;
@Inject
AndroidRemovableDrivePluginFactory(Application app) {
this.app = app;
}
@Override
public TransportId getId() {
return ID;
}
@Override
public long getMaxLatency() {
return MAX_LATENCY;
}
@Nullable
@Override
public SimplexPlugin createPlugin(PluginCallback callback) {
return new AndroidRemovableDrivePlugin(app, callback, MAX_LATENCY);
}
}

View File

@@ -29,7 +29,6 @@ import java.net.UnknownHostException;
import java.util.List; import java.util.List;
import java.util.concurrent.Executor; import java.util.concurrent.Executor;
import java.util.logging.Logger; import java.util.logging.Logger;
import java.util.regex.Pattern;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import javax.net.SocketFactory; import javax.net.SocketFactory;
@@ -49,7 +48,6 @@ import static org.briarproject.bramble.api.plugin.Plugin.State.ACTIVE;
import static org.briarproject.bramble.api.plugin.Plugin.State.INACTIVE; import static org.briarproject.bramble.api.plugin.Plugin.State.INACTIVE;
import static org.briarproject.bramble.util.IoUtils.tryToClose; import static org.briarproject.bramble.util.IoUtils.tryToClose;
import static org.briarproject.bramble.util.LogUtils.logException; import static org.briarproject.bramble.util.LogUtils.logException;
import static org.briarproject.bramble.util.NetworkUtils.getNetworkInterfaces;
@NotNullByDefault @NotNullByDefault
class AndroidLanTcpPlugin extends LanTcpPlugin { class AndroidLanTcpPlugin extends LanTcpPlugin {
@@ -57,13 +55,6 @@ class AndroidLanTcpPlugin extends LanTcpPlugin {
private static final Logger LOG = private static final Logger LOG =
getLogger(AndroidLanTcpPlugin.class.getName()); getLogger(AndroidLanTcpPlugin.class.getName());
/**
* The interface name is used as a heuristic for deciding whether the
* device is providing a wifi access point.
*/
private static final Pattern AP_INTERFACE_NAME =
Pattern.compile("^(wlan|ap|p2p)[-0-9]");
private final Executor connectionStatusExecutor; private final Executor connectionStatusExecutor;
private final ConnectivityManager connectivityManager; private final ConnectivityManager connectivityManager;
@Nullable @Nullable
@@ -76,7 +67,7 @@ class AndroidLanTcpPlugin extends LanTcpPlugin {
Application app, Application app,
Backoff backoff, Backoff backoff,
PluginCallback callback, PluginCallback callback,
long maxLatency, int maxLatency,
int maxIdleTime, int maxIdleTime,
int connectionTimeout) { int connectionTimeout) {
super(ioExecutor, wakefulIoExecutor, backoff, callback, maxLatency, super(ioExecutor, wakefulIoExecutor, backoff, callback, maxLatency,
@@ -139,14 +130,17 @@ class AndroidLanTcpPlugin extends LanTcpPlugin {
if (info != null && info.getIpAddress() != 0) { if (info != null && info.getIpAddress() != 0) {
return new Pair<>(intToInetAddress(info.getIpAddress()), false); return new Pair<>(intToInetAddress(info.getIpAddress()), false);
} }
// If we're providing an access point, return its address List<InterfaceAddress> ifAddrs = getLocalInterfaceAddresses();
for (NetworkInterface iface : getNetworkInterfaces()) { // If we're providing a normal access point, return its address
if (AP_INTERFACE_NAME.matcher(iface.getName()).find()) { for (InterfaceAddress ifAddr : ifAddrs) {
for (InterfaceAddress ifAddr : iface.getInterfaceAddresses()) { if (isAndroidWifiApAddress(ifAddr)) {
if (isPossibleWifiApInterface(ifAddr)) {
return new Pair<>(ifAddr.getAddress(), true); return new Pair<>(ifAddr.getAddress(), true);
} }
} }
// If we're providing a wifi direct access point, return its address
for (InterfaceAddress ifAddr : ifAddrs) {
if (isAndroidWifiDirectApAddress(ifAddr)) {
return new Pair<>(ifAddr.getAddress(), true);
} }
} }
// Not connected to wifi // Not connected to wifi
@@ -154,18 +148,33 @@ class AndroidLanTcpPlugin extends LanTcpPlugin {
} }
/** /**
* Returns true if the given address may belong to an interface providing * Returns true if the given address belongs to a network provided by an
* a wifi access point (including wifi direct legacy mode access points). * Android access point (including the access point's own address).
* <p> * <p>
* This method may return true for wifi client interfaces as well, but * The access point's address is usually 192.168.43.1, but at least one
* we've already checked for a wifi client connection above. * device (Honor 8A) may use other addresses in the range 192.168.43.0/24.
*/ */
private boolean isPossibleWifiApInterface(InterfaceAddress ifAddr) { private boolean isAndroidWifiApAddress(InterfaceAddress ifAddr) {
if (ifAddr.getNetworkPrefixLength() != 24) return false; if (ifAddr.getNetworkPrefixLength() != 24) return false;
byte[] ip = ifAddr.getAddress().getAddress(); byte[] ip = ifAddr.getAddress().getAddress();
return ip.length == 4 return ip.length == 4
&& ip[0] == (byte) 192 && ip[0] == (byte) 192
&& ip[1] == (byte) 168; && ip[1] == (byte) 168
&& ip[2] == (byte) 43;
}
/**
* Returns true if the given address belongs to a network provided by an
* Android wifi direct legacy mode access point (including the access
* point's own address).
*/
private boolean isAndroidWifiDirectApAddress(InterfaceAddress ifAddr) {
if (ifAddr.getNetworkPrefixLength() != 24) return false;
byte[] ip = ifAddr.getAddress().getAddress();
return ip.length == 4
&& ip[0] == (byte) 192
&& ip[1] == (byte) 168
&& ip[2] == (byte) 49;
} }
/** /**
@@ -175,25 +184,17 @@ class AndroidLanTcpPlugin extends LanTcpPlugin {
@TargetApi(21) @TargetApi(21)
@Nullable @Nullable
private InetAddress getWifiClientIpv6Address() { private InetAddress getWifiClientIpv6Address() {
// https://issuetracker.google.com/issues/175055271
try {
for (Network net : connectivityManager.getAllNetworks()) { for (Network net : connectivityManager.getAllNetworks()) {
NetworkCapabilities caps = NetworkCapabilities caps =
connectivityManager.getNetworkCapabilities(net); connectivityManager.getNetworkCapabilities(net);
if (caps == null || !caps.hasTransport(TRANSPORT_WIFI)) { if (caps == null || !caps.hasTransport(TRANSPORT_WIFI)) continue;
continue; LinkProperties props = connectivityManager.getLinkProperties(net);
}
LinkProperties props =
connectivityManager.getLinkProperties(net);
if (props == null) continue; if (props == null) continue;
for (LinkAddress linkAddress : props.getLinkAddresses()) { for (LinkAddress linkAddress : props.getLinkAddresses()) {
InetAddress addr = linkAddress.getAddress(); InetAddress addr = linkAddress.getAddress();
if (isIpv6LinkLocalAddress(addr)) return addr; if (isIpv6LinkLocalAddress(addr)) return addr;
} }
} }
} catch (SecurityException e) {
logException(LOG, WARNING, e);
}
return null; return null;
} }
@@ -235,8 +236,6 @@ class AndroidLanTcpPlugin extends LanTcpPlugin {
// network's socket factory may try to connect via another network // network's socket factory may try to connect via another network
private SocketFactory getSocketFactory() { private SocketFactory getSocketFactory() {
if (SDK_INT < 21) return SocketFactory.getDefault(); if (SDK_INT < 21) return SocketFactory.getDefault();
// https://issuetracker.google.com/issues/175055271
try {
for (Network net : connectivityManager.getAllNetworks()) { for (Network net : connectivityManager.getAllNetworks()) {
NetworkCapabilities caps = NetworkCapabilities caps =
connectivityManager.getNetworkCapabilities(net); connectivityManager.getNetworkCapabilities(net);
@@ -244,9 +243,6 @@ class AndroidLanTcpPlugin extends LanTcpPlugin {
return net.getSocketFactory(); return net.getSocketFactory();
} }
} }
} catch (SecurityException e) {
logException(LOG, WARNING, e);
}
LOG.warning("Could not find suitable socket factory"); LOG.warning("Could not find suitable socket factory");
return SocketFactory.getDefault(); return SocketFactory.getDefault();
} }

View File

@@ -37,7 +37,7 @@ public class AndroidLanTcpPluginFactory implements DuplexPluginFactory {
private final Application app; private final Application app;
@Inject @Inject
AndroidLanTcpPluginFactory(@IoExecutor Executor ioExecutor, public AndroidLanTcpPluginFactory(@IoExecutor Executor ioExecutor,
@WakefulIoExecutor Executor wakefulIoExecutor, @WakefulIoExecutor Executor wakefulIoExecutor,
EventBus eventBus, EventBus eventBus,
BackoffFactory backoffFactory, BackoffFactory backoffFactory,
@@ -55,7 +55,7 @@ public class AndroidLanTcpPluginFactory implements DuplexPluginFactory {
} }
@Override @Override
public long getMaxLatency() { public int getMaxLatency() {
return MAX_LATENCY; return MAX_LATENCY;
} }

View File

@@ -16,42 +16,19 @@ import org.briarproject.bramble.api.system.AndroidWakeLockManager;
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.ResourceProvider;
import org.briarproject.bramble.util.AndroidUtils;
import java.io.File; import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException; import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Executor; import java.util.concurrent.Executor;
import java.util.logging.Logger;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
import javax.net.SocketFactory; import javax.net.SocketFactory;
import static android.os.Build.VERSION.SDK_INT;
import static java.util.Arrays.asList;
import static java.util.logging.Level.INFO;
import static java.util.logging.Logger.getLogger;
@MethodsNotNullByDefault @MethodsNotNullByDefault
@ParametersNotNullByDefault @ParametersNotNullByDefault
class AndroidTorPlugin extends TorPlugin { class AndroidTorPlugin extends TorPlugin {
private static final List<String> LIBRARY_ARCHITECTURES =
asList("armeabi-v7a", "arm64-v8a", "x86", "x86_64");
private static final String TOR_LIB_NAME = "libtor.so";
private static final String OBFS4_LIB_NAME = "libobfs4proxy.so";
private static final Logger LOG =
getLogger(AndroidTorPlugin.class.getName());
private final Application app; private final Application app;
private final AndroidWakeLock wakeLock; private final AndroidWakeLock wakeLock;
private final File torLib, obfs4Lib;
AndroidTorPlugin(Executor ioExecutor, AndroidTorPlugin(Executor ioExecutor,
Executor wakefulIoExecutor, Executor wakefulIoExecutor,
@@ -68,21 +45,16 @@ class AndroidTorPlugin extends TorPlugin {
TorRendezvousCrypto torRendezvousCrypto, TorRendezvousCrypto torRendezvousCrypto,
PluginCallback callback, PluginCallback callback,
String architecture, String architecture,
long maxLatency, int maxLatency,
int maxIdleTime, int maxIdleTime,
File torDirectory, File torDirectory) {
int torSocksPort,
int torControlPort) {
super(ioExecutor, wakefulIoExecutor, networkManager, locationUtils, super(ioExecutor, wakefulIoExecutor, networkManager, locationUtils,
torSocketFactory, clock, resourceProvider, torSocketFactory, clock, resourceProvider,
circumventionProvider, batteryManager, backoff, circumventionProvider, batteryManager, backoff,
torRendezvousCrypto, callback, architecture, maxLatency, torRendezvousCrypto, callback, architecture, maxLatency,
maxIdleTime, torDirectory, torSocksPort, torControlPort); maxIdleTime, torDirectory);
this.app = app; this.app = app;
wakeLock = wakeLockManager.createWakeLock("TorPlugin"); wakeLock = wakeLockManager.createWakeLock("TorPlugin");
String nativeLibDir = app.getApplicationInfo().nativeLibraryDir;
torLib = new File(nativeLibDir, TOR_LIB_NAME);
obfs4Lib = new File(nativeLibDir, OBFS4_LIB_NAME);
} }
@Override @Override
@@ -113,112 +85,4 @@ class AndroidTorPlugin extends TorPlugin {
super.stop(); super.stop();
wakeLock.release(); wakeLock.release();
} }
@Override
protected File getTorExecutableFile() {
return torLib.exists() ? torLib : super.getTorExecutableFile();
}
@Override
protected File getObfs4ExecutableFile() {
return obfs4Lib.exists() ? obfs4Lib : super.getObfs4ExecutableFile();
}
@Override
protected void installTorExecutable() throws IOException {
File extracted = super.getTorExecutableFile();
if (torLib.exists()) {
// If an older version left behind a Tor binary, delete it
if (extracted.exists()) {
if (extracted.delete()) LOG.info("Deleted Tor binary");
else LOG.info("Failed to delete Tor binary");
}
} else if (SDK_INT < 29) {
// The binary wasn't extracted at install time. Try to extract it
extractLibraryFromApk(TOR_LIB_NAME, extracted);
} else {
// No point extracting the binary, we won't be allowed to execute it
throw new FileNotFoundException(torLib.getAbsolutePath());
}
}
@Override
protected void installObfs4Executable() throws IOException {
File extracted = super.getObfs4ExecutableFile();
if (obfs4Lib.exists()) {
// If an older version left behind an obfs4 binary, delete it
if (extracted.exists()) {
if (extracted.delete()) LOG.info("Deleted obfs4 binary");
else LOG.info("Failed to delete obfs4 binary");
}
} else if (SDK_INT < 29) {
// The binary wasn't extracted at install time. Try to extract it
extractLibraryFromApk(OBFS4_LIB_NAME, extracted);
} else {
// No point extracting the binary, we won't be allowed to execute it
throw new FileNotFoundException(obfs4Lib.getAbsolutePath());
}
}
private void extractLibraryFromApk(String libName, File dest)
throws IOException {
File sourceDir = new File(app.getApplicationInfo().sourceDir);
if (sourceDir.isFile()) {
// Look for other APK files in the same directory, if we're allowed
File parent = sourceDir.getParentFile();
if (parent != null) sourceDir = parent;
}
List<String> libPaths = getSupportedLibraryPaths(libName);
for (File apk : findApkFiles(sourceDir)) {
ZipInputStream zin = new ZipInputStream(new FileInputStream(apk));
for (ZipEntry e = zin.getNextEntry(); e != null;
e = zin.getNextEntry()) {
if (libPaths.contains(e.getName())) {
if (LOG.isLoggable(INFO)) {
LOG.info("Extracting " + e.getName()
+ " from " + apk.getAbsolutePath());
}
extract(zin, dest); // Zip input stream will be closed
return;
}
}
zin.close();
}
throw new FileNotFoundException(libName);
}
/**
* Returns all files with the extension .apk or .APK under the given root.
*/
private List<File> findApkFiles(File root) {
List<File> files = new ArrayList<>();
findApkFiles(root, files);
return files;
}
private void findApkFiles(File f, List<File> files) {
if (f.isFile() && f.getName().toLowerCase().endsWith(".apk")) {
files.add(f);
} else if (f.isDirectory()) {
File[] children = f.listFiles();
if (children != null) {
for (File child : children) findApkFiles(child, files);
}
}
}
/**
* Returns the paths at which libraries with the given name would be found
* inside an APK file, for all architectures supported by the device, in
* order of preference.
*/
private List<String> getSupportedLibraryPaths(String libName) {
List<String> architectures = new ArrayList<>();
for (String abi : AndroidUtils.getSupportedArchitectures()) {
if (LIBRARY_ARCHITECTURES.contains(abi)) {
architectures.add("lib/" + abi + "/" + libName);
}
}
return architectures;
}
} }

View File

@@ -3,7 +3,6 @@ package org.briarproject.bramble.plugin.tor;
import android.app.Application; import android.app.Application;
import org.briarproject.bramble.api.battery.BatteryManager; import org.briarproject.bramble.api.battery.BatteryManager;
import org.briarproject.bramble.api.crypto.CryptoComponent;
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.network.NetworkManager; import org.briarproject.bramble.api.network.NetworkManager;
@@ -11,35 +10,57 @@ 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;
import org.briarproject.bramble.api.plugin.PluginCallback; import org.briarproject.bramble.api.plugin.PluginCallback;
import org.briarproject.bramble.api.plugin.TorControlPort; import org.briarproject.bramble.api.plugin.TorConstants;
import org.briarproject.bramble.api.plugin.TorDirectory; import org.briarproject.bramble.api.plugin.TorDirectory;
import org.briarproject.bramble.api.plugin.TorSocksPort; import org.briarproject.bramble.api.plugin.TransportId;
import org.briarproject.bramble.api.plugin.duplex.DuplexPlugin;
import org.briarproject.bramble.api.plugin.duplex.DuplexPluginFactory;
import org.briarproject.bramble.api.system.AndroidWakeLockManager; import org.briarproject.bramble.api.system.AndroidWakeLockManager;
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.ResourceProvider;
import org.briarproject.bramble.api.system.WakefulIoExecutor; import org.briarproject.bramble.api.system.WakefulIoExecutor;
import org.briarproject.bramble.util.AndroidUtils;
import java.io.File; import java.io.File;
import java.util.concurrent.Executor; import java.util.concurrent.Executor;
import java.util.logging.Logger;
import javax.annotation.Nullable;
import javax.annotation.concurrent.Immutable; import javax.annotation.concurrent.Immutable;
import javax.inject.Inject; import javax.inject.Inject;
import javax.net.SocketFactory; import javax.net.SocketFactory;
import static org.briarproject.bramble.util.AndroidUtils.getSupportedArchitectures;
@Immutable @Immutable
@NotNullByDefault @NotNullByDefault
public class AndroidTorPluginFactory extends TorPluginFactory { public class AndroidTorPluginFactory implements DuplexPluginFactory {
private static final Logger LOG =
Logger.getLogger(AndroidTorPluginFactory.class.getName());
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 MIN_POLLING_INTERVAL = 60 * 1000; // 1 minute
private static final int MAX_POLLING_INTERVAL = 10 * 60 * 1000; // 10 mins
private static final double BACKOFF_BASE = 1.2;
private final Executor ioExecutor, wakefulIoExecutor;
private final Application app; private final Application app;
private final NetworkManager networkManager;
private final LocationUtils locationUtils;
private final EventBus eventBus;
private final SocketFactory torSocketFactory;
private final BackoffFactory backoffFactory;
private final ResourceProvider resourceProvider;
private final CircumventionProvider circumventionProvider;
private final BatteryManager batteryManager;
private final AndroidWakeLockManager wakeLockManager; private final AndroidWakeLockManager wakeLockManager;
private final Clock clock;
private final File torDirectory;
@Inject @Inject
AndroidTorPluginFactory(@IoExecutor Executor ioExecutor, public AndroidTorPluginFactory(@IoExecutor Executor ioExecutor,
@WakefulIoExecutor Executor wakefulIoExecutor, @WakefulIoExecutor Executor wakefulIoExecutor,
Application app,
NetworkManager networkManager, NetworkManager networkManager,
LocationUtils locationUtils, LocationUtils locationUtils,
EventBus eventBus, EventBus eventBus,
@@ -48,43 +69,72 @@ public class AndroidTorPluginFactory extends TorPluginFactory {
ResourceProvider resourceProvider, ResourceProvider resourceProvider,
CircumventionProvider circumventionProvider, CircumventionProvider circumventionProvider,
BatteryManager batteryManager, BatteryManager batteryManager,
AndroidWakeLockManager wakeLockManager,
Clock clock, Clock clock,
CryptoComponent crypto, @TorDirectory File torDirectory) {
@TorDirectory File torDirectory, this.ioExecutor = ioExecutor;
@TorSocksPort int torSocksPort, this.wakefulIoExecutor = wakefulIoExecutor;
@TorControlPort int torControlPort,
Application app,
AndroidWakeLockManager wakeLockManager) {
super(ioExecutor, wakefulIoExecutor, networkManager, locationUtils,
eventBus, torSocketFactory, backoffFactory, resourceProvider,
circumventionProvider, batteryManager, clock, crypto,
torDirectory, torSocksPort, torControlPort);
this.app = app; this.app = app;
this.networkManager = networkManager;
this.locationUtils = locationUtils;
this.eventBus = eventBus;
this.torSocketFactory = torSocketFactory;
this.backoffFactory = backoffFactory;
this.resourceProvider = resourceProvider;
this.circumventionProvider = circumventionProvider;
this.batteryManager = batteryManager;
this.wakeLockManager = wakeLockManager; this.wakeLockManager = wakeLockManager;
this.clock = clock;
this.torDirectory = torDirectory;
} }
@Nullable
@Override @Override
String getArchitectureForTorBinary() { public TransportId getId() {
for (String abi : getSupportedArchitectures()) { return TorConstants.ID;
if (abi.startsWith("x86_64")) return "x86_64_pie";
else if (abi.startsWith("x86")) return "x86_pie";
else if (abi.startsWith("arm64")) return "arm64_pie";
else if (abi.startsWith("armeabi")) return "arm_pie";
} }
@Override
public int getMaxLatency() {
return MAX_LATENCY;
}
@Override
public DuplexPlugin createPlugin(PluginCallback callback) {
// Check that we have a Tor binary for this architecture
String architecture = null;
for (String abi : AndroidUtils.getSupportedArchitectures()) {
if (abi.startsWith("x86_64")) {
architecture = "x86_64";
break;
} else if (abi.startsWith("x86")) {
architecture = "x86";
break;
} else if (abi.startsWith("arm64")) {
architecture = "arm64";
break;
} else if (abi.startsWith("armeabi")) {
architecture = "arm";
break;
}
}
if (architecture == null) {
LOG.info("Tor is not supported on this architecture");
return null; return null;
} }
// Use position-independent executable
architecture += "_pie";
@Override Backoff backoff = backoffFactory.createBackoff(MIN_POLLING_INTERVAL,
TorPlugin createPluginInstance(Backoff backoff, MAX_POLLING_INTERVAL, BACKOFF_BASE);
TorRendezvousCrypto torRendezvousCrypto, PluginCallback callback, TorRendezvousCrypto torRendezvousCrypto = new TorRendezvousCryptoImpl();
String architecture) { AndroidTorPlugin plugin = new AndroidTorPlugin(ioExecutor,
return new AndroidTorPlugin(ioExecutor,
wakefulIoExecutor, app, networkManager, locationUtils, wakefulIoExecutor, app, networkManager, locationUtils,
torSocketFactory, clock, resourceProvider, torSocketFactory, clock, resourceProvider,
circumventionProvider, batteryManager, wakeLockManager, circumventionProvider, batteryManager, wakeLockManager,
backoff, torRendezvousCrypto, callback, architecture, backoff, torRendezvousCrypto, callback, architecture,
MAX_LATENCY, MAX_IDLE_TIME, torDirectory, torSocksPort, MAX_LATENCY, MAX_IDLE_TIME, torDirectory);
torControlPort); eventBus.addListener(plugin);
return plugin;
} }
} }

View File

@@ -6,6 +6,8 @@ import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice; import android.bluetooth.BluetoothDevice;
import android.content.ContentResolver; import android.content.ContentResolver;
import android.content.Context; import android.content.Context;
import android.net.wifi.WifiConfiguration;
import android.net.wifi.WifiManager;
import android.os.Build; import android.os.Build;
import android.os.Parcel; import android.os.Parcel;
import android.os.StrictMode; import android.os.StrictMode;
@@ -15,10 +17,12 @@ import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import java.io.DataOutputStream; import java.io.DataOutputStream;
import java.io.IOException; import java.io.IOException;
import java.util.List;
import javax.annotation.concurrent.Immutable; import javax.annotation.concurrent.Immutable;
import javax.inject.Inject; import javax.inject.Inject;
import static android.content.Context.WIFI_SERVICE;
import static android.os.Build.VERSION.SDK_INT; import static android.os.Build.VERSION.SDK_INT;
import static android.provider.Settings.Secure.ANDROID_ID; import static android.provider.Settings.Secure.ANDROID_ID;
@@ -48,6 +52,15 @@ class AndroidSecureRandomProvider extends UnixSecureRandomProvider {
String id = Settings.Secure.getString(contentResolver, ANDROID_ID); String id = Settings.Secure.getString(contentResolver, ANDROID_ID);
if (id != null) out.writeUTF(id); if (id != null) out.writeUTF(id);
Parcel parcel = Parcel.obtain(); Parcel parcel = Parcel.obtain();
WifiManager wm = (WifiManager) appContext.getApplicationContext()
.getSystemService(WIFI_SERVICE);
if (wm != null) {
List<WifiConfiguration> configs = wm.getConfiguredNetworks();
if (configs != null) {
for (WifiConfiguration config : configs)
parcel.writeParcelable(config, 0);
}
}
BluetoothAdapter bt = BluetoothAdapter.getDefaultAdapter(); BluetoothAdapter bt = BluetoothAdapter.getDefaultAdapter();
if (bt != null) { if (bt != null) {
for (BluetoothDevice device : bt.getBondedDevices()) for (BluetoothDevice device : bt.getBondedDevices())

View File

@@ -8,7 +8,6 @@ import android.content.Intent;
import android.os.Process; import android.os.Process;
import android.os.SystemClock; import android.os.SystemClock;
import org.briarproject.bramble.api.Cancellable;
import org.briarproject.bramble.api.lifecycle.Service; import org.briarproject.bramble.api.lifecycle.Service;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault; import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import org.briarproject.bramble.api.system.AlarmListener; import org.briarproject.bramble.api.system.AlarmListener;
@@ -117,12 +116,10 @@ class AndroidTaskScheduler implements TaskScheduler, Service, AlarmListener {
long dueMillis = now + MILLISECONDS.convert(delay, unit); long dueMillis = now + MILLISECONDS.convert(delay, unit);
Runnable wakeful = () -> Runnable wakeful = () ->
wakeLockManager.executeWakefully(task, executor, "TaskHandoff"); wakeLockManager.executeWakefully(task, executor, "TaskHandoff");
// Acquire the lock before scheduling the check to ensure the check
// doesn't access the task queue before the task has been added
ScheduledTask s;
synchronized (lock) {
Future<?> check = scheduleCheckForDueTasks(delay, unit); Future<?> check = scheduleCheckForDueTasks(delay, unit);
s = new ScheduledTask(wakeful, dueMillis, check, cancelled); ScheduledTask s = new ScheduledTask(wakeful, dueMillis, check,
cancelled);
synchronized (lock) {
tasks.add(s); tasks.add(s);
} }
return s; return s;
@@ -139,7 +136,6 @@ class AndroidTaskScheduler implements TaskScheduler, Service, AlarmListener {
return schedule(wrapped, executor, delay, unit, cancelled); return schedule(wrapped, executor, delay, unit, cancelled);
} }
@GuardedBy("lock")
private Future<?> scheduleCheckForDueTasks(long delay, TimeUnit unit) { private Future<?> scheduleCheckForDueTasks(long delay, TimeUnit unit) {
Runnable wakeful = () -> wakeLockManager.runWakefully( Runnable wakeful = () -> wakeLockManager.runWakefully(
this::runDueTasks, "TaskScheduler"); this::runDueTasks, "TaskScheduler");
@@ -210,7 +206,7 @@ class AndroidTaskScheduler implements TaskScheduler, Service, AlarmListener {
private final Future<?> check; private final Future<?> check;
private final AtomicBoolean cancelled; private final AtomicBoolean cancelled;
private ScheduledTask(Runnable task, long dueMillis, public ScheduledTask(Runnable task, long dueMillis,
Future<?> check, AtomicBoolean cancelled) { Future<?> check, AtomicBoolean cancelled) {
this.task = task; this.task = task;
this.dueMillis = dueMillis; this.dueMillis = dueMillis;

View File

@@ -2,6 +2,7 @@ package org.briarproject.bramble.system;
import android.app.Application; import android.app.Application;
import android.content.Context; import android.content.Context;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager; import android.content.pm.PackageManager;
import android.os.PowerManager; import android.os.PowerManager;
@@ -105,21 +106,14 @@ class AndroidWakeLockManagerImpl implements AndroidWakeLockManager {
private String getWakeLockTag(Context ctx) { private String getWakeLockTag(Context ctx) {
PackageManager pm = ctx.getPackageManager(); PackageManager pm = ctx.getPackageManager();
if (isInstalled(pm, "com.huawei.powergenie")) { for (PackageInfo info : pm.getInstalledPackages(0)) {
String name = info.packageName.toLowerCase();
if (name.startsWith("com.huawei.powergenie")) {
return "LocationManagerService"; return "LocationManagerService";
} else if (isInstalled(pm, "com.evenwell.PowerMonitor")) { } else if (name.startsWith("com.evenwell.powermonitor")) {
return "AudioIn"; return "AudioIn";
} }
}
return ctx.getPackageName(); return ctx.getPackageName();
} }
private boolean isInstalled(PackageManager pm, String packageName) {
try {
pm.getPackageInfo(packageName, 0);
return true;
} catch (PackageManager.NameNotFoundException e) {
return false;
}
}
} }

View File

@@ -4,27 +4,23 @@ import android.annotation.SuppressLint;
import android.bluetooth.BluetoothAdapter; import android.bluetooth.BluetoothAdapter;
import android.content.Context; import android.content.Context;
import android.os.Build; import android.os.Build;
import android.os.Looper;
import android.provider.Settings; import android.provider.Settings;
import org.briarproject.bramble.api.Pair; import org.briarproject.bramble.api.Pair;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault; import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import java.io.File; import java.io.File;
import java.io.IOException;
import java.lang.reflect.Field; import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException; import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method; import java.lang.reflect.Method;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collection; import java.util.Collection;
import java.util.List; import java.util.List;
import java.util.Scanner;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import static android.content.Context.MODE_PRIVATE; import static android.content.Context.MODE_PRIVATE;
import static android.os.Build.VERSION.SDK_INT; import static android.os.Build.VERSION.SDK_INT;
import static java.lang.Runtime.getRuntime;
import static java.util.Arrays.asList; import static java.util.Arrays.asList;
import static org.briarproject.bramble.api.nullsafety.NullSafety.requireNonNull; import static org.briarproject.bramble.api.nullsafety.NullSafety.requireNonNull;
@@ -35,7 +31,6 @@ public class AndroidUtils {
private static final String FAKE_BLUETOOTH_ADDRESS = "02:00:00:00:00:00"; private static final String FAKE_BLUETOOTH_ADDRESS = "02:00:00:00:00:00";
private static final String STORED_REPORTS = "dev-reports"; private static final String STORED_REPORTS = "dev-reports";
private static final String STORED_LOGCAT = "dev-logcat";
public static Collection<String> getSupportedArchitectures() { public static Collection<String> getSupportedArchitectures() {
List<String> abis = new ArrayList<>(); List<String> abis = new ArrayList<>();
@@ -112,31 +107,14 @@ public class AndroidUtils {
return ctx.getDir(STORED_REPORTS, MODE_PRIVATE); return ctx.getDir(STORED_REPORTS, MODE_PRIVATE);
} }
public static File getLogcatFile(Context ctx) {
return new File(ctx.getFilesDir(), STORED_LOGCAT);
}
/** /**
* Returns an array of supported content types for image attachments. * Returns an array of supported content types for image attachments.
* GIFs can't be compressed on API < 24 so they're not supported.
* <p>
* TODO: Remove this restriction when large message support is added
*/ */
public static String[] getSupportedImageContentTypes() { public static String[] getSupportedImageContentTypes() {
return new String[] {"image/jpeg", "image/png", "image/gif"}; if (SDK_INT < 24) return new String[] {"image/jpeg", "image/png"};
} else return new String[] {"image/jpeg", "image/png", "image/gif"};
@Nullable
public static String getSystemProperty(String propName) {
try {
Process p = getRuntime().exec("getprop " + propName);
Scanner s = new Scanner(p.getInputStream());
String line = s.nextLine();
s.close();
return line;
} catch (SecurityException | IOException e) {
return null;
}
}
public static boolean isUiThread() {
return Looper.myLooper() == Looper.getMainLooper();
} }
} }

View File

@@ -9,7 +9,7 @@ import org.briarproject.bramble.api.db.DatabaseConfig;
import org.briarproject.bramble.api.identity.IdentityManager; import org.briarproject.bramble.api.identity.IdentityManager;
import org.briarproject.bramble.test.BrambleMockTestCase; import org.briarproject.bramble.test.BrambleMockTestCase;
import org.jmock.Expectations; import org.jmock.Expectations;
import org.jmock.imposters.ByteBuddyClassImposteriser; import org.jmock.lib.legacy.ClassImposteriser;
import org.junit.After; import org.junit.After;
import org.junit.Before; import org.junit.Before;
import org.junit.Test; import org.junit.Test;
@@ -44,7 +44,7 @@ public class AndroidAccountManagerTest extends BrambleMockTestCase {
private AndroidAccountManager accountManager; private AndroidAccountManager accountManager;
public AndroidAccountManagerTest() { public AndroidAccountManagerTest() {
context.setImposteriser(ByteBuddyClassImposteriser.INSTANCE); context.setImposteriser(ClassImposteriser.INSTANCE);
app = context.mock(Application.class); app = context.mock(Application.class);
applicationInfo = new ApplicationInfo(); applicationInfo = new ApplicationInfo();
applicationInfo.dataDir = testDir.getAbsolutePath(); applicationInfo.dataDir = testDir.getAbsolutePath();

View File

@@ -1,161 +1,103 @@
dependencyVerification { dependencyVerification {
verify = [ verify = [
'cglib:cglib:3.2.8:cglib-3.2.8.jar:3f64de999ecc5595dc84ca8ff0879d8a34c8623f9ef3c517a53ed59023fcb9db', 'cglib:cglib:3.2.0:cglib-3.2.0.jar:adb13bab79712ad6bdf1bd59f2a3918018a8016e722e8a357065afb9e6690861',
'com.android.tools.analytics-library:protos:30.0.3:protos-30.0.3.jar:f62b89dcd9de719c6a7b7e15fb1dd20e45b57222e675cf633607bd0ed6bca7e7', 'com.android.tools.analytics-library:protos:26.5.1:protos-26.5.1.jar:8dde1130725461fe827f2a343d353f2b51e8870661fc860d7d5ebddb097ead4e',
'com.android.tools.analytics-library:shared:30.0.3:shared-30.0.3.jar:05aa9ba3cc890354108521fdf99802565aae5dd6ca44a6ac8bb8d594d1c1cd15', 'com.android.tools.analytics-library:shared:26.5.1:shared-26.5.1.jar:ccc2f3b00ec17b11401610ba68553544fc8fc517120e84439ac6eb86b875e18d',
'com.android.tools.analytics-library:tracker:30.0.3:tracker-30.0.3.jar:5d0ef35bf6733e96210b5085a2a202152921bf834d345959dce1ca3369b528df', 'com.android.tools.analytics-library:tracker:26.5.1:tracker-26.5.1.jar:3a76984c0fe2e847ca7a8b35b4780ef0447a9d1666946cb8e60466318e0ab5ae',
'com.android.tools.build:aapt2-proto:4.1.0-alpha01-6193524:aapt2-proto-4.1.0-alpha01-6193524.jar:17e75523e1e92dd4f222c7368ee41df9e964a508232f591e265d0c499baf9dca', 'com.android.tools.build:aapt2-proto:0.4.0:aapt2-proto-0.4.0.jar:fac0435e08898f89eeeb9ca236bea707155ff816c12205ced285ad53604133ca',
'com.android.tools.build:apksig:7.0.3:apksig-7.0.3.jar:012337a2803c9a30dfc41dcbc6450686ee9e5f582549f7f126479f743a343ec9', 'com.android.tools.build:apksig:3.5.1:apksig-3.5.1.jar:1fd33e7f009a2a0da766cfeec4211a09f548034b015c289a66d75dd8a9302f4a',
'com.android.tools.build:apkzlib:7.0.3:apkzlib-7.0.3.jar:b31e53174c92db83c5cc6e7dac6734ea4e907a72e452c2bf1818dfd082c59397', 'com.android.tools.build:apkzlib:3.5.1:apkzlib-3.5.1.jar:9f330167cbe973b7db407692f74f4f6453b7ffa5f2048934b06280c2ceee60fa',
'com.android.tools.build:builder-model:7.0.3:builder-model-7.0.3.jar:483f99d7494a5bed027e1e8d29111384cf535d4842f0be5a79805bd44bb68d4e', 'com.android.tools.build:builder-model:3.5.1:builder-model-3.5.1.jar:39ea3c82b76b6e0c9f9fa88d93e0edc1dd4a0f1dfae0ef6fbf2d451da47e5450',
'com.android.tools.build:builder-test-api:7.0.3:builder-test-api-7.0.3.jar:f6de4bc2cef545e8367bf82d7c733829c7be3b0b3b8b09fd8c58f2150e59ab46', 'com.android.tools.build:builder-test-api:3.5.1:builder-test-api-3.5.1.jar:a1b59305584cbcaa078fdc9cfb80871012755b822dd32e8da19add6f7bbcb762',
'com.android.tools.build:builder:7.0.3:builder-7.0.3.jar:c6952da0094b094c2ba0fe84c675622097c5d9b9f9beb53485b860320540cf1d', 'com.android.tools.build:builder:3.5.1:builder-3.5.1.jar:e3a8d382434c5f60990730c4719fc814e85a898a33a1e96c1df8d627d3c6eea6',
'com.android.tools.build:manifest-merger:30.0.3:manifest-merger-30.0.3.jar:72b346ba6318b4b6260e6e49df4bea5da2e12329ab6c2beb2269c49a9f51f178', 'com.android.tools.build:gradle-api:3.5.1:gradle-api-3.5.1.jar:be9b41859bace11998f66b04ed944f87e413f3ad6da3c4665587699da125addc',
'com.android.tools.ddms:ddmlib:30.0.3:ddmlib-30.0.3.jar:7a914a68ab93393657297234e2f37b22410ae9a433cba692ce8c727c9607e3bb', 'com.android.tools.build:manifest-merger:26.5.1:manifest-merger-26.5.1.jar:dcad9ecb967251f4d750f55a4204a2b400e8fbfe5cb930a1d0d5dbe10ae8bdfc',
'com.android.tools.external.com-intellij:intellij-core:30.0.3:intellij-core-30.0.3.jar:1ebe858d3f58eeaa8c06507f8ac0f1c7051e6c61f35a70f3c3967d5734d3abc5', 'com.android.tools.ddms:ddmlib:26.5.1:ddmlib-26.5.1.jar:b081aef2a4ed3f4d47cae4cdb128469735f25a114e026d37123bf9ffdec742a8',
'com.android.tools.external.com-intellij:kotlin-compiler:30.0.3:kotlin-compiler-30.0.3.jar:ed00e441f427cb4e0d418287b9da30b12b7f735f9af32e6b5d3dc960b6a742fc', 'com.android.tools.external.com-intellij:intellij-core:26.5.1:intellij-core-26.5.1.jar:20eced30adc124805bd93488d9cd9d3e33e6bf7b48e9fe5a703d4983f894d450',
'com.android.tools.external.org-jetbrains:uast:30.0.3:uast-30.0.3.jar:a77801bee6ff509910e459525c9c34d7f04b066ade123547f16f1917548eadea', 'com.android.tools.external.com-intellij:kotlin-compiler:26.5.1:kotlin-compiler-26.5.1.jar:5aed762dd54875b77ae7018d97c05756ff0c5b9fd02ec595dd396ccd14cc22cb',
'com.android.tools.layoutlib:layoutlib-api:30.0.3:layoutlib-api-30.0.3.jar:4caa87e9ca2e11315f650d576cd59fec1793373bc3fca3f6d53c029e7534e7c4', 'com.android.tools.external.org-jetbrains:uast:26.5.1:uast-26.5.1.jar:4bc8653d6c0943f40fee963a149e36c6baa45683d2530968a13f5007e3c40740',
'com.android.tools.lint:lint-api:30.0.3:lint-api-30.0.3.jar:bcecbd2f752a6560096a9029a47d1de6bd788a51bab505c5ebfba6a18524b983', 'com.android.tools.layoutlib:layoutlib-api:26.5.1:layoutlib-api-26.5.1.jar:88732f11396c427273e515d23042e35633f4fe4295528a99b866aa2adf0efd9c',
'com.android.tools.lint:lint-checks:30.0.3:lint-checks-30.0.3.jar:25a7cd42dc3ad502337f131fb8b7e873c53301db0a67b1c64dd4ae7a8eb66cec', 'com.android.tools.lint:lint-api:26.5.1:lint-api-26.5.1.jar:ec33fcd72bfaf70dd841e03fbfd93f109c2e575aec146067c606689c3972f0de',
'com.android.tools.lint:lint-gradle:30.0.3:lint-gradle-30.0.3.jar:94544d6147a809bf2fd3440e51f28a4e42e547d74aab53eefd74938cdad42c26', 'com.android.tools.lint:lint-checks:26.5.1:lint-checks-26.5.1.jar:a1b9607d484aaae7a71dcecdc76f8003d8239af226c776894a2cf63f9e6c60d7',
'com.android.tools.lint:lint-model:30.0.3:lint-model-30.0.3.jar:0b940a7f575c2ff5cbd038260f41dde686a93c672213881ead3ce8af3513b396', 'com.android.tools.lint:lint-gradle-api:26.5.1:lint-gradle-api-26.5.1.jar:82453fd98a8394cc84ed995c04d2cd744abd1d6589403427ba7eef53115406f3',
'com.android.tools.lint:lint:30.0.3:lint-30.0.3.jar:ee4f11001e0c7e3b776e0d67399ad354b19b0f168822ec2b7db47c0910ed227d', 'com.android.tools.lint:lint-gradle:26.5.1:lint-gradle-26.5.1.jar:59465b56cf7db77c656d5f8195d721c3d48b6bdd0502d774de335bfe4baff00b',
'com.android.tools:annotations:30.0.3:annotations-30.0.3.jar:5c1944982fda8555855c4f5422fabf0dc8e2306e1f5460e9ad82dae71316bc31', 'com.android.tools.lint:lint:26.5.1:lint-26.5.1.jar:336e4b04ec6f8b0f25879131b7a7862d77df83a1879ee5b71be26128755f8e2e',
'com.android.tools:common:30.0.3:common-30.0.3.jar:8751efaaf2c2ddd1f0a37526c794347def6a3057ca9fc510307c13a6cf0d036f', 'com.android.tools:annotations:26.5.1:annotations-26.5.1.jar:2c43c82f8c59d8f7a61e3239e1a2dc9f69dc342ec09af9b7c9f69b25337c0b6e',
'com.android.tools:dvlib:30.0.3:dvlib-30.0.3.jar:5affafcec390041e5afd64cb924153f5e474db47ee8ccc2f555b495083141233', 'com.android.tools:common:26.5.1:common-26.5.1.jar:eccfa54486ed54c4e3123cc42195d023bd0dd21bcd2f0e4868e8c6fc70f8ef6b',
'com.android.tools:repository:30.0.3:repository-30.0.3.jar:0a40c6f16c506903ce2c609affd8228aceda73a69d93dfa42d4f02b8491449f6', 'com.android.tools:dvlib:26.5.1:dvlib-26.5.1.jar:46f93ad498b4756e7d867d2fe38c38890a80e7407a4ae459e4a8c8d5c5aeacfe',
'com.android.tools:sdk-common:30.0.3:sdk-common-30.0.3.jar:b45570a380360236ffee0f6bb593d66b673bad3834dfe0d6c9871fa7188ee0eb', 'com.android.tools:repository:26.5.1:repository-26.5.1.jar:2b3ee791aa4c3e8ce60498c161a27ca7228816fc630eed4d9f25f2f36a106dce',
'com.android.tools:sdklib:30.0.3:sdklib-30.0.3.jar:7088f20a414fab170a21e457825e14ebe099f753558e02c8acc12c67eb412162', 'com.android.tools:sdk-common:26.5.1:sdk-common-26.5.1.jar:365f749676c3574676fd465177c8a492f340816db2b520d6ed114d3b6e77bea7',
'com.android:signflinger:7.0.3:signflinger-7.0.3.jar:903a4536db3e96b4e1e1dc1e400eb0b91bf7866d9b39cd7ec94d75dde158f152', 'com.android.tools:sdklib:26.5.1:sdklib-26.5.1.jar:007da104afb27c8c682a1628023fe9ec438249c8d15ef0fd6624c5bb8e23b696',
'com.android:zipflinger:7.0.3:zipflinger-7.0.3.jar:fd209c960a3eff7a339e6fcba07d5e9ef4604d1633c69ab2df987460d9804140',
'com.beust:jcommander:1.78:jcommander-1.78.jar:7891debb84b5f83e9bd57593ebece3399abbe0fd938cf306b3534c57913b9615',
'com.github.javaparser:javaparser-core:3.17.0:javaparser-core-3.17.0.jar:23f5c982e1c7771423d37d52c774e8d2e80fd7ea7305ebe448797a96f67e6fca',
'com.google.code.findbugs:annotations:3.0.1:annotations-3.0.1.jar:6b47ff0a6de0ce17cbedc3abb0828ca5bce3009d53ea47b3723ff023c4742f79',
'com.google.code.findbugs:jsr305:3.0.2:jsr305-3.0.2.jar:766ad2a0783f2687962c8ad74ceecc38a28b9f72a2d085ee438b7813e928d0c7', 'com.google.code.findbugs:jsr305:3.0.2:jsr305-3.0.2.jar:766ad2a0783f2687962c8ad74ceecc38a28b9f72a2d085ee438b7813e928d0c7',
'com.google.code.gson:gson:2.8.6:gson-2.8.6.jar:c8fb4839054d280b3033f800d1f5a97de2f028eb8ba2eb458ad287e536f3f25f', 'com.google.code.gson:gson:2.8.5:gson-2.8.5.jar:233a0149fc365c9f6edbd683cfe266b19bdc773be98eabdaf6b3c924b48e7d81',
'com.google.dagger:dagger-compiler:2.33:dagger-compiler-2.33.jar:aa8a0d8370c578fd6999802d0d90b9829377a46d2c1141e11b8f737970e7155e', 'com.google.dagger:dagger-compiler:2.24:dagger-compiler-2.24.jar:3c5afb955fb188da485cb2c048eff37dce0e1530b9780a0f2f7187d16d1ccc1f',
'com.google.dagger:dagger-producers:2.33:dagger-producers-2.33.jar:5897f0b6eef799c2adfe3ccacc58c0fb374d58acb063c3ebe5366c38a8bce5c8', 'com.google.dagger:dagger-producers:2.24:dagger-producers-2.24.jar:f10f45b95191954d5d6b043fca9e62fb621d21bf70634b8f8476c7988b504c3a',
'com.google.dagger:dagger-spi:2.33:dagger-spi-2.33.jar:e2dcab2221b8afb9556ef0a1c83b0bd5f42552e254322a257330f754cdbbb9d4', 'com.google.dagger:dagger-spi:2.24:dagger-spi-2.24.jar:c038445d14dbcb4054e61bf49e05009edf26fce4fdc7ec1a9db544784f68e718',
'com.google.dagger:dagger:2.33:dagger-2.33.jar:d8798c5b8cf6b125234e33af5c6293bb9f2208ce29b57924c35b8c0be7b6bdcb', 'com.google.dagger:dagger:2.24:dagger-2.24.jar:550a6e46a6dfcdf1d764887b6090cea94f783327e50e5c73754f18facfc70b64',
'com.google.errorprone:error_prone_annotations:2.2.0:error_prone_annotations-2.2.0.jar:6ebd22ca1b9d8ec06d41de8d64e0596981d9607b42035f9ed374f9de271a481a', 'com.google.errorprone:error_prone_annotations:2.2.0:error_prone_annotations-2.2.0.jar:6ebd22ca1b9d8ec06d41de8d64e0596981d9607b42035f9ed374f9de271a481a',
'com.google.errorprone:error_prone_annotations:2.3.4:error_prone_annotations-2.3.4.jar:baf7d6ea97ce606c53e11b6854ba5f2ce7ef5c24dddf0afa18d1260bd25b002c',
'com.google.errorprone:javac-shaded:9-dev-r4023-3:javac-shaded-9-dev-r4023-3.jar:65bfccf60986c47fbc17c9ebab0be626afc41741e0a6ec7109e0768817a36f30', 'com.google.errorprone:javac-shaded:9-dev-r4023-3:javac-shaded-9-dev-r4023-3.jar:65bfccf60986c47fbc17c9ebab0be626afc41741e0a6ec7109e0768817a36f30',
'com.google.googlejavaformat:google-java-format:1.5:google-java-format-1.5.jar:aa19ad7850fb85178aa22f2fddb163b84d6ce4d0035872f30d4408195ca1144e', 'com.google.googlejavaformat:google-java-format:1.5:google-java-format-1.5.jar:aa19ad7850fb85178aa22f2fddb163b84d6ce4d0035872f30d4408195ca1144e',
'com.google.guava:failureaccess:1.0.1:failureaccess-1.0.1.jar:a171ee4c734dd2da837e4b16be9df4661afab72a41adaf31eb84dfdaf936ca26', 'com.google.guava:failureaccess:1.0.1:failureaccess-1.0.1.jar:a171ee4c734dd2da837e4b16be9df4661afab72a41adaf31eb84dfdaf936ca26',
'com.google.guava:guava:27.0.1-jre:guava-27.0.1-jre.jar:e1c814fd04492a27c38e0317eabeaa1b3e950ec8010239e400fe90ad6c9107b4',
'com.google.guava:guava:27.1-jre:guava-27.1-jre.jar:4a5aa70cc968a4d137e599ad37553e5cfeed2265e8c193476d7119036c536fe7', 'com.google.guava:guava:27.1-jre:guava-27.1-jre.jar:4a5aa70cc968a4d137e599ad37553e5cfeed2265e8c193476d7119036c536fe7',
'com.google.guava:guava:30.1-jre:guava-30.1-jre.jar:e6dd072f9d3fe02a4600688380bd422bdac184caf6fe2418cfdd0934f09432aa',
'com.google.guava:listenablefuture:9999.0-empty-to-avoid-conflict-with-guava:listenablefuture-9999.0-empty-to-avoid-conflict-with-guava.jar:b372a037d4230aa57fbeffdef30fd6123f9c0c2db85d0aced00c91b974f33f99', 'com.google.guava:listenablefuture:9999.0-empty-to-avoid-conflict-with-guava:listenablefuture-9999.0-empty-to-avoid-conflict-with-guava.jar:b372a037d4230aa57fbeffdef30fd6123f9c0c2db85d0aced00c91b974f33f99',
'com.google.j2objc:j2objc-annotations:1.1:j2objc-annotations-1.1.jar:2994a7eb78f2710bd3d3bfb639b2c94e219cedac0d4d084d516e78c16dddecf6', 'com.google.j2objc:j2objc-annotations:1.1:j2objc-annotations-1.1.jar:2994a7eb78f2710bd3d3bfb639b2c94e219cedac0d4d084d516e78c16dddecf6',
'com.google.j2objc:j2objc-annotations:1.3:j2objc-annotations-1.3.jar:21af30c92267bd6122c0e0b4d20cccb6641a37eaf956c6540ec471d584e64a7b',
'com.google.jimfs:jimfs:1.1:jimfs-1.1.jar:c4828e28d7c0a930af9387510b3bada7daa5c04d7c25a75c7b8b081f1c257ddd', 'com.google.jimfs:jimfs:1.1:jimfs-1.1.jar:c4828e28d7c0a930af9387510b3bada7daa5c04d7c25a75c7b8b081f1c257ddd',
'com.google.protobuf:protobuf-java:3.10.0:protobuf-java-3.10.0.jar:161d7d61a8cb3970891c299578702fd079646e032329d6c2cabf998d191437c9', 'com.google.protobuf:protobuf-java:3.4.0:protobuf-java-3.4.0.jar:dce7e66b32456a1b1198da0caff3a8acb71548658391e798c79369241e6490a4',
'com.googlecode.json-simple:json-simple:1.1:json-simple-1.1.jar:2d9484f4c649f708f47f9a479465fc729770ee65617dca3011836602264f6439', 'com.googlecode.json-simple:json-simple:1.1:json-simple-1.1.jar:2d9484f4c649f708f47f9a479465fc729770ee65617dca3011836602264f6439',
'com.squareup:javapoet:1.13.0:javapoet-1.13.0.jar:4c7517e848a71b36d069d12bb3bf46a70fd4cda3105d822b0ed2e19c00b69291', 'com.squareup:javapoet:1.11.1:javapoet-1.11.1.jar:9cbf2107be499ec6e95afd36b58e3ca122a24166cdd375732e51267d64058e90',
'com.squareup:javawriter:2.5.0:javawriter-2.5.0.jar:fcfb09fb0ea0aa97d3cfe7ea792398081348e468f126b3603cb3803f240197f0', 'com.squareup:javawriter:2.5.0:javawriter-2.5.0.jar:fcfb09fb0ea0aa97d3cfe7ea792398081348e468f126b3603cb3803f240197f0',
'com.sun.activation:javax.activation:1.2.0:javax.activation-1.2.0.jar:993302b16cd7056f21e779cc577d175a810bb4900ef73cd8fbf2b50f928ba9ce', 'com.sun.activation:javax.activation:1.2.0:javax.activation-1.2.0.jar:993302b16cd7056f21e779cc577d175a810bb4900ef73cd8fbf2b50f928ba9ce',
'com.sun.istack:istack-commons-runtime:3.0.8:istack-commons-runtime-3.0.8.jar:4ffabb06be454a05e4398e20c77fa2b6308d4b88dfbef7ca30a76b5b7d5505ef', 'com.sun.istack:istack-commons-runtime:2.21:istack-commons-runtime-2.21.jar:c33e67a0807095f02a0e2da139412dd7c4f9cc1a4c054b3e434f96831ba950f4',
'com.sun.xml.fastinfoset:FastInfoset:1.2.16:FastInfoset-1.2.16.jar:056f3a1e144409f21ed16afc26805f58e9a21f3fce1543c42d400719d250c511', 'com.sun.xml.fastinfoset:FastInfoset:1.2.13:FastInfoset-1.2.13.jar:27a77db909f3c2833c0b1a37c55af1db06045118ad2eed96ce567b6632bce038',
'com.thoughtworks.qdox:qdox:1.12.1:qdox-1.12.1.jar:21fba22f830e9268f07cf4ab2d99e8181abbdcb0cb91ee0228eb3cb918dcdd1d',
'commons-codec:commons-codec:1.10:commons-codec-1.10.jar:4241dfa94e711d435f29a4604a3e2de5c4aa3c165e23bd066be6fc1fc4309569', 'commons-codec:commons-codec:1.10:commons-codec-1.10.jar:4241dfa94e711d435f29a4604a3e2de5c4aa3c165e23bd066be6fc1fc4309569',
'commons-io:commons-io:2.4:commons-io-2.4.jar:cc6a41dc3eaacc9e440a6bd0d2890b20d36b4ee408fe2d67122f328bb6e01581',
'commons-logging:commons-logging:1.2:commons-logging-1.2.jar:daddea1ea0be0f56978ab3006b8ac92834afeefbd9b7e4e6316fca57df0fa636', 'commons-logging:commons-logging:1.2:commons-logging-1.2.jar:daddea1ea0be0f56978ab3006b8ac92834afeefbd9b7e4e6316fca57df0fa636',
'info.picocli:picocli:4.5.2:picocli-4.5.2.jar:b4395e9a67932616efd2245d984bf5fcd453c2c5049558c3ce959ac2af4d3fac', 'it.unimi.dsi:fastutil:7.2.0:fastutil-7.2.0.jar:74fa208043740642f7e6eb09faba15965218ad2f50ce3020efb100136e4b591c',
'it.unimi.dsi:fastutil:8.4.0:fastutil-8.4.0.jar:2ad2824a4a0a0eb836b52ee2fc84ba2134f44bce7bfa54015ae3f31c710a3071',
'jakarta.activation:jakarta.activation-api:1.2.1:jakarta.activation-api-1.2.1.jar:8b0a0f52fa8b05c5431921a063ed866efaa41dadf2e3a7ee3e1961f2b0d9645b',
'jakarta.xml.bind:jakarta.xml.bind-api:2.3.2:jakarta.xml.bind-api-2.3.2.jar:69156304079bdeed9fc0ae3b39389f19b3cc4ba4443bc80508995394ead742ea',
'javax.annotation:jsr250-api:1.0:jsr250-api-1.0.jar:a1a922d0d9b6d183ed3800dfac01d1e1eb159f0e8c6f94736931c1def54a941f', 'javax.annotation:jsr250-api:1.0:jsr250-api-1.0.jar:a1a922d0d9b6d183ed3800dfac01d1e1eb159f0e8c6f94736931c1def54a941f',
'javax.inject:javax.inject:1:javax.inject-1.jar:91c77044a50c481636c32d916fd89c9118a72195390452c81065080f957de7ff', 'javax.inject:javax.inject:1:javax.inject-1.jar:91c77044a50c481636c32d916fd89c9118a72195390452c81065080f957de7ff',
'jline:jline:2.14.6:jline-2.14.6.jar:97d1acaac82409be42e622d7a54d3ae9d08517e8aefdea3d2ba9791150c2f02d', 'javax.xml.bind:jaxb-api:2.2.12-b140109.1041:jaxb-api-2.2.12-b140109.1041.jar:b5e60cd8b7b5ff01ce4a74c5dd008f4fbd14ced3495d0b47b85cfedc182211f2',
'junit:junit:4.13.1:junit-4.13.1.jar:c30719db974d6452793fe191b3638a5777005485bae145924044530ffa5f6122', 'junit:junit:4.12:junit-4.12.jar:59721f0805e223d84b90677887d9ff567dc534d7c502ca903c0c2b17f05c116a',
'junit:junit:4.13.2:junit-4.13.2.jar:8e495b634469d64fb8acfa3495a065cbacc8a0fff55ce1e31007be4c16dc57d3',
'net.bytebuddy:byte-buddy:1.9.12:byte-buddy-1.9.12.jar:3688c3d434bebc3edc5516296a2ed0f47b65e451071b4afecad84f902f0efc11',
'net.java.dev.jna:jna-platform:5.6.0:jna-platform-5.6.0.jar:9ecea8bf2b1b39963939d18b70464eef60c508fed8820f9dcaba0c35518eabf7',
'net.java.dev.jna:jna:5.6.0:jna-5.6.0.jar:5557e235a8aa2f9766d5dc609d67948f2a8832c2d796cea9ef1d6cbe0b3b7eaf',
'net.jcip:jcip-annotations:1.0:jcip-annotations-1.0.jar:be5805392060c71474bf6c9a67a099471274d30b83eef84bfc4e0889a4f1dcc0',
'net.ltgt.gradle.incap:incap:0.2:incap-0.2.jar:b625b9806b0f1e4bc7a2e3457119488de3cd57ea20feedd513db070a573a4ffd', 'net.ltgt.gradle.incap:incap:0.2:incap-0.2.jar:b625b9806b0f1e4bc7a2e3457119488de3cd57ea20feedd513db070a573a4ffd',
'net.sf.jopt-simple:jopt-simple:4.9:jopt-simple-4.9.jar:26c5856e954b5f864db76f13b86919b59c6eecf9fd930b96baa8884626baf2f5', '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', 'net.sf.kxml:kxml2:2.3.0:kxml2-2.3.0.jar:f264dd9f79a1fde10ce5ecc53221eff24be4c9331c830b7d52f2f08a7b633de2',
'org.apache-extras.beanshell:bsh:2.0b6:bsh-2.0b6.jar:a17955976070c0573235ee662f2794a78082758b61accffce8d3f8aedcd91047', 'org.apache.ant:ant-launcher:1.9.4:ant-launcher-1.9.4.jar:7bccea20b41801ca17bcbc909a78c835d0f443f12d639c77bd6ae3d05861608d',
'org.apache.ant:ant-antlr:1.10.9:ant-antlr-1.10.9.jar:7623dc9d0f20ea713290c6bf1a23f4c059447aef7ff9f5b2be75960f3f028d2e', 'org.apache.ant:ant:1.9.4:ant-1.9.4.jar:649ae0730251de07b8913f49286d46bba7b92d47c5f332610aa426c4f02161d8',
'org.apache.ant:ant-junit:1.10.9:ant-junit-1.10.9.jar:960bdc8827954d62206ba42d0a68a7ee4476175ba47bb113e17e77cce7394630', 'org.apache.commons:commons-compress:1.12:commons-compress-1.12.jar:2c1542faf343185b7cab9c3d55c8ae5471d6d095d3887a4adefdbdf2984dc0b6',
'org.apache.ant:ant-launcher:1.10.9:ant-launcher-1.10.9.jar:fcce891f57f3be72149ff96ac2a80574165b3e0839866b95d24528f3027d50c1',
'org.apache.ant:ant:1.10.9:ant-1.10.9.jar:0715478af585ea80a18985613ebecdc7922122d45b2c3c970ff9b352cddb75fc',
'org.apache.commons:commons-compress:1.20:commons-compress-1.20.jar:0aeb625c948c697ea7b205156e112363b59ed5e2551212cd4e460bdb72c7c06e',
'org.apache.httpcomponents:httpclient:4.5.6:httpclient-4.5.6.jar:c03f813195e7a80e3608d0ddd8da80b21696a4c92a6a2298865bf149071551c7', 'org.apache.httpcomponents:httpclient:4.5.6:httpclient-4.5.6.jar:c03f813195e7a80e3608d0ddd8da80b21696a4c92a6a2298865bf149071551c7',
'org.apache.httpcomponents:httpcore:4.4.10:httpcore-4.4.10.jar:78ba1096561957db1b55200a159b648876430342d15d461277e62360da19f6fd', 'org.apache.httpcomponents:httpcore:4.4.10:httpcore-4.4.10.jar:78ba1096561957db1b55200a159b648876430342d15d461277e62360da19f6fd',
'org.apache.httpcomponents:httpmime:4.5.6:httpmime-4.5.6.jar:0b2b1102c18d3c7e05a77214b9b7501a6f6056174ae5604e0e256776eda7553e', 'org.apache.httpcomponents:httpmime:4.5.6:httpmime-4.5.6.jar:0b2b1102c18d3c7e05a77214b9b7501a6f6056174ae5604e0e256776eda7553e',
'org.beanshell:bsh:1.3.0:bsh-1.3.0.jar:9b04edc75d19db54f1b4e8b5355e9364384c6cf71eb0a1b9724c159d779879f8',
'org.bouncycastle:bcpkix-jdk15on:1.56:bcpkix-jdk15on-1.56.jar:7043dee4e9e7175e93e0b36f45b1ec1ecb893c5f755667e8b916eb8dd201c6ca', 'org.bouncycastle:bcpkix-jdk15on:1.56:bcpkix-jdk15on-1.56.jar:7043dee4e9e7175e93e0b36f45b1ec1ecb893c5f755667e8b916eb8dd201c6ca',
'org.bouncycastle:bcprov-jdk15on:1.56:bcprov-jdk15on-1.56.jar:963e1ee14f808ffb99897d848ddcdb28fa91ddda867eb18d303e82728f878349', 'org.bouncycastle:bcprov-jdk15on:1.56:bcprov-jdk15on-1.56.jar:963e1ee14f808ffb99897d848ddcdb28fa91ddda867eb18d303e82728f878349',
'org.briarproject:obfs4proxy-android:0.0.12:obfs4proxy-android-0.0.12.jar:84159d2a4668abc40e3fccaa1f6fa0c04892863f9eb80a866ac8928d9f9a7e89', 'org.briarproject:obfs4proxy-android:0.0.11-2:obfs4proxy-android-0.0.11-2.zip:57e55cbe87aa2aac210fdbb6cd8cdeafe15f825406a08ebf77a8b787aa2c6a8a',
'org.briarproject:tor-android:0.4.5.12-2:tor-android-0.4.5.12-2.jar:8545dbcef2bb6aa89c32bb6f8ac51f7a64bce3ae85845b3578ffdeb9b206feb9', 'org.briarproject:tor-android:0.3.5.10:tor-android-0.3.5.10.zip:edd83bf557fcff2105eaa0bdb3f607a6852ebe7360920929ae3039dd5f4774c5',
'org.checkerframework:checker-compat-qual:2.5.3:checker-compat-qual-2.5.3.jar:d76b9afea61c7c082908023f0cbc1427fab9abd2df915c8b8a3e7a509bccbc6d', 'org.checkerframework:checker-compat-qual:2.5.3:checker-compat-qual-2.5.3.jar:d76b9afea61c7c082908023f0cbc1427fab9abd2df915c8b8a3e7a509bccbc6d',
'org.checkerframework:checker-qual:2.5.2:checker-qual-2.5.2.jar:64b02691c8b9d4e7700f8ee2e742dce7ea2c6e81e662b7522c9ee3bf568c040a', 'org.checkerframework:checker-qual:2.5.2:checker-qual-2.5.2.jar:64b02691c8b9d4e7700f8ee2e742dce7ea2c6e81e662b7522c9ee3bf568c040a',
'org.checkerframework:checker-qual:3.5.0:checker-qual-3.5.0.jar:729990b3f18a95606fc2573836b6958bcdb44cb52bfbd1b7aa9c339cff35a5a4', 'org.codehaus.groovy:groovy-all:2.4.15:groovy-all-2.4.15.jar:51d6c4e71782e85674239189499854359d380fb75e1a703756e3aaa5b98a5af0',
'org.codehaus.groovy:groovy-ant:3.0.7:groovy-ant-3.0.7.jar:6ed2ba82813d128f7050c24142e87b3dc2ad8b504786280eb03e81f0cf6a5793',
'org.codehaus.groovy:groovy-astbuilder:3.0.7:groovy-astbuilder-3.0.7.jar:b290451eb1583666e906c41f7d14747b4cc96363c99c478b244634fd5dfc9013',
'org.codehaus.groovy:groovy-cli-picocli:3.0.7:groovy-cli-picocli-3.0.7.jar:71b4bd11fb30a9c7b5618e22122c9c5141958fb27f4dcf0068b6f715088f6916',
'org.codehaus.groovy:groovy-console:3.0.7:groovy-console-3.0.7.jar:0541b358b6b8e5363215026736168fccfec1d91bac678d066fa77349eeeaa5dd',
'org.codehaus.groovy:groovy-datetime:3.0.7:groovy-datetime-3.0.7.jar:b9823d14b1a4f94236ae2f8a471701aab17e093e1b33402b91550b5c8dd88f04',
'org.codehaus.groovy:groovy-docgenerator:3.0.7:groovy-docgenerator-3.0.7.jar:bf53f7a11c9eb1e278e1b8ed2714c741bcf781235c803ad3ba1555f2614573f3',
'org.codehaus.groovy:groovy-groovydoc:3.0.7:groovy-groovydoc-3.0.7.jar:86b24dfc23c005066ab83927cdb54177f06c9531773f2e2d2ecc9a131f7c2677',
'org.codehaus.groovy:groovy-groovysh:3.0.7:groovy-groovysh-3.0.7.jar:5c40e78cbc09726aedd1c75fab112d245d665d6294870f9119e6cd3013ed14ab',
'org.codehaus.groovy:groovy-jmx:3.0.7:groovy-jmx-3.0.7.jar:0a89f3007884eb156751937d93382038b83d39c7c2f0ab156ebf251a7251f2ab',
'org.codehaus.groovy:groovy-json:3.0.7:groovy-json-3.0.7.jar:df1f0ee475e3fc93a6a0d17548294e160cca5de6d9d36817a7be1fbe650de03b',
'org.codehaus.groovy:groovy-jsr223:3.0.7:groovy-jsr223-3.0.7.jar:1dbd969595332416193baa660fbb45743d19696eaa25fe98e591a2739e13517e',
'org.codehaus.groovy:groovy-macro:3.0.7:groovy-macro-3.0.7.jar:c6cc06df526b39e2c359e2435f0071594c5a1c7babafaa6c184fdd8fa931531f',
'org.codehaus.groovy:groovy-nio:3.0.7:groovy-nio-3.0.7.jar:db54c577882b294cd8c975ec5451596441baf54781319c61627dca0e0c2361ef',
'org.codehaus.groovy:groovy-servlet:3.0.7:groovy-servlet-3.0.7.jar:5b6a909bf501c209adfb6205b9e740649609074455fd979bf9da4853e6ff9a39',
'org.codehaus.groovy:groovy-sql:3.0.7:groovy-sql-3.0.7.jar:252bb6c74e1a9f41756ad4fbd3b0d2eddc93bb61109961dd1952a37bf2d57a64',
'org.codehaus.groovy:groovy-swing:3.0.7:groovy-swing-3.0.7.jar:bd942032d9328d54c6679c49a41f6caa0d4a0039ebe598493b8a647730d98cff',
'org.codehaus.groovy:groovy-templates:3.0.7:groovy-templates-3.0.7.jar:f119e07f650ef186ae5a4b944f9e30915b14311bad47c94a6b32de8d4f69bc80',
'org.codehaus.groovy:groovy-test-junit5:3.0.7:groovy-test-junit5-3.0.7.jar:c16eeea07b8e396891e266d7ba9388b24ac804237ffdd9a792b0d08969bad014',
'org.codehaus.groovy:groovy-test:3.0.7:groovy-test-3.0.7.jar:f71afd7c25d43017f89ea47e6de6daec971d159047dae083c1513a8422d44b90',
'org.codehaus.groovy:groovy-testng:3.0.7:groovy-testng-3.0.7.jar:713d5f2231bbb5712aefd362151b9ffd884aeb7ef2e773315cc54259cbdd063d',
'org.codehaus.groovy:groovy-xml:3.0.7:groovy-xml-3.0.7.jar:8a62e7c9ddece3e82676c4bef2f2c100f459602cd1fb6a14e94187bf863e97ff',
'org.codehaus.groovy:groovy:3.0.7:groovy-3.0.7.jar:51d1777e8dd1f00e60ea56e00d8a354ff5aab1f00fc8464ae8d39d71867e401f',
'org.codehaus.mojo:animal-sniffer-annotations:1.17:animal-sniffer-annotations-1.17.jar:92654f493ecfec52082e76354f0ebf87648dc3d5cec2e3c3cdb947c016747a53', 'org.codehaus.mojo:animal-sniffer-annotations:1.17:animal-sniffer-annotations-1.17.jar:92654f493ecfec52082e76354f0ebf87648dc3d5cec2e3c3cdb947c016747a53',
'org.glassfish.jaxb:jaxb-runtime:2.3.2:jaxb-runtime-2.3.2.jar:e6e0a1e89fb6ff786279e6a0082d5cef52dc2ebe67053d041800737652b4fd1b', 'org.glassfish.jaxb:jaxb-core:2.2.11:jaxb-core-2.2.11.jar:37bcaee8ebb04362c8352a5bf6221b86967ecdab5164c696b10b9a2bb587b2aa',
'org.glassfish.jaxb:txw2:2.3.2:txw2-2.3.2.jar:4a6a9f483388d461b81aa9a28c685b8b74c0597993bf1884b04eddbca95f48fe', '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-core:1.3:hamcrest-core-1.3.jar:66fdef91e9739348df7a096aa384a5685f4e875584cce89386a7a47251c4d8e9',
'org.hamcrest:hamcrest-core:2.1:hamcrest-core-2.1.jar:e09109e54a289d88506b9bfec987ddd199f4217c9464132668351b9a4f00bee9', 'org.hamcrest:hamcrest-library:1.3:hamcrest-library-1.3.jar:711d64522f9ec410983bd310934296da134be4254a125080a0416ec178dfad1c',
'org.hamcrest:hamcrest-library:2.1:hamcrest-library-2.1.jar:b7e2b6895b3b679f0e47b6380fda391b225e9b78505db9d8bdde8d3cc8d52a21', 'org.jetbrains.kotlin:kotlin-reflect:1.3.50:kotlin-reflect-1.3.50.jar:64583199ea5a54aefd1bd1595288925f784226ee562d1dd279011c6075b3d7a4',
'org.hamcrest:hamcrest:2.1:hamcrest-2.1.jar:ba93b2e3a562322ba432f0a1b53addcc55cb188253319a020ed77f824e692050', 'org.jetbrains.kotlin:kotlin-stdlib-common:1.3.50:kotlin-stdlib-common-1.3.50.jar:8ce678e88e4ba018b66dacecf952471e4d7dfee156a8a819760a5a5ff29d323c',
'org.jacoco:org.jacoco.agent:0.8.3:org.jacoco.agent-0.8.3.jar:522deb254ee16a04cc8341cc8f335f5cb7232982994d961b9cf3a0454709209f', 'org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.3.50:kotlin-stdlib-jdk7-1.3.50.jar:9a026639e76212f8d57b86d55b075394c2e009f1979110751d34c05c5f75d57b',
'org.jacoco:org.jacoco.ant:0.8.3:org.jacoco.ant-0.8.3.jar:735844e1ae15f9b875b42a27ac5cb61cc26e106d9e839e5d1c6756709b424ce0', 'org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.3.50:kotlin-stdlib-jdk8-1.3.50.jar:1b351fb6e09c14b55525c74c1f4cf48942eae43c348b7bc764a5e6e423d4da0c',
'org.jacoco:org.jacoco.core:0.8.3:org.jacoco.core-0.8.3.jar:0818437bc060a0c7cc798148f22b713702aae2771aba104444407697d578f1ea', 'org.jetbrains.kotlin:kotlin-stdlib:1.3.50:kotlin-stdlib-1.3.50.jar:e6f05746ee0366d0b52825a090fac474dcf44082c9083bbb205bd16976488d6c',
'org.jacoco:org.jacoco.report:0.8.3:org.jacoco.report-0.8.3.jar:aae08fa4ff043c807b8876cdb2d8705eb8449a55efce461baa6c09da245088c1', 'org.jetbrains.trove4j:trove4j:20160824:trove4j-20160824.jar:1917871c8deb468307a584680c87a44572f5a8b0b98c6d397fc0f5f86596dbe7',
'org.jetbrains.intellij.deps:trove4j:1.0.20181211:trove4j-1.0.20181211.jar:affb7c85a3c87bdcf69ff1dbb84de11f63dc931293934bc08cd7ab18de083601',
'org.jetbrains.kotlin:kotlin-reflect:1.4.32:kotlin-reflect-1.4.32.jar:dbf19e9cdaa9c3c170f3f6f6ce3922f38dfc1d7fa1cab5b7c23a19da8b5eec5b',
'org.jetbrains.kotlin:kotlin-stdlib-common:1.4.20:kotlin-stdlib-common-1.4.20.jar:a7112c9b3cefee418286c9c9372f7af992bd1e6e030691d52f60cb36dbec8320',
'org.jetbrains.kotlin:kotlin-stdlib-common:1.4.32:kotlin-stdlib-common-1.4.32.jar:e1ff6f55ee9e7591dcc633f7757bac25a7edb1cc7f738b37ec652f10f66a4145',
'org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.4.32:kotlin-stdlib-jdk7-1.4.32.jar:5f801e75ca27d8791c14b07943c608da27620d910a8093022af57f543d5d98b6',
'org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.4.32:kotlin-stdlib-jdk8-1.4.32.jar:adc43e54757b106e0cd7b3b7aa257dff471b61efdabe067fc02b2f57e2396262',
'org.jetbrains.kotlin:kotlin-stdlib:1.4.20:kotlin-stdlib-1.4.20.jar:b8ab1da5cdc89cb084d41e1f28f20a42bd431538642a5741c52bbfae3fa3e656',
'org.jetbrains.kotlin:kotlin-stdlib:1.4.32:kotlin-stdlib-1.4.32.jar:13e9fd3e69dc7230ce0fc873a92a4e5d521d179bcf1bef75a6705baac3bfecba',
'org.jetbrains.kotlinx:kotlinx-metadata-jvm:0.1.0:kotlinx-metadata-jvm-0.1.0.jar:9753bb39efef35957c5c15df9a3cb769aabf2cdfa74b47afcb7760e5146be3b5',
'org.jetbrains:annotations:13.0:annotations-13.0.jar:ace2a10dc8e2d5fd34925ecac03e4988b2c0f851650c94b8cef49ba1bd111478', 'org.jetbrains:annotations:13.0:annotations-13.0.jar:ace2a10dc8e2d5fd34925ecac03e4988b2c0f851650c94b8cef49ba1bd111478',
'org.jmock:jmock-imposters:2.12.0:jmock-imposters-2.12.0.jar:3b836269745a137c9b2347e8d7c2104845b126ef04f012d6bfd94f1a7dea7b09', 'org.jmock:jmock-junit4:2.8.2:jmock-junit4-2.8.2.jar:f7ee4df4f7bd7b7f1cafad3b99eb74d579f109d5992ff625347352edb55e674c',
'org.jmock:jmock-junit4:2.12.0:jmock-junit4-2.12.0.jar:3233062fc889637c151a24f1ee086bad04321ab7d8264fef279daff0fa27205b', 'org.jmock:jmock-legacy:2.8.2:jmock-legacy-2.8.2.jar:f2b985a5c08a9edb7f37612330c058809da3f6a6d63ce792426ebf8ff0d6d31b',
'org.jmock:jmock-legacy:2.12.0:jmock-legacy-2.12.0.jar:dea3a9cca653d082e2fe7e40232e982fe03a9984c7d67ceff24f3e03fe580dcd', 'org.jmock:jmock-testjar:2.8.2:jmock-testjar-2.8.2.jar:8900860f72c474e027cf97fe78dcbf154a1aa7fc62b6845c5fb4e4f3c7bc8760',
'org.jmock:jmock-testjar:2.12.0:jmock-testjar-2.12.0.jar:efefbcf6cd294d0e29f0c46eb2a3380d4ca4e1763ff719c69e2f2ac62f564a04', 'org.jmock:jmock:2.8.2:jmock-2.8.2.jar:6c73cb4a2e6dbfb61fd99c9a768539c170ab6568e57846bd60dbf19596b65b16',
'org.jmock:jmock:2.12.0:jmock-2.12.0.jar:266d07314c0cd343c46ff8a55601272de8cf406807caf55e6f313295f83d10be', 'org.jvnet.staxex:stax-ex:1.7.7:stax-ex-1.7.7.jar:a31ff7d77163c0deb09e7fee59ad35ae44c2cee2cc8552a116ccd1583d813fb4',
'org.junit.jupiter:junit-jupiter-api:5.7.0:junit-jupiter-api-5.7.0.jar:b03f78e0daeed2d77a0af9bcd662b4cdb9693f7ee72e01a539b508b84c63d182', 'org.objenesis:objenesis:2.1:objenesis-2.1.jar:c74330cc6b806c804fd37e74487b4fe5d7c2750c5e15fbc6efa13bdee1bdef80',
'org.junit.jupiter:junit-jupiter-engine:5.7.0:junit-jupiter-engine-5.7.0.jar:dfa26af94644ac2612dde6625852fcb550a0d21caa243257de54cba738ba87af', 'org.ow2.asm:asm-analysis:6.0:asm-analysis-6.0.jar:2f1a6387219c3a6cc4856481f221b03bd9f2408a326d416af09af5d6f608c1f4',
'org.junit.platform:junit-platform-commons:1.7.0:junit-platform-commons-1.7.0.jar:5330ee87cc7586e6e25175a34e9251624ff12ff525269d3415d0b4ca519b6fea', 'org.ow2.asm:asm-commons:6.0:asm-commons-6.0.jar:f1bce5c648a96a017bdcd01fe5d59af9845297fd7b79b81c015a6fbbd9719abf',
'org.junit.platform:junit-platform-engine:1.7.0:junit-platform-engine-1.7.0.jar:75f21a20dc594afdc875736725b408cec6d0344874d29f34b2dd3075500236f2', 'org.ow2.asm:asm-tree:6.0:asm-tree-6.0.jar:887998fb69727c8759e4d253f856822801e33f9fd4caa566b3ac58ee92106215',
'org.junit.platform:junit-platform-launcher:1.7.0:junit-platform-launcher-1.7.0.jar:fbdc748fde4c4279fe1d3c607447cb3b7ccd45d7338fc574f8a894ddf2d16818', 'org.ow2.asm:asm-util:6.0:asm-util-6.0.jar:356afebdb0f870175262e5188f8709a3b17aa2a5a6a4b0340b04d4b449bca5f6',
'org.jvnet.staxex:stax-ex:1.8.1:stax-ex-1.8.1.jar:20522549056e9e50aa35ef0b445a2e47a53d06be0b0a9467d704e2483ffb049a', 'org.ow2.asm:asm:5.0.4:asm-5.0.4.jar:896618ed8ae62702521a78bc7be42b7c491a08e6920a15f89a3ecdec31e9a220',
'org.objenesis:objenesis:3.0.1:objenesis-3.0.1.jar:7a8ff780b9ff48415d7c705f60030b0acaa616e7f823c98eede3b63508d4e984', 'org.ow2.asm:asm:6.0:asm-6.0.jar:dd8971c74a4e697899a8e95caae4ea8760ea6c486dc6b97b1795e75760420461',
'org.opentest4j:opentest4j:1.2.0:opentest4j-1.2.0.jar:58812de60898d976fb81ef3b62da05c6604c18fd4a249f5044282479fc286af2',
'org.ow2.asm:asm-analysis:7.0:asm-analysis-7.0.jar:e981f8f650c4d900bb033650b18e122fa6b161eadd5f88978d08751f72ee8474',
'org.ow2.asm:asm-commons:7.0:asm-commons-7.0.jar:fed348ef05958e3e846a3ac074a12af5f7936ef3d21ce44a62c4fa08a771927d',
'org.ow2.asm:asm-tree:7.0:asm-tree-7.0.jar:cfd7a0874f9de36a999c127feeadfbfe6e04d4a71ee954d7af3d853f0be48a6c',
'org.ow2.asm:asm-util:7.0:asm-util-7.0.jar:75fbbca440ef463f41c2b0ab1a80abe67e910ac486da60a7863cbcb5bae7e145',
'org.ow2.asm:asm:7.0:asm-7.0.jar:b88ef66468b3c978ad0c97fd6e90979e56155b4ac69089ba7a44e9aa7ffe9acf',
'org.ow2.asm:asm:7.1:asm-7.1.jar:4ab2fa2b6d2cc9ccb1eaa05ea329c407b47b13ed2915f62f8c4b8cc96258d4de',
'org.testng:testng:7.3.0:testng-7.3.0.jar:63727488f9717d57f0d0a0fee5a1fc10a2be9cfcff2ec3a7187656d663c0774e',
'xerces:xercesImpl:2.12.0:xercesImpl-2.12.0.jar:b50d3a4ca502faa4d1c838acb8aa9480446953421f7327e338c5dda3da5e76d0',
'xml-apis:xml-apis:1.4.01:xml-apis-1.4.01.jar:a840968176645684bb01aed376e067ab39614885f9eee44abe35a5f20ebe7fad',
] ]
} }

View File

@@ -5,16 +5,15 @@ targetCompatibility = 1.8
apply plugin: 'ru.vyarus.animalsniffer' apply plugin: 'ru.vyarus.animalsniffer'
apply plugin: 'witness' apply plugin: 'witness'
apply from: 'witness.gradle' apply from: 'witness.gradle'
apply plugin: 'checkstyle'
dependencies { dependencies {
implementation "com.google.dagger:dagger:$dagger_version" implementation "com.google.dagger:dagger:2.24"
implementation 'com.google.code.findbugs:jsr305:3.0.2' implementation 'com.google.code.findbugs:jsr305:3.0.2'
implementation "com.fasterxml.jackson.core:jackson-annotations:$jackson_version"
testImplementation "junit:junit:$junit_version" testImplementation 'junit:junit:4.12'
testImplementation "org.jmock:jmock:$jmock_version" testImplementation "org.jmock:jmock:2.8.2"
testImplementation "org.jmock:jmock-junit4:$jmock_version" testImplementation "org.jmock:jmock-junit4:2.8.2"
testImplementation "org.jmock:jmock-legacy:2.8.2"
signature 'org.codehaus.mojo.signature:java16:1.1@signature' signature 'org.codehaus.mojo.signature:java16:1.1@signature'
} }

View File

@@ -1,6 +0,0 @@
package org.briarproject.bramble.api;
public interface Cancellable {
void cancel();
}

View File

@@ -1,9 +0,0 @@
package org.briarproject.bramble.api;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
@NotNullByDefault
public interface Consumer<T> {
void accept(T t);
}

View File

@@ -6,16 +6,4 @@ package org.briarproject.bramble.api;
public interface FeatureFlags { public interface FeatureFlags {
boolean shouldEnableImageAttachments(); boolean shouldEnableImageAttachments();
boolean shouldEnableProfilePictures();
boolean shouldEnableDisappearingMessages();
boolean shouldEnableMailbox();
boolean shouldEnablePrivateGroupsInCore();
boolean shouldEnableForumsInCore();
boolean shouldEnableBlogsInCore();
} }

View File

@@ -1,14 +1,8 @@
package org.briarproject.bramble.api; package org.briarproject.bramble.api;
import org.briarproject.bramble.util.StringUtils;
import java.util.ArrayList;
import java.util.Hashtable; import java.util.Hashtable;
import java.util.List;
import java.util.Map; import java.util.Map;
import javax.annotation.Nullable;
public abstract class StringMap extends Hashtable<String, String> { public abstract class StringMap extends Hashtable<String, String> {
protected StringMap(Map<String, String> m) { protected StringMap(Map<String, String> m) {
@@ -58,31 +52,4 @@ public abstract class StringMap extends Hashtable<String, String> {
public void putLong(String key, long value) { public void putLong(String key, long value) {
put(key, String.valueOf(value)); put(key, String.valueOf(value));
} }
@Nullable
public int[] getIntArray(String key) {
String s = get(key);
if (s == null) return null;
// Handle empty string because "".split(",") returns {""}
if (s.length() == 0) return new int[0];
String[] intStrings = s.split(",");
int[] ints = new int[intStrings.length];
try {
for (int i = 0; i < ints.length; i++) {
ints[i] = Integer.parseInt(intStrings[i]);
}
} catch (NumberFormatException e) {
return null;
}
return ints;
}
public void putIntArray(String key, int[] value) {
List<String> intStrings = new ArrayList<>();
for (int integer : value) {
intStrings.add(String.valueOf(integer));
}
// Puts empty string if input array value is empty
put(key, StringUtils.join(intStrings, ","));
}
} }

View File

@@ -6,14 +6,14 @@ import javax.annotation.concurrent.ThreadSafe;
@ThreadSafe @ThreadSafe
@NotNullByDefault @NotNullByDefault
public class UniqueId extends Bytes { public abstract class UniqueId extends Bytes {
/** /**
* The length of a unique identifier in bytes. * The length of a unique identifier in bytes.
*/ */
public static final int LENGTH = 32; public static final int LENGTH = 32;
public UniqueId(byte[] id) { protected UniqueId(byte[] id) {
super(id); super(id);
if (id.length != LENGTH) throw new IllegalArgumentException(); if (id.length != LENGTH) throw new IllegalArgumentException();
} }

View File

@@ -1,35 +0,0 @@
package org.briarproject.bramble.api;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import java.lang.ref.WeakReference;
import javax.annotation.concurrent.GuardedBy;
import javax.inject.Provider;
/**
* A {@link Provider} that keeps a {@link WeakReference} to the last provided
* instance and provides the same instance again until the instance is garbage
* collected.
*/
@NotNullByDefault
public abstract class WeakSingletonProvider<T> implements Provider<T> {
private final Object lock = new Object();
@GuardedBy("lock")
private WeakReference<T> ref = new WeakReference<>(null);
@Override
public T get() {
synchronized (lock) {
T instance = ref.get();
if (instance == null) {
instance = createInstance();
ref = new WeakReference<>(instance);
}
return instance;
}
}
public abstract T createInstance();
}

View File

@@ -1,29 +0,0 @@
package org.briarproject.bramble.api.cleanup;
import org.briarproject.bramble.api.db.DatabaseComponent;
import org.briarproject.bramble.api.db.DbException;
import org.briarproject.bramble.api.db.Transaction;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import org.briarproject.bramble.api.sync.GroupId;
import org.briarproject.bramble.api.sync.MessageId;
import java.util.Collection;
/**
* An interface for registering a hook with the {@link CleanupManager}
* that will be called when a message's cleanup deadline is reached.
*/
@NotNullByDefault
public interface CleanupHook {
/**
* Called when the cleanup deadlines of one or more messages are reached.
* <p>
* The callee is not required to delete the messages, but the hook won't be
* called again for these messages unless another cleanup timer is set (see
* {@link DatabaseComponent#setCleanupTimerDuration(Transaction, MessageId, long)}
* and {@link DatabaseComponent#startCleanupTimer(Transaction, MessageId)}).
*/
void deleteMessages(Transaction txn, GroupId g,
Collection<MessageId> messageIds) throws DbException;
}

View File

@@ -1,42 +0,0 @@
package org.briarproject.bramble.api.cleanup;
import org.briarproject.bramble.api.cleanup.event.CleanupTimerStartedEvent;
import org.briarproject.bramble.api.crypto.SecretKey;
import org.briarproject.bramble.api.db.DatabaseComponent;
import org.briarproject.bramble.api.db.Transaction;
import org.briarproject.bramble.api.lifecycle.LifecycleManager;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import org.briarproject.bramble.api.sync.ClientId;
import org.briarproject.bramble.api.sync.MessageId;
/**
* The CleanupManager is responsible for tracking the cleanup deadlines of
* messages and passing them to their respective
* {@link CleanupHook CleanupHooks} when the deadlines are reached.
* <p>
* The CleanupManager responds to
* {@link CleanupTimerStartedEvent CleanupTimerStartedEvents} broadcast by the
* {@link DatabaseComponent}.
* <p>
* See {@link DatabaseComponent#setCleanupTimerDuration(Transaction, MessageId, long)},
* {@link DatabaseComponent#startCleanupTimer(Transaction, MessageId)},
* {@link DatabaseComponent#stopCleanupTimer(Transaction, MessageId)}.
*/
@NotNullByDefault
public interface CleanupManager {
/**
* When scheduling a cleanup task we overshoot the deadline by this many
* milliseconds to reduce the number of tasks that need to be scheduled
* when messages have cleanup deadlines that are close together.
*/
long BATCH_DELAY_MS = 1000;
/**
* Registers a hook to be called when messages are due for cleanup.
* This method should be called before
* {@link LifecycleManager#startServices(SecretKey)}.
*/
void registerCleanupHook(ClientId c, int majorVersion,
CleanupHook hook);
}

View File

@@ -1,32 +0,0 @@
package org.briarproject.bramble.api.cleanup.event;
import org.briarproject.bramble.api.event.Event;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import org.briarproject.bramble.api.sync.MessageId;
import javax.annotation.concurrent.Immutable;
/**
* An event that is broadcast when a message's cleanup timer is started.
*/
@Immutable
@NotNullByDefault
public class CleanupTimerStartedEvent extends Event {
private final MessageId messageId;
private final long cleanupDeadline;
public CleanupTimerStartedEvent(MessageId messageId,
long cleanupDeadline) {
this.messageId = messageId;
this.cleanupDeadline = cleanupDeadline;
}
public MessageId getMessageId() {
return messageId;
}
public long getCleanupDeadline() {
return cleanupDeadline;
}
}

View File

@@ -32,31 +32,28 @@ public abstract class BdfIncomingMessageHook implements IncomingMessageHook {
/** /**
* Called once for each incoming message that passes validation. * Called once for each incoming message that passes validation.
* <p>
* If an unexpected exception occurs while handling data that is assumed
* to be valid (e.g. locally created metadata), it may be sensible to
* rethrow the unexpected exception as a DbException so that delivery is
* attempted again at next startup. This will allow delivery to succeed if
* the unexpected exception was caused by a bug that has subsequently been
* fixed.
* *
* @param txn A read-write transaction * @param txn A read-write transaction
* @throws DbException if a database error occurs while delivering the * @return Whether or not this message should be shared
* message. Delivery will be attempted again at next startup. Throwing * @throws DbException Should only be used for real database errors.
* this exception has the same effect as returning * If this is thrown, delivery will be attempted again at next startup,
* {@link DeliveryAction#DEFER}. * whereas if a FormatException is thrown, the message will be permanently
* @throws FormatException if the message is invalid in the context of its * invalidated.
* dependencies. The message and any dependents will be marked as invalid * @throws FormatException Use this for any non-database error
* and deleted along with their metadata. Throwing this exception has the * that occurs while handling remotely created data.
* same effect as returning {@link DeliveryAction#REJECT}. * This includes errors that occur while handling locally created data
* in a context controlled by remotely created data
* (for example, parsing the metadata of a dependency
* of an incoming message).
* Never rethrow DbException as FormatException!
*/ */
protected abstract DeliveryAction incomingMessage(Transaction txn, protected abstract boolean incomingMessage(Transaction txn, Message m,
Message m, BdfList body, BdfDictionary meta) BdfList body, BdfDictionary meta) throws DbException,
throws DbException, FormatException; FormatException;
@Override @Override
public DeliveryAction incomingMessage(Transaction txn, Message m, public boolean incomingMessage(Transaction txn, Message m, Metadata meta)
Metadata meta) throws DbException, InvalidMessageException { throws DbException, InvalidMessageException {
try { try {
BdfList body = clientHelper.toList(m); BdfList body = clientHelper.toList(m);
BdfDictionary metaDictionary = metadataParser.parse(meta); BdfDictionary metaDictionary = metadataParser.parse(meta);

View File

@@ -1,7 +1,6 @@
package org.briarproject.bramble.api.client; package org.briarproject.bramble.api.client;
import org.briarproject.bramble.api.FormatException; import org.briarproject.bramble.api.FormatException;
import org.briarproject.bramble.api.contact.ContactId;
import org.briarproject.bramble.api.crypto.PrivateKey; import org.briarproject.bramble.api.crypto.PrivateKey;
import org.briarproject.bramble.api.crypto.PublicKey; import org.briarproject.bramble.api.crypto.PublicKey;
import org.briarproject.bramble.api.data.BdfDictionary; import org.briarproject.bramble.api.data.BdfDictionary;
@@ -9,8 +8,6 @@ import org.briarproject.bramble.api.data.BdfList;
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.mailbox.MailboxUpdate;
import org.briarproject.bramble.api.mailbox.MailboxVersion;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault; import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import org.briarproject.bramble.api.plugin.TransportId; import org.briarproject.bramble.api.plugin.TransportId;
import org.briarproject.bramble.api.properties.TransportProperties; import org.briarproject.bramble.api.properties.TransportProperties;
@@ -19,8 +16,6 @@ import org.briarproject.bramble.api.sync.Message;
import org.briarproject.bramble.api.sync.MessageId; import org.briarproject.bramble.api.sync.MessageId;
import java.security.GeneralSecurityException; import java.security.GeneralSecurityException;
import java.util.Collection;
import java.util.List;
import java.util.Map; import java.util.Map;
@NotNullByDefault @NotNullByDefault
@@ -55,11 +50,9 @@ public interface ClientHelper {
BdfDictionary getGroupMetadataAsDictionary(Transaction txn, GroupId g) BdfDictionary getGroupMetadataAsDictionary(Transaction txn, GroupId g)
throws DbException, FormatException; throws DbException, FormatException;
Collection<MessageId> getMessageIds(Transaction txn, GroupId g,
BdfDictionary query) throws DbException, FormatException;
BdfDictionary getMessageMetadataAsDictionary(MessageId m) BdfDictionary getMessageMetadataAsDictionary(MessageId m)
throws DbException, FormatException; throws DbException,
FormatException;
BdfDictionary getMessageMetadataAsDictionary(Transaction txn, MessageId m) BdfDictionary getMessageMetadataAsDictionary(Transaction txn, MessageId m)
throws DbException, FormatException; throws DbException, FormatException;
@@ -126,30 +119,4 @@ public interface ClientHelper {
Map<TransportId, TransportProperties> parseAndValidateTransportPropertiesMap( Map<TransportId, TransportProperties> parseAndValidateTransportPropertiesMap(
BdfDictionary properties) throws FormatException; BdfDictionary properties) throws FormatException;
/**
* Parse and validate the elements of a Mailbox update message.
*
* @return the parsed update message
* @throws FormatException if the message elements are invalid
*/
MailboxUpdate parseAndValidateMailboxUpdate(BdfList clientSupports,
BdfList serverSupports, BdfDictionary properties)
throws FormatException;
List<MailboxVersion> parseMailboxVersionList(BdfList bdfList)
throws FormatException;
/**
* Retrieves the contact ID from the group metadata of the given contact
* group.
*/
ContactId getContactId(Transaction txn, GroupId contactGroupId)
throws DbException;
/**
* Stores the given contact ID in the group metadata of the given contact
* group.
*/
void setContactId(Transaction txn, GroupId contactGroupId, ContactId c)
throws DbException;
} }

View File

@@ -1,9 +0,0 @@
package org.briarproject.bramble.api.client;
public interface ContactGroupConstants {
/**
* Group metadata key for associating a contact ID with a contact group.
*/
String GROUP_KEY_CONTACT_ID = "contactId";
}

View File

@@ -7,7 +7,6 @@ import org.briarproject.bramble.api.plugin.TransportConnectionReader;
import org.briarproject.bramble.api.plugin.TransportConnectionWriter; import org.briarproject.bramble.api.plugin.TransportConnectionWriter;
import org.briarproject.bramble.api.plugin.TransportId; import org.briarproject.bramble.api.plugin.TransportId;
import org.briarproject.bramble.api.plugin.duplex.DuplexTransportConnection; import org.briarproject.bramble.api.plugin.duplex.DuplexTransportConnection;
import org.briarproject.bramble.api.sync.OutgoingSessionRecord;
@NotNullByDefault @NotNullByDefault
public interface ConnectionManager { public interface ConnectionManager {
@@ -17,17 +16,6 @@ public interface ConnectionManager {
*/ */
void manageIncomingConnection(TransportId t, TransportConnectionReader r); void manageIncomingConnection(TransportId t, TransportConnectionReader r);
/**
* Manages an incoming connection from a contact via a mailbox.
* <p>
* This method does not mark the tag as recognised until after the data
* has been read from the {@link TransportConnectionReader}, at which
* point the {@link TagController} is called to decide whether the tag
* should be marked as recognised.
*/
void manageIncomingConnection(TransportId t, TransportConnectionReader r,
TagController c);
/** /**
* Manages an incoming connection from a contact over a duplex transport. * Manages an incoming connection from a contact over a duplex transport.
*/ */
@@ -46,14 +34,6 @@ public interface ConnectionManager {
void manageOutgoingConnection(ContactId c, TransportId t, void manageOutgoingConnection(ContactId c, TransportId t,
TransportConnectionWriter w); TransportConnectionWriter w);
/**
* Manages an outgoing connection to a contact via a mailbox. The IDs of
* any messages sent or acked are added to the given
* {@link OutgoingSessionRecord}.
*/
void manageOutgoingConnection(ContactId c, TransportId t,
TransportConnectionWriter w, OutgoingSessionRecord sessionRecord);
/** /**
* Manages an outgoing connection to a contact over a duplex transport. * Manages an outgoing connection to a contact over a duplex transport.
*/ */
@@ -66,21 +46,4 @@ public interface ConnectionManager {
*/ */
void manageOutgoingConnection(PendingContactId p, TransportId t, void manageOutgoingConnection(PendingContactId p, TransportId t,
DuplexTransportConnection d); DuplexTransportConnection d);
/**
* An interface for controlling whether a tag should be marked as
* recognised.
*/
interface TagController {
/**
* This method is only called if a tag was read from the corresponding
* {@link TransportConnectionReader} and recognised.
*
* @param exception True if an exception was thrown while reading from
* the {@link TransportConnectionReader}, after successfully reading
* and recognising the tag.
* @return True if the tag should be marked as recognised.
*/
boolean shouldMarkTagAsRecognised(boolean exception);
}
} }

View File

@@ -11,6 +11,7 @@ import org.briarproject.bramble.api.db.PendingContactExistsException;
import org.briarproject.bramble.api.db.Transaction; import org.briarproject.bramble.api.db.Transaction;
import org.briarproject.bramble.api.identity.Author; import org.briarproject.bramble.api.identity.Author;
import org.briarproject.bramble.api.identity.AuthorId; import org.briarproject.bramble.api.identity.AuthorId;
import org.briarproject.bramble.api.identity.AuthorInfo;
import org.briarproject.bramble.api.lifecycle.LifecycleManager; import org.briarproject.bramble.api.lifecycle.LifecycleManager;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault; import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
@@ -107,32 +108,6 @@ public interface ContactManager {
*/ */
String getHandshakeLink() throws DbException; String getHandshakeLink() throws DbException;
/**
* Returns the handshake link that needs to be sent to a contact we want
* to add.
*/
String getHandshakeLink(Transaction txn) throws DbException;
/**
* Creates a {@link PendingContact} from the given handshake link and
* alias, adds it to the database and returns it.
*
* @param link The handshake link received from the pending contact
* @param alias The alias the user has given this pending contact
* @throws UnsupportedVersionException If the link uses a format version
* that is not supported
* @throws FormatException If the link is invalid
* @throws GeneralSecurityException If the pending contact's handshake
* public key is invalid
* @throws ContactExistsException If a contact with the same handshake
* public key already exists
* @throws PendingContactExistsException If a pending contact with the same
* handshake public key already exists
*/
PendingContact addPendingContact(Transaction txn, String link, String alias)
throws DbException, FormatException, GeneralSecurityException,
ContactExistsException, PendingContactExistsException;
/** /**
* Creates a {@link PendingContact} from the given handshake link and * Creates a {@link PendingContact} from the given handshake link and
* alias, adds it to the database and returns it. * alias, adds it to the database and returns it.
@@ -166,24 +141,11 @@ public interface ContactManager {
Collection<Pair<PendingContact, PendingContactState>> getPendingContacts() Collection<Pair<PendingContact, PendingContactState>> getPendingContacts()
throws DbException; throws DbException;
/**
* Returns a list of {@link PendingContact PendingContacts} and their
* {@link PendingContactState states}.
*/
Collection<Pair<PendingContact, PendingContactState>> getPendingContacts(Transaction txn)
throws DbException;
/** /**
* Removes a {@link PendingContact}. * Removes a {@link PendingContact}.
*/ */
void removePendingContact(PendingContactId p) throws DbException; void removePendingContact(PendingContactId p) throws DbException;
/**
* Removes a {@link PendingContact}.
*/
void removePendingContact(Transaction txn, PendingContactId p)
throws DbException;
/** /**
* Returns the contact with the given ID. * Returns the contact with the given ID.
*/ */
@@ -217,11 +179,6 @@ public interface ContactManager {
*/ */
Collection<Contact> getContacts() throws DbException; Collection<Contact> getContacts() throws DbException;
/**
* Returns all contacts.
*/
Collection<Contact> getContacts(Transaction txn) throws DbException;
/** /**
* Removes a contact and all associated state. * Removes a contact and all associated state.
*/ */
@@ -258,6 +215,16 @@ public interface ContactManager {
boolean contactExists(AuthorId remoteAuthorId, AuthorId localAuthorId) boolean contactExists(AuthorId remoteAuthorId, AuthorId localAuthorId)
throws DbException; throws DbException;
/**
* Returns the {@link AuthorInfo} for the given author.
*/
AuthorInfo getAuthorInfo(AuthorId a) throws DbException;
/**
* Returns the {@link AuthorInfo} for the given author.
*/
AuthorInfo getAuthorInfo(Transaction txn, AuthorId a) throws DbException;
interface ContactHook { interface ContactHook {
/** /**

View File

@@ -3,6 +3,7 @@ package org.briarproject.bramble.api.contact;
import org.briarproject.bramble.api.UniqueId; import org.briarproject.bramble.api.UniqueId;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault; import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import javax.annotation.Nullable;
import javax.annotation.concurrent.ThreadSafe; import javax.annotation.concurrent.ThreadSafe;
/** /**
@@ -16,4 +17,9 @@ public class PendingContactId extends UniqueId {
public PendingContactId(byte[] id) { public PendingContactId(byte[] id) {
super(id); super(id);
} }
@Override
public boolean equals(@Nullable Object o) {
return o instanceof PendingContactId && super.equals(o);
}
} }

View File

@@ -1,35 +0,0 @@
package org.briarproject.bramble.api.contact.event;
import org.briarproject.bramble.api.contact.ContactId;
import org.briarproject.bramble.api.event.Event;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import javax.annotation.Nullable;
import javax.annotation.concurrent.Immutable;
/**
* An event that is broadcast when the alias for a contact changed.
*/
@Immutable
@NotNullByDefault
public class ContactAliasChangedEvent extends Event {
private final ContactId contactId;
@Nullable
private final String alias;
public ContactAliasChangedEvent(ContactId contactId,
@Nullable String alias) {
this.contactId = contactId;
this.alias = alias;
}
public ContactId getContactId() {
return contactId;
}
@Nullable
public String getAlias() {
return alias;
}
}

View File

@@ -1,6 +1,5 @@
package org.briarproject.bramble.api.crypto; package org.briarproject.bramble.api.crypto;
import org.briarproject.bramble.api.UniqueId;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault; import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import java.security.GeneralSecurityException; import java.security.GeneralSecurityException;
@@ -11,8 +10,6 @@ import javax.annotation.Nullable;
@NotNullByDefault @NotNullByDefault
public interface CryptoComponent { public interface CryptoComponent {
UniqueId generateUniqueId();
SecretKey generateSecretKey(); SecretKey generateSecretKey();
SecureRandom getSecureRandom(); SecureRandom getSecureRandom();
@@ -173,13 +170,4 @@ public interface CryptoComponent {
* length. The line terminator is CRLF. * length. The line terminator is CRLF.
*/ */
String asciiArmour(byte[] b, int lineLength); String asciiArmour(byte[] b, int lineLength);
/**
* Encode the Onion given its public key. Specified here:
* https://gitweb.torproject.org/torspec.git/tree/rend-spec-v3.txt?id=29245fd5#n2135
*
* @return the encoded onion, base32 chars
*/
String encodeOnion(byte[] publicKey);
} }

View File

@@ -1,19 +1,23 @@
package org.briarproject.bramble.api.crypto; package org.briarproject.bramble.api.crypto;
import org.briarproject.bramble.api.Bytes;
/** /**
* A secret key used for encryption and/or authentication. * A secret key used for encryption and/or authentication.
*/ */
public class SecretKey extends Bytes { public class SecretKey {
/** /**
* The length of a secret key in bytes. * The length of a secret key in bytes.
*/ */
public static final int LENGTH = 32; public static final int LENGTH = 32;
private final byte[] key;
public SecretKey(byte[] key) { public SecretKey(byte[] key) {
super(key);
if (key.length != LENGTH) throw new IllegalArgumentException(); if (key.length != LENGTH) throw new IllegalArgumentException();
this.key = key;
}
public byte[] getBytes() {
return key;
} }
} }

View File

@@ -19,10 +19,4 @@ public interface StreamDecrypterFactory {
*/ */
StreamDecrypter createContactExchangeStreamDecrypter(InputStream in, StreamDecrypter createContactExchangeStreamDecrypter(InputStream in,
SecretKey headerKey); SecretKey headerKey);
/**
* Creates a {@link StreamDecrypter} for decrypting a log stream.
*/
StreamDecrypter createLogStreamDecrypter(InputStream in,
SecretKey headerKey);
} }

View File

@@ -17,12 +17,6 @@ public interface StreamEncrypterFactory {
* Creates a {@link StreamEncrypter} for encrypting a contact exchange * Creates a {@link StreamEncrypter} for encrypting a contact exchange
* stream. * stream.
*/ */
StreamEncrypter createContactExchangeStreamEncrypter(OutputStream out, StreamEncrypter createContactExchangeStreamDecrypter(OutputStream out,
SecretKey headerKey);
/**
* Creates a {@link StreamEncrypter} for encrypting a log stream.
*/
StreamEncrypter createLogStreamEncrypter(OutputStream out,
SecretKey headerKey); SecretKey headerKey);
} }

View File

@@ -33,33 +33,14 @@ import java.util.List;
import java.util.Map; import java.util.Map;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import javax.annotation.concurrent.ThreadSafe;
/** /**
* Encapsulates the database implementation and exposes high-level operations * Encapsulates the database implementation and exposes high-level operations
* to other components. * to other components.
* <p>
* With the exception of the {@link #open(SecretKey, MigrationListener)} and
* {@link #close()} methods, which must not be called concurrently, the
* database can be accessed from any thread. See {@link TransactionManager}
* for locking behaviour.
*/ */
@ThreadSafe
@NotNullByDefault @NotNullByDefault
public interface DatabaseComponent extends TransactionManager { public interface DatabaseComponent extends TransactionManager {
/**
* Return value for {@link #getNextCleanupDeadline(Transaction)} if
* no messages are scheduled to be deleted.
*/
long NO_CLEANUP_DEADLINE = -1;
/**
* Return value for {@link #startCleanupTimer(Transaction, MessageId)}
* if the cleanup timer was not started.
*/
long TIMER_NOT_STARTED = -1;
/** /**
* Opens the database and returns true if the database already existed. * Opens the database and returns true if the database already existed.
* *
@@ -108,7 +89,7 @@ public interface DatabaseComponent extends TransactionManager {
/** /**
* Stores a transport. * Stores a transport.
*/ */
void addTransport(Transaction txn, TransportId t, long maxLatency) void addTransport(Transaction txn, TransportId t, int maxLatency)
throws DbException; throws DbException;
/** /**
@@ -125,13 +106,6 @@ public interface DatabaseComponent extends TransactionManager {
KeySetId addTransportKeys(Transaction txn, PendingContactId p, KeySetId addTransportKeys(Transaction txn, PendingContactId p,
TransportKeys k) throws DbException; TransportKeys k) throws DbException;
/**
* Returns true if there are any acks to send to the given contact.
* <p/>
* Read-only.
*/
boolean containsAcksToSend(Transaction txn, ContactId c) throws DbException;
/** /**
* Returns true if the database contains the given contact for the given * Returns true if the database contains the given contact for the given
* local pseudonym. * local pseudonym.
@@ -156,18 +130,6 @@ public interface DatabaseComponent extends TransactionManager {
*/ */
boolean containsIdentity(Transaction txn, AuthorId a) throws DbException; boolean containsIdentity(Transaction txn, AuthorId a) throws DbException;
/**
* Returns true if there are any messages to send to the given contact
* over a transport with the given maximum latency.
* <p/>
* Read-only.
*
* @param eager True if messages that are not yet due for retransmission
* should be included
*/
boolean containsMessagesToSend(Transaction txn, ContactId c,
long maxLatency, boolean eager) throws DbException;
/** /**
* Returns true if the database contains the given pending contact. * Returns true if the database contains the given pending contact.
* <p/> * <p/>
@@ -176,16 +138,6 @@ public interface DatabaseComponent extends TransactionManager {
boolean containsPendingContact(Transaction txn, PendingContactId p) boolean containsPendingContact(Transaction txn, PendingContactId p)
throws DbException; throws DbException;
/**
* Returns true if the database contains keys for communicating with the
* given contact over the given transport. Handshake mode and rotation mode
* keys are included, whether activated or not.
* <p/>
* Read-only.
*/
boolean containsTransportKeys(Transaction txn, ContactId c, TransportId t)
throws DbException;
/** /**
* Deletes the message with the given ID. Unlike * Deletes the message with the given ID. Unlike
* {@link #removeMessage(Transaction, MessageId)}, the message ID, * {@link #removeMessage(Transaction, MessageId)}, the message ID,
@@ -207,15 +159,14 @@ public interface DatabaseComponent extends TransactionManager {
throws DbException; throws DbException;
/** /**
* Returns a batch of messages for the given contact, for transmission over * Returns a batch of messages for the given contact, with a total length
* a transport with the given maximum latency. The total length of the * less than or equal to the given length, for transmission over a
* messages, including record headers, will be no more than the given * transport with the given maximum latency. Returns null if there are no
* capacity. Returns null if there are no sendable messages that would fit * sendable messages that fit in the given length.
* in the given capacity.
*/ */
@Nullable @Nullable
Collection<Message> generateBatch(Transaction txn, ContactId c, Collection<Message> generateBatch(Transaction txn, ContactId c,
long capacity, long maxLatency) throws DbException; int maxLength, int maxLatency) throws DbException;
/** /**
* Returns an offer for the given contact for transmission over a * Returns an offer for the given contact for transmission over a
@@ -224,7 +175,7 @@ public interface DatabaseComponent extends TransactionManager {
*/ */
@Nullable @Nullable
Offer generateOffer(Transaction txn, ContactId c, int maxMessages, Offer generateOffer(Transaction txn, ContactId c, int maxMessages,
long maxLatency) throws DbException; int maxLatency) throws DbException;
/** /**
* Returns a request for the given contact, or null if there are no * Returns a request for the given contact, or null if there are no
@@ -235,16 +186,15 @@ public interface DatabaseComponent extends TransactionManager {
throws DbException; throws DbException;
/** /**
* Returns a batch of messages for the given contact, for transmission over * Returns a batch of messages for the given contact, with a total length
* a transport with the given maximum latency. Only messages that have been * less than or equal to the given length, for transmission over a
* requested by the contact are returned. The total length of the messages, * transport with the given maximum latency. Only messages that have been
* including record headers, will be no more than the given capacity. * requested by the contact are returned. Returns null if there are no
* Returns null if there are no sendable messages that have been requested * sendable messages that fit in the given length.
* by the contact and would fit in the given capacity.
*/ */
@Nullable @Nullable
Collection<Message> generateRequestedBatch(Transaction txn, ContactId c, Collection<Message> generateRequestedBatch(Transaction txn, ContactId c,
long capacity, long maxLatency) throws DbException; int maxLength, int maxLatency) throws DbException;
/** /**
* Returns the contact with the given ID. * Returns the contact with the given ID.
@@ -283,13 +233,6 @@ public interface DatabaseComponent extends TransactionManager {
*/ */
Group getGroup(Transaction txn, GroupId g) throws DbException; Group getGroup(Transaction txn, GroupId g) throws DbException;
/**
* Returns the ID of the group containing the given message.
* <p/>
* Read-only.
*/
GroupId getGroupId(Transaction txn, MessageId m) throws DbException;
/** /**
* Returns the metadata for the given group. * Returns the metadata for the given group.
* <p/> * <p/>
@@ -345,40 +288,6 @@ public interface DatabaseComponent extends TransactionManager {
Collection<MessageId> getMessageIds(Transaction txn, GroupId g) Collection<MessageId> getMessageIds(Transaction txn, GroupId g)
throws DbException; throws DbException;
/**
* Returns the IDs of any delivered messages in the given group with
* metadata that matches all entries in the given query. If the query is
* empty, the IDs of all delivered messages are returned.
* <p/>
* Read-only.
*/
Collection<MessageId> getMessageIds(Transaction txn, GroupId g,
Metadata query) throws DbException;
/**
* Returns the IDs of all messages received from the given contact that
* need to be acknowledged.
* <p/>
* Read-only.
*/
Collection<MessageId> getMessagesToAck(Transaction txn, ContactId c)
throws DbException;
/**
* Returns the IDs of some messages that are eligible to be sent to the
* given contact over a transport with the given maximum latency. The total
* length of the messages including record headers will be no more than the
* given capacity.
* <p/>
* Unlike {@link #getUnackedMessagesToSend(Transaction, ContactId)} this
* method does not return messages that have already been sent unless they
* are due for retransmission.
* <p/>
* Read-only.
*/
Collection<MessageId> getMessagesToSend(Transaction txn, ContactId c,
long capacity, long maxLatency) throws DbException;
/** /**
* Returns the IDs of any messages that need to be validated. * Returns the IDs of any messages that need to be validated.
* <p/> * <p/>
@@ -405,15 +314,6 @@ public interface DatabaseComponent extends TransactionManager {
Collection<MessageId> getMessagesToShare(Transaction txn) Collection<MessageId> getMessagesToShare(Transaction txn)
throws DbException; throws DbException;
/**
* Returns the IDs of any messages of any messages that are due for
* deletion, along with their group IDs.
* <p/>
* Read-only.
*/
Map<GroupId, Collection<MessageId>> getMessagesToDelete(Transaction txn)
throws DbException;
/** /**
* Returns the metadata for all delivered messages in the given group. * Returns the metadata for all delivered messages in the given group.
* <p/> * <p/>
@@ -495,73 +395,15 @@ public interface DatabaseComponent extends TransactionManager {
MessageStatus getMessageStatus(Transaction txn, ContactId c, MessageId m) MessageStatus getMessageStatus(Transaction txn, ContactId c, MessageId m)
throws DbException; throws DbException;
/** /*
* Returns the message with the given ID for transmission to the given
* contact over a transport with the given maximum latency. Returns null
* if the message is no longer visible to the contact.
* <p/>
* Read-only if {@code markAsSent} is false.
*
* @param markAsSent True if the message should be marked as sent.
* If false it can be marked as sent by calling
* {@link #setMessagesSent(Transaction, ContactId, Collection, long)}.
*/
@Nullable
Message getMessageToSend(Transaction txn, ContactId c, MessageId m,
long maxLatency, boolean markAsSent) throws DbException;
/**
* Returns the IDs of all messages that are eligible to be sent to the
* given contact.
* <p>
* Unlike {@link #getMessagesToSend(Transaction, ContactId, long, long)}
* this method may return messages that have already been sent and are
* not yet due for retransmission.
* <p/>
* Read-only.
*/
Collection<MessageId> getUnackedMessagesToSend(Transaction txn,
ContactId c) throws DbException;
/**
* Resets the transmission count, expiry time and max latency of all messages
* that are eligible to be sent to the given contact. This includes messages
* that have already been sent and are not yet due for retransmission.
*/
void resetUnackedMessagesToSend(Transaction txn, ContactId c)
throws DbException;
/**
* Returns the total length, including headers, of all messages that are
* eligible to be sent to the given contact. This may include messages
* that have already been sent and are not yet due for retransmission.
* <p/>
* Read-only.
*/
long getUnackedMessageBytesToSend(Transaction txn, ContactId c)
throws DbException;
/**
* Returns the next time (in milliseconds since the Unix epoch) when a * Returns the next time (in milliseconds since the Unix epoch) when a
* message is due to be deleted, or {@link #NO_CLEANUP_DEADLINE} * message is due to be sent to the given contact. The returned value may
* if no messages are scheduled to be deleted. * be zero if a message is due to be sent immediately, or Long.MAX_VALUE if
* no messages are scheduled to be sent.
* <p/> * <p/>
* Read-only. * Read-only.
*/ */
long getNextCleanupDeadline(Transaction txn) throws DbException; long getNextSendTime(Transaction txn, ContactId c) throws DbException;
/**
* Returns the next time (in milliseconds since the Unix epoch) when a
* message is due to be sent to the given contact over a transport with
* the given latency.
* <p>
* The returned value may be zero if a message is due to be sent
* immediately, or Long.MAX_VALUE if no messages are scheduled to be sent.
* <p/>
* Read-only.
*/
long getNextSendTime(Transaction txn, ContactId c, long maxLatency)
throws DbException;
/** /**
* Returns the pending contact with the given ID. * Returns the pending contact with the given ID.
@@ -601,16 +443,6 @@ public interface DatabaseComponent extends TransactionManager {
Collection<TransportKeySet> getTransportKeys(Transaction txn, TransportId t) Collection<TransportKeySet> getTransportKeys(Transaction txn, TransportId t)
throws DbException; throws DbException;
/**
* Returns the contact IDs and transport IDs for which the DB contains
* at least one set of transport keys. Handshake mode and rotation mode
* keys are included, whether activated or not.
* <p/>
* Read-only.
*/
Map<ContactId, Collection<TransportId>> getTransportsWithKeys(
Transaction txn) throws DbException;
/** /**
* Increments the outgoing stream counter for the given transport keys. * Increments the outgoing stream counter for the given transport keys.
*/ */
@@ -703,20 +535,6 @@ public interface DatabaseComponent extends TransactionManager {
void removeTransportKeys(Transaction txn, TransportId t, KeySetId k) void removeTransportKeys(Transaction txn, TransportId t, KeySetId k)
throws DbException; throws DbException;
/**
* Records an ack for the given messages as having been sent to the given
* contact.
*/
void setAckSent(Transaction txn, ContactId c, Collection<MessageId> acked)
throws DbException;
/**
* Sets the cleanup timer duration for the given message. This does not
* start the message's cleanup timer.
*/
void setCleanupTimerDuration(Transaction txn, MessageId m, long duration)
throws DbException;
/** /**
* Marks the given contact as verified. * Marks the given contact as verified.
*/ */
@@ -739,12 +557,6 @@ public interface DatabaseComponent extends TransactionManager {
*/ */
void setMessagePermanent(Transaction txn, MessageId m) throws DbException; void setMessagePermanent(Transaction txn, MessageId m) throws DbException;
/**
* Marks the given message as not shared. This method is only meant for
* testing.
*/
void setMessageNotShared(Transaction txn, MessageId m) throws DbException;
/** /**
* Marks the given message as shared. * Marks the given message as shared.
*/ */
@@ -756,13 +568,6 @@ public interface DatabaseComponent extends TransactionManager {
void setMessageState(Transaction txn, MessageId m, MessageState state) void setMessageState(Transaction txn, MessageId m, MessageState state)
throws DbException; throws DbException;
/**
* Records the given messages as having been sent to the given contact
* over a transport with the given maximum latency.
*/
void setMessagesSent(Transaction txn, ContactId c,
Collection<MessageId> sent, long maxLatency) throws DbException;
/** /**
* Adds dependencies for a message * Adds dependencies for a message
*/ */
@@ -794,22 +599,6 @@ public interface DatabaseComponent extends TransactionManager {
void setTransportKeysActive(Transaction txn, TransportId t, KeySetId k) void setTransportKeysActive(Transaction txn, TransportId t, KeySetId k)
throws DbException; throws DbException;
/**
* Starts the cleanup timer for the given message, if a timer duration
* has been set and the timer has not already been started.
*
* @return The cleanup deadline, or {@link #TIMER_NOT_STARTED} if no
* timer duration has been set for this message or its timer has already
* been started.
*/
long startCleanupTimer(Transaction txn, MessageId m) throws DbException;
/**
* Stops the cleanup timer for the given message, if the timer has been
* started.
*/
void stopCleanupTimer(Transaction txn, MessageId m) 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

@@ -18,10 +18,6 @@ import static java.lang.annotation.RetentionPolicy.RUNTIME;
* submitted, tasks are not run concurrently, and submitting a task will never * submitted, tasks are not run concurrently, and submitting a task will never
* block. Tasks must not run indefinitely. Tasks submitted during shutdown are * block. Tasks must not run indefinitely. Tasks submitted during shutdown are
* discarded. * discarded.
* <p>
* It is not mandatory to use this executor for database tasks. The database
* can be accessed from any thread, but this executor's guarantee that tasks
* are run in the order they're submitted may be useful in some cases.
*/ */
@Qualifier @Qualifier
@Target({FIELD, METHOD, PARAMETER}) @Target({FIELD, METHOD, PARAMETER})

View File

@@ -45,9 +45,6 @@ public class Transaction {
/** /**
* Attaches an event to be broadcast when the transaction has been * Attaches an event to be broadcast when the transaction has been
* committed. The event will be broadcast on the {@link EventExecutor}. * committed. The event will be broadcast on the {@link EventExecutor}.
* Events and {@link #attach(Runnable) tasks} are submitted to the
* {@link EventExecutor} in the order they were attached to the
* transaction.
*/ */
public void attach(Event e) { public void attach(Event e) {
if (actions == null) actions = new ArrayList<>(); if (actions == null) actions = new ArrayList<>();
@@ -57,9 +54,6 @@ public class Transaction {
/** /**
* Attaches a task to be executed when the transaction has been * Attaches a task to be executed when the transaction has been
* committed. The task will be run on the {@link EventExecutor}. * committed. The task will be run on the {@link EventExecutor}.
* {@link #attach(Event) Events} and tasks are submitted to the
* {@link EventExecutor} in the order they were attached to the
* transaction.
*/ */
public void attach(Runnable r) { public void attach(Runnable r) {
if (actions == null) actions = new ArrayList<>(); if (actions == null) actions = new ArrayList<>();

View File

@@ -1,95 +1,51 @@
package org.briarproject.bramble.api.db; package org.briarproject.bramble.api.db;
import org.briarproject.bramble.api.event.EventExecutor;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault; import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import javax.annotation.concurrent.ThreadSafe;
/**
* An interface for managing database transactions.
* <p>
* Read-only transactions may access the database concurrently. Read-write
* transactions access the database exclusively, so starting a read-only or
* read-write transaction will block until there are no read-write
* transactions in progress.
* <p>
* Failing to {@link #endTransaction(Transaction) end} a transaction will
* prevent other callers from accessing the database, so it is recommended to
* use the {@link #transaction(boolean, DbRunnable)},
* {@link #transactionWithResult(boolean, DbCallable)} and
* {@link #transactionWithNullableResult(boolean, NullableDbCallable)} methods
* where possible, which handle committing or aborting the transaction on the
* caller's behalf.
* <p>
* Transactions are not reentrant, i.e. it is not permitted to start a
* transaction on a thread that already has a transaction in progress.
*/
@ThreadSafe
@NotNullByDefault @NotNullByDefault
public interface TransactionManager { public interface TransactionManager {
/** /**
* Starts a new transaction and returns an object representing it. This * Starts a new transaction and returns an object representing it.
* method acquires the database lock, which is held until * <p/>
* {@link #endTransaction(Transaction)} is called. * This method acquires locks, so it must not be called while holding a
* lock.
* *
* @param readOnly True if the transaction will only be used for reading, * @param readOnly true if the transaction will only be used for reading.
* in which case the database lock can be shared with other read-only
* transactions.
*/ */
Transaction startTransaction(boolean readOnly) throws DbException; Transaction startTransaction(boolean readOnly) throws DbException;
/** /**
* Commits a transaction to the database. * Commits a transaction to the database.
* {@link #endTransaction(Transaction)} must be called to release the
* database lock.
*/ */
void commitTransaction(Transaction txn) throws DbException; void commitTransaction(Transaction txn) throws DbException;
/** /**
* Ends a transaction. If the transaction has not been committed by * Ends a transaction. If the transaction has not been committed,
* calling {@link #commitTransaction(Transaction)}, it is aborted and the * it will be aborted. If the transaction has been committed,
* database lock is released. * any events attached to the transaction are broadcast.
* <p> * The database lock will be released in either case.
* If the transaction has been committed, any
* {@link Transaction#attach events} attached to the transaction are
* broadcast and any {@link Transaction#attach(Runnable) tasks} attached
* to the transaction are submitted to the {@link EventExecutor}. The
* database lock is then released.
*/ */
void endTransaction(Transaction txn); void endTransaction(Transaction txn);
/** /**
* Runs the given task within a transaction. The database lock is held * Runs the given task within a transaction.
* while running the task.
*
* @param readOnly True if the transaction will only be used for reading,
* in which case the database lock can be shared with other read-only
* transactions.
*/ */
<E extends Exception> void transaction(boolean readOnly, <E extends Exception> void transaction(boolean readOnly,
DbRunnable<E> task) throws DbException, E; DbRunnable<E> task) throws DbException, E;
/** /**
* Runs the given task within a transaction and returns the result of the * Runs the given task within a transaction and returns the result of the
* task. The database lock is held while running the task. * task.
*
* @param readOnly True if the transaction will only be used for reading,
* in which case the database lock can be shared with other read-only
* transactions.
*/ */
<R, E extends Exception> R transactionWithResult(boolean readOnly, <R, E extends Exception> R transactionWithResult(boolean readOnly,
DbCallable<R, E> task) throws DbException, E; DbCallable<R, E> task) throws DbException, E;
/** /**
* Runs the given task within a transaction and returns the result of the * Runs the given task within a transaction and returns the result of the
* task, which may be null. The database lock is held while running the * task, which may be null.
* task.
*
* @param readOnly True if the transaction will only be used for reading,
* in which case the database lock can be shared with other read-only
* transactions.
*/ */
@Nullable @Nullable
<R, E extends Exception> R transactionWithNullableResult(boolean readOnly, <R, E extends Exception> R transactionWithNullableResult(boolean readOnly,

View File

@@ -57,7 +57,6 @@ public class Author implements Nameable {
/** /**
* Returns the author's name. * Returns the author's name.
*/ */
@Override
public String getName() { public String getName() {
return name; return name;
} }

View File

@@ -21,4 +21,9 @@ public class AuthorId extends UniqueId {
public AuthorId(byte[] id) { public AuthorId(byte[] id) {
super(id); super(id);
} }
@Override
public boolean equals(Object o) {
return o instanceof AuthorId && super.equals(o);
}
} }

View File

@@ -1,8 +1,6 @@
package org.briarproject.briar.api.identity; package org.briarproject.bramble.api.identity;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault; import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import org.briarproject.bramble.api.nullsafety.NullSafety;
import org.briarproject.briar.api.attachment.AttachmentHeader;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import javax.annotation.concurrent.Immutable; import javax.annotation.concurrent.Immutable;
@@ -22,18 +20,14 @@ public class AuthorInfo {
private final Status status; private final Status status;
@Nullable @Nullable
private final String alias; private final String alias;
@Nullable
private final AttachmentHeader avatarHeader;
public AuthorInfo(Status status, @Nullable String alias, public AuthorInfo(Status status, @Nullable String alias) {
@Nullable AttachmentHeader avatarHeader) {
this.status = status; this.status = status;
this.alias = alias; this.alias = alias;
this.avatarHeader = avatarHeader;
} }
public AuthorInfo(Status status) { public AuthorInfo(Status status) {
this(status, null, null); this(status, null);
} }
public Status getStatus() { public Status getStatus() {
@@ -45,11 +39,6 @@ public class AuthorInfo {
return alias; return alias;
} }
@Nullable
public AttachmentHeader getAvatarHeader() {
return avatarHeader;
}
@Override @Override
public int hashCode() { public int hashCode() {
int hashCode = status.ordinal(); int hashCode = status.ordinal();
@@ -62,9 +51,6 @@ public class AuthorInfo {
if (!(o instanceof AuthorInfo)) return false; if (!(o instanceof AuthorInfo)) return false;
AuthorInfo info = (AuthorInfo) o; AuthorInfo info = (AuthorInfo) o;
return status == info.status && return status == info.status &&
// aliases are equal (alias == null ? info.alias == null : alias.equals(info.alias));
NullSafety.equals(alias, info.alias) &&
// avatars are equal
NullSafety.equals(avatarHeader, info.avatarHeader);
} }
} }

View File

@@ -3,7 +3,7 @@ package org.briarproject.bramble.api.keyagreement.event;
import org.briarproject.bramble.api.event.Event; import org.briarproject.bramble.api.event.Event;
/** /**
* An event that is broadcast when a BQP protocol begins. * An event that is broadcast when a BQP protocol completes.
*/ */
public class KeyAgreementStartedEvent extends Event { public class KeyAgreementStartedEvent extends Event {
} }

View File

@@ -5,7 +5,6 @@ import org.briarproject.bramble.api.db.DatabaseComponent;
import org.briarproject.bramble.api.db.DbException; import org.briarproject.bramble.api.db.DbException;
import org.briarproject.bramble.api.db.Transaction; import org.briarproject.bramble.api.db.Transaction;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault; import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import org.briarproject.bramble.api.system.Clock;
import org.briarproject.bramble.api.system.Wakeful; import org.briarproject.bramble.api.system.Wakeful;
import java.util.concurrent.ExecutorService; import java.util.concurrent.ExecutorService;
@@ -23,7 +22,6 @@ public interface LifecycleManager {
*/ */
enum StartResult { enum StartResult {
ALREADY_RUNNING, ALREADY_RUNNING,
CLOCK_ERROR,
DB_ERROR, DB_ERROR,
DATA_TOO_OLD_ERROR, DATA_TOO_OLD_ERROR,
DATA_TOO_NEW_ERROR, DATA_TOO_NEW_ERROR,
@@ -37,14 +35,8 @@ public interface LifecycleManager {
*/ */
enum LifecycleState { enum LifecycleState {
CREATED, STARTING, MIGRATING_DATABASE, COMPACTING_DATABASE, STARTING_SERVICES,
STARTING, RUNNING, STOPPING;
MIGRATING_DATABASE,
COMPACTING_DATABASE,
STARTING_SERVICES,
RUNNING,
STOPPING,
STOPPED;
public boolean isAfter(LifecycleState state) { public boolean isAfter(LifecycleState state) {
return ordinal() > state.ordinal(); return ordinal() > state.ordinal();
@@ -73,10 +65,6 @@ public interface LifecycleManager {
/** /**
* Opens the {@link DatabaseComponent} using the given key and starts any * Opens the {@link DatabaseComponent} using the given key and starts any
* registered {@link Service Services}. * registered {@link Service Services}.
*
* @return {@link StartResult#CLOCK_ERROR} if the system clock is earlier
* than {@link Clock#MIN_REASONABLE_TIME_MS} or later than
* {@link Clock#MAX_REASONABLE_TIME_MS}.
*/ */
@Wakeful @Wakeful
StartResult startServices(SecretKey dbKey); StartResult startServices(SecretKey dbKey);

View File

@@ -1,8 +0,0 @@
package org.briarproject.bramble.api.mailbox;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
@NotNullByDefault
public class InvalidMailboxIdException extends Exception {
}

View File

@@ -1,24 +0,0 @@
package org.briarproject.bramble.api.mailbox;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import javax.annotation.Nullable;
import javax.annotation.concurrent.ThreadSafe;
@ThreadSafe
@NotNullByDefault
public class MailboxAuthToken extends MailboxId {
public MailboxAuthToken(byte[] id) {
super(id);
}
/**
* Creates a {@link MailboxAuthToken} from the given string.
*
* @throws InvalidMailboxIdException if token is not valid.
*/
public static MailboxAuthToken fromString(@Nullable String token)
throws InvalidMailboxIdException {
return new MailboxAuthToken(bytesFromString(token));
}
}

View File

@@ -1,73 +0,0 @@
package org.briarproject.bramble.api.mailbox;
import org.briarproject.bramble.api.plugin.TransportId;
import java.util.List;
import static java.util.Collections.singletonList;
import static java.util.concurrent.TimeUnit.DAYS;
import static java.util.concurrent.TimeUnit.HOURS;
import static org.briarproject.bramble.api.transport.TransportConstants.MAX_FRAME_LENGTH;
import static org.briarproject.bramble.api.transport.TransportConstants.MAX_PAYLOAD_LENGTH;
import static org.briarproject.bramble.api.transport.TransportConstants.STREAM_HEADER_LENGTH;
import static org.briarproject.bramble.api.transport.TransportConstants.TAG_LENGTH;
public interface MailboxConstants {
/**
* The transport ID of the mailbox plugin.
*/
TransportId ID = new TransportId("org.briarproject.bramble.mailbox");
/**
* Mailbox API versions that we support as a client. This is reported to our
* contacts by {@link MailboxUpdateManager}.
*/
List<MailboxVersion> CLIENT_SUPPORTS = singletonList(
new MailboxVersion(1, 0));
/**
* The constant returned by
* {@link MailboxHelper#getHighestCommonMajorVersion(List, List)}
* when the server is too old to support our major version.
*/
int API_SERVER_TOO_OLD = -1;
/**
* The constant returned by
* {@link MailboxHelper#getHighestCommonMajorVersion(List, List)}
* when we as a client are too old to support the server's major version.
*/
int API_CLIENT_TOO_OLD = -2;
/**
* The maximum length of a file that can be uploaded to or downloaded from
* a mailbox.
*/
int MAX_FILE_BYTES = 1024 * 1024;
/**
* The maximum length of the plaintext payload of a file, such that the
* ciphertext is no more than {@link #MAX_FILE_BYTES}.
*/
int MAX_FILE_PAYLOAD_BYTES =
(MAX_FILE_BYTES - TAG_LENGTH - STREAM_HEADER_LENGTH)
/ MAX_FRAME_LENGTH * MAX_PAYLOAD_LENGTH;
/**
* The number of connection failures
* that indicate a problem with the mailbox.
*/
int PROBLEM_NUM_CONNECTION_FAILURES = 5;
/**
* The time in milliseconds since the last connection success
* that need to pass to indicates a problem with the mailbox.
*/
long PROBLEM_MS_SINCE_LAST_SUCCESS = HOURS.toMillis(1);
/**
* The maximum latency of the mailbox transport in milliseconds.
*/
long MAX_LATENCY = DAYS.toMillis(14);
}

View File

@@ -1,22 +0,0 @@
package org.briarproject.bramble.api.mailbox;
import java.io.File;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import javax.inject.Qualifier;
import static java.lang.annotation.ElementType.FIELD;
import static java.lang.annotation.ElementType.METHOD;
import static java.lang.annotation.ElementType.PARAMETER;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
/**
* Annotation for injecting the {@link File directory} where the Mailbox plugin
* should store its state.
*/
@Qualifier
@Target({FIELD, METHOD, PARAMETER})
@Retention(RUNTIME)
public @interface MailboxDirectory {
}

View File

@@ -1,24 +0,0 @@
package org.briarproject.bramble.api.mailbox;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import javax.annotation.Nullable;
import javax.annotation.concurrent.ThreadSafe;
@ThreadSafe
@NotNullByDefault
public class MailboxFileId extends MailboxId {
public MailboxFileId(byte[] id) {
super(id);
}
/**
* Creates a {@link MailboxFileId} from the given string.
*
* @throws IllegalArgumentException if token is not valid.
*/
public static MailboxFileId fromString(@Nullable String token)
throws InvalidMailboxIdException {
return new MailboxFileId(bytesFromString(token));
}
}

View File

@@ -1,24 +0,0 @@
package org.briarproject.bramble.api.mailbox;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import javax.annotation.Nullable;
import javax.annotation.concurrent.ThreadSafe;
@ThreadSafe
@NotNullByDefault
public class MailboxFolderId extends MailboxId {
public MailboxFolderId(byte[] id) {
super(id);
}
/**
* Creates a {@link MailboxFolderId} from the given string.
*
* @throws IllegalArgumentException if token is not valid.
*/
public static MailboxFolderId fromString(@Nullable String token)
throws InvalidMailboxIdException {
return new MailboxFolderId(bytesFromString(token));
}
}

View File

@@ -1,47 +0,0 @@
package org.briarproject.bramble.api.mailbox;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import java.util.List;
import java.util.TreeSet;
import static org.briarproject.bramble.api.mailbox.MailboxConstants.API_CLIENT_TOO_OLD;
import static org.briarproject.bramble.api.mailbox.MailboxConstants.API_SERVER_TOO_OLD;
@NotNullByDefault
public class MailboxHelper {
/**
* Returns the highest major version that both client and server support
* or {@link MailboxConstants#API_SERVER_TOO_OLD} if the server is too old
* or {@link MailboxConstants#API_CLIENT_TOO_OLD} if the client is too old.
*/
public static int getHighestCommonMajorVersion(
List<MailboxVersion> client, List<MailboxVersion> server) {
TreeSet<Integer> clientVersions = new TreeSet<>();
for (MailboxVersion version : client) {
clientVersions.add(version.getMajor());
}
TreeSet<Integer> serverVersions = new TreeSet<>();
for (MailboxVersion version : server) {
serverVersions.add(version.getMajor());
}
for (int clientVersion : clientVersions.descendingSet()) {
if (serverVersions.contains(clientVersion)) return clientVersion;
}
if (clientVersions.last() < serverVersions.last()) {
return API_CLIENT_TOO_OLD;
}
return API_SERVER_TOO_OLD;
}
/**
* Returns true if a client and server with the given API versions can
* communicate with each other (ie, have any major API versions in common).
*/
public static boolean isClientCompatibleWithServer(
List<MailboxVersion> client, List<MailboxVersion> server) {
int common = getHighestCommonMajorVersion(client, server);
return common != API_CLIENT_TOO_OLD && common != API_SERVER_TOO_OLD;
}
}

View File

@@ -1,50 +0,0 @@
package org.briarproject.bramble.api.mailbox;
import com.fasterxml.jackson.annotation.JsonValue;
import org.briarproject.bramble.api.FormatException;
import org.briarproject.bramble.api.UniqueId;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import java.util.Locale;
import javax.annotation.Nullable;
import javax.annotation.concurrent.ThreadSafe;
import static org.briarproject.bramble.util.StringUtils.fromHexString;
import static org.briarproject.bramble.util.StringUtils.toHexString;
@ThreadSafe
@NotNullByDefault
public abstract class MailboxId extends UniqueId {
MailboxId(byte[] id) {
super(id);
}
/**
* Returns valid {@link MailboxId} bytes from the given string.
*
* @throws InvalidMailboxIdException if token is not valid.
*/
static byte[] bytesFromString(@Nullable String token)
throws InvalidMailboxIdException {
if (token == null || token.length() != 64) {
throw new InvalidMailboxIdException();
}
try {
return fromHexString(token);
} catch (FormatException e) {
throw new InvalidMailboxIdException();
}
}
/**
* Returns the string representation expected by the mailbox API.
* Also used for serialization.
*/
@Override
@JsonValue
public String toString() {
return toHexString(getBytes()).toLowerCase(Locale.US);
}
}

View File

@@ -1,56 +0,0 @@
package org.briarproject.bramble.api.mailbox;
import org.briarproject.bramble.api.db.DbException;
import org.briarproject.bramble.api.db.Transaction;
import org.briarproject.bramble.api.lifecycle.IoExecutor;
import org.briarproject.bramble.api.mailbox.event.OwnMailboxConnectionStatusEvent;
import javax.annotation.Nullable;
public interface MailboxManager {
/**
* @return true if a mailbox is already paired.
*/
boolean isPaired(Transaction txn) throws DbException;
/**
* @return the current status of the mailbox.
*/
MailboxStatus getMailboxStatus(Transaction txn) throws DbException;
/**
* Returns the currently running pairing task,
* or null if no pairing task is running.
*/
@Nullable
MailboxPairingTask getCurrentPairingTask();
/**
* Starts and returns a pairing task. If a pairing task is already running,
* it will be returned and the argument will be ignored.
*
* @param qrCodePayload The ISO-8859-1 encoded bytes of the mailbox QR code.
*/
MailboxPairingTask startPairingTask(String qrCodePayload);
/**
* Can be used by the UI to test the mailbox connection.
*
* @return true (success) or false (error).
* A {@link OwnMailboxConnectionStatusEvent} might be broadcast with a new
* {@link MailboxStatus}.
*/
boolean checkConnection();
/**
* Unpairs the owner's mailbox and tries to wipe it.
* As this makes a network call, it should be run on the {@link IoExecutor}.
*
* @return true if we could wipe the mailbox, false if we couldn't.
* It is advised to inform the user to wipe the mailbox themselves,
* if we failed to wipe it.
*/
@IoExecutor
boolean unPair() throws DbException;
}

View File

@@ -1,25 +0,0 @@
package org.briarproject.bramble.api.mailbox;
public abstract class MailboxPairingState {
public static class QrCodeReceived extends MailboxPairingState {
}
public static class Pairing extends MailboxPairingState {
}
public static class Paired extends MailboxPairingState {
}
public static class InvalidQrCode extends MailboxPairingState {
}
public static class MailboxAlreadyPaired extends MailboxPairingState {
}
public static class ConnectionError extends MailboxPairingState {
}
public static class UnexpectedError extends MailboxPairingState {
}
}

View File

@@ -1,21 +0,0 @@
package org.briarproject.bramble.api.mailbox;
import org.briarproject.bramble.api.Consumer;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
@NotNullByDefault
public interface MailboxPairingTask extends Runnable {
/**
* Adds an observer to the task. The observer will be notified on the
* event thread of the current state of the task and any subsequent state
* changes.
*/
void addObserver(Consumer<MailboxPairingState> observer);
/**
* Removes an observer from the task.
*/
void removeObserver(Consumer<MailboxPairingState> observer);
}

View File

@@ -1,98 +0,0 @@
package org.briarproject.bramble.api.mailbox;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import org.briarproject.bramble.api.nullsafety.NullSafety;
import java.util.List;
import javax.annotation.Nullable;
import javax.annotation.concurrent.Immutable;
@Immutable
@NotNullByDefault
public class MailboxProperties {
private final String onion;
private final MailboxAuthToken authToken;
private final boolean owner;
private final List<MailboxVersion> serverSupports;
@Nullable
private final MailboxFolderId inboxId; // Null for own mailbox
@Nullable
private final MailboxFolderId outboxId; // Null for own mailbox
/**
* Constructor for properties used by the mailbox's owner.
*/
public MailboxProperties(String onion, MailboxAuthToken authToken,
List<MailboxVersion> serverSupports) {
this.onion = onion;
this.authToken = authToken;
this.owner = true;
this.serverSupports = serverSupports;
this.inboxId = null;
this.outboxId = null;
}
/**
* Constructor for properties used by a contact of the mailbox's owner.
*/
public MailboxProperties(String onion, MailboxAuthToken authToken,
List<MailboxVersion> serverSupports, MailboxFolderId inboxId,
MailboxFolderId outboxId) {
this.onion = onion;
this.authToken = authToken;
this.owner = false;
this.serverSupports = serverSupports;
this.inboxId = inboxId;
this.outboxId = outboxId;
}
/**
* Returns the onion address of the mailbox, excluding the .onion suffix.
*/
public String getOnion() {
return onion;
}
public MailboxAuthToken getAuthToken() {
return authToken;
}
public boolean isOwner() {
return owner;
}
public List<MailboxVersion> getServerSupports() {
return serverSupports;
}
@Nullable
public MailboxFolderId getInboxId() {
return inboxId;
}
@Nullable
public MailboxFolderId getOutboxId() {
return outboxId;
}
@Override
public boolean equals(Object o) {
if (o instanceof MailboxProperties) {
MailboxProperties m = (MailboxProperties) o;
return owner == m.owner &&
onion.equals(m.onion) &&
authToken.equals(m.authToken) &&
NullSafety.equals(inboxId, m.inboxId) &&
NullSafety.equals(outboxId, m.outboxId) &&
serverSupports.equals(m.serverSupports);
}
return false;
}
@Override
public int hashCode() {
return authToken.hashCode();
}
}

View File

@@ -1,73 +0,0 @@
package org.briarproject.bramble.api.mailbox;
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.Transaction;
import org.briarproject.bramble.api.lifecycle.LifecycleManager;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import java.util.List;
import javax.annotation.Nullable;
@NotNullByDefault
public interface MailboxSettingsManager {
/**
* Registers a hook to be called when a mailbox has been paired or unpaired.
* This method should be called before
* {@link LifecycleManager#startServices(SecretKey)}.
*/
void registerMailboxHook(MailboxHook hook);
@Nullable
MailboxProperties getOwnMailboxProperties(Transaction txn)
throws DbException;
void setOwnMailboxProperties(Transaction txn, MailboxProperties p)
throws DbException;
void removeOwnMailboxProperties(Transaction txn) throws DbException;
MailboxStatus getOwnMailboxStatus(Transaction txn) throws DbException;
void recordSuccessfulConnection(Transaction txn, long now,
List<MailboxVersion> versions) throws DbException;
void recordFailedConnectionAttempt(Transaction txn, long now)
throws DbException;
void setPendingUpload(Transaction txn, ContactId id,
@Nullable String filename) throws DbException;
@Nullable
String getPendingUpload(Transaction txn, ContactId id) throws DbException;
interface MailboxHook {
/**
* Called when Briar is paired with a mailbox.
*
* @param txn A read-write transaction
*/
void mailboxPaired(Transaction txn, MailboxProperties p)
throws DbException;
/**
* Called when the mailbox is unpaired.
*
* @param txn A read-write transaction
*/
void mailboxUnpaired(Transaction txn) throws DbException;
/**
* Called when we receive our mailbox's server-supported API versions.
* This happens whenever we successfully check the connectivity of
* our mailbox, so this hook may be called frequently.
*
* @param txn A read-write transaction
*/
void serverSupportedVersionsReceived(Transaction txn,
List<MailboxVersion> serverSupports) throws DbException;
}
}

View File

@@ -1,93 +0,0 @@
package org.briarproject.bramble.api.mailbox;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import java.util.List;
import javax.annotation.concurrent.Immutable;
import static org.briarproject.bramble.api.mailbox.MailboxConstants.CLIENT_SUPPORTS;
import static org.briarproject.bramble.api.mailbox.MailboxConstants.PROBLEM_MS_SINCE_LAST_SUCCESS;
import static org.briarproject.bramble.api.mailbox.MailboxConstants.PROBLEM_NUM_CONNECTION_FAILURES;
import static org.briarproject.bramble.api.mailbox.MailboxHelper.getHighestCommonMajorVersion;
@Immutable
@NotNullByDefault
public class MailboxStatus {
private final long lastAttempt, lastSuccess;
private final int attemptsSinceSuccess;
private final List<MailboxVersion> serverSupports;
public MailboxStatus(long lastAttempt, long lastSuccess,
int attemptsSinceSuccess,
List<MailboxVersion> serverSupports) {
this.lastAttempt = lastAttempt;
this.lastSuccess = lastSuccess;
this.attemptsSinceSuccess = attemptsSinceSuccess;
this.serverSupports = serverSupports;
}
/**
* Returns the time of the last attempt to connect to the mailbox, in
* milliseconds since the Unix epoch, or -1 if no attempt has been made.
* <p>
* If an attempt is in progress and has not yet succeeded or failed then
* this method returns the time of the previous attempt, or -1 if the
* current attempt is the first.
*/
public long getTimeOfLastAttempt() {
return lastAttempt;
}
/**
* Returns the time of the last successful attempt to connect to the
* mailbox, in milliseconds since the Unix epoch, or -1 if no attempt has
* succeeded.
* <p>
* If the last attempt was successful then this method returns the same
* value as {@link #getTimeOfLastAttempt()}. If an attempt is in progress
* and has not yet succeeded or failed then this method returns the time
* of the previous successful connection, or -1 if no attempt has
* succeeded.
*/
public long getTimeOfLastSuccess() {
return lastSuccess;
}
/**
* Returns the number of attempts to connect to the mailbox that have
* failed since the last attempt succeeded, or the number of attempts that
* have been made, if no attempt has ever succeeded.
* <p>
* If an attempt is in progress and has not yet succeeded or failed then
* it is not included in this count.
*/
public int getAttemptsSinceSuccess() {
return attemptsSinceSuccess;
}
/**
* Returns the mailbox's supported API versions.
*/
public List<MailboxVersion> getServerSupports() {
return serverSupports;
}
/**
* @return true if this status indicates a problem with the mailbox.
*/
public boolean hasProblem(long now) {
return attemptsSinceSuccess >= PROBLEM_NUM_CONNECTION_FAILURES &&
(now - lastSuccess) >= PROBLEM_MS_SINCE_LAST_SUCCESS;
}
/**
* @return a positive integer if the mailbox is compatible. Same result as
* {@link MailboxHelper#getHighestCommonMajorVersion(List, List)}.
*/
public int getMailboxCompatibility() {
return getHighestCommonMajorVersion(CLIENT_SUPPORTS, serverSupports);
}
}

View File

@@ -1,31 +0,0 @@
package org.briarproject.bramble.api.mailbox;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import java.util.List;
import javax.annotation.concurrent.Immutable;
@Immutable
@NotNullByDefault
public class MailboxUpdate {
private final boolean hasMailbox;
private final List<MailboxVersion> clientSupports;
public MailboxUpdate(List<MailboxVersion> clientSupports) {
this(clientSupports, false);
}
MailboxUpdate(List<MailboxVersion> clientSupports, boolean hasMailbox) {
this.clientSupports = clientSupports;
this.hasMailbox = hasMailbox;
}
public List<MailboxVersion> getClientSupports() {
return clientSupports;
}
public boolean hasMailbox() {
return hasMailbox;
}
}

View File

@@ -1,111 +0,0 @@
package org.briarproject.bramble.api.mailbox;
import org.briarproject.bramble.api.contact.ContactId;
import org.briarproject.bramble.api.db.DbException;
import org.briarproject.bramble.api.db.Transaction;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import org.briarproject.bramble.api.sync.ClientId;
import javax.annotation.Nullable;
@NotNullByDefault
public interface MailboxUpdateManager {
/**
* The unique ID of the mailbox update (properties) client.
*/
ClientId CLIENT_ID =
new ClientId("org.briarproject.bramble.mailbox.properties");
/**
* The current major version of the mailbox update (properties) client.
*/
int MAJOR_VERSION = 2;
/**
* The current minor version of the mailbox update (properties) client.
*/
int MINOR_VERSION = 0;
/**
* The number of properties required for an update message with a mailbox.
* <p>
* The required properties are {@link #PROP_KEY_ONION},
* {@link #PROP_KEY_AUTHTOKEN}, {@link #PROP_KEY_INBOXID} and
* {@link #PROP_KEY_OUTBOXID}.
*/
int PROP_COUNT = 4;
/**
* The onion address of the mailbox, excluding the .onion suffix.
*/
String PROP_KEY_ONION = "onion";
/**
* A bearer token for accessing the mailbox (64 hex digits).
*/
String PROP_KEY_AUTHTOKEN = "authToken";
/**
* A folder ID for downloading messages (64 hex digits).
*/
String PROP_KEY_INBOXID = "inboxId";
/**
* A folder ID for uploading messages (64 hex digits).
*/
String PROP_KEY_OUTBOXID = "outboxId";
/**
* Length of the {@link #PROP_KEY_ONION} property.
*/
int PROP_ONION_LENGTH = 56;
/**
* Message metadata key for the version number of a local or remote update,
* as a BDF long.
*/
String MSG_KEY_VERSION = "version";
/**
* Message metadata key for whether an update is local or remote, as a BDF
* boolean.
*/
String MSG_KEY_LOCAL = "local";
/**
* Key in the client's local group for storing the clientSupports list that
* was last sent out.
*/
String GROUP_KEY_SENT_CLIENT_SUPPORTS = "sentClientSupports";
/**
* Key in the client's local group for storing the serverSupports list that
* was last sent out, if any.
*/
String GROUP_KEY_SENT_SERVER_SUPPORTS = "sentServerSupports";
/**
* Returns the latest {@link MailboxUpdate} sent to the given contact.
* <p>
* If we have our own mailbox then the update will be a
* {@link MailboxUpdateWithMailbox} containing the
* {@link MailboxProperties} the contact should use for communicating with
* our mailbox.
*/
MailboxUpdate getLocalUpdate(Transaction txn, ContactId c)
throws DbException;
/**
* Returns the latest {@link MailboxUpdate} received from the given
* contact, or null if no update has been received.
* <p>
* If the contact has a mailbox then the update will be a
* {@link MailboxUpdateWithMailbox} containing the
* {@link MailboxProperties} we should use for communicating with the
* contact's mailbox.
*/
@Nullable
MailboxUpdate getRemoteUpdate(Transaction txn, ContactId c)
throws DbException;
}

View File

@@ -1,30 +0,0 @@
package org.briarproject.bramble.api.mailbox;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import java.util.List;
import javax.annotation.concurrent.Immutable;
@Immutable
@NotNullByDefault
public class MailboxUpdateWithMailbox extends MailboxUpdate {
private final MailboxProperties properties;
public MailboxUpdateWithMailbox(List<MailboxVersion> clientSupports,
MailboxProperties properties) {
super(clientSupports, true);
if (properties.isOwner()) throw new IllegalArgumentException();
this.properties = properties;
}
public MailboxUpdateWithMailbox(MailboxUpdateWithMailbox o,
List<MailboxVersion> newClientSupports) {
this(newClientSupports, o.getMailboxProperties());
}
public MailboxProperties getMailboxProperties() {
return properties;
}
}

View File

@@ -1,44 +0,0 @@
package org.briarproject.bramble.api.mailbox;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import javax.annotation.concurrent.Immutable;
@Immutable
@NotNullByDefault
public class MailboxVersion implements Comparable<MailboxVersion> {
private final int major;
private final int minor;
public MailboxVersion(int major, int minor) {
this.major = major;
this.minor = minor;
}
public int getMajor() {
return major;
}
public int getMinor() {
return minor;
}
@Override
public boolean equals(Object o) {
if (o instanceof MailboxVersion) {
MailboxVersion v = (MailboxVersion) o;
return major == v.major && minor == v.minor;
}
return false;
}
@Override
public int compareTo(MailboxVersion v) {
int c = major - v.major;
if (c != 0) {
return c;
}
return minor - v.minor;
}
}

View File

@@ -1,36 +0,0 @@
package org.briarproject.bramble.api.mailbox.event;
import org.briarproject.bramble.api.contact.ContactId;
import org.briarproject.bramble.api.event.Event;
import org.briarproject.bramble.api.mailbox.MailboxProperties;
import org.briarproject.bramble.api.mailbox.MailboxUpdateWithMailbox;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import java.util.Map;
import javax.annotation.concurrent.Immutable;
/**
* An event that is broadcast when a mailbox is paired.
*/
@Immutable
@NotNullByDefault
public class MailboxPairedEvent extends Event {
private final MailboxProperties properties;
private final Map<ContactId, MailboxUpdateWithMailbox> localUpdates;
public MailboxPairedEvent(MailboxProperties properties,
Map<ContactId, MailboxUpdateWithMailbox> localUpdates) {
this.properties = properties;
this.localUpdates = localUpdates;
}
public MailboxProperties getProperties() {
return properties;
}
public Map<ContactId, MailboxUpdateWithMailbox> getLocalUpdates() {
return localUpdates;
}
}

View File

@@ -1,19 +0,0 @@
package org.briarproject.bramble.api.mailbox.event;
import org.briarproject.bramble.api.event.Event;
import org.briarproject.bramble.api.mailbox.MailboxSettingsManager;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import javax.annotation.concurrent.Immutable;
/**
* An event that is broadcast by {@link MailboxSettingsManager} when
* recording a connection failure for own Mailbox
* that has persistent for long enough for the mailbox owner to become active
* and fix the problem with the mailbox.
*/
@Immutable
@NotNullByDefault
public class MailboxProblemEvent extends Event {
}

View File

@@ -1,28 +0,0 @@
package org.briarproject.bramble.api.mailbox.event;
import org.briarproject.bramble.api.contact.ContactId;
import org.briarproject.bramble.api.event.Event;
import org.briarproject.bramble.api.mailbox.MailboxUpdate;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import java.util.Map;
import javax.annotation.concurrent.Immutable;
/**
* An event that is broadcast when a mailbox is unpaired.
*/
@Immutable
@NotNullByDefault
public class MailboxUnpairedEvent extends Event {
private final Map<ContactId, MailboxUpdate> localUpdates;
public MailboxUnpairedEvent(Map<ContactId, MailboxUpdate> localUpdates) {
this.localUpdates = localUpdates;
}
public Map<ContactId, MailboxUpdate> getLocalUpdates() {
return localUpdates;
}
}

View File

@@ -1,40 +0,0 @@
package org.briarproject.bramble.api.mailbox.event;
import org.briarproject.bramble.api.contact.ContactId;
import org.briarproject.bramble.api.event.Event;
import org.briarproject.bramble.api.mailbox.MailboxUpdate;
import org.briarproject.bramble.api.mailbox.MailboxUpdateManager;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import javax.annotation.concurrent.Immutable;
/**
* An event that is broadcast when the first mailbox update is sent to a
* newly added contact, which happens in the same transaction in which the
* contact is added.
* <p>
* This event is not broadcast when the first mailbox update is sent to an
* existing contact when setting up the
* {@link MailboxUpdateManager mailbox update client}.
*/
@Immutable
@NotNullByDefault
public class MailboxUpdateSentToNewContactEvent extends Event {
private final ContactId contactId;
private final MailboxUpdate mailboxUpdate;
public MailboxUpdateSentToNewContactEvent(ContactId contactId,
MailboxUpdate mailboxUpdate) {
this.contactId = contactId;
this.mailboxUpdate = mailboxUpdate;
}
public ContactId getContactId() {
return contactId;
}
public MailboxUpdate getMailboxUpdate() {
return mailboxUpdate;
}
}

View File

@@ -1,27 +0,0 @@
package org.briarproject.bramble.api.mailbox.event;
import org.briarproject.bramble.api.event.Event;
import org.briarproject.bramble.api.mailbox.MailboxSettingsManager;
import org.briarproject.bramble.api.mailbox.MailboxStatus;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import javax.annotation.concurrent.Immutable;
/**
* An event that is broadcast by {@link MailboxSettingsManager} when
* recording the connection status of own Mailbox.
*/
@Immutable
@NotNullByDefault
public class OwnMailboxConnectionStatusEvent extends Event {
private final MailboxStatus status;
public OwnMailboxConnectionStatusEvent(MailboxStatus status) {
this.status = status;
}
public MailboxStatus getStatus() {
return status;
}
}

View File

@@ -1,34 +0,0 @@
package org.briarproject.bramble.api.mailbox.event;
import org.briarproject.bramble.api.contact.ContactId;
import org.briarproject.bramble.api.event.Event;
import org.briarproject.bramble.api.mailbox.MailboxUpdate;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import javax.annotation.concurrent.Immutable;
/**
* An event that is broadcast when {@link MailboxUpdate} are received
* from a contact.
*/
@Immutable
@NotNullByDefault
public class RemoteMailboxUpdateEvent extends Event {
private final ContactId contactId;
private final MailboxUpdate mailboxUpdate;
public RemoteMailboxUpdateEvent(ContactId contactId,
MailboxUpdate mailboxUpdate) {
this.contactId = contactId;
this.mailboxUpdate = mailboxUpdate;
}
public ContactId getContact() {
return contactId;
}
public MailboxUpdate getMailboxUpdate() {
return mailboxUpdate;
}
}

View File

@@ -8,12 +8,11 @@ import javax.annotation.concurrent.Immutable;
@NotNullByDefault @NotNullByDefault
public class NetworkStatus { public class NetworkStatus {
private final boolean connected, wifi, ipv6Only; private final boolean connected, wifi;
public NetworkStatus(boolean connected, boolean wifi, boolean ipv6Only) { public NetworkStatus(boolean connected, boolean wifi) {
this.connected = connected; this.connected = connected;
this.wifi = wifi; this.wifi = wifi;
this.ipv6Only = ipv6Only;
} }
public boolean isConnected() { public boolean isConnected() {
@@ -23,8 +22,4 @@ public class NetworkStatus {
public boolean isWifi() { public boolean isWifi() {
return wifi; return wifi;
} }
public boolean isIpv6Only() {
return ipv6Only;
}
} }

View File

@@ -29,12 +29,4 @@ public class NullSafety {
public static void requireNull(@Nullable Object o) { public static void requireNull(@Nullable Object o) {
if (o != null) throw new AssertionError(); if (o != null) throw new AssertionError();
} }
/**
* Stand-in for {@code Objects.equals()}.
*/
public static boolean equals(@Nullable Object a, @Nullable Object b) {
return (a == b) || (a != null && a.equals(b));
}
} }

View File

@@ -1,4 +1,4 @@
package org.briarproject.bramble.api.plugin.file; package org.briarproject.bramble.api.plugin;
public interface FileConstants { public interface FileConstants {

View File

@@ -61,7 +61,7 @@ public interface Plugin {
/** /**
* Returns the transport's maximum latency in milliseconds. * Returns the transport's maximum latency in milliseconds.
*/ */
long getMaxLatency(); int getMaxLatency();
/** /**
* Returns the transport's maximum idle time in milliseconds. * Returns the transport's maximum idle time in milliseconds.

View File

@@ -1,25 +0,0 @@
package org.briarproject.bramble.api.plugin;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import javax.annotation.Nullable;
@NotNullByDefault
public interface PluginFactory<P extends Plugin> {
/**
* Returns the plugin's transport identifier.
*/
TransportId getId();
/**
* Returns the maximum latency of the transport in milliseconds.
*/
long getMaxLatency();
/**
* Creates and returns a plugin, or null if no plugin can be created.
*/
@Nullable
P createPlugin(PluginCallback callback);
}

Some files were not shown because too many files have changed in this diff Show More