Compare commits

..

6 Commits

Author SHA1 Message Date
Torsten Grote
2d5f5d4419 WIP: FakeTestData proof-of-concept 2018-09-19 10:51:47 -03:00
Torsten Grote
8393513871 Remove code from TestDataCreator that breaks encapsulation 2018-09-19 10:50:09 -03:00
Torsten Grote
38270fbee8 Throw AssertionError when creating an account while a database key is in memory 2018-09-18 17:53:41 -03:00
Torsten Grote
65c0646812 Refactor tests so that all test data is created in the first test 2018-09-18 17:41:40 -03:00
Torsten Grote
0416583e8c Split up UI and Screenshot tests
Closes #1377
2018-09-18 17:41:40 -03:00
Torsten Grote
91f8c801b8 Create Screenshot of Conversation for Manual 2018-09-18 17:41:40 -03:00
1350 changed files with 20336 additions and 52163 deletions

View File

@@ -1,11 +1,6 @@
image: briar/ci-image-android:latest
stages:
- test
- check_reproducibility
test:
stage: test
before_script:
- set -e
- export GRADLE_USER_HOME=$PWD/.gradle
@@ -17,7 +12,7 @@ test:
script:
- ./gradlew --no-daemon -Djava.security.egd=file:/dev/urandom animalSnifferMain animalSnifferTest
- ./gradlew --no-daemon -Djava.security.egd=file:/dev/urandom check compileOfficialDebugAndroidTestSources compileScreenshotDebugAndroidTestSources
- ./gradlew --no-daemon -Djava.security.egd=file:/dev/urandom test
after_script:
# these file change every time but should not be cached
@@ -26,7 +21,6 @@ test:
test_reproducible:
stage: check_reproducibility
script:
- "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:

View File

@@ -1,10 +1,16 @@
<component name="ProjectCodeStyleConfiguration">
<code_scheme name="Project" version="173">
<option name="RIGHT_MARGIN" value="100" />
<AndroidXmlCodeStyleSettings>
<option name="ARRANGEMENT_SETTINGS_MIGRATED_TO_191" value="true" />
<option name="USE_CUSTOM_SETTINGS" value="true" />
</AndroidXmlCodeStyleSettings>
<JavaCodeStyleSettings>
<option name="ANNOTATION_PARAMETER_WRAP" value="1" />
<option name="CLASS_COUNT_TO_USE_IMPORT_ON_DEMAND" value="99" />
<option name="NAMES_COUNT_TO_USE_IMPORT_ON_DEMAND" value="99" />
<option name="PACKAGES_TO_USE_IMPORT_ON_DEMAND">
<value />
</option>
<option name="IMPORT_LAYOUT_TABLE">
<value>
<package name="android" withSubpackages="true" static="false" />
@@ -30,9 +36,31 @@
<option name="JD_ALIGN_PARAM_COMMENTS" value="false" />
<option name="JD_ALIGN_EXCEPTION_COMMENTS" value="false" />
</JavaCodeStyleSettings>
<JetCodeStyleSettings>
<option name="CODE_STYLE_DEFAULTS" value="KOTLIN_OFFICIAL" />
</JetCodeStyleSettings>
<Objective-C-extensions>
<file>
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Import" />
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Macro" />
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Typedef" />
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Enum" />
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Constant" />
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Global" />
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Struct" />
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="FunctionPredecl" />
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Function" />
</file>
<class>
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Property" />
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Synthesize" />
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="InitMethod" />
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="StaticMethod" />
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="InstanceMethod" />
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="DeallocMethod" />
</class>
<extensions>
<pair source="cpp" header="h" fileNamingConvention="NONE" />
<pair source="c" header="h" fileNamingConvention="NONE" />
</extensions>
</Objective-C-extensions>
<XML>
<option name="XML_LEGACY_SETTINGS_IMPORTED" value="true" />
</XML>
@@ -71,6 +99,7 @@
</indentOptions>
</codeStyleSettings>
<codeStyleSettings language="XML">
<option name="FORCE_REARRANGE_MODE" value="1" />
<indentOptions>
<option name="CONTINUATION_INDENT_SIZE" value="4" />
<option name="USE_TAB_CHARACTER" value="true" />
@@ -83,8 +112,7 @@
<match>
<AND>
<NAME>xmlns:android</NAME>
<XML_ATTRIBUTE />
<XML_NAMESPACE>^$</XML_NAMESPACE>
<XML_NAMESPACE>Namespace:</XML_NAMESPACE>
</AND>
</match>
</rule>
@@ -94,8 +122,7 @@
<match>
<AND>
<NAME>xmlns:.*</NAME>
<XML_ATTRIBUTE />
<XML_NAMESPACE>^$</XML_NAMESPACE>
<XML_NAMESPACE>Namespace:</XML_NAMESPACE>
</AND>
</match>
<order>BY_NAME</order>
@@ -106,7 +133,6 @@
<match>
<AND>
<NAME>.*:id</NAME>
<XML_ATTRIBUTE />
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
</AND>
</match>
@@ -117,7 +143,6 @@
<match>
<AND>
<NAME>.*:name</NAME>
<XML_ATTRIBUTE />
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
</AND>
</match>
@@ -128,7 +153,6 @@
<match>
<AND>
<NAME>name</NAME>
<XML_ATTRIBUTE />
<XML_NAMESPACE>^$</XML_NAMESPACE>
</AND>
</match>
@@ -139,7 +163,6 @@
<match>
<AND>
<NAME>style</NAME>
<XML_ATTRIBUTE />
<XML_NAMESPACE>^$</XML_NAMESPACE>
</AND>
</match>
@@ -150,7 +173,6 @@
<match>
<AND>
<NAME>.*</NAME>
<XML_ATTRIBUTE />
<XML_NAMESPACE>^$</XML_NAMESPACE>
</AND>
</match>
@@ -161,12 +183,64 @@
<rule>
<match>
<AND>
<NAME>.*</NAME>
<XML_ATTRIBUTE />
<NAME>.*:layout_width</NAME>
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
</AND>
</match>
<order>ANDROID_ATTRIBUTE_ORDER</order>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>.*:layout_height</NAME>
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
</AND>
</match>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>.*:layout_.*</NAME>
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
</AND>
</match>
<order>BY_NAME</order>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>.*:width</NAME>
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
</AND>
</match>
<order>BY_NAME</order>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>.*:height</NAME>
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
</AND>
</match>
<order>BY_NAME</order>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>.*</NAME>
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
</AND>
</match>
<order>BY_NAME</order>
</rule>
</section>
<section>
@@ -174,7 +248,6 @@
<match>
<AND>
<NAME>.*</NAME>
<XML_ATTRIBUTE />
<XML_NAMESPACE>.*</XML_NAMESPACE>
</AND>
</match>
@@ -184,11 +257,5 @@
</rules>
</arrangement>
</codeStyleSettings>
<codeStyleSettings language="kotlin">
<option name="CODE_STYLE_DEFAULTS" value="KOTLIN_OFFICIAL" />
<option name="PARAMETER_ANNOTATION_WRAP" value="1" />
<option name="VARIABLE_ANNOTATION_WRAP" value="1" />
<option name="ENUM_CONSTANTS_WRAP" value="1" />
</codeStyleSettings>
</code_scheme>
</component>

View File

@@ -1,20 +1,29 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="All tests" type="AndroidJUnit" factoryName="Android JUnit">
<extension name="coverage" enabled="false" merge="false" sample_coverage="true" runner="idea" />
<module name="briar-android" />
<option name="ALTERNATIVE_JRE_PATH_ENABLED" value="false" />
<option name="ALTERNATIVE_JRE_PATH" />
<option name="PACKAGE_NAME" value="" />
<option name="MAIN_CLASS_NAME" value="" />
<option name="METHOD_NAME" value="" />
<option name="TEST_OBJECT" value="package" />
<option name="VM_PARAMETERS" value="-ea" />
<option name="PARAMETERS" value="" />
<option name="WORKING_DIRECTORY" value="$PROJECT_DIR$/briar-android" />
<method v="2">
<option name="Android.Gradle.BeforeRunTask" enabled="true" />
<option name="WORKING_DIRECTORY" value="file://$PROJECT_DIR$/briar-android" />
<option name="ENV_VARIABLES" />
<option name="PASS_PARENT_ENVS" value="true" />
<option name="TEST_SEARCH_SCOPE">
<value defaultName="singleModule" />
</option>
<envs />
<patterns />
<method>
<option name="RunConfigurationTask" enabled="true" run_configuration_name="All tests in bramble-api" run_configuration_type="AndroidJUnit" />
<option name="RunConfigurationTask" enabled="true" run_configuration_name="All tests in bramble-core" run_configuration_type="AndroidJUnit" />
<option name="RunConfigurationTask" enabled="true" run_configuration_name="All tests in bramble-android" run_configuration_type="AndroidJUnit" />
<option name="RunConfigurationTask" enabled="true" run_configuration_name="All tests in bramble-java" run_configuration_type="AndroidJUnit" />
<option name="RunConfigurationTask" enabled="true" run_configuration_name="All tests in briar-core" run_configuration_type="AndroidJUnit" />
<option name="RunConfigurationTask" enabled="true" run_configuration_name="All tests in briar-headless" run_configuration_type="AndroidJUnit" />
</method>
</configuration>
</component>
</component>

View File

@@ -1,5 +1,6 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="All tests in bramble-android" type="AndroidJUnit" factoryName="Android JUnit">
<extension name="coverage" enabled="false" merge="false" sample_coverage="true" runner="idea" />
<module name="bramble-android" />
<option name="ALTERNATIVE_JRE_PATH_ENABLED" value="false" />
<option name="ALTERNATIVE_JRE_PATH" />
@@ -10,10 +11,12 @@
<option name="VM_PARAMETERS" value="-ea" />
<option name="PARAMETERS" value="" />
<option name="WORKING_DIRECTORY" value="file://$PROJECT_DIR$/bramble-android" />
<option name="ENV_VARIABLES" />
<option name="PASS_PARENT_ENVS" value="true" />
<option name="TEST_SEARCH_SCOPE">
<value defaultName="singleModule" />
</option>
<envs />
<patterns />
<method />
</configuration>

View File

@@ -1,5 +1,6 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="All tests in bramble-api" type="AndroidJUnit" factoryName="Android JUnit">
<extension name="coverage" enabled="false" merge="false" sample_coverage="true" runner="idea" />
<module name="bramble-api" />
<option name="ALTERNATIVE_JRE_PATH_ENABLED" value="false" />
<option name="ALTERNATIVE_JRE_PATH" />
@@ -10,10 +11,12 @@
<option name="VM_PARAMETERS" value="-ea" />
<option name="PARAMETERS" value="" />
<option name="WORKING_DIRECTORY" value="file://$PROJECT_DIR$/bramble-api" />
<option name="ENV_VARIABLES" />
<option name="PASS_PARENT_ENVS" value="true" />
<option name="TEST_SEARCH_SCOPE">
<value defaultName="singleModule" />
</option>
<envs />
<patterns />
<method />
</configuration>

View File

@@ -1,5 +1,6 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="All tests in bramble-core" type="AndroidJUnit" factoryName="Android JUnit">
<extension name="coverage" enabled="false" merge="false" sample_coverage="true" runner="idea" />
<module name="bramble-core" />
<option name="ALTERNATIVE_JRE_PATH_ENABLED" value="false" />
<option name="ALTERNATIVE_JRE_PATH" />
@@ -10,10 +11,12 @@
<option name="VM_PARAMETERS" value="-ea" />
<option name="PARAMETERS" value="" />
<option name="WORKING_DIRECTORY" value="file://$PROJECT_DIR$/bramble-core" />
<option name="ENV_VARIABLES" />
<option name="PASS_PARENT_ENVS" value="true" />
<option name="TEST_SEARCH_SCOPE">
<value defaultName="singleModule" />
</option>
<envs />
<patterns />
<method />
</configuration>

View File

@@ -1,5 +1,6 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="All tests in bramble-java" type="AndroidJUnit" factoryName="Android JUnit">
<extension name="coverage" enabled="false" merge="false" sample_coverage="true" runner="idea" />
<module name="bramble-java" />
<option name="ALTERNATIVE_JRE_PATH_ENABLED" value="false" />
<option name="ALTERNATIVE_JRE_PATH" />
@@ -10,10 +11,12 @@
<option name="VM_PARAMETERS" value="-ea -Djava.library.path=libs" />
<option name="PARAMETERS" value="" />
<option name="WORKING_DIRECTORY" value="file://$PROJECT_DIR$/bramble-java" />
<option name="ENV_VARIABLES" />
<option name="PASS_PARENT_ENVS" value="true" />
<option name="TEST_SEARCH_SCOPE">
<value defaultName="singleModule" />
</option>
<envs />
<patterns />
<method />
</configuration>

View File

@@ -1,5 +1,6 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="All tests in briar-android" type="AndroidJUnit" factoryName="Android JUnit">
<extension name="coverage" enabled="false" merge="false" sample_coverage="true" runner="idea" />
<module name="briar-android" />
<option name="ALTERNATIVE_JRE_PATH_ENABLED" value="false" />
<option name="ALTERNATIVE_JRE_PATH" />
@@ -10,10 +11,12 @@
<option name="VM_PARAMETERS" value="-ea" />
<option name="PARAMETERS" value="" />
<option name="WORKING_DIRECTORY" value="file://$PROJECT_DIR$/briar-android" />
<option name="ENV_VARIABLES" />
<option name="PASS_PARENT_ENVS" value="true" />
<option name="TEST_SEARCH_SCOPE">
<value defaultName="singleModule" />
</option>
<envs />
<patterns />
<method />
</configuration>

View File

@@ -1,5 +1,6 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="All tests in briar-core" type="AndroidJUnit" factoryName="Android JUnit">
<extension name="coverage" enabled="false" merge="false" sample_coverage="true" runner="idea" />
<module name="briar-core" />
<option name="ALTERNATIVE_JRE_PATH_ENABLED" value="false" />
<option name="ALTERNATIVE_JRE_PATH" />
@@ -10,10 +11,12 @@
<option name="VM_PARAMETERS" value="-ea" />
<option name="PARAMETERS" value="" />
<option name="WORKING_DIRECTORY" value="file://$PROJECT_DIR$/briar-core" />
<option name="ENV_VARIABLES" />
<option name="PASS_PARENT_ENVS" value="true" />
<option name="TEST_SEARCH_SCOPE">
<value defaultName="singleModule" />
</option>
<envs />
<patterns />
<method />
</configuration>

View File

@@ -1,15 +0,0 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="All tests in briar-headless" type="AndroidJUnit" factoryName="Android JUnit">
<module name="briar-headless" />
<option name="PACKAGE_NAME" value="org.briarproject.briar.headless" />
<option name="MAIN_CLASS_NAME" value="" />
<option name="METHOD_NAME" value="" />
<option name="TEST_OBJECT" value="package" />
<option name="VM_PARAMETERS" />
<option name="PARAMETERS" value="" />
<option name="WORKING_DIRECTORY" value="$PROJECT_DIR$/briar-headless" />
<method v="2">
<option name="Android.Gradle.BeforeRunTask" enabled="true" />
</method>
</configuration>
</component>

View File

@@ -1,5 +1,6 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="H2 Performance Test" type="AndroidJUnit" factoryName="Android JUnit">
<extension name="coverage" enabled="false" merge="false" sample_coverage="true" runner="idea" />
<module name="bramble-core" />
<option name="ALTERNATIVE_JRE_PATH_ENABLED" value="false" />
<option name="ALTERNATIVE_JRE_PATH" />
@@ -10,10 +11,12 @@
<option name="VM_PARAMETERS" value="-ea" />
<option name="PARAMETERS" value="" />
<option name="WORKING_DIRECTORY" value="" />
<option name="ENV_VARIABLES" />
<option name="PASS_PARENT_ENVS" value="true" />
<option name="TEST_SEARCH_SCOPE">
<value defaultName="singleModule" />
</option>
<envs />
<patterns />
<method />
</configuration>

View File

@@ -1,5 +1,6 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="HyperSQL Performance Test" type="AndroidJUnit" factoryName="Android JUnit">
<extension name="coverage" enabled="false" merge="false" sample_coverage="true" runner="idea" />
<module name="bramble-core" />
<option name="ALTERNATIVE_JRE_PATH_ENABLED" value="false" />
<option name="ALTERNATIVE_JRE_PATH" />
@@ -10,10 +11,12 @@
<option name="VM_PARAMETERS" value="-ea" />
<option name="PARAMETERS" value="" />
<option name="WORKING_DIRECTORY" value="" />
<option name="ENV_VARIABLES" />
<option name="PASS_PARENT_ENVS" value="true" />
<option name="TEST_SEARCH_SCOPE">
<value defaultName="singleModule" />
</option>
<envs />
<patterns />
<method />
</configuration>

View File

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

View File

@@ -1,35 +1,25 @@
import com.android.build.gradle.tasks.MergeResources
apply plugin: 'com.android.library'
apply plugin: 'witness'
apply from: 'witness.gradle'
android {
compileSdkVersion 29
buildToolsVersion '29.0.2'
compileSdkVersion 27
buildToolsVersion '27.0.3'
defaultConfig {
minSdkVersion 16
targetSdkVersion 28
versionCode 10205
versionName "1.2.5"
minSdkVersion 14
targetSdkVersion 26
versionCode 10101
versionName "1.1.1"
consumerProguardFiles 'proguard-rules.txt'
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
lintOptions {
// FIXME
warning "LintError"
warning "InvalidPackage"
warning "MissingPermission"
warning "InlinedApi", "ObsoleteSdkInt", "Override", "NewApi", "UnusedAttribute"
}
}
configurations {
@@ -38,10 +28,9 @@ configurations {
dependencies {
implementation project(path: ':bramble-core', configuration: 'default')
tor 'org.briarproject:tor-android:0.3.5.9@zip'
tor 'org.briarproject:obfs4proxy-android:0.0.11-2@zip'
tor 'org.briarproject:tor-android:0.2.9.16@zip'
annotationProcessor 'com.google.dagger:dagger-compiler:2.24'
annotationProcessor 'com.google.dagger:dagger-compiler:2.0.2'
compileOnly 'javax.annotation:jsr250-api:1.0'
@@ -50,31 +39,13 @@ dependencies {
testImplementation "org.jmock:jmock:2.8.2"
testImplementation "org.jmock:jmock-junit4:2.8.2"
testImplementation "org.jmock:jmock-legacy:2.8.2"
testImplementation "org.hamcrest:hamcrest-library:1.3"
testImplementation "org.hamcrest:hamcrest-core:1.3"
}
def torBinariesDir = 'src/main/res/raw'
task cleanTorBinaries {
doLast {
delete fileTree(torBinariesDir) { include '*.zip' }
project.afterEvaluate {
copy {
from configurations.tor.collect { zipTree(it) }
into 'src/main/res/raw'
}
}
clean.dependsOn cleanTorBinaries
task unpackTorBinaries {
doLast {
copy {
from configurations.tor.collect { zipTree(it) }
into torBinariesDir
// TODO: Remove after next Tor upgrade, which won't include non-PIE binaries
include 'geoip.zip', '*_pie.zip'
}
}
dependsOn cleanTorBinaries
}
tasks.withType(MergeResources) {
inputs.dir torBinariesDir
dependsOn unpackTorBinaries
}

View File

@@ -1,24 +0,0 @@
package org.briarproject.bramble;
import org.briarproject.bramble.battery.AndroidBatteryModule;
import org.briarproject.bramble.network.AndroidNetworkModule;
import org.briarproject.bramble.reporting.ReportingModule;
public interface BrambleAndroidEagerSingletons {
void inject(AndroidBatteryModule.EagerSingletons init);
void inject(AndroidNetworkModule.EagerSingletons init);
void inject(ReportingModule.EagerSingletons init);
class Helper {
public static void injectEagerSingletons(
BrambleAndroidEagerSingletons c) {
c.inject(new AndroidBatteryModule.EagerSingletons());
c.inject(new AndroidNetworkModule.EagerSingletons());
c.inject(new ReportingModule.EagerSingletons());
}
}
}

View File

@@ -1,21 +1,16 @@
package org.briarproject.bramble;
import org.briarproject.bramble.battery.AndroidBatteryModule;
import org.briarproject.bramble.network.AndroidNetworkModule;
import org.briarproject.bramble.plugin.tor.CircumventionModule;
import org.briarproject.bramble.reporting.ReportingModule;
import org.briarproject.bramble.socks.SocksModule;
import org.briarproject.bramble.system.AndroidSystemModule;
import dagger.Module;
@Module(includes = {
AndroidBatteryModule.class,
AndroidNetworkModule.class,
AndroidSystemModule.class,
CircumventionModule.class,
ReportingModule.class,
SocksModule.class
CircumventionModule.class
})
public class BrambleAndroidModule {
}

View File

@@ -9,27 +9,22 @@ import org.briarproject.bramble.api.account.AccountManager;
import org.briarproject.bramble.api.crypto.CryptoComponent;
import org.briarproject.bramble.api.db.DatabaseConfig;
import org.briarproject.bramble.api.identity.IdentityManager;
import org.briarproject.bramble.util.IoUtils;
import java.io.File;
import java.util.HashSet;
import java.util.Set;
import java.util.logging.Logger;
import javax.annotation.Nullable;
import javax.annotation.concurrent.GuardedBy;
import javax.inject.Inject;
import static android.os.Build.VERSION.SDK_INT;
import static java.util.logging.Level.INFO;
import static org.briarproject.bramble.util.IoUtils.deleteFileOrDir;
import static org.briarproject.bramble.util.LogUtils.logFileOrDir;
class AndroidAccountManager extends AccountManagerImpl
implements AccountManager {
private static final Logger LOG =
Logger.getLogger(AndroidAccountManager.class.getName());
private static final String PREF_DB_KEY = "key";
protected final Context appContext;
private final SharedPreferences prefs;
@@ -42,30 +37,42 @@ class AndroidAccountManager extends AccountManagerImpl
appContext = app.getApplicationContext();
}
// Locking: stateChangeLock
@Override
public boolean accountExists() {
boolean exists = super.accountExists();
if (!exists && LOG.isLoggable(INFO)) {
LOG.info("Account does not exist. Contents of account directory:");
logFileOrDir(LOG, INFO, getDataDir());
@Nullable
protected String loadEncryptedDatabaseKey() {
String key = getDatabaseKeyFromPreferences();
if (key == null) key = super.loadEncryptedDatabaseKey();
else migrateDatabaseKeyToFile(key);
return key;
}
// Locking: stateChangeLock
@Nullable
private String getDatabaseKeyFromPreferences() {
String key = prefs.getString(PREF_DB_KEY, null);
if (key == null) LOG.info("No database key in preferences");
else LOG.info("Found database key in preferences");
return key;
}
// Locking: stateChangeLock
private void migrateDatabaseKeyToFile(String key) {
if (storeEncryptedDatabaseKey(key)) {
if (prefs.edit().remove(PREF_DB_KEY).commit())
LOG.info("Database key migrated to file");
else LOG.warning("Database key not removed from preferences");
} else {
LOG.warning("Database key not migrated to file");
}
return exists;
}
@Override
public void deleteAccount() {
synchronized (stateChangeLock) {
if (LOG.isLoggable(INFO)) {
LOG.info("Contents of account directory before deleting:");
logFileOrDir(LOG, INFO, getDataDir());
}
super.deleteAccount();
SharedPreferences defaultPrefs = getDefaultSharedPreferences();
deleteAppData(prefs, defaultPrefs);
if (LOG.isLoggable(INFO)) {
LOG.info("Contents of account directory after deleting:");
logFileOrDir(LOG, INFO, getDataDir());
}
}
}
@@ -74,7 +81,7 @@ class AndroidAccountManager extends AccountManagerImpl
return PreferenceManager.getDefaultSharedPreferences(appContext);
}
@GuardedBy("stateChangeLock")
// Locking: stateChangeLock
private void deleteAppData(SharedPreferences... clear) {
// Clear and commit shared preferences
for (SharedPreferences prefs : clear) {
@@ -82,46 +89,20 @@ class AndroidAccountManager extends AccountManagerImpl
LOG.warning("Could not clear shared preferences");
}
// Delete files, except lib and shared_prefs directories
Set<File> files = new HashSet<>();
File dataDir = getDataDir();
@Nullable
File[] fileArray = dataDir.listFiles();
if (fileArray == null) {
File dataDir = new File(appContext.getApplicationInfo().dataDir);
File[] children = dataDir.listFiles();
if (children == null) {
LOG.warning("Could not list files in app data dir");
} else {
for (File file : fileArray) {
String name = file.getName();
for (File child : children) {
String name = child.getName();
if (!name.equals("lib") && !name.equals("shared_prefs")) {
files.add(file);
IoUtils.deleteFileOrDir(child);
}
}
}
files.add(appContext.getFilesDir());
files.add(appContext.getCacheDir());
addIfNotNull(files, appContext.getExternalCacheDir());
if (SDK_INT >= 19) {
for (File file : appContext.getExternalCacheDirs()) {
addIfNotNull(files, file);
}
}
if (SDK_INT >= 21) {
for (File file : appContext.getExternalMediaDirs()) {
addIfNotNull(files, file);
}
}
for (File file : files) {
deleteFileOrDir(file);
}
// Recreate the cache dir as some OpenGL drivers expect it to exist
if (!new File(dataDir, "cache").mkdirs())
if (!new File(dataDir, "cache").mkdir())
LOG.warning("Could not recreate cache dir");
}
private File getDataDir() {
return new File(appContext.getApplicationInfo().dataDir);
}
private void addIfNotNull(Set<File> files, @Nullable File file) {
if (file != null) files.add(file);
}
}

View File

@@ -1,81 +0,0 @@
package org.briarproject.bramble.battery;
import android.app.Application;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import org.briarproject.bramble.api.battery.BatteryManager;
import org.briarproject.bramble.api.battery.event.BatteryEvent;
import org.briarproject.bramble.api.event.EventBus;
import org.briarproject.bramble.api.lifecycle.Service;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.logging.Logger;
import javax.inject.Inject;
import static android.content.Intent.ACTION_BATTERY_CHANGED;
import static android.content.Intent.ACTION_POWER_CONNECTED;
import static android.content.Intent.ACTION_POWER_DISCONNECTED;
import static android.os.BatteryManager.EXTRA_PLUGGED;
import static java.util.logging.Level.INFO;
import static java.util.logging.Logger.getLogger;
class AndroidBatteryManager implements BatteryManager, Service {
private static final Logger LOG =
getLogger(AndroidBatteryManager.class.getName());
private final Context appContext;
private final EventBus eventBus;
private final AtomicBoolean used = new AtomicBoolean(false);
private volatile BroadcastReceiver batteryReceiver = null;
@Inject
AndroidBatteryManager(Application app, EventBus eventBus) {
this.appContext = app.getApplicationContext();
this.eventBus = eventBus;
}
@Override
public boolean isCharging() {
// Get the sticky intent for ACTION_BATTERY_CHANGED
IntentFilter filter = new IntentFilter(ACTION_BATTERY_CHANGED);
Intent i = appContext.registerReceiver(null, filter);
if (i == null) return false;
int status = i.getIntExtra(EXTRA_PLUGGED, 0);
return status != 0;
}
@Override
public void startService() {
if (used.getAndSet(true)) throw new IllegalStateException();
batteryReceiver = new BatteryReceiver();
IntentFilter filter = new IntentFilter();
filter.addAction(ACTION_POWER_CONNECTED);
filter.addAction(ACTION_POWER_DISCONNECTED);
appContext.registerReceiver(batteryReceiver, filter);
}
@Override
public void stopService() {
if (batteryReceiver != null)
appContext.unregisterReceiver(batteryReceiver);
}
private class BatteryReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context ctx, Intent i) {
String action = i.getAction();
if (LOG.isLoggable(INFO)) LOG.info("Received broadcast " + action);
if (ACTION_POWER_CONNECTED.equals(action))
eventBus.broadcast(new BatteryEvent(true));
else if (ACTION_POWER_DISCONNECTED.equals(action))
eventBus.broadcast(new BatteryEvent(false));
}
}
}

View File

@@ -1,27 +0,0 @@
package org.briarproject.bramble.battery;
import org.briarproject.bramble.api.battery.BatteryManager;
import org.briarproject.bramble.api.lifecycle.LifecycleManager;
import javax.inject.Inject;
import javax.inject.Singleton;
import dagger.Module;
import dagger.Provides;
@Module
public class AndroidBatteryModule {
public static class EagerSingletons {
@Inject
BatteryManager batteryManager;
}
@Provides
@Singleton
BatteryManager provideBatteryManager(LifecycleManager lifecycleManager,
AndroidBatteryManager batteryManager) {
lifecycleManager.registerService(batteryManager);
return batteryManager;
}
}

View File

@@ -3,7 +3,6 @@ package org.briarproject.bramble.network;
import org.briarproject.bramble.api.lifecycle.LifecycleManager;
import org.briarproject.bramble.api.network.NetworkManager;
import javax.inject.Inject;
import javax.inject.Singleton;
import dagger.Module;
@@ -12,11 +11,6 @@ import dagger.Provides;
@Module
public class AndroidNetworkModule {
public static class EagerSingletons {
@Inject
NetworkManager networkManager;
}
@Provides
@Singleton
NetworkManager provideNetworkManager(LifecycleManager lifecycleManager,

View File

@@ -12,31 +12,22 @@ import android.content.IntentFilter;
import org.briarproject.bramble.api.nullsafety.MethodsNotNullByDefault;
import org.briarproject.bramble.api.nullsafety.ParametersNotNullByDefault;
import org.briarproject.bramble.api.plugin.Backoff;
import org.briarproject.bramble.api.plugin.PluginCallback;
import org.briarproject.bramble.api.plugin.PluginException;
import org.briarproject.bramble.api.plugin.duplex.DuplexPluginCallback;
import org.briarproject.bramble.api.plugin.duplex.DuplexTransportConnection;
import org.briarproject.bramble.api.system.AndroidExecutor;
import org.briarproject.bramble.api.system.Clock;
import org.briarproject.bramble.util.AndroidUtils;
import org.briarproject.bramble.util.IoUtils;
import java.io.Closeable;
import java.io.IOException;
import java.security.SecureRandom;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.UUID;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Executor;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.logging.Logger;
import javax.annotation.Nullable;
import static android.bluetooth.BluetoothAdapter.ACTION_DISCOVERY_FINISHED;
import static android.bluetooth.BluetoothAdapter.ACTION_DISCOVERY_STARTED;
import static android.bluetooth.BluetoothAdapter.ACTION_SCAN_MODE_CHANGED;
import static android.bluetooth.BluetoothAdapter.ACTION_STATE_CHANGED;
import static android.bluetooth.BluetoothAdapter.EXTRA_SCAN_MODE;
@@ -46,26 +37,18 @@ import static android.bluetooth.BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERA
import static android.bluetooth.BluetoothAdapter.SCAN_MODE_NONE;
import static android.bluetooth.BluetoothAdapter.STATE_OFF;
import static android.bluetooth.BluetoothAdapter.STATE_ON;
import static android.bluetooth.BluetoothDevice.ACTION_FOUND;
import static android.bluetooth.BluetoothDevice.EXTRA_DEVICE;
import static java.util.concurrent.TimeUnit.MILLISECONDS;
import static java.util.logging.Level.INFO;
import static java.util.logging.Level.WARNING;
import static java.util.logging.Logger.getLogger;
import static org.briarproject.bramble.util.PrivacyUtils.scrubMacAddress;
import static org.briarproject.bramble.util.LogUtils.logException;
@MethodsNotNullByDefault
@ParametersNotNullByDefault
class AndroidBluetoothPlugin extends BluetoothPlugin<BluetoothServerSocket> {
private static final Logger LOG =
getLogger(AndroidBluetoothPlugin.class.getName());
private static final int MAX_DISCOVERY_MS = 10_000;
Logger.getLogger(AndroidBluetoothPlugin.class.getName());
private final AndroidExecutor androidExecutor;
private final Context appContext;
private final Clock clock;
private volatile boolean wasEnabledByUs = false;
private volatile BluetoothStateReceiver receiver = null;
@@ -75,13 +58,12 @@ class AndroidBluetoothPlugin extends BluetoothPlugin<BluetoothServerSocket> {
AndroidBluetoothPlugin(BluetoothConnectionLimiter connectionLimiter,
Executor ioExecutor, AndroidExecutor androidExecutor,
Context appContext, SecureRandom secureRandom, Clock clock,
Backoff backoff, PluginCallback callback, int maxLatency) {
Context appContext, SecureRandom secureRandom, Backoff backoff,
DuplexPluginCallback callback, int maxLatency) {
super(connectionLimiter, ioExecutor, secureRandom, backoff, callback,
maxLatency);
this.androidExecutor = androidExecutor;
this.appContext = appContext;
this.clock = clock;
}
@Override
@@ -161,7 +143,11 @@ class AndroidBluetoothPlugin extends BluetoothPlugin<BluetoothServerSocket> {
@Override
void tryToClose(@Nullable BluetoothServerSocket ss) {
IoUtils.tryToClose(ss, LOG, WARNING);
try {
if (ss != null) ss.close();
} catch (IOException e) {
logException(LOG, WARNING, e);
}
}
@Override
@@ -191,77 +177,17 @@ class AndroidBluetoothPlugin extends BluetoothPlugin<BluetoothServerSocket> {
s.connect();
return wrapSocket(s);
} catch (IOException e) {
IoUtils.tryToClose(s, LOG, WARNING);
tryToClose(s);
throw e;
}
}
@Override
@Nullable
DuplexTransportConnection discoverAndConnect(String uuid) {
if (adapter == null) return null;
for (String address : discoverDevices()) {
try {
if (LOG.isLoggable(INFO))
LOG.info("Connecting to " + scrubMacAddress(address));
return connectTo(address, uuid);
} catch (IOException e) {
if (LOG.isLoggable(INFO)) {
LOG.info("Could not connect to "
+ scrubMacAddress(address));
}
}
}
LOG.info("Could not connect to any devices");
return null;
}
private Collection<String> discoverDevices() {
List<String> addresses = new ArrayList<>();
BlockingQueue<Intent> intents = new LinkedBlockingQueue<>();
DiscoveryReceiver receiver = new DiscoveryReceiver(intents);
IntentFilter filter = new IntentFilter();
filter.addAction(ACTION_DISCOVERY_STARTED);
filter.addAction(ACTION_DISCOVERY_FINISHED);
filter.addAction(ACTION_FOUND);
appContext.registerReceiver(receiver, filter);
private void tryToClose(@Nullable Closeable c) {
try {
if (adapter.startDiscovery()) {
long now = clock.currentTimeMillis();
long end = now + MAX_DISCOVERY_MS;
while (now < end) {
Intent i = intents.poll(end - now, MILLISECONDS);
if (i == null) break;
String action = i.getAction();
if (ACTION_DISCOVERY_STARTED.equals(action)) {
LOG.info("Discovery started");
} else if (ACTION_DISCOVERY_FINISHED.equals(action)) {
LOG.info("Discovery finished");
break;
} else if (ACTION_FOUND.equals(action)) {
BluetoothDevice d = i.getParcelableExtra(EXTRA_DEVICE);
String address = d.getAddress();
if (LOG.isLoggable(INFO))
LOG.info("Discovered " + scrubMacAddress(address));
if (!addresses.contains(address))
addresses.add(address);
}
now = clock.currentTimeMillis();
}
} else {
LOG.info("Could not start discovery");
}
} catch (InterruptedException e) {
LOG.info("Interrupted while discovering devices");
Thread.currentThread().interrupt();
} finally {
LOG.info("Cancelling discovery");
adapter.cancelDiscovery();
appContext.unregisterReceiver(receiver);
if (c != null) c.close();
} catch (IOException e) {
logException(LOG, WARNING, e);
}
// Shuffle the addresses so we don't always try the same one first
Collections.shuffle(addresses);
return addresses;
}
private class BluetoothStateReceiver extends BroadcastReceiver {
@@ -281,18 +207,4 @@ class AndroidBluetoothPlugin extends BluetoothPlugin<BluetoothServerSocket> {
}
}
}
private static class DiscoveryReceiver extends BroadcastReceiver {
private final BlockingQueue<Intent> intents;
private DiscoveryReceiver(BlockingQueue<Intent> intents) {
this.intents = intents;
}
@Override
public void onReceive(Context ctx, Intent intent) {
intents.add(intent);
}
}
}

View File

@@ -6,12 +6,11 @@ import org.briarproject.bramble.api.event.EventBus;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import org.briarproject.bramble.api.plugin.Backoff;
import org.briarproject.bramble.api.plugin.BackoffFactory;
import org.briarproject.bramble.api.plugin.PluginCallback;
import org.briarproject.bramble.api.plugin.TransportId;
import org.briarproject.bramble.api.plugin.duplex.DuplexPlugin;
import org.briarproject.bramble.api.plugin.duplex.DuplexPluginCallback;
import org.briarproject.bramble.api.plugin.duplex.DuplexPluginFactory;
import org.briarproject.bramble.api.system.AndroidExecutor;
import org.briarproject.bramble.api.system.Clock;
import java.security.SecureRandom;
import java.util.concurrent.Executor;
@@ -34,19 +33,17 @@ public class AndroidBluetoothPluginFactory implements DuplexPluginFactory {
private final Context appContext;
private final SecureRandom secureRandom;
private final EventBus eventBus;
private final Clock clock;
private final BackoffFactory backoffFactory;
public AndroidBluetoothPluginFactory(Executor ioExecutor,
AndroidExecutor androidExecutor, Context appContext,
SecureRandom secureRandom, EventBus eventBus, Clock clock,
SecureRandom secureRandom, EventBus eventBus,
BackoffFactory backoffFactory) {
this.ioExecutor = ioExecutor;
this.androidExecutor = androidExecutor;
this.appContext = appContext;
this.secureRandom = secureRandom;
this.eventBus = eventBus;
this.clock = clock;
this.backoffFactory = backoffFactory;
}
@@ -61,14 +58,14 @@ public class AndroidBluetoothPluginFactory implements DuplexPluginFactory {
}
@Override
public DuplexPlugin createPlugin(PluginCallback callback) {
public DuplexPlugin createPlugin(DuplexPluginCallback callback) {
BluetoothConnectionLimiter connectionLimiter =
new BluetoothConnectionLimiterImpl();
Backoff backoff = backoffFactory.createBackoff(MIN_POLLING_INTERVAL,
MAX_POLLING_INTERVAL, BACKOFF_BASE);
AndroidBluetoothPlugin plugin = new AndroidBluetoothPlugin(
connectionLimiter, ioExecutor, androidExecutor, appContext,
secureRandom, clock, backoff, callback, MAX_LATENCY);
secureRandom, backoff, callback, MAX_LATENCY);
eventBus.addListener(plugin);
return plugin;
}

View File

@@ -13,7 +13,7 @@ import org.briarproject.bramble.api.event.EventListener;
import org.briarproject.bramble.api.network.event.NetworkStatusEvent;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import org.briarproject.bramble.api.plugin.Backoff;
import org.briarproject.bramble.api.plugin.PluginCallback;
import org.briarproject.bramble.api.plugin.duplex.DuplexPluginCallback;
import java.io.IOException;
import java.net.InetAddress;
@@ -32,18 +32,17 @@ import static android.net.ConnectivityManager.TYPE_WIFI;
import static android.os.Build.VERSION.SDK_INT;
import static java.util.Collections.emptyList;
import static java.util.Collections.singletonList;
import static java.util.logging.Logger.getLogger;
@NotNullByDefault
class AndroidLanTcpPlugin extends LanTcpPlugin implements EventListener {
private static final Logger LOG =
getLogger(AndroidLanTcpPlugin.class.getName());
private static final byte[] WIFI_AP_ADDRESS_BYTES =
{(byte) 192, (byte) 168, 43, 1};
private static final InetAddress WIFI_AP_ADDRESS;
private static final Logger LOG =
Logger.getLogger(AndroidLanTcpPlugin.class.getName());
static {
try {
WIFI_AP_ADDRESS = InetAddress.getByAddress(WIFI_AP_ADDRESS_BYTES);
@@ -61,7 +60,7 @@ class AndroidLanTcpPlugin extends LanTcpPlugin implements EventListener {
private volatile SocketFactory socketFactory;
AndroidLanTcpPlugin(Executor ioExecutor, Context appContext,
Backoff backoff, PluginCallback callback, int maxLatency,
Backoff backoff, DuplexPluginCallback callback, int maxLatency,
int maxIdleTime) {
super(ioExecutor, backoff, callback, maxLatency, maxIdleTime);
// Don't execute more than one connection status check at a time

View File

@@ -6,9 +6,9 @@ import org.briarproject.bramble.api.event.EventBus;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import org.briarproject.bramble.api.plugin.Backoff;
import org.briarproject.bramble.api.plugin.BackoffFactory;
import org.briarproject.bramble.api.plugin.PluginCallback;
import org.briarproject.bramble.api.plugin.TransportId;
import org.briarproject.bramble.api.plugin.duplex.DuplexPlugin;
import org.briarproject.bramble.api.plugin.duplex.DuplexPluginCallback;
import org.briarproject.bramble.api.plugin.duplex.DuplexPluginFactory;
import java.util.concurrent.Executor;
@@ -51,7 +51,7 @@ public class AndroidLanTcpPluginFactory implements DuplexPluginFactory {
}
@Override
public DuplexPlugin createPlugin(PluginCallback callback) {
public DuplexPlugin createPlugin(DuplexPluginCallback callback) {
Backoff backoff = backoffFactory.createBackoff(MIN_POLLING_INTERVAL,
MAX_POLLING_INTERVAL, BACKOFF_BASE);
AndroidLanTcpPlugin plugin = new AndroidLanTcpPlugin(ioExecutor,

View File

@@ -6,12 +6,11 @@ import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.os.PowerManager;
import org.briarproject.bramble.api.battery.BatteryManager;
import org.briarproject.bramble.api.network.NetworkManager;
import org.briarproject.bramble.api.nullsafety.MethodsNotNullByDefault;
import org.briarproject.bramble.api.nullsafety.ParametersNotNullByDefault;
import org.briarproject.bramble.api.plugin.Backoff;
import org.briarproject.bramble.api.plugin.PluginCallback;
import org.briarproject.bramble.api.plugin.duplex.DuplexPluginCallback;
import org.briarproject.bramble.api.system.Clock;
import org.briarproject.bramble.api.system.LocationUtils;
import org.briarproject.bramble.api.system.ResourceProvider;
@@ -32,6 +31,9 @@ import static java.util.concurrent.TimeUnit.MINUTES;
@ParametersNotNullByDefault
class AndroidTorPlugin extends TorPlugin {
// This tag may prevent Huawei's power manager from killing us
private static final String WAKE_LOCK_TAG = "LocationManagerService";
private final Context appContext;
private final RenewableWakeLock wakeLock;
@@ -39,21 +41,19 @@ class AndroidTorPlugin extends TorPlugin {
Context appContext, NetworkManager networkManager,
LocationUtils locationUtils, SocketFactory torSocketFactory,
Clock clock, ResourceProvider resourceProvider,
CircumventionProvider circumventionProvider,
BatteryManager batteryManager, Backoff backoff,
TorRendezvousCrypto torRendezvousCrypto,
PluginCallback callback, String architecture, int maxLatency,
CircumventionProvider circumventionProvider, Backoff backoff,
DuplexPluginCallback callback, String architecture, int maxLatency,
int maxIdleTime) {
super(ioExecutor, networkManager, locationUtils, torSocketFactory,
clock, resourceProvider, circumventionProvider, batteryManager,
backoff, torRendezvousCrypto, callback, architecture, maxLatency, maxIdleTime,
clock, resourceProvider, circumventionProvider, backoff,
callback, architecture, maxLatency, maxIdleTime,
appContext.getDir("tor", MODE_PRIVATE));
this.appContext = appContext;
PowerManager pm = (PowerManager)
appContext.getSystemService(POWER_SERVICE);
if (pm == null) throw new AssertionError();
assert pm != null;
wakeLock = new RenewableWakeLock(pm, scheduler, PARTIAL_WAKE_LOCK,
getWakeLockTag(), 1, MINUTES);
WAKE_LOCK_TAG, 1, MINUTES);
}
@Override
@@ -85,17 +85,4 @@ class AndroidTorPlugin extends TorPlugin {
super.stop();
wakeLock.release();
}
private String getWakeLockTag() {
PackageManager pm = appContext.getPackageManager();
for (PackageInfo info : pm.getInstalledPackages(0)) {
String name = info.packageName.toLowerCase();
if (name.startsWith("com.huawei.powergenie")) {
return "LocationManagerService";
} else if (name.startsWith("com.evenwell.powermonitor")) {
return "AudioIn";
}
}
return getClass().getSimpleName();
}
}

View File

@@ -1,17 +1,17 @@
package org.briarproject.bramble.plugin.tor;
import android.content.Context;
import android.os.Build;
import org.briarproject.bramble.api.battery.BatteryManager;
import org.briarproject.bramble.api.event.EventBus;
import org.briarproject.bramble.api.network.NetworkManager;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import org.briarproject.bramble.api.plugin.Backoff;
import org.briarproject.bramble.api.plugin.BackoffFactory;
import org.briarproject.bramble.api.plugin.PluginCallback;
import org.briarproject.bramble.api.plugin.TorConstants;
import org.briarproject.bramble.api.plugin.TransportId;
import org.briarproject.bramble.api.plugin.duplex.DuplexPlugin;
import org.briarproject.bramble.api.plugin.duplex.DuplexPluginCallback;
import org.briarproject.bramble.api.plugin.duplex.DuplexPluginFactory;
import org.briarproject.bramble.api.system.Clock;
import org.briarproject.bramble.api.system.LocationUtils;
@@ -48,7 +48,6 @@ public class AndroidTorPluginFactory implements DuplexPluginFactory {
private final BackoffFactory backoffFactory;
private final ResourceProvider resourceProvider;
private final CircumventionProvider circumventionProvider;
private final BatteryManager batteryManager;
private final Clock clock;
public AndroidTorPluginFactory(Executor ioExecutor,
@@ -56,8 +55,7 @@ public class AndroidTorPluginFactory implements DuplexPluginFactory {
NetworkManager networkManager, LocationUtils locationUtils,
EventBus eventBus, SocketFactory torSocketFactory,
BackoffFactory backoffFactory, ResourceProvider resourceProvider,
CircumventionProvider circumventionProvider,
BatteryManager batteryManager, Clock clock) {
CircumventionProvider circumventionProvider, Clock clock) {
this.ioExecutor = ioExecutor;
this.scheduler = scheduler;
this.appContext = appContext;
@@ -68,7 +66,6 @@ public class AndroidTorPluginFactory implements DuplexPluginFactory {
this.backoffFactory = backoffFactory;
this.resourceProvider = resourceProvider;
this.circumventionProvider = circumventionProvider;
this.batteryManager = batteryManager;
this.clock = clock;
}
@@ -83,20 +80,14 @@ public class AndroidTorPluginFactory implements DuplexPluginFactory {
}
@Override
public DuplexPlugin createPlugin(PluginCallback callback) {
public DuplexPlugin createPlugin(DuplexPluginCallback 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")) {
if (abi.startsWith("x86")) {
architecture = "x86";
break;
} else if (abi.startsWith("arm64")) {
architecture = "arm64";
break;
} else if (abi.startsWith("armeabi")) {
architecture = "arm";
break;
@@ -106,17 +97,15 @@ public class AndroidTorPluginFactory implements DuplexPluginFactory {
LOG.info("Tor is not supported on this architecture");
return null;
}
// Use position-independent executable
architecture += "_pie";
// Use position-independent executable for SDK >= 16
if (Build.VERSION.SDK_INT >= 16) architecture += "_pie";
Backoff backoff = backoffFactory.createBackoff(MIN_POLLING_INTERVAL,
MAX_POLLING_INTERVAL, BACKOFF_BASE);
TorRendezvousCrypto torRendezvousCrypto = new TorRendezvousCryptoImpl();
AndroidTorPlugin plugin = new AndroidTorPlugin(ioExecutor, scheduler,
appContext, networkManager, locationUtils, torSocketFactory,
clock, resourceProvider, circumventionProvider, batteryManager,
backoff, torRendezvousCrypto, callback, architecture,
MAX_LATENCY, MAX_IDLE_TIME);
clock, resourceProvider, circumventionProvider, backoff,
callback, architecture, MAX_LATENCY, MAX_IDLE_TIME);
eventBus.addListener(plugin);
return plugin;
}

View File

@@ -1,6 +1,5 @@
package org.briarproject.bramble.system;
import android.annotation.SuppressLint;
import android.app.Application;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
@@ -23,12 +22,11 @@ import javax.annotation.concurrent.Immutable;
import javax.inject.Inject;
import static android.content.Context.WIFI_SERVICE;
import static android.os.Build.VERSION.SDK_INT;
import static android.provider.Settings.Secure.ANDROID_ID;
@Immutable
@NotNullByDefault
class AndroidSecureRandomProvider extends UnixSecureRandomProvider {
class AndroidSecureRandomProvider extends LinuxSecureRandomProvider {
private static final int SEED_LENGTH = 32;
@@ -39,7 +37,6 @@ class AndroidSecureRandomProvider extends UnixSecureRandomProvider {
appContext = app.getApplicationContext();
}
@SuppressLint("HardwareIds")
@Override
protected void writeToEntropyPool(DataOutputStream out) throws IOException {
super.writeToEntropyPool(out);
@@ -52,14 +49,12 @@ class AndroidSecureRandomProvider extends UnixSecureRandomProvider {
String id = Settings.Secure.getString(contentResolver, ANDROID_ID);
if (id != null) out.writeUTF(id);
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);
}
WifiManager wm =
(WifiManager) appContext.getSystemService(WIFI_SERVICE);
List<WifiConfiguration> configs = wm.getConfiguredNetworks();
if (configs != null) {
for (WifiConfiguration config : configs)
parcel.writeParcelable(config, 0);
}
BluetoothAdapter bt = BluetoothAdapter.getDefaultAdapter();
if (bt != null) {
@@ -75,19 +70,20 @@ class AndroidSecureRandomProvider extends UnixSecureRandomProvider {
// Silence strict mode
StrictMode.ThreadPolicy tp = StrictMode.allowThreadDiskWrites();
super.writeSeed();
if (SDK_INT <= 18) applyOpenSslFix();
if (Build.VERSION.SDK_INT >= 16 && Build.VERSION.SDK_INT <= 18)
applyOpenSslFix();
StrictMode.setThreadPolicy(tp);
}
// Based on https://android-developers.googleblog.com/2013/08/some-securerandom-thoughts.html
private void applyOpenSslFix() {
byte[] seed = new UnixSecureRandomSpi().engineGenerateSeed(
byte[] seed = new LinuxSecureRandomSpi().engineGenerateSeed(
SEED_LENGTH);
try {
// Seed the OpenSSL PRNG
Class.forName("org.apache.harmony.xnet.provider.jsse.NativeCrypto")
.getMethod("RAND_seed", byte[].class)
.invoke(null, (Object) seed);
.invoke(null, seed);
// Mix the output of the Linux PRNG into the OpenSSL PRNG
int bytesRead = (Integer) Class.forName(
"org.apache.harmony.xnet.provider.jsse.NativeCrypto")

View File

@@ -1,13 +1,10 @@
package org.briarproject.bramble.system;
import org.briarproject.bramble.api.event.EventExecutor;
import org.briarproject.bramble.api.system.AndroidExecutor;
import org.briarproject.bramble.api.system.LocationUtils;
import org.briarproject.bramble.api.system.ResourceProvider;
import org.briarproject.bramble.api.system.SecureRandomProvider;
import java.util.concurrent.Executor;
import javax.inject.Singleton;
import dagger.Module;
@@ -35,13 +32,6 @@ public class AndroidSystemModule {
return androidExecutor;
}
@Provides
@Singleton
@EventExecutor
Executor provideEventExecutor(AndroidExecutor androidExecutor) {
return androidExecutor::runOnUiThread;
}
@Provides
@Singleton
ResourceProvider provideResourceProvider(AndroidResourceProvider provider) {

View File

@@ -6,36 +6,30 @@ import android.content.Context;
import android.os.Build;
import android.provider.Settings;
import org.briarproject.bramble.api.Pair;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import java.io.File;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import javax.annotation.Nullable;
import java.util.logging.Logger;
import static android.content.Context.MODE_PRIVATE;
import static android.os.Build.VERSION.SDK_INT;
import static java.util.Arrays.asList;
import static org.briarproject.bramble.api.nullsafety.NullSafety.requireNonNull;
@NotNullByDefault
public class AndroidUtils {
private static final Logger LOG =
Logger.getLogger(AndroidUtils.class.getName());
// Fake Bluetooth address returned by BluetoothAdapter on API 23 and later
private static final String FAKE_BLUETOOTH_ADDRESS = "02:00:00:00:00:00";
private static final String STORED_REPORTS = "dev-reports";
@SuppressWarnings("deprecation")
public static Collection<String> getSupportedArchitectures() {
List<String> abis = new ArrayList<>();
if (SDK_INT >= 21) {
abis.addAll(asList(Build.SUPPORTED_ABIS));
if (Build.VERSION.SDK_INT >= 21) {
abis.addAll(Arrays.asList(Build.SUPPORTED_ABIS));
} else {
abis.add(Build.CPU_ABI);
if (Build.CPU_ABI2 != null) abis.add(Build.CPU_ABI2);
@@ -45,76 +39,25 @@ public class AndroidUtils {
public static String getBluetoothAddress(Context ctx,
BluetoothAdapter adapter) {
return getBluetoothAddressAndMethod(ctx, adapter).getFirst();
}
public static Pair<String, String> getBluetoothAddressAndMethod(Context ctx,
BluetoothAdapter adapter) {
// Return the adapter's address if it's valid and not fake
@SuppressLint("HardwareIds")
String address = adapter.getAddress();
if (isValidBluetoothAddress(address)) {
return new Pair<>(address, "adapter");
}
if (isValidBluetoothAddress(address)) return address;
// Return the address from settings if it's valid and not fake
address = Settings.Secure.getString(ctx.getContentResolver(),
"bluetooth_address");
if (isValidBluetoothAddress(address)) {
return new Pair<>(address, "settings");
}
// Try to get the address via reflection
address = getBluetoothAddressByReflection(adapter);
if (isValidBluetoothAddress(address)) {
return new Pair<>(requireNonNull(address), "reflection");
}
if (isValidBluetoothAddress(address)) return address;
// Let the caller know we can't find the address
return new Pair<>("", "");
return "";
}
private static boolean isValidBluetoothAddress(@Nullable String address) {
private static boolean isValidBluetoothAddress(String address) {
return !StringUtils.isNullOrEmpty(address)
&& BluetoothAdapter.checkBluetoothAddress(address)
&& !address.equals(FAKE_BLUETOOTH_ADDRESS);
}
@Nullable
private static String getBluetoothAddressByReflection(
BluetoothAdapter adapter) {
try {
Field mServiceField =
adapter.getClass().getDeclaredField("mService");
mServiceField.setAccessible(true);
Object mService = mServiceField.get(adapter);
// mService may be null when Bluetooth is disabled
if (mService == null) throw new NoSuchFieldException();
Method getAddressMethod =
mService.getClass().getMethod("getAddress");
return (String) getAddressMethod.invoke(mService);
} catch (NoSuchFieldException e) {
return null;
} catch (IllegalAccessException e) {
return null;
} catch (NoSuchMethodException e) {
return null;
} catch (InvocationTargetException e) {
return null;
} catch (SecurityException e) {
return null;
}
}
public static File getReportDir(Context ctx) {
return ctx.getDir(STORED_REPORTS, MODE_PRIVATE);
}
/**
* 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() {
if (SDK_INT < 24) return new String[] {"image/jpeg", "image/png"};
else return new String[] {"image/jpeg", "image/png", "image/gif"};
}
}

View File

@@ -16,10 +16,13 @@ import org.junit.Test;
import java.io.File;
import static junit.framework.Assert.assertEquals;
import static junit.framework.Assert.assertFalse;
import static junit.framework.Assert.assertTrue;
import static org.briarproject.bramble.test.TestUtils.deleteTestDirectory;
import static org.briarproject.bramble.test.TestUtils.getRandomBytes;
import static org.briarproject.bramble.test.TestUtils.getTestDirectory;
import static org.briarproject.bramble.util.StringUtils.toHexString;
public class AndroidAccountManagerTest extends BrambleMockTestCase {
@@ -37,8 +40,11 @@ public class AndroidAccountManagerTest extends BrambleMockTestCase {
private final Application app;
private final ApplicationInfo applicationInfo;
private final String encryptedKeyHex = toHexString(getRandomBytes(123));
private final File testDir = getTestDirectory();
private final File keyDir = new File(testDir, "key");
private final File keyFile = new File(keyDir, "db.key");
private final File keyBackupFile = new File(keyDir, "db.key.bak");
private final File dbDir = new File(testDir, "db");
private AndroidAccountManager accountManager;
@@ -69,6 +75,29 @@ public class AndroidAccountManagerTest extends BrambleMockTestCase {
};
}
@Test
public void testDbKeyIsMigratedFromPreferencesToFile() {
context.checking(new Expectations() {{
oneOf(prefs).getString("key", null);
will(returnValue(encryptedKeyHex));
oneOf(prefs).edit();
will(returnValue(editor));
oneOf(editor).remove("key");
will(returnValue(editor));
oneOf(editor).commit();
will(returnValue(true));
}});
assertFalse(keyFile.exists());
assertFalse(keyBackupFile.exists());
assertEquals(encryptedKeyHex,
accountManager.loadEncryptedDatabaseKey());
assertTrue(keyFile.exists());
assertTrue(keyBackupFile.exists());
}
@Test
public void testDeleteAccountClearsSharedPrefsAndDeletesFiles()
throws Exception {
@@ -83,8 +112,6 @@ public class AndroidAccountManagerTest extends BrambleMockTestCase {
// Other directories should be deleted
File potatoDir = new File(testDir, ".potato");
File potatoFile = new File(potatoDir, "file");
File filesDir = new File(testDir, "filesDir");
File externalCacheDir = new File(testDir, "externalCacheDir");
context.checking(new Expectations() {{
oneOf(prefs).edit();
@@ -99,14 +126,8 @@ public class AndroidAccountManagerTest extends BrambleMockTestCase {
will(returnValue(editor));
oneOf(editor).commit();
will(returnValue(true));
allowing(app).getApplicationInfo();
oneOf(app).getApplicationInfo();
will(returnValue(applicationInfo));
oneOf(app).getFilesDir();
will(returnValue(filesDir));
oneOf(app).getCacheDir();
will(returnValue(cacheDir));
oneOf(app).getExternalCacheDir();
will(returnValue(externalCacheDir));
}});
assertTrue(dbDir.mkdirs());
@@ -119,8 +140,6 @@ public class AndroidAccountManagerTest extends BrambleMockTestCase {
assertTrue(cacheFile.createNewFile());
assertTrue(potatoDir.mkdirs());
assertTrue(potatoFile.createNewFile());
assertTrue(filesDir.mkdirs());
assertTrue(externalCacheDir.mkdirs());
accountManager.deleteAccount();
@@ -134,8 +153,6 @@ public class AndroidAccountManagerTest extends BrambleMockTestCase {
assertFalse(cacheFile.exists());
assertFalse(potatoDir.exists());
assertFalse(potatoFile.exists());
assertFalse(filesDir.exists());
assertFalse(externalCacheDir.exists());
}
@After

View File

@@ -1,90 +1,78 @@
dependencyVerification {
verify = [
'cglib:cglib:3.2.0:cglib-3.2.0.jar:adb13bab79712ad6bdf1bd59f2a3918018a8016e722e8a357065afb9e6690861',
'com.android.tools.analytics-library:protos:26.5.1:protos-26.5.1.jar:8dde1130725461fe827f2a343d353f2b51e8870661fc860d7d5ebddb097ead4e',
'com.android.tools.analytics-library:shared:26.5.1:shared-26.5.1.jar:ccc2f3b00ec17b11401610ba68553544fc8fc517120e84439ac6eb86b875e18d',
'com.android.tools.analytics-library:tracker:26.5.1:tracker-26.5.1.jar:3a76984c0fe2e847ca7a8b35b4780ef0447a9d1666946cb8e60466318e0ab5ae',
'com.android.tools.build:aapt2-proto:0.4.0:aapt2-proto-0.4.0.jar:fac0435e08898f89eeeb9ca236bea707155ff816c12205ced285ad53604133ca',
'com.android.tools.build:apksig:3.5.1:apksig-3.5.1.jar:1fd33e7f009a2a0da766cfeec4211a09f548034b015c289a66d75dd8a9302f4a',
'com.android.tools.build:apkzlib:3.5.1:apkzlib-3.5.1.jar:9f330167cbe973b7db407692f74f4f6453b7ffa5f2048934b06280c2ceee60fa',
'com.android.tools.build:builder-model:3.5.1:builder-model-3.5.1.jar:39ea3c82b76b6e0c9f9fa88d93e0edc1dd4a0f1dfae0ef6fbf2d451da47e5450',
'com.android.tools.build:builder-test-api:3.5.1:builder-test-api-3.5.1.jar:a1b59305584cbcaa078fdc9cfb80871012755b822dd32e8da19add6f7bbcb762',
'com.android.tools.build:builder:3.5.1:builder-3.5.1.jar:e3a8d382434c5f60990730c4719fc814e85a898a33a1e96c1df8d627d3c6eea6',
'com.android.tools.build:gradle-api:3.5.1:gradle-api-3.5.1.jar:be9b41859bace11998f66b04ed944f87e413f3ad6da3c4665587699da125addc',
'com.android.tools.build:manifest-merger:26.5.1:manifest-merger-26.5.1.jar:dcad9ecb967251f4d750f55a4204a2b400e8fbfe5cb930a1d0d5dbe10ae8bdfc',
'com.android.tools.ddms:ddmlib:26.5.1:ddmlib-26.5.1.jar:b081aef2a4ed3f4d47cae4cdb128469735f25a114e026d37123bf9ffdec742a8',
'com.android.tools.external.com-intellij:intellij-core:26.5.1:intellij-core-26.5.1.jar:20eced30adc124805bd93488d9cd9d3e33e6bf7b48e9fe5a703d4983f894d450',
'com.android.tools.external.com-intellij:kotlin-compiler:26.5.1:kotlin-compiler-26.5.1.jar:5aed762dd54875b77ae7018d97c05756ff0c5b9fd02ec595dd396ccd14cc22cb',
'com.android.tools.external.org-jetbrains:uast:26.5.1:uast-26.5.1.jar:4bc8653d6c0943f40fee963a149e36c6baa45683d2530968a13f5007e3c40740',
'com.android.tools.layoutlib:layoutlib-api:26.5.1:layoutlib-api-26.5.1.jar:88732f11396c427273e515d23042e35633f4fe4295528a99b866aa2adf0efd9c',
'com.android.tools.lint:lint-api:26.5.1:lint-api-26.5.1.jar:ec33fcd72bfaf70dd841e03fbfd93f109c2e575aec146067c606689c3972f0de',
'com.android.tools.lint:lint-checks:26.5.1:lint-checks-26.5.1.jar:a1b9607d484aaae7a71dcecdc76f8003d8239af226c776894a2cf63f9e6c60d7',
'com.android.tools.lint:lint-gradle-api:26.5.1:lint-gradle-api-26.5.1.jar:82453fd98a8394cc84ed995c04d2cd744abd1d6589403427ba7eef53115406f3',
'com.android.tools.lint:lint-gradle:26.5.1:lint-gradle-26.5.1.jar:59465b56cf7db77c656d5f8195d721c3d48b6bdd0502d774de335bfe4baff00b',
'com.android.tools.lint:lint:26.5.1:lint-26.5.1.jar:336e4b04ec6f8b0f25879131b7a7862d77df83a1879ee5b71be26128755f8e2e',
'com.android.tools:annotations:26.5.1:annotations-26.5.1.jar:2c43c82f8c59d8f7a61e3239e1a2dc9f69dc342ec09af9b7c9f69b25337c0b6e',
'com.android.tools:common:26.5.1:common-26.5.1.jar:eccfa54486ed54c4e3123cc42195d023bd0dd21bcd2f0e4868e8c6fc70f8ef6b',
'com.android.tools:dvlib:26.5.1:dvlib-26.5.1.jar:46f93ad498b4756e7d867d2fe38c38890a80e7407a4ae459e4a8c8d5c5aeacfe',
'com.android.tools:repository:26.5.1:repository-26.5.1.jar:2b3ee791aa4c3e8ce60498c161a27ca7228816fc630eed4d9f25f2f36a106dce',
'com.android.tools:sdk-common:26.5.1:sdk-common-26.5.1.jar:365f749676c3574676fd465177c8a492f340816db2b520d6ed114d3b6e77bea7',
'com.android.tools:sdklib:26.5.1:sdklib-26.5.1.jar:007da104afb27c8c682a1628023fe9ec438249c8d15ef0fd6624c5bb8e23b696',
'com.google.code.findbugs:jsr305:3.0.2:jsr305-3.0.2.jar:766ad2a0783f2687962c8ad74ceecc38a28b9f72a2d085ee438b7813e928d0c7',
'com.google.code.gson:gson:2.8.5:gson-2.8.5.jar:233a0149fc365c9f6edbd683cfe266b19bdc773be98eabdaf6b3c924b48e7d81',
'com.google.dagger:dagger-compiler:2.24:dagger-compiler-2.24.jar:3c5afb955fb188da485cb2c048eff37dce0e1530b9780a0f2f7187d16d1ccc1f',
'com.google.dagger:dagger-producers:2.24:dagger-producers-2.24.jar:f10f45b95191954d5d6b043fca9e62fb621d21bf70634b8f8476c7988b504c3a',
'com.google.dagger:dagger-spi:2.24:dagger-spi-2.24.jar:c038445d14dbcb4054e61bf49e05009edf26fce4fdc7ec1a9db544784f68e718',
'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:javac-shaded:9-dev-r4023-3:javac-shaded-9-dev-r4023-3.jar:65bfccf60986c47fbc17c9ebab0be626afc41741e0a6ec7109e0768817a36f30',
'com.google.googlejavaformat:google-java-format:1.5:google-java-format-1.5.jar:aa19ad7850fb85178aa22f2fddb163b84d6ce4d0035872f30d4408195ca1144e',
'com.google.guava: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: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.android.tools.analytics-library:protos:26.1.3:protos-26.1.3.jar:818c9f256f141d9dafec03a1aa2b94d240b2c140acfd7ee31a8b3e6c2b9479e3',
'com.android.tools.analytics-library:shared:26.1.3:shared-26.1.3.jar:7110706c7ada96c8b6f5ca80c478291bc7899d46277de2c48527e045442401a3',
'com.android.tools.analytics-library:tracker:26.1.3:tracker-26.1.3.jar:4155424bf2ce4872da83332579a1707252bc66cbd77c5144fdc4483d0f2e1418',
'com.android.tools.build:apksig:3.1.3:apksig-3.1.3.jar:7e1f8e675a6e768e5b56405e41d6c3cc05befe62e601b04177de1029902c9c89',
'com.android.tools.build:builder-model:3.1.3:builder-model-3.1.3.jar:06ad1c422d679fc698451479cb40ba863849d67bfd1de23f6d2c16d78b024b0b',
'com.android.tools.build:builder-test-api:3.1.3:builder-test-api-3.1.3.jar:4d989f780436794f0f8b2f50e9e079b786571eac90f26c208ab2ae6d4012f389',
'com.android.tools.build:builder:3.1.3:builder-3.1.3.jar:8a1092012c89d0ec1ee2eff09c5708c71ef4482a6862df8d3a44a67fccace01c',
'com.android.tools.build:gradle-api:3.1.3:gradle-api-3.1.3.jar:01e4df521456aef66514336f1d492346730dd1fb8f6433a89f62da834941ed72',
'com.android.tools.build:manifest-merger:26.1.3:manifest-merger-26.1.3.jar:1e4fc7e932adb4607082409800e5e6fccb42e6c5360ae5990094bf522f3ada55',
'com.android.tools.ddms:ddmlib:26.1.3:ddmlib-26.1.3.jar:c54931cd68df5d1ea2923b3b320eae47cd2307a5a916bb8674c0acf93cd1d3cd',
'com.android.tools.external.com-intellij:intellij-core:26.1.3:intellij-core-26.1.3.jar:af67f5535fef2e1a28b1007a4acb8c5deb6a1e33b8afe7b11d012c9e778ebcec',
'com.android.tools.external.com-intellij:kotlin-compiler:26.1.3:kotlin-compiler-26.1.3.jar:c746d2859dc11cc05c84b692b3498d3a621e0929511f8440ee009c6557838fd4',
'com.android.tools.external.org-jetbrains:uast:26.1.3:uast-26.1.3.jar:3f3f6651d0c7685a77ecb22e9c82d6b49fdf24322c17360768dc530678f43265',
'com.android.tools.layoutlib:layoutlib-api:26.1.3:layoutlib-api-26.1.3.jar:10bc73ce706c45629872d6a999dbe12116df64e24f47ff93b7b13121ff57b4b0',
'com.android.tools.lint:lint-api:26.1.3:lint-api-26.1.3.jar:6f97323f9af8deda86278717885b5c927f3766757db89709f52d11d42b6fb751',
'com.android.tools.lint:lint-checks:26.1.3:lint-checks-26.1.3.jar:73c3d53784c9ce3e6d5968506581918e0179645d20809927ca4a001dd766b001',
'com.android.tools.lint:lint-gradle-api:26.1.3:lint-gradle-api-26.1.3.jar:7ca3c4866ec21dc21d53a9d86f752b77ace6f6c610a0c9dc877313856c733d9d',
'com.android.tools.lint:lint-gradle:26.1.3:lint-gradle-26.1.3.jar:db0c354b8f4b6f6637e31f91c564785a59ff896325331fcbc3de7458e0b6c067',
'com.android.tools.lint:lint-kotlin:26.1.3:lint-kotlin-26.1.3.jar:94e2b0f4565a241561cfb8fc1222bb3f132a3b98d2a90421dbb72ee8358e7d68',
'com.android.tools.lint:lint:26.1.3:lint-26.1.3.jar:8d5f32c989c6d191d712e90ad3ca2d1c409313599551d04d834caa44d26c78df',
'com.android.tools:annotations:26.1.3:annotations-26.1.3.jar:c950430b24ac5d58fc97e7283b8f0115f99587e76e08b4e1e2aaa780f2d77323',
'com.android.tools:common:26.1.3:common-26.1.3.jar:7c31a90581a148ab219f615a59667f0dded7fa39b248529784474da3c2274ef2',
'com.android.tools:dvlib:26.1.3:dvlib-26.1.3.jar:0cae87906f53d3f1088366a916ed180a7312b6d9919b90797f238875c8492855',
'com.android.tools:repository:26.1.3:repository-26.1.3.jar:52d4539cc68db91b261e2a33b2c8206b26e05539078758dc28cfb3854adb4f59',
'com.android.tools:sdk-common:26.1.3:sdk-common-26.1.3.jar:1948603ca9ff22c7ebb3178000bffa3a9dd2ca1cc5cb0c793cae08468b8fcfc1',
'com.android.tools:sdklib:26.1.3:sdklib-26.1.3.jar:4adcfaad9514607098d2c51503c39811112d3050f4d1e744c01c7f08f591032b',
'com.google.code.findbugs:jsr305:1.3.9:jsr305-1.3.9.jar:905721a0eea90a81534abb7ee6ef4ea2e5e645fa1def0a5cd88402df1b46c9ed',
'com.google.code.gson:gson:2.7:gson-2.7.jar:2d43eb5ea9e133d2ee2405cc14f5ee08951b8361302fdd93494a3a997b508d32',
'com.google.dagger:dagger-compiler:2.0.2:dagger-compiler-2.0.2.jar:b74bc9de063dd4c6400b232231f2ef5056145b8fbecbf5382012007dd1c071b3',
'com.google.dagger:dagger-producers:2.0-beta:dagger-producers-2.0-beta.jar:99ec15e8a0507ba569e7655bc1165ee5e5ca5aa914b3c8f7e2c2458f724edd6b',
'com.google.dagger:dagger:2.0.2:dagger-2.0.2.jar:84c0282ed8be73a29e0475d639da030b55dee72369e58dd35ae7d4fe6243dcf9',
'com.google.errorprone:error_prone_annotations:2.0.18:error_prone_annotations-2.0.18.jar:cb4cfad870bf563a07199f3ebea5763f0dec440fcda0b318640b1feaa788656b',
'com.google.guava:guava:18.0:guava-18.0.jar:d664fbfc03d2e5ce9cab2a44fb01f1d0bf9dfebeccc1a473b1f9ea31f79f6f99',
'com.google.guava:guava:22.0:guava-22.0.jar:1158e94c7de4da480873f0b4ab4a1da14c0d23d4b1902cc94a58a6f0f9ab579e',
'com.google.j2objc:j2objc-annotations:1.1:j2objc-annotations-1.1.jar:40ceb7157feb263949e0f503fe5f71689333a621021aa20ce0d0acee3badaa0f',
'com.google.jimfs:jimfs:1.1:jimfs-1.1.jar:c4828e28d7c0a930af9387510b3bada7daa5c04d7c25a75c7b8b081f1c257ddd',
'com.google.protobuf:protobuf-java:3.4.0:protobuf-java-3.4.0.jar:dce7e66b32456a1b1198da0caff3a8acb71548658391e798c79369241e6490a4',
'com.googlecode.json-simple:json-simple:1.1:json-simple-1.1.jar:2d9484f4c649f708f47f9a479465fc729770ee65617dca3011836602264f6439',
'com.squareup:javapoet:1.11.1:javapoet-1.11.1.jar:9cbf2107be499ec6e95afd36b58e3ca122a24166cdd375732e51267d64058e90',
'com.squareup:javawriter:2.5.0:javawriter-2.5.0.jar:fcfb09fb0ea0aa97d3cfe7ea792398081348e468f126b3603cb3803f240197f0',
'com.sun.activation:javax.activation:1.2.0:javax.activation-1.2.0.jar:993302b16cd7056f21e779cc577d175a810bb4900ef73cd8fbf2b50f928ba9ce',
'com.sun.istack:istack-commons-runtime:2.21:istack-commons-runtime-2.21.jar:c33e67a0807095f02a0e2da139412dd7c4f9cc1a4c054b3e434f96831ba950f4',
'com.sun.xml.fastinfoset:FastInfoset:1.2.13:FastInfoset-1.2.13.jar:27a77db909f3c2833c0b1a37c55af1db06045118ad2eed96ce567b6632bce038',
'commons-codec:commons-codec:1.10:commons-codec-1.10.jar:4241dfa94e711d435f29a4604a3e2de5c4aa3c165e23bd066be6fc1fc4309569',
'commons-logging:commons-logging:1.2:commons-logging-1.2.jar:daddea1ea0be0f56978ab3006b8ac92834afeefbd9b7e4e6316fca57df0fa636',
'commons-codec:commons-codec:1.6:commons-codec-1.6.jar:54b34e941b8e1414bd3e40d736efd3481772dc26db3296f6aa45cec9f6203d86',
'commons-logging:commons-logging:1.1.1:commons-logging-1.1.1.jar:ce6f913cad1f0db3aad70186d65c5bc7ffcc9a99e3fe8e0b137312819f7c362f',
'it.unimi.dsi:fastutil:7.2.0:fastutil-7.2.0.jar:74fa208043740642f7e6eb09faba15965218ad2f50ce3020efb100136e4b591c',
'javax.annotation:jsr250-api:1.0:jsr250-api-1.0.jar:a1a922d0d9b6d183ed3800dfac01d1e1eb159f0e8c6f94736931c1def54a941f',
'javax.inject:javax.inject:1:javax.inject-1.jar:91c77044a50c481636c32d916fd89c9118a72195390452c81065080f957de7ff',
'javax.xml.bind:jaxb-api:2.2.12-b140109.1041:jaxb-api-2.2.12-b140109.1041.jar:b5e60cd8b7b5ff01ce4a74c5dd008f4fbd14ced3495d0b47b85cfedc182211f2',
'junit:junit:4.12:junit-4.12.jar:59721f0805e223d84b90677887d9ff567dc534d7c502ca903c0c2b17f05c116a',
'net.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.kxml:kxml2:2.3.0:kxml2-2.3.0.jar:f264dd9f79a1fde10ce5ecc53221eff24be4c9331c830b7d52f2f08a7b633de2',
'org.apache.ant:ant-launcher:1.9.4:ant-launcher-1.9.4.jar:7bccea20b41801ca17bcbc909a78c835d0f443f12d639c77bd6ae3d05861608d',
'org.apache.ant:ant:1.9.4:ant-1.9.4.jar:649ae0730251de07b8913f49286d46bba7b92d47c5f332610aa426c4f02161d8',
'org.apache.commons:commons-compress:1.12:commons-compress-1.12.jar:2c1542faf343185b7cab9c3d55c8ae5471d6d095d3887a4adefdbdf2984dc0b6',
'org.apache.httpcomponents:httpclient:4.5.6:httpclient-4.5.6.jar:c03f813195e7a80e3608d0ddd8da80b21696a4c92a6a2298865bf149071551c7',
'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:httpclient:4.2.6:httpclient-4.2.6.jar:362e9324ee7c697e21279e20077b52737ddef3f1b2c1a7abe5ad34b465145550',
'org.apache.httpcomponents:httpcore:4.2.5:httpcore-4.2.5.jar:e5e82da4cc66c8d917bbf743e3c0752efe8522735e7fc9dbddb65bccea81cfe9',
'org.apache.httpcomponents:httpmime:4.1:httpmime-4.1.jar:31629566148e8a47688ae43b420abc3ecd783ed15b33bebc00824bf24c9b15aa',
'org.beanshell:bsh:1.3.0:bsh-1.3.0.jar:9b04edc75d19db54f1b4e8b5355e9364384c6cf71eb0a1b9724c159d779879f8',
'org.bouncycastle:bcpkix-jdk15on:1.56:bcpkix-jdk15on-1.56.jar:7043dee4e9e7175e93e0b36f45b1ec1ecb893c5f755667e8b916eb8dd201c6ca',
'org.bouncycastle:bcprov-jdk15on:1.56:bcprov-jdk15on-1.56.jar:963e1ee14f808ffb99897d848ddcdb28fa91ddda867eb18d303e82728f878349',
'org.briarproject:obfs4proxy-android:0.0.11-2:obfs4proxy-android-0.0.11-2.zip:57e55cbe87aa2aac210fdbb6cd8cdeafe15f825406a08ebf77a8b787aa2c6a8a',
'org.briarproject:tor-android:0.3.5.9:tor-android-0.3.5.9.zip:853b0440feccd6904bd03e6b2de53a62ebcde1d58068beeadc447a7dff950bc8',
'org.checkerframework:checker-compat-qual:2.5.3:checker-compat-qual-2.5.3.jar:d76b9afea61c7c082908023f0cbc1427fab9abd2df915c8b8a3e7a509bccbc6d',
'org.checkerframework:checker-qual:2.5.2:checker-qual-2.5.2.jar:64b02691c8b9d4e7700f8ee2e742dce7ea2c6e81e662b7522c9ee3bf568c040a',
'org.codehaus.groovy:groovy-all:2.4.15:groovy-all-2.4.15.jar:51d6c4e71782e85674239189499854359d380fb75e1a703756e3aaa5b98a5af0',
'org.codehaus.mojo:animal-sniffer-annotations:1.17:animal-sniffer-annotations-1.17.jar:92654f493ecfec52082e76354f0ebf87648dc3d5cec2e3c3cdb947c016747a53',
'org.briarproject:tor-android:0.2.9.16:tor-android-0.2.9.16.zip:515e33dda6a30853c885a2de2c79ae1ab9ad8b6db44f5db8890333ec2e24f4ae',
'org.codehaus.groovy:groovy-all:2.4.12:groovy-all-2.4.12.jar:6a56af4bd48903d56bec62821876cadefafd007360cc6bd0d8f7aa8d72b38be4',
'org.codehaus.mojo:animal-sniffer-annotations:1.14:animal-sniffer-annotations-1.14.jar:2068320bd6bad744c3673ab048f67e30bef8f518996fa380033556600669905d',
'org.glassfish.jaxb:jaxb-core:2.2.11:jaxb-core-2.2.11.jar:37bcaee8ebb04362c8352a5bf6221b86967ecdab5164c696b10b9a2bb587b2aa',
'org.glassfish.jaxb:jaxb-runtime:2.2.11:jaxb-runtime-2.2.11.jar:a874f2351cfba8e2946be3002d10c18a6da8f21b52ba2acf52f2b85d5520ed70',
'org.glassfish.jaxb:txw2:2.2.11:txw2-2.2.11.jar:272a3ccad45a4511351920cd2a8633c53cab8d5220c7a92954da5526bb5eafea',
'org.hamcrest:hamcrest-core:1.3:hamcrest-core-1.3.jar:66fdef91e9739348df7a096aa384a5685f4e875584cce89386a7a47251c4d8e9',
'org.hamcrest:hamcrest-library:1.3:hamcrest-library-1.3.jar:711d64522f9ec410983bd310934296da134be4254a125080a0416ec178dfad1c',
'org.jetbrains.kotlin:kotlin-reflect:1.3.50:kotlin-reflect-1.3.50.jar:64583199ea5a54aefd1bd1595288925f784226ee562d1dd279011c6075b3d7a4',
'org.jetbrains.kotlin:kotlin-stdlib-common:1.3.50:kotlin-stdlib-common-1.3.50.jar:8ce678e88e4ba018b66dacecf952471e4d7dfee156a8a819760a5a5ff29d323c',
'org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.3.50:kotlin-stdlib-jdk7-1.3.50.jar:9a026639e76212f8d57b86d55b075394c2e009f1979110751d34c05c5f75d57b',
'org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.3.50:kotlin-stdlib-jdk8-1.3.50.jar:1b351fb6e09c14b55525c74c1f4cf48942eae43c348b7bc764a5e6e423d4da0c',
'org.jetbrains.kotlin:kotlin-stdlib:1.3.50:kotlin-stdlib-1.3.50.jar:e6f05746ee0366d0b52825a090fac474dcf44082c9083bbb205bd16976488d6c',
'org.jetbrains.kotlin:kotlin-reflect:1.2.0:kotlin-reflect-1.2.0.jar:4f48a872bad6e4d9c053f4ad610d11e4012ad7e58dc19a03dd5eb811f36069dd',
'org.jetbrains.kotlin:kotlin-stdlib-jre7:1.2.0:kotlin-stdlib-jre7-1.2.0.jar:c7a20fb951d437797afe8980aff6c1e5a03f310c661ba58ba1d4fa90cb0f2926',
'org.jetbrains.kotlin:kotlin-stdlib-jre8:1.2.0:kotlin-stdlib-jre8-1.2.0.jar:633524eee6ef1941f7cb1dab7ee3927b0a221ceee9047aeb5515f4cbb990c82a',
'org.jetbrains.kotlin:kotlin-stdlib:1.2.0:kotlin-stdlib-1.2.0.jar:05cfd9f5ac0b41910703a8925f7211a495909b27a2ffdd1c5106f1689aeafcd4',
'org.jetbrains.trove4j:trove4j:20160824:trove4j-20160824.jar:1917871c8deb468307a584680c87a44572f5a8b0b98c6d397fc0f5f86596dbe7',
'org.jetbrains:annotations:13.0:annotations-13.0.jar:ace2a10dc8e2d5fd34925ecac03e4988b2c0f851650c94b8cef49ba1bd111478',
'org.jmock:jmock-junit4:2.8.2:jmock-junit4-2.8.2.jar:f7ee4df4f7bd7b7f1cafad3b99eb74d579f109d5992ff625347352edb55e674c',
@@ -93,11 +81,11 @@ dependencyVerification {
'org.jmock:jmock:2.8.2:jmock-2.8.2.jar:6c73cb4a2e6dbfb61fd99c9a768539c170ab6568e57846bd60dbf19596b65b16',
'org.jvnet.staxex:stax-ex:1.7.7:stax-ex-1.7.7.jar:a31ff7d77163c0deb09e7fee59ad35ae44c2cee2cc8552a116ccd1583d813fb4',
'org.objenesis:objenesis:2.1:objenesis-2.1.jar:c74330cc6b806c804fd37e74487b4fe5d7c2750c5e15fbc6efa13bdee1bdef80',
'org.ow2.asm:asm-analysis:6.0:asm-analysis-6.0.jar:2f1a6387219c3a6cc4856481f221b03bd9f2408a326d416af09af5d6f608c1f4',
'org.ow2.asm:asm-commons:6.0:asm-commons-6.0.jar:f1bce5c648a96a017bdcd01fe5d59af9845297fd7b79b81c015a6fbbd9719abf',
'org.ow2.asm:asm-tree:6.0:asm-tree-6.0.jar:887998fb69727c8759e4d253f856822801e33f9fd4caa566b3ac58ee92106215',
'org.ow2.asm:asm-util:6.0:asm-util-6.0.jar:356afebdb0f870175262e5188f8709a3b17aa2a5a6a4b0340b04d4b449bca5f6',
'org.ow2.asm:asm-analysis:5.1:asm-analysis-5.1.jar:a34658f5c5de4b573eef21131cc32cc25f7b66407944f312b28ec2e56abb1fa9',
'org.ow2.asm:asm-commons:5.1:asm-commons-5.1.jar:97b3786e1f55e74bddf8ad102bf50e33bbcbc1f6b7fd7b36f0bbbb25cd4981be',
'org.ow2.asm:asm-tree:5.1:asm-tree-5.1.jar:c0de2bbc4cb8297419659813ecd4ed1d077ed1dd5c1f5544cc5143e493e84c10',
'org.ow2.asm:asm-util:5.1:asm-util-5.1.jar:ee032c39ae5e3cd099148fbba9a2124f9ed613e5cb93e03ee0fa8808ce364040',
'org.ow2.asm:asm:5.0.4:asm-5.0.4.jar:896618ed8ae62702521a78bc7be42b7c491a08e6920a15f89a3ecdec31e9a220',
'org.ow2.asm:asm:6.0:asm-6.0.jar:dd8971c74a4e697899a8e95caae4ea8760ea6c486dc6b97b1795e75760420461',
'org.ow2.asm:asm:5.1:asm-5.1.jar:d2da399a9967c69f0a21739256fa79d284222c223082cacadc17372244764b54',
]
}

View File

@@ -7,13 +7,15 @@ apply plugin: 'witness'
apply from: 'witness.gradle'
dependencies {
implementation "com.google.dagger:dagger:2.24"
implementation "com.google.dagger:dagger:2.0.2"
implementation 'com.google.code.findbugs:jsr305:3.0.2'
testImplementation 'junit:junit:4.12'
testImplementation "org.jmock:jmock:2.8.2"
testImplementation "org.jmock:jmock-junit4:2.8.2"
testImplementation "org.jmock:jmock-legacy:2.8.2"
testImplementation "org.hamcrest:hamcrest-library:1.3"
testImplementation "org.hamcrest:hamcrest-core:1.3"
signature 'org.codehaus.mojo.signature:java16:1.1@signature'
}

View File

@@ -4,8 +4,8 @@ import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import org.briarproject.bramble.util.StringUtils;
import java.util.Arrays;
import java.util.Comparator;
import javax.annotation.Nullable;
import javax.annotation.concurrent.ThreadSafe;
/**
@@ -15,6 +15,8 @@ import javax.annotation.concurrent.ThreadSafe;
@NotNullByDefault
public class Bytes implements Comparable<Bytes> {
public static final BytesComparator COMPARATOR = new BytesComparator();
private final byte[] bytes;
private int hashCode = -1;
@@ -36,13 +38,20 @@ public class Bytes implements Comparable<Bytes> {
}
@Override
public boolean equals(@Nullable Object o) {
public boolean equals(Object o) {
return o instanceof Bytes && Arrays.equals(bytes, ((Bytes) o).bytes);
}
@Override
public int compareTo(Bytes other) {
return compare(bytes, other.bytes);
byte[] aBytes = bytes, bBytes = other.bytes;
int length = Math.min(aBytes.length, bBytes.length);
for (int i = 0; i < length; i++) {
int aUnsigned = aBytes[i] & 0xFF, bUnsigned = bBytes[i] & 0xFF;
if (aUnsigned < bUnsigned) return -1;
if (aUnsigned > bUnsigned) return 1;
}
return aBytes.length - bBytes.length;
}
@Override
@@ -51,13 +60,11 @@ public class Bytes implements Comparable<Bytes> {
"(" + StringUtils.toHexString(getBytes()) + ")";
}
public static int compare(byte[] a, byte[] b) {
int length = Math.min(a.length, b.length);
for (int i = 0; i < length; i++) {
int aUnsigned = a[i] & 0xFF, bUnsigned = b[i] & 0xFF;
if (aUnsigned < bUnsigned) return -1;
if (aUnsigned > bUnsigned) return 1;
public static class BytesComparator implements Comparator<Bytes> {
@Override
public int compare(Bytes a, Bytes b) {
return a.compareTo(b);
}
return a.length - b.length;
}
}

View File

@@ -1,9 +0,0 @@
package org.briarproject.bramble.api;
/**
* Interface for specifying which features are enabled in a build.
*/
public interface FeatureFlags {
boolean shouldEnableImageAttachments();
}

View File

@@ -1,10 +0,0 @@
package org.briarproject.bramble.api;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
@NotNullByDefault
public interface Nameable {
String getName();
}

View File

@@ -1,26 +0,0 @@
package org.briarproject.bramble.api;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import javax.annotation.concurrent.Immutable;
@Immutable
@NotNullByDefault
public class Pair<A, B> {
private final A first;
private final B second;
public Pair(A first, B second) {
this.first = first;
this.second = second;
}
public A getFirst() {
return first;
}
public B getSecond() {
return second;
}
}

View File

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

View File

@@ -38,18 +38,4 @@ public abstract class StringMap extends Hashtable<String, String> {
public void putInt(String key, int value) {
put(key, String.valueOf(value));
}
public long getLong(String key, long defaultValue) {
String s = get(key);
if (s == null) return defaultValue;
try {
return Long.valueOf(s);
} catch (NumberFormatException e) {
return defaultValue;
}
}
public void putLong(String key, long value) {
put(key, String.valueOf(value));
}
}

View File

@@ -1,18 +1,9 @@
package org.briarproject.bramble.api;
import java.io.IOException;
/**
* Thrown when data being parsed uses a protocol or format version that is not
* supported.
* An exception that indicates an unrecoverable version mismatch.
*/
public class UnsupportedVersionException extends FormatException {
private final boolean tooOld;
public UnsupportedVersionException(boolean tooOld) {
this.tooOld = tooOld;
}
public boolean isTooOld() {
return tooOld;
}
public class UnsupportedVersionException extends IOException {
}

View File

@@ -1,6 +0,0 @@
package org.briarproject.bramble.api.battery;
public interface BatteryManager {
boolean isCharging();
}

View File

@@ -1,19 +0,0 @@
package org.briarproject.bramble.api.battery.event;
import org.briarproject.bramble.api.event.Event;
/**
* An event that is broadcast when the device starts or stops charging.
*/
public class BatteryEvent extends Event {
private final boolean charging;
public BatteryEvent(boolean charging) {
this.charging = charging;
}
public boolean isCharging() {
return charging;
}
}

View File

@@ -9,7 +9,7 @@ import org.briarproject.bramble.api.sync.Group;
import org.briarproject.bramble.api.sync.InvalidMessageException;
import org.briarproject.bramble.api.sync.Message;
import org.briarproject.bramble.api.sync.MessageContext;
import org.briarproject.bramble.api.sync.validation.MessageValidator;
import org.briarproject.bramble.api.sync.ValidationManager.MessageValidator;
import org.briarproject.bramble.api.system.Clock;
import java.util.logging.Logger;
@@ -48,8 +48,12 @@ public abstract class BdfMessageValidator implements MessageValidator {
throw new InvalidMessageException(
"Timestamp is too far in the future");
}
byte[] body = m.getBody();
if (body.length == 0) {
throw new InvalidMessageException("Message is too short");
}
try {
BdfList bodyList = clientHelper.toList(m.getBody());
BdfList bodyList = clientHelper.toList(body);
BdfMessageContext result = validateMessage(m, g, bodyList);
Metadata meta = metadataEncoder.encode(result.getDictionary());
return new MessageContext(meta, result.getDependencies());

View File

@@ -1,8 +1,6 @@
package org.briarproject.bramble.api.client;
import org.briarproject.bramble.api.FormatException;
import org.briarproject.bramble.api.crypto.PrivateKey;
import org.briarproject.bramble.api.crypto.PublicKey;
import org.briarproject.bramble.api.data.BdfDictionary;
import org.briarproject.bramble.api.data.BdfList;
import org.briarproject.bramble.api.db.DbException;
@@ -25,10 +23,7 @@ public interface ClientHelper {
throws DbException, FormatException;
void addLocalMessage(Transaction txn, Message m, BdfDictionary metadata,
boolean shared, boolean temporary)
throws DbException, FormatException;
Message createMessage(GroupId g, long timestamp, byte[] body);
boolean shared) throws DbException, FormatException;
Message createMessage(GroupId g, long timestamp, BdfList body)
throws FormatException;
@@ -101,18 +96,14 @@ public interface ClientHelper {
BdfList toList(Author a);
byte[] sign(String label, BdfList toSign, PrivateKey privateKey)
byte[] sign(String label, BdfList toSign, byte[] privateKey)
throws FormatException, GeneralSecurityException;
void verifySignature(byte[] signature, String label, BdfList signed,
PublicKey publicKey)
throws FormatException, GeneralSecurityException;
byte[] publicKey) throws FormatException, GeneralSecurityException;
Author parseAndValidateAuthor(BdfList author) throws FormatException;
PublicKey parseAndValidateAgreementPublicKey(byte[] publicKeyBytes)
throws FormatException;
TransportProperties parseAndValidateTransportProperties(
BdfDictionary properties) throws FormatException;

View File

@@ -1,16 +1,11 @@
package org.briarproject.bramble.api.contact;
import org.briarproject.bramble.api.crypto.PublicKey;
import org.briarproject.bramble.api.identity.Author;
import org.briarproject.bramble.api.identity.AuthorId;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import javax.annotation.Nullable;
import javax.annotation.concurrent.Immutable;
import static org.briarproject.bramble.api.identity.AuthorConstants.MAX_AUTHOR_NAME_LENGTH;
import static org.briarproject.bramble.util.StringUtils.toUtf8;
@Immutable
@NotNullByDefault
public class Contact {
@@ -18,26 +13,15 @@ public class Contact {
private final ContactId id;
private final Author author;
private final AuthorId localAuthorId;
@Nullable
private final String alias;
@Nullable
private final PublicKey handshakePublicKey;
private final boolean verified;
private final boolean verified, active;
public Contact(ContactId id, Author author, AuthorId localAuthorId,
@Nullable String alias, @Nullable PublicKey handshakePublicKey,
boolean verified) {
if (alias != null) {
int aliasLength = toUtf8(alias).length;
if (aliasLength == 0 || aliasLength > MAX_AUTHOR_NAME_LENGTH)
throw new IllegalArgumentException();
}
boolean verified, boolean active) {
this.id = id;
this.author = author;
this.localAuthorId = localAuthorId;
this.alias = alias;
this.handshakePublicKey = handshakePublicKey;
this.verified = verified;
this.active = active;
}
public ContactId getId() {
@@ -52,20 +36,14 @@ public class Contact {
return localAuthorId;
}
@Nullable
public String getAlias() {
return alias;
}
@Nullable
public PublicKey getHandshakePublicKey() {
return handshakePublicKey;
}
public boolean isVerified() {
return verified;
}
public boolean isActive() {
return active;
}
@Override
public int hashCode() {
return id.hashCode();

View File

@@ -0,0 +1,20 @@
package org.briarproject.bramble.api.contact;
import org.briarproject.bramble.api.identity.Author;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
@NotNullByDefault
public interface ContactExchangeListener {
void contactExchangeSucceeded(Author remoteAuthor);
/**
* The exchange failed because the contact already exists.
*/
void duplicateContact(Author remoteAuthor);
/**
* A general failure.
*/
void contactExchangeFailed();
}

View File

@@ -1,37 +0,0 @@
package org.briarproject.bramble.api.contact;
import org.briarproject.bramble.api.crypto.SecretKey;
import org.briarproject.bramble.api.db.ContactExistsException;
import org.briarproject.bramble.api.db.DbException;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import org.briarproject.bramble.api.plugin.duplex.DuplexTransportConnection;
import java.io.IOException;
@NotNullByDefault
public interface ContactExchangeManager {
/**
* Exchanges contact information with a remote peer and adds the peer
* as a contact.
*
* @param alice Whether the local peer takes the role of Alice
* @return The newly added contact
* @throws ContactExistsException If the contact already exists
*/
Contact exchangeContacts(DuplexTransportConnection conn,
SecretKey masterKey, boolean alice, boolean verified)
throws IOException, DbException;
/**
* Exchanges contact information with a remote peer and adds the peer
* as a contact, replacing the given pending contact.
*
* @param alice Whether the local peer takes the role of Alice
* @return The newly added contact
* @throws ContactExistsException If the contact already exists
*/
Contact exchangeContacts(PendingContactId p, DuplexTransportConnection conn,
SecretKey masterKey, boolean alice, boolean verified)
throws IOException, DbException;
}

View File

@@ -0,0 +1,48 @@
package org.briarproject.bramble.api.contact;
import org.briarproject.bramble.api.crypto.SecretKey;
import org.briarproject.bramble.api.identity.LocalAuthor;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import org.briarproject.bramble.api.plugin.TransportId;
import org.briarproject.bramble.api.plugin.duplex.DuplexTransportConnection;
/**
* A task for conducting a contact information exchange with a remote peer.
*/
@NotNullByDefault
public interface ContactExchangeTask {
/**
* The current version of the contact exchange protocol.
*/
byte PROTOCOL_VERSION = 1;
/**
* Label for deriving Alice's header key from the master secret.
*/
String ALICE_KEY_LABEL =
"org.briarproject.bramble.contact/ALICE_HEADER_KEY";
/**
* Label for deriving Bob's header key from the master secret.
*/
String BOB_KEY_LABEL = "org.briarproject.bramble.contact/BOB_HEADER_KEY";
/**
* Label for deriving Alice's key binding nonce from the master secret.
*/
String ALICE_NONCE_LABEL = "org.briarproject.bramble.contact/ALICE_NONCE";
/**
* Label for deriving Bob's key binding nonce from the master secret.
*/
String BOB_NONCE_LABEL = "org.briarproject.bramble.contact/BOB_NONCE";
/**
* Exchanges contact information with a remote peer.
*/
void startExchange(ContactExchangeListener listener,
LocalAuthor localAuthor, SecretKey masterSecret,
DuplexTransportConnection conn, TransportId transportId,
boolean alice);
}

View File

@@ -2,7 +2,6 @@ package org.briarproject.bramble.api.contact;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import javax.annotation.Nullable;
import javax.annotation.concurrent.Immutable;
/**
@@ -29,7 +28,7 @@ public class ContactId {
}
@Override
public boolean equals(@Nullable Object o) {
public boolean equals(Object o) {
return o instanceof ContactId && id == ((ContactId) o).id;
}
}

View File

@@ -1,25 +1,15 @@
package org.briarproject.bramble.api.contact;
import org.briarproject.bramble.api.FormatException;
import org.briarproject.bramble.api.Pair;
import org.briarproject.bramble.api.UnsupportedVersionException;
import org.briarproject.bramble.api.crypto.SecretKey;
import org.briarproject.bramble.api.db.ContactExistsException;
import org.briarproject.bramble.api.db.DbException;
import org.briarproject.bramble.api.db.NoSuchContactException;
import org.briarproject.bramble.api.db.PendingContactExistsException;
import org.briarproject.bramble.api.db.Transaction;
import org.briarproject.bramble.api.identity.Author;
import org.briarproject.bramble.api.identity.AuthorId;
import org.briarproject.bramble.api.identity.AuthorInfo;
import org.briarproject.bramble.api.lifecycle.LifecycleManager;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import java.security.GeneralSecurityException;
import java.util.Collection;
import javax.annotation.Nullable;
@NotNullByDefault
public interface ContactManager {
@@ -32,152 +22,60 @@ public interface ContactManager {
/**
* Stores a contact associated with the given local and remote pseudonyms,
* derives and stores rotation mode transport keys for each transport, and
* returns an ID for the contact.
*
* @param rootKey The root key for a set of rotation mode transport keys
* @param timestamp The timestamp for deriving rotation mode transport
* keys from the root key
* @param alice True if the local party is Alice
* @param verified True if the contact's identity has been verified, which
* is true if the contact was added in person or false if the contact was
* introduced or added remotely
* @param active True if the rotation mode transport keys can be used for
* outgoing streams
*/
ContactId addContact(Transaction txn, Author remote, AuthorId local,
SecretKey rootKey, long timestamp, boolean alice, boolean verified,
boolean active) throws DbException;
/**
* Stores a contact associated with the given local and remote pseudonyms,
* replacing the given pending contact, derives and stores handshake mode
* and rotation mode transport keys for each transport, and returns an ID
* derives and stores transport keys for each transport, and returns an ID
* for the contact.
*
* @param rootKey The root key for a set of rotation mode transport keys
* @param timestamp The timestamp for deriving rotation mode transport
* keys from the root key
* @param alice True if the local party is Alice
* @param verified True if the contact's identity has been verified, which
* is true if the contact was added in person or false if the contact was
* introduced or added remotely
* @param active True if the rotation mode transport keys can be used for
* outgoing streams
* @throws GeneralSecurityException If the pending contact's handshake
* public key is invalid
* @param alice true if the local party is Alice
*/
ContactId addContact(Transaction txn, PendingContactId p, Author remote,
AuthorId local, SecretKey rootKey, long timestamp, boolean alice,
boolean verified, boolean active)
throws DbException, GeneralSecurityException;
ContactId addContact(Transaction txn, Author remote, AuthorId local,
SecretKey master, long timestamp, boolean alice, boolean verified,
boolean active) throws DbException;
/**
* Stores a contact associated with the given local and remote pseudonyms
* and returns an ID for the contact.
*
* @param verified True if the contact's identity has been verified, which
* is true if the contact was added in person or false if the contact was
* introduced or added remotely
*/
ContactId addContact(Transaction txn, Author remote, AuthorId local,
boolean verified) throws DbException;
boolean verified, boolean active) throws DbException;
/**
* Stores a contact associated with the given local and remote pseudonyms,
* derives and stores rotation mode transport keys for each transport, and
* returns an ID for the contact.
* derives and stores transport keys for each transport, and returns an ID
* for the contact.
*
* @param rootKey The root key for a set of rotation mode transport keys
* @param timestamp The timestamp for deriving rotation mode transport
* keys from the root key
* @param alice True if the local party is Alice
* @param verified True if the contact's identity has been verified, which
* is true if the contact was added in person or false if the contact was
* introduced or added remotely
* @param active True if the rotation mode transport keys can be used for
* outgoing streams
* @param alice true if the local party is Alice
*/
ContactId addContact(Author remote, AuthorId local, SecretKey rootKey,
ContactId addContact(Author remote, AuthorId local, SecretKey master,
long timestamp, boolean alice, boolean verified, boolean active)
throws DbException;
/**
* Returns the handshake link that needs to be sent to a contact we want
* to add.
*/
String getHandshakeLink() 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(String link, String alias)
throws DbException, FormatException, GeneralSecurityException,
ContactExistsException, PendingContactExistsException;
/**
* Returns the pending contact with the given ID.
*/
PendingContact getPendingContact(Transaction txn, PendingContactId p)
throws DbException;
/**
* Returns a list of {@link PendingContact PendingContacts} and their
* {@link PendingContactState states}.
*/
Collection<Pair<PendingContact, PendingContactState>> getPendingContacts()
throws DbException;
/**
* Removes a {@link PendingContact}.
*/
void removePendingContact(PendingContactId p) throws DbException;
/**
* Returns the contact with the given ID.
*/
Contact getContact(ContactId c) throws DbException;
/**
* Returns the contact with the given ID.
*/
Contact getContact(Transaction txn, ContactId c) throws DbException;
/**
* Returns the contact with the given {@code remoteAuthorId}
* that belongs to the local pseudonym with the given {@code localAuthorId}.
* Returns the contact with the given remoteAuthorId
* that was added by the LocalAuthor with the given localAuthorId
*
* @throws NoSuchContactException If the contact is not in the database
* @throws org.briarproject.bramble.api.db.NoSuchContactException
*/
Contact getContact(AuthorId remoteAuthorId, AuthorId localAuthorId)
throws DbException;
/**
* Returns the contact with the given {@code remoteAuthorId}
* that belongs to the local pseudonym with the given {@code localAuthorId}.
* Returns the contact with the given remoteAuthorId
* that was added by the LocalAuthor with the given localAuthorId
*
* @throws NoSuchContactException If the contact is not in the database
* @throws org.briarproject.bramble.api.db.NoSuchContactException
*/
Contact getContact(Transaction txn, AuthorId remoteAuthorId,
AuthorId localAuthorId) throws DbException;
/**
* Returns all contacts.
* Returns all active contacts.
*/
Collection<Contact> getContacts() throws DbException;
Collection<Contact> getActiveContacts() throws DbException;
/**
* Removes a contact and all associated state.
@@ -190,57 +88,27 @@ public interface ContactManager {
void removeContact(Transaction txn, ContactId c) throws DbException;
/**
* Sets an alias for the contact or unsets it if {@code alias} is null.
* Marks a contact as active or inactive.
*/
void setContactAlias(Transaction txn, ContactId c, @Nullable String alias)
void setContactActive(Transaction txn, ContactId c, boolean active)
throws DbException;
/**
* Sets an alias for the contact or unsets it if {@code alias} is null.
*/
void setContactAlias(ContactId c, @Nullable String alias)
throws DbException;
/**
* Returns true if a contact with this {@code remoteAuthorId} belongs to
* the local pseudonym with this {@code localAuthorId}.
* Return true if a contact with this name and public key already exists
*/
boolean contactExists(Transaction txn, AuthorId remoteAuthorId,
AuthorId localAuthorId) throws DbException;
/**
* Returns true if a contact with this {@code remoteAuthorId} belongs to
* the local pseudonym with this {@code localAuthorId}.
* Return true if a contact with this name and public key already exists
*/
boolean contactExists(AuthorId remoteAuthorId, AuthorId localAuthorId)
throws DbException;
/**
* Returns the {@link AuthorInfo} for the given author.
*/
AuthorInfo getAuthorInfo(AuthorId a) throws DbException;
/**
* Returns the {@link AuthorInfo} for the given author.
*/
AuthorInfo getAuthorInfo(Transaction txn, AuthorId a) throws DbException;
interface ContactHook {
/**
* Called when a contact is being added.
*
* @param txn A read-write transaction
* @param c The contact that is being added
*/
void addingContact(Transaction txn, Contact c) throws DbException;
/**
* Called when a contact is being removed
*
* @param txn A read-write transaction
* @param c The contact that is being removed
*/
void removingContact(Transaction txn, Contact c) throws DbException;
}
}

View File

@@ -1,34 +0,0 @@
package org.briarproject.bramble.api.contact;
import java.util.regex.Pattern;
public interface HandshakeLinkConstants {
/**
* The current version of the handshake link format.
*/
int FORMAT_VERSION = 0;
/**
* The length of a base32-encoded handshake link in bytes, excluding the
* 'briar://' prefix.
*/
int BASE32_LINK_BYTES = 53;
/**
* The length of a raw handshake link in bytes, before base32 encoding.
*/
int RAW_LINK_BYTES = 33;
/**
* Regular expression for matching handshake links, including or excluding
* the 'briar://' prefix.
*/
Pattern LINK_REGEX =
Pattern.compile("(briar://)?([a-z2-7]{" + BASE32_LINK_BYTES + "})");
/**
* Label for hashing handshake public keys to calculate their identifiers.
*/
String ID_LABEL = "org.briarproject.bramble/HANDSHAKE_KEY_ID";
}

View File

@@ -1,45 +0,0 @@
package org.briarproject.bramble.api.contact;
import org.briarproject.bramble.api.crypto.SecretKey;
import org.briarproject.bramble.api.db.DbException;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import org.briarproject.bramble.api.transport.StreamWriter;
import java.io.IOException;
import java.io.InputStream;
@NotNullByDefault
public interface HandshakeManager {
/**
* Handshakes with the given pending contact. Returns an ephemeral master
* key authenticated with both parties' handshake key pairs and a flag
* indicating whether the local peer is Alice or Bob.
*
* @param in An incoming stream for the handshake, which must be secured in
* handshake mode
* @param out An outgoing stream for the handshake, which must be secured
* in handshake mode
*/
HandshakeResult handshake(PendingContactId p, InputStream in,
StreamWriter out) throws DbException, IOException;
class HandshakeResult {
private final SecretKey masterKey;
private final boolean alice;
public HandshakeResult(SecretKey masterKey, boolean alice) {
this.masterKey = masterKey;
this.alice = alice;
}
public SecretKey getMasterKey() {
return masterKey;
}
public boolean isAlice() {
return alice;
}
}
}

View File

@@ -1,51 +0,0 @@
package org.briarproject.bramble.api.contact;
import org.briarproject.bramble.api.crypto.PublicKey;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import javax.annotation.concurrent.Immutable;
@Immutable
@NotNullByDefault
public class PendingContact {
private final PendingContactId id;
private final PublicKey publicKey;
private final String alias;
private final long timestamp;
public PendingContact(PendingContactId id, PublicKey publicKey,
String alias, long timestamp) {
this.id = id;
this.publicKey = publicKey;
this.alias = alias;
this.timestamp = timestamp;
}
public PendingContactId getId() {
return id;
}
public PublicKey getPublicKey() {
return publicKey;
}
public String getAlias() {
return alias;
}
public long getTimestamp() {
return timestamp;
}
@Override
public int hashCode() {
return id.hashCode();
}
@Override
public boolean equals(Object o) {
return o instanceof PendingContact &&
id.equals(((PendingContact) o).id);
}
}

View File

@@ -1,25 +0,0 @@
package org.briarproject.bramble.api.contact;
import org.briarproject.bramble.api.UniqueId;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import javax.annotation.Nullable;
import javax.annotation.concurrent.ThreadSafe;
/**
* Type-safe wrapper for a byte array that uniquely identifies a
* {@link PendingContact}.
*/
@ThreadSafe
@NotNullByDefault
public class PendingContactId extends UniqueId {
public PendingContactId(byte[] id) {
super(id);
}
@Override
public boolean equals(@Nullable Object o) {
return o instanceof PendingContactId && super.equals(o);
}
}

View File

@@ -1,10 +0,0 @@
package org.briarproject.bramble.api.contact;
public enum PendingContactState {
WAITING_FOR_CONNECTION,
OFFLINE,
CONNECTING,
ADDING_CONTACT,
FAILED
}

View File

@@ -1,9 +1,9 @@
package org.briarproject.bramble.contact;
package org.briarproject.bramble.api.contact;
/**
* Record types for the contact exchange protocol.
*/
interface ContactExchangeRecordTypes {
public interface RecordTypes {
byte CONTACT_INFO = 0;
}

View File

@@ -14,18 +14,18 @@ import javax.annotation.concurrent.Immutable;
public class ContactAddedEvent extends Event {
private final ContactId contactId;
private final boolean verified;
private final boolean active;
public ContactAddedEvent(ContactId contactId, boolean verified) {
public ContactAddedEvent(ContactId contactId, boolean active) {
this.contactId = contactId;
this.verified = verified;
this.active = active;
}
public ContactId getContactId() {
return contactId;
}
public boolean isVerified() {
return verified;
public boolean isActive() {
return active;
}
}

View File

@@ -0,0 +1,31 @@
package org.briarproject.bramble.api.contact.event;
import org.briarproject.bramble.api.contact.ContactId;
import org.briarproject.bramble.api.event.Event;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import javax.annotation.concurrent.Immutable;
/**
* An event that is broadcast when a contact is marked active or inactive.
*/
@Immutable
@NotNullByDefault
public class ContactStatusChangedEvent extends Event {
private final ContactId contactId;
private final boolean active;
public ContactStatusChangedEvent(ContactId contactId, boolean active) {
this.contactId = contactId;
this.active = active;
}
public ContactId getContactId() {
return contactId;
}
public boolean isActive() {
return active;
}
}

View File

@@ -1,25 +0,0 @@
package org.briarproject.bramble.api.contact.event;
import org.briarproject.bramble.api.contact.PendingContact;
import org.briarproject.bramble.api.event.Event;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import javax.annotation.concurrent.Immutable;
/**
* An event that is broadcast when a pending contact is added.
*/
@Immutable
@NotNullByDefault
public class PendingContactAddedEvent extends Event {
private final PendingContact pendingContact;
public PendingContactAddedEvent(PendingContact pendingContact) {
this.pendingContact = pendingContact;
}
public PendingContact getPendingContact() {
return pendingContact;
}
}

View File

@@ -1,26 +0,0 @@
package org.briarproject.bramble.api.contact.event;
import org.briarproject.bramble.api.contact.PendingContactId;
import org.briarproject.bramble.api.event.Event;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import javax.annotation.concurrent.Immutable;
/**
* An event that is broadcast when a pending contact is removed.
*/
@Immutable
@NotNullByDefault
public class PendingContactRemovedEvent extends Event {
private final PendingContactId id;
public PendingContactRemovedEvent(PendingContactId id) {
this.id = id;
}
public PendingContactId getId() {
return id;
}
}

View File

@@ -1,34 +0,0 @@
package org.briarproject.bramble.api.contact.event;
import org.briarproject.bramble.api.contact.PendingContactId;
import org.briarproject.bramble.api.contact.PendingContactState;
import org.briarproject.bramble.api.event.Event;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import javax.annotation.concurrent.Immutable;
/**
* An event that is broadcast when a pending contact's state is changed.
*/
@Immutable
@NotNullByDefault
public class PendingContactStateChangedEvent extends Event {
private final PendingContactId id;
private final PendingContactState state;
public PendingContactStateChangedEvent(PendingContactId id,
PendingContactState state) {
this.id = id;
this.state = state;
}
public PendingContactId getId() {
return id;
}
public PendingContactState getPendingContactState() {
return state;
}
}

View File

@@ -1,30 +0,0 @@
package org.briarproject.bramble.api.crypto;
import org.briarproject.bramble.api.Bytes;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import javax.annotation.concurrent.Immutable;
import static org.briarproject.bramble.api.crypto.CryptoConstants.KEY_TYPE_AGREEMENT;
/**
* Type-safe wrapper for a private key used for key agreement.
*/
@Immutable
@NotNullByDefault
public class AgreementPrivateKey extends Bytes implements PrivateKey {
public AgreementPrivateKey(byte[] encoded) {
super(encoded);
}
@Override
public String getKeyType() {
return KEY_TYPE_AGREEMENT;
}
@Override
public byte[] getEncoded() {
return getBytes();
}
}

View File

@@ -1,35 +0,0 @@
package org.briarproject.bramble.api.crypto;
import org.briarproject.bramble.api.Bytes;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import javax.annotation.concurrent.Immutable;
import static org.briarproject.bramble.api.crypto.CryptoConstants.KEY_TYPE_AGREEMENT;
import static org.briarproject.bramble.api.crypto.CryptoConstants.MAX_AGREEMENT_PUBLIC_KEY_BYTES;
/**
* Type-safe wrapper for a public key used for key agreement.
*/
@Immutable
@NotNullByDefault
public class AgreementPublicKey extends Bytes implements PublicKey {
public AgreementPublicKey(byte[] encoded) {
super(encoded);
if (encoded.length == 0 ||
encoded.length > MAX_AGREEMENT_PUBLIC_KEY_BYTES) {
throw new IllegalArgumentException();
}
}
@Override
public String getKeyType() {
return KEY_TYPE_AGREEMENT;
}
@Override
public byte[] getEncoded() {
return getBytes();
}
}

View File

@@ -27,78 +27,54 @@ public interface CryptoComponent {
/**
* Derives another secret key from the given secret key.
*
* @param label A namespaced label indicating the purpose of the derived
* @param label a namespaced label indicating the purpose of the derived
* key, to prevent it from being repurposed or colliding with a key derived
* for another purpose
* @param inputs Additional inputs that will be included in the derivation
* of the key
*/
SecretKey deriveKey(String label, SecretKey k, byte[]... inputs);
/**
* Derives a shared secret from two key pairs.
* Derives a common shared secret from two public keys and one of the
* corresponding private keys.
*
* @param label A namespaced label indicating the purpose of this shared
* @param label a namespaced label indicating the purpose of this shared
* secret, to prevent it from being repurposed or colliding with a shared
* secret derived for another purpose
* @param theirPublicKey The public key of the remote party
* @param ourKeyPair The key pair of the local party
* @param inputs Additional inputs that will be included in the derivation
* of the shared secret
* @return The shared secret
* @param theirPublicKey the public key of the remote party
* @param ourKeyPair the key pair of the local party
* @return the shared secret
*/
SecretKey deriveSharedSecret(String label, PublicKey theirPublicKey,
KeyPair ourKeyPair, byte[]... inputs)
throws GeneralSecurityException;
/**
* Derives a shared secret from two static and two ephemeral key pairs.
*
* @param label A namespaced label indicating the purpose of this shared
* secret, to prevent it from being repurposed or colliding with a shared
* secret derived for another purpose
* @param theirStaticPublicKey The static public key of the remote party
* @param theirEphemeralPublicKey The ephemeral public key of the remote
* party
* @param ourStaticKeyPair The static key pair of the local party
* @param ourEphemeralKeyPair The ephemeral key pair of the local party
* @param alice True if the local party is Alice
* @param inputs Additional inputs that will be included in the
* derivation of the shared secret
* @return The shared secret
*/
SecretKey deriveSharedSecret(String label, PublicKey theirStaticPublicKey,
PublicKey theirEphemeralPublicKey, KeyPair ourStaticKeyPair,
KeyPair ourEphemeralKeyPair, boolean alice, byte[]... inputs)
throws GeneralSecurityException;
/**
* Signs the given byte[] with the given private key.
*
* @param label A namespaced label indicating the purpose of this
* @param label a namespaced label indicating the purpose of this
* signature, to prevent it from being repurposed or colliding with a
* signature created for another purpose
*/
byte[] sign(String label, byte[] toSign, PrivateKey privateKey)
byte[] sign(String label, byte[] toSign, byte[] privateKey)
throws GeneralSecurityException;
/**
* Verifies that the given signature is valid for the signed data
* and the given public key.
*
* @param label A namespaced label indicating the purpose of this
* @param label a namespaced label indicating the purpose of this
* signature, to prevent it from being repurposed or colliding with a
* signature created for another purpose
* @return True if the signature was valid, false otherwise.
* @return true if the signature was valid, false otherwise.
*/
boolean verifySignature(byte[] signature, String label, byte[] signed,
PublicKey publicKey) throws GeneralSecurityException;
byte[] publicKey) throws GeneralSecurityException;
/**
* Returns the hash of the given inputs. The inputs are unambiguously
* combined by prefixing each input with its length.
*
* @param label A namespaced label indicating the purpose of this hash, to
* @param label a namespaced label indicating the purpose of this hash, to
* prevent it from being repurposed or colliding with a hash created for
* another purpose
*/
@@ -109,7 +85,7 @@ public interface CryptoComponent {
* given inputs. The inputs are unambiguously combined by prefixing each
* input with its length.
*
* @param label A namespaced label indicating the purpose of this MAC, to
* @param label a namespaced label indicating the purpose of this MAC, to
* prevent it from being repurposed or colliding with a MAC created for
* another purpose
*/
@@ -119,10 +95,10 @@ public interface CryptoComponent {
* Verifies that the given message authentication code is valid for the
* given secret key and inputs.
*
* @param label A namespaced label indicating the purpose of this MAC, to
* @param label a namespaced label indicating the purpose of this MAC, to
* prevent it from being repurposed or colliding with a MAC created for
* another purpose
* @return True if the MAC was valid, false otherwise.
* @return true if the MAC was valid, false otherwise.
*/
boolean verifyMac(byte[] mac, String label, SecretKey macKey,
byte[]... inputs);
@@ -132,32 +108,17 @@ public interface CryptoComponent {
* storage. The encryption and authentication keys are derived from the
* given password. The ciphertext will be decryptable using the same
* password after the app restarts.
*
* @param keyStrengthener Used to strengthen the password-based key. If
* null, the password-based key will not be strengthened
*/
byte[] encryptWithPassword(byte[] plaintext, String password,
@Nullable KeyStrengthener keyStrengthener);
byte[] encryptWithPassword(byte[] plaintext, String password);
/**
* Decrypts and authenticates the given ciphertext that has been read from
* storage. The encryption and authentication keys are derived from the
* given password. Returns null if the ciphertext cannot be decrypted and
* authenticated (for example, if the password is wrong).
*
* @param keyStrengthener Used to strengthen the password-based key. If
* null, or if strengthening was not used when encrypting the ciphertext,
* the password-based key will not be strengthened
*/
@Nullable
byte[] decryptWithPassword(byte[] ciphertext, String password,
@Nullable KeyStrengthener keyStrengthener);
/**
* Returns true if the given ciphertext was encrypted using a strengthened
* key. The validity of the ciphertext is not checked.
*/
boolean isEncryptedWithStrengthenedKey(byte[] ciphertext);
byte[] decryptWithPassword(byte[] ciphertext, String password);
/**
* Encrypts the given plaintext to the given public key.

View File

@@ -7,21 +7,11 @@ public interface CryptoConstants {
*/
int MAX_AGREEMENT_PUBLIC_KEY_BYTES = 32;
/**
* The key type for agreement key pairs.
*/
String KEY_TYPE_AGREEMENT = "Curve25519";
/**
* The maximum length of a signature public key in bytes.
*/
int MAX_SIGNATURE_PUBLIC_KEY_BYTES = 32;
/**
* The key type for signature key pairs.
*/
String KEY_TYPE_SIGNATURE = "Ed25519";
/**
* The maximum length of a signature in bytes.
*/

View File

@@ -2,7 +2,7 @@ package org.briarproject.bramble.api.crypto;
/**
* Crypto operations for the key agreement protocol - see
* https://code.briarproject.org/briar/briar-spec/blob/master/protocols/BQP.md
* https://code.briarproject.org/akwizgran/briar-spec/blob/master/protocols/BQP.md
*/
public interface KeyAgreementCrypto {

View File

@@ -15,8 +15,6 @@ public class KeyPair {
private final PrivateKey privateKey;
public KeyPair(PublicKey publicKey, PrivateKey privateKey) {
if (!publicKey.getKeyType().equals(privateKey.getKeyType()))
throw new IllegalArgumentException();
this.publicKey = publicKey;
this.privateKey = privateKey;
}

View File

@@ -1,23 +0,0 @@
package org.briarproject.bramble.api.crypto;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
/**
* Interface for strengthening a password-based key, for example by using a
* key stored in a key management service or hardware security module.
*/
@NotNullByDefault
public interface KeyStrengthener {
/**
* Returns true if the strengthener has been initialised.
*/
@SuppressWarnings("BooleanMethodIsAlwaysInverted")
boolean isInitialised();
/**
* Initialises the strengthener if necessary and returns a strong key
* derived from the given key.
*/
SecretKey strengthenKey(SecretKey k);
}

View File

@@ -8,11 +8,6 @@ import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
@NotNullByDefault
public interface PrivateKey {
/**
* Returns the type of this key pair.
*/
String getKeyType();
/**
* Returns the encoded representation of this key.
*/

View File

@@ -8,11 +8,6 @@ import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
@NotNullByDefault
public interface PublicKey {
/**
* Returns the type of this key pair.
*/
String getKeyType();
/**
* Returns the encoded representation of this key.
*/

View File

@@ -1,30 +0,0 @@
package org.briarproject.bramble.api.crypto;
import org.briarproject.bramble.api.Bytes;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import javax.annotation.concurrent.Immutable;
import static org.briarproject.bramble.api.crypto.CryptoConstants.KEY_TYPE_SIGNATURE;
/**
* Type-safe wrapper for a public key used for signing.
*/
@Immutable
@NotNullByDefault
public class SignaturePrivateKey extends Bytes implements PrivateKey {
public SignaturePrivateKey(byte[] bytes) {
super(bytes);
}
@Override
public String getKeyType() {
return KEY_TYPE_SIGNATURE;
}
@Override
public byte[] getEncoded() {
return getBytes();
}
}

View File

@@ -1,35 +0,0 @@
package org.briarproject.bramble.api.crypto;
import org.briarproject.bramble.api.Bytes;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import javax.annotation.concurrent.Immutable;
import static org.briarproject.bramble.api.crypto.CryptoConstants.KEY_TYPE_SIGNATURE;
import static org.briarproject.bramble.api.crypto.CryptoConstants.MAX_SIGNATURE_PUBLIC_KEY_BYTES;
/**
* Type-safe wrapper for a public key used for verifying signatures.
*/
@Immutable
@NotNullByDefault
public class SignaturePublicKey extends Bytes implements PublicKey {
public SignaturePublicKey(byte[] encoded) {
super(encoded);
if (encoded.length == 0 ||
encoded.length > MAX_SIGNATURE_PUBLIC_KEY_BYTES) {
throw new IllegalArgumentException();
}
}
@Override
public String getKeyType() {
return KEY_TYPE_SIGNATURE;
}
@Override
public byte[] getEncoded() {
return getBytes();
}
}

View File

@@ -3,61 +3,27 @@ package org.briarproject.bramble.api.crypto;
import org.briarproject.bramble.api.plugin.TransportId;
import org.briarproject.bramble.api.transport.TransportKeys;
import java.security.GeneralSecurityException;
/**
* Crypto operations for the transport security protocol - see
* https://code.briarproject.org/briar/briar-spec/blob/master/protocols/BTP.md
* https://code.briarproject.org/akwizgran/briar-spec/blob/master/protocols/BTP.md
*/
public interface TransportCrypto {
/**
* Returns true if the local peer is Alice.
*/
boolean isAlice(PublicKey theirHandshakePublicKey,
KeyPair ourHandshakeKeyPair);
/**
* Derives the static master key shared with a contact or pending contact.
*/
SecretKey deriveStaticMasterKey(PublicKey theirHandshakePublicKey,
KeyPair ourHandshakeKeyPair) throws GeneralSecurityException;
/**
* Derives the handshake mode root key from the static master key. To
* prevent tag reuse, separate root keys are derived for contacts and
* pending contacts.
* Derives initial transport keys for the given transport in the given
* rotation period from the given master secret.
*
* @param pendingContact Whether the static master key is shared with a
* pending contact or a contact
* @param alice whether the keys are for use by Alice or Bob.
* @param active whether the keys are usable for outgoing streams.
*/
SecretKey deriveHandshakeRootKey(SecretKey staticMasterKey,
boolean pendingContact);
TransportKeys deriveTransportKeys(TransportId t, SecretKey master,
long rotationPeriod, boolean alice, boolean active);
/**
* Derives initial rotation mode transport keys for the given transport in
* the given time period from the given root key.
*
* @param alice Whether the keys are for use by Alice or Bob
* @param active Whether the keys are usable for outgoing streams
* Rotates the given transport keys to the given rotation period. If the
* keys are for the given period or any later period they are not rotated.
*/
TransportKeys deriveRotationKeys(TransportId t, SecretKey rootKey,
long timePeriod, boolean alice, boolean active);
/**
* Derives handshake keys for the given transport in the given time period
* from the given root key.
*
* @param alice Whether the keys are for use by Alice or Bob
*/
TransportKeys deriveHandshakeKeys(TransportId t, SecretKey rootKey,
long timePeriod, boolean alice);
/**
* Updates the given transport keys to the given time period. If the keys
* are for the given period or any later period they are not updated.
*/
TransportKeys updateTransportKeys(TransportKeys k, long timePeriod);
TransportKeys rotateTransportKeys(TransportKeys k, long rotationPeriod);
/**
* Encodes the pseudo-random tag that is used to recognise a stream.

View File

@@ -1,71 +0,0 @@
package org.briarproject.bramble.api.data;
import org.briarproject.bramble.api.Bytes;
import org.briarproject.bramble.api.FormatException;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import javax.annotation.Nullable;
import static org.briarproject.bramble.api.data.BdfDictionary.NULL_VALUE;
import static org.briarproject.bramble.util.StringUtils.toHexString;
@NotNullByDefault
public class BdfStringUtils {
public static String toString(@Nullable Object o) throws FormatException {
return toString(o, 0);
}
private static String toString(@Nullable Object o, int indent)
throws FormatException {
if (o == null || o == NULL_VALUE) return "null";
if (o instanceof Boolean) return o.toString();
if (o instanceof Number) return o.toString();
if (o instanceof String) return "\"" + o + "\"";
if (o instanceof Bytes)
return "x" + toHexString(((Bytes) o).getBytes());
if (o instanceof byte[])
return "x" + toHexString((byte[]) o);
if (o instanceof List) {
List<?> list = (List) o;
StringBuilder sb = new StringBuilder();
sb.append("[\n");
int i = 0, size = list.size();
for (Object e : list) {
indent(sb, indent + 1);
sb.append(toString(e, indent + 1));
if (i++ < size - 1) sb.append(',');
sb.append('\n');
}
indent(sb, indent);
sb.append(']');
return sb.toString();
}
if (o instanceof Map) {
Map<?, ?> map = (Map) o;
StringBuilder sb = new StringBuilder();
sb.append("{\n");
int i = 0, size = map.size();
for (Entry e : map.entrySet()) {
indent(sb, indent + 1);
sb.append(toString(e.getKey(), indent + 1));
sb.append(": ");
sb.append(toString(e.getValue(), indent + 1));
if (i++ < size - 1) sb.append(',');
sb.append('\n');
}
indent(sb, indent);
sb.append('}');
return sb.toString();
}
throw new FormatException();
}
private static void indent(StringBuilder sb, int indent) {
for (int i = 0; i < indent; i++) sb.append('\t');
}
}

View File

@@ -1,20 +0,0 @@
package org.briarproject.bramble.api.db;
import org.briarproject.bramble.api.event.EventExecutor;
/**
* An action that's taken when a {@link Transaction} is committed.
*/
public interface CommitAction {
void accept(Visitor visitor);
interface Visitor {
@EventExecutor
void visit(EventAction a);
@EventExecutor
void visit(TaskAction a);
}
}

View File

@@ -1,27 +1,8 @@
package org.briarproject.bramble.api.db;
import org.briarproject.bramble.api.identity.Author;
import org.briarproject.bramble.api.identity.AuthorId;
/**
* Thrown when a duplicate contact is added to the database. This exception may
* occur due to concurrent updates and does not indicate a database error.
*/
public class ContactExistsException extends DbException {
private final AuthorId local;
private final Author remote;
public ContactExistsException(AuthorId local, Author remote) {
this.local = local;
this.remote = remote;
}
public AuthorId getLocalAuthorId() {
return local;
}
public Author getRemoteAuthor() {
return remote;
}
}

View File

@@ -2,14 +2,10 @@ package org.briarproject.bramble.api.db;
import org.briarproject.bramble.api.contact.Contact;
import org.briarproject.bramble.api.contact.ContactId;
import org.briarproject.bramble.api.contact.PendingContact;
import org.briarproject.bramble.api.contact.PendingContactId;
import org.briarproject.bramble.api.crypto.PrivateKey;
import org.briarproject.bramble.api.crypto.PublicKey;
import org.briarproject.bramble.api.crypto.SecretKey;
import org.briarproject.bramble.api.identity.Author;
import org.briarproject.bramble.api.identity.AuthorId;
import org.briarproject.bramble.api.identity.Identity;
import org.briarproject.bramble.api.identity.LocalAuthor;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import org.briarproject.bramble.api.plugin.TransportId;
import org.briarproject.bramble.api.settings.Settings;
@@ -23,23 +19,23 @@ import org.briarproject.bramble.api.sync.MessageId;
import org.briarproject.bramble.api.sync.MessageStatus;
import org.briarproject.bramble.api.sync.Offer;
import org.briarproject.bramble.api.sync.Request;
import org.briarproject.bramble.api.sync.validation.MessageState;
import org.briarproject.bramble.api.transport.KeySet;
import org.briarproject.bramble.api.transport.KeySetId;
import org.briarproject.bramble.api.transport.TransportKeySet;
import org.briarproject.bramble.api.transport.TransportKeys;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import javax.annotation.Nullable;
import static org.briarproject.bramble.api.sync.ValidationManager.State;
/**
* Encapsulates the database implementation and exposes high-level operations
* to other components.
*/
@NotNullByDefault
public interface DatabaseComponent extends TransactionManager {
public interface DatabaseComponent {
/**
* Opens the database and returns true if the database already existed.
@@ -57,12 +53,35 @@ public interface DatabaseComponent extends TransactionManager {
*/
void close() throws DbException;
/**
* Starts a new transaction and returns an object representing it.
* <p/>
* 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.
*/
Transaction startTransaction(boolean readOnly) throws DbException;
/**
* Commits a transaction to the database.
*/
void commitTransaction(Transaction txn) throws DbException;
/**
* Ends a transaction. If the transaction has not been committed,
* it will be aborted. If the transaction has been committed,
* any events attached to the transaction are broadcast.
* The database lock will be released in either case.
*/
void endTransaction(Transaction txn);
/**
* Stores a contact associated with the given local and remote pseudonyms,
* and returns an ID for the contact.
*/
ContactId addContact(Transaction txn, Author remote, AuthorId local,
@Nullable PublicKey handshake, boolean verified) throws DbException;
boolean verified, boolean active) throws DbException;
/**
* Stores a group.
@@ -70,21 +89,15 @@ public interface DatabaseComponent extends TransactionManager {
void addGroup(Transaction txn, Group g) throws DbException;
/**
* Stores an identity.
* Stores a local pseudonym.
*/
void addIdentity(Transaction txn, Identity i) throws DbException;
void addLocalAuthor(Transaction txn, LocalAuthor a) throws DbException;
/**
* Stores a local message.
*/
void addLocalMessage(Transaction txn, Message m, Metadata meta,
boolean shared, boolean temporary) throws DbException;
/**
* Stores a pending contact.
*/
void addPendingContact(Transaction txn, PendingContact p, AuthorId local)
throws DbException;
boolean shared) throws DbException;
/**
* Stores a transport.
@@ -96,46 +109,25 @@ public interface DatabaseComponent extends TransactionManager {
* Stores the given transport keys for the given contact and returns a
* key set ID.
*/
KeySetId addTransportKeys(Transaction txn, ContactId c, TransportKeys k)
throws DbException;
/**
* Stores the given transport keys for the given pending contact and
* returns a key set ID.
*/
KeySetId addTransportKeys(Transaction txn, PendingContactId p,
KeySetId addTransportKeys(Transaction txn, ContactId c,
TransportKeys k) throws DbException;
/**
* Returns true if the database contains the given contact for the given
* local pseudonym.
* <p/>
* Read-only.
*/
boolean containsContact(Transaction txn, AuthorId remote, AuthorId local)
throws DbException;
/**
* Returns true if the database contains the given group.
* <p/>
* Read-only.
*/
boolean containsGroup(Transaction txn, GroupId g) throws DbException;
/**
* Returns true if the database contains an identity for the given
* pseudonym.
* <p/>
* Read-only.
* Returns true if the database contains the given local author.
*/
boolean containsIdentity(Transaction txn, AuthorId a) throws DbException;
/**
* Returns true if the database contains the given pending contact.
* <p/>
* Read-only.
*/
boolean containsPendingContact(Transaction txn, PendingContactId p)
boolean containsLocalAuthor(Transaction txn, AuthorId local)
throws DbException;
/**
@@ -223,7 +215,7 @@ public interface DatabaseComponent extends TransactionManager {
* <p/>
* Read-only.
*/
Collection<ContactId> getContacts(Transaction txn, AuthorId local)
Collection<ContactId> getContacts(Transaction txn, AuthorId a)
throws DbException;
/**
@@ -258,18 +250,18 @@ public interface DatabaseComponent extends TransactionManager {
throws DbException;
/**
* Returns the identity for the local pseudonym with the given ID.
* Returns the local pseudonym with the given ID.
* <p/>
* Read-only.
*/
Identity getIdentity(Transaction txn, AuthorId a) throws DbException;
LocalAuthor getLocalAuthor(Transaction txn, AuthorId a) throws DbException;
/**
* Returns the identities for all local pseudonyms.
* Returns all local pseudonyms.
* <p/>
* Read-only.
*/
Collection<Identity> getIdentities(Transaction txn) throws DbException;
Collection<LocalAuthor> getLocalAuthors(Transaction txn) throws DbException;
/**
* Returns the message with the given ID.
@@ -361,12 +353,12 @@ public interface DatabaseComponent extends TransactionManager {
/**
* Returns the IDs and states of all dependencies of the given message.
* For missing dependencies and dependencies in other groups, the state
* {@link MessageState UNKNOWN} is returned.
* {@link State UNKNOWN} is returned.
* <p/>
* Read-only.
*/
Map<MessageId, MessageState> getMessageDependencies(Transaction txn,
MessageId m) throws DbException;
Map<MessageId, State> getMessageDependencies(Transaction txn, MessageId m)
throws DbException;
/**
* Returns the IDs and states of all dependents of the given message.
@@ -375,16 +367,15 @@ public interface DatabaseComponent extends TransactionManager {
* <p/>
* Read-only.
*/
Map<MessageId, MessageState> getMessageDependents(Transaction txn,
MessageId m) throws DbException;
Map<MessageId, State> getMessageDependents(Transaction txn, MessageId m)
throws DbException;
/**
* Gets the validation and delivery state of the given message.
* <p/>
* Read-only.
*/
MessageState getMessageState(Transaction txn, MessageId m)
throws DbException;
State getMessageState(Transaction txn, MessageId m) throws DbException;
/**
* Returns the status of the given delivered message with respect to the
@@ -405,22 +396,6 @@ public interface DatabaseComponent extends TransactionManager {
*/
long getNextSendTime(Transaction txn, ContactId c) throws DbException;
/**
* Returns the pending contact with the given ID.
* <p/>
* Read-only.
*/
PendingContact getPendingContact(Transaction txn, PendingContactId p)
throws DbException;
/**
* Returns all pending contacts.
* <p/>
* Read-only.
*/
Collection<PendingContact> getPendingContacts(Transaction txn)
throws DbException;
/**
* Returns all settings in the given namespace.
* <p/>
@@ -428,19 +403,12 @@ public interface DatabaseComponent extends TransactionManager {
*/
Settings getSettings(Transaction txn, String namespace) throws DbException;
/**
* Returns the versions of the sync protocol supported by the given contact.
* <p/>
* Read-only.
*/
List<Byte> getSyncVersions(Transaction txn, ContactId c) throws DbException;
/**
* Returns all transport keys for the given transport.
* <p/>
* Read-only.
*/
Collection<TransportKeySet> getTransportKeys(Transaction txn, TransportId t)
Collection<KeySet> getTransportKeys(Transaction txn, TransportId t)
throws DbException;
/**
@@ -503,27 +471,15 @@ public interface DatabaseComponent extends TransactionManager {
void removeGroup(Transaction txn, Group g) throws DbException;
/**
* Removes an identity (and all associated state) from the database.
* Removes a local pseudonym (and all associated state) from the database.
*/
void removeIdentity(Transaction txn, AuthorId a) throws DbException;
void removeLocalAuthor(Transaction txn, AuthorId a) throws DbException;
/**
* Removes a message (and all associated state) from the database.
*/
void removeMessage(Transaction txn, MessageId m) throws DbException;
/**
* Removes a pending contact (and all associated state) from the database.
*/
void removePendingContact(Transaction txn, PendingContactId p)
throws DbException;
/**
* Removes all temporary messages (and all associated state) from the
* database.
*/
void removeTemporaryMessages(Transaction txn) throws DbException;
/**
* Removes a transport (and all associated state) from the database.
*/
@@ -541,9 +497,9 @@ public interface DatabaseComponent extends TransactionManager {
void setContactVerified(Transaction txn, ContactId c) throws DbException;
/**
* Sets an alias name for the contact or unsets it if alias is null.
* Marks the given contact as active or inactive.
*/
void setContactAlias(Transaction txn, ContactId c, @Nullable String alias)
void setContactActive(Transaction txn, ContactId c, boolean active)
throws DbException;
/**
@@ -552,11 +508,6 @@ public interface DatabaseComponent extends TransactionManager {
void setGroupVisibility(Transaction txn, ContactId c, GroupId g,
Visibility v) throws DbException;
/**
* Marks the given message as permanent, i.e. not temporary.
*/
void setMessagePermanent(Transaction txn, MessageId m) throws DbException;
/**
* Marks the given message as shared.
*/
@@ -565,7 +516,7 @@ public interface DatabaseComponent extends TransactionManager {
/**
* Sets the validation and delivery state of the given message.
*/
void setMessageState(Transaction txn, MessageId m, MessageState state)
void setMessageState(Transaction txn, MessageId m, State state)
throws DbException;
/**
@@ -575,23 +526,11 @@ public interface DatabaseComponent extends TransactionManager {
Collection<MessageId> dependencies) throws DbException;
/**
* Sets the handshake key pair for the identity with the given ID.
*/
void setHandshakeKeyPair(Transaction txn, AuthorId local,
PublicKey publicKey, PrivateKey privateKey) throws DbException;
/**
* Sets the reordering window for the given transport keys in the given
* time period.
* Sets the reordering window for the given key set and transport in the
* given rotation period.
*/
void setReorderingWindow(Transaction txn, KeySetId k, TransportId t,
long timePeriod, long base, byte[] bitmap) throws DbException;
/**
* Sets the versions of the sync protocol supported by the given contact.
*/
void setSyncVersions(Transaction txn, ContactId c, List<Byte> supported)
throws DbException;
long rotationPeriod, long base, byte[] bitmap) throws DbException;
/**
* Marks the given transport keys as usable for outgoing streams.
@@ -602,6 +541,6 @@ public interface DatabaseComponent extends TransactionManager {
/**
* Stores the given transport keys, deleting any keys they have replaced.
*/
void updateTransportKeys(Transaction txn, Collection<TransportKeySet> keys)
void updateTransportKeys(Transaction txn, Collection<KeySet> keys)
throws DbException;
}

View File

@@ -1,29 +1,15 @@
package org.briarproject.bramble.api.db;
import org.briarproject.bramble.api.crypto.KeyStrengthener;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import java.io.File;
import javax.annotation.Nullable;
@NotNullByDefault
public interface DatabaseConfig {
/**
* Returns the directory where the database stores its data.
*/
File getDatabaseDirectory();
/**
* Returns the directory where the encrypted database key is stored.
*/
File getDatabaseKeyDirectory();
/**
* Returns a {@link KeyStrengthener} for strengthening the encryption of
* the database key, or null if no strengthener should be used.
*/
@Nullable
KeyStrengthener getKeyStrengthener();
long getMaxSize();
}

View File

@@ -1,9 +0,0 @@
package org.briarproject.bramble.api.db;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
@NotNullByDefault
public interface DbCallable<R, E extends Exception> {
R call(Transaction txn) throws DbException, E;
}

View File

@@ -1,9 +0,0 @@
package org.briarproject.bramble.api.db;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
@NotNullByDefault
public interface DbRunnable<E extends Exception> {
void run(Transaction txn) throws DbException, E;
}

View File

@@ -1,24 +0,0 @@
package org.briarproject.bramble.api.db;
import org.briarproject.bramble.api.event.Event;
/**
* A {@link CommitAction} that broadcasts an event.
*/
public class EventAction implements CommitAction {
private final Event event;
EventAction(Event event) {
this.event = event;
}
public Event getEvent() {
return event;
}
@Override
public void accept(Visitor visitor) {
visitor.visit(this);
}
}

View File

@@ -6,10 +6,6 @@ public interface MigrationListener {
* This is called when a migration is started while opening the database.
* It will be called once for each migration being applied.
*/
void onDatabaseMigration();
void onMigrationRun();
/**
* This is called when compaction is started while opening the database.
*/
void onDatabaseCompaction();
}

View File

@@ -1,9 +1,9 @@
package org.briarproject.bramble.api.db;
/**
* Thrown when a database operation is attempted for an identity that is not in
* Thrown when a database operation is attempted for a pseudonym that is not in
* the database. This exception may occur due to concurrent updates and does
* not indicate a database error.
*/
public class NoSuchIdentityException extends DbException {
public class NoSuchLocalAuthorException extends DbException {
}

View File

@@ -1,9 +0,0 @@
package org.briarproject.bramble.api.db;
/**
* Thrown when a database operation is attempted for a pending contact that is
* not in the database. This exception may occur due to concurrent updates and
* does not indicate a database error.
*/
public class NoSuchPendingContactException extends DbException {
}

View File

@@ -1,12 +0,0 @@
package org.briarproject.bramble.api.db;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import javax.annotation.Nullable;
@NotNullByDefault
public interface NullableDbCallable<R, E extends Exception> {
@Nullable
R call(Transaction txn) throws DbException, E;
}

View File

@@ -1,21 +0,0 @@
package org.briarproject.bramble.api.db;
import org.briarproject.bramble.api.contact.PendingContact;
/**
* Thrown when a duplicate pending contact is added to the database. This
* exception may occur due to concurrent updates and does not indicate a
* database error.
*/
public class PendingContactExistsException extends DbException {
private final PendingContact pendingContact;
public PendingContactExistsException(PendingContact pendingContact) {
this.pendingContact = pendingContact;
}
public PendingContact getPendingContact() {
return pendingContact;
}
}

View File

@@ -1,24 +0,0 @@
package org.briarproject.bramble.api.db;
import org.briarproject.bramble.api.event.EventExecutor;
/**
* A {@link CommitAction} that submits a task to the {@link EventExecutor}.
*/
public class TaskAction implements CommitAction {
private final Runnable task;
TaskAction(Runnable task) {
this.task = task;
}
public Runnable getTask() {
return task;
}
@Override
public void accept(Visitor visitor) {
visitor.visit(this);
}
}

View File

@@ -1,15 +1,13 @@
package org.briarproject.bramble.api.db;
import org.briarproject.bramble.api.event.Event;
import org.briarproject.bramble.api.event.EventExecutor;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import javax.annotation.concurrent.NotThreadSafe;
import static java.util.Collections.emptyList;
/**
* A wrapper around a database transaction. Transactions are not thread-safe.
*/
@@ -19,7 +17,7 @@ public class Transaction {
private final Object txn;
private final boolean readOnly;
private List<CommitAction> actions = null;
private List<Event> events = null;
private boolean committed = false;
public Transaction(Object txn, boolean readOnly) {
@@ -44,27 +42,19 @@ public class Transaction {
/**
* Attaches an event to be broadcast when the transaction has been
* committed. The event will be broadcast on the {@link EventExecutor}.
* committed.
*/
public void attach(Event e) {
if (actions == null) actions = new ArrayList<>();
actions.add(new EventAction(e));
if (events == null) events = new ArrayList<>();
events.add(e);
}
/**
* Attaches a task to be executed when the transaction has been
* committed. The task will be run on the {@link EventExecutor}.
* Returns any events attached to the transaction.
*/
public void attach(Runnable r) {
if (actions == null) actions = new ArrayList<>();
actions.add(new TaskAction(r));
}
/**
* Returns any actions attached to the transaction.
*/
public List<CommitAction> getActions() {
return actions == null ? emptyList() : actions;
public List<Event> getEvents() {
if (events == null) return Collections.emptyList();
return events;
}
/**

View File

@@ -1,54 +0,0 @@
package org.briarproject.bramble.api.db;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import javax.annotation.Nullable;
@NotNullByDefault
public interface TransactionManager {
/**
* Starts a new transaction and returns an object representing it.
* <p/>
* 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.
*/
Transaction startTransaction(boolean readOnly) throws DbException;
/**
* Commits a transaction to the database.
*/
void commitTransaction(Transaction txn) throws DbException;
/**
* Ends a transaction. If the transaction has not been committed,
* it will be aborted. If the transaction has been committed,
* any events attached to the transaction are broadcast.
* The database lock will be released in either case.
*/
void endTransaction(Transaction txn);
/**
* Runs the given task within a transaction.
*/
<E extends Exception> void transaction(boolean readOnly,
DbRunnable<E> task) throws DbException, E;
/**
* Runs the given task within a transaction and returns the result of the
* task.
*/
<R, E extends Exception> R transactionWithResult(boolean readOnly,
DbCallable<R, E> task) throws DbException, E;
/**
* Runs the given task within a transaction and returns the result of the
* task, which may be null.
*/
@Nullable
<R, E extends Exception> R transactionWithNullableResult(boolean readOnly,
NullableDbCallable<R, E> task) throws DbException, E;
}

View File

@@ -16,8 +16,7 @@ public interface EventBus {
void removeListener(EventListener l);
/**
* Asynchronously notifies all listeners of an event. Listeners are
* notified on the {@link EventExecutor}.
* Notifies all listeners of an event.
*/
void broadcast(Event e);
}

View File

@@ -1,26 +0,0 @@
package org.briarproject.bramble.api.event;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import javax.inject.Qualifier;
import static java.lang.annotation.ElementType.FIELD;
import static java.lang.annotation.ElementType.METHOD;
import static java.lang.annotation.ElementType.PARAMETER;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
/**
* Annotation for injecting the executor for broadcasting events and running
* tasks that need to run in a defined order with respect to events. Also used
* for annotating methods that should run on the event executor.
* <p>
* The contract of this executor is that tasks are run in the order they're
* submitted, tasks are not run concurrently, and submitting a task will never
* block. Tasks must not block. Tasks submitted during shutdown are discarded.
*/
@Qualifier
@Target({FIELD, METHOD, PARAMETER})
@Retention(RUNTIME)
public @interface EventExecutor {
}

View File

@@ -12,6 +12,5 @@ public interface EventListener {
* Called when an event is broadcast. Implementations of this method must
* not block.
*/
@EventExecutor
void eventOccurred(Event e);
}

View File

@@ -1,21 +1,23 @@
package org.briarproject.bramble.api.identity;
import org.briarproject.bramble.api.Nameable;
import org.briarproject.bramble.api.crypto.PublicKey;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import org.briarproject.bramble.util.StringUtils;
import javax.annotation.concurrent.Immutable;
import static org.briarproject.bramble.api.crypto.CryptoConstants.KEY_TYPE_SIGNATURE;
import static org.briarproject.bramble.api.identity.AuthorConstants.MAX_AUTHOR_NAME_LENGTH;
import static org.briarproject.bramble.util.StringUtils.toUtf8;
import static org.briarproject.bramble.api.identity.AuthorConstants.MAX_PUBLIC_KEY_LENGTH;
/**
* A pseudonym for a user.
*/
@Immutable
@NotNullByDefault
public class Author implements Nameable {
public class Author {
public enum Status {
NONE, ANONYMOUS, UNKNOWN, UNVERIFIED, VERIFIED, OURSELVES
}
/**
* The current version of the author structure.
@@ -25,14 +27,14 @@ public class Author implements Nameable {
private final AuthorId id;
private final int formatVersion;
private final String name;
private final PublicKey publicKey;
private final byte[] publicKey;
public Author(AuthorId id, int formatVersion, String name,
PublicKey publicKey) {
int nameLength = toUtf8(name).length;
byte[] publicKey) {
int nameLength = StringUtils.toUtf8(name).length;
if (nameLength == 0 || nameLength > MAX_AUTHOR_NAME_LENGTH)
throw new IllegalArgumentException();
if (!publicKey.getKeyType().equals(KEY_TYPE_SIGNATURE))
if (publicKey.length == 0 || publicKey.length > MAX_PUBLIC_KEY_LENGTH)
throw new IllegalArgumentException();
this.id = id;
this.formatVersion = formatVersion;
@@ -64,7 +66,7 @@ public class Author implements Nameable {
/**
* Returns the public key used to verify the pseudonym's signatures.
*/
public PublicKey getPublicKey() {
public byte[] getPublicKey() {
return publicKey;
}

View File

@@ -1,6 +1,5 @@
package org.briarproject.bramble.api.identity;
import org.briarproject.bramble.api.crypto.PublicKey;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
@NotNullByDefault
@@ -10,16 +9,23 @@ public interface AuthorFactory {
* Creates an author with the current format version and the given name and
* public key.
*/
Author createAuthor(String name, PublicKey publicKey);
Author createAuthor(String name, byte[] publicKey);
/**
* Creates an author with the given format version, name and public key.
*/
Author createAuthor(int formatVersion, String name, PublicKey publicKey);
Author createAuthor(int formatVersion, String name, byte[] publicKey);
/**
* Creates a local author with the current format version and the given
* name.
* name and keys.
*/
LocalAuthor createLocalAuthor(String name);
LocalAuthor createLocalAuthor(String name, byte[] publicKey,
byte[] privateKey);
/**
* Creates a local author with the given format version, name and keys.
*/
LocalAuthor createLocalAuthor(int formatVersion, String name,
byte[] publicKey, byte[] privateKey);
}

View File

@@ -1,56 +0,0 @@
package org.briarproject.bramble.api.identity;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import javax.annotation.Nullable;
import javax.annotation.concurrent.Immutable;
@Immutable
@NotNullByDefault
public class AuthorInfo {
public enum Status {
NONE, ANONYMOUS, UNKNOWN, UNVERIFIED, VERIFIED, OURSELVES;
public boolean isContact() {
return this == UNVERIFIED || this == VERIFIED;
}
}
private final Status status;
@Nullable
private final String alias;
public AuthorInfo(Status status, @Nullable String alias) {
this.status = status;
this.alias = alias;
}
public AuthorInfo(Status status) {
this(status, null);
}
public Status getStatus() {
return status;
}
@Nullable
public String getAlias() {
return alias;
}
@Override
public int hashCode() {
int hashCode = status.ordinal();
if (alias != null) hashCode += alias.hashCode();
return hashCode;
}
@Override
public boolean equals(Object o) {
if (!(o instanceof AuthorInfo)) return false;
AuthorInfo info = (AuthorInfo) o;
return status == info.status &&
(alias == null ? info.alias == null : alias.equals(info.alias));
}
}

View File

@@ -1,88 +0,0 @@
package org.briarproject.bramble.api.identity;
import org.briarproject.bramble.api.crypto.PrivateKey;
import org.briarproject.bramble.api.crypto.PublicKey;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import javax.annotation.Nullable;
import javax.annotation.concurrent.Immutable;
import static org.briarproject.bramble.api.crypto.CryptoConstants.KEY_TYPE_AGREEMENT;
@Immutable
@NotNullByDefault
public class Identity {
private final LocalAuthor localAuthor;
@Nullable
private final PublicKey handshakePublicKey;
@Nullable
private final PrivateKey handshakePrivateKey;
private final long created;
public Identity(LocalAuthor localAuthor,
@Nullable PublicKey handshakePublicKey,
@Nullable PrivateKey handshakePrivateKey, long created) {
if (handshakePublicKey != null) {
if (handshakePrivateKey == null)
throw new IllegalArgumentException();
if (!handshakePublicKey.getKeyType().equals(KEY_TYPE_AGREEMENT))
throw new IllegalArgumentException();
}
if (handshakePrivateKey != null) {
if (handshakePublicKey == null)
throw new IllegalArgumentException();
if (!handshakePrivateKey.getKeyType().equals(KEY_TYPE_AGREEMENT))
throw new IllegalArgumentException();
}
this.localAuthor = localAuthor;
this.handshakePublicKey = handshakePublicKey;
this.handshakePrivateKey = handshakePrivateKey;
this.created = created;
}
/**
* Returns the ID of the user's pseudonym.
*/
public AuthorId getId() {
return localAuthor.getId();
}
/**
* Returns the user's pseudonym.
*/
public LocalAuthor getLocalAuthor() {
return localAuthor;
}
/**
* Returns true if the identity has a handshake key pair.
*/
public boolean hasHandshakeKeyPair() {
return handshakePublicKey != null && handshakePrivateKey != null;
}
/**
* Returns the public key used for handshaking, or null if no key exists.
*/
@Nullable
public PublicKey getHandshakePublicKey() {
return handshakePublicKey;
}
/**
* Returns the private key used for handshaking, or null if no key exists.
*/
@Nullable
public PrivateKey getHandshakePrivateKey() {
return handshakePrivateKey;
}
/**
* Returns the time the identity was created, in milliseconds since the
* Unix epoch.
*/
public long getTimeCreated() {
return created;
}
}

View File

@@ -1,30 +1,31 @@
package org.briarproject.bramble.api.identity;
import org.briarproject.bramble.api.crypto.CryptoExecutor;
import org.briarproject.bramble.api.crypto.KeyPair;
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.identity.Author.Status;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
@NotNullByDefault
public interface IdentityManager {
/**
* Creates an identity with the given name. The identity includes a
* handshake key pair.
* Creates a local identity with the given name.
*/
@CryptoExecutor
Identity createIdentity(String name);
LocalAuthor createLocalAuthor(String name);
/**
* Registers the given identity with the manager. This method should be
* called before {@link LifecycleManager#startServices(SecretKey)}. The
* identity is stored when {@link LifecycleManager#startServices(SecretKey)}
* is called. The identity must include a handshake key pair.
* Registers the given local identity with the manager. The identity is
* not stored until {@link #storeLocalAuthor()} is called.
*/
void registerIdentity(Identity i);
void registerLocalAuthor(LocalAuthor a);
/**
* Stores the local identity registered with
* {@link #registerLocalAuthor(LocalAuthor)}, if any.
*/
void storeLocalAuthor() throws DbException;
/**
* Returns the cached local identity or loads it from the database.
@@ -33,15 +34,17 @@ public interface IdentityManager {
/**
* Returns the cached local identity or loads it from the database.
* <p/>
* Read-only.
*/
LocalAuthor getLocalAuthor(Transaction txn) throws DbException;
/**
* Returns the cached handshake keys or loads them from the database.
* <p/>
* Read-only.
* Returns the {@link Status} of the given author.
*/
KeyPair getHandshakeKeys(Transaction txn) throws DbException;
Status getAuthorStatus(AuthorId a) throws DbException;
/**
* Returns the {@link Status} of the given author.
*/
Status getAuthorStatus(Transaction txn, AuthorId a) throws DbException;
}

View File

@@ -1,13 +1,9 @@
package org.briarproject.bramble.api.identity;
import org.briarproject.bramble.api.crypto.PrivateKey;
import org.briarproject.bramble.api.crypto.PublicKey;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import javax.annotation.concurrent.Immutable;
import static org.briarproject.bramble.api.crypto.CryptoConstants.KEY_TYPE_SIGNATURE;
/**
* A pseudonym for the local user.
*/
@@ -15,20 +11,28 @@ import static org.briarproject.bramble.api.crypto.CryptoConstants.KEY_TYPE_SIGNA
@NotNullByDefault
public class LocalAuthor extends Author {
private final PrivateKey privateKey;
private final byte[] privateKey;
private final long created;
public LocalAuthor(AuthorId id, int formatVersion, String name,
PublicKey publicKey, PrivateKey privateKey) {
byte[] publicKey, byte[] privateKey, long created) {
super(id, formatVersion, name, publicKey);
if (!privateKey.getKeyType().equals(KEY_TYPE_SIGNATURE))
throw new IllegalArgumentException();
this.privateKey = privateKey;
this.created = created;
}
/**
* Returns the private key used to generate the pseudonym's signatures.
*/
public PrivateKey getPrivateKey() {
public byte[] getPrivateKey() {
return privateKey;
}
/**
* Returns the time the pseudonym was created, in milliseconds since the
* Unix epoch.
*/
public long getTimeCreated() {
return created;
}
}

View File

@@ -7,15 +7,15 @@ import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import javax.annotation.concurrent.Immutable;
/**
* An event that is broadcast when an identity is added.
* An event that is broadcast when a local pseudonym is added.
*/
@Immutable
@NotNullByDefault
public class IdentityAddedEvent extends Event {
public class LocalAuthorAddedEvent extends Event {
private final AuthorId authorId;
public IdentityAddedEvent(AuthorId authorId) {
public LocalAuthorAddedEvent(AuthorId authorId) {
this.authorId = authorId;
}

View File

@@ -7,15 +7,15 @@ import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import javax.annotation.concurrent.Immutable;
/**
* An event that is broadcast when an identity is removed.
* An event that is broadcast when a local pseudonym is removed.
*/
@Immutable
@NotNullByDefault
public class IdentityRemovedEvent extends Event {
public class LocalAuthorRemovedEvent extends Event {
private final AuthorId authorId;
public IdentityRemovedEvent(AuthorId authorId) {
public LocalAuthorRemovedEvent(AuthorId authorId) {
this.authorId = authorId;
}

View File

@@ -3,13 +3,7 @@ package org.briarproject.bramble.api.keyagreement;
public interface KeyAgreementConstants {
/**
* The version of the BQP protocol used in beta releases. This version
* number is reserved.
*/
byte BETA_PROTOCOL_VERSION = 89;
/**
* The current version of the BQP protocol.
* The current version of the BQP protocol. Version number 89 is reserved.
*/
byte PROTOCOL_VERSION = 4;
@@ -21,7 +15,7 @@ public interface KeyAgreementConstants {
/**
* The connection timeout in milliseconds.
*/
long CONNECTION_TIMEOUT = 60_000;
long CONNECTION_TIMEOUT = 20 * 1000;
/**
* The transport identifier for Bluetooth.
@@ -40,8 +34,8 @@ public interface KeyAgreementConstants {
"org.briarproject.bramble.keyagreement/SHARED_SECRET";
/**
* Label for deriving the master key.
* Label for deriving the master secret.
*/
String MASTER_KEY_LABEL =
String MASTER_SECRET_LABEL =
"org.briarproject.bramble.keyagreement/MASTER_SECRET";
}

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