mirror of
https://code.briarproject.org/briar/briar.git
synced 2026-02-12 18:59:06 +01:00
Compare commits
4 Commits
bluetooth-
...
bluetooth_
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a51f0f803f | ||
|
|
8f9d7a70bf | ||
|
|
3ea642c6c0 | ||
|
|
da0a32c613 |
@@ -1,31 +1,27 @@
|
|||||||
image: briar/ci-image-android:latest
|
image: registry.gitlab.com/fdroid/ci-images-base:latest
|
||||||
|
|
||||||
|
cache:
|
||||||
|
paths:
|
||||||
|
- .gradle/wrapper
|
||||||
|
- .gradle/caches
|
||||||
|
|
||||||
|
before_script:
|
||||||
|
- set -e
|
||||||
|
- export GRADLE_USER_HOME=$PWD/.gradle
|
||||||
|
# Download OpenJDK 6 so we can compile against its standard library
|
||||||
|
- JDK_FILE=openjdk-6-jre-headless_6b38-1.13.10-1~deb7u1_amd64.deb
|
||||||
|
- if [ ! -d openjdk ]
|
||||||
|
- then
|
||||||
|
- wget -q http://ftp.uk.debian.org/debian/pool/main/o/openjdk-6/$JDK_FILE
|
||||||
|
- dpkg-deb -x $JDK_FILE openjdk
|
||||||
|
- fi
|
||||||
|
- export JAVA_6_HOME=$PWD/openjdk/usr/lib/jvm/java-6-openjdk-amd64
|
||||||
|
|
||||||
test:
|
test:
|
||||||
before_script:
|
|
||||||
- set -e
|
|
||||||
- export GRADLE_USER_HOME=$PWD/.gradle
|
|
||||||
|
|
||||||
cache:
|
|
||||||
paths:
|
|
||||||
- .gradle/wrapper
|
|
||||||
- .gradle/caches
|
|
||||||
|
|
||||||
script:
|
script:
|
||||||
- ./gradlew --no-daemon animalSnifferMain animalSnifferTest
|
- ./gradlew test
|
||||||
- ./gradlew --no-daemon test
|
|
||||||
|
|
||||||
after_script:
|
after_script:
|
||||||
# these file change every time but should not be cached
|
# this file changes every time but should not be cached
|
||||||
- rm -f $GRADLE_USER_HOME/caches/modules-2/modules-2.lock
|
- rm -f $GRADLE_USER_HOME/caches/modules-2/modules-2.lock
|
||||||
- rm -fr $GRADLE_USER_HOME/caches/*/plugin-resolution/
|
- rm -fr $GRADLE_USER_HOME/caches/*/plugin-resolution/
|
||||||
|
|
||||||
|
|
||||||
test_reproducible:
|
|
||||||
image: briar/reproducer:latest
|
|
||||||
|
|
||||||
script:
|
|
||||||
- cd /opt/briar-reproducer
|
|
||||||
- ./reproduce.py ${CI_COMMIT_REF_NAME}
|
|
||||||
|
|
||||||
only:
|
|
||||||
- tags
|
|
||||||
|
|||||||
@@ -1,5 +1,11 @@
|
|||||||
|
import de.undercouch.gradle.tasks.download.Download
|
||||||
|
import de.undercouch.gradle.tasks.download.Verify
|
||||||
|
|
||||||
|
import java.security.NoSuchAlgorithmException
|
||||||
|
|
||||||
apply plugin: 'com.android.library'
|
apply plugin: 'com.android.library'
|
||||||
apply plugin: 'witness'
|
apply plugin: 'witness'
|
||||||
|
apply plugin: 'de.undercouch.download'
|
||||||
|
|
||||||
android {
|
android {
|
||||||
compileSdkVersion 27
|
compileSdkVersion 27
|
||||||
@@ -8,8 +14,8 @@ android {
|
|||||||
defaultConfig {
|
defaultConfig {
|
||||||
minSdkVersion 14
|
minSdkVersion 14
|
||||||
targetSdkVersion 26
|
targetSdkVersion 26
|
||||||
versionCode 10005
|
versionCode 10001
|
||||||
versionName "1.0.5"
|
versionName "1.0.1"
|
||||||
consumerProguardFiles 'proguard-rules.txt'
|
consumerProguardFiles 'proguard-rules.txt'
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -19,14 +25,9 @@ android {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
configurations {
|
|
||||||
tor
|
|
||||||
}
|
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
implementation project(path: ':bramble-core', configuration: 'default')
|
implementation project(path: ':bramble-core', configuration: 'default')
|
||||||
implementation 'org.briarproject:jtorctl:0.3'
|
implementation fileTree(dir: 'libs', include: '*.jar')
|
||||||
tor 'org.briarproject:tor-android:0.2.9.15@zip'
|
|
||||||
|
|
||||||
annotationProcessor 'com.google.dagger:dagger-compiler:2.0.2'
|
annotationProcessor 'com.google.dagger:dagger-compiler:2.0.2'
|
||||||
|
|
||||||
@@ -91,8 +92,6 @@ dependencyVerification {
|
|||||||
'org.apache.httpcomponents:httpmime:4.1:httpmime-4.1.jar:31629566148e8a47688ae43b420abc3ecd783ed15b33bebc00824bf24c9b15aa',
|
'org.apache.httpcomponents:httpmime:4.1:httpmime-4.1.jar:31629566148e8a47688ae43b420abc3ecd783ed15b33bebc00824bf24c9b15aa',
|
||||||
'org.bouncycastle:bcpkix-jdk15on:1.56:bcpkix-jdk15on-1.56.jar:7043dee4e9e7175e93e0b36f45b1ec1ecb893c5f755667e8b916eb8dd201c6ca',
|
'org.bouncycastle:bcpkix-jdk15on:1.56:bcpkix-jdk15on-1.56.jar:7043dee4e9e7175e93e0b36f45b1ec1ecb893c5f755667e8b916eb8dd201c6ca',
|
||||||
'org.bouncycastle:bcprov-jdk15on:1.56:bcprov-jdk15on-1.56.jar:963e1ee14f808ffb99897d848ddcdb28fa91ddda867eb18d303e82728f878349',
|
'org.bouncycastle:bcprov-jdk15on:1.56:bcprov-jdk15on-1.56.jar:963e1ee14f808ffb99897d848ddcdb28fa91ddda867eb18d303e82728f878349',
|
||||||
'org.briarproject:jtorctl:0.3:jtorctl-0.3.jar:f2939238a097898998432effe93b0334d97a787972ab3a91a8973a1d309fc864',
|
|
||||||
'org.briarproject:tor-android:0.2.9.15:tor-android-0.2.9.15.zip:34a6474ee219ffa52e0f3393e917dda6ed03d320b02247d4fa5075aa4094ee6d',
|
|
||||||
'org.codehaus.groovy:groovy-all:2.4.12:groovy-all-2.4.12.jar:6a56af4bd48903d56bec62821876cadefafd007360cc6bd0d8f7aa8d72b38be4',
|
'org.codehaus.groovy:groovy-all:2.4.12:groovy-all-2.4.12.jar:6a56af4bd48903d56bec62821876cadefafd007360cc6bd0d8f7aa8d72b38be4',
|
||||||
'org.codehaus.mojo:animal-sniffer-annotations:1.14:animal-sniffer-annotations-1.14.jar:2068320bd6bad744c3673ab048f67e30bef8f518996fa380033556600669905d',
|
'org.codehaus.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-core:2.2.11:jaxb-core-2.2.11.jar:37bcaee8ebb04362c8352a5bf6221b86967ecdab5164c696b10b9a2bb587b2aa',
|
||||||
@@ -113,9 +112,81 @@ dependencyVerification {
|
|||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
project.afterEvaluate {
|
ext.torBinaryDir = 'src/main/res/raw'
|
||||||
copy {
|
ext.torVersion = '0.2.9.14'
|
||||||
from configurations.tor.collect { zipTree(it) }
|
ext.geoipVersion = '2017-11-06'
|
||||||
into 'src/main/res/raw'
|
ext.torDownloadUrl = 'https://briarproject.org/build/'
|
||||||
|
|
||||||
|
def torBinaries = [
|
||||||
|
"tor_arm" : '1710ea6c47b7f4c1a88bdf4858c7893837635db10e8866854eed8d61629f50e8',
|
||||||
|
"tor_arm_pie": '974e6949507db8fa2ea45231817c2c3677ed4ccf5488a2252317d744b0be1917',
|
||||||
|
"tor_x86" : '3a5e45b3f051fcda9353b098b7086e762ffe7ba9242f7d7c8bf6523faaa8b1e9',
|
||||||
|
"tor_x86_pie": 'd1d96d8ce1a4b68accf04850185780d10cd5563d3552f7e1f040f8ca32cb4e51',
|
||||||
|
"geoip" : '8239b98374493529a29096e45fc5877d4d6fdad0146ad8380b291f90d61484ea'
|
||||||
|
]
|
||||||
|
|
||||||
|
def verifyOrDeleteBinary(name, chksum, alreadyVerified) {
|
||||||
|
return tasks.create("verifyOrDeleteBinary${name}", VerifyOrDelete) {
|
||||||
|
src "${torBinaryDir}/${name}.zip"
|
||||||
|
algorithm 'SHA-256'
|
||||||
|
checksum chksum
|
||||||
|
result alreadyVerified
|
||||||
|
onlyIf {
|
||||||
|
src.exists()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
def downloadBinary(name, chksum, alreadyVerified) {
|
||||||
|
return tasks.create([
|
||||||
|
name: "downloadBinary${name}",
|
||||||
|
type: Download,
|
||||||
|
dependsOn: verifyOrDeleteBinary(name, chksum, alreadyVerified)]) {
|
||||||
|
src "${torDownloadUrl}${name}.zip"
|
||||||
|
.replace('tor_', "tor-${torVersion}-")
|
||||||
|
.replace('geoip', "geoip-${geoipVersion}")
|
||||||
|
.replaceAll('_', '-')
|
||||||
|
dest "${torBinaryDir}/${name}.zip"
|
||||||
|
onlyIf {
|
||||||
|
!dest.exists()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
def verifyBinary(name, chksum) {
|
||||||
|
boolean[] alreadyVerified = [false]
|
||||||
|
return tasks.create([
|
||||||
|
name : "verifyBinary${name}",
|
||||||
|
type : Verify,
|
||||||
|
dependsOn: downloadBinary(name, chksum, alreadyVerified)]) {
|
||||||
|
src "${torBinaryDir}/${name}.zip"
|
||||||
|
algorithm 'SHA-256'
|
||||||
|
checksum chksum
|
||||||
|
onlyIf {
|
||||||
|
!alreadyVerified[0]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
project.afterEvaluate {
|
||||||
|
torBinaries.every { name, checksum ->
|
||||||
|
preBuild.dependsOn.add(verifyBinary(name, checksum))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class VerifyOrDelete extends Verify {
|
||||||
|
|
||||||
|
boolean[] result
|
||||||
|
|
||||||
|
@TaskAction
|
||||||
|
@Override
|
||||||
|
void verify() throws IOException, NoSuchAlgorithmException {
|
||||||
|
try {
|
||||||
|
super.verify()
|
||||||
|
result[0] = true
|
||||||
|
} catch (Exception e) {
|
||||||
|
println "${src} failed verification - deleting"
|
||||||
|
src.delete()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
BIN
bramble-android/libs/jtorctl-briar.jar
Normal file
BIN
bramble-android/libs/jtorctl-briar.jar
Normal file
Binary file not shown.
@@ -1,10 +1,12 @@
|
|||||||
package org.briarproject.bramble;
|
package org.briarproject.bramble;
|
||||||
|
|
||||||
|
import org.briarproject.bramble.plugin.AndroidPluginModule;
|
||||||
import org.briarproject.bramble.system.AndroidSystemModule;
|
import org.briarproject.bramble.system.AndroidSystemModule;
|
||||||
|
|
||||||
import dagger.Module;
|
import dagger.Module;
|
||||||
|
|
||||||
@Module(includes = {
|
@Module(includes = {
|
||||||
|
AndroidPluginModule.class,
|
||||||
AndroidSystemModule.class
|
AndroidSystemModule.class
|
||||||
})
|
})
|
||||||
public class BrambleAndroidModule {
|
public class BrambleAndroidModule {
|
||||||
|
|||||||
@@ -0,0 +1,69 @@
|
|||||||
|
package org.briarproject.bramble.plugin;
|
||||||
|
|
||||||
|
import android.app.Application;
|
||||||
|
import android.content.Context;
|
||||||
|
|
||||||
|
import org.briarproject.bramble.api.event.EventBus;
|
||||||
|
import org.briarproject.bramble.api.lifecycle.IoExecutor;
|
||||||
|
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||||
|
import org.briarproject.bramble.api.plugin.BackoffFactory;
|
||||||
|
import org.briarproject.bramble.api.plugin.PluginConfig;
|
||||||
|
import org.briarproject.bramble.api.plugin.duplex.DuplexPluginFactory;
|
||||||
|
import org.briarproject.bramble.api.plugin.simplex.SimplexPluginFactory;
|
||||||
|
import org.briarproject.bramble.api.reporting.DevReporter;
|
||||||
|
import org.briarproject.bramble.api.system.AndroidExecutor;
|
||||||
|
import org.briarproject.bramble.api.system.LocationUtils;
|
||||||
|
import org.briarproject.bramble.api.system.Scheduler;
|
||||||
|
import org.briarproject.bramble.plugin.bluetooth.AndroidBluetoothPluginFactory;
|
||||||
|
import org.briarproject.bramble.plugin.tcp.AndroidLanTcpPluginFactory;
|
||||||
|
import org.briarproject.bramble.plugin.tor.TorPluginFactory;
|
||||||
|
|
||||||
|
import java.security.SecureRandom;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.concurrent.Executor;
|
||||||
|
import java.util.concurrent.ScheduledExecutorService;
|
||||||
|
|
||||||
|
import javax.net.SocketFactory;
|
||||||
|
|
||||||
|
import dagger.Module;
|
||||||
|
import dagger.Provides;
|
||||||
|
|
||||||
|
@Module
|
||||||
|
public class AndroidPluginModule {
|
||||||
|
|
||||||
|
@Provides
|
||||||
|
PluginConfig providePluginConfig(@IoExecutor Executor ioExecutor,
|
||||||
|
@Scheduler ScheduledExecutorService scheduler,
|
||||||
|
AndroidExecutor androidExecutor, SecureRandom random,
|
||||||
|
SocketFactory torSocketFactory, BackoffFactory backoffFactory,
|
||||||
|
Application app, LocationUtils locationUtils, DevReporter reporter,
|
||||||
|
EventBus eventBus) {
|
||||||
|
Context appContext = app.getApplicationContext();
|
||||||
|
DuplexPluginFactory bluetooth =
|
||||||
|
new AndroidBluetoothPluginFactory(ioExecutor, androidExecutor,
|
||||||
|
appContext, random, eventBus, backoffFactory);
|
||||||
|
DuplexPluginFactory tor = new TorPluginFactory(ioExecutor, scheduler,
|
||||||
|
appContext, locationUtils, reporter, eventBus,
|
||||||
|
torSocketFactory, backoffFactory);
|
||||||
|
DuplexPluginFactory lan = new AndroidLanTcpPluginFactory(ioExecutor,
|
||||||
|
scheduler, backoffFactory, appContext);
|
||||||
|
Collection<DuplexPluginFactory> duplex =
|
||||||
|
Arrays.asList(bluetooth, tor, lan);
|
||||||
|
@NotNullByDefault
|
||||||
|
PluginConfig pluginConfig = new PluginConfig() {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Collection<DuplexPluginFactory> getDuplexFactories() {
|
||||||
|
return duplex;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Collection<SimplexPluginFactory> getSimplexFactories() {
|
||||||
|
return Collections.emptyList();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
return pluginConfig;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -32,9 +32,11 @@ import org.briarproject.bramble.api.plugin.duplex.DuplexPlugin;
|
|||||||
import org.briarproject.bramble.api.plugin.duplex.DuplexPluginCallback;
|
import org.briarproject.bramble.api.plugin.duplex.DuplexPluginCallback;
|
||||||
import org.briarproject.bramble.api.plugin.duplex.DuplexTransportConnection;
|
import org.briarproject.bramble.api.plugin.duplex.DuplexTransportConnection;
|
||||||
import org.briarproject.bramble.api.properties.TransportProperties;
|
import org.briarproject.bramble.api.properties.TransportProperties;
|
||||||
|
import org.briarproject.bramble.api.reporting.DevReporter;
|
||||||
import org.briarproject.bramble.api.settings.Settings;
|
import org.briarproject.bramble.api.settings.Settings;
|
||||||
import org.briarproject.bramble.api.settings.event.SettingsUpdatedEvent;
|
import org.briarproject.bramble.api.settings.event.SettingsUpdatedEvent;
|
||||||
import org.briarproject.bramble.api.system.LocationUtils;
|
import org.briarproject.bramble.api.system.LocationUtils;
|
||||||
|
import org.briarproject.bramble.util.AndroidUtils;
|
||||||
import org.briarproject.bramble.util.IoUtils;
|
import org.briarproject.bramble.util.IoUtils;
|
||||||
import org.briarproject.bramble.util.StringUtils;
|
import org.briarproject.bramble.util.StringUtils;
|
||||||
|
|
||||||
@@ -50,6 +52,7 @@ import java.net.InetSocketAddress;
|
|||||||
import java.net.ServerSocket;
|
import java.net.ServerSocket;
|
||||||
import java.net.Socket;
|
import java.net.Socket;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
|
import java.util.Collection;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
@@ -111,6 +114,7 @@ class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
|
|||||||
private final ScheduledExecutorService scheduler;
|
private final ScheduledExecutorService scheduler;
|
||||||
private final Context appContext;
|
private final Context appContext;
|
||||||
private final LocationUtils locationUtils;
|
private final LocationUtils locationUtils;
|
||||||
|
private final DevReporter reporter;
|
||||||
private final SocketFactory torSocketFactory;
|
private final SocketFactory torSocketFactory;
|
||||||
private final Backoff backoff;
|
private final Backoff backoff;
|
||||||
private final DuplexPluginCallback callback;
|
private final DuplexPluginCallback callback;
|
||||||
@@ -132,13 +136,14 @@ class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
|
|||||||
|
|
||||||
TorPlugin(Executor ioExecutor, ScheduledExecutorService scheduler,
|
TorPlugin(Executor ioExecutor, ScheduledExecutorService scheduler,
|
||||||
Context appContext, LocationUtils locationUtils,
|
Context appContext, LocationUtils locationUtils,
|
||||||
SocketFactory torSocketFactory, Backoff backoff,
|
DevReporter reporter, SocketFactory torSocketFactory,
|
||||||
DuplexPluginCallback callback, String architecture,
|
Backoff backoff, DuplexPluginCallback callback,
|
||||||
int maxLatency, int maxIdleTime) {
|
String architecture, int maxLatency, int maxIdleTime) {
|
||||||
this.ioExecutor = ioExecutor;
|
this.ioExecutor = ioExecutor;
|
||||||
this.scheduler = scheduler;
|
this.scheduler = scheduler;
|
||||||
this.appContext = appContext;
|
this.appContext = appContext;
|
||||||
this.locationUtils = locationUtils;
|
this.locationUtils = locationUtils;
|
||||||
|
this.reporter = reporter;
|
||||||
this.torSocketFactory = torSocketFactory;
|
this.torSocketFactory = torSocketFactory;
|
||||||
this.backoff = backoff;
|
this.backoff = backoff;
|
||||||
this.callback = callback;
|
this.callback = callback;
|
||||||
@@ -333,7 +338,7 @@ class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
|
|||||||
return zin;
|
return zin;
|
||||||
}
|
}
|
||||||
|
|
||||||
private InputStream getConfigInputStream() {
|
private InputStream getConfigInputStream() throws IOException {
|
||||||
int resId = getResourceId("torrc");
|
int resId = getResourceId("torrc");
|
||||||
return appContext.getResources().openRawResource(resId);
|
return appContext.getResources().openRawResource(resId);
|
||||||
}
|
}
|
||||||
@@ -384,6 +389,14 @@ class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void sendDevReports() {
|
||||||
|
ioExecutor.execute(() -> {
|
||||||
|
// TODO: Trigger this with a TransportEnabledEvent
|
||||||
|
File reportDir = AndroidUtils.getReportDir(appContext);
|
||||||
|
reporter.sendReports(reportDir);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
private void bind() {
|
private void bind() {
|
||||||
ioExecutor.execute(() -> {
|
ioExecutor.execute(() -> {
|
||||||
// If there's already a port number stored in config, reuse it
|
// If there's already a port number stored in config, reuse it
|
||||||
@@ -498,7 +511,7 @@ class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void stop() {
|
public void stop() throws PluginException {
|
||||||
running = false;
|
running = false;
|
||||||
tryToClose(socket);
|
tryToClose(socket);
|
||||||
if (networkStateReceiver != null)
|
if (networkStateReceiver != null)
|
||||||
@@ -532,16 +545,20 @@ class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void poll(Map<ContactId, TransportProperties> contacts) {
|
public void poll(Collection<ContactId> connected) {
|
||||||
if (!isRunning()) return;
|
if (!isRunning()) return;
|
||||||
backoff.increment();
|
backoff.increment();
|
||||||
for (Entry<ContactId, TransportProperties> e : contacts.entrySet()) {
|
Map<ContactId, TransportProperties> remote =
|
||||||
connectAndCallBack(e.getKey(), e.getValue());
|
callback.getRemoteProperties();
|
||||||
|
for (Entry<ContactId, TransportProperties> e : remote.entrySet()) {
|
||||||
|
ContactId c = e.getKey();
|
||||||
|
if (!connected.contains(c)) connectAndCallBack(c, e.getValue());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void connectAndCallBack(ContactId c, TransportProperties p) {
|
private void connectAndCallBack(ContactId c, TransportProperties p) {
|
||||||
ioExecutor.execute(() -> {
|
ioExecutor.execute(() -> {
|
||||||
|
if (!isRunning()) return;
|
||||||
DuplexTransportConnection d = createConnection(p);
|
DuplexTransportConnection d = createConnection(p);
|
||||||
if (d != null) {
|
if (d != null) {
|
||||||
backoff.reset();
|
backoff.reset();
|
||||||
@@ -551,8 +568,13 @@ class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public DuplexTransportConnection createConnection(TransportProperties p) {
|
public DuplexTransportConnection createConnection(ContactId c) {
|
||||||
if (!isRunning()) return null;
|
if (!isRunning()) return null;
|
||||||
|
return createConnection(callback.getRemoteProperties(c));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
private DuplexTransportConnection createConnection(TransportProperties p) {
|
||||||
String onion = p.get(PROP_ONION);
|
String onion = p.get(PROP_ONION);
|
||||||
if (StringUtils.isNullOrEmpty(onion)) return null;
|
if (StringUtils.isNullOrEmpty(onion)) return null;
|
||||||
if (!ONION.matcher(onion).matches()) {
|
if (!ONION.matcher(onion).matches()) {
|
||||||
@@ -602,7 +624,10 @@ class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
|
|||||||
connectionStatus.getAndSetCircuitBuilt()) {
|
connectionStatus.getAndSetCircuitBuilt()) {
|
||||||
LOG.info("First circuit built");
|
LOG.info("First circuit built");
|
||||||
backoff.reset();
|
backoff.reset();
|
||||||
if (isRunning()) callback.transportEnabled();
|
if (isRunning()) {
|
||||||
|
sendDevReports();
|
||||||
|
callback.transportEnabled();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -631,7 +656,10 @@ class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
|
|||||||
if (severity.equals("NOTICE") && msg.startsWith("Bootstrapped 100%")) {
|
if (severity.equals("NOTICE") && msg.startsWith("Bootstrapped 100%")) {
|
||||||
connectionStatus.setBootstrapped();
|
connectionStatus.setBootstrapped();
|
||||||
backoff.reset();
|
backoff.reset();
|
||||||
if (isRunning()) callback.transportEnabled();
|
if (isRunning()) {
|
||||||
|
sendDevReports();
|
||||||
|
callback.transportEnabled();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ import org.briarproject.bramble.api.plugin.TransportId;
|
|||||||
import org.briarproject.bramble.api.plugin.duplex.DuplexPlugin;
|
import org.briarproject.bramble.api.plugin.duplex.DuplexPlugin;
|
||||||
import org.briarproject.bramble.api.plugin.duplex.DuplexPluginCallback;
|
import org.briarproject.bramble.api.plugin.duplex.DuplexPluginCallback;
|
||||||
import org.briarproject.bramble.api.plugin.duplex.DuplexPluginFactory;
|
import org.briarproject.bramble.api.plugin.duplex.DuplexPluginFactory;
|
||||||
|
import org.briarproject.bramble.api.reporting.DevReporter;
|
||||||
import org.briarproject.bramble.api.system.LocationUtils;
|
import org.briarproject.bramble.api.system.LocationUtils;
|
||||||
import org.briarproject.bramble.util.AndroidUtils;
|
import org.briarproject.bramble.util.AndroidUtils;
|
||||||
|
|
||||||
@@ -39,18 +40,21 @@ public class TorPluginFactory implements DuplexPluginFactory {
|
|||||||
private final ScheduledExecutorService scheduler;
|
private final ScheduledExecutorService scheduler;
|
||||||
private final Context appContext;
|
private final Context appContext;
|
||||||
private final LocationUtils locationUtils;
|
private final LocationUtils locationUtils;
|
||||||
|
private final DevReporter reporter;
|
||||||
private final EventBus eventBus;
|
private final EventBus eventBus;
|
||||||
private final SocketFactory torSocketFactory;
|
private final SocketFactory torSocketFactory;
|
||||||
private final BackoffFactory backoffFactory;
|
private final BackoffFactory backoffFactory;
|
||||||
|
|
||||||
public TorPluginFactory(Executor ioExecutor,
|
public TorPluginFactory(Executor ioExecutor,
|
||||||
ScheduledExecutorService scheduler, Context appContext,
|
ScheduledExecutorService scheduler, Context appContext,
|
||||||
LocationUtils locationUtils, EventBus eventBus,
|
LocationUtils locationUtils, DevReporter reporter,
|
||||||
SocketFactory torSocketFactory, BackoffFactory backoffFactory) {
|
EventBus eventBus, SocketFactory torSocketFactory,
|
||||||
|
BackoffFactory backoffFactory) {
|
||||||
this.ioExecutor = ioExecutor;
|
this.ioExecutor = ioExecutor;
|
||||||
this.scheduler = scheduler;
|
this.scheduler = scheduler;
|
||||||
this.appContext = appContext;
|
this.appContext = appContext;
|
||||||
this.locationUtils = locationUtils;
|
this.locationUtils = locationUtils;
|
||||||
|
this.reporter = reporter;
|
||||||
this.eventBus = eventBus;
|
this.eventBus = eventBus;
|
||||||
this.torSocketFactory = torSocketFactory;
|
this.torSocketFactory = torSocketFactory;
|
||||||
this.backoffFactory = backoffFactory;
|
this.backoffFactory = backoffFactory;
|
||||||
@@ -90,7 +94,7 @@ public class TorPluginFactory implements DuplexPluginFactory {
|
|||||||
Backoff backoff = backoffFactory.createBackoff(MIN_POLLING_INTERVAL,
|
Backoff backoff = backoffFactory.createBackoff(MIN_POLLING_INTERVAL,
|
||||||
MAX_POLLING_INTERVAL, BACKOFF_BASE);
|
MAX_POLLING_INTERVAL, BACKOFF_BASE);
|
||||||
TorPlugin plugin = new TorPlugin(ioExecutor, scheduler, appContext,
|
TorPlugin plugin = new TorPlugin(ioExecutor, scheduler, appContext,
|
||||||
locationUtils, torSocketFactory, backoff, callback,
|
locationUtils, reporter, torSocketFactory, backoff, callback,
|
||||||
architecture, MAX_LATENCY, MAX_IDLE_TIME);
|
architecture, MAX_LATENCY, MAX_IDLE_TIME);
|
||||||
eventBus.addListener(plugin);
|
eventBus.addListener(plugin);
|
||||||
return plugin;
|
return plugin;
|
||||||
|
|||||||
@@ -9,7 +9,6 @@ import android.net.wifi.WifiConfiguration;
|
|||||||
import android.net.wifi.WifiManager;
|
import android.net.wifi.WifiManager;
|
||||||
import android.os.Build;
|
import android.os.Build;
|
||||||
import android.os.Parcel;
|
import android.os.Parcel;
|
||||||
import android.os.StrictMode;
|
|
||||||
import android.provider.Settings;
|
import android.provider.Settings;
|
||||||
|
|
||||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||||
@@ -67,12 +66,9 @@ class AndroidSecureRandomProvider extends LinuxSecureRandomProvider {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void writeSeed() {
|
protected void writeSeed() {
|
||||||
// Silence strict mode
|
|
||||||
StrictMode.ThreadPolicy tp = StrictMode.allowThreadDiskWrites();
|
|
||||||
super.writeSeed();
|
super.writeSeed();
|
||||||
if (Build.VERSION.SDK_INT >= 16 && Build.VERSION.SDK_INT <= 18)
|
if (Build.VERSION.SDK_INT >= 16 && Build.VERSION.SDK_INT <= 18)
|
||||||
applyOpenSslFix();
|
applyOpenSslFix();
|
||||||
StrictMode.setThreadPolicy(tp);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Based on https://android-developers.googleblog.com/2013/08/some-securerandom-thoughts.html
|
// Based on https://android-developers.googleblog.com/2013/08/some-securerandom-thoughts.html
|
||||||
|
|||||||
@@ -1,9 +1,7 @@
|
|||||||
package org.briarproject.bramble.util;
|
package org.briarproject.bramble.util;
|
||||||
|
|
||||||
import android.annotation.SuppressLint;
|
|
||||||
import android.bluetooth.BluetoothAdapter;
|
import android.bluetooth.BluetoothAdapter;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.SharedPreferences;
|
|
||||||
import android.os.Build;
|
import android.os.Build;
|
||||||
import android.provider.Settings;
|
import android.provider.Settings;
|
||||||
|
|
||||||
@@ -12,15 +10,11 @@ import java.util.ArrayList;
|
|||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.logging.Logger;
|
|
||||||
|
|
||||||
import static android.content.Context.MODE_PRIVATE;
|
import static android.content.Context.MODE_PRIVATE;
|
||||||
|
|
||||||
public class AndroidUtils {
|
public class AndroidUtils {
|
||||||
|
|
||||||
private static final Logger LOG =
|
|
||||||
Logger.getLogger(AndroidUtils.class.getName());
|
|
||||||
|
|
||||||
// Fake Bluetooth address returned by BluetoothAdapter on API 23 and later
|
// 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 FAKE_BLUETOOTH_ADDRESS = "02:00:00:00:00:00";
|
||||||
|
|
||||||
@@ -41,7 +35,6 @@ public class AndroidUtils {
|
|||||||
public static String getBluetoothAddress(Context ctx,
|
public static String getBluetoothAddress(Context ctx,
|
||||||
BluetoothAdapter adapter) {
|
BluetoothAdapter adapter) {
|
||||||
// Return the adapter's address if it's valid and not fake
|
// Return the adapter's address if it's valid and not fake
|
||||||
@SuppressLint("HardwareIds")
|
|
||||||
String address = adapter.getAddress();
|
String address = adapter.getAddress();
|
||||||
if (isValidBluetoothAddress(address)) return address;
|
if (isValidBluetoothAddress(address)) return address;
|
||||||
// Return the address from settings if it's valid and not fake
|
// Return the address from settings if it's valid and not fake
|
||||||
@@ -58,28 +51,17 @@ public class AndroidUtils {
|
|||||||
&& !address.equals(FAKE_BLUETOOTH_ADDRESS);
|
&& !address.equals(FAKE_BLUETOOTH_ADDRESS);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void deleteAppData(Context ctx, SharedPreferences... clear) {
|
public static void deleteAppData(Context ctx) {
|
||||||
// Clear and commit shared preferences
|
|
||||||
for (SharedPreferences prefs : clear) {
|
|
||||||
if (!prefs.edit().clear().commit())
|
|
||||||
LOG.warning("Could not clear shared preferences");
|
|
||||||
}
|
|
||||||
// Delete files, except lib and shared_prefs directories
|
|
||||||
File dataDir = new File(ctx.getApplicationInfo().dataDir);
|
File dataDir = new File(ctx.getApplicationInfo().dataDir);
|
||||||
File[] children = dataDir.listFiles();
|
File[] children = dataDir.listFiles();
|
||||||
if (children == null) {
|
if (children != null) {
|
||||||
LOG.warning("Could not list files in app data dir");
|
|
||||||
} else {
|
|
||||||
for (File child : children) {
|
for (File child : children) {
|
||||||
String name = child.getName();
|
if (!child.getName().equals("lib"))
|
||||||
if (!name.equals("lib") && !name.equals("shared_prefs")) {
|
|
||||||
IoUtils.deleteFileOrDir(child);
|
IoUtils.deleteFileOrDir(child);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Recreate the cache dir as some OpenGL drivers expect it to exist
|
// Recreate the cache dir as some OpenGL drivers expect it to exist
|
||||||
if (!new File(dataDir, "cache").mkdir())
|
new File(dataDir, "cache").mkdir();
|
||||||
LOG.warning("Could not recreate cache dir");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static File getReportDir(Context ctx) {
|
public static File getReportDir(Context ctx) {
|
||||||
|
|||||||
@@ -2,7 +2,6 @@ apply plugin: 'java-library'
|
|||||||
sourceCompatibility = 1.8
|
sourceCompatibility = 1.8
|
||||||
targetCompatibility = 1.8
|
targetCompatibility = 1.8
|
||||||
|
|
||||||
apply plugin: 'ru.vyarus.animalsniffer'
|
|
||||||
apply plugin: 'witness'
|
apply plugin: 'witness'
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
@@ -15,8 +14,6 @@ dependencies {
|
|||||||
testImplementation "org.jmock:jmock-legacy:2.8.2"
|
testImplementation "org.jmock:jmock-legacy:2.8.2"
|
||||||
testImplementation "org.hamcrest:hamcrest-library:1.3"
|
testImplementation "org.hamcrest:hamcrest-library:1.3"
|
||||||
testImplementation "org.hamcrest:hamcrest-core:1.3"
|
testImplementation "org.hamcrest:hamcrest-core:1.3"
|
||||||
|
|
||||||
signature 'org.codehaus.mojo.signature:java16:1.1@signature'
|
|
||||||
}
|
}
|
||||||
|
|
||||||
dependencyVerification {
|
dependencyVerification {
|
||||||
@@ -29,9 +26,6 @@ dependencyVerification {
|
|||||||
'org.apache.ant:ant-launcher:1.9.4:ant-launcher-1.9.4.jar:7bccea20b41801ca17bcbc909a78c835d0f443f12d639c77bd6ae3d05861608d',
|
'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.ant:ant:1.9.4:ant-1.9.4.jar:649ae0730251de07b8913f49286d46bba7b92d47c5f332610aa426c4f02161d8',
|
||||||
'org.beanshell:bsh:1.3.0:bsh-1.3.0.jar:9b04edc75d19db54f1b4e8b5355e9364384c6cf71eb0a1b9724c159d779879f8',
|
'org.beanshell:bsh:1.3.0:bsh-1.3.0.jar:9b04edc75d19db54f1b4e8b5355e9364384c6cf71eb0a1b9724c159d779879f8',
|
||||||
'org.codehaus.mojo.signature:java16:1.1:java16-1.1.signature:53799223a2c98dba2d0add810bed76315460df285c69e4f397ae6098f87dd619',
|
|
||||||
'org.codehaus.mojo:animal-sniffer-ant-tasks:1.16:animal-sniffer-ant-tasks-1.16.jar:890040976fbe2d584619a6a61b1fd2e925b3b5eb342a85eb2762c467c0d64e90',
|
|
||||||
'org.codehaus.mojo:animal-sniffer:1.16:animal-sniffer-1.16.jar:72be8bcc226ba43b937c722a08a07852bfa1b11400089265d5df0ee7b38b1d52',
|
|
||||||
'org.hamcrest:hamcrest-core:1.3:hamcrest-core-1.3.jar:66fdef91e9739348df7a096aa384a5685f4e875584cce89386a7a47251c4d8e9',
|
'org.hamcrest:hamcrest-core:1.3:hamcrest-core-1.3.jar:66fdef91e9739348df7a096aa384a5685f4e875584cce89386a7a47251c4d8e9',
|
||||||
'org.hamcrest:hamcrest-library:1.3:hamcrest-library-1.3.jar:711d64522f9ec410983bd310934296da134be4254a125080a0416ec178dfad1c',
|
'org.hamcrest:hamcrest-library:1.3:hamcrest-library-1.3.jar:711d64522f9ec410983bd310934296da134be4254a125080a0416ec178dfad1c',
|
||||||
'org.jmock:jmock-junit4:2.8.2:jmock-junit4-2.8.2.jar:f7ee4df4f7bd7b7f1cafad3b99eb74d579f109d5992ff625347352edb55e674c',
|
'org.jmock:jmock-junit4:2.8.2:jmock-junit4-2.8.2.jar:f7ee4df4f7bd7b7f1cafad3b99eb74d579f109d5992ff625347352edb55e674c',
|
||||||
@@ -39,7 +33,6 @@ dependencyVerification {
|
|||||||
'org.jmock:jmock-testjar:2.8.2:jmock-testjar-2.8.2.jar:8900860f72c474e027cf97fe78dcbf154a1aa7fc62b6845c5fb4e4f3c7bc8760',
|
'org.jmock:jmock-testjar:2.8.2:jmock-testjar-2.8.2.jar:8900860f72c474e027cf97fe78dcbf154a1aa7fc62b6845c5fb4e4f3c7bc8760',
|
||||||
'org.jmock:jmock:2.8.2:jmock-2.8.2.jar:6c73cb4a2e6dbfb61fd99c9a768539c170ab6568e57846bd60dbf19596b65b16',
|
'org.jmock:jmock:2.8.2:jmock-2.8.2.jar:6c73cb4a2e6dbfb61fd99c9a768539c170ab6568e57846bd60dbf19596b65b16',
|
||||||
'org.objenesis:objenesis:2.1:objenesis-2.1.jar:c74330cc6b806c804fd37e74487b4fe5d7c2750c5e15fbc6efa13bdee1bdef80',
|
'org.objenesis:objenesis:2.1:objenesis-2.1.jar:c74330cc6b806c804fd37e74487b4fe5d7c2750c5e15fbc6efa13bdee1bdef80',
|
||||||
'org.ow2.asm:asm-all:5.2:asm-all-5.2.jar:7fbffbc1db3422e2101689fd88df8384b15817b52b9b2b267b9f6d2511dc198d',
|
|
||||||
'org.ow2.asm:asm:5.0.4:asm-5.0.4.jar:896618ed8ae62702521a78bc7be42b7c491a08e6920a15f89a3ecdec31e9a220',
|
'org.ow2.asm:asm:5.0.4:asm-5.0.4.jar:896618ed8ae62702521a78bc7be42b7c491a08e6920a15f89a3ecdec31e9a220',
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
@@ -55,3 +48,8 @@ task jarTest(type: Jar, dependsOn: testClasses) {
|
|||||||
artifacts {
|
artifacts {
|
||||||
testOutput jarTest
|
testOutput jarTest
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If a Java 6 JRE is available, check we're not using any Java 7 or 8 APIs
|
||||||
|
tasks.withType(JavaCompile) {
|
||||||
|
useJava6StandardLibrary(it)
|
||||||
|
}
|
||||||
|
|||||||
@@ -45,9 +45,9 @@ public interface ContactManager {
|
|||||||
*
|
*
|
||||||
* @param alice true if the local party is Alice
|
* @param alice true if the local party is Alice
|
||||||
*/
|
*/
|
||||||
ContactId addContact(Author remote, AuthorId local, SecretKey master,
|
ContactId addContact(Author remote, AuthorId local,
|
||||||
long timestamp, boolean alice, boolean verified, boolean active)
|
SecretKey master, long timestamp, boolean alice, boolean verified,
|
||||||
throws DbException;
|
boolean active) throws DbException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the contact with the given ID.
|
* Returns the contact with the given ID.
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
|||||||
import javax.annotation.concurrent.Immutable;
|
import javax.annotation.concurrent.Immutable;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A key pair consisting of a {@link PublicKey} and a {@link PrivateKey}.
|
* A key pair consisting of a {@link PublicKey} and a {@link PrivateKey).
|
||||||
*/
|
*/
|
||||||
@Immutable
|
@Immutable
|
||||||
@NotNullByDefault
|
@NotNullByDefault
|
||||||
|
|||||||
@@ -8,7 +8,6 @@ import java.io.IOException;
|
|||||||
public interface BdfReader {
|
public interface BdfReader {
|
||||||
|
|
||||||
int DEFAULT_NESTED_LIMIT = 5;
|
int DEFAULT_NESTED_LIMIT = 5;
|
||||||
int DEFAULT_MAX_BUFFER_SIZE = 64 * 1024;
|
|
||||||
|
|
||||||
boolean eof() throws IOException;
|
boolean eof() throws IOException;
|
||||||
|
|
||||||
@@ -40,13 +39,13 @@ public interface BdfReader {
|
|||||||
|
|
||||||
boolean hasString() throws IOException;
|
boolean hasString() throws IOException;
|
||||||
|
|
||||||
String readString() throws IOException;
|
String readString(int maxLength) throws IOException;
|
||||||
|
|
||||||
void skipString() throws IOException;
|
void skipString() throws IOException;
|
||||||
|
|
||||||
boolean hasRaw() throws IOException;
|
boolean hasRaw() throws IOException;
|
||||||
|
|
||||||
byte[] readRaw() throws IOException;
|
byte[] readRaw(int maxLength) throws IOException;
|
||||||
|
|
||||||
void skipRaw() throws IOException;
|
void skipRaw() throws IOException;
|
||||||
|
|
||||||
|
|||||||
@@ -9,6 +9,5 @@ public interface BdfReaderFactory {
|
|||||||
|
|
||||||
BdfReader createReader(InputStream in);
|
BdfReader createReader(InputStream in);
|
||||||
|
|
||||||
BdfReader createReader(InputStream in, int nestedLimit,
|
BdfReader createReader(InputStream in, int nestedLimit);
|
||||||
int maxBufferSize);
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -104,12 +104,18 @@ public interface DatabaseComponent {
|
|||||||
throws DbException;
|
throws DbException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Stores the given transport keys for the given contact and returns a
|
* Stores the given transport keys, optionally binding them to the given
|
||||||
* key set ID.
|
* contact, and returns a key set ID.
|
||||||
*/
|
*/
|
||||||
KeySetId addTransportKeys(Transaction txn, ContactId c,
|
KeySetId addTransportKeys(Transaction txn, @Nullable ContactId c,
|
||||||
TransportKeys k) throws DbException;
|
TransportKeys k) throws DbException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Binds the given keys for the given transport to the given contact.
|
||||||
|
*/
|
||||||
|
void bindTransportKeys(Transaction txn, ContactId c, TransportId t,
|
||||||
|
KeySetId k) throws DbException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns true if the database contains the given contact for the given
|
* Returns true if the database contains the given contact for the given
|
||||||
* local pseudonym.
|
* local pseudonym.
|
||||||
|
|||||||
@@ -14,8 +14,6 @@ public interface DatabaseConfig {
|
|||||||
|
|
||||||
File getDatabaseDirectory();
|
File getDatabaseDirectory();
|
||||||
|
|
||||||
File getDatabaseKeyDirectory();
|
|
||||||
|
|
||||||
void setEncryptionKey(SecretKey key);
|
void setEncryptionKey(SecretKey key);
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
|
|||||||
@@ -1,6 +0,0 @@
|
|||||||
package org.briarproject.bramble.api.plugin;
|
|
||||||
|
|
||||||
public interface FileConstants {
|
|
||||||
|
|
||||||
String PROP_PATH = "path";
|
|
||||||
}
|
|
||||||
@@ -2,9 +2,8 @@ package org.briarproject.bramble.api.plugin;
|
|||||||
|
|
||||||
import org.briarproject.bramble.api.contact.ContactId;
|
import org.briarproject.bramble.api.contact.ContactId;
|
||||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||||
import org.briarproject.bramble.api.properties.TransportProperties;
|
|
||||||
|
|
||||||
import java.util.Map;
|
import java.util.Collection;
|
||||||
|
|
||||||
@NotNullByDefault
|
@NotNullByDefault
|
||||||
public interface Plugin {
|
public interface Plugin {
|
||||||
@@ -40,19 +39,21 @@ public interface Plugin {
|
|||||||
boolean isRunning();
|
boolean isRunning();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns true if the plugin should be polled periodically to attempt to
|
* Returns true if the plugin's {@link #poll(Collection)} method should be
|
||||||
* establish connections.
|
* called periodically to attempt to establish connections.
|
||||||
*/
|
*/
|
||||||
boolean shouldPoll();
|
boolean shouldPoll();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the desired interval in milliseconds between polling attempts.
|
* Returns the desired interval in milliseconds between calls to the
|
||||||
|
* plugin's {@link #poll(Collection)} method.
|
||||||
*/
|
*/
|
||||||
int getPollingInterval();
|
int getPollingInterval();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Attempts to establish connections to the given contacts, passing any
|
* Attempts to establish connections to contacts, passing any created
|
||||||
* created connections to the callback.
|
* connections to the callback. To avoid creating redundant connections,
|
||||||
|
* the plugin may exclude the given contacts from polling.
|
||||||
*/
|
*/
|
||||||
void poll(Map<ContactId, TransportProperties> contacts);
|
void poll(Collection<ContactId> connected);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,9 +1,12 @@
|
|||||||
package org.briarproject.bramble.api.plugin;
|
package org.briarproject.bramble.api.plugin;
|
||||||
|
|
||||||
|
import org.briarproject.bramble.api.contact.ContactId;
|
||||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||||
import org.briarproject.bramble.api.properties.TransportProperties;
|
import org.briarproject.bramble.api.properties.TransportProperties;
|
||||||
import org.briarproject.bramble.api.settings.Settings;
|
import org.briarproject.bramble.api.settings.Settings;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An interface through which a transport plugin interacts with the rest of
|
* An interface through which a transport plugin interacts with the rest of
|
||||||
* the application.
|
* the application.
|
||||||
@@ -22,7 +25,17 @@ public interface PluginCallback {
|
|||||||
TransportProperties getLocalProperties();
|
TransportProperties getLocalProperties();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Merges the given settings with the plugin's settings
|
* Returns the plugin's remote transport properties.
|
||||||
|
*/
|
||||||
|
Map<ContactId, TransportProperties> getRemoteProperties();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the plugin's remote transport properties for the given contact.
|
||||||
|
*/
|
||||||
|
TransportProperties getRemoteProperties(ContactId c);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Merges the given settings with the namespaced settings
|
||||||
*/
|
*/
|
||||||
void mergeSettings(Settings s);
|
void mergeSettings(Settings s);
|
||||||
|
|
||||||
@@ -32,12 +45,34 @@ public interface PluginCallback {
|
|||||||
void mergeLocalProperties(TransportProperties p);
|
void mergeLocalProperties(TransportProperties p);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Signals that the transport is enabled.
|
* Presents the user with a choice among two or more named options and
|
||||||
|
* returns the user's response. The message may consist of a translatable
|
||||||
|
* format string and arguments.
|
||||||
|
*
|
||||||
|
* @return an index into the array of options indicating the user's choice,
|
||||||
|
* or -1 if the user cancelled the choice.
|
||||||
|
*/
|
||||||
|
int showChoice(String[] options, String... message);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Asks the user to confirm an action and returns the user's response. The
|
||||||
|
* message may consist of a translatable format string and arguments.
|
||||||
|
*/
|
||||||
|
boolean showConfirmationMessage(String... message);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Shows a message to the user. The message may consist of a translatable
|
||||||
|
* format string and arguments.
|
||||||
|
*/
|
||||||
|
void showMessage(String... message);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Signal that the transport got enabled.
|
||||||
*/
|
*/
|
||||||
void transportEnabled();
|
void transportEnabled();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Signals that the transport is disabled.
|
* Signal that the transport got disabled.
|
||||||
*/
|
*/
|
||||||
void transportDisabled();
|
void transportDisabled();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,6 +12,4 @@ public interface PluginConfig {
|
|||||||
Collection<DuplexPluginFactory> getDuplexFactories();
|
Collection<DuplexPluginFactory> getDuplexFactories();
|
||||||
|
|
||||||
Collection<SimplexPluginFactory> getSimplexFactories();
|
Collection<SimplexPluginFactory> getSimplexFactories();
|
||||||
|
|
||||||
boolean shouldPoll();
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,6 +22,11 @@ public interface TransportConnectionWriter {
|
|||||||
*/
|
*/
|
||||||
int getMaxIdleTime();
|
int getMaxIdleTime();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the capacity of the transport connection in bytes.
|
||||||
|
*/
|
||||||
|
long getCapacity();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns an output stream for writing to the transport connection.
|
* Returns an output stream for writing to the transport connection.
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -71,6 +71,11 @@ public abstract class AbstractDuplexTransportConnection
|
|||||||
return plugin.getMaxIdleTime();
|
return plugin.getMaxIdleTime();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public long getCapacity() {
|
||||||
|
return Long.MAX_VALUE;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public OutputStream getOutputStream() throws IOException {
|
public OutputStream getOutputStream() throws IOException {
|
||||||
return AbstractDuplexTransportConnection.this.getOutputStream();
|
return AbstractDuplexTransportConnection.this.getOutputStream();
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
package org.briarproject.bramble.api.plugin.duplex;
|
package org.briarproject.bramble.api.plugin.duplex;
|
||||||
|
|
||||||
|
import org.briarproject.bramble.api.contact.ContactId;
|
||||||
import org.briarproject.bramble.api.data.BdfList;
|
import org.briarproject.bramble.api.data.BdfList;
|
||||||
import org.briarproject.bramble.api.keyagreement.KeyAgreementListener;
|
import org.briarproject.bramble.api.keyagreement.KeyAgreementListener;
|
||||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||||
import org.briarproject.bramble.api.plugin.Plugin;
|
import org.briarproject.bramble.api.plugin.Plugin;
|
||||||
import org.briarproject.bramble.api.properties.TransportProperties;
|
|
||||||
|
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
|
|
||||||
@@ -15,11 +15,12 @@ import javax.annotation.Nullable;
|
|||||||
public interface DuplexPlugin extends Plugin {
|
public interface DuplexPlugin extends Plugin {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Attempts to create and return a connection using the given transport
|
* Attempts to create and return a connection to the given contact using
|
||||||
* properties. Returns null if a connection cannot be created.
|
* the current transport and configuration properties. Returns null if a
|
||||||
|
* connection cannot be created.
|
||||||
*/
|
*/
|
||||||
@Nullable
|
@Nullable
|
||||||
DuplexTransportConnection createConnection(TransportProperties p);
|
DuplexTransportConnection createConnection(ContactId c);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns true if the plugin supports short-range key agreement.
|
* Returns true if the plugin supports short-range key agreement.
|
||||||
|
|||||||
@@ -5,8 +5,7 @@ import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
|||||||
import org.briarproject.bramble.api.plugin.PluginCallback;
|
import org.briarproject.bramble.api.plugin.PluginCallback;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An interface through which a duplex plugin interacts with the rest of the
|
* An interface for handling connections created by a duplex transport plugin.
|
||||||
* application.
|
|
||||||
*/
|
*/
|
||||||
@NotNullByDefault
|
@NotNullByDefault
|
||||||
public interface DuplexPluginCallback extends PluginCallback {
|
public interface DuplexPluginCallback extends PluginCallback {
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
package org.briarproject.bramble.api.plugin.simplex;
|
package org.briarproject.bramble.api.plugin.simplex;
|
||||||
|
|
||||||
|
import org.briarproject.bramble.api.contact.ContactId;
|
||||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||||
import org.briarproject.bramble.api.plugin.Plugin;
|
import org.briarproject.bramble.api.plugin.Plugin;
|
||||||
import org.briarproject.bramble.api.plugin.TransportConnectionReader;
|
import org.briarproject.bramble.api.plugin.TransportConnectionReader;
|
||||||
import org.briarproject.bramble.api.plugin.TransportConnectionWriter;
|
import org.briarproject.bramble.api.plugin.TransportConnectionWriter;
|
||||||
import org.briarproject.bramble.api.properties.TransportProperties;
|
|
||||||
|
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
|
|
||||||
@@ -15,16 +15,18 @@ import javax.annotation.Nullable;
|
|||||||
public interface SimplexPlugin extends Plugin {
|
public interface SimplexPlugin extends Plugin {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Attempts to create and return a reader for the given transport
|
* Attempts to create and return a reader for the given contact using the
|
||||||
* properties. Returns null if a reader cannot be created.
|
* current transport and configuration properties. Returns null if a reader
|
||||||
|
* cannot be created.
|
||||||
*/
|
*/
|
||||||
@Nullable
|
@Nullable
|
||||||
TransportConnectionReader createReader(TransportProperties p);
|
TransportConnectionReader createReader(ContactId c);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Attempts to create and return a writer for the given transport
|
* Attempts to create and return a writer for the given contact using the
|
||||||
* properties. Returns null if a writer cannot be created.
|
* current transport and configuration properties. Returns null if a writer
|
||||||
|
* cannot be created.
|
||||||
*/
|
*/
|
||||||
@Nullable
|
@Nullable
|
||||||
TransportConnectionWriter createWriter(TransportProperties p);
|
TransportConnectionWriter createWriter(ContactId c);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,8 +7,8 @@ import org.briarproject.bramble.api.plugin.TransportConnectionReader;
|
|||||||
import org.briarproject.bramble.api.plugin.TransportConnectionWriter;
|
import org.briarproject.bramble.api.plugin.TransportConnectionWriter;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An interface through which a simplex plugin interacts with the rest of the
|
* An interface for handling readers and writers created by a simplex transport
|
||||||
* application.
|
* plugin.
|
||||||
*/
|
*/
|
||||||
@NotNullByDefault
|
@NotNullByDefault
|
||||||
public interface SimplexPluginCallback extends PluginCallback {
|
public interface SimplexPluginCallback extends PluginCallback {
|
||||||
|
|||||||
@@ -3,14 +3,10 @@ package org.briarproject.bramble.api.reporting;
|
|||||||
import org.briarproject.bramble.api.crypto.PublicKey;
|
import org.briarproject.bramble.api.crypto.PublicKey;
|
||||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||||
|
|
||||||
import java.io.File;
|
|
||||||
|
|
||||||
@NotNullByDefault
|
@NotNullByDefault
|
||||||
public interface DevConfig {
|
public interface DevConfig {
|
||||||
|
|
||||||
PublicKey getDevPublicKey();
|
PublicKey getDevPublicKey();
|
||||||
|
|
||||||
String getDevOnionAddress();
|
String getDevOnionAddress();
|
||||||
|
|
||||||
File getReportDir();
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -23,6 +23,8 @@ public interface DevReporter {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Sends any reports previously stored on disk.
|
* Sends any reports previously stored on disk.
|
||||||
|
*
|
||||||
|
* @param reportDir the directory where reports are stored.
|
||||||
*/
|
*/
|
||||||
void sendReports();
|
void sendReports(File reportDir);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,9 +2,9 @@ package org.briarproject.bramble.api.sync;
|
|||||||
|
|
||||||
import org.briarproject.bramble.api.contact.ContactId;
|
import org.briarproject.bramble.api.contact.ContactId;
|
||||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||||
import org.briarproject.bramble.api.transport.StreamWriter;
|
|
||||||
|
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
|
import java.io.OutputStream;
|
||||||
|
|
||||||
@NotNullByDefault
|
@NotNullByDefault
|
||||||
public interface SyncSessionFactory {
|
public interface SyncSessionFactory {
|
||||||
@@ -12,8 +12,8 @@ public interface SyncSessionFactory {
|
|||||||
SyncSession createIncomingSession(ContactId c, InputStream in);
|
SyncSession createIncomingSession(ContactId c, InputStream in);
|
||||||
|
|
||||||
SyncSession createSimplexOutgoingSession(ContactId c, int maxLatency,
|
SyncSession createSimplexOutgoingSession(ContactId c, int maxLatency,
|
||||||
StreamWriter streamWriter);
|
OutputStream out);
|
||||||
|
|
||||||
SyncSession createDuplexOutgoingSession(ContactId c, int maxLatency,
|
SyncSession createDuplexOutgoingSession(ContactId c, int maxLatency,
|
||||||
int maxIdleTime, StreamWriter streamWriter);
|
int maxIdleTime, OutputStream out);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,12 +7,12 @@ package org.briarproject.bramble.api.system;
|
|||||||
public interface Clock {
|
public interface Clock {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @see System#currentTimeMillis()
|
* @see {@link System#currentTimeMillis()}
|
||||||
*/
|
*/
|
||||||
long currentTimeMillis();
|
long currentTimeMillis();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @see Thread#sleep(long)
|
* @see {@link Thread#sleep(long)}
|
||||||
*/
|
*/
|
||||||
void sleep(long milliseconds) throws InterruptedException;
|
void sleep(long milliseconds) throws InterruptedException;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,24 +19,48 @@ public interface KeyManager {
|
|||||||
/**
|
/**
|
||||||
* Informs the key manager that a new contact has been added. Derives and
|
* Informs the key manager that a new contact has been added. Derives and
|
||||||
* stores a set of transport keys for communicating with the contact over
|
* stores a set of transport keys for communicating with the contact over
|
||||||
* each transport and returns the key set IDs.
|
* each transport.
|
||||||
* <p/>
|
* <p/>
|
||||||
* {@link StreamContext StreamContexts} for the contact can be created
|
* {@link StreamContext StreamContexts} for the contact can be created
|
||||||
* after this method has returned.
|
* after this method has returned.
|
||||||
*
|
*
|
||||||
* @param alice true if the local party is Alice
|
* @param alice true if the local party is Alice
|
||||||
* @param active whether the derived keys can be used for outgoing streams
|
|
||||||
*/
|
*/
|
||||||
Map<TransportId, KeySetId> addContact(Transaction txn, ContactId c,
|
void addContact(Transaction txn, ContactId c, SecretKey master,
|
||||||
SecretKey master, long timestamp, boolean alice, boolean active)
|
long timestamp, boolean alice) throws DbException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Derives and stores a set of unbound transport keys for each transport
|
||||||
|
* and returns the key set IDs.
|
||||||
|
* <p/>
|
||||||
|
* The keys must be bound before they can be used for incoming streams,
|
||||||
|
* and also activated before they can be used for outgoing streams.
|
||||||
|
*
|
||||||
|
* @param alice true if the local party is Alice
|
||||||
|
*/
|
||||||
|
Map<TransportId, KeySetId> addUnboundKeys(Transaction txn, SecretKey master,
|
||||||
|
long timestamp, boolean alice) throws DbException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Binds the given transport keys to the given contact.
|
||||||
|
*/
|
||||||
|
void bindKeys(Transaction txn, ContactId c, Map<TransportId, KeySetId> keys)
|
||||||
throws DbException;
|
throws DbException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Marks the given transport keys as usable for outgoing streams.
|
* Marks the given transport keys as usable for outgoing streams. Keys must
|
||||||
|
* be bound before they are activated.
|
||||||
*/
|
*/
|
||||||
void activateKeys(Transaction txn, Map<TransportId, KeySetId> keys)
|
void activateKeys(Transaction txn, Map<TransportId, KeySetId> keys)
|
||||||
throws DbException;
|
throws DbException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes the given transport keys, which must not have been bound, from
|
||||||
|
* the manager and the database.
|
||||||
|
*/
|
||||||
|
void removeKeys(Transaction txn, Map<TransportId, KeySetId> keys)
|
||||||
|
throws DbException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns true if we have keys that can be used for outgoing streams to
|
* Returns true if we have keys that can be used for outgoing streams to
|
||||||
* the given contact over the given transport.
|
* the given contact over the given transport.
|
||||||
|
|||||||
@@ -3,20 +3,23 @@ package org.briarproject.bramble.api.transport;
|
|||||||
import org.briarproject.bramble.api.contact.ContactId;
|
import org.briarproject.bramble.api.contact.ContactId;
|
||||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||||
|
|
||||||
|
import javax.annotation.Nullable;
|
||||||
import javax.annotation.concurrent.Immutable;
|
import javax.annotation.concurrent.Immutable;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A set of transport keys for communicating with a contact.
|
* A set of transport keys for communicating with a contact. If the keys have
|
||||||
|
* not yet been bound to a contact, {@link #getContactId()}} returns null.
|
||||||
*/
|
*/
|
||||||
@Immutable
|
@Immutable
|
||||||
@NotNullByDefault
|
@NotNullByDefault
|
||||||
public class KeySet {
|
public class KeySet {
|
||||||
|
|
||||||
private final KeySetId keySetId;
|
private final KeySetId keySetId;
|
||||||
|
@Nullable
|
||||||
private final ContactId contactId;
|
private final ContactId contactId;
|
||||||
private final TransportKeys transportKeys;
|
private final TransportKeys transportKeys;
|
||||||
|
|
||||||
public KeySet(KeySetId keySetId, ContactId contactId,
|
public KeySet(KeySetId keySetId, @Nullable ContactId contactId,
|
||||||
TransportKeys transportKeys) {
|
TransportKeys transportKeys) {
|
||||||
this.keySetId = keySetId;
|
this.keySetId = keySetId;
|
||||||
this.contactId = contactId;
|
this.contactId = contactId;
|
||||||
@@ -27,6 +30,7 @@ public class KeySet {
|
|||||||
return keySetId;
|
return keySetId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
public ContactId getContactId() {
|
public ContactId getContactId() {
|
||||||
return contactId;
|
return contactId;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,19 +0,0 @@
|
|||||||
package org.briarproject.bramble.api.transport;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.OutputStream;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* An interface for writing data to a transport connection. Data will be
|
|
||||||
* encrypted and authenticated before being written to the connection.
|
|
||||||
*/
|
|
||||||
public interface StreamWriter {
|
|
||||||
|
|
||||||
OutputStream getOutputStream();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sends the end of stream marker, informing the recipient that no more
|
|
||||||
* data will be sent. The connection is flushed but not closed.
|
|
||||||
*/
|
|
||||||
void sendEndOfStream() throws IOException;
|
|
||||||
}
|
|
||||||
@@ -12,12 +12,12 @@ public interface StreamWriterFactory {
|
|||||||
* Creates an {@link OutputStream OutputStream} for writing to a
|
* Creates an {@link OutputStream OutputStream} for writing to a
|
||||||
* transport stream
|
* transport stream
|
||||||
*/
|
*/
|
||||||
StreamWriter createStreamWriter(OutputStream out, StreamContext ctx);
|
OutputStream createStreamWriter(OutputStream out, StreamContext ctx);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates an {@link OutputStream OutputStream} for writing to a contact
|
* Creates an {@link OutputStream OutputStream} for writing to a contact
|
||||||
* exchange stream.
|
* exchange stream.
|
||||||
*/
|
*/
|
||||||
StreamWriter createContactExchangeStreamWriter(OutputStream out,
|
OutputStream createContactExchangeStreamWriter(OutputStream out,
|
||||||
SecretKey headerKey);
|
SecretKey headerKey);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,26 @@
|
|||||||
|
package org.briarproject.bramble.api.ui;
|
||||||
|
|
||||||
|
public interface UiCallback {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Presents the user with a choice among two or more named options and
|
||||||
|
* returns the user's response. The message may consist of a translatable
|
||||||
|
* format string and arguments.
|
||||||
|
*
|
||||||
|
* @return an index into the array of options indicating the user's choice,
|
||||||
|
* or -1 if the user cancelled the choice.
|
||||||
|
*/
|
||||||
|
int showChoice(String[] options, String... message);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Asks the user to confirm an action and returns the user's response. The
|
||||||
|
* message may consist of a translatable format string and arguments.
|
||||||
|
*/
|
||||||
|
boolean showConfirmationMessage(String... message);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Shows a message to the user. The message may consist of a translatable
|
||||||
|
* format string and arguments.
|
||||||
|
*/
|
||||||
|
void showMessage(String... message);
|
||||||
|
}
|
||||||
@@ -9,40 +9,25 @@ import java.io.IOException;
|
|||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.io.OutputStream;
|
import java.io.OutputStream;
|
||||||
import java.net.Socket;
|
import java.net.Socket;
|
||||||
import java.util.logging.Logger;
|
|
||||||
|
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
|
|
||||||
import static java.util.logging.Level.WARNING;
|
|
||||||
|
|
||||||
@NotNullByDefault
|
@NotNullByDefault
|
||||||
public class IoUtils {
|
public class IoUtils {
|
||||||
|
|
||||||
private static final Logger LOG = Logger.getLogger(IoUtils.class.getName());
|
|
||||||
|
|
||||||
public static void deleteFileOrDir(File f) {
|
public static void deleteFileOrDir(File f) {
|
||||||
if (f.isFile()) {
|
if (f.isFile()) {
|
||||||
delete(f);
|
f.delete();
|
||||||
} else if (f.isDirectory()) {
|
} else if (f.isDirectory()) {
|
||||||
File[] children = f.listFiles();
|
File[] children = f.listFiles();
|
||||||
if (children == null) {
|
if (children != null)
|
||||||
if (LOG.isLoggable(WARNING)) {
|
|
||||||
LOG.warning("Could not list files in "
|
|
||||||
+ f.getAbsolutePath());
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
for (File child : children) deleteFileOrDir(child);
|
for (File child : children) deleteFileOrDir(child);
|
||||||
}
|
f.delete();
|
||||||
delete(f);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void delete(File f) {
|
public static void copyAndClose(InputStream in, OutputStream out)
|
||||||
if (!f.delete() && LOG.isLoggable(WARNING))
|
throws IOException {
|
||||||
LOG.warning("Could not delete " + f.getAbsolutePath());
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void copyAndClose(InputStream in, OutputStream out) {
|
|
||||||
byte[] buf = new byte[4096];
|
byte[] buf = new byte[4096];
|
||||||
try {
|
try {
|
||||||
while (true) {
|
while (true) {
|
||||||
|
|||||||
@@ -22,6 +22,19 @@ public class OsUtils {
|
|||||||
return os != null && os.contains("Mac OS");
|
return os != null && os.contains("Mac OS");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static boolean isMacLeopardOrNewer() {
|
||||||
|
if (!isMac() || version == null) return false;
|
||||||
|
try {
|
||||||
|
String[] v = version.split("\\.");
|
||||||
|
if (v.length != 3) return false;
|
||||||
|
int major = Integer.parseInt(v[0]);
|
||||||
|
int minor = Integer.parseInt(v[1]);
|
||||||
|
return major >= 10 && minor >= 5;
|
||||||
|
} catch (NumberFormatException e) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public static boolean isLinux() {
|
public static boolean isLinux() {
|
||||||
return os != null && os.contains("Linux") && !isAndroid();
|
return os != null && os.contains("Linux") && !isAndroid();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,7 +2,6 @@ apply plugin: 'java-library'
|
|||||||
sourceCompatibility = 1.8
|
sourceCompatibility = 1.8
|
||||||
targetCompatibility = 1.8
|
targetCompatibility = 1.8
|
||||||
|
|
||||||
apply plugin: 'ru.vyarus.animalsniffer'
|
|
||||||
apply plugin: 'net.ltgt.apt'
|
apply plugin: 'net.ltgt.apt'
|
||||||
apply plugin: 'idea'
|
apply plugin: 'idea'
|
||||||
apply plugin: 'witness'
|
apply plugin: 'witness'
|
||||||
@@ -27,8 +26,6 @@ dependencies {
|
|||||||
testImplementation "org.hamcrest:hamcrest-core:1.3"
|
testImplementation "org.hamcrest:hamcrest-core:1.3"
|
||||||
|
|
||||||
testApt 'com.google.dagger:dagger-compiler:2.0.2'
|
testApt 'com.google.dagger:dagger-compiler:2.0.2'
|
||||||
|
|
||||||
signature 'org.codehaus.mojo.signature:java16:1.1@signature'
|
|
||||||
}
|
}
|
||||||
|
|
||||||
dependencyVerification {
|
dependencyVerification {
|
||||||
@@ -47,9 +44,6 @@ dependencyVerification {
|
|||||||
'org.apache.ant:ant:1.9.4:ant-1.9.4.jar:649ae0730251de07b8913f49286d46bba7b92d47c5f332610aa426c4f02161d8',
|
'org.apache.ant:ant:1.9.4:ant-1.9.4.jar:649ae0730251de07b8913f49286d46bba7b92d47c5f332610aa426c4f02161d8',
|
||||||
'org.beanshell:bsh:1.3.0:bsh-1.3.0.jar:9b04edc75d19db54f1b4e8b5355e9364384c6cf71eb0a1b9724c159d779879f8',
|
'org.beanshell:bsh:1.3.0:bsh-1.3.0.jar:9b04edc75d19db54f1b4e8b5355e9364384c6cf71eb0a1b9724c159d779879f8',
|
||||||
'org.bitlet:weupnp:0.1.4:weupnp-0.1.4.jar:88df7e6504929d00bdb832863761385c68ab92af945b04f0770b126270a444fb',
|
'org.bitlet:weupnp:0.1.4:weupnp-0.1.4.jar:88df7e6504929d00bdb832863761385c68ab92af945b04f0770b126270a444fb',
|
||||||
'org.codehaus.mojo.signature:java16:1.1:java16-1.1.signature:53799223a2c98dba2d0add810bed76315460df285c69e4f397ae6098f87dd619',
|
|
||||||
'org.codehaus.mojo:animal-sniffer-ant-tasks:1.16:animal-sniffer-ant-tasks-1.16.jar:890040976fbe2d584619a6a61b1fd2e925b3b5eb342a85eb2762c467c0d64e90',
|
|
||||||
'org.codehaus.mojo:animal-sniffer:1.16:animal-sniffer-1.16.jar:72be8bcc226ba43b937c722a08a07852bfa1b11400089265d5df0ee7b38b1d52',
|
|
||||||
'org.hamcrest:hamcrest-core:1.3:hamcrest-core-1.3.jar:66fdef91e9739348df7a096aa384a5685f4e875584cce89386a7a47251c4d8e9',
|
'org.hamcrest:hamcrest-core:1.3:hamcrest-core-1.3.jar:66fdef91e9739348df7a096aa384a5685f4e875584cce89386a7a47251c4d8e9',
|
||||||
'org.hamcrest:hamcrest-library:1.3:hamcrest-library-1.3.jar:711d64522f9ec410983bd310934296da134be4254a125080a0416ec178dfad1c',
|
'org.hamcrest:hamcrest-library:1.3:hamcrest-library-1.3.jar:711d64522f9ec410983bd310934296da134be4254a125080a0416ec178dfad1c',
|
||||||
'org.hsqldb:hsqldb:2.3.5:hsqldb-2.3.5.jar:6676a6977ac98997a80f827ddbd3fe8ca1e0853dad1492512135fd1a222ccfad',
|
'org.hsqldb:hsqldb:2.3.5:hsqldb-2.3.5.jar:6676a6977ac98997a80f827ddbd3fe8ca1e0853dad1492512135fd1a222ccfad',
|
||||||
@@ -58,7 +52,6 @@ dependencyVerification {
|
|||||||
'org.jmock:jmock-testjar:2.8.2:jmock-testjar-2.8.2.jar:8900860f72c474e027cf97fe78dcbf154a1aa7fc62b6845c5fb4e4f3c7bc8760',
|
'org.jmock:jmock-testjar:2.8.2:jmock-testjar-2.8.2.jar:8900860f72c474e027cf97fe78dcbf154a1aa7fc62b6845c5fb4e4f3c7bc8760',
|
||||||
'org.jmock:jmock:2.8.2:jmock-2.8.2.jar:6c73cb4a2e6dbfb61fd99c9a768539c170ab6568e57846bd60dbf19596b65b16',
|
'org.jmock:jmock:2.8.2:jmock-2.8.2.jar:6c73cb4a2e6dbfb61fd99c9a768539c170ab6568e57846bd60dbf19596b65b16',
|
||||||
'org.objenesis:objenesis:2.1:objenesis-2.1.jar:c74330cc6b806c804fd37e74487b4fe5d7c2750c5e15fbc6efa13bdee1bdef80',
|
'org.objenesis:objenesis:2.1:objenesis-2.1.jar:c74330cc6b806c804fd37e74487b4fe5d7c2750c5e15fbc6efa13bdee1bdef80',
|
||||||
'org.ow2.asm:asm-all:5.2:asm-all-5.2.jar:7fbffbc1db3422e2101689fd88df8384b15817b52b9b2b267b9f6d2511dc198d',
|
|
||||||
'org.ow2.asm:asm:5.0.4:asm-5.0.4.jar:896618ed8ae62702521a78bc7be42b7c491a08e6920a15f89a3ecdec31e9a220',
|
'org.ow2.asm:asm:5.0.4:asm-5.0.4.jar:896618ed8ae62702521a78bc7be42b7c491a08e6920a15f89a3ecdec31e9a220',
|
||||||
'org.whispersystems:curve25519-java:0.4.1:curve25519-java-0.4.1.jar:7dd659d8822c06c3aea1a47f18fac9e5761e29cab8100030b877db445005f03e',
|
'org.whispersystems:curve25519-java:0.4.1:curve25519-java-0.4.1.jar:7dd659d8822c06c3aea1a47f18fac9e5761e29cab8100030b877db445005f03e',
|
||||||
]
|
]
|
||||||
@@ -75,3 +68,8 @@ task jarTest(type: Jar, dependsOn: testClasses) {
|
|||||||
artifacts {
|
artifacts {
|
||||||
testOutput jarTest
|
testOutput jarTest
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If a Java 6 JRE is available, check we're not using any Java 7 or 8 APIs
|
||||||
|
tasks.withType(JavaCompile) {
|
||||||
|
useJava6StandardLibrary(it)
|
||||||
|
}
|
||||||
|
|||||||
@@ -7,7 +7,6 @@ import org.briarproject.bramble.identity.IdentityModule;
|
|||||||
import org.briarproject.bramble.lifecycle.LifecycleModule;
|
import org.briarproject.bramble.lifecycle.LifecycleModule;
|
||||||
import org.briarproject.bramble.plugin.PluginModule;
|
import org.briarproject.bramble.plugin.PluginModule;
|
||||||
import org.briarproject.bramble.properties.PropertiesModule;
|
import org.briarproject.bramble.properties.PropertiesModule;
|
||||||
import org.briarproject.bramble.reporting.ReportingModule;
|
|
||||||
import org.briarproject.bramble.sync.SyncModule;
|
import org.briarproject.bramble.sync.SyncModule;
|
||||||
import org.briarproject.bramble.system.SystemModule;
|
import org.briarproject.bramble.system.SystemModule;
|
||||||
import org.briarproject.bramble.transport.TransportModule;
|
import org.briarproject.bramble.transport.TransportModule;
|
||||||
@@ -29,8 +28,6 @@ public interface BrambleCoreEagerSingletons {
|
|||||||
|
|
||||||
void inject(PropertiesModule.EagerSingletons init);
|
void inject(PropertiesModule.EagerSingletons init);
|
||||||
|
|
||||||
void inject(ReportingModule.EagerSingletons init);
|
|
||||||
|
|
||||||
void inject(SyncModule.EagerSingletons init);
|
void inject(SyncModule.EagerSingletons init);
|
||||||
|
|
||||||
void inject(SystemModule.EagerSingletons init);
|
void inject(SystemModule.EagerSingletons init);
|
||||||
|
|||||||
@@ -59,7 +59,6 @@ public class BrambleCoreModule {
|
|||||||
c.inject(new LifecycleModule.EagerSingletons());
|
c.inject(new LifecycleModule.EagerSingletons());
|
||||||
c.inject(new PluginModule.EagerSingletons());
|
c.inject(new PluginModule.EagerSingletons());
|
||||||
c.inject(new PropertiesModule.EagerSingletons());
|
c.inject(new PropertiesModule.EagerSingletons());
|
||||||
c.inject(new ReportingModule.EagerSingletons());
|
|
||||||
c.inject(new SyncModule.EagerSingletons());
|
c.inject(new SyncModule.EagerSingletons());
|
||||||
c.inject(new SystemModule.EagerSingletons());
|
c.inject(new SystemModule.EagerSingletons());
|
||||||
c.inject(new TransportModule.EagerSingletons());
|
c.inject(new TransportModule.EagerSingletons());
|
||||||
|
|||||||
@@ -30,7 +30,6 @@ import org.briarproject.bramble.api.record.RecordWriter;
|
|||||||
import org.briarproject.bramble.api.record.RecordWriterFactory;
|
import org.briarproject.bramble.api.record.RecordWriterFactory;
|
||||||
import org.briarproject.bramble.api.system.Clock;
|
import org.briarproject.bramble.api.system.Clock;
|
||||||
import org.briarproject.bramble.api.transport.StreamReaderFactory;
|
import org.briarproject.bramble.api.transport.StreamReaderFactory;
|
||||||
import org.briarproject.bramble.api.transport.StreamWriter;
|
|
||||||
import org.briarproject.bramble.api.transport.StreamWriterFactory;
|
import org.briarproject.bramble.api.transport.StreamWriterFactory;
|
||||||
|
|
||||||
import java.io.EOFException;
|
import java.io.EOFException;
|
||||||
@@ -153,11 +152,11 @@ class ContactExchangeTaskImpl extends Thread implements ContactExchangeTask {
|
|||||||
recordReaderFactory.createRecordReader(streamReader);
|
recordReaderFactory.createRecordReader(streamReader);
|
||||||
|
|
||||||
// Create the writers
|
// Create the writers
|
||||||
StreamWriter streamWriter =
|
OutputStream streamWriter =
|
||||||
streamWriterFactory.createContactExchangeStreamWriter(out,
|
streamWriterFactory.createContactExchangeStreamWriter(out,
|
||||||
alice ? aliceHeaderKey : bobHeaderKey);
|
alice ? aliceHeaderKey : bobHeaderKey);
|
||||||
RecordWriter recordWriter =
|
RecordWriter recordWriter =
|
||||||
recordWriterFactory.createRecordWriter(streamWriter.getOutputStream());
|
recordWriterFactory.createRecordWriter(streamWriter);
|
||||||
|
|
||||||
// Derive the nonces to be signed
|
// Derive the nonces to be signed
|
||||||
byte[] aliceNonce = crypto.mac(ALICE_NONCE_LABEL, masterSecret,
|
byte[] aliceNonce = crypto.mac(ALICE_NONCE_LABEL, masterSecret,
|
||||||
@@ -185,8 +184,8 @@ class ContactExchangeTaskImpl extends Thread implements ContactExchangeTask {
|
|||||||
localSignature, localTimestamp);
|
localSignature, localTimestamp);
|
||||||
recordWriter.flush();
|
recordWriter.flush();
|
||||||
}
|
}
|
||||||
// Send EOF on the outgoing stream
|
// Close the outgoing stream
|
||||||
streamWriter.sendEndOfStream();
|
recordWriter.close();
|
||||||
// Skip any remaining records from the incoming stream
|
// Skip any remaining records from the incoming stream
|
||||||
try {
|
try {
|
||||||
while (true) recordReader.readRecord();
|
while (true) recordReader.readRecord();
|
||||||
|
|||||||
@@ -46,7 +46,7 @@ class ContactManagerImpl implements ContactManager {
|
|||||||
SecretKey master, long timestamp, boolean alice, boolean verified,
|
SecretKey master, long timestamp, boolean alice, boolean verified,
|
||||||
boolean active) throws DbException {
|
boolean active) throws DbException {
|
||||||
ContactId c = db.addContact(txn, remote, local, verified, active);
|
ContactId c = db.addContact(txn, remote, local, verified, active);
|
||||||
keyManager.addContact(txn, c, master, timestamp, alice, active);
|
keyManager.addContact(txn, c, master, timestamp, alice);
|
||||||
Contact contact = db.getContact(txn, c);
|
Contact contact = db.getContact(txn, c);
|
||||||
for (ContactHook hook : hooks) hook.addingContact(txn, contact);
|
for (ContactHook hook : hooks) hook.addingContact(txn, contact);
|
||||||
return c;
|
return c;
|
||||||
|
|||||||
@@ -152,47 +152,59 @@ public class MessageEncrypter {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void main(String[] args) {
|
public static void main(String[] args) throws Exception {
|
||||||
if (args.length < 1) {
|
if (args.length < 1) {
|
||||||
printUsage();
|
printUsage();
|
||||||
System.exit(1);
|
return;
|
||||||
}
|
}
|
||||||
|
SecureRandom random = new SecureRandom();
|
||||||
|
MessageEncrypter encrypter = new MessageEncrypter(random);
|
||||||
if (args[0].equals("generate")) {
|
if (args[0].equals("generate")) {
|
||||||
if (args.length != 3) {
|
if (args.length != 3) {
|
||||||
printUsage();
|
printUsage();
|
||||||
System.exit(1);
|
return;
|
||||||
}
|
|
||||||
try {
|
|
||||||
generateKeyPair(args[1], args[2]);
|
|
||||||
} catch (Exception e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
System.exit(2);
|
|
||||||
}
|
}
|
||||||
|
// Generate a key pair
|
||||||
|
KeyPair keyPair = encrypter.generateKeyPair();
|
||||||
|
PrintStream out = new PrintStream(new FileOutputStream(args[1]));
|
||||||
|
out.print(
|
||||||
|
StringUtils.toHexString(keyPair.getPublic().getEncoded()));
|
||||||
|
out.flush();
|
||||||
|
out.close();
|
||||||
|
out = new PrintStream(new FileOutputStream(args[2]));
|
||||||
|
out.print(
|
||||||
|
StringUtils.toHexString(keyPair.getPrivate().getEncoded()));
|
||||||
|
out.flush();
|
||||||
|
out.close();
|
||||||
} else if (args[0].equals("encrypt")) {
|
} else if (args[0].equals("encrypt")) {
|
||||||
if (args.length != 2) {
|
if (args.length != 2) {
|
||||||
printUsage();
|
printUsage();
|
||||||
System.exit(1);
|
return;
|
||||||
}
|
|
||||||
try {
|
|
||||||
encryptMessage(args[1]);
|
|
||||||
} catch (Exception e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
System.exit(2);
|
|
||||||
}
|
}
|
||||||
|
// Encrypt a decrypted message
|
||||||
|
InputStream in = new FileInputStream(args[1]);
|
||||||
|
byte[] keyBytes = StringUtils.fromHexString(readFully(in).trim());
|
||||||
|
PublicKey publicKey =
|
||||||
|
encrypter.getKeyParser().parsePublicKey(keyBytes);
|
||||||
|
String message = readFully(System.in);
|
||||||
|
byte[] plaintext = message.getBytes(Charset.forName("UTF-8"));
|
||||||
|
byte[] ciphertext = encrypter.encrypt(publicKey, plaintext);
|
||||||
|
System.out.println(AsciiArmour.wrap(ciphertext, LINE_LENGTH));
|
||||||
} else if (args[0].equals("decrypt")) {
|
} else if (args[0].equals("decrypt")) {
|
||||||
if (args.length != 2) {
|
if (args.length != 2) {
|
||||||
printUsage();
|
printUsage();
|
||||||
System.exit(1);
|
return;
|
||||||
}
|
|
||||||
try {
|
|
||||||
decryptMessage(args[1]);
|
|
||||||
} catch (Exception e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
System.exit(2);
|
|
||||||
}
|
}
|
||||||
|
// Decrypt an encrypted message
|
||||||
|
InputStream in = new FileInputStream(args[1]);
|
||||||
|
byte[] keyBytes = StringUtils.fromHexString(readFully(in).trim());
|
||||||
|
PrivateKey privateKey =
|
||||||
|
encrypter.getKeyParser().parsePrivateKey(keyBytes);
|
||||||
|
byte[] ciphertext = AsciiArmour.unwrap(readFully(System.in));
|
||||||
|
byte[] plaintext = encrypter.decrypt(privateKey, ciphertext);
|
||||||
|
System.out.println(new String(plaintext, Charset.forName("UTF-8")));
|
||||||
} else {
|
} else {
|
||||||
printUsage();
|
printUsage();
|
||||||
System.exit(1);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -204,46 +216,6 @@ public class MessageEncrypter {
|
|||||||
System.err.println("MessageEncrypter decrypt <private_key_file>");
|
System.err.println("MessageEncrypter decrypt <private_key_file>");
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void generateKeyPair(String publicKeyFile,
|
|
||||||
String privateKeyFile) throws Exception {
|
|
||||||
SecureRandom random = new SecureRandom();
|
|
||||||
MessageEncrypter encrypter = new MessageEncrypter(random);
|
|
||||||
KeyPair keyPair = encrypter.generateKeyPair();
|
|
||||||
PrintStream out = new PrintStream(new FileOutputStream(publicKeyFile));
|
|
||||||
out.print(StringUtils.toHexString(keyPair.getPublic().getEncoded()));
|
|
||||||
out.flush();
|
|
||||||
out.close();
|
|
||||||
out = new PrintStream(new FileOutputStream(privateKeyFile));
|
|
||||||
out.print(StringUtils.toHexString(keyPair.getPrivate().getEncoded()));
|
|
||||||
out.flush();
|
|
||||||
out.close();
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void encryptMessage(String publicKeyFile) throws Exception {
|
|
||||||
SecureRandom random = new SecureRandom();
|
|
||||||
MessageEncrypter encrypter = new MessageEncrypter(random);
|
|
||||||
InputStream in = new FileInputStream(publicKeyFile);
|
|
||||||
byte[] keyBytes = StringUtils.fromHexString(readFully(in).trim());
|
|
||||||
PublicKey publicKey =
|
|
||||||
encrypter.getKeyParser().parsePublicKey(keyBytes);
|
|
||||||
String message = readFully(System.in);
|
|
||||||
byte[] plaintext = message.getBytes(Charset.forName("UTF-8"));
|
|
||||||
byte[] ciphertext = encrypter.encrypt(publicKey, plaintext);
|
|
||||||
System.out.println(AsciiArmour.wrap(ciphertext, LINE_LENGTH));
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void decryptMessage(String privateKeyFile) throws Exception {
|
|
||||||
SecureRandom random = new SecureRandom();
|
|
||||||
MessageEncrypter encrypter = new MessageEncrypter(random);
|
|
||||||
InputStream in = new FileInputStream(privateKeyFile);
|
|
||||||
byte[] keyBytes = StringUtils.fromHexString(readFully(in).trim());
|
|
||||||
PrivateKey privateKey =
|
|
||||||
encrypter.getKeyParser().parsePrivateKey(keyBytes);
|
|
||||||
byte[] ciphertext = AsciiArmour.unwrap(readFully(System.in));
|
|
||||||
byte[] plaintext = encrypter.decrypt(privateKey, ciphertext);
|
|
||||||
System.out.println(new String(plaintext, Charset.forName("UTF-8")));
|
|
||||||
}
|
|
||||||
|
|
||||||
private static String readFully(InputStream in) throws IOException {
|
private static String readFully(InputStream in) throws IOException {
|
||||||
String newline = System.getProperty("line.separator");
|
String newline = System.getProperty("line.separator");
|
||||||
StringBuilder stringBuilder = new StringBuilder();
|
StringBuilder stringBuilder = new StringBuilder();
|
||||||
|
|||||||
@@ -10,37 +10,37 @@ import java.security.GeneralSecurityException;
|
|||||||
interface Signature {
|
interface Signature {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @see java.security.Signature#initSign(java.security.PrivateKey)
|
* @see {@link java.security.Signature#initSign(java.security.PrivateKey)}
|
||||||
*/
|
*/
|
||||||
void initSign(PrivateKey k) throws GeneralSecurityException;
|
void initSign(PrivateKey k) throws GeneralSecurityException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @see java.security.Signature#initVerify(java.security.PublicKey)
|
* @see {@link java.security.Signature#initVerify(java.security.PublicKey)}
|
||||||
*/
|
*/
|
||||||
void initVerify(PublicKey k) throws GeneralSecurityException;
|
void initVerify(PublicKey k) throws GeneralSecurityException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @see java.security.Signature#update(byte)
|
* @see {@link java.security.Signature#update(byte)}
|
||||||
*/
|
*/
|
||||||
void update(byte b) throws GeneralSecurityException;
|
void update(byte b) throws GeneralSecurityException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @see java.security.Signature#update(byte[])
|
* @see {@link java.security.Signature#update(byte[])}
|
||||||
*/
|
*/
|
||||||
void update(byte[] b) throws GeneralSecurityException;
|
void update(byte[] b) throws GeneralSecurityException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @see java.security.Signature#update(byte[], int, int)
|
* @see {@link java.security.Signature#update(byte[], int, int)}
|
||||||
*/
|
*/
|
||||||
void update(byte[] b, int off, int len) throws GeneralSecurityException;
|
void update(byte[] b, int off, int len) throws GeneralSecurityException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @see java.security.Signature#sign()}
|
* @see {@link java.security.Signature#sign()}
|
||||||
*/
|
*/
|
||||||
byte[] sign() throws GeneralSecurityException;
|
byte[] sign() throws GeneralSecurityException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @see java.security.Signature#verify(byte[])
|
* @see {@link java.security.Signature#verify(byte[])}
|
||||||
*/
|
*/
|
||||||
boolean verify(byte[] signature) throws GeneralSecurityException;
|
boolean verify(byte[] signature) throws GeneralSecurityException;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,7 +8,6 @@ import java.io.InputStream;
|
|||||||
|
|
||||||
import javax.annotation.concurrent.Immutable;
|
import javax.annotation.concurrent.Immutable;
|
||||||
|
|
||||||
import static org.briarproject.bramble.api.data.BdfReader.DEFAULT_MAX_BUFFER_SIZE;
|
|
||||||
import static org.briarproject.bramble.api.data.BdfReader.DEFAULT_NESTED_LIMIT;
|
import static org.briarproject.bramble.api.data.BdfReader.DEFAULT_NESTED_LIMIT;
|
||||||
|
|
||||||
@Immutable
|
@Immutable
|
||||||
@@ -17,13 +16,11 @@ class BdfReaderFactoryImpl implements BdfReaderFactory {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public BdfReader createReader(InputStream in) {
|
public BdfReader createReader(InputStream in) {
|
||||||
return new BdfReaderImpl(in, DEFAULT_NESTED_LIMIT,
|
return new BdfReaderImpl(in, DEFAULT_NESTED_LIMIT);
|
||||||
DEFAULT_MAX_BUFFER_SIZE);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public BdfReader createReader(InputStream in, int nestedLimit,
|
public BdfReader createReader(InputStream in, int nestedLimit) {
|
||||||
int maxBufferSize) {
|
return new BdfReaderImpl(in, nestedLimit);
|
||||||
return new BdfReaderImpl(in, nestedLimit, maxBufferSize);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -37,16 +37,15 @@ class BdfReaderImpl implements BdfReader {
|
|||||||
private static final byte[] EMPTY_BUFFER = new byte[0];
|
private static final byte[] EMPTY_BUFFER = new byte[0];
|
||||||
|
|
||||||
private final InputStream in;
|
private final InputStream in;
|
||||||
private final int nestedLimit, maxBufferSize;
|
private final int nestedLimit;
|
||||||
|
|
||||||
private boolean hasLookahead = false, eof = false;
|
private boolean hasLookahead = false, eof = false;
|
||||||
private byte next;
|
private byte next;
|
||||||
private byte[] buf = new byte[8];
|
private byte[] buf = new byte[8];
|
||||||
|
|
||||||
BdfReaderImpl(InputStream in, int nestedLimit, int maxBufferSize) {
|
BdfReaderImpl(InputStream in, int nestedLimit) {
|
||||||
this.in = in;
|
this.in = in;
|
||||||
this.nestedLimit = nestedLimit;
|
this.nestedLimit = nestedLimit;
|
||||||
this.maxBufferSize = maxBufferSize;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void readLookahead() throws IOException {
|
private void readLookahead() throws IOException {
|
||||||
@@ -92,8 +91,8 @@ class BdfReaderImpl implements BdfReader {
|
|||||||
if (hasBoolean()) return readBoolean();
|
if (hasBoolean()) return readBoolean();
|
||||||
if (hasLong()) return readLong();
|
if (hasLong()) return readLong();
|
||||||
if (hasDouble()) return readDouble();
|
if (hasDouble()) return readDouble();
|
||||||
if (hasString()) return readString();
|
if (hasString()) return readString(Integer.MAX_VALUE);
|
||||||
if (hasRaw()) return readRaw();
|
if (hasRaw()) return readRaw(Integer.MAX_VALUE);
|
||||||
if (hasList()) return readList(level);
|
if (hasList()) return readList(level);
|
||||||
if (hasDictionary()) return readDictionary(level);
|
if (hasDictionary()) return readDictionary(level);
|
||||||
throw new FormatException();
|
throw new FormatException();
|
||||||
@@ -246,11 +245,11 @@ class BdfReaderImpl implements BdfReader {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String readString() throws IOException {
|
public String readString(int maxLength) throws IOException {
|
||||||
if (!hasString()) throw new FormatException();
|
if (!hasString()) throw new FormatException();
|
||||||
hasLookahead = false;
|
hasLookahead = false;
|
||||||
int length = readStringLength();
|
int length = readStringLength();
|
||||||
if (length < 0 || length > maxBufferSize) throw new FormatException();
|
if (length < 0 || length > maxLength) throw new FormatException();
|
||||||
if (length == 0) return "";
|
if (length == 0) return "";
|
||||||
readIntoBuffer(length);
|
readIntoBuffer(length);
|
||||||
return new String(buf, 0, length, "UTF-8");
|
return new String(buf, 0, length, "UTF-8");
|
||||||
@@ -280,11 +279,11 @@ class BdfReaderImpl implements BdfReader {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public byte[] readRaw() throws IOException {
|
public byte[] readRaw(int maxLength) throws IOException {
|
||||||
if (!hasRaw()) throw new FormatException();
|
if (!hasRaw()) throw new FormatException();
|
||||||
hasLookahead = false;
|
hasLookahead = false;
|
||||||
int length = readRawLength();
|
int length = readRawLength();
|
||||||
if (length < 0 || length > maxBufferSize) throw new FormatException();
|
if (length < 0 || length > maxLength) throw new FormatException();
|
||||||
if (length == 0) return EMPTY_BUFFER;
|
if (length == 0) return EMPTY_BUFFER;
|
||||||
byte[] b = new byte[length];
|
byte[] b = new byte[length];
|
||||||
readIntoBuffer(b, length);
|
readIntoBuffer(b, length);
|
||||||
@@ -382,7 +381,7 @@ class BdfReaderImpl implements BdfReader {
|
|||||||
BdfDictionary dictionary = new BdfDictionary();
|
BdfDictionary dictionary = new BdfDictionary();
|
||||||
readDictionaryStart();
|
readDictionaryStart();
|
||||||
while (!hasDictionaryEnd())
|
while (!hasDictionaryEnd())
|
||||||
dictionary.put(readString(), readObject(level + 1));
|
dictionary.put(readString(Integer.MAX_VALUE), readObject(level + 1));
|
||||||
readDictionaryEnd();
|
readDictionaryEnd();
|
||||||
return dictionary;
|
return dictionary;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -59,8 +59,8 @@ class MetadataParserImpl implements MetadataParser {
|
|||||||
if (reader.hasBoolean()) return reader.readBoolean();
|
if (reader.hasBoolean()) return reader.readBoolean();
|
||||||
if (reader.hasLong()) return reader.readLong();
|
if (reader.hasLong()) return reader.readLong();
|
||||||
if (reader.hasDouble()) return reader.readDouble();
|
if (reader.hasDouble()) return reader.readDouble();
|
||||||
if (reader.hasString()) return reader.readString();
|
if (reader.hasString()) return reader.readString(Integer.MAX_VALUE);
|
||||||
if (reader.hasRaw()) return reader.readRaw();
|
if (reader.hasRaw()) return reader.readRaw(Integer.MAX_VALUE);
|
||||||
if (reader.hasList()) return reader.readList();
|
if (reader.hasList()) return reader.readList();
|
||||||
if (reader.hasDictionary()) return reader.readDictionary();
|
if (reader.hasDictionary()) return reader.readDictionary();
|
||||||
throw new FormatException();
|
throw new FormatException();
|
||||||
|
|||||||
@@ -34,8 +34,8 @@ import javax.annotation.Nullable;
|
|||||||
* A low-level interface to the database (DatabaseComponent provides a
|
* A low-level interface to the database (DatabaseComponent provides a
|
||||||
* high-level interface). Most operations take a transaction argument, which is
|
* high-level interface). Most operations take a transaction argument, which is
|
||||||
* obtained by calling {@link #startTransaction()}. Every transaction must be
|
* obtained by calling {@link #startTransaction()}. Every transaction must be
|
||||||
* terminated by calling either {@link #abortTransaction(Object) abortTransaction(T)} or
|
* terminated by calling either {@link #abortTransaction(T)} or
|
||||||
* {@link #commitTransaction(Object) commitTransaction(T)}, even if an exception is thrown.
|
* {@link #commitTransaction(T)}, even if an exception is thrown.
|
||||||
*/
|
*/
|
||||||
@NotNullByDefault
|
@NotNullByDefault
|
||||||
interface Database<T> {
|
interface Database<T> {
|
||||||
@@ -125,10 +125,16 @@ interface Database<T> {
|
|||||||
throws DbException;
|
throws DbException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Stores the given transport keys for the given contact and returns a
|
* Stores the given transport keys, optionally binding them to the given
|
||||||
* key set ID.
|
* contact, and returns a key set ID.
|
||||||
*/
|
*/
|
||||||
KeySetId addTransportKeys(T txn, ContactId c, TransportKeys k)
|
KeySetId addTransportKeys(T txn, @Nullable ContactId c, TransportKeys k)
|
||||||
|
throws DbException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Binds the given keys for the given transport to the given contact.
|
||||||
|
*/
|
||||||
|
void bindTransportKeys(T txn, ContactId c, TransportId t, KeySetId k)
|
||||||
throws DbException;
|
throws DbException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -234,17 +234,29 @@ class DatabaseComponentImpl<T> implements DatabaseComponent {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public KeySetId addTransportKeys(Transaction transaction, ContactId c,
|
public KeySetId addTransportKeys(Transaction transaction,
|
||||||
TransportKeys k) throws DbException {
|
@Nullable ContactId c, TransportKeys k) throws DbException {
|
||||||
if (transaction.isReadOnly()) throw new IllegalArgumentException();
|
if (transaction.isReadOnly()) throw new IllegalArgumentException();
|
||||||
T txn = unbox(transaction);
|
T txn = unbox(transaction);
|
||||||
if (!db.containsContact(txn, c))
|
if (c != null && !db.containsContact(txn, c))
|
||||||
throw new NoSuchContactException();
|
throw new NoSuchContactException();
|
||||||
if (!db.containsTransport(txn, k.getTransportId()))
|
if (!db.containsTransport(txn, k.getTransportId()))
|
||||||
throw new NoSuchTransportException();
|
throw new NoSuchTransportException();
|
||||||
return db.addTransportKeys(txn, c, k);
|
return db.addTransportKeys(txn, c, k);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void bindTransportKeys(Transaction transaction, ContactId c,
|
||||||
|
TransportId t, KeySetId k) throws DbException {
|
||||||
|
if (transaction.isReadOnly()) throw new IllegalArgumentException();
|
||||||
|
T txn = unbox(transaction);
|
||||||
|
if (!db.containsContact(txn, c))
|
||||||
|
throw new NoSuchContactException();
|
||||||
|
if (!db.containsTransport(txn, t))
|
||||||
|
throw new NoSuchTransportException();
|
||||||
|
db.bindTransportKeys(txn, c, t, k);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean containsContact(Transaction transaction, AuthorId remote,
|
public boolean containsContact(Transaction transaction, AuthorId remote,
|
||||||
AuthorId local) throws DbException {
|
AuthorId local) throws DbException {
|
||||||
|
|||||||
@@ -53,7 +53,6 @@ import java.util.logging.Logger;
|
|||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
|
|
||||||
import static java.sql.Types.INTEGER;
|
import static java.sql.Types.INTEGER;
|
||||||
import static java.util.Collections.singletonList;
|
|
||||||
import static java.util.logging.Level.INFO;
|
import static java.util.logging.Level.INFO;
|
||||||
import static java.util.logging.Level.WARNING;
|
import static java.util.logging.Level.WARNING;
|
||||||
import static org.briarproject.bramble.api.db.Metadata.REMOVE;
|
import static org.briarproject.bramble.api.db.Metadata.REMOVE;
|
||||||
@@ -75,7 +74,7 @@ import static org.briarproject.bramble.db.ExponentialBackoff.calculateExpiry;
|
|||||||
abstract class JdbcDatabase implements Database<Connection> {
|
abstract class JdbcDatabase implements Database<Connection> {
|
||||||
|
|
||||||
// Package access for testing
|
// Package access for testing
|
||||||
static final int CODE_SCHEMA_VERSION = 39;
|
static final int CODE_SCHEMA_VERSION = 38;
|
||||||
|
|
||||||
// Rotation period offsets for incoming transport keys
|
// Rotation period offsets for incoming transport keys
|
||||||
private static final int OFFSET_PREV = -1;
|
private static final int OFFSET_PREV = -1;
|
||||||
@@ -237,7 +236,7 @@ abstract class JdbcDatabase implements Database<Connection> {
|
|||||||
+ " (transportId _STRING NOT NULL,"
|
+ " (transportId _STRING NOT NULL,"
|
||||||
+ " keySetId _COUNTER,"
|
+ " keySetId _COUNTER,"
|
||||||
+ " rotationPeriod BIGINT NOT NULL,"
|
+ " rotationPeriod BIGINT NOT NULL,"
|
||||||
+ " contactId INT NOT NULL,"
|
+ " contactId INT," // Null if keys are not bound
|
||||||
+ " tagKey _SECRET NOT NULL,"
|
+ " tagKey _SECRET NOT NULL,"
|
||||||
+ " headerKey _SECRET NOT NULL,"
|
+ " headerKey _SECRET NOT NULL,"
|
||||||
+ " stream BIGINT NOT NULL,"
|
+ " stream BIGINT NOT NULL,"
|
||||||
@@ -256,7 +255,7 @@ abstract class JdbcDatabase implements Database<Connection> {
|
|||||||
+ " (transportId _STRING NOT NULL,"
|
+ " (transportId _STRING NOT NULL,"
|
||||||
+ " keySetId INT NOT NULL,"
|
+ " keySetId INT NOT NULL,"
|
||||||
+ " rotationPeriod BIGINT NOT NULL,"
|
+ " rotationPeriod BIGINT NOT NULL,"
|
||||||
+ " contactId INT NOT NULL,"
|
+ " contactId INT," // Null if keys are not bound
|
||||||
+ " tagKey _SECRET NOT NULL,"
|
+ " tagKey _SECRET NOT NULL,"
|
||||||
+ " headerKey _SECRET NOT NULL,"
|
+ " headerKey _SECRET NOT NULL,"
|
||||||
+ " base BIGINT NOT NULL,"
|
+ " base BIGINT NOT NULL,"
|
||||||
@@ -390,7 +389,7 @@ abstract class JdbcDatabase implements Database<Connection> {
|
|||||||
|
|
||||||
// Package access for testing
|
// Package access for testing
|
||||||
List<Migration<Connection>> getMigrations() {
|
List<Migration<Connection>> getMigrations() {
|
||||||
return singletonList(new Migration38_39());
|
return Collections.emptyList();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void storeSchemaVersion(Connection txn, int version)
|
private void storeSchemaVersion(Connection txn, int version)
|
||||||
@@ -884,7 +883,7 @@ abstract class JdbcDatabase implements Database<Connection> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public KeySetId addTransportKeys(Connection txn, ContactId c,
|
public KeySetId addTransportKeys(Connection txn, @Nullable ContactId c,
|
||||||
TransportKeys k) throws DbException {
|
TransportKeys k) throws DbException {
|
||||||
PreparedStatement ps = null;
|
PreparedStatement ps = null;
|
||||||
ResultSet rs = null;
|
ResultSet rs = null;
|
||||||
@@ -894,7 +893,8 @@ abstract class JdbcDatabase implements Database<Connection> {
|
|||||||
+ " rotationPeriod, tagKey, headerKey, stream, active)"
|
+ " rotationPeriod, tagKey, headerKey, stream, active)"
|
||||||
+ " VALUES (?, ?, ?, ?, ?, ?, ?)";
|
+ " VALUES (?, ?, ?, ?, ?, ?, ?)";
|
||||||
ps = txn.prepareStatement(sql);
|
ps = txn.prepareStatement(sql);
|
||||||
ps.setInt(1, c.getInt());
|
if (c == null) ps.setNull(1, INTEGER);
|
||||||
|
else ps.setInt(1, c.getInt());
|
||||||
ps.setString(2, k.getTransportId().getString());
|
ps.setString(2, k.getTransportId().getString());
|
||||||
OutgoingKeys outCurr = k.getCurrentOutgoingKeys();
|
OutgoingKeys outCurr = k.getCurrentOutgoingKeys();
|
||||||
ps.setLong(3, outCurr.getRotationPeriod());
|
ps.setLong(3, outCurr.getRotationPeriod());
|
||||||
@@ -922,7 +922,8 @@ abstract class JdbcDatabase implements Database<Connection> {
|
|||||||
+ " VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)";
|
+ " VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)";
|
||||||
ps = txn.prepareStatement(sql);
|
ps = txn.prepareStatement(sql);
|
||||||
ps.setInt(1, keySetId.getInt());
|
ps.setInt(1, keySetId.getInt());
|
||||||
ps.setInt(2, c.getInt());
|
if (c == null) ps.setNull(2, INTEGER);
|
||||||
|
else ps.setInt(2, c.getInt());
|
||||||
ps.setString(3, k.getTransportId().getString());
|
ps.setString(3, k.getTransportId().getString());
|
||||||
// Previous rotation period
|
// Previous rotation period
|
||||||
IncomingKeys inPrev = k.getPreviousIncomingKeys();
|
IncomingKeys inPrev = k.getPreviousIncomingKeys();
|
||||||
@@ -964,6 +965,33 @@ abstract class JdbcDatabase implements Database<Connection> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void bindTransportKeys(Connection txn, ContactId c, TransportId t,
|
||||||
|
KeySetId k) throws DbException {
|
||||||
|
PreparedStatement ps = null;
|
||||||
|
try {
|
||||||
|
String sql = "UPDATE outgoingKeys SET contactId = ?"
|
||||||
|
+ " WHERE keySetId = ?";
|
||||||
|
ps = txn.prepareStatement(sql);
|
||||||
|
ps.setInt(1, c.getInt());
|
||||||
|
ps.setInt(2, k.getInt());
|
||||||
|
int affected = ps.executeUpdate();
|
||||||
|
if (affected < 0) throw new DbStateException();
|
||||||
|
ps.close();
|
||||||
|
sql = "UPDATE incomingKeys SET contactId = ?"
|
||||||
|
+ " WHERE keySetId = ?";
|
||||||
|
ps = txn.prepareStatement(sql);
|
||||||
|
ps.setInt(1, c.getInt());
|
||||||
|
ps.setInt(2, k.getInt());
|
||||||
|
affected = ps.executeUpdate();
|
||||||
|
if (affected < 0) throw new DbStateException();
|
||||||
|
ps.close();
|
||||||
|
} catch (SQLException e) {
|
||||||
|
tryToClose(ps);
|
||||||
|
throw new DbException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean containsContact(Connection txn, AuthorId remote,
|
public boolean containsContact(Connection txn, AuthorId remote,
|
||||||
AuthorId local) throws DbException {
|
AuthorId local) throws DbException {
|
||||||
@@ -2144,6 +2172,7 @@ abstract class JdbcDatabase implements Database<Connection> {
|
|||||||
if (inKeys.size() < (i + 1) * 3) throw new DbStateException();
|
if (inKeys.size() < (i + 1) * 3) throw new DbStateException();
|
||||||
KeySetId keySetId = new KeySetId(rs.getInt(1));
|
KeySetId keySetId = new KeySetId(rs.getInt(1));
|
||||||
ContactId contactId = new ContactId(rs.getInt(2));
|
ContactId contactId = new ContactId(rs.getInt(2));
|
||||||
|
if (rs.wasNull()) contactId = null;
|
||||||
long rotationPeriod = rs.getLong(3);
|
long rotationPeriod = rs.getLong(3);
|
||||||
SecretKey tagKey = new SecretKey(rs.getBytes(4));
|
SecretKey tagKey = new SecretKey(rs.getBytes(4));
|
||||||
SecretKey headerKey = new SecretKey(rs.getBytes(5));
|
SecretKey headerKey = new SecretKey(rs.getBytes(5));
|
||||||
|
|||||||
@@ -1,54 +0,0 @@
|
|||||||
package org.briarproject.bramble.db;
|
|
||||||
|
|
||||||
import org.briarproject.bramble.api.db.DbException;
|
|
||||||
|
|
||||||
import java.sql.Connection;
|
|
||||||
import java.sql.SQLException;
|
|
||||||
import java.sql.Statement;
|
|
||||||
import java.util.logging.Logger;
|
|
||||||
|
|
||||||
import javax.annotation.Nullable;
|
|
||||||
|
|
||||||
import static java.util.logging.Level.WARNING;
|
|
||||||
|
|
||||||
class Migration38_39 implements Migration<Connection> {
|
|
||||||
|
|
||||||
private static final Logger LOG =
|
|
||||||
Logger.getLogger(Migration38_39.class.getName());
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int getStartVersion() {
|
|
||||||
return 38;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int getEndVersion() {
|
|
||||||
return 39;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void migrate(Connection txn) throws DbException {
|
|
||||||
Statement s = null;
|
|
||||||
try {
|
|
||||||
s = txn.createStatement();
|
|
||||||
// Add not null constraints
|
|
||||||
s.execute("ALTER TABLE outgoingKeys"
|
|
||||||
+ " ALTER COLUMN contactId"
|
|
||||||
+ " SET NOT NULL");
|
|
||||||
s.execute("ALTER TABLE incomingKeys"
|
|
||||||
+ " ALTER COLUMN contactId"
|
|
||||||
+ " SET NOT NULL");
|
|
||||||
} catch (SQLException e) {
|
|
||||||
tryToClose(s);
|
|
||||||
throw new DbException(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void tryToClose(@Nullable Statement s) {
|
|
||||||
try {
|
|
||||||
if (s != null) s.close();
|
|
||||||
} catch (SQLException e) {
|
|
||||||
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -14,12 +14,12 @@ import org.briarproject.bramble.api.sync.SyncSessionFactory;
|
|||||||
import org.briarproject.bramble.api.transport.KeyManager;
|
import org.briarproject.bramble.api.transport.KeyManager;
|
||||||
import org.briarproject.bramble.api.transport.StreamContext;
|
import org.briarproject.bramble.api.transport.StreamContext;
|
||||||
import org.briarproject.bramble.api.transport.StreamReaderFactory;
|
import org.briarproject.bramble.api.transport.StreamReaderFactory;
|
||||||
import org.briarproject.bramble.api.transport.StreamWriter;
|
|
||||||
import org.briarproject.bramble.api.transport.StreamWriterFactory;
|
import org.briarproject.bramble.api.transport.StreamWriterFactory;
|
||||||
|
|
||||||
import java.io.EOFException;
|
import java.io.EOFException;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
|
import java.io.OutputStream;
|
||||||
import java.util.concurrent.Executor;
|
import java.util.concurrent.Executor;
|
||||||
import java.util.logging.Logger;
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
@@ -101,7 +101,7 @@ class ConnectionManagerImpl implements ConnectionManager {
|
|||||||
|
|
||||||
private SyncSession createSimplexOutgoingSession(StreamContext ctx,
|
private SyncSession createSimplexOutgoingSession(StreamContext ctx,
|
||||||
TransportConnectionWriter w) throws IOException {
|
TransportConnectionWriter w) throws IOException {
|
||||||
StreamWriter streamWriter = streamWriterFactory.createStreamWriter(
|
OutputStream streamWriter = streamWriterFactory.createStreamWriter(
|
||||||
w.getOutputStream(), ctx);
|
w.getOutputStream(), ctx);
|
||||||
return syncSessionFactory.createSimplexOutgoingSession(
|
return syncSessionFactory.createSimplexOutgoingSession(
|
||||||
ctx.getContactId(), w.getMaxLatency(), streamWriter);
|
ctx.getContactId(), w.getMaxLatency(), streamWriter);
|
||||||
@@ -109,7 +109,7 @@ class ConnectionManagerImpl implements ConnectionManager {
|
|||||||
|
|
||||||
private SyncSession createDuplexOutgoingSession(StreamContext ctx,
|
private SyncSession createDuplexOutgoingSession(StreamContext ctx,
|
||||||
TransportConnectionWriter w) throws IOException {
|
TransportConnectionWriter w) throws IOException {
|
||||||
StreamWriter streamWriter = streamWriterFactory.createStreamWriter(
|
OutputStream streamWriter = streamWriterFactory.createStreamWriter(
|
||||||
w.getOutputStream(), ctx);
|
w.getOutputStream(), ctx);
|
||||||
return syncSessionFactory.createDuplexOutgoingSession(
|
return syncSessionFactory.createDuplexOutgoingSession(
|
||||||
ctx.getContactId(), w.getMaxLatency(), w.getMaxIdleTime(),
|
ctx.getContactId(), w.getMaxLatency(), w.getMaxIdleTime(),
|
||||||
@@ -300,8 +300,8 @@ class ConnectionManagerImpl implements ConnectionManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void disposeReader(boolean exception, boolean recognised) {
|
private void disposeReader(boolean exception, boolean recognised) {
|
||||||
// Interrupt the outgoing session so it finishes cleanly
|
if (exception && outgoingSession != null)
|
||||||
if (outgoingSession != null) outgoingSession.interrupt();
|
outgoingSession.interrupt();
|
||||||
try {
|
try {
|
||||||
reader.dispose(exception, recognised);
|
reader.dispose(exception, recognised);
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
@@ -310,8 +310,6 @@ class ConnectionManagerImpl implements ConnectionManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void disposeWriter(boolean exception) {
|
private void disposeWriter(boolean exception) {
|
||||||
// Interrupt the incoming session if an exception occurred,
|
|
||||||
// otherwise wait for the end of stream marker
|
|
||||||
if (exception && incomingSession != null)
|
if (exception && incomingSession != null)
|
||||||
incomingSession.interrupt();
|
incomingSession.interrupt();
|
||||||
try {
|
try {
|
||||||
@@ -409,8 +407,8 @@ class ConnectionManagerImpl implements ConnectionManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void disposeReader(boolean exception, boolean recognised) {
|
private void disposeReader(boolean exception, boolean recognised) {
|
||||||
// Interrupt the outgoing session so it finishes cleanly
|
if (exception && outgoingSession != null)
|
||||||
if (outgoingSession != null) outgoingSession.interrupt();
|
outgoingSession.interrupt();
|
||||||
try {
|
try {
|
||||||
reader.dispose(exception, recognised);
|
reader.dispose(exception, recognised);
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
@@ -419,8 +417,6 @@ class ConnectionManagerImpl implements ConnectionManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void disposeWriter(boolean exception) {
|
private void disposeWriter(boolean exception) {
|
||||||
// Interrupt the incoming session if an exception occurred,
|
|
||||||
// otherwise wait for the end of stream marker
|
|
||||||
if (exception && incomingSession != null)
|
if (exception && incomingSession != null)
|
||||||
incomingSession.interrupt();
|
incomingSession.interrupt();
|
||||||
try {
|
try {
|
||||||
|
|||||||
@@ -106,7 +106,7 @@ class ConnectionRegistryImpl implements ConnectionRegistry {
|
|||||||
if (m == null) return Collections.emptyList();
|
if (m == null) return Collections.emptyList();
|
||||||
List<ContactId> ids = new ArrayList<>(m.keySet());
|
List<ContactId> ids = new ArrayList<>(m.keySet());
|
||||||
if (LOG.isLoggable(INFO))
|
if (LOG.isLoggable(INFO))
|
||||||
LOG.info(ids.size() + " contacts connected: " + t);
|
LOG.info(ids.size() + " contacts connected");
|
||||||
return ids;
|
return ids;
|
||||||
} finally {
|
} finally {
|
||||||
lock.unlock();
|
lock.unlock();
|
||||||
|
|||||||
@@ -8,7 +8,6 @@ import org.briarproject.bramble.api.lifecycle.Service;
|
|||||||
import org.briarproject.bramble.api.lifecycle.ServiceException;
|
import org.briarproject.bramble.api.lifecycle.ServiceException;
|
||||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||||
import org.briarproject.bramble.api.plugin.ConnectionManager;
|
import org.briarproject.bramble.api.plugin.ConnectionManager;
|
||||||
import org.briarproject.bramble.api.plugin.ConnectionRegistry;
|
|
||||||
import org.briarproject.bramble.api.plugin.Plugin;
|
import org.briarproject.bramble.api.plugin.Plugin;
|
||||||
import org.briarproject.bramble.api.plugin.PluginCallback;
|
import org.briarproject.bramble.api.plugin.PluginCallback;
|
||||||
import org.briarproject.bramble.api.plugin.PluginConfig;
|
import org.briarproject.bramble.api.plugin.PluginConfig;
|
||||||
@@ -30,19 +29,17 @@ import org.briarproject.bramble.api.properties.TransportProperties;
|
|||||||
import org.briarproject.bramble.api.properties.TransportPropertyManager;
|
import org.briarproject.bramble.api.properties.TransportPropertyManager;
|
||||||
import org.briarproject.bramble.api.settings.Settings;
|
import org.briarproject.bramble.api.settings.Settings;
|
||||||
import org.briarproject.bramble.api.settings.SettingsManager;
|
import org.briarproject.bramble.api.settings.SettingsManager;
|
||||||
import org.briarproject.bramble.api.system.Clock;
|
import org.briarproject.bramble.api.ui.UiCallback;
|
||||||
import org.briarproject.bramble.api.system.Scheduler;
|
|
||||||
|
|
||||||
import java.security.SecureRandom;
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
import java.util.concurrent.CopyOnWriteArrayList;
|
import java.util.concurrent.CopyOnWriteArrayList;
|
||||||
import java.util.concurrent.CountDownLatch;
|
import java.util.concurrent.CountDownLatch;
|
||||||
import java.util.concurrent.Executor;
|
import java.util.concurrent.Executor;
|
||||||
import java.util.concurrent.ScheduledExecutorService;
|
|
||||||
import java.util.concurrent.atomic.AtomicBoolean;
|
import java.util.concurrent.atomic.AtomicBoolean;
|
||||||
import java.util.logging.Logger;
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
@@ -60,15 +57,12 @@ class PluginManagerImpl implements PluginManager, Service {
|
|||||||
Logger.getLogger(PluginManagerImpl.class.getName());
|
Logger.getLogger(PluginManagerImpl.class.getName());
|
||||||
|
|
||||||
private final Executor ioExecutor;
|
private final Executor ioExecutor;
|
||||||
private final ScheduledExecutorService scheduler;
|
|
||||||
private final EventBus eventBus;
|
private final EventBus eventBus;
|
||||||
private final PluginConfig pluginConfig;
|
private final PluginConfig pluginConfig;
|
||||||
private final ConnectionManager connectionManager;
|
private final ConnectionManager connectionManager;
|
||||||
private final ConnectionRegistry connectionRegistry;
|
|
||||||
private final SettingsManager settingsManager;
|
private final SettingsManager settingsManager;
|
||||||
private final TransportPropertyManager transportPropertyManager;
|
private final TransportPropertyManager transportPropertyManager;
|
||||||
private final SecureRandom random;
|
private final UiCallback uiCallback;
|
||||||
private final Clock clock;
|
|
||||||
private final Map<TransportId, Plugin> plugins;
|
private final Map<TransportId, Plugin> plugins;
|
||||||
private final List<SimplexPlugin> simplexPlugins;
|
private final List<SimplexPlugin> simplexPlugins;
|
||||||
private final List<DuplexPlugin> duplexPlugins;
|
private final List<DuplexPlugin> duplexPlugins;
|
||||||
@@ -76,41 +70,27 @@ class PluginManagerImpl implements PluginManager, Service {
|
|||||||
private final AtomicBoolean used = new AtomicBoolean(false);
|
private final AtomicBoolean used = new AtomicBoolean(false);
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
PluginManagerImpl(@IoExecutor Executor ioExecutor,
|
PluginManagerImpl(@IoExecutor Executor ioExecutor, EventBus eventBus,
|
||||||
@Scheduler ScheduledExecutorService scheduler, EventBus eventBus,
|
|
||||||
PluginConfig pluginConfig, ConnectionManager connectionManager,
|
PluginConfig pluginConfig, ConnectionManager connectionManager,
|
||||||
ConnectionRegistry connectionRegistry,
|
|
||||||
SettingsManager settingsManager,
|
SettingsManager settingsManager,
|
||||||
TransportPropertyManager transportPropertyManager,
|
TransportPropertyManager transportPropertyManager,
|
||||||
SecureRandom random, Clock clock) {
|
UiCallback uiCallback) {
|
||||||
this.ioExecutor = ioExecutor;
|
this.ioExecutor = ioExecutor;
|
||||||
this.scheduler = scheduler;
|
|
||||||
this.eventBus = eventBus;
|
this.eventBus = eventBus;
|
||||||
this.pluginConfig = pluginConfig;
|
this.pluginConfig = pluginConfig;
|
||||||
this.connectionManager = connectionManager;
|
this.connectionManager = connectionManager;
|
||||||
this.connectionRegistry = connectionRegistry;
|
|
||||||
this.settingsManager = settingsManager;
|
this.settingsManager = settingsManager;
|
||||||
this.transportPropertyManager = transportPropertyManager;
|
this.transportPropertyManager = transportPropertyManager;
|
||||||
this.random = random;
|
this.uiCallback = uiCallback;
|
||||||
this.clock = clock;
|
|
||||||
plugins = new ConcurrentHashMap<>();
|
plugins = new ConcurrentHashMap<>();
|
||||||
simplexPlugins = new CopyOnWriteArrayList<>();
|
simplexPlugins = new CopyOnWriteArrayList<>();
|
||||||
duplexPlugins = new CopyOnWriteArrayList<>();
|
duplexPlugins = new CopyOnWriteArrayList<>();
|
||||||
startLatches = new ConcurrentHashMap<>();
|
startLatches = new ConcurrentHashMap<>();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void startService() {
|
public void startService() throws ServiceException {
|
||||||
if (used.getAndSet(true)) throw new IllegalStateException();
|
if (used.getAndSet(true)) throw new IllegalStateException();
|
||||||
// Instantiate the poller
|
|
||||||
if (pluginConfig.shouldPoll()) {
|
|
||||||
LOG.info("Starting poller");
|
|
||||||
Poller poller = new Poller(ioExecutor, scheduler, connectionManager,
|
|
||||||
connectionRegistry, this, transportPropertyManager, random,
|
|
||||||
clock);
|
|
||||||
eventBus.addListener(poller);
|
|
||||||
}
|
|
||||||
// Instantiate the simplex plugins and start them asynchronously
|
// Instantiate the simplex plugins and start them asynchronously
|
||||||
LOG.info("Starting simplex plugins");
|
LOG.info("Starting simplex plugins");
|
||||||
for (SimplexPluginFactory f : pluginConfig.getSimplexFactories()) {
|
for (SimplexPluginFactory f : pluginConfig.getSimplexFactories()) {
|
||||||
@@ -293,6 +273,26 @@ class PluginManagerImpl implements PluginManager, Service {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Map<ContactId, TransportProperties> getRemoteProperties() {
|
||||||
|
try {
|
||||||
|
return transportPropertyManager.getRemoteProperties(id);
|
||||||
|
} catch (DbException e) {
|
||||||
|
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
||||||
|
return Collections.emptyMap();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public TransportProperties getRemoteProperties(ContactId c) {
|
||||||
|
try {
|
||||||
|
return transportPropertyManager.getRemoteProperties(c, id);
|
||||||
|
} catch (DbException e) {
|
||||||
|
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
||||||
|
return new TransportProperties();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void mergeSettings(Settings s) {
|
public void mergeSettings(Settings s) {
|
||||||
try {
|
try {
|
||||||
@@ -311,6 +311,21 @@ class PluginManagerImpl implements PluginManager, Service {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int showChoice(String[] options, String... message) {
|
||||||
|
return uiCallback.showChoice(options, message);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean showConfirmationMessage(String... message) {
|
||||||
|
return uiCallback.showConfirmationMessage(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void showMessage(String... message) {
|
||||||
|
uiCallback.showMessage(message);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void transportEnabled() {
|
public void transportEnabled() {
|
||||||
eventBus.broadcast(new TransportEnabledEvent(id));
|
eventBus.broadcast(new TransportEnabledEvent(id));
|
||||||
|
|||||||
@@ -1,10 +1,18 @@
|
|||||||
package org.briarproject.bramble.plugin;
|
package org.briarproject.bramble.plugin;
|
||||||
|
|
||||||
|
import org.briarproject.bramble.api.event.EventBus;
|
||||||
|
import org.briarproject.bramble.api.lifecycle.IoExecutor;
|
||||||
import org.briarproject.bramble.api.lifecycle.LifecycleManager;
|
import org.briarproject.bramble.api.lifecycle.LifecycleManager;
|
||||||
import org.briarproject.bramble.api.plugin.BackoffFactory;
|
import org.briarproject.bramble.api.plugin.BackoffFactory;
|
||||||
import org.briarproject.bramble.api.plugin.ConnectionManager;
|
import org.briarproject.bramble.api.plugin.ConnectionManager;
|
||||||
import org.briarproject.bramble.api.plugin.ConnectionRegistry;
|
import org.briarproject.bramble.api.plugin.ConnectionRegistry;
|
||||||
import org.briarproject.bramble.api.plugin.PluginManager;
|
import org.briarproject.bramble.api.plugin.PluginManager;
|
||||||
|
import org.briarproject.bramble.api.system.Clock;
|
||||||
|
import org.briarproject.bramble.api.system.Scheduler;
|
||||||
|
|
||||||
|
import java.security.SecureRandom;
|
||||||
|
import java.util.concurrent.Executor;
|
||||||
|
import java.util.concurrent.ScheduledExecutorService;
|
||||||
|
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
import javax.inject.Singleton;
|
import javax.inject.Singleton;
|
||||||
@@ -18,6 +26,8 @@ public class PluginModule {
|
|||||||
public static class EagerSingletons {
|
public static class EagerSingletons {
|
||||||
@Inject
|
@Inject
|
||||||
PluginManager pluginManager;
|
PluginManager pluginManager;
|
||||||
|
@Inject
|
||||||
|
Poller poller;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Provides
|
@Provides
|
||||||
@@ -25,6 +35,19 @@ public class PluginModule {
|
|||||||
return new BackoffFactoryImpl();
|
return new BackoffFactoryImpl();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Provides
|
||||||
|
@Singleton
|
||||||
|
Poller providePoller(@IoExecutor Executor ioExecutor,
|
||||||
|
@Scheduler ScheduledExecutorService scheduler,
|
||||||
|
ConnectionManager connectionManager,
|
||||||
|
ConnectionRegistry connectionRegistry, PluginManager pluginManager,
|
||||||
|
SecureRandom random, Clock clock, EventBus eventBus) {
|
||||||
|
Poller poller = new Poller(ioExecutor, scheduler, connectionManager,
|
||||||
|
connectionRegistry, pluginManager, random, clock);
|
||||||
|
eventBus.addListener(poller);
|
||||||
|
return poller;
|
||||||
|
}
|
||||||
|
|
||||||
@Provides
|
@Provides
|
||||||
@Singleton
|
@Singleton
|
||||||
ConnectionManager provideConnectionManager(
|
ConnectionManager provideConnectionManager(
|
||||||
|
|||||||
@@ -2,7 +2,6 @@ package org.briarproject.bramble.plugin;
|
|||||||
|
|
||||||
import org.briarproject.bramble.api.contact.ContactId;
|
import org.briarproject.bramble.api.contact.ContactId;
|
||||||
import org.briarproject.bramble.api.contact.event.ContactStatusChangedEvent;
|
import org.briarproject.bramble.api.contact.event.ContactStatusChangedEvent;
|
||||||
import org.briarproject.bramble.api.db.DbException;
|
|
||||||
import org.briarproject.bramble.api.event.Event;
|
import org.briarproject.bramble.api.event.Event;
|
||||||
import org.briarproject.bramble.api.event.EventListener;
|
import org.briarproject.bramble.api.event.EventListener;
|
||||||
import org.briarproject.bramble.api.lifecycle.IoExecutor;
|
import org.briarproject.bramble.api.lifecycle.IoExecutor;
|
||||||
@@ -20,13 +19,10 @@ import org.briarproject.bramble.api.plugin.event.ConnectionOpenedEvent;
|
|||||||
import org.briarproject.bramble.api.plugin.event.TransportDisabledEvent;
|
import org.briarproject.bramble.api.plugin.event.TransportDisabledEvent;
|
||||||
import org.briarproject.bramble.api.plugin.event.TransportEnabledEvent;
|
import org.briarproject.bramble.api.plugin.event.TransportEnabledEvent;
|
||||||
import org.briarproject.bramble.api.plugin.simplex.SimplexPlugin;
|
import org.briarproject.bramble.api.plugin.simplex.SimplexPlugin;
|
||||||
import org.briarproject.bramble.api.properties.TransportProperties;
|
|
||||||
import org.briarproject.bramble.api.properties.TransportPropertyManager;
|
|
||||||
import org.briarproject.bramble.api.system.Clock;
|
import org.briarproject.bramble.api.system.Clock;
|
||||||
import org.briarproject.bramble.api.system.Scheduler;
|
import org.briarproject.bramble.api.system.Scheduler;
|
||||||
|
|
||||||
import java.security.SecureRandom;
|
import java.security.SecureRandom;
|
||||||
import java.util.Collection;
|
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
@@ -39,10 +35,10 @@ import java.util.concurrent.locks.ReentrantLock;
|
|||||||
import java.util.logging.Logger;
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
import javax.annotation.concurrent.ThreadSafe;
|
import javax.annotation.concurrent.ThreadSafe;
|
||||||
|
import javax.inject.Inject;
|
||||||
|
|
||||||
import static java.util.concurrent.TimeUnit.MILLISECONDS;
|
import static java.util.concurrent.TimeUnit.MILLISECONDS;
|
||||||
import static java.util.logging.Level.INFO;
|
import static java.util.logging.Level.INFO;
|
||||||
import static java.util.logging.Level.WARNING;
|
|
||||||
|
|
||||||
@ThreadSafe
|
@ThreadSafe
|
||||||
@NotNullByDefault
|
@NotNullByDefault
|
||||||
@@ -55,25 +51,23 @@ class Poller implements EventListener {
|
|||||||
private final ConnectionManager connectionManager;
|
private final ConnectionManager connectionManager;
|
||||||
private final ConnectionRegistry connectionRegistry;
|
private final ConnectionRegistry connectionRegistry;
|
||||||
private final PluginManager pluginManager;
|
private final PluginManager pluginManager;
|
||||||
private final TransportPropertyManager transportPropertyManager;
|
|
||||||
private final SecureRandom random;
|
private final SecureRandom random;
|
||||||
private final Clock clock;
|
private final Clock clock;
|
||||||
private final Lock lock;
|
private final Lock lock;
|
||||||
private final Map<TransportId, ScheduledPollTask> tasks; // Locking: lock
|
private final Map<TransportId, ScheduledPollTask> tasks; // Locking: lock
|
||||||
private final Set<TransportId> polling; // Locking: lock
|
private final Set<TransportId> polling; // Locking: lock
|
||||||
|
|
||||||
|
@Inject
|
||||||
Poller(@IoExecutor Executor ioExecutor,
|
Poller(@IoExecutor Executor ioExecutor,
|
||||||
@Scheduler ScheduledExecutorService scheduler,
|
@Scheduler ScheduledExecutorService scheduler,
|
||||||
ConnectionManager connectionManager,
|
ConnectionManager connectionManager,
|
||||||
ConnectionRegistry connectionRegistry, PluginManager pluginManager,
|
ConnectionRegistry connectionRegistry, PluginManager pluginManager,
|
||||||
TransportPropertyManager transportPropertyManager,
|
|
||||||
SecureRandom random, Clock clock) {
|
SecureRandom random, Clock clock) {
|
||||||
this.ioExecutor = ioExecutor;
|
this.ioExecutor = ioExecutor;
|
||||||
this.scheduler = scheduler;
|
this.scheduler = scheduler;
|
||||||
this.connectionManager = connectionManager;
|
this.connectionManager = connectionManager;
|
||||||
this.connectionRegistry = connectionRegistry;
|
this.connectionRegistry = connectionRegistry;
|
||||||
this.pluginManager = pluginManager;
|
this.pluginManager = pluginManager;
|
||||||
this.transportPropertyManager = transportPropertyManager;
|
|
||||||
this.random = random;
|
this.random = random;
|
||||||
this.clock = clock;
|
this.clock = clock;
|
||||||
lock = new ReentrantLock();
|
lock = new ReentrantLock();
|
||||||
@@ -85,10 +79,12 @@ class Poller implements EventListener {
|
|||||||
public void eventOccurred(Event e) {
|
public void eventOccurred(Event e) {
|
||||||
if (e instanceof ContactStatusChangedEvent) {
|
if (e instanceof ContactStatusChangedEvent) {
|
||||||
ContactStatusChangedEvent c = (ContactStatusChangedEvent) e;
|
ContactStatusChangedEvent c = (ContactStatusChangedEvent) e;
|
||||||
|
/*
|
||||||
if (c.isActive()) {
|
if (c.isActive()) {
|
||||||
// Connect to the newly activated contact
|
// Connect to the newly activated contact
|
||||||
connectToContact(c.getContactId());
|
connectToContact(c.getContactId());
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
} else if (e instanceof ConnectionClosedEvent) {
|
} else if (e instanceof ConnectionClosedEvent) {
|
||||||
ConnectionClosedEvent c = (ConnectionClosedEvent) e;
|
ConnectionClosedEvent c = (ConnectionClosedEvent) e;
|
||||||
// Reschedule polling, the polling interval may have decreased
|
// Reschedule polling, the polling interval may have decreased
|
||||||
@@ -130,15 +126,10 @@ class Poller implements EventListener {
|
|||||||
private void connectToContact(ContactId c, SimplexPlugin p) {
|
private void connectToContact(ContactId c, SimplexPlugin p) {
|
||||||
ioExecutor.execute(() -> {
|
ioExecutor.execute(() -> {
|
||||||
TransportId t = p.getId();
|
TransportId t = p.getId();
|
||||||
if (connectionRegistry.isConnected(c, t)) return;
|
if (!connectionRegistry.isConnected(c, t)) {
|
||||||
try {
|
TransportConnectionWriter w = p.createWriter(c);
|
||||||
TransportProperties props =
|
|
||||||
transportPropertyManager.getRemoteProperties(c, t);
|
|
||||||
TransportConnectionWriter w = p.createWriter(props);
|
|
||||||
if (w != null)
|
if (w != null)
|
||||||
connectionManager.manageOutgoingConnection(c, t, w);
|
connectionManager.manageOutgoingConnection(c, t, w);
|
||||||
} catch (DbException e) {
|
|
||||||
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -146,15 +137,10 @@ class Poller implements EventListener {
|
|||||||
private void connectToContact(ContactId c, DuplexPlugin p) {
|
private void connectToContact(ContactId c, DuplexPlugin p) {
|
||||||
ioExecutor.execute(() -> {
|
ioExecutor.execute(() -> {
|
||||||
TransportId t = p.getId();
|
TransportId t = p.getId();
|
||||||
if (connectionRegistry.isConnected(c, t)) return;
|
if (!connectionRegistry.isConnected(c, t)) {
|
||||||
try {
|
DuplexTransportConnection d = p.createConnection(c);
|
||||||
TransportProperties props =
|
|
||||||
transportPropertyManager.getRemoteProperties(c, t);
|
|
||||||
DuplexTransportConnection d = p.createConnection(props);
|
|
||||||
if (d != null)
|
if (d != null)
|
||||||
connectionManager.manageOutgoingConnection(c, t, d);
|
connectionManager.manageOutgoingConnection(c, t, d);
|
||||||
} catch (DbException e) {
|
|
||||||
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -206,17 +192,7 @@ class Poller implements EventListener {
|
|||||||
private void poll(Plugin p) {
|
private void poll(Plugin p) {
|
||||||
TransportId t = p.getId();
|
TransportId t = p.getId();
|
||||||
if (LOG.isLoggable(INFO)) LOG.info("Polling plugin " + t);
|
if (LOG.isLoggable(INFO)) LOG.info("Polling plugin " + t);
|
||||||
try {
|
p.poll(connectionRegistry.getConnectedContacts(t));
|
||||||
Map<ContactId, TransportProperties> remote =
|
|
||||||
transportPropertyManager.getRemoteProperties(t);
|
|
||||||
Collection<ContactId> connected =
|
|
||||||
connectionRegistry.getConnectedContacts(t);
|
|
||||||
remote = new HashMap<>(remote);
|
|
||||||
remote.keySet().removeAll(connected);
|
|
||||||
if (!remote.isEmpty()) p.poll(remote);
|
|
||||||
} catch (DbException e) {
|
|
||||||
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private class ScheduledPollTask {
|
private class ScheduledPollTask {
|
||||||
|
|||||||
@@ -27,6 +27,7 @@ import org.briarproject.bramble.util.StringUtils;
|
|||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.security.SecureRandom;
|
import java.security.SecureRandom;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collection;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
@@ -58,7 +59,7 @@ abstract class BluetoothPlugin<SS> implements DuplexPlugin, EventListener {
|
|||||||
* How many milliseconds to pause between connection attempts when
|
* How many milliseconds to pause between connection attempts when
|
||||||
* polling, to avoid interfering with other Bluetooth or wifi connections.
|
* polling, to avoid interfering with other Bluetooth or wifi connections.
|
||||||
*/
|
*/
|
||||||
private static final int POLLING_PAUSE_MS = 1000;
|
private static final int POLLING_PAUSE_MS = 3000;
|
||||||
|
|
||||||
final BluetoothConnectionLimiter connectionLimiter;
|
final BluetoothConnectionLimiter connectionLimiter;
|
||||||
|
|
||||||
@@ -257,18 +258,21 @@ abstract class BluetoothPlugin<SS> implements DuplexPlugin, EventListener {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void poll(Map<ContactId, TransportProperties> contacts) {
|
public void poll(Collection<ContactId> connected) {
|
||||||
if (!isRunning() || !shouldAllowContactConnections()) return;
|
if (!isRunning() || !shouldAllowContactConnections()) return;
|
||||||
backoff.increment();
|
backoff.increment();
|
||||||
// Try to connect to known devices in a random order
|
// Try to connect to known devices in a random order
|
||||||
List<ContactId> keys = new ArrayList<>(contacts.keySet());
|
Map<ContactId, TransportProperties> remote =
|
||||||
|
callback.getRemoteProperties();
|
||||||
|
List<ContactId> keys = new ArrayList<>(remote.keySet());
|
||||||
Collections.shuffle(keys);
|
Collections.shuffle(keys);
|
||||||
ioExecutor.execute(() -> {
|
ioExecutor.execute(() -> {
|
||||||
boolean first = true;
|
boolean first = true;
|
||||||
for (ContactId c : keys) {
|
for (ContactId c : keys) {
|
||||||
if (!isRunning() || !shouldAllowContactConnections()) return;
|
if (!isRunning() || !shouldAllowContactConnections()) return;
|
||||||
if (!connectionLimiter.canOpenContactConnection()) return;
|
if (!connectionLimiter.canOpenContactConnection()) return;
|
||||||
TransportProperties p = contacts.get(c);
|
if (connected.contains(c)) continue;
|
||||||
|
TransportProperties p = remote.get(c);
|
||||||
String address = p.get(PROP_ADDRESS);
|
String address = p.get(PROP_ADDRESS);
|
||||||
if (StringUtils.isNullOrEmpty(address)) continue;
|
if (StringUtils.isNullOrEmpty(address)) continue;
|
||||||
String uuid = p.get(PROP_UUID);
|
String uuid = p.get(PROP_UUID);
|
||||||
@@ -327,9 +331,10 @@ abstract class BluetoothPlugin<SS> implements DuplexPlugin, EventListener {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public DuplexTransportConnection createConnection(TransportProperties p) {
|
public DuplexTransportConnection createConnection(ContactId c) {
|
||||||
if (!isRunning() || !shouldAllowContactConnections()) return null;
|
if (!isRunning() || !shouldAllowContactConnections()) return null;
|
||||||
if (!connectionLimiter.canOpenContactConnection()) return null;
|
if (!connectionLimiter.canOpenContactConnection()) return null;
|
||||||
|
TransportProperties p = callback.getRemoteProperties(c);
|
||||||
String address = p.get(PROP_ADDRESS);
|
String address = p.get(PROP_ADDRESS);
|
||||||
if (StringUtils.isNullOrEmpty(address)) return null;
|
if (StringUtils.isNullOrEmpty(address)) return null;
|
||||||
String uuid = p.get(PROP_UUID);
|
String uuid = p.get(PROP_UUID);
|
||||||
|
|||||||
@@ -1,21 +1,27 @@
|
|||||||
package org.briarproject.bramble.plugin.file;
|
package org.briarproject.bramble.plugin.file;
|
||||||
|
|
||||||
|
import org.briarproject.bramble.api.contact.ContactId;
|
||||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||||
import org.briarproject.bramble.api.plugin.TransportConnectionReader;
|
import org.briarproject.bramble.api.plugin.TransportConnectionReader;
|
||||||
import org.briarproject.bramble.api.plugin.TransportConnectionWriter;
|
import org.briarproject.bramble.api.plugin.TransportConnectionWriter;
|
||||||
import org.briarproject.bramble.api.plugin.simplex.SimplexPlugin;
|
import org.briarproject.bramble.api.plugin.simplex.SimplexPlugin;
|
||||||
import org.briarproject.bramble.api.plugin.simplex.SimplexPluginCallback;
|
import org.briarproject.bramble.api.plugin.simplex.SimplexPluginCallback;
|
||||||
import org.briarproject.bramble.api.properties.TransportProperties;
|
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.FileInputStream;
|
import java.io.FileInputStream;
|
||||||
import java.io.FileOutputStream;
|
import java.io.FileOutputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.io.OutputStream;
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.Locale;
|
||||||
|
import java.util.concurrent.Executor;
|
||||||
|
import java.util.concurrent.atomic.AtomicBoolean;
|
||||||
import java.util.logging.Logger;
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
|
import javax.annotation.Nullable;
|
||||||
|
|
||||||
import static java.util.logging.Level.WARNING;
|
import static java.util.logging.Level.WARNING;
|
||||||
import static org.briarproject.bramble.api.plugin.FileConstants.PROP_PATH;
|
import static org.briarproject.bramble.api.transport.TransportConstants.MIN_STREAM_LENGTH;
|
||||||
import static org.briarproject.bramble.util.StringUtils.isNullOrEmpty;
|
|
||||||
|
|
||||||
@NotNullByDefault
|
@NotNullByDefault
|
||||||
abstract class FilePlugin implements SimplexPlugin {
|
abstract class FilePlugin implements SimplexPlugin {
|
||||||
@@ -23,15 +29,25 @@ abstract class FilePlugin implements SimplexPlugin {
|
|||||||
private static final Logger LOG =
|
private static final Logger LOG =
|
||||||
Logger.getLogger(FilePlugin.class.getName());
|
Logger.getLogger(FilePlugin.class.getName());
|
||||||
|
|
||||||
|
protected final Executor ioExecutor;
|
||||||
protected final SimplexPluginCallback callback;
|
protected final SimplexPluginCallback callback;
|
||||||
protected final int maxLatency;
|
protected final int maxLatency;
|
||||||
|
protected final AtomicBoolean used = new AtomicBoolean(false);
|
||||||
|
|
||||||
protected abstract void writerFinished(File f, boolean exception);
|
protected volatile boolean running = false;
|
||||||
|
|
||||||
protected abstract void readerFinished(File f, boolean exception,
|
@Nullable
|
||||||
boolean recognised);
|
protected abstract File chooseOutputDirectory();
|
||||||
|
|
||||||
FilePlugin(SimplexPluginCallback callback, int maxLatency) {
|
protected abstract Collection<File> findFilesByName(String filename);
|
||||||
|
|
||||||
|
protected abstract void writerFinished(File f);
|
||||||
|
|
||||||
|
protected abstract void readerFinished(File f);
|
||||||
|
|
||||||
|
protected FilePlugin(Executor ioExecutor, SimplexPluginCallback callback,
|
||||||
|
int maxLatency) {
|
||||||
|
this.ioExecutor = ioExecutor;
|
||||||
this.callback = callback;
|
this.callback = callback;
|
||||||
this.maxLatency = maxLatency;
|
this.maxLatency = maxLatency;
|
||||||
}
|
}
|
||||||
@@ -42,36 +58,81 @@ abstract class FilePlugin implements SimplexPlugin {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public TransportConnectionReader createReader(TransportProperties p) {
|
public int getMaxIdleTime() {
|
||||||
if (!isRunning()) return null;
|
return Integer.MAX_VALUE; // We don't need keepalives
|
||||||
String path = p.get(PROP_PATH);
|
}
|
||||||
if (isNullOrEmpty(path)) return null;
|
|
||||||
|
@Override
|
||||||
|
public boolean isRunning() {
|
||||||
|
return running;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public TransportConnectionReader createReader(ContactId c) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public TransportConnectionWriter createWriter(ContactId c) {
|
||||||
|
if (!running) return null;
|
||||||
|
return createWriter(createConnectionFilename());
|
||||||
|
}
|
||||||
|
|
||||||
|
private String createConnectionFilename() {
|
||||||
|
StringBuilder s = new StringBuilder(12);
|
||||||
|
for (int i = 0; i < 8; i++) s.append((char) ('a' + Math.random() * 26));
|
||||||
|
s.append(".dat");
|
||||||
|
return s.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Package access for testing
|
||||||
|
boolean isPossibleConnectionFilename(String filename) {
|
||||||
|
return filename.toLowerCase(Locale.US).matches("[a-z]{8}\\.dat");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
private TransportConnectionWriter createWriter(String filename) {
|
||||||
|
if (!running) return null;
|
||||||
|
File dir = chooseOutputDirectory();
|
||||||
|
if (dir == null || !dir.exists() || !dir.isDirectory()) return null;
|
||||||
|
File f = new File(dir, filename);
|
||||||
try {
|
try {
|
||||||
File file = new File(path);
|
long capacity = dir.getFreeSpace();
|
||||||
FileInputStream in = new FileInputStream(file);
|
if (capacity < MIN_STREAM_LENGTH) return null;
|
||||||
return new FileTransportReader(file, in, this);
|
OutputStream out = new FileOutputStream(f);
|
||||||
|
return new FileTransportWriter(f, out, capacity, this);
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
||||||
|
f.delete();
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
protected void createReaderFromFile(File f) {
|
||||||
public TransportConnectionWriter createWriter(TransportProperties p) {
|
if (!running) return;
|
||||||
if (!isRunning()) return null;
|
ioExecutor.execute(new ReaderCreator(f));
|
||||||
String path = p.get(PROP_PATH);
|
}
|
||||||
if (isNullOrEmpty(path)) return null;
|
|
||||||
try {
|
private class ReaderCreator implements Runnable {
|
||||||
File file = new File(path);
|
|
||||||
if (!file.exists() && !file.createNewFile()) {
|
private final File file;
|
||||||
LOG.info("Failed to create file");
|
|
||||||
return null;
|
private ReaderCreator(File file) {
|
||||||
|
this.file = file;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
if (isPossibleConnectionFilename(file.getName())) {
|
||||||
|
try {
|
||||||
|
FileInputStream in = new FileInputStream(file);
|
||||||
|
callback.readerCreated(new FileTransportReader(file, in,
|
||||||
|
FilePlugin.this));
|
||||||
|
} catch (IOException e) {
|
||||||
|
if (LOG.isLoggable(WARNING))
|
||||||
|
LOG.log(WARNING, e.toString(), e);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
FileOutputStream out = new FileOutputStream(file);
|
|
||||||
return new FileTransportWriter(file, out, this);
|
|
||||||
} catch (IOException e) {
|
|
||||||
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -38,6 +38,9 @@ class FileTransportReader implements TransportConnectionReader {
|
|||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
||||||
}
|
}
|
||||||
plugin.readerFinished(file, exception, recognised);
|
if (recognised) {
|
||||||
|
file.delete();
|
||||||
|
plugin.readerFinished(file);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,11 +18,14 @@ class FileTransportWriter implements TransportConnectionWriter {
|
|||||||
|
|
||||||
private final File file;
|
private final File file;
|
||||||
private final OutputStream out;
|
private final OutputStream out;
|
||||||
|
private final long capacity;
|
||||||
private final FilePlugin plugin;
|
private final FilePlugin plugin;
|
||||||
|
|
||||||
FileTransportWriter(File file, OutputStream out, FilePlugin plugin) {
|
FileTransportWriter(File file, OutputStream out, long capacity,
|
||||||
|
FilePlugin plugin) {
|
||||||
this.file = file;
|
this.file = file;
|
||||||
this.out = out;
|
this.out = out;
|
||||||
|
this.capacity = capacity;
|
||||||
this.plugin = plugin;
|
this.plugin = plugin;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -36,6 +39,11 @@ class FileTransportWriter implements TransportConnectionWriter {
|
|||||||
return plugin.getMaxIdleTime();
|
return plugin.getMaxIdleTime();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public long getCapacity() {
|
||||||
|
return capacity;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public OutputStream getOutputStream() {
|
public OutputStream getOutputStream() {
|
||||||
return out;
|
return out;
|
||||||
@@ -48,6 +56,7 @@ class FileTransportWriter implements TransportConnectionWriter {
|
|||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
||||||
}
|
}
|
||||||
plugin.writerFinished(file, exception);
|
if (exception) file.delete();
|
||||||
|
else plugin.writerFinished(file);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -207,16 +207,20 @@ abstract class TcpPlugin implements DuplexPlugin {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void poll(Map<ContactId, TransportProperties> contacts) {
|
public void poll(Collection<ContactId> connected) {
|
||||||
if (!isRunning()) return;
|
if (!isRunning()) return;
|
||||||
backoff.increment();
|
backoff.increment();
|
||||||
for (Entry<ContactId, TransportProperties> e : contacts.entrySet()) {
|
Map<ContactId, TransportProperties> remote =
|
||||||
connectAndCallBack(e.getKey(), e.getValue());
|
callback.getRemoteProperties();
|
||||||
|
for (Entry<ContactId, TransportProperties> e : remote.entrySet()) {
|
||||||
|
ContactId c = e.getKey();
|
||||||
|
if (!connected.contains(c)) connectAndCallBack(c, e.getValue());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void connectAndCallBack(ContactId c, TransportProperties p) {
|
private void connectAndCallBack(ContactId c, TransportProperties p) {
|
||||||
ioExecutor.execute(() -> {
|
ioExecutor.execute(() -> {
|
||||||
|
if (!isRunning()) return;
|
||||||
DuplexTransportConnection d = createConnection(p);
|
DuplexTransportConnection d = createConnection(p);
|
||||||
if (d != null) {
|
if (d != null) {
|
||||||
backoff.reset();
|
backoff.reset();
|
||||||
@@ -226,8 +230,13 @@ abstract class TcpPlugin implements DuplexPlugin {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public DuplexTransportConnection createConnection(TransportProperties p) {
|
public DuplexTransportConnection createConnection(ContactId c) {
|
||||||
if (!isRunning()) return null;
|
if (!isRunning()) return null;
|
||||||
|
return createConnection(callback.getRemoteProperties(c));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
private DuplexTransportConnection createConnection(TransportProperties p) {
|
||||||
for (InetSocketAddress remote : getRemoteSocketAddresses(p)) {
|
for (InetSocketAddress remote : getRemoteSocketAddresses(p)) {
|
||||||
if (!isConnectable(remote)) {
|
if (!isConnectable(remote)) {
|
||||||
if (LOG.isLoggable(INFO)) {
|
if (LOG.isLoggable(INFO)) {
|
||||||
|
|||||||
@@ -1,12 +1,7 @@
|
|||||||
package org.briarproject.bramble.reporting;
|
package org.briarproject.bramble.reporting;
|
||||||
|
|
||||||
import org.briarproject.bramble.api.crypto.CryptoComponent;
|
import org.briarproject.bramble.api.crypto.CryptoComponent;
|
||||||
import org.briarproject.bramble.api.event.Event;
|
|
||||||
import org.briarproject.bramble.api.event.EventListener;
|
|
||||||
import org.briarproject.bramble.api.lifecycle.IoExecutor;
|
|
||||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||||
import org.briarproject.bramble.api.plugin.TorConstants;
|
|
||||||
import org.briarproject.bramble.api.plugin.event.TransportEnabledEvent;
|
|
||||||
import org.briarproject.bramble.api.reporting.DevConfig;
|
import org.briarproject.bramble.api.reporting.DevConfig;
|
||||||
import org.briarproject.bramble.api.reporting.DevReporter;
|
import org.briarproject.bramble.api.reporting.DevReporter;
|
||||||
import org.briarproject.bramble.util.IoUtils;
|
import org.briarproject.bramble.util.IoUtils;
|
||||||
@@ -23,19 +18,17 @@ import java.io.OutputStream;
|
|||||||
import java.io.OutputStreamWriter;
|
import java.io.OutputStreamWriter;
|
||||||
import java.io.PrintWriter;
|
import java.io.PrintWriter;
|
||||||
import java.net.Socket;
|
import java.net.Socket;
|
||||||
import java.util.concurrent.Executor;
|
|
||||||
import java.util.logging.Logger;
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
import javax.annotation.concurrent.Immutable;
|
import javax.annotation.concurrent.Immutable;
|
||||||
import javax.inject.Inject;
|
|
||||||
import javax.net.SocketFactory;
|
import javax.net.SocketFactory;
|
||||||
|
|
||||||
import static java.util.logging.Level.WARNING;
|
import static java.util.logging.Level.WARNING;
|
||||||
|
|
||||||
@Immutable
|
@Immutable
|
||||||
@NotNullByDefault
|
@NotNullByDefault
|
||||||
class DevReporterImpl implements DevReporter, EventListener {
|
class DevReporterImpl implements DevReporter {
|
||||||
|
|
||||||
private static final Logger LOG =
|
private static final Logger LOG =
|
||||||
Logger.getLogger(DevReporterImpl.class.getName());
|
Logger.getLogger(DevReporterImpl.class.getName());
|
||||||
@@ -43,15 +36,12 @@ class DevReporterImpl implements DevReporter, EventListener {
|
|||||||
private static final int SOCKET_TIMEOUT = 30 * 1000; // 30 seconds
|
private static final int SOCKET_TIMEOUT = 30 * 1000; // 30 seconds
|
||||||
private static final int LINE_LENGTH = 70;
|
private static final int LINE_LENGTH = 70;
|
||||||
|
|
||||||
private final Executor ioExecutor;
|
|
||||||
private final CryptoComponent crypto;
|
private final CryptoComponent crypto;
|
||||||
private final DevConfig devConfig;
|
private final DevConfig devConfig;
|
||||||
private final SocketFactory torSocketFactory;
|
private final SocketFactory torSocketFactory;
|
||||||
|
|
||||||
@Inject
|
DevReporterImpl(CryptoComponent crypto, DevConfig devConfig,
|
||||||
DevReporterImpl(@IoExecutor Executor ioExecutor, CryptoComponent crypto,
|
SocketFactory torSocketFactory) {
|
||||||
DevConfig devConfig, SocketFactory torSocketFactory) {
|
|
||||||
this.ioExecutor = ioExecutor;
|
|
||||||
this.crypto = crypto;
|
this.crypto = crypto;
|
||||||
this.devConfig = devConfig;
|
this.devConfig = devConfig;
|
||||||
this.torSocketFactory = torSocketFactory;
|
this.torSocketFactory = torSocketFactory;
|
||||||
@@ -73,7 +63,6 @@ class DevReporterImpl implements DevReporter, EventListener {
|
|||||||
@Override
|
@Override
|
||||||
public void encryptReportToFile(File reportDir, String filename,
|
public void encryptReportToFile(File reportDir, String filename,
|
||||||
String report) throws FileNotFoundException {
|
String report) throws FileNotFoundException {
|
||||||
LOG.info("Encrypting report to file");
|
|
||||||
byte[] plaintext = StringUtils.toUtf8(report);
|
byte[] plaintext = StringUtils.toUtf8(report);
|
||||||
byte[] ciphertext = crypto.encryptToKey(devConfig.getDevPublicKey(),
|
byte[] ciphertext = crypto.encryptToKey(devConfig.getDevPublicKey(),
|
||||||
plaintext);
|
plaintext);
|
||||||
@@ -93,17 +82,7 @@ class DevReporterImpl implements DevReporter, EventListener {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void eventOccurred(Event e) {
|
public void sendReports(File reportDir) {
|
||||||
if (e instanceof TransportEnabledEvent) {
|
|
||||||
TransportEnabledEvent t = (TransportEnabledEvent) e;
|
|
||||||
if (t.getTransportId().equals(TorConstants.ID))
|
|
||||||
ioExecutor.execute(this::sendReports);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void sendReports() {
|
|
||||||
File reportDir = devConfig.getReportDir();
|
|
||||||
File[] reports = reportDir.listFiles();
|
File[] reports = reportDir.listFiles();
|
||||||
if (reports == null || reports.length == 0)
|
if (reports == null || reports.length == 0)
|
||||||
return; // No reports to send
|
return; // No reports to send
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
package org.briarproject.bramble.reporting;
|
package org.briarproject.bramble.reporting;
|
||||||
|
|
||||||
import org.briarproject.bramble.api.event.EventBus;
|
import org.briarproject.bramble.api.crypto.CryptoComponent;
|
||||||
|
import org.briarproject.bramble.api.reporting.DevConfig;
|
||||||
import org.briarproject.bramble.api.reporting.DevReporter;
|
import org.briarproject.bramble.api.reporting.DevReporter;
|
||||||
|
|
||||||
import javax.inject.Inject;
|
import javax.net.SocketFactory;
|
||||||
import javax.inject.Singleton;
|
|
||||||
|
|
||||||
import dagger.Module;
|
import dagger.Module;
|
||||||
import dagger.Provides;
|
import dagger.Provides;
|
||||||
@@ -12,16 +12,9 @@ import dagger.Provides;
|
|||||||
@Module
|
@Module
|
||||||
public class ReportingModule {
|
public class ReportingModule {
|
||||||
|
|
||||||
public static class EagerSingletons {
|
|
||||||
@Inject
|
|
||||||
DevReporter devReporter;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Provides
|
@Provides
|
||||||
@Singleton
|
DevReporter provideDevReporter(CryptoComponent crypto,
|
||||||
DevReporter provideDevReporter(DevReporterImpl devReporter,
|
DevConfig devConfig, SocketFactory torSocketFactory) {
|
||||||
EventBus eventBus) {
|
return new DevReporterImpl(crypto, devConfig, torSocketFactory);
|
||||||
eventBus.addListener(devReporter);
|
|
||||||
return devReporter;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -23,7 +23,6 @@ import org.briarproject.bramble.api.sync.event.MessageSharedEvent;
|
|||||||
import org.briarproject.bramble.api.sync.event.MessageToAckEvent;
|
import org.briarproject.bramble.api.sync.event.MessageToAckEvent;
|
||||||
import org.briarproject.bramble.api.sync.event.MessageToRequestEvent;
|
import org.briarproject.bramble.api.sync.event.MessageToRequestEvent;
|
||||||
import org.briarproject.bramble.api.system.Clock;
|
import org.briarproject.bramble.api.system.Clock;
|
||||||
import org.briarproject.bramble.api.transport.StreamWriter;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
@@ -68,7 +67,6 @@ class DuplexOutgoingSession implements SyncSession, EventListener {
|
|||||||
private final Clock clock;
|
private final Clock clock;
|
||||||
private final ContactId contactId;
|
private final ContactId contactId;
|
||||||
private final int maxLatency, maxIdleTime;
|
private final int maxLatency, maxIdleTime;
|
||||||
private final StreamWriter streamWriter;
|
|
||||||
private final SyncRecordWriter recordWriter;
|
private final SyncRecordWriter recordWriter;
|
||||||
private final BlockingQueue<ThrowingRunnable<IOException>> writerTasks;
|
private final BlockingQueue<ThrowingRunnable<IOException>> writerTasks;
|
||||||
|
|
||||||
@@ -83,8 +81,7 @@ class DuplexOutgoingSession implements SyncSession, EventListener {
|
|||||||
|
|
||||||
DuplexOutgoingSession(DatabaseComponent db, Executor dbExecutor,
|
DuplexOutgoingSession(DatabaseComponent db, Executor dbExecutor,
|
||||||
EventBus eventBus, Clock clock, ContactId contactId, int maxLatency,
|
EventBus eventBus, Clock clock, ContactId contactId, int maxLatency,
|
||||||
int maxIdleTime, StreamWriter streamWriter,
|
int maxIdleTime, SyncRecordWriter recordWriter) {
|
||||||
SyncRecordWriter recordWriter) {
|
|
||||||
this.db = db;
|
this.db = db;
|
||||||
this.dbExecutor = dbExecutor;
|
this.dbExecutor = dbExecutor;
|
||||||
this.eventBus = eventBus;
|
this.eventBus = eventBus;
|
||||||
@@ -92,7 +89,6 @@ class DuplexOutgoingSession implements SyncSession, EventListener {
|
|||||||
this.contactId = contactId;
|
this.contactId = contactId;
|
||||||
this.maxLatency = maxLatency;
|
this.maxLatency = maxLatency;
|
||||||
this.maxIdleTime = maxIdleTime;
|
this.maxIdleTime = maxIdleTime;
|
||||||
this.streamWriter = streamWriter;
|
|
||||||
this.recordWriter = recordWriter;
|
this.recordWriter = recordWriter;
|
||||||
writerTasks = new LinkedBlockingQueue<>();
|
writerTasks = new LinkedBlockingQueue<>();
|
||||||
}
|
}
|
||||||
@@ -153,7 +149,7 @@ class DuplexOutgoingSession implements SyncSession, EventListener {
|
|||||||
dataToFlush = true;
|
dataToFlush = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
streamWriter.sendEndOfStream();
|
if (dataToFlush) recordWriter.flush();
|
||||||
} catch (InterruptedException e) {
|
} catch (InterruptedException e) {
|
||||||
LOG.info("Interrupted while waiting for a record to write");
|
LOG.info("Interrupted while waiting for a record to write");
|
||||||
Thread.currentThread().interrupt();
|
Thread.currentThread().interrupt();
|
||||||
|
|||||||
@@ -63,11 +63,7 @@ class IncomingSession implements SyncSession, EventListener {
|
|||||||
eventBus.addListener(this);
|
eventBus.addListener(this);
|
||||||
try {
|
try {
|
||||||
// Read records until interrupted or EOF
|
// Read records until interrupted or EOF
|
||||||
while (!interrupted) {
|
while (!interrupted && !recordReader.eof()) {
|
||||||
if (recordReader.eof()) {
|
|
||||||
LOG.info("End of stream");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (recordReader.hasAck()) {
|
if (recordReader.hasAck()) {
|
||||||
Ack a = recordReader.readAck();
|
Ack a = recordReader.readAck();
|
||||||
dbExecutor.execute(new ReceiveAck(a));
|
dbExecutor.execute(new ReceiveAck(a));
|
||||||
|
|||||||
@@ -15,7 +15,6 @@ import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
|||||||
import org.briarproject.bramble.api.sync.Ack;
|
import org.briarproject.bramble.api.sync.Ack;
|
||||||
import org.briarproject.bramble.api.sync.SyncRecordWriter;
|
import org.briarproject.bramble.api.sync.SyncRecordWriter;
|
||||||
import org.briarproject.bramble.api.sync.SyncSession;
|
import org.briarproject.bramble.api.sync.SyncSession;
|
||||||
import org.briarproject.bramble.api.transport.StreamWriter;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
@@ -52,7 +51,6 @@ class SimplexOutgoingSession implements SyncSession, EventListener {
|
|||||||
private final EventBus eventBus;
|
private final EventBus eventBus;
|
||||||
private final ContactId contactId;
|
private final ContactId contactId;
|
||||||
private final int maxLatency;
|
private final int maxLatency;
|
||||||
private final StreamWriter streamWriter;
|
|
||||||
private final SyncRecordWriter recordWriter;
|
private final SyncRecordWriter recordWriter;
|
||||||
private final AtomicInteger outstandingQueries;
|
private final AtomicInteger outstandingQueries;
|
||||||
private final BlockingQueue<ThrowingRunnable<IOException>> writerTasks;
|
private final BlockingQueue<ThrowingRunnable<IOException>> writerTasks;
|
||||||
@@ -60,14 +58,13 @@ class SimplexOutgoingSession implements SyncSession, EventListener {
|
|||||||
private volatile boolean interrupted = false;
|
private volatile boolean interrupted = false;
|
||||||
|
|
||||||
SimplexOutgoingSession(DatabaseComponent db, Executor dbExecutor,
|
SimplexOutgoingSession(DatabaseComponent db, Executor dbExecutor,
|
||||||
EventBus eventBus, ContactId contactId, int maxLatency,
|
EventBus eventBus, ContactId contactId,
|
||||||
StreamWriter streamWriter, SyncRecordWriter recordWriter) {
|
int maxLatency, SyncRecordWriter recordWriter) {
|
||||||
this.db = db;
|
this.db = db;
|
||||||
this.dbExecutor = dbExecutor;
|
this.dbExecutor = dbExecutor;
|
||||||
this.eventBus = eventBus;
|
this.eventBus = eventBus;
|
||||||
this.contactId = contactId;
|
this.contactId = contactId;
|
||||||
this.maxLatency = maxLatency;
|
this.maxLatency = maxLatency;
|
||||||
this.streamWriter = streamWriter;
|
|
||||||
this.recordWriter = recordWriter;
|
this.recordWriter = recordWriter;
|
||||||
outstandingQueries = new AtomicInteger(2); // One per type of record
|
outstandingQueries = new AtomicInteger(2); // One per type of record
|
||||||
writerTasks = new LinkedBlockingQueue<>();
|
writerTasks = new LinkedBlockingQueue<>();
|
||||||
@@ -88,7 +85,7 @@ class SimplexOutgoingSession implements SyncSession, EventListener {
|
|||||||
if (task == CLOSE) break;
|
if (task == CLOSE) break;
|
||||||
task.run();
|
task.run();
|
||||||
}
|
}
|
||||||
streamWriter.sendEndOfStream();
|
recordWriter.flush();
|
||||||
} catch (InterruptedException e) {
|
} catch (InterruptedException e) {
|
||||||
LOG.info("Interrupted while waiting for a record to write");
|
LOG.info("Interrupted while waiting for a record to write");
|
||||||
Thread.currentThread().interrupt();
|
Thread.currentThread().interrupt();
|
||||||
|
|||||||
@@ -12,7 +12,6 @@ import org.briarproject.bramble.api.sync.SyncRecordWriterFactory;
|
|||||||
import org.briarproject.bramble.api.sync.SyncSession;
|
import org.briarproject.bramble.api.sync.SyncSession;
|
||||||
import org.briarproject.bramble.api.sync.SyncSessionFactory;
|
import org.briarproject.bramble.api.sync.SyncSessionFactory;
|
||||||
import org.briarproject.bramble.api.system.Clock;
|
import org.briarproject.bramble.api.system.Clock;
|
||||||
import org.briarproject.bramble.api.transport.StreamWriter;
|
|
||||||
|
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.io.OutputStream;
|
import java.io.OutputStream;
|
||||||
@@ -54,21 +53,19 @@ class SyncSessionFactoryImpl implements SyncSessionFactory {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public SyncSession createSimplexOutgoingSession(ContactId c,
|
public SyncSession createSimplexOutgoingSession(ContactId c,
|
||||||
int maxLatency, StreamWriter streamWriter) {
|
int maxLatency, OutputStream out) {
|
||||||
OutputStream out = streamWriter.getOutputStream();
|
|
||||||
SyncRecordWriter recordWriter =
|
SyncRecordWriter recordWriter =
|
||||||
recordWriterFactory.createRecordWriter(out);
|
recordWriterFactory.createRecordWriter(out);
|
||||||
return new SimplexOutgoingSession(db, dbExecutor, eventBus, c,
|
return new SimplexOutgoingSession(db, dbExecutor, eventBus, c,
|
||||||
maxLatency, streamWriter, recordWriter);
|
maxLatency, recordWriter);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public SyncSession createDuplexOutgoingSession(ContactId c, int maxLatency,
|
public SyncSession createDuplexOutgoingSession(ContactId c, int maxLatency,
|
||||||
int maxIdleTime, StreamWriter streamWriter) {
|
int maxIdleTime, OutputStream out) {
|
||||||
OutputStream out = streamWriter.getOutputStream();
|
|
||||||
SyncRecordWriter recordWriter =
|
SyncRecordWriter recordWriter =
|
||||||
recordWriterFactory.createRecordWriter(out);
|
recordWriterFactory.createRecordWriter(out);
|
||||||
return new DuplexOutgoingSession(db, dbExecutor, eventBus, clock, c,
|
return new DuplexOutgoingSession(db, dbExecutor, eventBus, clock, c,
|
||||||
maxLatency, maxIdleTime, streamWriter, recordWriter);
|
maxLatency, maxIdleTime, recordWriter);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -99,18 +99,39 @@ class KeyManagerImpl implements KeyManager, Service, EventListener {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Map<TransportId, KeySetId> addContact(Transaction txn, ContactId c,
|
public void addContact(Transaction txn, ContactId c, SecretKey master,
|
||||||
SecretKey master, long timestamp, boolean alice, boolean active)
|
long timestamp, boolean alice) throws DbException {
|
||||||
|
for (TransportKeyManager m : managers.values())
|
||||||
|
m.addContact(txn, c, master, timestamp, alice);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Map<TransportId, KeySetId> addUnboundKeys(Transaction txn,
|
||||||
|
SecretKey master, long timestamp, boolean alice)
|
||||||
throws DbException {
|
throws DbException {
|
||||||
Map<TransportId, KeySetId> ids = new HashMap<>();
|
Map<TransportId, KeySetId> ids = new HashMap<>();
|
||||||
for (Entry<TransportId, TransportKeyManager> e : managers.entrySet()) {
|
for (Entry<TransportId, TransportKeyManager> e : managers.entrySet()) {
|
||||||
TransportId t = e.getKey();
|
TransportId t = e.getKey();
|
||||||
TransportKeyManager m = e.getValue();
|
TransportKeyManager m = e.getValue();
|
||||||
ids.put(t, m.addContact(txn, c, master, timestamp, alice, active));
|
ids.put(t, m.addUnboundKeys(txn, master, timestamp, alice));
|
||||||
}
|
}
|
||||||
return ids;
|
return ids;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void bindKeys(Transaction txn, ContactId c,
|
||||||
|
Map<TransportId, KeySetId> keys) throws DbException {
|
||||||
|
for (Entry<TransportId, KeySetId> e : keys.entrySet()) {
|
||||||
|
TransportId t = e.getKey();
|
||||||
|
TransportKeyManager m = managers.get(t);
|
||||||
|
if (m == null) {
|
||||||
|
if (LOG.isLoggable(INFO)) LOG.info("No key manager for " + t);
|
||||||
|
} else {
|
||||||
|
m.bindKeys(txn, c, e.getValue());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void activateKeys(Transaction txn, Map<TransportId, KeySetId> keys)
|
public void activateKeys(Transaction txn, Map<TransportId, KeySetId> keys)
|
||||||
throws DbException {
|
throws DbException {
|
||||||
@@ -125,10 +146,24 @@ class KeyManagerImpl implements KeyManager, Service, EventListener {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void removeKeys(Transaction txn, Map<TransportId, KeySetId> keys)
|
||||||
|
throws DbException {
|
||||||
|
for (Entry<TransportId, KeySetId> e : keys.entrySet()) {
|
||||||
|
TransportId t = e.getKey();
|
||||||
|
TransportKeyManager m = managers.get(t);
|
||||||
|
if (m == null) {
|
||||||
|
if (LOG.isLoggable(INFO)) LOG.info("No key manager for " + t);
|
||||||
|
} else {
|
||||||
|
m.removeKeys(txn, e.getValue());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean canSendOutgoingStreams(ContactId c, TransportId t) {
|
public boolean canSendOutgoingStreams(ContactId c, TransportId t) {
|
||||||
TransportKeyManager m = managers.get(t);
|
TransportKeyManager m = managers.get(t);
|
||||||
return m != null && m.canSendOutgoingStreams(c);
|
return m == null ? false : m.canSendOutgoingStreams(c);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -3,28 +3,32 @@ package org.briarproject.bramble.transport;
|
|||||||
import org.briarproject.bramble.api.contact.ContactId;
|
import org.briarproject.bramble.api.contact.ContactId;
|
||||||
import org.briarproject.bramble.api.transport.KeySetId;
|
import org.briarproject.bramble.api.transport.KeySetId;
|
||||||
|
|
||||||
class MutableKeySet {
|
import javax.annotation.Nullable;
|
||||||
|
|
||||||
|
public class MutableKeySet {
|
||||||
|
|
||||||
private final KeySetId keySetId;
|
private final KeySetId keySetId;
|
||||||
|
@Nullable
|
||||||
private final ContactId contactId;
|
private final ContactId contactId;
|
||||||
private final MutableTransportKeys transportKeys;
|
private final MutableTransportKeys transportKeys;
|
||||||
|
|
||||||
MutableKeySet(KeySetId keySetId, ContactId contactId,
|
public MutableKeySet(KeySetId keySetId, @Nullable ContactId contactId,
|
||||||
MutableTransportKeys transportKeys) {
|
MutableTransportKeys transportKeys) {
|
||||||
this.keySetId = keySetId;
|
this.keySetId = keySetId;
|
||||||
this.contactId = contactId;
|
this.contactId = contactId;
|
||||||
this.transportKeys = transportKeys;
|
this.transportKeys = transportKeys;
|
||||||
}
|
}
|
||||||
|
|
||||||
KeySetId getKeySetId() {
|
public KeySetId getKeySetId() {
|
||||||
return keySetId;
|
return keySetId;
|
||||||
}
|
}
|
||||||
|
|
||||||
ContactId getContactId() {
|
@Nullable
|
||||||
|
public ContactId getContactId() {
|
||||||
return contactId;
|
return contactId;
|
||||||
}
|
}
|
||||||
|
|
||||||
MutableTransportKeys getTransportKeys() {
|
public MutableTransportKeys getTransportKeys() {
|
||||||
return transportKeys;
|
return transportKeys;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,7 +4,6 @@ import org.briarproject.bramble.api.crypto.SecretKey;
|
|||||||
import org.briarproject.bramble.api.crypto.StreamEncrypterFactory;
|
import org.briarproject.bramble.api.crypto.StreamEncrypterFactory;
|
||||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||||
import org.briarproject.bramble.api.transport.StreamContext;
|
import org.briarproject.bramble.api.transport.StreamContext;
|
||||||
import org.briarproject.bramble.api.transport.StreamWriter;
|
|
||||||
import org.briarproject.bramble.api.transport.StreamWriterFactory;
|
import org.briarproject.bramble.api.transport.StreamWriterFactory;
|
||||||
|
|
||||||
import java.io.OutputStream;
|
import java.io.OutputStream;
|
||||||
@@ -24,14 +23,14 @@ class StreamWriterFactoryImpl implements StreamWriterFactory {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public StreamWriter createStreamWriter(OutputStream out,
|
public OutputStream createStreamWriter(OutputStream out,
|
||||||
StreamContext ctx) {
|
StreamContext ctx) {
|
||||||
return new StreamWriterImpl(
|
return new StreamWriterImpl(
|
||||||
streamEncrypterFactory.createStreamEncrypter(out, ctx));
|
streamEncrypterFactory.createStreamEncrypter(out, ctx));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public StreamWriter createContactExchangeStreamWriter(OutputStream out,
|
public OutputStream createContactExchangeStreamWriter(OutputStream out,
|
||||||
SecretKey headerKey) {
|
SecretKey headerKey) {
|
||||||
return new StreamWriterImpl(
|
return new StreamWriterImpl(
|
||||||
streamEncrypterFactory.createContactExchangeStreamDecrypter(out,
|
streamEncrypterFactory.createContactExchangeStreamDecrypter(out,
|
||||||
|
|||||||
@@ -2,7 +2,6 @@ package org.briarproject.bramble.transport;
|
|||||||
|
|
||||||
import org.briarproject.bramble.api.crypto.StreamEncrypter;
|
import org.briarproject.bramble.api.crypto.StreamEncrypter;
|
||||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||||
import org.briarproject.bramble.api.transport.StreamWriter;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.OutputStream;
|
import java.io.OutputStream;
|
||||||
@@ -18,7 +17,7 @@ import static org.briarproject.bramble.api.transport.TransportConstants.MAX_PAYL
|
|||||||
*/
|
*/
|
||||||
@NotThreadSafe
|
@NotThreadSafe
|
||||||
@NotNullByDefault
|
@NotNullByDefault
|
||||||
class StreamWriterImpl extends OutputStream implements StreamWriter {
|
class StreamWriterImpl extends OutputStream {
|
||||||
|
|
||||||
private final StreamEncrypter encrypter;
|
private final StreamEncrypter encrypter;
|
||||||
private final byte[] payload;
|
private final byte[] payload;
|
||||||
@@ -30,17 +29,6 @@ class StreamWriterImpl extends OutputStream implements StreamWriter {
|
|||||||
payload = new byte[MAX_PAYLOAD_LENGTH];
|
payload = new byte[MAX_PAYLOAD_LENGTH];
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public OutputStream getOutputStream() {
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void sendEndOfStream() throws IOException {
|
|
||||||
writeFrame(true);
|
|
||||||
encrypter.flush();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void close() throws IOException {
|
public void close() throws IOException {
|
||||||
writeFrame(true);
|
writeFrame(true);
|
||||||
|
|||||||
@@ -15,11 +15,18 @@ interface TransportKeyManager {
|
|||||||
|
|
||||||
void start(Transaction txn) throws DbException;
|
void start(Transaction txn) throws DbException;
|
||||||
|
|
||||||
KeySetId addContact(Transaction txn, ContactId c, SecretKey master,
|
void addContact(Transaction txn, ContactId c, SecretKey master,
|
||||||
long timestamp, boolean alice, boolean active) throws DbException;
|
long timestamp, boolean alice) throws DbException;
|
||||||
|
|
||||||
|
KeySetId addUnboundKeys(Transaction txn, SecretKey master, long timestamp,
|
||||||
|
boolean alice) throws DbException;
|
||||||
|
|
||||||
|
void bindKeys(Transaction txn, ContactId c, KeySetId k) throws DbException;
|
||||||
|
|
||||||
void activateKeys(Transaction txn, KeySetId k) throws DbException;
|
void activateKeys(Transaction txn, KeySetId k) throws DbException;
|
||||||
|
|
||||||
|
void removeKeys(Transaction txn, KeySetId k) throws DbException;
|
||||||
|
|
||||||
void removeContact(ContactId c);
|
void removeContact(ContactId c);
|
||||||
|
|
||||||
boolean canSendOutgoingStreams(ContactId c);
|
boolean canSendOutgoingStreams(ContactId c);
|
||||||
|
|||||||
@@ -28,6 +28,7 @@ import java.util.concurrent.atomic.AtomicBoolean;
|
|||||||
import java.util.concurrent.locks.ReentrantLock;
|
import java.util.concurrent.locks.ReentrantLock;
|
||||||
import java.util.logging.Logger;
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
|
import javax.annotation.Nullable;
|
||||||
import javax.annotation.concurrent.ThreadSafe;
|
import javax.annotation.concurrent.ThreadSafe;
|
||||||
|
|
||||||
import static java.util.concurrent.TimeUnit.MILLISECONDS;
|
import static java.util.concurrent.TimeUnit.MILLISECONDS;
|
||||||
@@ -118,14 +119,16 @@ class TransportKeyManagerImpl implements TransportKeyManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Locking: lock
|
// Locking: lock
|
||||||
private void addKeys(KeySetId keySetId, ContactId contactId,
|
private void addKeys(KeySetId keySetId, @Nullable ContactId contactId,
|
||||||
MutableTransportKeys m) {
|
MutableTransportKeys m) {
|
||||||
MutableKeySet ks = new MutableKeySet(keySetId, contactId, m);
|
MutableKeySet ks = new MutableKeySet(keySetId, contactId, m);
|
||||||
keys.put(keySetId, ks);
|
keys.put(keySetId, ks);
|
||||||
encodeTags(keySetId, contactId, m.getPreviousIncomingKeys());
|
if (contactId != null) {
|
||||||
encodeTags(keySetId, contactId, m.getCurrentIncomingKeys());
|
encodeTags(keySetId, contactId, m.getPreviousIncomingKeys());
|
||||||
encodeTags(keySetId, contactId, m.getNextIncomingKeys());
|
encodeTags(keySetId, contactId, m.getCurrentIncomingKeys());
|
||||||
considerReplacingOutgoingKeys(ks);
|
encodeTags(keySetId, contactId, m.getNextIncomingKeys());
|
||||||
|
considerReplacingOutgoingKeys(ks);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Locking: lock
|
// Locking: lock
|
||||||
@@ -147,9 +150,8 @@ class TransportKeyManagerImpl implements TransportKeyManager {
|
|||||||
if (ks.getTransportKeys().getCurrentOutgoingKeys().isActive()) {
|
if (ks.getTransportKeys().getCurrentOutgoingKeys().isActive()) {
|
||||||
MutableKeySet old = outContexts.get(ks.getContactId());
|
MutableKeySet old = outContexts.get(ks.getContactId());
|
||||||
if (old == null ||
|
if (old == null ||
|
||||||
old.getKeySetId().getInt() < ks.getKeySetId().getInt()) {
|
old.getKeySetId().getInt() < ks.getKeySetId().getInt())
|
||||||
outContexts.put(ks.getContactId(), ks);
|
outContexts.put(ks.getContactId(), ks);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -175,8 +177,20 @@ class TransportKeyManagerImpl implements TransportKeyManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public KeySetId addContact(Transaction txn, ContactId c, SecretKey master,
|
public void addContact(Transaction txn, ContactId c, SecretKey master,
|
||||||
long timestamp, boolean alice, boolean active) throws DbException {
|
long timestamp, boolean alice) throws DbException {
|
||||||
|
deriveAndAddKeys(txn, c, master, timestamp, alice, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public KeySetId addUnboundKeys(Transaction txn, SecretKey master,
|
||||||
|
long timestamp, boolean alice) throws DbException {
|
||||||
|
return deriveAndAddKeys(txn, null, master, timestamp, alice, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
private KeySetId deriveAndAddKeys(Transaction txn, @Nullable ContactId c,
|
||||||
|
SecretKey master, long timestamp, boolean alice, boolean active)
|
||||||
|
throws DbException {
|
||||||
lock.lock();
|
lock.lock();
|
||||||
try {
|
try {
|
||||||
// Work out what rotation period the timestamp belongs to
|
// Work out what rotation period the timestamp belongs to
|
||||||
@@ -197,12 +211,31 @@ class TransportKeyManagerImpl implements TransportKeyManager {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void bindKeys(Transaction txn, ContactId c, KeySetId k)
|
||||||
|
throws DbException {
|
||||||
|
lock.lock();
|
||||||
|
try {
|
||||||
|
MutableKeySet ks = keys.get(k);
|
||||||
|
if (ks == null) throw new IllegalArgumentException();
|
||||||
|
// Check that the keys haven't already been bound
|
||||||
|
if (ks.getContactId() != null) throw new IllegalArgumentException();
|
||||||
|
MutableTransportKeys m = ks.getTransportKeys();
|
||||||
|
addKeys(k, c, m);
|
||||||
|
db.bindTransportKeys(txn, c, m.getTransportId(), k);
|
||||||
|
} finally {
|
||||||
|
lock.unlock();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void activateKeys(Transaction txn, KeySetId k) throws DbException {
|
public void activateKeys(Transaction txn, KeySetId k) throws DbException {
|
||||||
lock.lock();
|
lock.lock();
|
||||||
try {
|
try {
|
||||||
MutableKeySet ks = keys.get(k);
|
MutableKeySet ks = keys.get(k);
|
||||||
if (ks == null) throw new IllegalArgumentException();
|
if (ks == null) throw new IllegalArgumentException();
|
||||||
|
// Check that the keys have been bound
|
||||||
|
if (ks.getContactId() == null) throw new IllegalArgumentException();
|
||||||
MutableTransportKeys m = ks.getTransportKeys();
|
MutableTransportKeys m = ks.getTransportKeys();
|
||||||
m.getCurrentOutgoingKeys().activate();
|
m.getCurrentOutgoingKeys().activate();
|
||||||
considerReplacingOutgoingKeys(ks);
|
considerReplacingOutgoingKeys(ks);
|
||||||
@@ -212,6 +245,21 @@ class TransportKeyManagerImpl implements TransportKeyManager {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void removeKeys(Transaction txn, KeySetId k) throws DbException {
|
||||||
|
lock.lock();
|
||||||
|
try {
|
||||||
|
MutableKeySet ks = keys.remove(k);
|
||||||
|
if (ks == null) throw new IllegalArgumentException();
|
||||||
|
// Check that the keys haven't been bound
|
||||||
|
if (ks.getContactId() != null) throw new IllegalArgumentException();
|
||||||
|
TransportId t = ks.getTransportKeys().getTransportId();
|
||||||
|
db.removeTransportKeys(txn, t, k);
|
||||||
|
} finally {
|
||||||
|
lock.unlock();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void removeContact(ContactId c) {
|
public void removeContact(ContactId c) {
|
||||||
lock.lock();
|
lock.lock();
|
||||||
|
|||||||
@@ -55,8 +55,8 @@ public class ContactManagerImplTest extends BrambleMockTestCase {
|
|||||||
will(returnValue(txn));
|
will(returnValue(txn));
|
||||||
oneOf(db).addContact(txn, remote, local, verified, active);
|
oneOf(db).addContact(txn, remote, local, verified, active);
|
||||||
will(returnValue(contactId));
|
will(returnValue(contactId));
|
||||||
oneOf(keyManager).addContact(txn, contactId, master, timestamp,
|
oneOf(keyManager)
|
||||||
alice, active);
|
.addContact(txn, contactId, master, timestamp, alice);
|
||||||
oneOf(db).getContact(txn, contactId);
|
oneOf(db).getContact(txn, contactId);
|
||||||
will(returnValue(contact));
|
will(returnValue(contact));
|
||||||
oneOf(db).commitTransaction(txn);
|
oneOf(db).commitTransaction(txn);
|
||||||
|
|||||||
@@ -4,16 +4,13 @@ import org.briarproject.bramble.api.FormatException;
|
|||||||
import org.briarproject.bramble.api.data.BdfDictionary;
|
import org.briarproject.bramble.api.data.BdfDictionary;
|
||||||
import org.briarproject.bramble.api.data.BdfList;
|
import org.briarproject.bramble.api.data.BdfList;
|
||||||
import org.briarproject.bramble.test.BrambleTestCase;
|
import org.briarproject.bramble.test.BrambleTestCase;
|
||||||
|
import org.briarproject.bramble.util.StringUtils;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
import java.io.ByteArrayInputStream;
|
import java.io.ByteArrayInputStream;
|
||||||
|
|
||||||
import static org.briarproject.bramble.api.data.BdfDictionary.NULL_VALUE;
|
import static org.briarproject.bramble.api.data.BdfDictionary.NULL_VALUE;
|
||||||
import static org.briarproject.bramble.api.data.BdfReader.DEFAULT_MAX_BUFFER_SIZE;
|
|
||||||
import static org.briarproject.bramble.data.BdfReaderImpl.DEFAULT_NESTED_LIMIT;
|
import static org.briarproject.bramble.data.BdfReaderImpl.DEFAULT_NESTED_LIMIT;
|
||||||
import static org.briarproject.bramble.util.StringUtils.fromHexString;
|
|
||||||
import static org.briarproject.bramble.util.StringUtils.getRandomString;
|
|
||||||
import static org.briarproject.bramble.util.StringUtils.toHexString;
|
|
||||||
import static org.junit.Assert.assertArrayEquals;
|
import static org.junit.Assert.assertArrayEquals;
|
||||||
import static org.junit.Assert.assertEquals;
|
import static org.junit.Assert.assertEquals;
|
||||||
import static org.junit.Assert.assertFalse;
|
import static org.junit.Assert.assertFalse;
|
||||||
@@ -161,32 +158,30 @@ public class BdfReaderImplTest extends BrambleTestCase {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testReadString8() throws Exception {
|
public void testReadString8() throws Exception {
|
||||||
String longest = getRandomString(Byte.MAX_VALUE);
|
String longest = StringUtils.getRandomString(Byte.MAX_VALUE);
|
||||||
String longHex = toHexString(longest.getBytes("UTF-8"));
|
String longHex = StringUtils.toHexString(longest.getBytes("UTF-8"));
|
||||||
// "foo", the empty string, and 127 random letters
|
// "foo", the empty string, and 127 random letters
|
||||||
setContents("41" + "03" + "666F6F" + "41" + "00" +
|
setContents("41" + "03" + "666F6F" + "41" + "00" +
|
||||||
"41" + "7F" + longHex);
|
"41" + "7F" + longHex);
|
||||||
assertEquals("foo", r.readString());
|
assertEquals("foo", r.readString(Integer.MAX_VALUE));
|
||||||
assertEquals("", r.readString());
|
assertEquals("", r.readString(Integer.MAX_VALUE));
|
||||||
assertEquals(longest, r.readString());
|
assertEquals(longest, r.readString(Integer.MAX_VALUE));
|
||||||
assertTrue(r.eof());
|
assertTrue(r.eof());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test(expected = FormatException.class)
|
@Test(expected = FormatException.class)
|
||||||
public void testReadString8ChecksMaxLength() throws Exception {
|
public void testReadString8ChecksMaxLength() throws Exception {
|
||||||
int maxBufferSize = 3;
|
// "foo" twice
|
||||||
// "foo", "fooo"
|
setContents("41" + "03" + "666F6F" + "41" + "03" + "666F6F");
|
||||||
setContents("41" + "03" + "666F6F"
|
assertEquals("foo", r.readString(3));
|
||||||
+ "41" + "04" + "666F6F6F", maxBufferSize);
|
|
||||||
assertEquals("foo", r.readString());
|
|
||||||
assertTrue(r.hasString());
|
assertTrue(r.hasString());
|
||||||
r.readString();
|
r.readString(2);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testSkipString8() throws Exception {
|
public void testSkipString8() throws Exception {
|
||||||
String longest = getRandomString(Byte.MAX_VALUE);
|
String longest = StringUtils.getRandomString(Byte.MAX_VALUE);
|
||||||
String longHex = toHexString(longest.getBytes("UTF-8"));
|
String longHex = StringUtils.toHexString(longest.getBytes("UTF-8"));
|
||||||
// "foo", the empty string, and 127 random letters
|
// "foo", the empty string, and 127 random letters
|
||||||
setContents("41" + "03" + "666F6F" + "41" + "00" +
|
setContents("41" + "03" + "666F6F" + "41" + "00" +
|
||||||
"41" + "7F" + longHex);
|
"41" + "7F" + longHex);
|
||||||
@@ -198,37 +193,34 @@ public class BdfReaderImplTest extends BrambleTestCase {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testReadString16() throws Exception {
|
public void testReadString16() throws Exception {
|
||||||
String shortest = getRandomString(Byte.MAX_VALUE + 1);
|
String shortest = StringUtils.getRandomString(Byte.MAX_VALUE + 1);
|
||||||
String shortHex = toHexString(shortest.getBytes("UTF-8"));
|
String shortHex = StringUtils.toHexString(shortest.getBytes("UTF-8"));
|
||||||
String longest = getRandomString(Short.MAX_VALUE);
|
String longest = StringUtils.getRandomString(Short.MAX_VALUE);
|
||||||
String longHex = toHexString(longest.getBytes("UTF-8"));
|
String longHex = StringUtils.toHexString(longest.getBytes("UTF-8"));
|
||||||
// 128 random letters and 2^15 -1 random letters
|
// 128 random letters and 2^15 -1 random letters
|
||||||
setContents("42" + "0080" + shortHex + "42" + "7FFF" + longHex);
|
setContents("42" + "0080" + shortHex + "42" + "7FFF" + longHex);
|
||||||
assertEquals(shortest, r.readString());
|
assertEquals(shortest, r.readString(Integer.MAX_VALUE));
|
||||||
assertEquals(longest, r.readString());
|
assertEquals(longest, r.readString(Integer.MAX_VALUE));
|
||||||
assertTrue(r.eof());
|
assertTrue(r.eof());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test(expected = FormatException.class)
|
@Test(expected = FormatException.class)
|
||||||
public void testReadString16ChecksMaxLength() throws Exception {
|
public void testReadString16ChecksMaxLength() throws Exception {
|
||||||
int maxBufferSize = Byte.MAX_VALUE + 1;
|
String shortest = StringUtils.getRandomString(Byte.MAX_VALUE + 1);
|
||||||
String valid = getRandomString(Byte.MAX_VALUE + 1);
|
String shortHex = StringUtils.toHexString(shortest.getBytes("UTF-8"));
|
||||||
String validHex = toHexString(valid.getBytes("UTF-8"));
|
// 128 random letters, twice
|
||||||
String invalidhex = validHex + "20";
|
setContents("42" + "0080" + shortHex + "42" + "0080" + shortHex);
|
||||||
// 128 random letters, the same plus a space
|
assertEquals(shortest, r.readString(Byte.MAX_VALUE + 1));
|
||||||
setContents("42" + "0080" + validHex
|
|
||||||
+ "42" + "0081" + invalidhex, maxBufferSize);
|
|
||||||
assertEquals(valid, r.readString());
|
|
||||||
assertTrue(r.hasString());
|
assertTrue(r.hasString());
|
||||||
r.readString();
|
r.readString(Byte.MAX_VALUE);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testSkipString16() throws Exception {
|
public void testSkipString16() throws Exception {
|
||||||
String shortest = getRandomString(Byte.MAX_VALUE + 1);
|
String shortest = StringUtils.getRandomString(Byte.MAX_VALUE + 1);
|
||||||
String shortHex = toHexString(shortest.getBytes("UTF-8"));
|
String shortHex = StringUtils.toHexString(shortest.getBytes("UTF-8"));
|
||||||
String longest = getRandomString(Short.MAX_VALUE);
|
String longest = StringUtils.getRandomString(Short.MAX_VALUE);
|
||||||
String longHex = toHexString(longest.getBytes("UTF-8"));
|
String longHex = StringUtils.toHexString(longest.getBytes("UTF-8"));
|
||||||
// 128 random letters and 2^15 - 1 random letters
|
// 128 random letters and 2^15 - 1 random letters
|
||||||
setContents("42" + "0080" + shortHex + "42" + "7FFF" + longHex);
|
setContents("42" + "0080" + shortHex + "42" + "7FFF" + longHex);
|
||||||
r.skipString();
|
r.skipString();
|
||||||
@@ -238,32 +230,30 @@ public class BdfReaderImplTest extends BrambleTestCase {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testReadString32() throws Exception {
|
public void testReadString32() throws Exception {
|
||||||
String shortest = getRandomString(Short.MAX_VALUE + 1);
|
String shortest = StringUtils.getRandomString(Short.MAX_VALUE + 1);
|
||||||
String shortHex = toHexString(shortest.getBytes("UTF-8"));
|
String shortHex = StringUtils.toHexString(shortest.getBytes("UTF-8"));
|
||||||
// 2^15 random letters
|
// 2^15 random letters
|
||||||
setContents("44" + "00008000" + shortHex);
|
setContents("44" + "00008000" + shortHex);
|
||||||
assertEquals(shortest, r.readString());
|
assertEquals(shortest, r.readString(Integer.MAX_VALUE));
|
||||||
assertTrue(r.eof());
|
assertTrue(r.eof());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test(expected = FormatException.class)
|
@Test(expected = FormatException.class)
|
||||||
public void testReadString32ChecksMaxLength() throws Exception {
|
public void testReadString32ChecksMaxLength() throws Exception {
|
||||||
int maxBufferSize = Short.MAX_VALUE + 1;
|
String shortest = StringUtils.getRandomString(Short.MAX_VALUE + 1);
|
||||||
String valid = getRandomString(maxBufferSize);
|
String shortHex = StringUtils.toHexString(shortest.getBytes("UTF-8"));
|
||||||
String validHex = toHexString(valid.getBytes("UTF-8"));
|
// 2^15 random letters, twice
|
||||||
String invalidHex = validHex + "20";
|
setContents("44" + "00008000" + shortHex +
|
||||||
// 2^15 random letters, the same plus a space
|
"44" + "00008000" + shortHex);
|
||||||
setContents("44" + "00008000" + validHex +
|
assertEquals(shortest, r.readString(Short.MAX_VALUE + 1));
|
||||||
"44" + "00008001" + invalidHex, maxBufferSize);
|
|
||||||
assertEquals(valid, r.readString());
|
|
||||||
assertTrue(r.hasString());
|
assertTrue(r.hasString());
|
||||||
r.readString();
|
r.readString(Short.MAX_VALUE);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testSkipString32() throws Exception {
|
public void testSkipString32() throws Exception {
|
||||||
String shortest = getRandomString(Short.MAX_VALUE + 1);
|
String shortest = StringUtils.getRandomString(Short.MAX_VALUE + 1);
|
||||||
String shortHex = toHexString(shortest.getBytes("UTF-8"));
|
String shortHex = StringUtils.toHexString(shortest.getBytes("UTF-8"));
|
||||||
// 2^15 random letters, twice
|
// 2^15 random letters, twice
|
||||||
setContents("44" + "00008000" + shortHex +
|
setContents("44" + "00008000" + shortHex +
|
||||||
"44" + "00008000" + shortHex);
|
"44" + "00008000" + shortHex);
|
||||||
@@ -275,43 +265,41 @@ public class BdfReaderImplTest extends BrambleTestCase {
|
|||||||
@Test
|
@Test
|
||||||
public void testReadUtf8String() throws Exception {
|
public void testReadUtf8String() throws Exception {
|
||||||
String unicode = "\uFDD0\uFDD1\uFDD2\uFDD3";
|
String unicode = "\uFDD0\uFDD1\uFDD2\uFDD3";
|
||||||
String hex = toHexString(unicode.getBytes("UTF-8"));
|
String hex = StringUtils.toHexString(unicode.getBytes("UTF-8"));
|
||||||
// STRING_8 tag, "foo", the empty string, and the test string
|
// STRING_8 tag, "foo", the empty string, and the test string
|
||||||
setContents("41" + "03" + "666F6F" + "41" + "00" + "41" + "0C" + hex);
|
setContents("41" + "03" + "666F6F" + "41" + "00" + "41" + "0C" + hex);
|
||||||
assertEquals("foo", r.readString());
|
assertEquals("foo", r.readString(Integer.MAX_VALUE));
|
||||||
assertEquals("", r.readString());
|
assertEquals("", r.readString(Integer.MAX_VALUE));
|
||||||
assertEquals(unicode, r.readString());
|
assertEquals(unicode, r.readString(Integer.MAX_VALUE));
|
||||||
assertTrue(r.eof());
|
assertTrue(r.eof());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testReadRaw8() throws Exception {
|
public void testReadRaw8() throws Exception {
|
||||||
byte[] longest = new byte[Byte.MAX_VALUE];
|
byte[] longest = new byte[Byte.MAX_VALUE];
|
||||||
String longHex = toHexString(longest);
|
String longHex = StringUtils.toHexString(longest);
|
||||||
// {1, 2, 3}, {}, and 127 zero bytes
|
// {1, 2, 3}, {}, and 127 zero bytes
|
||||||
setContents("51" + "03" + "010203" + "51" + "00" +
|
setContents("51" + "03" + "010203" + "51" + "00" +
|
||||||
"51" + "7F" + longHex);
|
"51" + "7F" + longHex);
|
||||||
assertArrayEquals(new byte[] {1, 2, 3}, r.readRaw());
|
assertArrayEquals(new byte[] {1, 2, 3}, r.readRaw(Integer.MAX_VALUE));
|
||||||
assertArrayEquals(new byte[0], r.readRaw());
|
assertArrayEquals(new byte[0], r.readRaw(Integer.MAX_VALUE));
|
||||||
assertArrayEquals(longest, r.readRaw());
|
assertArrayEquals(longest, r.readRaw(Integer.MAX_VALUE));
|
||||||
assertTrue(r.eof());
|
assertTrue(r.eof());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test(expected = FormatException.class)
|
@Test(expected = FormatException.class)
|
||||||
public void testReadRaw8ChecksMaxLength() throws Exception {
|
public void testReadRaw8ChecksMaxLength() throws Exception {
|
||||||
int maxBufferSize = 3;
|
// {1, 2, 3} twice
|
||||||
// {1, 2, 3}, {1, 2, 3, 4}
|
setContents("51" + "03" + "010203" + "51" + "03" + "010203");
|
||||||
setContents("51" + "03" + "010203" + "51" + "04" + "01020304",
|
assertArrayEquals(new byte[] {1, 2, 3}, r.readRaw(3));
|
||||||
maxBufferSize);
|
|
||||||
assertArrayEquals(new byte[] {1, 2, 3}, r.readRaw());
|
|
||||||
assertTrue(r.hasRaw());
|
assertTrue(r.hasRaw());
|
||||||
r.readRaw();
|
r.readRaw(2);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testSkipRaw8() throws Exception {
|
public void testSkipRaw8() throws Exception {
|
||||||
byte[] longest = new byte[Byte.MAX_VALUE];
|
byte[] longest = new byte[Byte.MAX_VALUE];
|
||||||
String longHex = toHexString(longest);
|
String longHex = StringUtils.toHexString(longest);
|
||||||
// {1, 2, 3}, {}, and 127 zero bytes
|
// {1, 2, 3}, {}, and 127 zero bytes
|
||||||
setContents("51" + "03" + "010203" + "51" + "00" +
|
setContents("51" + "03" + "010203" + "51" + "00" +
|
||||||
"51" + "7F" + longHex);
|
"51" + "7F" + longHex);
|
||||||
@@ -324,36 +312,33 @@ public class BdfReaderImplTest extends BrambleTestCase {
|
|||||||
@Test
|
@Test
|
||||||
public void testReadRaw16() throws Exception {
|
public void testReadRaw16() throws Exception {
|
||||||
byte[] shortest = new byte[Byte.MAX_VALUE + 1];
|
byte[] shortest = new byte[Byte.MAX_VALUE + 1];
|
||||||
String shortHex = toHexString(shortest);
|
String shortHex = StringUtils.toHexString(shortest);
|
||||||
byte[] longest = new byte[Short.MAX_VALUE];
|
byte[] longest = new byte[Short.MAX_VALUE];
|
||||||
String longHex = toHexString(longest);
|
String longHex = StringUtils.toHexString(longest);
|
||||||
// 128 zero bytes and 2^15 - 1 zero bytes
|
// 128 zero bytes and 2^15 - 1 zero bytes
|
||||||
setContents("52" + "0080" + shortHex + "52" + "7FFF" + longHex);
|
setContents("52" + "0080" + shortHex + "52" + "7FFF" + longHex);
|
||||||
assertArrayEquals(shortest, r.readRaw());
|
assertArrayEquals(shortest, r.readRaw(Integer.MAX_VALUE));
|
||||||
assertArrayEquals(longest, r.readRaw());
|
assertArrayEquals(longest, r.readRaw(Integer.MAX_VALUE));
|
||||||
assertTrue(r.eof());
|
assertTrue(r.eof());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test(expected = FormatException.class)
|
@Test(expected = FormatException.class)
|
||||||
public void testReadRaw16ChecksMaxLength() throws Exception {
|
public void testReadRaw16ChecksMaxLength() throws Exception {
|
||||||
int maxBufferSize = Byte.MAX_VALUE + 1;
|
byte[] shortest = new byte[Byte.MAX_VALUE + 1];
|
||||||
byte[] valid = new byte[maxBufferSize];
|
String shortHex = StringUtils.toHexString(shortest);
|
||||||
String validHex = toHexString(valid);
|
// 128 zero bytes, twice
|
||||||
String invalidHex = validHex + "00";
|
setContents("52" + "0080" + shortHex + "52" + "0080" + shortHex);
|
||||||
// 128 zero bytes, 129 zero bytes
|
assertArrayEquals(shortest, r.readRaw(Byte.MAX_VALUE + 1));
|
||||||
setContents("52" + "0080" + validHex
|
|
||||||
+ "52" + "0081" + invalidHex, maxBufferSize);
|
|
||||||
assertArrayEquals(valid, r.readRaw());
|
|
||||||
assertTrue(r.hasRaw());
|
assertTrue(r.hasRaw());
|
||||||
r.readRaw();
|
r.readRaw(Byte.MAX_VALUE);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testSkipRaw16() throws Exception {
|
public void testSkipRaw16() throws Exception {
|
||||||
byte[] shortest = new byte[Byte.MAX_VALUE + 1];
|
byte[] shortest = new byte[Byte.MAX_VALUE + 1];
|
||||||
String shortHex = toHexString(shortest);
|
String shortHex = StringUtils.toHexString(shortest);
|
||||||
byte[] longest = new byte[Short.MAX_VALUE];
|
byte[] longest = new byte[Short.MAX_VALUE];
|
||||||
String longHex = toHexString(longest);
|
String longHex = StringUtils.toHexString(longest);
|
||||||
// 128 zero bytes and 2^15 - 1 zero bytes
|
// 128 zero bytes and 2^15 - 1 zero bytes
|
||||||
setContents("52" + "0080" + shortHex + "52" + "7FFF" + longHex);
|
setContents("52" + "0080" + shortHex + "52" + "7FFF" + longHex);
|
||||||
r.skipRaw();
|
r.skipRaw();
|
||||||
@@ -364,31 +349,29 @@ public class BdfReaderImplTest extends BrambleTestCase {
|
|||||||
@Test
|
@Test
|
||||||
public void testReadRaw32() throws Exception {
|
public void testReadRaw32() throws Exception {
|
||||||
byte[] shortest = new byte[Short.MAX_VALUE + 1];
|
byte[] shortest = new byte[Short.MAX_VALUE + 1];
|
||||||
String shortHex = toHexString(shortest);
|
String shortHex = StringUtils.toHexString(shortest);
|
||||||
// 2^15 zero bytes
|
// 2^15 zero bytes
|
||||||
setContents("54" + "00008000" + shortHex);
|
setContents("54" + "00008000" + shortHex);
|
||||||
assertArrayEquals(shortest, r.readRaw());
|
assertArrayEquals(shortest, r.readRaw(Integer.MAX_VALUE));
|
||||||
assertTrue(r.eof());
|
assertTrue(r.eof());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test(expected = FormatException.class)
|
@Test(expected = FormatException.class)
|
||||||
public void testReadRaw32ChecksMaxLength() throws Exception {
|
public void testReadRaw32ChecksMaxLength() throws Exception {
|
||||||
int maxBufferSize = Short.MAX_VALUE + 1;
|
byte[] shortest = new byte[Short.MAX_VALUE + 1];
|
||||||
byte[] valid = new byte[maxBufferSize];
|
String shortHex = StringUtils.toHexString(shortest);
|
||||||
String validHex = toHexString(valid);
|
// 2^15 zero bytes, twice
|
||||||
String invalidHex = validHex + "00";
|
setContents("54" + "00008000" + shortHex +
|
||||||
// 2^15 zero bytes, 2^15 + 1 zero bytes
|
"54" + "00008000" + shortHex);
|
||||||
setContents("54" + "00008000" + validHex +
|
assertArrayEquals(shortest, r.readRaw(Short.MAX_VALUE + 1));
|
||||||
"54" + "00008001" + invalidHex, maxBufferSize);
|
|
||||||
assertArrayEquals(valid, r.readRaw());
|
|
||||||
assertTrue(r.hasRaw());
|
assertTrue(r.hasRaw());
|
||||||
r.readRaw();
|
r.readRaw(Short.MAX_VALUE);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testSkipRaw32() throws Exception {
|
public void testSkipRaw32() throws Exception {
|
||||||
byte[] shortest = new byte[Short.MAX_VALUE + 1];
|
byte[] shortest = new byte[Short.MAX_VALUE + 1];
|
||||||
String shortHex = toHexString(shortest);
|
String shortHex = StringUtils.toHexString(shortest);
|
||||||
// 2^15 zero bytes, twice
|
// 2^15 zero bytes, twice
|
||||||
setContents("54" + "00008000" + shortHex +
|
setContents("54" + "00008000" + shortHex +
|
||||||
"54" + "00008000" + shortHex);
|
"54" + "00008000" + shortHex);
|
||||||
@@ -410,30 +393,6 @@ public class BdfReaderImplTest extends BrambleTestCase {
|
|||||||
assertEquals(NULL_VALUE, list.get(2));
|
assertEquals(NULL_VALUE, list.get(2));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test(expected = FormatException.class)
|
|
||||||
public void testReadListChecksMaxLengthForString() throws Exception {
|
|
||||||
// A list containing "foo", a list containing "fooo"
|
|
||||||
setContents("60" + "41" + "03" + "666F6F" + "80"
|
|
||||||
+ "60" + "41" + "04" + "666F6F6F" + "80", 3);
|
|
||||||
BdfList list = r.readList();
|
|
||||||
assertEquals(1, list.size());
|
|
||||||
assertEquals("foo", list.get(0));
|
|
||||||
assertTrue(r.hasList());
|
|
||||||
r.readList();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test(expected = FormatException.class)
|
|
||||||
public void testReadListChecksMaxLengthForRaw() throws Exception {
|
|
||||||
// A list containing {1, 2, 3}, a list containing {1, 2, 3, 4}
|
|
||||||
setContents("60" + "51" + "03" + "010203" + "80"
|
|
||||||
+ "60" + "51" + "04" + "01020304" + "80", 3);
|
|
||||||
BdfList list = r.readList();
|
|
||||||
assertEquals(1, list.size());
|
|
||||||
assertArrayEquals(new byte[] {1, 2, 3}, (byte[]) list.get(0));
|
|
||||||
assertTrue(r.hasList());
|
|
||||||
r.readList();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testReadListManually() throws Exception {
|
public void testReadListManually() throws Exception {
|
||||||
// A list containing 1, "foo", and null
|
// A list containing 1, "foo", and null
|
||||||
@@ -444,7 +403,7 @@ public class BdfReaderImplTest extends BrambleTestCase {
|
|||||||
assertFalse(r.hasListEnd());
|
assertFalse(r.hasListEnd());
|
||||||
assertEquals(1, r.readLong());
|
assertEquals(1, r.readLong());
|
||||||
assertFalse(r.hasListEnd());
|
assertFalse(r.hasListEnd());
|
||||||
assertEquals("foo", r.readString());
|
assertEquals("foo", r.readString(1000));
|
||||||
assertFalse(r.hasListEnd());
|
assertFalse(r.hasListEnd());
|
||||||
assertTrue(r.hasNull());
|
assertTrue(r.hasNull());
|
||||||
r.readNull();
|
r.readNull();
|
||||||
@@ -476,47 +435,6 @@ public class BdfReaderImplTest extends BrambleTestCase {
|
|||||||
assertEquals(NULL_VALUE, dictionary.get("bar"));
|
assertEquals(NULL_VALUE, dictionary.get("bar"));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test(expected = FormatException.class)
|
|
||||||
public void testReadDictionaryChecksMaxLengthForKey() throws Exception {
|
|
||||||
// A dictionary containing "foo" -> null, a dictionary containing
|
|
||||||
// "fooo" -> null
|
|
||||||
setContents("70" + "41" + "03" + "666F6F" + "00" + "80"
|
|
||||||
+ "70" + "41" + "04" + "666F6F6F" + "00" + "80", 3);
|
|
||||||
BdfDictionary dictionary = r.readDictionary();
|
|
||||||
assertEquals(1, dictionary.size());
|
|
||||||
assertEquals(NULL_VALUE, dictionary.get("foo"));
|
|
||||||
assertTrue(r.hasDictionary());
|
|
||||||
r.readDictionary();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test(expected = FormatException.class)
|
|
||||||
public void testReadDictionaryChecksMaxLengthForString() throws Exception {
|
|
||||||
// A dictionary containing "foo" -> "bar", a dictionary containing
|
|
||||||
// "foo" -> "baar"
|
|
||||||
String foo = "41" + "03" + "666F6F";
|
|
||||||
setContents("70" + foo + "41" + "03" + "626172" + "80"
|
|
||||||
+ "70" + foo + "41" + "04" + "62616172" + "80", 3);
|
|
||||||
BdfDictionary dictionary = r.readDictionary();
|
|
||||||
assertEquals(1, dictionary.size());
|
|
||||||
assertEquals("bar", dictionary.get("foo"));
|
|
||||||
assertTrue(r.hasDictionary());
|
|
||||||
r.readDictionary();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test(expected = FormatException.class)
|
|
||||||
public void testReadDictionaryChecksMaxLengthForRaw() throws Exception {
|
|
||||||
// A dictionary containing "foo" -> {1, 2, 3}, a dictionary containing
|
|
||||||
// "foo" -> {1, 2, 3, 4}
|
|
||||||
String foo = "41" + "03" + "666F6F";
|
|
||||||
setContents("70" + foo + "51" + "03" + "010203" + "80"
|
|
||||||
+ "70" + foo + "51" + "04" + "01020304" + "80", 3);
|
|
||||||
BdfDictionary dictionary = r.readDictionary();
|
|
||||||
assertEquals(1, dictionary.size());
|
|
||||||
assertArrayEquals(new byte[] {1, 2, 3}, (byte[]) dictionary.get("foo"));
|
|
||||||
assertTrue(r.hasDictionary());
|
|
||||||
r.readDictionary();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testReadDictionaryManually() throws Exception {
|
public void testReadDictionaryManually() throws Exception {
|
||||||
// A dictionary containing "foo" -> 123 and "bar" -> null
|
// A dictionary containing "foo" -> 123 and "bar" -> null
|
||||||
@@ -524,11 +442,11 @@ public class BdfReaderImplTest extends BrambleTestCase {
|
|||||||
"41" + "03" + "626172" + "00" + "80");
|
"41" + "03" + "626172" + "00" + "80");
|
||||||
r.readDictionaryStart();
|
r.readDictionaryStart();
|
||||||
assertFalse(r.hasDictionaryEnd());
|
assertFalse(r.hasDictionaryEnd());
|
||||||
assertEquals("foo", r.readString());
|
assertEquals("foo", r.readString(1000));
|
||||||
assertFalse(r.hasDictionaryEnd());
|
assertFalse(r.hasDictionaryEnd());
|
||||||
assertEquals(123, r.readLong());
|
assertEquals(123, r.readLong());
|
||||||
assertFalse(r.hasDictionaryEnd());
|
assertFalse(r.hasDictionaryEnd());
|
||||||
assertEquals("bar", r.readString());
|
assertEquals("bar", r.readString(1000));
|
||||||
assertFalse(r.hasDictionaryEnd());
|
assertFalse(r.hasDictionaryEnd());
|
||||||
assertTrue(r.hasNull());
|
assertTrue(r.hasNull());
|
||||||
r.readNull();
|
r.readNull();
|
||||||
@@ -619,11 +537,8 @@ public class BdfReaderImplTest extends BrambleTestCase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void setContents(String hex) {
|
private void setContents(String hex) {
|
||||||
setContents(hex, DEFAULT_MAX_BUFFER_SIZE);
|
ByteArrayInputStream in = new ByteArrayInputStream(
|
||||||
}
|
StringUtils.fromHexString(hex));
|
||||||
|
r = new BdfReaderImpl(in, DEFAULT_NESTED_LIMIT);
|
||||||
private void setContents(String hex, int maxBufferSize) {
|
|
||||||
ByteArrayInputStream in = new ByteArrayInputStream(fromHexString(hex));
|
|
||||||
r = new BdfReaderImpl(in, DEFAULT_NESTED_LIMIT, maxBufferSize);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -289,11 +289,11 @@ public class DatabaseComponentImplTest extends BrambleMockTestCase {
|
|||||||
throws Exception {
|
throws Exception {
|
||||||
context.checking(new Expectations() {{
|
context.checking(new Expectations() {{
|
||||||
// Check whether the contact is in the DB (which it's not)
|
// Check whether the contact is in the DB (which it's not)
|
||||||
exactly(16).of(database).startTransaction();
|
exactly(17).of(database).startTransaction();
|
||||||
will(returnValue(txn));
|
will(returnValue(txn));
|
||||||
exactly(16).of(database).containsContact(txn, contactId);
|
exactly(17).of(database).containsContact(txn, contactId);
|
||||||
will(returnValue(false));
|
will(returnValue(false));
|
||||||
exactly(16).of(database).abortTransaction(txn);
|
exactly(17).of(database).abortTransaction(txn);
|
||||||
}});
|
}});
|
||||||
DatabaseComponent db = createDatabaseComponent(database, eventBus,
|
DatabaseComponent db = createDatabaseComponent(database, eventBus,
|
||||||
shutdown);
|
shutdown);
|
||||||
@@ -308,6 +308,16 @@ public class DatabaseComponentImplTest extends BrambleMockTestCase {
|
|||||||
db.endTransaction(transaction);
|
db.endTransaction(transaction);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
transaction = db.startTransaction(false);
|
||||||
|
try {
|
||||||
|
db.bindTransportKeys(transaction, contactId, transportId, keySetId);
|
||||||
|
fail();
|
||||||
|
} catch (NoSuchContactException expected) {
|
||||||
|
// Expected
|
||||||
|
} finally {
|
||||||
|
db.endTransaction(transaction);
|
||||||
|
}
|
||||||
|
|
||||||
transaction = db.startTransaction(false);
|
transaction = db.startTransaction(false);
|
||||||
try {
|
try {
|
||||||
db.generateAck(transaction, contactId, 123);
|
db.generateAck(transaction, contactId, 123);
|
||||||
@@ -763,11 +773,13 @@ public class DatabaseComponentImplTest extends BrambleMockTestCase {
|
|||||||
// endTransaction()
|
// endTransaction()
|
||||||
oneOf(database).commitTransaction(txn);
|
oneOf(database).commitTransaction(txn);
|
||||||
// Check whether the transport is in the DB (which it's not)
|
// Check whether the transport is in the DB (which it's not)
|
||||||
exactly(5).of(database).startTransaction();
|
exactly(6).of(database).startTransaction();
|
||||||
will(returnValue(txn));
|
will(returnValue(txn));
|
||||||
exactly(5).of(database).containsTransport(txn, transportId);
|
oneOf(database).containsContact(txn, contactId);
|
||||||
|
will(returnValue(true));
|
||||||
|
exactly(6).of(database).containsTransport(txn, transportId);
|
||||||
will(returnValue(false));
|
will(returnValue(false));
|
||||||
exactly(5).of(database).abortTransaction(txn);
|
exactly(6).of(database).abortTransaction(txn);
|
||||||
}});
|
}});
|
||||||
DatabaseComponent db = createDatabaseComponent(database, eventBus,
|
DatabaseComponent db = createDatabaseComponent(database, eventBus,
|
||||||
shutdown);
|
shutdown);
|
||||||
@@ -782,6 +794,16 @@ public class DatabaseComponentImplTest extends BrambleMockTestCase {
|
|||||||
db.endTransaction(transaction);
|
db.endTransaction(transaction);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
transaction = db.startTransaction(false);
|
||||||
|
try {
|
||||||
|
db.bindTransportKeys(transaction, contactId, transportId, keySetId);
|
||||||
|
fail();
|
||||||
|
} catch (NoSuchTransportException expected) {
|
||||||
|
// Expected
|
||||||
|
} finally {
|
||||||
|
db.endTransaction(transaction);
|
||||||
|
}
|
||||||
|
|
||||||
transaction = db.startTransaction(false);
|
transaction = db.startTransaction(false);
|
||||||
try {
|
try {
|
||||||
db.getTransportKeys(transaction, transportId);
|
db.getTransportKeys(transaction, transportId);
|
||||||
|
|||||||
@@ -94,7 +94,6 @@ public abstract class JdbcDatabaseTest extends BrambleTestCase {
|
|||||||
private final TransportId transportId;
|
private final TransportId transportId;
|
||||||
private final ContactId contactId;
|
private final ContactId contactId;
|
||||||
private final KeySetId keySetId, keySetId1;
|
private final KeySetId keySetId, keySetId1;
|
||||||
private final Random random = new Random();
|
|
||||||
|
|
||||||
JdbcDatabaseTest() throws Exception {
|
JdbcDatabaseTest() throws Exception {
|
||||||
clientId = getClientId();
|
clientId = getClientId();
|
||||||
@@ -671,9 +670,8 @@ public abstract class JdbcDatabaseTest extends BrambleTestCase {
|
|||||||
@Test
|
@Test
|
||||||
public void testTransportKeys() throws Exception {
|
public void testTransportKeys() throws Exception {
|
||||||
long rotationPeriod = 123, rotationPeriod1 = 234;
|
long rotationPeriod = 123, rotationPeriod1 = 234;
|
||||||
boolean active = random.nextBoolean();
|
TransportKeys keys = createTransportKeys(rotationPeriod);
|
||||||
TransportKeys keys = createTransportKeys(rotationPeriod, active);
|
TransportKeys keys1 = createTransportKeys(rotationPeriod1);
|
||||||
TransportKeys keys1 = createTransportKeys(rotationPeriod1, active);
|
|
||||||
|
|
||||||
Database<Connection> db = open(false);
|
Database<Connection> db = open(false);
|
||||||
Connection txn = db.startTransaction();
|
Connection txn = db.startTransaction();
|
||||||
@@ -684,7 +682,7 @@ public abstract class JdbcDatabaseTest extends BrambleTestCase {
|
|||||||
// Add the contact, the transport and the transport keys
|
// Add the contact, the transport and the transport keys
|
||||||
db.addLocalAuthor(txn, localAuthor);
|
db.addLocalAuthor(txn, localAuthor);
|
||||||
assertEquals(contactId, db.addContact(txn, author, localAuthor.getId(),
|
assertEquals(contactId, db.addContact(txn, author, localAuthor.getId(),
|
||||||
true, active));
|
true, true));
|
||||||
db.addTransport(txn, transportId, 123);
|
db.addTransport(txn, transportId, 123);
|
||||||
assertEquals(keySetId, db.addTransportKeys(txn, contactId, keys));
|
assertEquals(keySetId, db.addTransportKeys(txn, contactId, keys));
|
||||||
assertEquals(keySetId1, db.addTransportKeys(txn, contactId, keys1));
|
assertEquals(keySetId1, db.addTransportKeys(txn, contactId, keys1));
|
||||||
@@ -703,9 +701,8 @@ public abstract class JdbcDatabaseTest extends BrambleTestCase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Rotate the transport keys
|
// Rotate the transport keys
|
||||||
TransportKeys rotated = createTransportKeys(rotationPeriod + 1, active);
|
TransportKeys rotated = createTransportKeys(rotationPeriod + 1);
|
||||||
TransportKeys rotated1 =
|
TransportKeys rotated1 = createTransportKeys(rotationPeriod1 + 1);
|
||||||
createTransportKeys(rotationPeriod1 + 1, active);
|
|
||||||
db.updateTransportKeys(txn, new KeySet(keySetId, contactId, rotated));
|
db.updateTransportKeys(txn, new KeySet(keySetId, contactId, rotated));
|
||||||
db.updateTransportKeys(txn, new KeySet(keySetId1, contactId, rotated1));
|
db.updateTransportKeys(txn, new KeySet(keySetId1, contactId, rotated1));
|
||||||
|
|
||||||
@@ -730,6 +727,95 @@ public abstract class JdbcDatabaseTest extends BrambleTestCase {
|
|||||||
db.close();
|
db.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testUnboundTransportKeys() throws Exception {
|
||||||
|
long rotationPeriod = 123, rotationPeriod1 = 234;
|
||||||
|
TransportKeys keys = createTransportKeys(rotationPeriod);
|
||||||
|
TransportKeys keys1 = createTransportKeys(rotationPeriod1);
|
||||||
|
|
||||||
|
Database<Connection> db = open(false);
|
||||||
|
Connection txn = db.startTransaction();
|
||||||
|
|
||||||
|
// Initially there should be no transport keys in the database
|
||||||
|
assertEquals(emptyList(), db.getTransportKeys(txn, transportId));
|
||||||
|
|
||||||
|
// Add the contact, the transport and the unbound transport keys
|
||||||
|
db.addLocalAuthor(txn, localAuthor);
|
||||||
|
assertEquals(contactId, db.addContact(txn, author, localAuthor.getId(),
|
||||||
|
true, true));
|
||||||
|
db.addTransport(txn, transportId, 123);
|
||||||
|
assertEquals(keySetId, db.addTransportKeys(txn, null, keys));
|
||||||
|
assertEquals(keySetId1, db.addTransportKeys(txn, null, keys1));
|
||||||
|
|
||||||
|
// Retrieve the transport keys
|
||||||
|
Collection<KeySet> allKeys = db.getTransportKeys(txn, transportId);
|
||||||
|
assertEquals(2, allKeys.size());
|
||||||
|
for (KeySet ks : allKeys) {
|
||||||
|
assertNull(ks.getContactId());
|
||||||
|
if (ks.getKeySetId().equals(keySetId)) {
|
||||||
|
assertKeysEquals(keys, ks.getTransportKeys());
|
||||||
|
} else {
|
||||||
|
assertEquals(keySetId1, ks.getKeySetId());
|
||||||
|
assertKeysEquals(keys1, ks.getTransportKeys());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Bind the first set of transport keys
|
||||||
|
db.bindTransportKeys(txn, contactId, transportId, keySetId);
|
||||||
|
|
||||||
|
// Retrieve the keys again - the first set should be bound
|
||||||
|
allKeys = db.getTransportKeys(txn, transportId);
|
||||||
|
assertEquals(2, allKeys.size());
|
||||||
|
for (KeySet ks : allKeys) {
|
||||||
|
if (ks.getKeySetId().equals(keySetId)) {
|
||||||
|
assertEquals(contactId, ks.getContactId());
|
||||||
|
assertKeysEquals(keys, ks.getTransportKeys());
|
||||||
|
} else {
|
||||||
|
assertEquals(keySetId1, ks.getKeySetId());
|
||||||
|
assertNull(ks.getContactId());
|
||||||
|
assertKeysEquals(keys1, ks.getTransportKeys());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Rotate the transport keys
|
||||||
|
TransportKeys rotated = createTransportKeys(rotationPeriod + 1);
|
||||||
|
TransportKeys rotated1 = createTransportKeys(rotationPeriod1 + 1);
|
||||||
|
db.updateTransportKeys(txn, new KeySet(keySetId, contactId, rotated));
|
||||||
|
db.updateTransportKeys(txn, new KeySet(keySetId1, null, rotated1));
|
||||||
|
|
||||||
|
// Retrieve the transport keys again
|
||||||
|
allKeys = db.getTransportKeys(txn, transportId);
|
||||||
|
assertEquals(2, allKeys.size());
|
||||||
|
for (KeySet ks : allKeys) {
|
||||||
|
if (ks.getKeySetId().equals(keySetId)) {
|
||||||
|
assertEquals(contactId, ks.getContactId());
|
||||||
|
assertKeysEquals(rotated, ks.getTransportKeys());
|
||||||
|
} else {
|
||||||
|
assertEquals(keySetId1, ks.getKeySetId());
|
||||||
|
assertNull(ks.getContactId());
|
||||||
|
assertKeysEquals(rotated1, ks.getTransportKeys());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove the unbound transport keys
|
||||||
|
db.removeTransportKeys(txn, transportId, keySetId1);
|
||||||
|
|
||||||
|
// Retrieve the keys again - the second set should be gone
|
||||||
|
allKeys = db.getTransportKeys(txn, transportId);
|
||||||
|
assertEquals(1, allKeys.size());
|
||||||
|
KeySet ks = allKeys.iterator().next();
|
||||||
|
assertEquals(keySetId, ks.getKeySetId());
|
||||||
|
assertEquals(contactId, ks.getContactId());
|
||||||
|
assertKeysEquals(rotated, ks.getTransportKeys());
|
||||||
|
|
||||||
|
// Removing the transport should remove the remaining transport keys
|
||||||
|
db.removeTransport(txn, transportId);
|
||||||
|
assertEquals(emptyList(), db.getTransportKeys(txn, transportId));
|
||||||
|
|
||||||
|
db.commitTransaction(txn);
|
||||||
|
db.close();
|
||||||
|
}
|
||||||
|
|
||||||
private void assertKeysEquals(TransportKeys expected,
|
private void assertKeysEquals(TransportKeys expected,
|
||||||
TransportKeys actual) {
|
TransportKeys actual) {
|
||||||
assertEquals(expected.getTransportId(), actual.getTransportId());
|
assertEquals(expected.getTransportId(), actual.getTransportId());
|
||||||
@@ -767,7 +853,7 @@ public abstract class JdbcDatabaseTest extends BrambleTestCase {
|
|||||||
@Test
|
@Test
|
||||||
public void testIncrementStreamCounter() throws Exception {
|
public void testIncrementStreamCounter() throws Exception {
|
||||||
long rotationPeriod = 123;
|
long rotationPeriod = 123;
|
||||||
TransportKeys keys = createTransportKeys(rotationPeriod, true);
|
TransportKeys keys = createTransportKeys(rotationPeriod);
|
||||||
long streamCounter = keys.getCurrentOutgoingKeys().getStreamCounter();
|
long streamCounter = keys.getCurrentOutgoingKeys().getStreamCounter();
|
||||||
|
|
||||||
Database<Connection> db = open(false);
|
Database<Connection> db = open(false);
|
||||||
@@ -807,9 +893,8 @@ public abstract class JdbcDatabaseTest extends BrambleTestCase {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testSetReorderingWindow() throws Exception {
|
public void testSetReorderingWindow() throws Exception {
|
||||||
boolean active = random.nextBoolean();
|
|
||||||
long rotationPeriod = 123;
|
long rotationPeriod = 123;
|
||||||
TransportKeys keys = createTransportKeys(rotationPeriod, active);
|
TransportKeys keys = createTransportKeys(rotationPeriod);
|
||||||
long base = keys.getCurrentIncomingKeys().getWindowBase();
|
long base = keys.getCurrentIncomingKeys().getWindowBase();
|
||||||
byte[] bitmap = keys.getCurrentIncomingKeys().getWindowBitmap();
|
byte[] bitmap = keys.getCurrentIncomingKeys().getWindowBitmap();
|
||||||
|
|
||||||
@@ -819,12 +904,12 @@ public abstract class JdbcDatabaseTest extends BrambleTestCase {
|
|||||||
// Add the contact, transport and transport keys
|
// Add the contact, transport and transport keys
|
||||||
db.addLocalAuthor(txn, localAuthor);
|
db.addLocalAuthor(txn, localAuthor);
|
||||||
assertEquals(contactId, db.addContact(txn, author, localAuthor.getId(),
|
assertEquals(contactId, db.addContact(txn, author, localAuthor.getId(),
|
||||||
true, active));
|
true, true));
|
||||||
db.addTransport(txn, transportId, 123);
|
db.addTransport(txn, transportId, 123);
|
||||||
assertEquals(keySetId, db.addTransportKeys(txn, contactId, keys));
|
assertEquals(keySetId, db.addTransportKeys(txn, contactId, keys));
|
||||||
|
|
||||||
// Update the reordering window and retrieve the transport keys
|
// Update the reordering window and retrieve the transport keys
|
||||||
random.nextBytes(bitmap);
|
new Random().nextBytes(bitmap);
|
||||||
db.setReorderingWindow(txn, keySetId, transportId, rotationPeriod,
|
db.setReorderingWindow(txn, keySetId, transportId, rotationPeriod,
|
||||||
base + 1, bitmap);
|
base + 1, bitmap);
|
||||||
Collection<KeySet> newKeys = db.getTransportKeys(txn, transportId);
|
Collection<KeySet> newKeys = db.getTransportKeys(txn, transportId);
|
||||||
@@ -1823,8 +1908,7 @@ public abstract class JdbcDatabaseTest extends BrambleTestCase {
|
|||||||
return db;
|
return db;
|
||||||
}
|
}
|
||||||
|
|
||||||
private TransportKeys createTransportKeys(long rotationPeriod,
|
private TransportKeys createTransportKeys(long rotationPeriod) {
|
||||||
boolean active) {
|
|
||||||
SecretKey inPrevTagKey = getSecretKey();
|
SecretKey inPrevTagKey = getSecretKey();
|
||||||
SecretKey inPrevHeaderKey = getSecretKey();
|
SecretKey inPrevHeaderKey = getSecretKey();
|
||||||
IncomingKeys inPrev = new IncomingKeys(inPrevTagKey, inPrevHeaderKey,
|
IncomingKeys inPrev = new IncomingKeys(inPrevTagKey, inPrevHeaderKey,
|
||||||
@@ -1840,7 +1924,7 @@ public abstract class JdbcDatabaseTest extends BrambleTestCase {
|
|||||||
SecretKey outCurrTagKey = getSecretKey();
|
SecretKey outCurrTagKey = getSecretKey();
|
||||||
SecretKey outCurrHeaderKey = getSecretKey();
|
SecretKey outCurrHeaderKey = getSecretKey();
|
||||||
OutgoingKeys outCurr = new OutgoingKeys(outCurrTagKey, outCurrHeaderKey,
|
OutgoingKeys outCurr = new OutgoingKeys(outCurrTagKey, outCurrHeaderKey,
|
||||||
rotationPeriod, 456, active);
|
rotationPeriod, 456, true);
|
||||||
return new TransportKeys(transportId, inPrev, inCurr, inNext, outCurr);
|
return new TransportKeys(transportId, inPrev, inCurr, inNext, outCurr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -2,7 +2,6 @@ package org.briarproject.bramble.plugin;
|
|||||||
|
|
||||||
import org.briarproject.bramble.api.event.EventBus;
|
import org.briarproject.bramble.api.event.EventBus;
|
||||||
import org.briarproject.bramble.api.plugin.ConnectionManager;
|
import org.briarproject.bramble.api.plugin.ConnectionManager;
|
||||||
import org.briarproject.bramble.api.plugin.ConnectionRegistry;
|
|
||||||
import org.briarproject.bramble.api.plugin.PluginConfig;
|
import org.briarproject.bramble.api.plugin.PluginConfig;
|
||||||
import org.briarproject.bramble.api.plugin.PluginException;
|
import org.briarproject.bramble.api.plugin.PluginException;
|
||||||
import org.briarproject.bramble.api.plugin.TransportId;
|
import org.briarproject.bramble.api.plugin.TransportId;
|
||||||
@@ -14,18 +13,16 @@ import org.briarproject.bramble.api.plugin.simplex.SimplexPluginCallback;
|
|||||||
import org.briarproject.bramble.api.plugin.simplex.SimplexPluginFactory;
|
import org.briarproject.bramble.api.plugin.simplex.SimplexPluginFactory;
|
||||||
import org.briarproject.bramble.api.properties.TransportPropertyManager;
|
import org.briarproject.bramble.api.properties.TransportPropertyManager;
|
||||||
import org.briarproject.bramble.api.settings.SettingsManager;
|
import org.briarproject.bramble.api.settings.SettingsManager;
|
||||||
import org.briarproject.bramble.api.system.Clock;
|
import org.briarproject.bramble.api.ui.UiCallback;
|
||||||
import org.briarproject.bramble.test.BrambleTestCase;
|
import org.briarproject.bramble.test.BrambleTestCase;
|
||||||
import org.jmock.Expectations;
|
import org.jmock.Expectations;
|
||||||
import org.jmock.Mockery;
|
import org.jmock.Mockery;
|
||||||
import org.jmock.lib.concurrent.Synchroniser;
|
import org.jmock.lib.concurrent.Synchroniser;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
import java.security.SecureRandom;
|
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.concurrent.Executor;
|
import java.util.concurrent.Executor;
|
||||||
import java.util.concurrent.Executors;
|
import java.util.concurrent.Executors;
|
||||||
import java.util.concurrent.ScheduledExecutorService;
|
|
||||||
|
|
||||||
import static org.briarproject.bramble.test.TestUtils.getTransportId;
|
import static org.briarproject.bramble.test.TestUtils.getTransportId;
|
||||||
|
|
||||||
@@ -37,20 +34,15 @@ public class PluginManagerImplTest extends BrambleTestCase {
|
|||||||
setThreadingPolicy(new Synchroniser());
|
setThreadingPolicy(new Synchroniser());
|
||||||
}};
|
}};
|
||||||
Executor ioExecutor = Executors.newSingleThreadExecutor();
|
Executor ioExecutor = Executors.newSingleThreadExecutor();
|
||||||
ScheduledExecutorService scheduler =
|
|
||||||
context.mock(ScheduledExecutorService.class);
|
|
||||||
SecureRandom random = new SecureRandom();
|
|
||||||
Clock clock = context.mock(Clock.class);
|
|
||||||
EventBus eventBus = context.mock(EventBus.class);
|
EventBus eventBus = context.mock(EventBus.class);
|
||||||
PluginConfig pluginConfig = context.mock(PluginConfig.class);
|
PluginConfig pluginConfig = context.mock(PluginConfig.class);
|
||||||
ConnectionManager connectionManager =
|
ConnectionManager connectionManager =
|
||||||
context.mock(ConnectionManager.class);
|
context.mock(ConnectionManager.class);
|
||||||
ConnectionRegistry connectionRegistry =
|
|
||||||
context.mock(ConnectionRegistry.class);
|
|
||||||
SettingsManager settingsManager =
|
SettingsManager settingsManager =
|
||||||
context.mock(SettingsManager.class);
|
context.mock(SettingsManager.class);
|
||||||
TransportPropertyManager transportPropertyManager =
|
TransportPropertyManager transportPropertyManager =
|
||||||
context.mock(TransportPropertyManager.class);
|
context.mock(TransportPropertyManager.class);
|
||||||
|
UiCallback uiCallback = context.mock(UiCallback.class);
|
||||||
|
|
||||||
// Two simplex plugin factories: both create plugins, one fails to start
|
// Two simplex plugin factories: both create plugins, one fails to start
|
||||||
SimplexPluginFactory simplexFactory =
|
SimplexPluginFactory simplexFactory =
|
||||||
@@ -79,8 +71,6 @@ public class PluginManagerImplTest extends BrambleTestCase {
|
|||||||
will(returnValue(simplexFailId));
|
will(returnValue(simplexFailId));
|
||||||
allowing(duplexPlugin).getId();
|
allowing(duplexPlugin).getId();
|
||||||
will(returnValue(duplexId));
|
will(returnValue(duplexId));
|
||||||
allowing(pluginConfig).shouldPoll();
|
|
||||||
will(returnValue(false));
|
|
||||||
// start()
|
// start()
|
||||||
// First simplex plugin
|
// First simplex plugin
|
||||||
oneOf(pluginConfig).getSimplexFactories();
|
oneOf(pluginConfig).getSimplexFactories();
|
||||||
@@ -122,9 +112,9 @@ public class PluginManagerImplTest extends BrambleTestCase {
|
|||||||
oneOf(duplexPlugin).stop();
|
oneOf(duplexPlugin).stop();
|
||||||
}});
|
}});
|
||||||
|
|
||||||
PluginManagerImpl p = new PluginManagerImpl(ioExecutor, scheduler,
|
PluginManagerImpl p = new PluginManagerImpl(ioExecutor, eventBus,
|
||||||
eventBus, pluginConfig, connectionManager, connectionRegistry,
|
pluginConfig, connectionManager, settingsManager,
|
||||||
settingsManager, transportPropertyManager, random, clock);
|
transportPropertyManager, uiCallback);
|
||||||
|
|
||||||
// Two plugins should be started and stopped
|
// Two plugins should be started and stopped
|
||||||
p.startService();
|
p.startService();
|
||||||
|
|||||||
@@ -15,8 +15,6 @@ import org.briarproject.bramble.api.plugin.event.ConnectionOpenedEvent;
|
|||||||
import org.briarproject.bramble.api.plugin.event.TransportDisabledEvent;
|
import org.briarproject.bramble.api.plugin.event.TransportDisabledEvent;
|
||||||
import org.briarproject.bramble.api.plugin.event.TransportEnabledEvent;
|
import org.briarproject.bramble.api.plugin.event.TransportEnabledEvent;
|
||||||
import org.briarproject.bramble.api.plugin.simplex.SimplexPlugin;
|
import org.briarproject.bramble.api.plugin.simplex.SimplexPlugin;
|
||||||
import org.briarproject.bramble.api.properties.TransportProperties;
|
|
||||||
import org.briarproject.bramble.api.properties.TransportPropertyManager;
|
|
||||||
import org.briarproject.bramble.api.system.Clock;
|
import org.briarproject.bramble.api.system.Clock;
|
||||||
import org.briarproject.bramble.test.BrambleMockTestCase;
|
import org.briarproject.bramble.test.BrambleMockTestCase;
|
||||||
import org.briarproject.bramble.test.ImmediateExecutor;
|
import org.briarproject.bramble.test.ImmediateExecutor;
|
||||||
@@ -26,15 +24,13 @@ import org.jmock.lib.legacy.ClassImposteriser;
|
|||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
import java.security.SecureRandom;
|
import java.security.SecureRandom;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.concurrent.Executor;
|
import java.util.concurrent.Executor;
|
||||||
import java.util.concurrent.ScheduledExecutorService;
|
import java.util.concurrent.ScheduledExecutorService;
|
||||||
import java.util.concurrent.ScheduledFuture;
|
import java.util.concurrent.ScheduledFuture;
|
||||||
|
|
||||||
import static java.util.Arrays.asList;
|
|
||||||
import static java.util.Collections.emptyList;
|
|
||||||
import static java.util.Collections.singletonList;
|
|
||||||
import static java.util.Collections.singletonMap;
|
|
||||||
import static java.util.concurrent.TimeUnit.MILLISECONDS;
|
import static java.util.concurrent.TimeUnit.MILLISECONDS;
|
||||||
import static org.briarproject.bramble.test.TestUtils.getTransportId;
|
import static org.briarproject.bramble.test.TestUtils.getTransportId;
|
||||||
|
|
||||||
@@ -48,8 +44,6 @@ public class PollerTest extends BrambleMockTestCase {
|
|||||||
context.mock(ConnectionRegistry.class);
|
context.mock(ConnectionRegistry.class);
|
||||||
private final PluginManager pluginManager =
|
private final PluginManager pluginManager =
|
||||||
context.mock(PluginManager.class);
|
context.mock(PluginManager.class);
|
||||||
private final TransportPropertyManager transportPropertyManager =
|
|
||||||
context.mock(TransportPropertyManager.class);
|
|
||||||
private final Clock clock = context.mock(Clock.class);
|
private final Clock clock = context.mock(Clock.class);
|
||||||
private final ScheduledFuture future = context.mock(ScheduledFuture.class);
|
private final ScheduledFuture future = context.mock(ScheduledFuture.class);
|
||||||
private final SecureRandom random;
|
private final SecureRandom random;
|
||||||
@@ -57,7 +51,6 @@ public class PollerTest extends BrambleMockTestCase {
|
|||||||
private final Executor ioExecutor = new ImmediateExecutor();
|
private final Executor ioExecutor = new ImmediateExecutor();
|
||||||
private final TransportId transportId = getTransportId();
|
private final TransportId transportId = getTransportId();
|
||||||
private final ContactId contactId = new ContactId(234);
|
private final ContactId contactId = new ContactId(234);
|
||||||
private final TransportProperties properties = new TransportProperties();
|
|
||||||
private final int pollingInterval = 60 * 1000;
|
private final int pollingInterval = 60 * 1000;
|
||||||
private final long now = System.currentTimeMillis();
|
private final long now = System.currentTimeMillis();
|
||||||
|
|
||||||
@@ -73,8 +66,8 @@ public class PollerTest extends BrambleMockTestCase {
|
|||||||
SimplexPlugin simplexPlugin1 =
|
SimplexPlugin simplexPlugin1 =
|
||||||
context.mock(SimplexPlugin.class, "simplexPlugin1");
|
context.mock(SimplexPlugin.class, "simplexPlugin1");
|
||||||
TransportId simplexId1 = getTransportId();
|
TransportId simplexId1 = getTransportId();
|
||||||
List<SimplexPlugin> simplexPlugins =
|
List<SimplexPlugin> simplexPlugins = Arrays.asList(simplexPlugin,
|
||||||
asList(simplexPlugin, simplexPlugin1);
|
simplexPlugin1);
|
||||||
TransportConnectionWriter simplexWriter =
|
TransportConnectionWriter simplexWriter =
|
||||||
context.mock(TransportConnectionWriter.class);
|
context.mock(TransportConnectionWriter.class);
|
||||||
|
|
||||||
@@ -83,8 +76,8 @@ public class PollerTest extends BrambleMockTestCase {
|
|||||||
TransportId duplexId = getTransportId();
|
TransportId duplexId = getTransportId();
|
||||||
DuplexPlugin duplexPlugin1 =
|
DuplexPlugin duplexPlugin1 =
|
||||||
context.mock(DuplexPlugin.class, "duplexPlugin1");
|
context.mock(DuplexPlugin.class, "duplexPlugin1");
|
||||||
List<DuplexPlugin> duplexPlugins =
|
List<DuplexPlugin> duplexPlugins = Arrays.asList(duplexPlugin,
|
||||||
asList(duplexPlugin, duplexPlugin1);
|
duplexPlugin1);
|
||||||
DuplexTransportConnection duplexConnection =
|
DuplexTransportConnection duplexConnection =
|
||||||
context.mock(DuplexTransportConnection.class);
|
context.mock(DuplexTransportConnection.class);
|
||||||
|
|
||||||
@@ -103,12 +96,8 @@ public class PollerTest extends BrambleMockTestCase {
|
|||||||
will(returnValue(simplexId1));
|
will(returnValue(simplexId1));
|
||||||
oneOf(connectionRegistry).isConnected(contactId, simplexId1);
|
oneOf(connectionRegistry).isConnected(contactId, simplexId1);
|
||||||
will(returnValue(false));
|
will(returnValue(false));
|
||||||
// Get the transport properties
|
|
||||||
oneOf(transportPropertyManager).getRemoteProperties(contactId,
|
|
||||||
simplexId1);
|
|
||||||
will(returnValue(properties));
|
|
||||||
// Connect to the contact
|
// Connect to the contact
|
||||||
oneOf(simplexPlugin1).createWriter(properties);
|
oneOf(simplexPlugin1).createWriter(contactId);
|
||||||
will(returnValue(simplexWriter));
|
will(returnValue(simplexWriter));
|
||||||
// Pass the connection to the connection manager
|
// Pass the connection to the connection manager
|
||||||
oneOf(connectionManager).manageOutgoingConnection(contactId,
|
oneOf(connectionManager).manageOutgoingConnection(contactId,
|
||||||
@@ -116,7 +105,7 @@ public class PollerTest extends BrambleMockTestCase {
|
|||||||
// Get the duplex plugins
|
// Get the duplex plugins
|
||||||
oneOf(pluginManager).getDuplexPlugins();
|
oneOf(pluginManager).getDuplexPlugins();
|
||||||
will(returnValue(duplexPlugins));
|
will(returnValue(duplexPlugins));
|
||||||
// The duplex plugin supports polling
|
// The first plugin supports polling
|
||||||
oneOf(duplexPlugin).shouldPoll();
|
oneOf(duplexPlugin).shouldPoll();
|
||||||
will(returnValue(true));
|
will(returnValue(true));
|
||||||
// Check whether the contact is already connected
|
// Check whether the contact is already connected
|
||||||
@@ -124,12 +113,8 @@ public class PollerTest extends BrambleMockTestCase {
|
|||||||
will(returnValue(duplexId));
|
will(returnValue(duplexId));
|
||||||
oneOf(connectionRegistry).isConnected(contactId, duplexId);
|
oneOf(connectionRegistry).isConnected(contactId, duplexId);
|
||||||
will(returnValue(false));
|
will(returnValue(false));
|
||||||
// Get the transport properties
|
|
||||||
oneOf(transportPropertyManager).getRemoteProperties(contactId,
|
|
||||||
duplexId);
|
|
||||||
will(returnValue(properties));
|
|
||||||
// Connect to the contact
|
// Connect to the contact
|
||||||
oneOf(duplexPlugin).createConnection(properties);
|
oneOf(duplexPlugin).createConnection(contactId);
|
||||||
will(returnValue(duplexConnection));
|
will(returnValue(duplexConnection));
|
||||||
// Pass the connection to the connection manager
|
// Pass the connection to the connection manager
|
||||||
oneOf(connectionManager).manageOutgoingConnection(contactId,
|
oneOf(connectionManager).manageOutgoingConnection(contactId,
|
||||||
@@ -140,8 +125,7 @@ public class PollerTest extends BrambleMockTestCase {
|
|||||||
}});
|
}});
|
||||||
|
|
||||||
Poller p = new Poller(ioExecutor, scheduler, connectionManager,
|
Poller p = new Poller(ioExecutor, scheduler, connectionManager,
|
||||||
connectionRegistry, pluginManager, transportPropertyManager,
|
connectionRegistry, pluginManager, random, clock);
|
||||||
random, clock);
|
|
||||||
|
|
||||||
p.eventOccurred(new ContactStatusChangedEvent(contactId, true));
|
p.eventOccurred(new ContactStatusChangedEvent(contactId, true));
|
||||||
}
|
}
|
||||||
@@ -181,12 +165,8 @@ public class PollerTest extends BrambleMockTestCase {
|
|||||||
// Check whether the contact is already connected
|
// Check whether the contact is already connected
|
||||||
oneOf(connectionRegistry).isConnected(contactId, transportId);
|
oneOf(connectionRegistry).isConnected(contactId, transportId);
|
||||||
will(returnValue(false));
|
will(returnValue(false));
|
||||||
// Get the transport properties
|
|
||||||
oneOf(transportPropertyManager).getRemoteProperties(contactId,
|
|
||||||
transportId);
|
|
||||||
will(returnValue(properties));
|
|
||||||
// Connect to the contact
|
// Connect to the contact
|
||||||
oneOf(plugin).createConnection(properties);
|
oneOf(plugin).createConnection(contactId);
|
||||||
will(returnValue(duplexConnection));
|
will(returnValue(duplexConnection));
|
||||||
// Pass the connection to the connection manager
|
// Pass the connection to the connection manager
|
||||||
oneOf(connectionManager).manageOutgoingConnection(contactId,
|
oneOf(connectionManager).manageOutgoingConnection(contactId,
|
||||||
@@ -194,15 +174,15 @@ public class PollerTest extends BrambleMockTestCase {
|
|||||||
}});
|
}});
|
||||||
|
|
||||||
Poller p = new Poller(ioExecutor, scheduler, connectionManager,
|
Poller p = new Poller(ioExecutor, scheduler, connectionManager,
|
||||||
connectionRegistry, pluginManager, transportPropertyManager,
|
connectionRegistry, pluginManager, random, clock);
|
||||||
random, clock);
|
|
||||||
|
|
||||||
p.eventOccurred(new ConnectionClosedEvent(contactId, transportId,
|
p.eventOccurred(new ConnectionClosedEvent(contactId, transportId,
|
||||||
false));
|
false));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testRescheduleOnConnectionOpened() {
|
public void testRescheduleOnConnectionOpened() throws Exception {
|
||||||
Plugin plugin = context.mock(Plugin.class);
|
Plugin plugin = context.mock(Plugin.class);
|
||||||
|
|
||||||
context.checking(new Expectations() {{
|
context.checking(new Expectations() {{
|
||||||
@@ -225,15 +205,14 @@ public class PollerTest extends BrambleMockTestCase {
|
|||||||
}});
|
}});
|
||||||
|
|
||||||
Poller p = new Poller(ioExecutor, scheduler, connectionManager,
|
Poller p = new Poller(ioExecutor, scheduler, connectionManager,
|
||||||
connectionRegistry, pluginManager, transportPropertyManager,
|
connectionRegistry, pluginManager, random, clock);
|
||||||
random, clock);
|
|
||||||
|
|
||||||
p.eventOccurred(new ConnectionOpenedEvent(contactId, transportId,
|
p.eventOccurred(new ConnectionOpenedEvent(contactId, transportId,
|
||||||
false));
|
false));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testRescheduleDoesNotReplaceEarlierTask() {
|
public void testRescheduleDoesNotReplaceEarlierTask() throws Exception {
|
||||||
Plugin plugin = context.mock(Plugin.class);
|
Plugin plugin = context.mock(Plugin.class);
|
||||||
|
|
||||||
context.checking(new Expectations() {{
|
context.checking(new Expectations() {{
|
||||||
@@ -269,8 +248,7 @@ public class PollerTest extends BrambleMockTestCase {
|
|||||||
}});
|
}});
|
||||||
|
|
||||||
Poller p = new Poller(ioExecutor, scheduler, connectionManager,
|
Poller p = new Poller(ioExecutor, scheduler, connectionManager,
|
||||||
connectionRegistry, pluginManager, transportPropertyManager,
|
connectionRegistry, pluginManager, random, clock);
|
||||||
random, clock);
|
|
||||||
|
|
||||||
p.eventOccurred(new ConnectionOpenedEvent(contactId, transportId,
|
p.eventOccurred(new ConnectionOpenedEvent(contactId, transportId,
|
||||||
false));
|
false));
|
||||||
@@ -279,7 +257,7 @@ public class PollerTest extends BrambleMockTestCase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testRescheduleReplacesLaterTask() {
|
public void testRescheduleReplacesLaterTask() throws Exception {
|
||||||
Plugin plugin = context.mock(Plugin.class);
|
Plugin plugin = context.mock(Plugin.class);
|
||||||
|
|
||||||
context.checking(new Expectations() {{
|
context.checking(new Expectations() {{
|
||||||
@@ -318,8 +296,7 @@ public class PollerTest extends BrambleMockTestCase {
|
|||||||
}});
|
}});
|
||||||
|
|
||||||
Poller p = new Poller(ioExecutor, scheduler, connectionManager,
|
Poller p = new Poller(ioExecutor, scheduler, connectionManager,
|
||||||
connectionRegistry, pluginManager, transportPropertyManager,
|
connectionRegistry, pluginManager, random, clock);
|
||||||
random, clock);
|
|
||||||
|
|
||||||
p.eventOccurred(new ConnectionOpenedEvent(contactId, transportId,
|
p.eventOccurred(new ConnectionOpenedEvent(contactId, transportId,
|
||||||
false));
|
false));
|
||||||
@@ -329,7 +306,8 @@ public class PollerTest extends BrambleMockTestCase {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testPollsOnTransportEnabled() throws Exception {
|
public void testPollsOnTransportEnabled() throws Exception {
|
||||||
DuplexPlugin plugin = context.mock(DuplexPlugin.class);
|
Plugin plugin = context.mock(Plugin.class);
|
||||||
|
List<ContactId> connected = Collections.singletonList(contactId);
|
||||||
|
|
||||||
context.checking(new Expectations() {{
|
context.checking(new Expectations() {{
|
||||||
allowing(plugin).getId();
|
allowing(plugin).getId();
|
||||||
@@ -357,69 +335,20 @@ public class PollerTest extends BrambleMockTestCase {
|
|||||||
oneOf(scheduler).schedule(with(any(Runnable.class)),
|
oneOf(scheduler).schedule(with(any(Runnable.class)),
|
||||||
with((long) (pollingInterval * 0.5)), with(MILLISECONDS));
|
with((long) (pollingInterval * 0.5)), with(MILLISECONDS));
|
||||||
will(returnValue(future));
|
will(returnValue(future));
|
||||||
// Get the transport properties and connected contacts
|
|
||||||
oneOf(transportPropertyManager).getRemoteProperties(transportId);
|
|
||||||
will(returnValue(singletonMap(contactId, properties)));
|
|
||||||
oneOf(connectionRegistry).getConnectedContacts(transportId);
|
|
||||||
will(returnValue(emptyList()));
|
|
||||||
// Poll the plugin
|
// Poll the plugin
|
||||||
oneOf(plugin).poll(singletonMap(contactId, properties));
|
|
||||||
}});
|
|
||||||
|
|
||||||
Poller p = new Poller(ioExecutor, scheduler, connectionManager,
|
|
||||||
connectionRegistry, pluginManager, transportPropertyManager,
|
|
||||||
random, clock);
|
|
||||||
|
|
||||||
p.eventOccurred(new TransportEnabledEvent(transportId));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testDoesNotPollIfAllContactsAreConnected() throws Exception {
|
|
||||||
DuplexPlugin plugin = context.mock(DuplexPlugin.class);
|
|
||||||
|
|
||||||
context.checking(new Expectations() {{
|
|
||||||
allowing(plugin).getId();
|
|
||||||
will(returnValue(transportId));
|
|
||||||
// Get the plugin
|
|
||||||
oneOf(pluginManager).getPlugin(transportId);
|
|
||||||
will(returnValue(plugin));
|
|
||||||
// The plugin supports polling
|
|
||||||
oneOf(plugin).shouldPoll();
|
|
||||||
will(returnValue(true));
|
|
||||||
// Schedule a polling task immediately
|
|
||||||
oneOf(clock).currentTimeMillis();
|
|
||||||
will(returnValue(now));
|
|
||||||
oneOf(scheduler).schedule(with(any(Runnable.class)), with(0L),
|
|
||||||
with(MILLISECONDS));
|
|
||||||
will(returnValue(future));
|
|
||||||
will(new RunAction());
|
|
||||||
// Running the polling task schedules the next polling task
|
|
||||||
oneOf(plugin).getPollingInterval();
|
|
||||||
will(returnValue(pollingInterval));
|
|
||||||
oneOf(random).nextDouble();
|
|
||||||
will(returnValue(0.5));
|
|
||||||
oneOf(clock).currentTimeMillis();
|
|
||||||
will(returnValue(now));
|
|
||||||
oneOf(scheduler).schedule(with(any(Runnable.class)),
|
|
||||||
with((long) (pollingInterval * 0.5)), with(MILLISECONDS));
|
|
||||||
will(returnValue(future));
|
|
||||||
// Get the transport properties and connected contacts
|
|
||||||
oneOf(transportPropertyManager).getRemoteProperties(transportId);
|
|
||||||
will(returnValue(singletonMap(contactId, properties)));
|
|
||||||
oneOf(connectionRegistry).getConnectedContacts(transportId);
|
oneOf(connectionRegistry).getConnectedContacts(transportId);
|
||||||
will(returnValue(singletonList(contactId)));
|
will(returnValue(connected));
|
||||||
// All contacts are connected, so don't poll the plugin
|
oneOf(plugin).poll(connected);
|
||||||
}});
|
}});
|
||||||
|
|
||||||
Poller p = new Poller(ioExecutor, scheduler, connectionManager,
|
Poller p = new Poller(ioExecutor, scheduler, connectionManager,
|
||||||
connectionRegistry, pluginManager, transportPropertyManager,
|
connectionRegistry, pluginManager, random, clock);
|
||||||
random, clock);
|
|
||||||
|
|
||||||
p.eventOccurred(new TransportEnabledEvent(transportId));
|
p.eventOccurred(new TransportEnabledEvent(transportId));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testCancelsPollingOnTransportDisabled() {
|
public void testCancelsPollingOnTransportDisabled() throws Exception {
|
||||||
Plugin plugin = context.mock(Plugin.class);
|
Plugin plugin = context.mock(Plugin.class);
|
||||||
|
|
||||||
context.checking(new Expectations() {{
|
context.checking(new Expectations() {{
|
||||||
@@ -442,8 +371,7 @@ public class PollerTest extends BrambleMockTestCase {
|
|||||||
}});
|
}});
|
||||||
|
|
||||||
Poller p = new Poller(ioExecutor, scheduler, connectionManager,
|
Poller p = new Poller(ioExecutor, scheduler, connectionManager,
|
||||||
connectionRegistry, pluginManager, transportPropertyManager,
|
connectionRegistry, pluginManager, random, clock);
|
||||||
random, clock);
|
|
||||||
|
|
||||||
p.eventOccurred(new TransportEnabledEvent(transportId));
|
p.eventOccurred(new TransportEnabledEvent(transportId));
|
||||||
p.eventOccurred(new TransportDisabledEvent(transportId));
|
p.eventOccurred(new TransportDisabledEvent(transportId));
|
||||||
|
|||||||
@@ -23,6 +23,8 @@ import java.net.ServerSocket;
|
|||||||
import java.net.Socket;
|
import java.net.Socket;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.Comparator;
|
import java.util.Comparator;
|
||||||
|
import java.util.Hashtable;
|
||||||
|
import java.util.Map;
|
||||||
import java.util.concurrent.CountDownLatch;
|
import java.util.concurrent.CountDownLatch;
|
||||||
import java.util.concurrent.Executor;
|
import java.util.concurrent.Executor;
|
||||||
import java.util.concurrent.Executors;
|
import java.util.concurrent.Executors;
|
||||||
@@ -38,6 +40,7 @@ import static org.junit.Assert.assertTrue;
|
|||||||
|
|
||||||
public class LanTcpPluginTest extends BrambleTestCase {
|
public class LanTcpPluginTest extends BrambleTestCase {
|
||||||
|
|
||||||
|
private final ContactId contactId = new ContactId(234);
|
||||||
private final Backoff backoff = new TestBackoff();
|
private final Backoff backoff = new TestBackoff();
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -157,10 +160,12 @@ public class LanTcpPluginTest extends BrambleTestCase {
|
|||||||
error.set(true);
|
error.set(true);
|
||||||
}
|
}
|
||||||
}).start();
|
}).start();
|
||||||
// Connect to the port
|
// Tell the plugin about the port
|
||||||
TransportProperties p = new TransportProperties();
|
TransportProperties p = new TransportProperties();
|
||||||
p.put("ipPorts", addrString + ":" + port);
|
p.put("ipPorts", addrString + ":" + port);
|
||||||
DuplexTransportConnection d = plugin.createConnection(p);
|
callback.remote.put(contactId, p);
|
||||||
|
// Connect to the port
|
||||||
|
DuplexTransportConnection d = plugin.createConnection(contactId);
|
||||||
assertNotNull(d);
|
assertNotNull(d);
|
||||||
// Check that the connection was accepted
|
// Check that the connection was accepted
|
||||||
assertTrue(latch.await(5, SECONDS));
|
assertTrue(latch.await(5, SECONDS));
|
||||||
@@ -276,7 +281,7 @@ public class LanTcpPluginTest extends BrambleTestCase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testComparatorPrefersNonZeroPorts() {
|
public void testComparatorPrefersNonZeroPorts() throws Exception {
|
||||||
Comparator<InetSocketAddress> comparator = new LanAddressComparator();
|
Comparator<InetSocketAddress> comparator = new LanAddressComparator();
|
||||||
InetSocketAddress nonZero = new InetSocketAddress("1.2.3.4", 1234);
|
InetSocketAddress nonZero = new InetSocketAddress("1.2.3.4", 1234);
|
||||||
InetSocketAddress zero = new InetSocketAddress("1.2.3.4", 0);
|
InetSocketAddress zero = new InetSocketAddress("1.2.3.4", 0);
|
||||||
@@ -289,7 +294,7 @@ public class LanTcpPluginTest extends BrambleTestCase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testComparatorPrefersLongerPrefixes() {
|
public void testComparatorPrefersLongerPrefixes() throws Exception {
|
||||||
Comparator<InetSocketAddress> comparator = new LanAddressComparator();
|
Comparator<InetSocketAddress> comparator = new LanAddressComparator();
|
||||||
InetSocketAddress prefix192 = new InetSocketAddress("192.168.0.1", 0);
|
InetSocketAddress prefix192 = new InetSocketAddress("192.168.0.1", 0);
|
||||||
InetSocketAddress prefix172 = new InetSocketAddress("172.16.0.1", 0);
|
InetSocketAddress prefix172 = new InetSocketAddress("172.16.0.1", 0);
|
||||||
@@ -309,7 +314,7 @@ public class LanTcpPluginTest extends BrambleTestCase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testComparatorPrefersSiteLocalToLinkLocal() {
|
public void testComparatorPrefersSiteLocalToLinkLocal() throws Exception {
|
||||||
Comparator<InetSocketAddress> comparator = new LanAddressComparator();
|
Comparator<InetSocketAddress> comparator = new LanAddressComparator();
|
||||||
InetSocketAddress prefix192 = new InetSocketAddress("192.168.0.1", 0);
|
InetSocketAddress prefix192 = new InetSocketAddress("192.168.0.1", 0);
|
||||||
InetSocketAddress prefix172 = new InetSocketAddress("172.16.0.1", 0);
|
InetSocketAddress prefix172 = new InetSocketAddress("172.16.0.1", 0);
|
||||||
@@ -340,6 +345,8 @@ public class LanTcpPluginTest extends BrambleTestCase {
|
|||||||
@NotNullByDefault
|
@NotNullByDefault
|
||||||
private static class Callback implements DuplexPluginCallback {
|
private static class Callback implements DuplexPluginCallback {
|
||||||
|
|
||||||
|
private final Map<ContactId, TransportProperties> remote =
|
||||||
|
new Hashtable<>();
|
||||||
private final CountDownLatch propertiesLatch = new CountDownLatch(1);
|
private final CountDownLatch propertiesLatch = new CountDownLatch(1);
|
||||||
private final CountDownLatch connectionsLatch = new CountDownLatch(1);
|
private final CountDownLatch connectionsLatch = new CountDownLatch(1);
|
||||||
private final TransportProperties local = new TransportProperties();
|
private final TransportProperties local = new TransportProperties();
|
||||||
@@ -354,6 +361,16 @@ public class LanTcpPluginTest extends BrambleTestCase {
|
|||||||
return local;
|
return local;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Map<ContactId, TransportProperties> getRemoteProperties() {
|
||||||
|
return remote;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public TransportProperties getRemoteProperties(ContactId c) {
|
||||||
|
return remote.get(c);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void mergeSettings(Settings s) {
|
public void mergeSettings(Settings s) {
|
||||||
}
|
}
|
||||||
@@ -364,6 +381,20 @@ public class LanTcpPluginTest extends BrambleTestCase {
|
|||||||
propertiesLatch.countDown();
|
propertiesLatch.countDown();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int showChoice(String[] options, String... message) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean showConfirmationMessage(String... message) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void showMessage(String... message) {
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void incomingConnectionCreated(DuplexTransportConnection d) {
|
public void incomingConnectionCreated(DuplexTransportConnection d) {
|
||||||
connectionsLatch.countDown();
|
connectionsLatch.countDown();
|
||||||
|
|||||||
@@ -7,10 +7,11 @@ import org.briarproject.bramble.api.event.EventBus;
|
|||||||
import org.briarproject.bramble.api.sync.Ack;
|
import org.briarproject.bramble.api.sync.Ack;
|
||||||
import org.briarproject.bramble.api.sync.MessageId;
|
import org.briarproject.bramble.api.sync.MessageId;
|
||||||
import org.briarproject.bramble.api.sync.SyncRecordWriter;
|
import org.briarproject.bramble.api.sync.SyncRecordWriter;
|
||||||
import org.briarproject.bramble.api.transport.StreamWriter;
|
import org.briarproject.bramble.test.BrambleTestCase;
|
||||||
import org.briarproject.bramble.test.BrambleMockTestCase;
|
|
||||||
import org.briarproject.bramble.test.ImmediateExecutor;
|
import org.briarproject.bramble.test.ImmediateExecutor;
|
||||||
|
import org.briarproject.bramble.test.TestUtils;
|
||||||
import org.jmock.Expectations;
|
import org.jmock.Expectations;
|
||||||
|
import org.jmock.Mockery;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
@@ -18,27 +19,33 @@ import java.util.Collections;
|
|||||||
import java.util.concurrent.Executor;
|
import java.util.concurrent.Executor;
|
||||||
|
|
||||||
import static org.briarproject.bramble.api.sync.SyncConstants.MAX_MESSAGE_IDS;
|
import static org.briarproject.bramble.api.sync.SyncConstants.MAX_MESSAGE_IDS;
|
||||||
import static org.briarproject.bramble.test.TestUtils.getRandomId;
|
|
||||||
|
|
||||||
public class SimplexOutgoingSessionTest extends BrambleMockTestCase {
|
public class SimplexOutgoingSessionTest extends BrambleTestCase {
|
||||||
|
|
||||||
private static final int MAX_LATENCY = Integer.MAX_VALUE;
|
private final Mockery context;
|
||||||
|
private final DatabaseComponent db;
|
||||||
|
private final Executor dbExecutor;
|
||||||
|
private final EventBus eventBus;
|
||||||
|
private final ContactId contactId;
|
||||||
|
private final MessageId messageId;
|
||||||
|
private final int maxLatency;
|
||||||
|
private final SyncRecordWriter recordWriter;
|
||||||
|
|
||||||
private final DatabaseComponent db = context.mock(DatabaseComponent.class);
|
public SimplexOutgoingSessionTest() {
|
||||||
private final EventBus eventBus = context.mock(EventBus.class);
|
context = new Mockery();
|
||||||
private final StreamWriter streamWriter = context.mock(StreamWriter.class);
|
db = context.mock(DatabaseComponent.class);
|
||||||
private final SyncRecordWriter recordWriter =
|
dbExecutor = new ImmediateExecutor();
|
||||||
context.mock(SyncRecordWriter.class);
|
eventBus = context.mock(EventBus.class);
|
||||||
|
recordWriter = context.mock(SyncRecordWriter.class);
|
||||||
private final Executor dbExecutor = new ImmediateExecutor();
|
contactId = new ContactId(234);
|
||||||
private final ContactId contactId = new ContactId(234);
|
messageId = new MessageId(TestUtils.getRandomId());
|
||||||
private final MessageId messageId = new MessageId(getRandomId());
|
maxLatency = Integer.MAX_VALUE;
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testNothingToSend() throws Exception {
|
public void testNothingToSend() throws Exception {
|
||||||
SimplexOutgoingSession session = new SimplexOutgoingSession(db,
|
SimplexOutgoingSession session = new SimplexOutgoingSession(db,
|
||||||
dbExecutor, eventBus, contactId, MAX_LATENCY, streamWriter,
|
dbExecutor, eventBus, contactId, maxLatency, recordWriter);
|
||||||
recordWriter);
|
|
||||||
Transaction noAckTxn = new Transaction(null, false);
|
Transaction noAckTxn = new Transaction(null, false);
|
||||||
Transaction noMsgTxn = new Transaction(null, false);
|
Transaction noMsgTxn = new Transaction(null, false);
|
||||||
|
|
||||||
@@ -56,17 +63,19 @@ public class SimplexOutgoingSessionTest extends BrambleMockTestCase {
|
|||||||
oneOf(db).startTransaction(false);
|
oneOf(db).startTransaction(false);
|
||||||
will(returnValue(noMsgTxn));
|
will(returnValue(noMsgTxn));
|
||||||
oneOf(db).generateBatch(with(noMsgTxn), with(contactId),
|
oneOf(db).generateBatch(with(noMsgTxn), with(contactId),
|
||||||
with(any(int.class)), with(MAX_LATENCY));
|
with(any(int.class)), with(maxLatency));
|
||||||
will(returnValue(null));
|
will(returnValue(null));
|
||||||
oneOf(db).commitTransaction(noMsgTxn);
|
oneOf(db).commitTransaction(noMsgTxn);
|
||||||
oneOf(db).endTransaction(noMsgTxn);
|
oneOf(db).endTransaction(noMsgTxn);
|
||||||
// Send the end of stream marker
|
// Flush the output stream
|
||||||
oneOf(streamWriter).sendEndOfStream();
|
oneOf(recordWriter).flush();
|
||||||
// Remove listener
|
// Remove listener
|
||||||
oneOf(eventBus).removeListener(session);
|
oneOf(eventBus).removeListener(session);
|
||||||
}});
|
}});
|
||||||
|
|
||||||
session.run();
|
session.run();
|
||||||
|
|
||||||
|
context.assertIsSatisfied();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -74,8 +83,7 @@ public class SimplexOutgoingSessionTest extends BrambleMockTestCase {
|
|||||||
Ack ack = new Ack(Collections.singletonList(messageId));
|
Ack ack = new Ack(Collections.singletonList(messageId));
|
||||||
byte[] raw = new byte[1234];
|
byte[] raw = new byte[1234];
|
||||||
SimplexOutgoingSession session = new SimplexOutgoingSession(db,
|
SimplexOutgoingSession session = new SimplexOutgoingSession(db,
|
||||||
dbExecutor, eventBus, contactId, MAX_LATENCY, streamWriter,
|
dbExecutor, eventBus, contactId, maxLatency, recordWriter);
|
||||||
recordWriter);
|
|
||||||
Transaction ackTxn = new Transaction(null, false);
|
Transaction ackTxn = new Transaction(null, false);
|
||||||
Transaction noAckTxn = new Transaction(null, false);
|
Transaction noAckTxn = new Transaction(null, false);
|
||||||
Transaction msgTxn = new Transaction(null, false);
|
Transaction msgTxn = new Transaction(null, false);
|
||||||
@@ -96,7 +104,7 @@ public class SimplexOutgoingSessionTest extends BrambleMockTestCase {
|
|||||||
oneOf(db).startTransaction(false);
|
oneOf(db).startTransaction(false);
|
||||||
will(returnValue(msgTxn));
|
will(returnValue(msgTxn));
|
||||||
oneOf(db).generateBatch(with(msgTxn), with(contactId),
|
oneOf(db).generateBatch(with(msgTxn), with(contactId),
|
||||||
with(any(int.class)), with(MAX_LATENCY));
|
with(any(int.class)), with(maxLatency));
|
||||||
will(returnValue(Arrays.asList(raw)));
|
will(returnValue(Arrays.asList(raw)));
|
||||||
oneOf(db).commitTransaction(msgTxn);
|
oneOf(db).commitTransaction(msgTxn);
|
||||||
oneOf(db).endTransaction(msgTxn);
|
oneOf(db).endTransaction(msgTxn);
|
||||||
@@ -112,16 +120,18 @@ public class SimplexOutgoingSessionTest extends BrambleMockTestCase {
|
|||||||
oneOf(db).startTransaction(false);
|
oneOf(db).startTransaction(false);
|
||||||
will(returnValue(noMsgTxn));
|
will(returnValue(noMsgTxn));
|
||||||
oneOf(db).generateBatch(with(noMsgTxn), with(contactId),
|
oneOf(db).generateBatch(with(noMsgTxn), with(contactId),
|
||||||
with(any(int.class)), with(MAX_LATENCY));
|
with(any(int.class)), with(maxLatency));
|
||||||
will(returnValue(null));
|
will(returnValue(null));
|
||||||
oneOf(db).commitTransaction(noMsgTxn);
|
oneOf(db).commitTransaction(noMsgTxn);
|
||||||
oneOf(db).endTransaction(noMsgTxn);
|
oneOf(db).endTransaction(noMsgTxn);
|
||||||
// Send the end of stream marker
|
// Flush the output stream
|
||||||
oneOf(streamWriter).sendEndOfStream();
|
oneOf(recordWriter).flush();
|
||||||
// Remove listener
|
// Remove listener
|
||||||
oneOf(eventBus).removeListener(session);
|
oneOf(eventBus).removeListener(session);
|
||||||
}});
|
}});
|
||||||
|
|
||||||
session.run();
|
session.run();
|
||||||
|
|
||||||
|
context.assertIsSatisfied();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,7 +19,6 @@ import org.briarproject.bramble.api.sync.SyncRecordWriter;
|
|||||||
import org.briarproject.bramble.api.sync.SyncRecordWriterFactory;
|
import org.briarproject.bramble.api.sync.SyncRecordWriterFactory;
|
||||||
import org.briarproject.bramble.api.transport.StreamContext;
|
import org.briarproject.bramble.api.transport.StreamContext;
|
||||||
import org.briarproject.bramble.api.transport.StreamReaderFactory;
|
import org.briarproject.bramble.api.transport.StreamReaderFactory;
|
||||||
import org.briarproject.bramble.api.transport.StreamWriter;
|
|
||||||
import org.briarproject.bramble.api.transport.StreamWriterFactory;
|
import org.briarproject.bramble.api.transport.StreamWriterFactory;
|
||||||
import org.briarproject.bramble.test.BrambleTestCase;
|
import org.briarproject.bramble.test.BrambleTestCase;
|
||||||
import org.briarproject.bramble.test.TestUtils;
|
import org.briarproject.bramble.test.TestUtils;
|
||||||
@@ -28,6 +27,7 @@ import org.junit.Test;
|
|||||||
import java.io.ByteArrayInputStream;
|
import java.io.ByteArrayInputStream;
|
||||||
import java.io.ByteArrayOutputStream;
|
import java.io.ByteArrayOutputStream;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
|
import java.io.OutputStream;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
|
|
||||||
@@ -102,18 +102,18 @@ public class SyncIntegrationTest extends BrambleTestCase {
|
|||||||
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||||
StreamContext ctx = new StreamContext(contactId, transportId, tagKey,
|
StreamContext ctx = new StreamContext(contactId, transportId, tagKey,
|
||||||
headerKey, streamNumber);
|
headerKey, streamNumber);
|
||||||
StreamWriter streamWriter = streamWriterFactory.createStreamWriter(out,
|
OutputStream streamWriter = streamWriterFactory.createStreamWriter(out,
|
||||||
ctx);
|
ctx);
|
||||||
SyncRecordWriter recordWriter = recordWriterFactory.createRecordWriter(
|
SyncRecordWriter recordWriter = recordWriterFactory.createRecordWriter(
|
||||||
streamWriter.getOutputStream());
|
streamWriter);
|
||||||
|
|
||||||
recordWriter.writeAck(new Ack(messageIds));
|
recordWriter.writeAck(new Ack(messageIds));
|
||||||
recordWriter.writeMessage(message.getRaw());
|
recordWriter.writeMessage(message.getRaw());
|
||||||
recordWriter.writeMessage(message1.getRaw());
|
recordWriter.writeMessage(message1.getRaw());
|
||||||
recordWriter.writeOffer(new Offer(messageIds));
|
recordWriter.writeOffer(new Offer(messageIds));
|
||||||
recordWriter.writeRequest(new Request(messageIds));
|
recordWriter.writeRequest(new Request(messageIds));
|
||||||
|
recordWriter.flush();
|
||||||
|
|
||||||
streamWriter.sendEndOfStream();
|
|
||||||
return out.toByteArray();
|
return out.toByteArray();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ public class CaptureArgumentAction<T> implements Action {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Object invoke(Invocation invocation) {
|
public Object invoke(Invocation invocation) throws Throwable {
|
||||||
captured.set(capturedClass.cast(invocation.getParameter(index)));
|
captured.set(capturedClass.cast(invocation.getParameter(index)));
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,31 +9,25 @@ import java.io.File;
|
|||||||
@NotNullByDefault
|
@NotNullByDefault
|
||||||
public class TestDatabaseConfig implements DatabaseConfig {
|
public class TestDatabaseConfig implements DatabaseConfig {
|
||||||
|
|
||||||
private final File dbDir, keyDir;
|
private final File dir;
|
||||||
private final long maxSize;
|
private final long maxSize;
|
||||||
private volatile SecretKey key = new SecretKey(new byte[SecretKey.LENGTH]);
|
private volatile SecretKey key = new SecretKey(new byte[SecretKey.LENGTH]);
|
||||||
|
|
||||||
public TestDatabaseConfig(File testDir, long maxSize) {
|
public TestDatabaseConfig(File dir, long maxSize) {
|
||||||
dbDir = new File(testDir, "db");
|
this.dir = dir;
|
||||||
keyDir = new File(testDir, "key");
|
|
||||||
this.maxSize = maxSize;
|
this.maxSize = maxSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean databaseExists() {
|
public boolean databaseExists() {
|
||||||
if (!dbDir.isDirectory()) return false;
|
if (!dir.isDirectory()) return false;
|
||||||
File[] files = dbDir.listFiles();
|
File[] files = dir.listFiles();
|
||||||
return files != null && files.length > 0;
|
return files != null && files.length > 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public File getDatabaseDirectory() {
|
public File getDatabaseDirectory() {
|
||||||
return dbDir;
|
return dir;
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public File getDatabaseKeyDirectory() {
|
|
||||||
return keyDir;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -9,14 +9,13 @@ import org.briarproject.bramble.api.plugin.simplex.SimplexPluginCallback;
|
|||||||
import org.briarproject.bramble.api.plugin.simplex.SimplexPluginFactory;
|
import org.briarproject.bramble.api.plugin.simplex.SimplexPluginFactory;
|
||||||
|
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
|
import java.util.Collections;
|
||||||
|
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
|
|
||||||
import dagger.Module;
|
import dagger.Module;
|
||||||
import dagger.Provides;
|
import dagger.Provides;
|
||||||
|
|
||||||
import static java.util.Collections.emptyList;
|
|
||||||
import static java.util.Collections.singletonList;
|
|
||||||
import static org.briarproject.bramble.test.TestUtils.getTransportId;
|
import static org.briarproject.bramble.test.TestUtils.getTransportId;
|
||||||
|
|
||||||
@Module
|
@Module
|
||||||
@@ -52,17 +51,12 @@ public class TestPluginConfigModule {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Collection<DuplexPluginFactory> getDuplexFactories() {
|
public Collection<DuplexPluginFactory> getDuplexFactories() {
|
||||||
return emptyList();
|
return Collections.emptyList();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Collection<SimplexPluginFactory> getSimplexFactories() {
|
public Collection<SimplexPluginFactory> getSimplexFactories() {
|
||||||
return singletonList(simplex);
|
return Collections.singletonList(simplex);
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean shouldPoll() {
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
return pluginConfig;
|
return pluginConfig;
|
||||||
|
|||||||
@@ -22,7 +22,6 @@ import org.junit.Test;
|
|||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.Map;
|
|
||||||
import java.util.Random;
|
import java.util.Random;
|
||||||
|
|
||||||
import static java.util.Collections.singletonList;
|
import static java.util.Collections.singletonList;
|
||||||
@@ -55,7 +54,6 @@ public class KeyManagerImplTest extends BrambleMockTestCase {
|
|||||||
new StreamContext(contactId, transportId, getSecretKey(),
|
new StreamContext(contactId, transportId, getSecretKey(),
|
||||||
getSecretKey(), 1);
|
getSecretKey(), 1);
|
||||||
private final byte[] tag = getRandomBytes(TAG_LENGTH);
|
private final byte[] tag = getRandomBytes(TAG_LENGTH);
|
||||||
private final Random random = new Random();
|
|
||||||
|
|
||||||
private final KeyManagerImpl keyManager = new KeyManagerImpl(db, executor,
|
private final KeyManagerImpl keyManager = new KeyManagerImpl(db, executor,
|
||||||
pluginConfig, transportKeyManagerFactory);
|
pluginConfig, transportKeyManagerFactory);
|
||||||
@@ -104,18 +102,30 @@ public class KeyManagerImplTest extends BrambleMockTestCase {
|
|||||||
public void testAddContact() throws Exception {
|
public void testAddContact() throws Exception {
|
||||||
SecretKey secretKey = getSecretKey();
|
SecretKey secretKey = getSecretKey();
|
||||||
long timestamp = System.currentTimeMillis();
|
long timestamp = System.currentTimeMillis();
|
||||||
boolean alice = random.nextBoolean();
|
boolean alice = new Random().nextBoolean();
|
||||||
boolean active = random.nextBoolean();
|
|
||||||
|
|
||||||
context.checking(new Expectations() {{
|
context.checking(new Expectations() {{
|
||||||
oneOf(transportKeyManager).addContact(txn, contactId, secretKey,
|
oneOf(transportKeyManager).addContact(txn, contactId, secretKey,
|
||||||
timestamp, alice, active);
|
timestamp, alice);
|
||||||
|
}});
|
||||||
|
|
||||||
|
keyManager.addContact(txn, contactId, secretKey, timestamp, alice);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testAddUnboundKeys() throws Exception {
|
||||||
|
SecretKey secretKey = getSecretKey();
|
||||||
|
long timestamp = System.currentTimeMillis();
|
||||||
|
boolean alice = new Random().nextBoolean();
|
||||||
|
|
||||||
|
context.checking(new Expectations() {{
|
||||||
|
oneOf(transportKeyManager).addUnboundKeys(txn, secretKey,
|
||||||
|
timestamp, alice);
|
||||||
will(returnValue(keySetId));
|
will(returnValue(keySetId));
|
||||||
}});
|
}});
|
||||||
|
|
||||||
Map<TransportId, KeySetId> ids = keyManager.addContact(txn, contactId,
|
assertEquals(singletonMap(transportId, keySetId),
|
||||||
secretKey, timestamp, alice, active);
|
keyManager.addUnboundKeys(txn, secretKey, timestamp, alice));
|
||||||
assertEquals(singletonMap(transportId, keySetId), ids);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|||||||
@@ -61,6 +61,7 @@ public class TransportKeyManagerImplTest extends BrambleMockTestCase {
|
|||||||
private final ContactId contactId1 = new ContactId(234);
|
private final ContactId contactId1 = new ContactId(234);
|
||||||
private final KeySetId keySetId = new KeySetId(345);
|
private final KeySetId keySetId = new KeySetId(345);
|
||||||
private final KeySetId keySetId1 = new KeySetId(456);
|
private final KeySetId keySetId1 = new KeySetId(456);
|
||||||
|
private final KeySetId keySetId2 = new KeySetId(567);
|
||||||
private final SecretKey tagKey = TestUtils.getSecretKey();
|
private final SecretKey tagKey = TestUtils.getSecretKey();
|
||||||
private final SecretKey headerKey = TestUtils.getSecretKey();
|
private final SecretKey headerKey = TestUtils.getSecretKey();
|
||||||
private final SecretKey masterKey = TestUtils.getSecretKey();
|
private final SecretKey masterKey = TestUtils.getSecretKey();
|
||||||
@@ -70,11 +71,14 @@ public class TransportKeyManagerImplTest extends BrambleMockTestCase {
|
|||||||
public void testKeysAreRotatedAtStartup() throws Exception {
|
public void testKeysAreRotatedAtStartup() throws Exception {
|
||||||
TransportKeys shouldRotate = createTransportKeys(900, 0, true);
|
TransportKeys shouldRotate = createTransportKeys(900, 0, true);
|
||||||
TransportKeys shouldNotRotate = createTransportKeys(1000, 0, true);
|
TransportKeys shouldNotRotate = createTransportKeys(1000, 0, true);
|
||||||
|
TransportKeys shouldRotate1 = createTransportKeys(999, 0, false);
|
||||||
Collection<KeySet> loaded = asList(
|
Collection<KeySet> loaded = asList(
|
||||||
new KeySet(keySetId, contactId, shouldRotate),
|
new KeySet(keySetId, contactId, shouldRotate),
|
||||||
new KeySet(keySetId1, contactId1, shouldNotRotate)
|
new KeySet(keySetId1, contactId1, shouldNotRotate),
|
||||||
|
new KeySet(keySetId2, null, shouldRotate1)
|
||||||
);
|
);
|
||||||
TransportKeys rotated = createTransportKeys(1000, 0, true);
|
TransportKeys rotated = createTransportKeys(1000, 0, true);
|
||||||
|
TransportKeys rotated1 = createTransportKeys(1000, 0, false);
|
||||||
Transaction txn = new Transaction(null, false);
|
Transaction txn = new Transaction(null, false);
|
||||||
|
|
||||||
context.checking(new Expectations() {{
|
context.checking(new Expectations() {{
|
||||||
@@ -89,6 +93,8 @@ public class TransportKeyManagerImplTest extends BrambleMockTestCase {
|
|||||||
will(returnValue(rotated));
|
will(returnValue(rotated));
|
||||||
oneOf(transportCrypto).rotateTransportKeys(shouldNotRotate, 1000);
|
oneOf(transportCrypto).rotateTransportKeys(shouldNotRotate, 1000);
|
||||||
will(returnValue(shouldNotRotate));
|
will(returnValue(shouldNotRotate));
|
||||||
|
oneOf(transportCrypto).rotateTransportKeys(shouldRotate1, 1000);
|
||||||
|
will(returnValue(rotated1));
|
||||||
// Encode the tags (3 sets per contact)
|
// Encode the tags (3 sets per contact)
|
||||||
for (long i = 0; i < REORDERING_WINDOW_SIZE; i++) {
|
for (long i = 0; i < REORDERING_WINDOW_SIZE; i++) {
|
||||||
exactly(6).of(transportCrypto).encodeTag(
|
exactly(6).of(transportCrypto).encodeTag(
|
||||||
@@ -97,8 +103,10 @@ public class TransportKeyManagerImplTest extends BrambleMockTestCase {
|
|||||||
will(new EncodeTagAction());
|
will(new EncodeTagAction());
|
||||||
}
|
}
|
||||||
// Save the keys that were rotated
|
// Save the keys that were rotated
|
||||||
oneOf(db).updateTransportKeys(txn,
|
oneOf(db).updateTransportKeys(txn, asList(
|
||||||
singletonList(new KeySet(keySetId, contactId, rotated)));
|
new KeySet(keySetId, contactId, rotated),
|
||||||
|
new KeySet(keySetId2, null, rotated1))
|
||||||
|
);
|
||||||
// Schedule key rotation at the start of the next rotation period
|
// Schedule key rotation at the start of the next rotation period
|
||||||
oneOf(scheduler).schedule(with(any(Runnable.class)),
|
oneOf(scheduler).schedule(with(any(Runnable.class)),
|
||||||
with(rotationPeriodLength - 1), with(MILLISECONDS));
|
with(rotationPeriodLength - 1), with(MILLISECONDS));
|
||||||
@@ -145,11 +153,43 @@ public class TransportKeyManagerImplTest extends BrambleMockTestCase {
|
|||||||
maxLatency);
|
maxLatency);
|
||||||
// The timestamp is 1 ms before the start of rotation period 1000
|
// The timestamp is 1 ms before the start of rotation period 1000
|
||||||
long timestamp = rotationPeriodLength * 1000 - 1;
|
long timestamp = rotationPeriodLength * 1000 - 1;
|
||||||
assertEquals(keySetId, transportKeyManager.addContact(txn, contactId,
|
transportKeyManager.addContact(txn, contactId, masterKey, timestamp,
|
||||||
masterKey, timestamp, alice, true));
|
alice);
|
||||||
assertTrue(transportKeyManager.canSendOutgoingStreams(contactId));
|
assertTrue(transportKeyManager.canSendOutgoingStreams(contactId));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testKeysAreRotatedWhenAddingUnboundKeys() throws Exception {
|
||||||
|
boolean alice = random.nextBoolean();
|
||||||
|
TransportKeys transportKeys = createTransportKeys(999, 0, false);
|
||||||
|
TransportKeys rotated = createTransportKeys(1000, 0, false);
|
||||||
|
Transaction txn = new Transaction(null, false);
|
||||||
|
|
||||||
|
context.checking(new Expectations() {{
|
||||||
|
oneOf(transportCrypto).deriveTransportKeys(transportId, masterKey,
|
||||||
|
999, alice, false);
|
||||||
|
will(returnValue(transportKeys));
|
||||||
|
// Get the current time (1 ms after start of rotation period 1000)
|
||||||
|
oneOf(clock).currentTimeMillis();
|
||||||
|
will(returnValue(rotationPeriodLength * 1000 + 1));
|
||||||
|
// Rotate the transport keys
|
||||||
|
oneOf(transportCrypto).rotateTransportKeys(transportKeys, 1000);
|
||||||
|
will(returnValue(rotated));
|
||||||
|
// Save the keys
|
||||||
|
oneOf(db).addTransportKeys(txn, null, rotated);
|
||||||
|
will(returnValue(keySetId));
|
||||||
|
}});
|
||||||
|
|
||||||
|
TransportKeyManager transportKeyManager = new TransportKeyManagerImpl(
|
||||||
|
db, transportCrypto, dbExecutor, scheduler, clock, transportId,
|
||||||
|
maxLatency);
|
||||||
|
// The timestamp is 1 ms before the start of rotation period 1000
|
||||||
|
long timestamp = rotationPeriodLength * 1000 - 1;
|
||||||
|
assertEquals(keySetId, transportKeyManager.addUnboundKeys(txn,
|
||||||
|
masterKey, timestamp, alice));
|
||||||
|
assertFalse(transportKeyManager.canSendOutgoingStreams(contactId));
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testOutgoingStreamContextIsNullIfContactIsNotFound()
|
public void testOutgoingStreamContextIsNullIfContactIsNotFound()
|
||||||
throws Exception {
|
throws Exception {
|
||||||
@@ -171,15 +211,15 @@ public class TransportKeyManagerImplTest extends BrambleMockTestCase {
|
|||||||
MAX_32_BIT_UNSIGNED + 1, true);
|
MAX_32_BIT_UNSIGNED + 1, true);
|
||||||
Transaction txn = new Transaction(null, false);
|
Transaction txn = new Transaction(null, false);
|
||||||
|
|
||||||
expectAddContactNoRotation(alice, true, transportKeys, txn);
|
expectAddContactNoRotation(alice, transportKeys, txn);
|
||||||
|
|
||||||
TransportKeyManager transportKeyManager = new TransportKeyManagerImpl(
|
TransportKeyManager transportKeyManager = new TransportKeyManagerImpl(
|
||||||
db, transportCrypto, dbExecutor, scheduler, clock, transportId,
|
db, transportCrypto, dbExecutor, scheduler, clock, transportId,
|
||||||
maxLatency);
|
maxLatency);
|
||||||
// The timestamp is at the start of rotation period 1000
|
// The timestamp is at the start of rotation period 1000
|
||||||
long timestamp = rotationPeriodLength * 1000;
|
long timestamp = rotationPeriodLength * 1000;
|
||||||
assertEquals(keySetId, transportKeyManager.addContact(txn, contactId,
|
transportKeyManager.addContact(txn, contactId, masterKey, timestamp,
|
||||||
masterKey, timestamp, alice, true));
|
alice);
|
||||||
assertFalse(transportKeyManager.canSendOutgoingStreams(contactId));
|
assertFalse(transportKeyManager.canSendOutgoingStreams(contactId));
|
||||||
assertNull(transportKeyManager.getStreamContext(txn, contactId));
|
assertNull(transportKeyManager.getStreamContext(txn, contactId));
|
||||||
}
|
}
|
||||||
@@ -192,7 +232,7 @@ public class TransportKeyManagerImplTest extends BrambleMockTestCase {
|
|||||||
MAX_32_BIT_UNSIGNED, true);
|
MAX_32_BIT_UNSIGNED, true);
|
||||||
Transaction txn = new Transaction(null, false);
|
Transaction txn = new Transaction(null, false);
|
||||||
|
|
||||||
expectAddContactNoRotation(alice, true, transportKeys, txn);
|
expectAddContactNoRotation(alice, transportKeys, txn);
|
||||||
|
|
||||||
context.checking(new Expectations() {{
|
context.checking(new Expectations() {{
|
||||||
// Increment the stream counter
|
// Increment the stream counter
|
||||||
@@ -204,8 +244,8 @@ public class TransportKeyManagerImplTest extends BrambleMockTestCase {
|
|||||||
maxLatency);
|
maxLatency);
|
||||||
// The timestamp is at the start of rotation period 1000
|
// The timestamp is at the start of rotation period 1000
|
||||||
long timestamp = rotationPeriodLength * 1000;
|
long timestamp = rotationPeriodLength * 1000;
|
||||||
assertEquals(keySetId, transportKeyManager.addContact(txn, contactId,
|
transportKeyManager.addContact(txn, contactId, masterKey, timestamp,
|
||||||
masterKey, timestamp, alice, true));
|
alice);
|
||||||
// The first request should return a stream context
|
// The first request should return a stream context
|
||||||
assertTrue(transportKeyManager.canSendOutgoingStreams(contactId));
|
assertTrue(transportKeyManager.canSendOutgoingStreams(contactId));
|
||||||
StreamContext ctx = transportKeyManager.getStreamContext(txn,
|
StreamContext ctx = transportKeyManager.getStreamContext(txn,
|
||||||
@@ -225,21 +265,19 @@ public class TransportKeyManagerImplTest extends BrambleMockTestCase {
|
|||||||
public void testIncomingStreamContextIsNullIfTagIsNotFound()
|
public void testIncomingStreamContextIsNullIfTagIsNotFound()
|
||||||
throws Exception {
|
throws Exception {
|
||||||
boolean alice = random.nextBoolean();
|
boolean alice = random.nextBoolean();
|
||||||
boolean active = random.nextBoolean();
|
TransportKeys transportKeys = createTransportKeys(1000, 0, true);
|
||||||
TransportKeys transportKeys = createTransportKeys(1000, 0, active);
|
|
||||||
Transaction txn = new Transaction(null, false);
|
Transaction txn = new Transaction(null, false);
|
||||||
|
|
||||||
expectAddContactNoRotation(alice, active, transportKeys, txn);
|
expectAddContactNoRotation(alice, transportKeys, txn);
|
||||||
|
|
||||||
TransportKeyManager transportKeyManager = new TransportKeyManagerImpl(
|
TransportKeyManager transportKeyManager = new TransportKeyManagerImpl(
|
||||||
db, transportCrypto, dbExecutor, scheduler, clock, transportId,
|
db, transportCrypto, dbExecutor, scheduler, clock, transportId,
|
||||||
maxLatency);
|
maxLatency);
|
||||||
// The timestamp is at the start of rotation period 1000
|
// The timestamp is at the start of rotation period 1000
|
||||||
long timestamp = rotationPeriodLength * 1000;
|
long timestamp = rotationPeriodLength * 1000;
|
||||||
assertEquals(keySetId, transportKeyManager.addContact(txn, contactId,
|
transportKeyManager.addContact(txn, contactId, masterKey, timestamp,
|
||||||
masterKey, timestamp, alice, active));
|
alice);
|
||||||
assertEquals(active,
|
assertTrue(transportKeyManager.canSendOutgoingStreams(contactId));
|
||||||
transportKeyManager.canSendOutgoingStreams(contactId));
|
|
||||||
// The tag should not be recognised
|
// The tag should not be recognised
|
||||||
assertNull(transportKeyManager.getStreamContext(txn,
|
assertNull(transportKeyManager.getStreamContext(txn,
|
||||||
new byte[TAG_LENGTH]));
|
new byte[TAG_LENGTH]));
|
||||||
@@ -289,8 +327,8 @@ public class TransportKeyManagerImplTest extends BrambleMockTestCase {
|
|||||||
maxLatency);
|
maxLatency);
|
||||||
// The timestamp is at the start of rotation period 1000
|
// The timestamp is at the start of rotation period 1000
|
||||||
long timestamp = rotationPeriodLength * 1000;
|
long timestamp = rotationPeriodLength * 1000;
|
||||||
assertEquals(keySetId, transportKeyManager.addContact(txn, contactId,
|
transportKeyManager.addContact(txn, contactId, masterKey, timestamp,
|
||||||
masterKey, timestamp, alice, true));
|
alice);
|
||||||
assertTrue(transportKeyManager.canSendOutgoingStreams(contactId));
|
assertTrue(transportKeyManager.canSendOutgoingStreams(contactId));
|
||||||
// Use the first tag (previous rotation period, stream number 0)
|
// Use the first tag (previous rotation period, stream number 0)
|
||||||
assertEquals(REORDERING_WINDOW_SIZE * 3, tags.size());
|
assertEquals(REORDERING_WINDOW_SIZE * 3, tags.size());
|
||||||
@@ -377,14 +415,23 @@ public class TransportKeyManagerImplTest extends BrambleMockTestCase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testActivatingKeys() throws Exception {
|
public void testBindingAndActivatingKeys() throws Exception {
|
||||||
boolean alice = random.nextBoolean();
|
boolean alice = random.nextBoolean();
|
||||||
TransportKeys transportKeys = createTransportKeys(1000, 0, false);
|
TransportKeys transportKeys = createTransportKeys(1000, 0, false);
|
||||||
Transaction txn = new Transaction(null, false);
|
Transaction txn = new Transaction(null, false);
|
||||||
|
|
||||||
expectAddContactNoRotation(alice, false, transportKeys, txn);
|
expectAddUnboundKeysNoRotation(alice, transportKeys, txn);
|
||||||
|
|
||||||
context.checking(new Expectations() {{
|
context.checking(new Expectations() {{
|
||||||
|
// When the keys are bound, encode the tags (3 sets)
|
||||||
|
for (long i = 0; i < REORDERING_WINDOW_SIZE; i++) {
|
||||||
|
exactly(3).of(transportCrypto).encodeTag(
|
||||||
|
with(any(byte[].class)), with(tagKey),
|
||||||
|
with(PROTOCOL_VERSION), with(i));
|
||||||
|
will(new EncodeTagAction());
|
||||||
|
}
|
||||||
|
// Save the key binding
|
||||||
|
oneOf(db).bindTransportKeys(txn, contactId, transportId, keySetId);
|
||||||
// Activate the keys
|
// Activate the keys
|
||||||
oneOf(db).setTransportKeysActive(txn, transportId, keySetId);
|
oneOf(db).setTransportKeysActive(txn, transportId, keySetId);
|
||||||
// Increment the stream counter
|
// Increment the stream counter
|
||||||
@@ -396,8 +443,12 @@ public class TransportKeyManagerImplTest extends BrambleMockTestCase {
|
|||||||
maxLatency);
|
maxLatency);
|
||||||
// The timestamp is at the start of rotation period 1000
|
// The timestamp is at the start of rotation period 1000
|
||||||
long timestamp = rotationPeriodLength * 1000;
|
long timestamp = rotationPeriodLength * 1000;
|
||||||
assertEquals(keySetId, transportKeyManager.addContact(txn, contactId,
|
assertEquals(keySetId, transportKeyManager.addUnboundKeys(txn,
|
||||||
masterKey, timestamp, alice, false));
|
masterKey, timestamp, alice));
|
||||||
|
// The keys are unbound so no stream context should be returned
|
||||||
|
assertFalse(transportKeyManager.canSendOutgoingStreams(contactId));
|
||||||
|
assertNull(transportKeyManager.getStreamContext(txn, contactId));
|
||||||
|
transportKeyManager.bindKeys(txn, contactId, keySetId);
|
||||||
// The keys are inactive so no stream context should be returned
|
// The keys are inactive so no stream context should be returned
|
||||||
assertFalse(transportKeyManager.canSendOutgoingStreams(contactId));
|
assertFalse(transportKeyManager.canSendOutgoingStreams(contactId));
|
||||||
assertNull(transportKeyManager.getStreamContext(txn, contactId));
|
assertNull(transportKeyManager.getStreamContext(txn, contactId));
|
||||||
@@ -423,26 +474,18 @@ public class TransportKeyManagerImplTest extends BrambleMockTestCase {
|
|||||||
// Keep a copy of the tags
|
// Keep a copy of the tags
|
||||||
List<byte[]> tags = new ArrayList<>();
|
List<byte[]> tags = new ArrayList<>();
|
||||||
|
|
||||||
|
expectAddUnboundKeysNoRotation(alice, transportKeys, txn);
|
||||||
|
|
||||||
context.checking(new Expectations() {{
|
context.checking(new Expectations() {{
|
||||||
oneOf(transportCrypto).deriveTransportKeys(transportId, masterKey,
|
// When the keys are bound, encode the tags (3 sets)
|
||||||
1000, alice, false);
|
|
||||||
will(returnValue(transportKeys));
|
|
||||||
// Get the current time (the start of rotation period 1000)
|
|
||||||
oneOf(clock).currentTimeMillis();
|
|
||||||
will(returnValue(rotationPeriodLength * 1000));
|
|
||||||
// Encode the tags (3 sets)
|
|
||||||
for (long i = 0; i < REORDERING_WINDOW_SIZE; i++) {
|
for (long i = 0; i < REORDERING_WINDOW_SIZE; i++) {
|
||||||
exactly(3).of(transportCrypto).encodeTag(
|
exactly(3).of(transportCrypto).encodeTag(
|
||||||
with(any(byte[].class)), with(tagKey),
|
with(any(byte[].class)), with(tagKey),
|
||||||
with(PROTOCOL_VERSION), with(i));
|
with(PROTOCOL_VERSION), with(i));
|
||||||
will(new EncodeTagAction(tags));
|
will(new EncodeTagAction(tags));
|
||||||
}
|
}
|
||||||
// Rotate the transport keys (the keys are unaffected)
|
// Save the key binding
|
||||||
oneOf(transportCrypto).rotateTransportKeys(transportKeys, 1000);
|
oneOf(db).bindTransportKeys(txn, contactId, transportId, keySetId);
|
||||||
will(returnValue(transportKeys));
|
|
||||||
// Save the keys
|
|
||||||
oneOf(db).addTransportKeys(txn, contactId, transportKeys);
|
|
||||||
will(returnValue(keySetId));
|
|
||||||
// Encode a new tag after sliding the window
|
// Encode a new tag after sliding the window
|
||||||
oneOf(transportCrypto).encodeTag(with(any(byte[].class)),
|
oneOf(transportCrypto).encodeTag(with(any(byte[].class)),
|
||||||
with(tagKey), with(PROTOCOL_VERSION),
|
with(tagKey), with(PROTOCOL_VERSION),
|
||||||
@@ -462,8 +505,9 @@ public class TransportKeyManagerImplTest extends BrambleMockTestCase {
|
|||||||
maxLatency);
|
maxLatency);
|
||||||
// The timestamp is at the start of rotation period 1000
|
// The timestamp is at the start of rotation period 1000
|
||||||
long timestamp = rotationPeriodLength * 1000;
|
long timestamp = rotationPeriodLength * 1000;
|
||||||
assertEquals(keySetId, transportKeyManager.addContact(txn, contactId,
|
assertEquals(keySetId, transportKeyManager.addUnboundKeys(txn,
|
||||||
masterKey, timestamp, alice, false));
|
masterKey, timestamp, alice));
|
||||||
|
transportKeyManager.bindKeys(txn, contactId, keySetId);
|
||||||
// The keys are inactive so no stream context should be returned
|
// The keys are inactive so no stream context should be returned
|
||||||
assertFalse(transportKeyManager.canSendOutgoingStreams(contactId));
|
assertFalse(transportKeyManager.canSendOutgoingStreams(contactId));
|
||||||
assertNull(transportKeyManager.getStreamContext(txn, contactId));
|
assertNull(transportKeyManager.getStreamContext(txn, contactId));
|
||||||
@@ -488,11 +532,36 @@ public class TransportKeyManagerImplTest extends BrambleMockTestCase {
|
|||||||
assertEquals(0L, ctx.getStreamNumber());
|
assertEquals(0L, ctx.getStreamNumber());
|
||||||
}
|
}
|
||||||
|
|
||||||
private void expectAddContactNoRotation(boolean alice, boolean active,
|
@Test
|
||||||
|
public void testRemovingUnboundKeys() throws Exception {
|
||||||
|
boolean alice = random.nextBoolean();
|
||||||
|
TransportKeys transportKeys = createTransportKeys(1000, 0, false);
|
||||||
|
Transaction txn = new Transaction(null, false);
|
||||||
|
|
||||||
|
expectAddUnboundKeysNoRotation(alice, transportKeys, txn);
|
||||||
|
|
||||||
|
context.checking(new Expectations() {{
|
||||||
|
// Remove the unbound keys
|
||||||
|
oneOf(db).removeTransportKeys(txn, transportId, keySetId);
|
||||||
|
}});
|
||||||
|
|
||||||
|
TransportKeyManager transportKeyManager = new TransportKeyManagerImpl(
|
||||||
|
db, transportCrypto, dbExecutor, scheduler, clock, transportId,
|
||||||
|
maxLatency);
|
||||||
|
// The timestamp is at the start of rotation period 1000
|
||||||
|
long timestamp = rotationPeriodLength * 1000;
|
||||||
|
assertEquals(keySetId, transportKeyManager.addUnboundKeys(txn,
|
||||||
|
masterKey, timestamp, alice));
|
||||||
|
assertFalse(transportKeyManager.canSendOutgoingStreams(contactId));
|
||||||
|
transportKeyManager.removeKeys(txn, keySetId);
|
||||||
|
assertFalse(transportKeyManager.canSendOutgoingStreams(contactId));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void expectAddContactNoRotation(boolean alice,
|
||||||
TransportKeys transportKeys, Transaction txn) throws Exception {
|
TransportKeys transportKeys, Transaction txn) throws Exception {
|
||||||
context.checking(new Expectations() {{
|
context.checking(new Expectations() {{
|
||||||
oneOf(transportCrypto).deriveTransportKeys(transportId, masterKey,
|
oneOf(transportCrypto).deriveTransportKeys(transportId, masterKey,
|
||||||
1000, alice, active);
|
1000, alice, true);
|
||||||
will(returnValue(transportKeys));
|
will(returnValue(transportKeys));
|
||||||
// Get the current time (the start of rotation period 1000)
|
// Get the current time (the start of rotation period 1000)
|
||||||
oneOf(clock).currentTimeMillis();
|
oneOf(clock).currentTimeMillis();
|
||||||
@@ -513,6 +582,24 @@ public class TransportKeyManagerImplTest extends BrambleMockTestCase {
|
|||||||
}});
|
}});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void expectAddUnboundKeysNoRotation(boolean alice,
|
||||||
|
TransportKeys transportKeys, Transaction txn) throws Exception {
|
||||||
|
context.checking(new Expectations() {{
|
||||||
|
oneOf(transportCrypto).deriveTransportKeys(transportId, masterKey,
|
||||||
|
1000, alice, false);
|
||||||
|
will(returnValue(transportKeys));
|
||||||
|
// Get the current time (the start of rotation period 1000)
|
||||||
|
oneOf(clock).currentTimeMillis();
|
||||||
|
will(returnValue(rotationPeriodLength * 1000));
|
||||||
|
// Rotate the transport keys (the keys are unaffected)
|
||||||
|
oneOf(transportCrypto).rotateTransportKeys(transportKeys, 1000);
|
||||||
|
will(returnValue(transportKeys));
|
||||||
|
// Save the unbound keys
|
||||||
|
oneOf(db).addTransportKeys(txn, null, transportKeys);
|
||||||
|
will(returnValue(keySetId));
|
||||||
|
}});
|
||||||
|
}
|
||||||
|
|
||||||
private TransportKeys createTransportKeys(long rotationPeriod,
|
private TransportKeys createTransportKeys(long rotationPeriod,
|
||||||
long streamCounter, boolean active) {
|
long streamCounter, boolean active) {
|
||||||
IncomingKeys inPrev = new IncomingKeys(tagKey, headerKey,
|
IncomingKeys inPrev = new IncomingKeys(tagKey, headerKey,
|
||||||
|
|||||||
BIN
bramble-j2se/libs/jnotify-0.94.jar
Normal file
BIN
bramble-j2se/libs/jnotify-0.94.jar
Normal file
Binary file not shown.
BIN
bramble-j2se/libs/jnotify-x86.dll
Normal file
BIN
bramble-j2se/libs/jnotify-x86.dll
Normal file
Binary file not shown.
BIN
bramble-j2se/libs/jnotify-x86_64.dll
Normal file
BIN
bramble-j2se/libs/jnotify-x86_64.dll
Normal file
Binary file not shown.
BIN
bramble-j2se/libs/libjnotify-amd64.so
Normal file
BIN
bramble-j2se/libs/libjnotify-amd64.so
Normal file
Binary file not shown.
BIN
bramble-j2se/libs/libjnotify-i386.so
Normal file
BIN
bramble-j2se/libs/libjnotify-i386.so
Normal file
Binary file not shown.
BIN
bramble-j2se/libs/libjnotify.dylib
Normal file
BIN
bramble-j2se/libs/libjnotify.dylib
Normal file
Binary file not shown.
@@ -10,20 +10,20 @@ import org.briarproject.bramble.api.plugin.duplex.DuplexPluginFactory;
|
|||||||
import org.briarproject.bramble.api.plugin.simplex.SimplexPluginFactory;
|
import org.briarproject.bramble.api.plugin.simplex.SimplexPluginFactory;
|
||||||
import org.briarproject.bramble.api.reliability.ReliabilityLayerFactory;
|
import org.briarproject.bramble.api.reliability.ReliabilityLayerFactory;
|
||||||
import org.briarproject.bramble.plugin.bluetooth.JavaBluetoothPluginFactory;
|
import org.briarproject.bramble.plugin.bluetooth.JavaBluetoothPluginFactory;
|
||||||
|
import org.briarproject.bramble.plugin.file.RemovableDrivePluginFactory;
|
||||||
import org.briarproject.bramble.plugin.modem.ModemPluginFactory;
|
import org.briarproject.bramble.plugin.modem.ModemPluginFactory;
|
||||||
import org.briarproject.bramble.plugin.tcp.LanTcpPluginFactory;
|
import org.briarproject.bramble.plugin.tcp.LanTcpPluginFactory;
|
||||||
import org.briarproject.bramble.plugin.tcp.WanTcpPluginFactory;
|
import org.briarproject.bramble.plugin.tcp.WanTcpPluginFactory;
|
||||||
|
|
||||||
import java.security.SecureRandom;
|
import java.security.SecureRandom;
|
||||||
|
import java.util.Arrays;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
|
import java.util.Collections;
|
||||||
import java.util.concurrent.Executor;
|
import java.util.concurrent.Executor;
|
||||||
|
|
||||||
import dagger.Module;
|
import dagger.Module;
|
||||||
import dagger.Provides;
|
import dagger.Provides;
|
||||||
|
|
||||||
import static java.util.Arrays.asList;
|
|
||||||
import static java.util.Collections.emptyList;
|
|
||||||
|
|
||||||
@Module
|
@Module
|
||||||
public class DesktopPluginModule extends PluginModule {
|
public class DesktopPluginModule extends PluginModule {
|
||||||
|
|
||||||
@@ -41,8 +41,12 @@ public class DesktopPluginModule extends PluginModule {
|
|||||||
backoffFactory);
|
backoffFactory);
|
||||||
DuplexPluginFactory wan = new WanTcpPluginFactory(ioExecutor,
|
DuplexPluginFactory wan = new WanTcpPluginFactory(ioExecutor,
|
||||||
backoffFactory, shutdownManager);
|
backoffFactory, shutdownManager);
|
||||||
|
SimplexPluginFactory removable =
|
||||||
|
new RemovableDrivePluginFactory(ioExecutor);
|
||||||
|
Collection<SimplexPluginFactory> simplex =
|
||||||
|
Collections.singletonList(removable);
|
||||||
Collection<DuplexPluginFactory> duplex =
|
Collection<DuplexPluginFactory> duplex =
|
||||||
asList(bluetooth, modem, lan, wan);
|
Arrays.asList(bluetooth, modem, lan, wan);
|
||||||
@NotNullByDefault
|
@NotNullByDefault
|
||||||
PluginConfig pluginConfig = new PluginConfig() {
|
PluginConfig pluginConfig = new PluginConfig() {
|
||||||
|
|
||||||
@@ -53,12 +57,7 @@ public class DesktopPluginModule extends PluginModule {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Collection<SimplexPluginFactory> getSimplexFactories() {
|
public Collection<SimplexPluginFactory> getSimplexFactories() {
|
||||||
return emptyList();
|
return simplex;
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean shouldPoll() {
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
return pluginConfig;
|
return pluginConfig;
|
||||||
|
|||||||
@@ -0,0 +1,28 @@
|
|||||||
|
package org.briarproject.bramble.plugin.file;
|
||||||
|
|
||||||
|
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||||
|
|
||||||
|
import javax.annotation.Nullable;
|
||||||
|
|
||||||
|
@NotNullByDefault
|
||||||
|
class LinuxRemovableDriveFinder extends UnixRemovableDriveFinder {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected String getMountCommand() {
|
||||||
|
return "/bin/mount";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Nullable
|
||||||
|
protected String parseMountPoint(String line) {
|
||||||
|
// The format is "/dev/foo on /bar/baz type bam (opt1,opt2)"
|
||||||
|
String pattern = "^/dev/[^ ]+ on (.*) type [^ ]+ \\([^)]+\\)$";
|
||||||
|
String path = line.replaceFirst(pattern, "$1");
|
||||||
|
return path.equals(line) ? null : path;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected boolean isRemovableDriveMountPoint(String path) {
|
||||||
|
return path.startsWith("/mnt/") || path.startsWith("/media/");
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
package org.briarproject.bramble.plugin.file;
|
||||||
|
|
||||||
|
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||||
|
|
||||||
|
@NotNullByDefault
|
||||||
|
class LinuxRemovableDriveMonitor extends UnixRemovableDriveMonitor {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected String[] getPathsToWatch() {
|
||||||
|
return new String[] {"/mnt", "/media"};
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
package org.briarproject.bramble.plugin.file;
|
||||||
|
|
||||||
|
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||||
|
|
||||||
|
import javax.annotation.Nullable;
|
||||||
|
|
||||||
|
@NotNullByDefault
|
||||||
|
class MacRemovableDriveFinder extends UnixRemovableDriveFinder {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected String getMountCommand() {
|
||||||
|
return "/sbin/mount";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Nullable
|
||||||
|
protected String parseMountPoint(String line) {
|
||||||
|
// The format is "/dev/foo on /bar/baz (opt1, opt2)"
|
||||||
|
String pattern = "^/dev/[^ ]+ on (.*) \\([^)]+\\)$";
|
||||||
|
String path = line.replaceFirst(pattern, "$1");
|
||||||
|
return path.equals(line) ? null : path;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected boolean isRemovableDriveMountPoint(String path) {
|
||||||
|
return path.startsWith("/Volumes/");
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
package org.briarproject.bramble.plugin.file;
|
||||||
|
|
||||||
|
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||||
|
|
||||||
|
@NotNullByDefault
|
||||||
|
class MacRemovableDriveMonitor extends UnixRemovableDriveMonitor {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected String[] getPathsToWatch() {
|
||||||
|
return new String[] {"/Volumes"};
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,84 @@
|
|||||||
|
package org.briarproject.bramble.plugin.file;
|
||||||
|
|
||||||
|
import org.briarproject.bramble.api.nullsafety.MethodsNotNullByDefault;
|
||||||
|
import org.briarproject.bramble.api.nullsafety.ParametersNotNullByDefault;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.concurrent.Executor;
|
||||||
|
import java.util.concurrent.locks.Condition;
|
||||||
|
import java.util.concurrent.locks.Lock;
|
||||||
|
import java.util.concurrent.locks.ReentrantLock;
|
||||||
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
|
import static java.util.concurrent.TimeUnit.MILLISECONDS;
|
||||||
|
|
||||||
|
@MethodsNotNullByDefault
|
||||||
|
@ParametersNotNullByDefault
|
||||||
|
class PollingRemovableDriveMonitor implements RemovableDriveMonitor, Runnable {
|
||||||
|
|
||||||
|
private static final Logger LOG =
|
||||||
|
Logger.getLogger(PollingRemovableDriveMonitor.class.getName());
|
||||||
|
|
||||||
|
private final Executor ioExecutor;
|
||||||
|
private final RemovableDriveFinder finder;
|
||||||
|
private final int pollingInterval;
|
||||||
|
|
||||||
|
private final Lock pollingLock = new ReentrantLock();
|
||||||
|
private final Condition stopPolling = pollingLock.newCondition();
|
||||||
|
|
||||||
|
private volatile boolean running = false;
|
||||||
|
private volatile Callback callback = null;
|
||||||
|
|
||||||
|
PollingRemovableDriveMonitor(Executor ioExecutor,
|
||||||
|
RemovableDriveFinder finder, int pollingInterval) {
|
||||||
|
this.ioExecutor = ioExecutor;
|
||||||
|
this.finder = finder;
|
||||||
|
this.pollingInterval = pollingInterval;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void start(Callback callback) throws IOException {
|
||||||
|
this.callback = callback;
|
||||||
|
running = true;
|
||||||
|
ioExecutor.execute(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void stop() throws IOException {
|
||||||
|
running = false;
|
||||||
|
pollingLock.lock();
|
||||||
|
try {
|
||||||
|
stopPolling.signalAll();
|
||||||
|
} finally {
|
||||||
|
pollingLock.unlock();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
try {
|
||||||
|
Collection<File> drives = finder.findRemovableDrives();
|
||||||
|
while (running) {
|
||||||
|
pollingLock.lock();
|
||||||
|
try {
|
||||||
|
stopPolling.await(pollingInterval, MILLISECONDS);
|
||||||
|
} finally {
|
||||||
|
pollingLock.unlock();
|
||||||
|
}
|
||||||
|
if (!running) return;
|
||||||
|
Collection<File> newDrives = finder.findRemovableDrives();
|
||||||
|
for (File f : newDrives) {
|
||||||
|
if (!drives.contains(f)) callback.driveInserted(f);
|
||||||
|
}
|
||||||
|
drives = newDrives;
|
||||||
|
}
|
||||||
|
} catch (InterruptedException e) {
|
||||||
|
LOG.warning("Interrupted while waiting to poll");
|
||||||
|
Thread.currentThread().interrupt();
|
||||||
|
} catch (IOException e) {
|
||||||
|
callback.exceptionThrown(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
package org.briarproject.bramble.plugin.file;
|
||||||
|
|
||||||
|
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.Collection;
|
||||||
|
|
||||||
|
@NotNullByDefault
|
||||||
|
interface RemovableDriveFinder {
|
||||||
|
|
||||||
|
Collection<File> findRemovableDrives() throws IOException;
|
||||||
|
}
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user