mirror of
https://code.briarproject.org/briar/briar.git
synced 2026-02-12 10:49:06 +01:00
Compare commits
204 Commits
831_refact
...
beta-0.16.
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1a83b2c99b | ||
|
|
f641fae1c7 | ||
|
|
deb43d9872 | ||
|
|
cee4e1305e | ||
|
|
a1f989c43c | ||
|
|
b67abadbac | ||
|
|
8c29c85696 | ||
|
|
13d35229d5 | ||
|
|
f0137b41b6 | ||
|
|
b221d21903 | ||
|
|
8bac202626 | ||
|
|
973151c949 | ||
|
|
ed26ab78a5 | ||
|
|
8454b2d235 | ||
|
|
91d0f89f60 | ||
|
|
e074672e86 | ||
|
|
6c1901fe5b | ||
|
|
49052be627 | ||
|
|
5b5b540630 | ||
|
|
9993bac3a1 | ||
|
|
3c95988693 | ||
|
|
fc5c3b470e | ||
|
|
53f05a72ba | ||
|
|
2c10ae7d06 | ||
|
|
6b9010c557 | ||
|
|
1bf0fdfa81 | ||
|
|
237759aac0 | ||
|
|
2a141e0a97 | ||
|
|
d6900be68e | ||
|
|
a35d7c7204 | ||
|
|
86287f9241 | ||
|
|
0b2e3dd96f | ||
|
|
90aa1d1ce7 | ||
|
|
ef2286ab53 | ||
|
|
47b25f3221 | ||
|
|
c30bfa12ce | ||
|
|
d0fc04251d | ||
|
|
dcbb41eb7a | ||
|
|
5c51259269 | ||
|
|
7eefa07052 | ||
|
|
999bdf8866 | ||
|
|
911c0c0fd9 | ||
|
|
99d8cc64a6 | ||
|
|
ba727d7568 | ||
|
|
ed01048f9f | ||
|
|
043ee3c58e | ||
|
|
6e0af7deda | ||
|
|
9591db2097 | ||
|
|
329a4c64f6 | ||
|
|
79015bc5ae | ||
|
|
27422ab9f9 | ||
|
|
abcb682498 | ||
|
|
5044127c46 | ||
|
|
0e4b8ca62e | ||
|
|
822017c69c | ||
|
|
eb6561b93d | ||
|
|
eb9d0c00a8 | ||
|
|
d24b1884a2 | ||
|
|
078534889e | ||
|
|
e92713006a | ||
|
|
18f43f3bc1 | ||
|
|
a4118b40e1 | ||
|
|
de29fbc324 | ||
|
|
3197dcf9b5 | ||
|
|
35aad409fd | ||
|
|
08ce6a7331 | ||
|
|
33a0099065 | ||
|
|
34d20fafda | ||
|
|
aafddcd0f0 | ||
|
|
0d6983b4ef | ||
|
|
69bfb72171 | ||
|
|
1aa33ec9b2 | ||
|
|
6702df1e22 | ||
|
|
c1748c9a86 | ||
|
|
9df624c62a | ||
|
|
0ee6197d7f | ||
|
|
b03a7dce3e | ||
|
|
6c59d7dd5f | ||
|
|
050191f0ef | ||
|
|
4b5a19ce5d | ||
|
|
7c4dd991b9 | ||
|
|
8455569e88 | ||
|
|
d25676559c | ||
|
|
a9437f7985 | ||
|
|
8141a97fc9 | ||
|
|
db842bd7e4 | ||
|
|
6dbec3a864 | ||
|
|
29f658cf4d | ||
|
|
ca83744a84 | ||
|
|
d91a9e2be4 | ||
|
|
8408c3f467 | ||
|
|
544c83a64c | ||
|
|
3800cd5e4f | ||
|
|
259f2cd419 | ||
|
|
20eb022c36 | ||
|
|
531e555b52 | ||
|
|
a9024aa34b | ||
|
|
d4e3b7842c | ||
|
|
167fddfbcc | ||
|
|
a48d642648 | ||
|
|
9a70f054c7 | ||
|
|
ca43d13bd6 | ||
|
|
5b71004179 | ||
|
|
63befccdbf | ||
|
|
4ecf7c02d0 | ||
|
|
f25badc18c | ||
|
|
6e931e9ba5 | ||
|
|
7e749124bf | ||
|
|
5822eb7808 | ||
|
|
7a7e086541 | ||
|
|
abab3167c2 | ||
|
|
8d08570568 | ||
|
|
2007078f13 | ||
|
|
dfb71a7978 | ||
|
|
480b0e3a03 | ||
|
|
8f8751f4ac | ||
|
|
de2ea112ee | ||
|
|
6f99a53fd9 | ||
|
|
a8a9b9032d | ||
|
|
6b15fb89de | ||
|
|
a711d6b8a1 | ||
|
|
5678f8aaa4 | ||
|
|
2fe37f6c26 | ||
|
|
a879747968 | ||
|
|
95e8fd7ee0 | ||
|
|
4416aaaa4c | ||
|
|
500d5f0efe | ||
|
|
fc8978fd90 | ||
|
|
73df126bd4 | ||
|
|
9146488c7d | ||
|
|
613a7fe376 | ||
|
|
ecb62f00d4 | ||
|
|
c4540a03cd | ||
|
|
3e31da99b5 | ||
|
|
098c1d0b1e | ||
|
|
178e908c86 | ||
|
|
ecf7cf14ae | ||
|
|
09e2a15a73 | ||
|
|
ab387860a6 | ||
|
|
f63fc94f2b | ||
|
|
41e5928cca | ||
|
|
8303175494 | ||
|
|
151eb6935b | ||
|
|
6a419c0c7b | ||
|
|
1795b32121 | ||
|
|
01971768ce | ||
|
|
ef7483ab01 | ||
|
|
527d11473d | ||
|
|
775dadc9a0 | ||
|
|
800b10a988 | ||
|
|
c977bf047d | ||
|
|
660a25f21d | ||
|
|
e7fd6d23af | ||
|
|
46982897f0 | ||
|
|
d24de68d64 | ||
|
|
7514c46a3f | ||
|
|
6632c0f8e3 | ||
|
|
79aafcda69 | ||
|
|
05af21e8dc | ||
|
|
0dc62cbbdc | ||
|
|
f3a084cfd2 | ||
|
|
8b32f82566 | ||
|
|
d598b6ed44 | ||
|
|
f5dc6f24b9 | ||
|
|
37454392da | ||
|
|
de7f9111d3 | ||
|
|
96d2889a6c | ||
|
|
f6412d1e9a | ||
|
|
b377cd6b1c | ||
|
|
f6cdbda5bb | ||
|
|
855c600a3e | ||
|
|
ea6e8303b0 | ||
|
|
d4934040d9 | ||
|
|
3449677b24 | ||
|
|
1ad3a6646e | ||
|
|
2d10f6b2bd | ||
|
|
5b05424d83 | ||
|
|
0826022d82 | ||
|
|
a901bfb9cb | ||
|
|
03cdce122a | ||
|
|
f2e0e16969 | ||
|
|
0c441e2ff3 | ||
|
|
21302304a5 | ||
|
|
6839d8b844 | ||
|
|
aee65a716c | ||
|
|
6a07d8f2c9 | ||
|
|
3c1ea81cd0 | ||
|
|
025f417bc7 | ||
|
|
c9dcd906c9 | ||
|
|
7024e04d15 | ||
|
|
0b8ac947db | ||
|
|
948410a064 | ||
|
|
2841339cac | ||
|
|
e8e82bd805 | ||
|
|
6876f40a0e | ||
|
|
5f4e1ecdfd | ||
|
|
044719432a | ||
|
|
d1a929da85 | ||
|
|
2a8978a60d | ||
|
|
c0afad7a26 | ||
|
|
37281c6c23 | ||
|
|
76a5e25656 | ||
|
|
3575b74837 | ||
|
|
f1c7996960 |
19
.gitlab-ci.yml
Normal file
19
.gitlab-ci.yml
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
image: registry.gitlab.com/fdroid/ci-images-base:latest
|
||||||
|
|
||||||
|
cache:
|
||||||
|
paths:
|
||||||
|
- .gradle/wrapper
|
||||||
|
- .gradle/caches
|
||||||
|
|
||||||
|
before_script:
|
||||||
|
- export GRADLE_USER_HOME=$PWD/.gradle
|
||||||
|
- echo y | /opt/android-sdk/tools/bin/sdkmanager "build-tools;23.0.3"
|
||||||
|
|
||||||
|
test:
|
||||||
|
script:
|
||||||
|
- ./gradlew test
|
||||||
|
|
||||||
|
after_script:
|
||||||
|
# this file changes every time but should not be cached
|
||||||
|
- rm -f $GRADLE_USER_HOME/caches/modules-2/modules-2.lock
|
||||||
|
- rm -fr $GRADLE_USER_HOME/caches/*/plugin-resolution/
|
||||||
@@ -12,8 +12,8 @@ android {
|
|||||||
defaultConfig {
|
defaultConfig {
|
||||||
minSdkVersion 14
|
minSdkVersion 14
|
||||||
targetSdkVersion 22
|
targetSdkVersion 22
|
||||||
versionCode 1
|
versionCode 1611
|
||||||
versionName "1.0"
|
versionName "0.16.11"
|
||||||
consumerProguardFiles 'proguard-rules.txt'
|
consumerProguardFiles 'proguard-rules.txt'
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -25,38 +25,38 @@ android {
|
|||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
compile project(':bramble-core')
|
compile project(':bramble-core')
|
||||||
compile fileTree(dir: 'libs', include: ['*.jar'])
|
compile fileTree(dir: 'libs', include: '*.jar')
|
||||||
provided 'javax.annotation:jsr250-api:1.0'
|
provided 'javax.annotation:jsr250-api:1.0'
|
||||||
}
|
}
|
||||||
|
|
||||||
def torBinaryDir = 'src/main/res/raw'
|
def torBinaryDir = 'src/main/res/raw'
|
||||||
|
|
||||||
task downloadTorGeoIp(type: Download) {
|
task downloadTorGeoIp(type: Download) {
|
||||||
src 'https://briarproject.org/build/geoip-2015-12-01.zip'
|
src 'https://briarproject.org/build/geoip-2017-09-06.zip'
|
||||||
dest "$torBinaryDir/geoip.zip"
|
dest "$torBinaryDir/geoip.zip"
|
||||||
onlyIfNewer true
|
onlyIfNewer true
|
||||||
}
|
}
|
||||||
|
|
||||||
task downloadTorBinaryArm(type: Download) {
|
task downloadTorBinaryArm(type: Download) {
|
||||||
src 'https://briarproject.org/build/tor-0.2.7.6-arm.zip'
|
src 'https://briarproject.org/build/tor-0.2.9.12-arm.zip'
|
||||||
dest "$torBinaryDir/tor_arm.zip"
|
dest "$torBinaryDir/tor_arm.zip"
|
||||||
onlyIfNewer true
|
onlyIfNewer true
|
||||||
}
|
}
|
||||||
|
|
||||||
task downloadTorBinaryArmPie(type: Download) {
|
task downloadTorBinaryArmPie(type: Download) {
|
||||||
src 'https://briarproject.org/build/tor-0.2.7.6-arm-pie.zip'
|
src 'https://briarproject.org/build/tor-0.2.9.12-arm-pie.zip'
|
||||||
dest "$torBinaryDir/tor_arm_pie.zip"
|
dest "$torBinaryDir/tor_arm_pie.zip"
|
||||||
onlyIfNewer true
|
onlyIfNewer true
|
||||||
}
|
}
|
||||||
|
|
||||||
task downloadTorBinaryX86(type: Download) {
|
task downloadTorBinaryX86(type: Download) {
|
||||||
src 'https://briarproject.org/build/tor-0.2.7.6-x86.zip'
|
src 'https://briarproject.org/build/tor-0.2.9.12-x86.zip'
|
||||||
dest "$torBinaryDir/tor_x86.zip"
|
dest "$torBinaryDir/tor_x86.zip"
|
||||||
onlyIfNewer true
|
onlyIfNewer true
|
||||||
}
|
}
|
||||||
|
|
||||||
task downloadTorBinaryX86Pie(type: Download) {
|
task downloadTorBinaryX86Pie(type: Download) {
|
||||||
src 'https://briarproject.org/build/tor-0.2.7.6-x86-pie.zip'
|
src 'https://briarproject.org/build/tor-0.2.9.12-x86-pie.zip'
|
||||||
dest "$torBinaryDir/tor_x86_pie.zip"
|
dest "$torBinaryDir/tor_x86_pie.zip"
|
||||||
onlyIfNewer true
|
onlyIfNewer true
|
||||||
}
|
}
|
||||||
@@ -64,31 +64,31 @@ task downloadTorBinaryX86Pie(type: Download) {
|
|||||||
task verifyTorGeoIp(type: Verify, dependsOn: 'downloadTorGeoIp') {
|
task verifyTorGeoIp(type: Verify, dependsOn: 'downloadTorGeoIp') {
|
||||||
src "$torBinaryDir/geoip.zip"
|
src "$torBinaryDir/geoip.zip"
|
||||||
algorithm 'SHA-256'
|
algorithm 'SHA-256'
|
||||||
checksum '9bcdaf0a7ba0933735328d8ec466c25c25dbb459efc2bce9e55c774eabea5162'
|
checksum 'fe49d3adb86d3c512373101422a017dbb86c85a570524663f09dd8ce143a24f3'
|
||||||
}
|
}
|
||||||
|
|
||||||
task verifyTorBinaryArm(type: Verify, dependsOn: 'downloadTorBinaryArm') {
|
task verifyTorBinaryArm(type: Verify, dependsOn: 'downloadTorBinaryArm') {
|
||||||
src "$torBinaryDir/tor_arm.zip"
|
src "$torBinaryDir/tor_arm.zip"
|
||||||
algorithm 'SHA-256'
|
algorithm 'SHA-256'
|
||||||
checksum '83272962eda701cd5d74d2418651c4ff0f0b1dff51f558a292d1a1c42bf12146'
|
checksum '8ed0b347ffed1d6a4d2fd14495118eb92be83e9cc06e057e15220dc288b31688'
|
||||||
}
|
}
|
||||||
|
|
||||||
task verifyTorBinaryArmPie(type: Verify, dependsOn: 'downloadTorBinaryArmPie') {
|
task verifyTorBinaryArmPie(type: Verify, dependsOn: 'downloadTorBinaryArmPie') {
|
||||||
src "$torBinaryDir/tor_arm_pie.zip"
|
src "$torBinaryDir/tor_arm_pie.zip"
|
||||||
algorithm 'SHA-256'
|
algorithm 'SHA-256'
|
||||||
checksum 'd0300d1e45de11ebb24ed62b9c492be9c2e88590b7822195ab38c7a76ffcf646'
|
checksum '64403262511c29f462ca5e7c7621bfc3c944898364d1d5ad35a016bb8a034283'
|
||||||
}
|
}
|
||||||
|
|
||||||
task verifyTorBinaryX86(type: Verify, dependsOn: 'downloadTorBinaryX86') {
|
task verifyTorBinaryX86(type: Verify, dependsOn: 'downloadTorBinaryX86') {
|
||||||
src "$torBinaryDir/tor_x86.zip"
|
src "$torBinaryDir/tor_x86.zip"
|
||||||
algorithm 'SHA-256'
|
algorithm 'SHA-256'
|
||||||
checksum 'b8813d97b01ee1b9c9a4233c1b9bbe9f9f6b494ae6f9cbd84de8a3911911615e'
|
checksum '61e014607a2079bcf1646289c67bff6372b1aded6e1d8d83d7791efda9a4d5ab'
|
||||||
}
|
}
|
||||||
|
|
||||||
task verifyTorBinaryX86Pie(type: Verify, dependsOn: 'downloadTorBinaryX86Pie') {
|
task verifyTorBinaryX86Pie(type: Verify, dependsOn: 'downloadTorBinaryX86Pie') {
|
||||||
src "$torBinaryDir/tor_x86_pie.zip"
|
src "$torBinaryDir/tor_x86_pie.zip"
|
||||||
algorithm 'SHA-256'
|
algorithm 'SHA-256'
|
||||||
checksum '9c66e765aa196dc089951a1b2140cc8290305c2fcbf365121f99e01a233baf4e'
|
checksum '18fbc98356697dd0895836ab46d5c9877d1c539193464f7db1e82a65adaaf288'
|
||||||
}
|
}
|
||||||
|
|
||||||
project.afterEvaluate {
|
project.afterEvaluate {
|
||||||
|
|||||||
Binary file not shown.
@@ -39,7 +39,7 @@ public class AndroidPluginModule {
|
|||||||
EventBus eventBus) {
|
EventBus eventBus) {
|
||||||
Context appContext = app.getApplicationContext();
|
Context appContext = app.getApplicationContext();
|
||||||
DuplexPluginFactory bluetooth = new DroidtoothPluginFactory(ioExecutor,
|
DuplexPluginFactory bluetooth = new DroidtoothPluginFactory(ioExecutor,
|
||||||
androidExecutor, appContext, random, backoffFactory);
|
androidExecutor, appContext, random, eventBus, backoffFactory);
|
||||||
DuplexPluginFactory tor = new TorPluginFactory(ioExecutor, appContext,
|
DuplexPluginFactory tor = new TorPluginFactory(ioExecutor, appContext,
|
||||||
locationUtils, reporter, eventBus, torSocketFactory,
|
locationUtils, reporter, eventBus, torSocketFactory,
|
||||||
backoffFactory);
|
backoffFactory);
|
||||||
|
|||||||
@@ -11,8 +11,9 @@ import android.content.IntentFilter;
|
|||||||
|
|
||||||
import org.briarproject.bramble.api.FormatException;
|
import org.briarproject.bramble.api.FormatException;
|
||||||
import org.briarproject.bramble.api.contact.ContactId;
|
import org.briarproject.bramble.api.contact.ContactId;
|
||||||
import org.briarproject.bramble.api.crypto.PseudoRandom;
|
|
||||||
import org.briarproject.bramble.api.data.BdfList;
|
import org.briarproject.bramble.api.data.BdfList;
|
||||||
|
import org.briarproject.bramble.api.event.Event;
|
||||||
|
import org.briarproject.bramble.api.event.EventListener;
|
||||||
import org.briarproject.bramble.api.keyagreement.KeyAgreementConnection;
|
import org.briarproject.bramble.api.keyagreement.KeyAgreementConnection;
|
||||||
import org.briarproject.bramble.api.keyagreement.KeyAgreementListener;
|
import org.briarproject.bramble.api.keyagreement.KeyAgreementListener;
|
||||||
import org.briarproject.bramble.api.nullsafety.MethodsNotNullByDefault;
|
import org.briarproject.bramble.api.nullsafety.MethodsNotNullByDefault;
|
||||||
@@ -23,6 +24,8 @@ 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.DuplexTransportConnection;
|
import org.briarproject.bramble.api.plugin.duplex.DuplexTransportConnection;
|
||||||
|
import org.briarproject.bramble.api.plugin.event.DisableBluetoothEvent;
|
||||||
|
import org.briarproject.bramble.api.plugin.event.EnableBluetoothEvent;
|
||||||
import org.briarproject.bramble.api.properties.TransportProperties;
|
import org.briarproject.bramble.api.properties.TransportProperties;
|
||||||
import org.briarproject.bramble.api.system.AndroidExecutor;
|
import org.briarproject.bramble.api.system.AndroidExecutor;
|
||||||
import org.briarproject.bramble.util.AndroidUtils;
|
import org.briarproject.bramble.util.AndroidUtils;
|
||||||
@@ -30,23 +33,14 @@ import org.briarproject.bramble.util.StringUtils;
|
|||||||
|
|
||||||
import java.io.Closeable;
|
import java.io.Closeable;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
|
||||||
import java.security.SecureRandom;
|
import java.security.SecureRandom;
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Map.Entry;
|
import java.util.Map.Entry;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
import java.util.concurrent.Callable;
|
import java.util.concurrent.Callable;
|
||||||
import java.util.concurrent.CompletionService;
|
|
||||||
import java.util.concurrent.CopyOnWriteArrayList;
|
|
||||||
import java.util.concurrent.CountDownLatch;
|
|
||||||
import java.util.concurrent.ExecutionException;
|
import java.util.concurrent.ExecutionException;
|
||||||
import java.util.concurrent.Executor;
|
import java.util.concurrent.Executor;
|
||||||
import java.util.concurrent.ExecutorCompletionService;
|
|
||||||
import java.util.concurrent.Future;
|
|
||||||
import java.util.concurrent.atomic.AtomicBoolean;
|
import java.util.concurrent.atomic.AtomicBoolean;
|
||||||
import java.util.logging.Logger;
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
@@ -61,8 +55,6 @@ import static android.bluetooth.BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERA
|
|||||||
import static android.bluetooth.BluetoothAdapter.SCAN_MODE_NONE;
|
import static android.bluetooth.BluetoothAdapter.SCAN_MODE_NONE;
|
||||||
import static android.bluetooth.BluetoothAdapter.STATE_OFF;
|
import static android.bluetooth.BluetoothAdapter.STATE_OFF;
|
||||||
import static android.bluetooth.BluetoothAdapter.STATE_ON;
|
import static android.bluetooth.BluetoothAdapter.STATE_ON;
|
||||||
import static android.bluetooth.BluetoothDevice.EXTRA_DEVICE;
|
|
||||||
import static java.util.concurrent.TimeUnit.MILLISECONDS;
|
|
||||||
import static java.util.logging.Level.INFO;
|
import static java.util.logging.Level.INFO;
|
||||||
import static java.util.logging.Level.WARNING;
|
import static java.util.logging.Level.WARNING;
|
||||||
import static org.briarproject.bramble.api.keyagreement.KeyAgreementConstants.TRANSPORT_ID_BLUETOOTH;
|
import static org.briarproject.bramble.api.keyagreement.KeyAgreementConstants.TRANSPORT_ID_BLUETOOTH;
|
||||||
@@ -75,14 +67,10 @@ import static org.briarproject.bramble.util.PrivacyUtils.scrubMacAddress;
|
|||||||
|
|
||||||
@MethodsNotNullByDefault
|
@MethodsNotNullByDefault
|
||||||
@ParametersNotNullByDefault
|
@ParametersNotNullByDefault
|
||||||
class DroidtoothPlugin implements DuplexPlugin {
|
class DroidtoothPlugin implements DuplexPlugin, EventListener {
|
||||||
|
|
||||||
private static final Logger LOG =
|
private static final Logger LOG =
|
||||||
Logger.getLogger(DroidtoothPlugin.class.getName());
|
Logger.getLogger(DroidtoothPlugin.class.getName());
|
||||||
private static final String FOUND =
|
|
||||||
"android.bluetooth.device.action.FOUND";
|
|
||||||
private static final String DISCOVERY_FINISHED =
|
|
||||||
"android.bluetooth.adapter.action.DISCOVERY_FINISHED";
|
|
||||||
|
|
||||||
private final Executor ioExecutor;
|
private final Executor ioExecutor;
|
||||||
private final AndroidExecutor androidExecutor;
|
private final AndroidExecutor androidExecutor;
|
||||||
@@ -166,9 +154,7 @@ class DroidtoothPlugin implements DuplexPlugin {
|
|||||||
} else {
|
} else {
|
||||||
// Enable Bluetooth if settings allow
|
// Enable Bluetooth if settings allow
|
||||||
if (callback.getSettings().getBoolean(PREF_BT_ENABLE, false)) {
|
if (callback.getSettings().getBoolean(PREF_BT_ENABLE, false)) {
|
||||||
wasEnabledByUs = true;
|
enableAdapter();
|
||||||
if (adapter.enable()) LOG.info("Enabling Bluetooth");
|
|
||||||
else LOG.info("Could not enable Bluetooth");
|
|
||||||
} else {
|
} else {
|
||||||
LOG.info("Not enabling Bluetooth");
|
LOG.info("Not enabling Bluetooth");
|
||||||
}
|
}
|
||||||
@@ -259,13 +245,27 @@ class DroidtoothPlugin implements DuplexPlugin {
|
|||||||
return new DroidtoothTransportConnection(this, s);
|
return new DroidtoothTransportConnection(this, s);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void enableAdapter() {
|
||||||
|
if (adapter != null && !adapter.isEnabled()) {
|
||||||
|
if (adapter.enable()) {
|
||||||
|
LOG.info("Enabling Bluetooth");
|
||||||
|
wasEnabledByUs = true;
|
||||||
|
} else {
|
||||||
|
LOG.info("Could not enable Bluetooth");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void stop() {
|
public void stop() {
|
||||||
running = false;
|
running = false;
|
||||||
if (receiver != null) appContext.unregisterReceiver(receiver);
|
if (receiver != null) appContext.unregisterReceiver(receiver);
|
||||||
tryToClose(socket);
|
tryToClose(socket);
|
||||||
// Disable Bluetooth if we enabled it and it's still enabled
|
disableAdapter();
|
||||||
if (wasEnabledByUs && adapter.isEnabled()) {
|
}
|
||||||
|
|
||||||
|
private void disableAdapter() {
|
||||||
|
if (adapter != null && adapter.isEnabled() && wasEnabledByUs) {
|
||||||
if (adapter.disable()) LOG.info("Disabling Bluetooth");
|
if (adapter.disable()) LOG.info("Disabling Bluetooth");
|
||||||
else LOG.info("Could not disable Bluetooth");
|
else LOG.info("Could not disable Bluetooth");
|
||||||
}
|
}
|
||||||
@@ -363,8 +363,7 @@ class DroidtoothPlugin implements DuplexPlugin {
|
|||||||
@Override
|
@Override
|
||||||
public DuplexTransportConnection createConnection(ContactId c) {
|
public DuplexTransportConnection createConnection(ContactId c) {
|
||||||
if (!isRunning()) return null;
|
if (!isRunning()) return null;
|
||||||
TransportProperties p = callback.getRemoteProperties().get(c);
|
TransportProperties p = callback.getRemoteProperties(c);
|
||||||
if (p == null) return null;
|
|
||||||
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);
|
||||||
@@ -374,90 +373,6 @@ class DroidtoothPlugin implements DuplexPlugin {
|
|||||||
return new DroidtoothTransportConnection(this, s);
|
return new DroidtoothTransportConnection(this, s);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean supportsInvitations() {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public DuplexTransportConnection createInvitationConnection(PseudoRandom r,
|
|
||||||
long timeout, boolean alice) {
|
|
||||||
if (!isRunning()) return null;
|
|
||||||
// Use the invitation codes to generate the UUID
|
|
||||||
byte[] b = r.nextBytes(UUID_BYTES);
|
|
||||||
UUID uuid = UUID.nameUUIDFromBytes(b);
|
|
||||||
if (LOG.isLoggable(INFO)) LOG.info("Invitation UUID " + uuid);
|
|
||||||
// Bind a server socket for receiving invitation connections
|
|
||||||
BluetoothServerSocket ss;
|
|
||||||
try {
|
|
||||||
ss = adapter.listenUsingInsecureRfcommWithServiceRecord(
|
|
||||||
"RFCOMM", uuid);
|
|
||||||
} catch (IOException e) {
|
|
||||||
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
// Create the background tasks
|
|
||||||
CompletionService<BluetoothSocket> complete =
|
|
||||||
new ExecutorCompletionService<>(ioExecutor);
|
|
||||||
List<Future<BluetoothSocket>> futures = new ArrayList<>();
|
|
||||||
if (alice) {
|
|
||||||
// Return the first connected socket
|
|
||||||
futures.add(complete.submit(new ListeningTask(ss)));
|
|
||||||
futures.add(complete.submit(new DiscoveryTask(uuid.toString())));
|
|
||||||
} else {
|
|
||||||
// Return the first socket with readable data
|
|
||||||
futures.add(complete.submit(new ReadableTask(
|
|
||||||
new ListeningTask(ss))));
|
|
||||||
futures.add(complete.submit(new ReadableTask(
|
|
||||||
new DiscoveryTask(uuid.toString()))));
|
|
||||||
}
|
|
||||||
BluetoothSocket chosen = null;
|
|
||||||
try {
|
|
||||||
Future<BluetoothSocket> f = complete.poll(timeout, MILLISECONDS);
|
|
||||||
if (f == null) return null; // No task completed within the timeout
|
|
||||||
chosen = f.get();
|
|
||||||
return new DroidtoothTransportConnection(this, chosen);
|
|
||||||
} catch (InterruptedException e) {
|
|
||||||
LOG.info("Interrupted while exchanging invitations");
|
|
||||||
Thread.currentThread().interrupt();
|
|
||||||
return null;
|
|
||||||
} catch (ExecutionException e) {
|
|
||||||
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
|
||||||
return null;
|
|
||||||
} finally {
|
|
||||||
// Closing the socket will terminate the listener task
|
|
||||||
tryToClose(ss);
|
|
||||||
closeSockets(futures, chosen);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void closeSockets(final List<Future<BluetoothSocket>> futures,
|
|
||||||
@Nullable final BluetoothSocket chosen) {
|
|
||||||
ioExecutor.execute(new Runnable() {
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
for (Future<BluetoothSocket> f : futures) {
|
|
||||||
try {
|
|
||||||
if (f.cancel(true)) {
|
|
||||||
LOG.info("Cancelled task");
|
|
||||||
} else {
|
|
||||||
BluetoothSocket s = f.get();
|
|
||||||
if (s != null && s != chosen) {
|
|
||||||
LOG.info("Closing unwanted socket");
|
|
||||||
s.close();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (InterruptedException e) {
|
|
||||||
LOG.info("Interrupted while closing sockets");
|
|
||||||
return;
|
|
||||||
} catch (ExecutionException | IOException e) {
|
|
||||||
if (LOG.isLoggable(INFO)) LOG.info(e.toString());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean supportsKeyAgreement() {
|
public boolean supportsKeyAgreement() {
|
||||||
return true;
|
return true;
|
||||||
@@ -472,7 +387,7 @@ class DroidtoothPlugin implements DuplexPlugin {
|
|||||||
// No truncation necessary because COMMIT_LENGTH = 16
|
// No truncation necessary because COMMIT_LENGTH = 16
|
||||||
UUID uuid = UUID.nameUUIDFromBytes(commitment);
|
UUID uuid = UUID.nameUUIDFromBytes(commitment);
|
||||||
if (LOG.isLoggable(INFO)) LOG.info("Key agreement UUID " + uuid);
|
if (LOG.isLoggable(INFO)) LOG.info("Key agreement UUID " + uuid);
|
||||||
// Bind a server socket for receiving invitation connections
|
// Bind a server socket for receiving key agreement connections
|
||||||
BluetoothServerSocket ss;
|
BluetoothServerSocket ss;
|
||||||
try {
|
try {
|
||||||
ss = adapter.listenUsingInsecureRfcommWithServiceRecord(
|
ss = adapter.listenUsingInsecureRfcommWithServiceRecord(
|
||||||
@@ -513,6 +428,33 @@ class DroidtoothPlugin implements DuplexPlugin {
|
|||||||
return StringUtils.macToString(mac);
|
return StringUtils.macToString(mac);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void eventOccurred(Event e) {
|
||||||
|
if (e instanceof EnableBluetoothEvent) {
|
||||||
|
enableAdapterAsync();
|
||||||
|
} else if (e instanceof DisableBluetoothEvent) {
|
||||||
|
disableAdapterAsync();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void enableAdapterAsync() {
|
||||||
|
ioExecutor.execute(new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
enableAdapter();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private void disableAdapterAsync() {
|
||||||
|
ioExecutor.execute(new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
disableAdapter();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
private class BluetoothStateReceiver extends BroadcastReceiver {
|
private class BluetoothStateReceiver extends BroadcastReceiver {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -536,115 +478,6 @@ class DroidtoothPlugin implements DuplexPlugin {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private class DiscoveryTask implements Callable<BluetoothSocket> {
|
|
||||||
|
|
||||||
private final String uuid;
|
|
||||||
|
|
||||||
private DiscoveryTask(String uuid) {
|
|
||||||
this.uuid = uuid;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public BluetoothSocket call() throws Exception {
|
|
||||||
// Repeat discovery until we connect or get interrupted
|
|
||||||
while (true) {
|
|
||||||
// Discover nearby devices
|
|
||||||
LOG.info("Discovering nearby devices");
|
|
||||||
List<String> addresses = discoverDevices();
|
|
||||||
if (addresses.isEmpty()) {
|
|
||||||
LOG.info("No devices discovered");
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
// Connect to any device with the right UUID
|
|
||||||
for (String address : addresses) {
|
|
||||||
BluetoothSocket s = connect(address, uuid);
|
|
||||||
if (s != null) {
|
|
||||||
LOG.info("Outgoing connection");
|
|
||||||
return s;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private List<String> discoverDevices() throws InterruptedException {
|
|
||||||
IntentFilter filter = new IntentFilter();
|
|
||||||
filter.addAction(FOUND);
|
|
||||||
filter.addAction(DISCOVERY_FINISHED);
|
|
||||||
DiscoveryReceiver disco = new DiscoveryReceiver();
|
|
||||||
appContext.registerReceiver(disco, filter);
|
|
||||||
LOG.info("Starting discovery");
|
|
||||||
adapter.startDiscovery();
|
|
||||||
return disco.waitForAddresses();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static class DiscoveryReceiver extends BroadcastReceiver {
|
|
||||||
|
|
||||||
private final CountDownLatch finished = new CountDownLatch(1);
|
|
||||||
private final List<String> addresses = new CopyOnWriteArrayList<>();
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onReceive(Context ctx, Intent intent) {
|
|
||||||
String action = intent.getAction();
|
|
||||||
if (action.equals(DISCOVERY_FINISHED)) {
|
|
||||||
LOG.info("Discovery finished");
|
|
||||||
ctx.unregisterReceiver(this);
|
|
||||||
finished.countDown();
|
|
||||||
} else if (action.equals(FOUND)) {
|
|
||||||
BluetoothDevice d = intent.getParcelableExtra(EXTRA_DEVICE);
|
|
||||||
if (LOG.isLoggable(INFO)) {
|
|
||||||
LOG.info("Discovered device: " +
|
|
||||||
scrubMacAddress(d.getAddress()));
|
|
||||||
}
|
|
||||||
addresses.add(d.getAddress());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private List<String> waitForAddresses() throws InterruptedException {
|
|
||||||
finished.await();
|
|
||||||
List<String> shuffled = new ArrayList<>(addresses);
|
|
||||||
Collections.shuffle(shuffled);
|
|
||||||
return shuffled;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static class ListeningTask implements Callable<BluetoothSocket> {
|
|
||||||
|
|
||||||
private final BluetoothServerSocket serverSocket;
|
|
||||||
|
|
||||||
private ListeningTask(BluetoothServerSocket serverSocket) {
|
|
||||||
this.serverSocket = serverSocket;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public BluetoothSocket call() throws IOException {
|
|
||||||
BluetoothSocket s = serverSocket.accept();
|
|
||||||
LOG.info("Incoming connection");
|
|
||||||
return s;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static class ReadableTask implements Callable<BluetoothSocket> {
|
|
||||||
|
|
||||||
private final Callable<BluetoothSocket> connectionTask;
|
|
||||||
|
|
||||||
private ReadableTask(Callable<BluetoothSocket> connectionTask) {
|
|
||||||
this.connectionTask = connectionTask;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public BluetoothSocket call() throws Exception {
|
|
||||||
BluetoothSocket s = connectionTask.call();
|
|
||||||
InputStream in = s.getInputStream();
|
|
||||||
while (in.available() == 0) {
|
|
||||||
LOG.info("Waiting for data");
|
|
||||||
Thread.sleep(1000);
|
|
||||||
}
|
|
||||||
LOG.info("Data available");
|
|
||||||
return s;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private class BluetoothKeyAgreementListener extends KeyAgreementListener {
|
private class BluetoothKeyAgreementListener extends KeyAgreementListener {
|
||||||
|
|
||||||
private final BluetoothServerSocket ss;
|
private final BluetoothServerSocket ss;
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ package org.briarproject.bramble.plugin.droidtooth;
|
|||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
|
|
||||||
|
import org.briarproject.bramble.api.event.EventBus;
|
||||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||||
import org.briarproject.bramble.api.plugin.Backoff;
|
import org.briarproject.bramble.api.plugin.Backoff;
|
||||||
import org.briarproject.bramble.api.plugin.BackoffFactory;
|
import org.briarproject.bramble.api.plugin.BackoffFactory;
|
||||||
@@ -31,15 +32,18 @@ public class DroidtoothPluginFactory implements DuplexPluginFactory {
|
|||||||
private final AndroidExecutor androidExecutor;
|
private final AndroidExecutor androidExecutor;
|
||||||
private final Context appContext;
|
private final Context appContext;
|
||||||
private final SecureRandom secureRandom;
|
private final SecureRandom secureRandom;
|
||||||
|
private final EventBus eventBus;
|
||||||
private final BackoffFactory backoffFactory;
|
private final BackoffFactory backoffFactory;
|
||||||
|
|
||||||
public DroidtoothPluginFactory(Executor ioExecutor,
|
public DroidtoothPluginFactory(Executor ioExecutor,
|
||||||
AndroidExecutor androidExecutor, Context appContext,
|
AndroidExecutor androidExecutor, Context appContext,
|
||||||
SecureRandom secureRandom, BackoffFactory backoffFactory) {
|
SecureRandom secureRandom, EventBus eventBus,
|
||||||
|
BackoffFactory backoffFactory) {
|
||||||
this.ioExecutor = ioExecutor;
|
this.ioExecutor = ioExecutor;
|
||||||
this.androidExecutor = androidExecutor;
|
this.androidExecutor = androidExecutor;
|
||||||
this.appContext = appContext;
|
this.appContext = appContext;
|
||||||
this.secureRandom = secureRandom;
|
this.secureRandom = secureRandom;
|
||||||
|
this.eventBus = eventBus;
|
||||||
this.backoffFactory = backoffFactory;
|
this.backoffFactory = backoffFactory;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -57,7 +61,10 @@ public class DroidtoothPluginFactory implements DuplexPluginFactory {
|
|||||||
public DuplexPlugin createPlugin(DuplexPluginCallback callback) {
|
public DuplexPlugin createPlugin(DuplexPluginCallback callback) {
|
||||||
Backoff backoff = backoffFactory.createBackoff(MIN_POLLING_INTERVAL,
|
Backoff backoff = backoffFactory.createBackoff(MIN_POLLING_INTERVAL,
|
||||||
MAX_POLLING_INTERVAL, BACKOFF_BASE);
|
MAX_POLLING_INTERVAL, BACKOFF_BASE);
|
||||||
return new DroidtoothPlugin(ioExecutor, androidExecutor, appContext,
|
DroidtoothPlugin plugin = new DroidtoothPlugin(ioExecutor,
|
||||||
secureRandom, backoff, callback, MAX_LATENCY);
|
androidExecutor, appContext, secureRandom, backoff, callback,
|
||||||
|
MAX_LATENCY);
|
||||||
|
eventBus.addListener(plugin);
|
||||||
|
return plugin;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,7 +17,6 @@ import net.freehaven.tor.control.EventHandler;
|
|||||||
import net.freehaven.tor.control.TorControlConnection;
|
import net.freehaven.tor.control.TorControlConnection;
|
||||||
|
|
||||||
import org.briarproject.bramble.api.contact.ContactId;
|
import org.briarproject.bramble.api.contact.ContactId;
|
||||||
import org.briarproject.bramble.api.crypto.PseudoRandom;
|
|
||||||
import org.briarproject.bramble.api.data.BdfList;
|
import org.briarproject.bramble.api.data.BdfList;
|
||||||
import org.briarproject.bramble.api.event.Event;
|
import org.briarproject.bramble.api.event.Event;
|
||||||
import org.briarproject.bramble.api.event.EventListener;
|
import org.briarproject.bramble.api.event.EventListener;
|
||||||
@@ -56,6 +55,7 @@ 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;
|
||||||
|
import java.util.Map.Entry;
|
||||||
import java.util.Scanner;
|
import java.util.Scanner;
|
||||||
import java.util.concurrent.CountDownLatch;
|
import java.util.concurrent.CountDownLatch;
|
||||||
import java.util.concurrent.Executor;
|
import java.util.concurrent.Executor;
|
||||||
@@ -85,13 +85,13 @@ import static org.briarproject.bramble.api.plugin.TorConstants.PREF_TOR_NETWORK_
|
|||||||
import static org.briarproject.bramble.api.plugin.TorConstants.PREF_TOR_NETWORK_NEVER;
|
import static org.briarproject.bramble.api.plugin.TorConstants.PREF_TOR_NETWORK_NEVER;
|
||||||
import static org.briarproject.bramble.api.plugin.TorConstants.PREF_TOR_NETWORK_WIFI;
|
import static org.briarproject.bramble.api.plugin.TorConstants.PREF_TOR_NETWORK_WIFI;
|
||||||
import static org.briarproject.bramble.api.plugin.TorConstants.PREF_TOR_PORT;
|
import static org.briarproject.bramble.api.plugin.TorConstants.PREF_TOR_PORT;
|
||||||
|
import static org.briarproject.bramble.api.plugin.TorConstants.PROP_ONION;
|
||||||
import static org.briarproject.bramble.util.PrivacyUtils.scrubOnion;
|
import static org.briarproject.bramble.util.PrivacyUtils.scrubOnion;
|
||||||
|
|
||||||
@MethodsNotNullByDefault
|
@MethodsNotNullByDefault
|
||||||
@ParametersNotNullByDefault
|
@ParametersNotNullByDefault
|
||||||
class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
|
class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
|
||||||
|
|
||||||
private static final String PROP_ONION = "onion";
|
|
||||||
private static final String[] EVENTS = {
|
private static final String[] EVENTS = {
|
||||||
"CIRC", "ORCONN", "HS_DESC", "NOTICE", "WARN", "ERR"
|
"CIRC", "ORCONN", "HS_DESC", "NOTICE", "WARN", "ERR"
|
||||||
};
|
};
|
||||||
@@ -539,16 +539,21 @@ class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
|
|||||||
public void poll(Collection<ContactId> connected) {
|
public void poll(Collection<ContactId> connected) {
|
||||||
if (!isRunning()) return;
|
if (!isRunning()) return;
|
||||||
backoff.increment();
|
backoff.increment();
|
||||||
// TODO: Pass properties to connectAndCallBack()
|
Map<ContactId, TransportProperties> remote =
|
||||||
for (ContactId c : callback.getRemoteProperties().keySet())
|
callback.getRemoteProperties();
|
||||||
if (!connected.contains(c)) connectAndCallBack(c);
|
for (Entry<ContactId, TransportProperties> e : remote.entrySet()) {
|
||||||
|
ContactId c = e.getKey();
|
||||||
|
if (!connected.contains(c)) connectAndCallBack(c, e.getValue());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void connectAndCallBack(final ContactId c) {
|
private void connectAndCallBack(final ContactId c,
|
||||||
|
final TransportProperties p) {
|
||||||
ioExecutor.execute(new Runnable() {
|
ioExecutor.execute(new Runnable() {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
DuplexTransportConnection d = createConnection(c);
|
if (!isRunning()) return;
|
||||||
|
DuplexTransportConnection d = createConnection(p);
|
||||||
if (d != null) {
|
if (d != null) {
|
||||||
backoff.reset();
|
backoff.reset();
|
||||||
callback.outgoingConnectionCreated(c, d);
|
callback.outgoingConnectionCreated(c, d);
|
||||||
@@ -560,8 +565,11 @@ class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
|
|||||||
@Override
|
@Override
|
||||||
public DuplexTransportConnection createConnection(ContactId c) {
|
public DuplexTransportConnection createConnection(ContactId c) {
|
||||||
if (!isRunning()) return null;
|
if (!isRunning()) return null;
|
||||||
TransportProperties p = callback.getRemoteProperties().get(c);
|
return createConnection(callback.getRemoteProperties(c));
|
||||||
if (p == null) return null;
|
}
|
||||||
|
|
||||||
|
@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()) {
|
||||||
@@ -589,17 +597,6 @@ class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean supportsInvitations() {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public DuplexTransportConnection createInvitationConnection(PseudoRandom r,
|
|
||||||
long timeout, boolean alice) {
|
|
||||||
throw new UnsupportedOperationException();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean supportsKeyAgreement() {
|
public boolean supportsKeyAgreement() {
|
||||||
return false;
|
return false;
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ package org.briarproject.bramble.plugin.tor;
|
|||||||
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.duplex.AbstractDuplexTransportConnection;
|
import org.briarproject.bramble.api.plugin.duplex.AbstractDuplexTransportConnection;
|
||||||
|
import org.briarproject.bramble.util.IoUtils;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
@@ -21,12 +22,12 @@ class TorTransportConnection extends AbstractDuplexTransportConnection {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected InputStream getInputStream() throws IOException {
|
protected InputStream getInputStream() throws IOException {
|
||||||
return socket.getInputStream();
|
return IoUtils.getInputStream(socket);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected OutputStream getOutputStream() throws IOException {
|
protected OutputStream getOutputStream() throws IOException {
|
||||||
return socket.getOutputStream();
|
return IoUtils.getOutputStream(socket);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -7,12 +7,12 @@ apply plugin: 'witness'
|
|||||||
dependencies {
|
dependencies {
|
||||||
compile "com.google.dagger:dagger:2.0.2"
|
compile "com.google.dagger:dagger:2.0.2"
|
||||||
compile 'com.google.dagger:dagger-compiler:2.0.2'
|
compile 'com.google.dagger:dagger-compiler:2.0.2'
|
||||||
compile 'com.google.code.findbugs:jsr305:3.0.1'
|
compile 'com.google.code.findbugs:jsr305:3.0.2'
|
||||||
|
|
||||||
testCompile 'junit:junit:4.12'
|
testCompile 'junit:junit:4.12'
|
||||||
testCompile "org.jmock:jmock:2.8.1"
|
testCompile "org.jmock:jmock:2.8.2"
|
||||||
testCompile "org.jmock:jmock-junit4:2.8.1"
|
testCompile "org.jmock:jmock-junit4:2.8.2"
|
||||||
testCompile "org.jmock:jmock-legacy:2.8.1"
|
testCompile "org.jmock:jmock-legacy:2.8.2"
|
||||||
testCompile "org.hamcrest:hamcrest-library:1.3"
|
testCompile "org.hamcrest:hamcrest-library:1.3"
|
||||||
testCompile "org.hamcrest:hamcrest-core:1.3"
|
testCompile "org.hamcrest:hamcrest-core:1.3"
|
||||||
}
|
}
|
||||||
@@ -21,7 +21,7 @@ dependencyVerification {
|
|||||||
verify = [
|
verify = [
|
||||||
'com.google.dagger:dagger:84c0282ed8be73a29e0475d639da030b55dee72369e58dd35ae7d4fe6243dcf9',
|
'com.google.dagger:dagger:84c0282ed8be73a29e0475d639da030b55dee72369e58dd35ae7d4fe6243dcf9',
|
||||||
'com.google.dagger:dagger-compiler:b74bc9de063dd4c6400b232231f2ef5056145b8fbecbf5382012007dd1c071b3',
|
'com.google.dagger:dagger-compiler:b74bc9de063dd4c6400b232231f2ef5056145b8fbecbf5382012007dd1c071b3',
|
||||||
'com.google.code.findbugs:jsr305:c885ce34249682bc0236b4a7d56efcc12048e6135a5baf7a9cde8ad8cda13fcd',
|
'com.google.code.findbugs:jsr305:766ad2a0783f2687962c8ad74ceecc38a28b9f72a2d085ee438b7813e928d0c7',
|
||||||
'javax.inject:javax.inject:91c77044a50c481636c32d916fd89c9118a72195390452c81065080f957de7ff',
|
'javax.inject:javax.inject:91c77044a50c481636c32d916fd89c9118a72195390452c81065080f957de7ff',
|
||||||
'com.google.dagger:dagger-producers:99ec15e8a0507ba569e7655bc1165ee5e5ca5aa914b3c8f7e2c2458f724edd6b',
|
'com.google.dagger:dagger-producers:99ec15e8a0507ba569e7655bc1165ee5e5ca5aa914b3c8f7e2c2458f724edd6b',
|
||||||
'com.google.guava:guava:d664fbfc03d2e5ce9cab2a44fb01f1d0bf9dfebeccc1a473b1f9ea31f79f6f99',
|
'com.google.guava:guava:d664fbfc03d2e5ce9cab2a44fb01f1d0bf9dfebeccc1a473b1f9ea31f79f6f99',
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package org.briarproject.bramble.api;
|
package org.briarproject.bramble.api;
|
||||||
|
|
||||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||||
|
import org.briarproject.bramble.util.StringUtils;
|
||||||
|
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Comparator;
|
import java.util.Comparator;
|
||||||
@@ -53,6 +54,12 @@ public class Bytes implements Comparable<Bytes> {
|
|||||||
return aBytes.length - bBytes.length;
|
return aBytes.length - bBytes.length;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return getClass().getSimpleName() +
|
||||||
|
"(" + StringUtils.toHexString(getBytes()) + ")";
|
||||||
|
}
|
||||||
|
|
||||||
public static class BytesComparator implements Comparator<Bytes> {
|
public static class BytesComparator implements Comparator<Bytes> {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -10,8 +10,6 @@ public interface CryptoComponent {
|
|||||||
|
|
||||||
SecretKey generateSecretKey();
|
SecretKey generateSecretKey();
|
||||||
|
|
||||||
PseudoRandom getPseudoRandom(int seed1, int seed2);
|
|
||||||
|
|
||||||
SecureRandom getSecureRandom();
|
SecureRandom getSecureRandom();
|
||||||
|
|
||||||
KeyPair generateAgreementKeyPair();
|
KeyPair generateAgreementKeyPair();
|
||||||
@@ -24,15 +22,6 @@ public interface CryptoComponent {
|
|||||||
|
|
||||||
KeyParser getMessageKeyParser();
|
KeyParser getMessageKeyParser();
|
||||||
|
|
||||||
/** Generates a random invitation code. */
|
|
||||||
int generateBTInvitationCode();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Derives a confirmation code from the given master secret.
|
|
||||||
* @param alice whether the code is for use by Alice or Bob.
|
|
||||||
*/
|
|
||||||
int deriveBTConfirmationCode(SecretKey master, boolean alice);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Derives a stream header key from the given master secret.
|
* Derives a stream header key from the given master secret.
|
||||||
* @param alice whether the key is for use by Alice or Bob.
|
* @param alice whether the key is for use by Alice or Bob.
|
||||||
@@ -137,7 +126,8 @@ public interface CryptoComponent {
|
|||||||
TransportKeys rotateTransportKeys(TransportKeys k, long rotationPeriod);
|
TransportKeys rotateTransportKeys(TransportKeys k, long rotationPeriod);
|
||||||
|
|
||||||
/** Encodes the pseudo-random tag that is used to recognise a stream. */
|
/** Encodes the pseudo-random tag that is used to recognise a stream. */
|
||||||
void encodeTag(byte[] tag, SecretKey tagKey, long streamNumber);
|
void encodeTag(byte[] tag, SecretKey tagKey, int protocolVersion,
|
||||||
|
long streamNumber);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Signs the given byte[] with the given PrivateKey.
|
* Signs the given byte[] with the given PrivateKey.
|
||||||
|
|||||||
@@ -1,12 +0,0 @@
|
|||||||
package org.briarproject.bramble.api.crypto;
|
|
||||||
|
|
||||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A deterministic pseudo-random number generator.
|
|
||||||
*/
|
|
||||||
@NotNullByDefault
|
|
||||||
public interface PseudoRandom {
|
|
||||||
|
|
||||||
byte[] nextBytes(int bytes);
|
|
||||||
}
|
|
||||||
@@ -14,8 +14,9 @@ public interface StreamDecrypterFactory {
|
|||||||
StreamDecrypter createStreamDecrypter(InputStream in, StreamContext ctx);
|
StreamDecrypter createStreamDecrypter(InputStream in, StreamContext ctx);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a {@link StreamDecrypter} for decrypting an invitation stream.
|
* Creates a {@link StreamDecrypter} for decrypting a contact exchange
|
||||||
|
* stream.
|
||||||
*/
|
*/
|
||||||
StreamDecrypter createInvitationStreamDecrypter(InputStream in,
|
StreamDecrypter createContactExchangeStreamDecrypter(InputStream in,
|
||||||
SecretKey headerKey);
|
SecretKey headerKey);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,8 +14,9 @@ public interface StreamEncrypterFactory {
|
|||||||
StreamEncrypter createStreamEncrypter(OutputStream out, StreamContext ctx);
|
StreamEncrypter createStreamEncrypter(OutputStream out, StreamContext ctx);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a {@link StreamEncrypter} for encrypting an invitation stream.
|
* Creates a {@link StreamEncrypter} for encrypting a contact exchange
|
||||||
|
* stream.
|
||||||
*/
|
*/
|
||||||
StreamEncrypter createInvitationStreamEncrypter(OutputStream out,
|
StreamEncrypter createContactExchangeStreamDecrypter(OutputStream out,
|
||||||
SecretKey headerKey);
|
SecretKey headerKey);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,20 +0,0 @@
|
|||||||
package org.briarproject.bramble.api.invitation;
|
|
||||||
|
|
||||||
public interface InvitationConstants {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The connection timeout in milliseconds.
|
|
||||||
*/
|
|
||||||
long CONNECTION_TIMEOUT = 60 * 1000;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The confirmation timeout in milliseconds.
|
|
||||||
*/
|
|
||||||
long CONFIRMATION_TIMEOUT = 60 * 1000;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The number of bits in an invitation or confirmation code. Codes must fit
|
|
||||||
* into six decimal digits.
|
|
||||||
*/
|
|
||||||
int CODE_BITS = 19;
|
|
||||||
}
|
|
||||||
@@ -1,47 +0,0 @@
|
|||||||
package org.briarproject.bramble.api.invitation;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* An interface for receiving updates about the state of an
|
|
||||||
* {@link InvitationTask}.
|
|
||||||
*/
|
|
||||||
public interface InvitationListener {
|
|
||||||
|
|
||||||
/** Called if a connection to the remote peer is established. */
|
|
||||||
void connectionSucceeded();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Called if a connection to the remote peer cannot be established. This
|
|
||||||
* indicates that the protocol has ended unsuccessfully.
|
|
||||||
*/
|
|
||||||
void connectionFailed();
|
|
||||||
|
|
||||||
/** Called if key agreement with the remote peer succeeds. */
|
|
||||||
void keyAgreementSucceeded(int localCode, int remoteCode);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Called if key agreement with the remote peer fails or the connection is
|
|
||||||
* lost. This indicates that the protocol has ended unsuccessfully.
|
|
||||||
*/
|
|
||||||
void keyAgreementFailed();
|
|
||||||
|
|
||||||
/** Called if the remote peer's confirmation check succeeds. */
|
|
||||||
void remoteConfirmationSucceeded();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Called if remote peer's confirmation check fails or the connection is
|
|
||||||
* lost. This indicates that the protocol has ended unsuccessfully.
|
|
||||||
*/
|
|
||||||
void remoteConfirmationFailed();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Called if the exchange of pseudonyms succeeds. This indicates that the
|
|
||||||
* protocol has ended successfully.
|
|
||||||
*/
|
|
||||||
void pseudonymExchangeSucceeded(String remoteName);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Called if the exchange of pseudonyms fails or the connection is lost.
|
|
||||||
* This indicates that the protocol has ended unsuccessfully.
|
|
||||||
*/
|
|
||||||
void pseudonymExchangeFailed();
|
|
||||||
}
|
|
||||||
@@ -1,85 +0,0 @@
|
|||||||
package org.briarproject.bramble.api.invitation;
|
|
||||||
|
|
||||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
|
||||||
|
|
||||||
import javax.annotation.Nullable;
|
|
||||||
import javax.annotation.concurrent.Immutable;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A snapshot of the state of an {@link InvitationTask}.
|
|
||||||
*/
|
|
||||||
@Immutable
|
|
||||||
@NotNullByDefault
|
|
||||||
public class InvitationState {
|
|
||||||
|
|
||||||
private final int localInvitationCode, remoteInvitationCode;
|
|
||||||
private final int localConfirmationCode, remoteConfirmationCode;
|
|
||||||
private final boolean connected, connectionFailed;
|
|
||||||
private final boolean localCompared, remoteCompared;
|
|
||||||
private final boolean localMatched, remoteMatched;
|
|
||||||
@Nullable
|
|
||||||
private final String contactName;
|
|
||||||
|
|
||||||
public InvitationState(int localInvitationCode, int remoteInvitationCode,
|
|
||||||
int localConfirmationCode, int remoteConfirmationCode,
|
|
||||||
boolean connected, boolean connectionFailed, boolean localCompared,
|
|
||||||
boolean remoteCompared, boolean localMatched,
|
|
||||||
boolean remoteMatched, @Nullable String contactName) {
|
|
||||||
this.localInvitationCode = localInvitationCode;
|
|
||||||
this.remoteInvitationCode = remoteInvitationCode;
|
|
||||||
this.localConfirmationCode = localConfirmationCode;
|
|
||||||
this.remoteConfirmationCode = remoteConfirmationCode;
|
|
||||||
this.connected = connected;
|
|
||||||
this.connectionFailed = connectionFailed;
|
|
||||||
this.localCompared = localCompared;
|
|
||||||
this.remoteCompared = remoteCompared;
|
|
||||||
this.localMatched = localMatched;
|
|
||||||
this.remoteMatched = remoteMatched;
|
|
||||||
this.contactName = contactName;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getLocalInvitationCode() {
|
|
||||||
return localInvitationCode;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getRemoteInvitationCode() {
|
|
||||||
return remoteInvitationCode;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getLocalConfirmationCode() {
|
|
||||||
return localConfirmationCode;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getRemoteConfirmationCode() {
|
|
||||||
return remoteConfirmationCode;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean getConnected() {
|
|
||||||
return connected;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean getConnectionFailed() {
|
|
||||||
return connectionFailed;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean getLocalCompared() {
|
|
||||||
return localCompared;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean getRemoteCompared() {
|
|
||||||
return remoteCompared;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean getLocalMatched() {
|
|
||||||
return localMatched;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean getRemoteMatched() {
|
|
||||||
return remoteMatched;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Nullable
|
|
||||||
public String getContactName() {
|
|
||||||
return contactName;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,38 +0,0 @@
|
|||||||
package org.briarproject.bramble.api.invitation;
|
|
||||||
|
|
||||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A task for exchanging invitations with a remote peer.
|
|
||||||
*/
|
|
||||||
@NotNullByDefault
|
|
||||||
public interface InvitationTask {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Adds a listener to be informed of state changes and returns the
|
|
||||||
* task's current state.
|
|
||||||
*/
|
|
||||||
InvitationState addListener(InvitationListener l);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Removes the given listener.
|
|
||||||
*/
|
|
||||||
void removeListener(InvitationListener l);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Asynchronously starts the connection process.
|
|
||||||
*/
|
|
||||||
void connect();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Asynchronously informs the remote peer that the local peer's
|
|
||||||
* confirmation codes matched.
|
|
||||||
*/
|
|
||||||
void localConfirmationSucceeded();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Asynchronously informs the remote peer that the local peer's
|
|
||||||
* confirmation codes did not match.
|
|
||||||
*/
|
|
||||||
void localConfirmationFailed();
|
|
||||||
}
|
|
||||||
@@ -1,15 +0,0 @@
|
|||||||
package org.briarproject.bramble.api.invitation;
|
|
||||||
|
|
||||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates tasks for exchanging invitations with remote peers.
|
|
||||||
*/
|
|
||||||
@NotNullByDefault
|
|
||||||
public interface InvitationTaskFactory {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates a task using the given local and remote invitation codes.
|
|
||||||
*/
|
|
||||||
InvitationTask createTask(int localCode, int remoteCode);
|
|
||||||
}
|
|
||||||
@@ -4,5 +4,10 @@ public interface LanTcpConstants {
|
|||||||
|
|
||||||
TransportId ID = new TransportId("org.briarproject.bramble.lan");
|
TransportId ID = new TransportId("org.briarproject.bramble.lan");
|
||||||
|
|
||||||
|
// a transport property (shared with contacts)
|
||||||
|
String PROP_IP_PORTS = "ipPorts";
|
||||||
|
|
||||||
|
// a local setting
|
||||||
String PREF_LAN_IP_PORTS = "ipPorts";
|
String PREF_LAN_IP_PORTS = "ipPorts";
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -29,6 +29,11 @@ public interface PluginCallback {
|
|||||||
*/
|
*/
|
||||||
Map<ContactId, TransportProperties> getRemoteProperties();
|
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
|
* Merges the given settings with the namespaced settings
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -32,11 +32,6 @@ public interface PluginManager {
|
|||||||
*/
|
*/
|
||||||
Collection<DuplexPlugin> getDuplexPlugins();
|
Collection<DuplexPlugin> getDuplexPlugins();
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns any duplex plugins that support invitations.
|
|
||||||
*/
|
|
||||||
Collection<DuplexPlugin> getInvitationPlugins();
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns any duplex plugins that support key agreement.
|
* Returns any duplex plugins that support key agreement.
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -4,6 +4,8 @@ public interface TorConstants {
|
|||||||
|
|
||||||
TransportId ID = new TransportId("org.briarproject.bramble.tor");
|
TransportId ID = new TransportId("org.briarproject.bramble.tor");
|
||||||
|
|
||||||
|
String PROP_ONION = "onion";
|
||||||
|
|
||||||
int SOCKS_PORT = 59050;
|
int SOCKS_PORT = 59050;
|
||||||
int CONTROL_PORT = 59051;
|
int CONTROL_PORT = 59051;
|
||||||
|
|
||||||
@@ -16,4 +18,5 @@ public interface TorConstants {
|
|||||||
int PREF_TOR_NETWORK_NEVER = 0;
|
int PREF_TOR_NETWORK_NEVER = 0;
|
||||||
int PREF_TOR_NETWORK_WIFI = 1;
|
int PREF_TOR_NETWORK_WIFI = 1;
|
||||||
int PREF_TOR_NETWORK_ALWAYS = 2;
|
int PREF_TOR_NETWORK_ALWAYS = 2;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
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.contact.ContactId;
|
||||||
import org.briarproject.bramble.api.crypto.PseudoRandom;
|
|
||||||
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;
|
||||||
@@ -23,20 +22,6 @@ public interface DuplexPlugin extends Plugin {
|
|||||||
@Nullable
|
@Nullable
|
||||||
DuplexTransportConnection createConnection(ContactId c);
|
DuplexTransportConnection createConnection(ContactId c);
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns true if the plugin supports exchanging invitations.
|
|
||||||
*/
|
|
||||||
boolean supportsInvitations();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Attempts to create and return an invitation connection to the remote
|
|
||||||
* peer. Returns null if no connection can be established within the given
|
|
||||||
* time.
|
|
||||||
*/
|
|
||||||
@Nullable
|
|
||||||
DuplexTransportConnection createInvitationConnection(PseudoRandom r,
|
|
||||||
long timeout, boolean alice);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns true if the plugin supports short-range key agreement.
|
* Returns true if the plugin supports short-range key agreement.
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -0,0 +1,15 @@
|
|||||||
|
package org.briarproject.bramble.api.plugin.event;
|
||||||
|
|
||||||
|
import org.briarproject.bramble.api.event.Event;
|
||||||
|
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||||
|
|
||||||
|
import javax.annotation.concurrent.Immutable;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An event that asks the Bluetooth plugin to disable the Bluetooth adapter if
|
||||||
|
* we previously enabled it.
|
||||||
|
*/
|
||||||
|
@Immutable
|
||||||
|
@NotNullByDefault
|
||||||
|
public class DisableBluetoothEvent extends Event {
|
||||||
|
}
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
package org.briarproject.bramble.api.plugin.event;
|
||||||
|
|
||||||
|
import org.briarproject.bramble.api.event.Event;
|
||||||
|
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||||
|
|
||||||
|
import javax.annotation.concurrent.Immutable;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An event asks the Bluetooth plugin to enable the Bluetooth adapter.
|
||||||
|
*/
|
||||||
|
@Immutable
|
||||||
|
@NotNullByDefault
|
||||||
|
public class EnableBluetoothEvent extends Event {
|
||||||
|
}
|
||||||
@@ -49,6 +49,13 @@ public interface TransportPropertyManager {
|
|||||||
Map<ContactId, TransportProperties> getRemoteProperties(TransportId t)
|
Map<ContactId, TransportProperties> getRemoteProperties(TransportId t)
|
||||||
throws DbException;
|
throws DbException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the remote transport properties for the given contact and
|
||||||
|
* transport.
|
||||||
|
*/
|
||||||
|
TransportProperties getRemoteProperties(ContactId c, TransportId t)
|
||||||
|
throws DbException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Merges the given properties with the existing local properties for the
|
* Merges the given properties with the existing local properties for the
|
||||||
* given transport.
|
* given transport.
|
||||||
|
|||||||
@@ -15,9 +15,9 @@ public interface StreamReaderFactory {
|
|||||||
InputStream createStreamReader(InputStream in, StreamContext ctx);
|
InputStream createStreamReader(InputStream in, StreamContext ctx);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates an {@link InputStream InputStream} for reading from an
|
* Creates an {@link InputStream InputStream} for reading from a contact
|
||||||
* invitation stream.
|
* exchangestream.
|
||||||
*/
|
*/
|
||||||
InputStream createInvitationStreamReader(InputStream in,
|
InputStream createContactExchangeStreamReader(InputStream in,
|
||||||
SecretKey headerKey);
|
SecretKey headerKey);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,9 +15,9 @@ public interface StreamWriterFactory {
|
|||||||
OutputStream createStreamWriter(OutputStream out, StreamContext ctx);
|
OutputStream createStreamWriter(OutputStream out, StreamContext ctx);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates an {@link OutputStream OutputStream} for writing to an
|
* Creates an {@link OutputStream OutputStream} for writing to a contact
|
||||||
* invitation stream.
|
* exchange stream.
|
||||||
*/
|
*/
|
||||||
OutputStream createInvitationStreamWriter(OutputStream out,
|
OutputStream createContactExchangeStreamWriter(OutputStream out,
|
||||||
SecretKey headerKey);
|
SecretKey headerKey);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,6 +4,11 @@ import org.briarproject.bramble.api.crypto.SecretKey;
|
|||||||
|
|
||||||
public interface TransportConstants {
|
public interface TransportConstants {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The current version of the transport protocol.
|
||||||
|
*/
|
||||||
|
int PROTOCOL_VERSION = 3;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The length of the pseudo-random tag in bytes.
|
* The length of the pseudo-random tag in bytes.
|
||||||
*/
|
*/
|
||||||
@@ -14,21 +19,22 @@ public interface TransportConstants {
|
|||||||
*/
|
*/
|
||||||
int STREAM_HEADER_NONCE_LENGTH = 24;
|
int STREAM_HEADER_NONCE_LENGTH = 24;
|
||||||
|
|
||||||
/**
|
|
||||||
* The length of the stream header initialisation vector (IV) in bytes.
|
|
||||||
*/
|
|
||||||
int STREAM_HEADER_IV_LENGTH = STREAM_HEADER_NONCE_LENGTH - 8;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The length of the message authentication code (MAC) in bytes.
|
* The length of the message authentication code (MAC) in bytes.
|
||||||
*/
|
*/
|
||||||
int MAC_LENGTH = 16;
|
int MAC_LENGTH = 16;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The length of the stream header plaintext in bytes. The stream header
|
||||||
|
* contains the protocol version, stream number and frame key.
|
||||||
|
*/
|
||||||
|
int STREAM_HEADER_PLAINTEXT_LENGTH = 2 + 8 + SecretKey.LENGTH;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The length of the stream header in bytes.
|
* The length of the stream header in bytes.
|
||||||
*/
|
*/
|
||||||
int STREAM_HEADER_LENGTH = STREAM_HEADER_IV_LENGTH + SecretKey.LENGTH
|
int STREAM_HEADER_LENGTH = STREAM_HEADER_NONCE_LENGTH
|
||||||
+ MAC_LENGTH;
|
+ STREAM_HEADER_PLAINTEXT_LENGTH + MAC_LENGTH;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The length of the frame nonce in bytes.
|
* The length of the frame nonce in bytes.
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ import java.io.File;
|
|||||||
import java.io.IOException;
|
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 javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
|
|
||||||
@@ -59,4 +60,24 @@ public class IoUtils {
|
|||||||
offset += read;
|
offset += read;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Workaround for a bug in Android 7, see
|
||||||
|
// https://android-review.googlesource.com/#/c/271775/
|
||||||
|
public static InputStream getInputStream(Socket s) throws IOException {
|
||||||
|
try {
|
||||||
|
return s.getInputStream();
|
||||||
|
} catch (NullPointerException e) {
|
||||||
|
throw new IOException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Workaround for a bug in Android 7, see
|
||||||
|
// https://android-review.googlesource.com/#/c/271775/
|
||||||
|
public static OutputStream getOutputStream(Socket s) throws IOException {
|
||||||
|
try {
|
||||||
|
return s.getOutputStream();
|
||||||
|
} catch (NullPointerException e) {
|
||||||
|
throw new IOException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ public class PrivacyUtils {
|
|||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
public static String scrubMacAddress(@Nullable String address) {
|
public static String scrubMacAddress(@Nullable String address) {
|
||||||
if (address == null) return null;
|
if (address == null || address.length() == 0) return null;
|
||||||
// this is a fake address we need to know about
|
// this is a fake address we need to know about
|
||||||
if (address.equals("02:00:00:00:00:00")) return address;
|
if (address.equals("02:00:00:00:00:00")) return address;
|
||||||
// keep first and last octet of MAC address
|
// keep first and last octet of MAC address
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ import java.nio.charset.CharacterCodingException;
|
|||||||
import java.nio.charset.Charset;
|
import java.nio.charset.Charset;
|
||||||
import java.nio.charset.CharsetDecoder;
|
import java.nio.charset.CharsetDecoder;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
|
import java.util.Random;
|
||||||
import java.util.regex.Pattern;
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
@@ -27,6 +28,7 @@ public class StringUtils {
|
|||||||
'0', '1', '2', '3', '4', '5', '6', '7',
|
'0', '1', '2', '3', '4', '5', '6', '7',
|
||||||
'8', '9', 'A', 'B', 'C', 'D', 'E', 'F'
|
'8', '9', 'A', 'B', 'C', 'D', 'E', 'F'
|
||||||
};
|
};
|
||||||
|
private static final Random random = new Random();
|
||||||
|
|
||||||
public static boolean isNullOrEmpty(@Nullable String s) {
|
public static boolean isNullOrEmpty(@Nullable String s) {
|
||||||
return s == null || s.length() == 0;
|
return s == null || s.length() == 0;
|
||||||
@@ -139,4 +141,12 @@ public class StringUtils {
|
|||||||
}
|
}
|
||||||
return s.toString();
|
return s.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static String getRandomString(int length) {
|
||||||
|
char[] c = new char[length];
|
||||||
|
for (int i = 0; i < length; i++)
|
||||||
|
c[i] = (char) ('a' + random.nextInt(26));
|
||||||
|
return new String(c);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -34,13 +34,6 @@ public class TestUtils {
|
|||||||
return getRandomBytes(UniqueId.LENGTH);
|
return getRandomBytes(UniqueId.LENGTH);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static String getRandomString(int length) {
|
|
||||||
char[] c = new char[length];
|
|
||||||
for (int i = 0; i < length; i++)
|
|
||||||
c[i] = (char) ('a' + random.nextInt(26));
|
|
||||||
return new String(c);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static SecretKey getSecretKey() {
|
public static SecretKey getSecretKey() {
|
||||||
return new SecretKey(getRandomBytes(SecretKey.LENGTH));
|
return new SecretKey(getRandomBytes(SecretKey.LENGTH));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,8 +1,9 @@
|
|||||||
plugins {
|
plugins {
|
||||||
id "java"
|
id 'java'
|
||||||
id "net.ltgt.apt" version "0.9"
|
id 'net.ltgt.apt' version '0.9'
|
||||||
id "idea"
|
id 'idea'
|
||||||
}
|
}
|
||||||
|
|
||||||
sourceCompatibility = 1.6
|
sourceCompatibility = 1.6
|
||||||
targetCompatibility = 1.6
|
targetCompatibility = 1.6
|
||||||
|
|
||||||
@@ -10,17 +11,18 @@ apply plugin: 'witness'
|
|||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
compile project(':bramble-api')
|
compile project(':bramble-api')
|
||||||
compile fileTree(dir: 'libs', include: '*.jar')
|
compile 'com.madgag.spongycastle:core:1.58.0.0'
|
||||||
compile 'com.madgag.spongycastle:core:1.54.0.0'
|
compile 'com.h2database:h2:1.4.192' // This is the last version that supports Java 1.6
|
||||||
compile 'com.h2database:h2:1.4.190'
|
compile 'org.bitlet:weupnp:0.1.4'
|
||||||
|
|
||||||
testCompile project(path: ':bramble-api', configuration: 'testOutput')
|
testCompile project(path: ':bramble-api', configuration: 'testOutput')
|
||||||
}
|
}
|
||||||
|
|
||||||
dependencyVerification {
|
dependencyVerification {
|
||||||
verify = [
|
verify = [
|
||||||
'com.madgag.spongycastle:core:1e7fa4b19ccccd1011364ab838d0b4702470c178bbbdd94c5c90b2d4d749ea1e',
|
'com.madgag.spongycastle:core:199617dd5698c5a9312b898c0a4cec7ce9dd8649d07f65d91629f58229d72728',
|
||||||
'com.h2database:h2:23ba495a07bbbb3bd6c3084d10a96dad7a23741b8b6d64b213459a784195a98c'
|
'com.h2database:h2:225b22e9857235c46c93861410b60b8c81c10dc8985f4faf188985ba5445126c',
|
||||||
|
'org.bitlet:weupnp:88df7e6504929d00bdb832863761385c68ab92af945b04f0770b126270a444fb',
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Binary file not shown.
@@ -8,7 +8,6 @@ import org.briarproject.bramble.db.DatabaseExecutorModule;
|
|||||||
import org.briarproject.bramble.db.DatabaseModule;
|
import org.briarproject.bramble.db.DatabaseModule;
|
||||||
import org.briarproject.bramble.event.EventModule;
|
import org.briarproject.bramble.event.EventModule;
|
||||||
import org.briarproject.bramble.identity.IdentityModule;
|
import org.briarproject.bramble.identity.IdentityModule;
|
||||||
import org.briarproject.bramble.invitation.InvitationModule;
|
|
||||||
import org.briarproject.bramble.keyagreement.KeyAgreementModule;
|
import org.briarproject.bramble.keyagreement.KeyAgreementModule;
|
||||||
import org.briarproject.bramble.lifecycle.LifecycleModule;
|
import org.briarproject.bramble.lifecycle.LifecycleModule;
|
||||||
import org.briarproject.bramble.plugin.PluginModule;
|
import org.briarproject.bramble.plugin.PluginModule;
|
||||||
@@ -32,7 +31,6 @@ import dagger.Module;
|
|||||||
DatabaseExecutorModule.class,
|
DatabaseExecutorModule.class,
|
||||||
EventModule.class,
|
EventModule.class,
|
||||||
IdentityModule.class,
|
IdentityModule.class,
|
||||||
InvitationModule.class,
|
|
||||||
KeyAgreementModule.class,
|
KeyAgreementModule.class,
|
||||||
LifecycleModule.class,
|
LifecycleModule.class,
|
||||||
PluginModule.class,
|
PluginModule.class,
|
||||||
@@ -54,6 +52,7 @@ public class BrambleCoreModule {
|
|||||||
c.inject(new IdentityModule.EagerSingletons());
|
c.inject(new IdentityModule.EagerSingletons());
|
||||||
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 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());
|
||||||
|
|||||||
@@ -80,7 +80,7 @@ class ContactExchangeTaskImpl extends Thread implements ContactExchangeTask {
|
|||||||
private volatile boolean alice;
|
private volatile boolean alice;
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
public ContactExchangeTaskImpl(DatabaseComponent db,
|
ContactExchangeTaskImpl(DatabaseComponent db,
|
||||||
AuthorFactory authorFactory, BdfReaderFactory bdfReaderFactory,
|
AuthorFactory authorFactory, BdfReaderFactory bdfReaderFactory,
|
||||||
BdfWriterFactory bdfWriterFactory, Clock clock,
|
BdfWriterFactory bdfWriterFactory, Clock clock,
|
||||||
ConnectionManager connectionManager, ContactManager contactManager,
|
ConnectionManager connectionManager, ContactManager contactManager,
|
||||||
@@ -146,12 +146,12 @@ class ContactExchangeTaskImpl extends Thread implements ContactExchangeTask {
|
|||||||
|
|
||||||
// Create the readers
|
// Create the readers
|
||||||
InputStream streamReader =
|
InputStream streamReader =
|
||||||
streamReaderFactory.createInvitationStreamReader(in,
|
streamReaderFactory.createContactExchangeStreamReader(in,
|
||||||
alice ? bobHeaderKey : aliceHeaderKey);
|
alice ? bobHeaderKey : aliceHeaderKey);
|
||||||
BdfReader r = bdfReaderFactory.createReader(streamReader);
|
BdfReader r = bdfReaderFactory.createReader(streamReader);
|
||||||
// Create the writers
|
// Create the writers
|
||||||
OutputStream streamWriter =
|
OutputStream streamWriter =
|
||||||
streamWriterFactory.createInvitationStreamWriter(out,
|
streamWriterFactory.createContactExchangeStreamWriter(out,
|
||||||
alice ? aliceHeaderKey : bobHeaderKey);
|
alice ? aliceHeaderKey : bobHeaderKey);
|
||||||
BdfWriter w = bdfWriterFactory.createWriter(streamWriter);
|
BdfWriter w = bdfWriterFactory.createWriter(streamWriter);
|
||||||
|
|
||||||
|
|||||||
@@ -4,7 +4,6 @@ import org.briarproject.bramble.api.crypto.CryptoComponent;
|
|||||||
import org.briarproject.bramble.api.crypto.KeyPair;
|
import org.briarproject.bramble.api.crypto.KeyPair;
|
||||||
import org.briarproject.bramble.api.crypto.KeyParser;
|
import org.briarproject.bramble.api.crypto.KeyParser;
|
||||||
import org.briarproject.bramble.api.crypto.PrivateKey;
|
import org.briarproject.bramble.api.crypto.PrivateKey;
|
||||||
import org.briarproject.bramble.api.crypto.PseudoRandom;
|
|
||||||
import org.briarproject.bramble.api.crypto.PublicKey;
|
import org.briarproject.bramble.api.crypto.PublicKey;
|
||||||
import org.briarproject.bramble.api.crypto.SecretKey;
|
import org.briarproject.bramble.api.crypto.SecretKey;
|
||||||
import org.briarproject.bramble.api.plugin.TransportId;
|
import org.briarproject.bramble.api.plugin.TransportId;
|
||||||
@@ -41,12 +40,13 @@ import java.util.logging.Logger;
|
|||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
|
|
||||||
import static java.util.logging.Level.INFO;
|
import static java.util.logging.Level.INFO;
|
||||||
import static org.briarproject.bramble.api.invitation.InvitationConstants.CODE_BITS;
|
|
||||||
import static org.briarproject.bramble.api.keyagreement.KeyAgreementConstants.COMMIT_LENGTH;
|
import static org.briarproject.bramble.api.keyagreement.KeyAgreementConstants.COMMIT_LENGTH;
|
||||||
import static org.briarproject.bramble.api.transport.TransportConstants.TAG_LENGTH;
|
import static org.briarproject.bramble.api.transport.TransportConstants.TAG_LENGTH;
|
||||||
import static org.briarproject.bramble.crypto.EllipticCurveConstants.PARAMETERS;
|
import static org.briarproject.bramble.crypto.EllipticCurveConstants.PARAMETERS;
|
||||||
|
import static org.briarproject.bramble.util.ByteUtils.INT_16_BYTES;
|
||||||
import static org.briarproject.bramble.util.ByteUtils.INT_32_BYTES;
|
import static org.briarproject.bramble.util.ByteUtils.INT_32_BYTES;
|
||||||
import static org.briarproject.bramble.util.ByteUtils.INT_64_BYTES;
|
import static org.briarproject.bramble.util.ByteUtils.INT_64_BYTES;
|
||||||
|
import static org.briarproject.bramble.util.ByteUtils.MAX_16_BIT_UNSIGNED;
|
||||||
import static org.briarproject.bramble.util.ByteUtils.MAX_32_BIT_UNSIGNED;
|
import static org.briarproject.bramble.util.ByteUtils.MAX_32_BIT_UNSIGNED;
|
||||||
|
|
||||||
class CryptoComponentImpl implements CryptoComponent {
|
class CryptoComponentImpl implements CryptoComponent {
|
||||||
@@ -66,9 +66,6 @@ class CryptoComponentImpl implements CryptoComponent {
|
|||||||
return s.getBytes(Charset.forName("US-ASCII"));
|
return s.getBytes(Charset.forName("US-ASCII"));
|
||||||
}
|
}
|
||||||
|
|
||||||
// KDF labels for bluetooth confirmation code derivation
|
|
||||||
private static final byte[] BT_A_CONFIRM = ascii("ALICE_CONFIRMATION_CODE");
|
|
||||||
private static final byte[] BT_B_CONFIRM = ascii("BOB_CONFIRMATION_CODE");
|
|
||||||
// KDF labels for contact exchange stream header key derivation
|
// KDF labels for contact exchange stream header key derivation
|
||||||
private static final byte[] A_INVITE = ascii("ALICE_INVITATION_KEY");
|
private static final byte[] A_INVITE = ascii("ALICE_INVITATION_KEY");
|
||||||
private static final byte[] B_INVITE = ascii("BOB_INVITATION_KEY");
|
private static final byte[] B_INVITE = ascii("BOB_INVITATION_KEY");
|
||||||
@@ -169,14 +166,6 @@ class CryptoComponentImpl implements CryptoComponent {
|
|||||||
return new SecretKey(b);
|
return new SecretKey(b);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public PseudoRandom getPseudoRandom(int seed1, int seed2) {
|
|
||||||
byte[] seed = new byte[INT_32_BYTES * 2];
|
|
||||||
ByteUtils.writeUint32(seed1, seed, 0);
|
|
||||||
ByteUtils.writeUint32(seed2, seed, INT_32_BYTES);
|
|
||||||
return new PseudoRandomImpl(seed);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public SecureRandom getSecureRandom() {
|
public SecureRandom getSecureRandom() {
|
||||||
return secureRandom;
|
return secureRandom;
|
||||||
@@ -248,20 +237,6 @@ class CryptoComponentImpl implements CryptoComponent {
|
|||||||
return messageEncrypter.getKeyParser();
|
return messageEncrypter.getKeyParser();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public int generateBTInvitationCode() {
|
|
||||||
int codeBytes = (CODE_BITS + 7) / 8;
|
|
||||||
byte[] random = new byte[codeBytes];
|
|
||||||
secureRandom.nextBytes(random);
|
|
||||||
return ByteUtils.readUint(random, CODE_BITS);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int deriveBTConfirmationCode(SecretKey master, boolean alice) {
|
|
||||||
byte[] b = macKdf(master, alice ? BT_A_CONFIRM : BT_B_CONFIRM);
|
|
||||||
return ByteUtils.readUint(b, CODE_BITS);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public SecretKey deriveHeaderKey(SecretKey master,
|
public SecretKey deriveHeaderKey(SecretKey master,
|
||||||
boolean alice) {
|
boolean alice) {
|
||||||
@@ -412,8 +387,11 @@ class CryptoComponentImpl implements CryptoComponent {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void encodeTag(byte[] tag, SecretKey tagKey, long streamNumber) {
|
public void encodeTag(byte[] tag, SecretKey tagKey, int protocolVersion,
|
||||||
|
long streamNumber) {
|
||||||
if (tag.length < TAG_LENGTH) throw new IllegalArgumentException();
|
if (tag.length < TAG_LENGTH) throw new IllegalArgumentException();
|
||||||
|
if (protocolVersion < 0 || protocolVersion > MAX_16_BIT_UNSIGNED)
|
||||||
|
throw new IllegalArgumentException();
|
||||||
if (streamNumber < 0 || streamNumber > MAX_32_BIT_UNSIGNED)
|
if (streamNumber < 0 || streamNumber > MAX_32_BIT_UNSIGNED)
|
||||||
throw new IllegalArgumentException();
|
throw new IllegalArgumentException();
|
||||||
// Initialise the PRF
|
// Initialise the PRF
|
||||||
@@ -421,10 +399,14 @@ class CryptoComponentImpl implements CryptoComponent {
|
|||||||
// The output of the PRF must be long enough to use as a tag
|
// The output of the PRF must be long enough to use as a tag
|
||||||
int macLength = prf.getDigestSize();
|
int macLength = prf.getDigestSize();
|
||||||
if (macLength < TAG_LENGTH) throw new IllegalStateException();
|
if (macLength < TAG_LENGTH) throw new IllegalStateException();
|
||||||
// The input is the stream number as a 64-bit integer
|
// The input is the protocol version as a 16-bit integer, followed by
|
||||||
byte[] input = new byte[INT_64_BYTES];
|
// the stream number as a 64-bit integer
|
||||||
ByteUtils.writeUint64(streamNumber, input, 0);
|
byte[] protocolVersionBytes = new byte[INT_16_BYTES];
|
||||||
prf.update(input, 0, input.length);
|
ByteUtils.writeUint16(protocolVersion, protocolVersionBytes, 0);
|
||||||
|
prf.update(protocolVersionBytes, 0, protocolVersionBytes.length);
|
||||||
|
byte[] streamNumberBytes = new byte[INT_64_BYTES];
|
||||||
|
ByteUtils.writeUint64(streamNumber, streamNumberBytes, 0);
|
||||||
|
prf.update(streamNumberBytes, 0, streamNumberBytes.length);
|
||||||
byte[] mac = new byte[macLength];
|
byte[] mac = new byte[macLength];
|
||||||
prf.doFinal(mac, 0);
|
prf.doFinal(mac, 0);
|
||||||
// The output is the first TAG_LENGTH bytes of the MAC
|
// The output is the first TAG_LENGTH bytes of the MAC
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ class StreamDecrypterFactoryImpl implements StreamDecrypterFactory {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public StreamDecrypter createInvitationStreamDecrypter(InputStream in,
|
public StreamDecrypter createContactExchangeStreamDecrypter(InputStream in,
|
||||||
SecretKey headerKey) {
|
SecretKey headerKey) {
|
||||||
return new StreamDecrypterImpl(in, cipherProvider.get(), 0, headerKey);
|
return new StreamDecrypterImpl(in, cipherProvider.get(), 0, headerKey);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,9 +20,11 @@ import static org.briarproject.bramble.api.transport.TransportConstants.FRAME_NO
|
|||||||
import static org.briarproject.bramble.api.transport.TransportConstants.MAC_LENGTH;
|
import static org.briarproject.bramble.api.transport.TransportConstants.MAC_LENGTH;
|
||||||
import static org.briarproject.bramble.api.transport.TransportConstants.MAX_FRAME_LENGTH;
|
import static org.briarproject.bramble.api.transport.TransportConstants.MAX_FRAME_LENGTH;
|
||||||
import static org.briarproject.bramble.api.transport.TransportConstants.MAX_PAYLOAD_LENGTH;
|
import static org.briarproject.bramble.api.transport.TransportConstants.MAX_PAYLOAD_LENGTH;
|
||||||
import static org.briarproject.bramble.api.transport.TransportConstants.STREAM_HEADER_IV_LENGTH;
|
import static org.briarproject.bramble.api.transport.TransportConstants.PROTOCOL_VERSION;
|
||||||
import static org.briarproject.bramble.api.transport.TransportConstants.STREAM_HEADER_LENGTH;
|
import static org.briarproject.bramble.api.transport.TransportConstants.STREAM_HEADER_LENGTH;
|
||||||
import static org.briarproject.bramble.api.transport.TransportConstants.STREAM_HEADER_NONCE_LENGTH;
|
import static org.briarproject.bramble.api.transport.TransportConstants.STREAM_HEADER_NONCE_LENGTH;
|
||||||
|
import static org.briarproject.bramble.api.transport.TransportConstants.STREAM_HEADER_PLAINTEXT_LENGTH;
|
||||||
|
import static org.briarproject.bramble.util.ByteUtils.INT_16_BYTES;
|
||||||
import static org.briarproject.bramble.util.ByteUtils.INT_64_BYTES;
|
import static org.briarproject.bramble.util.ByteUtils.INT_64_BYTES;
|
||||||
|
|
||||||
@NotThreadSafe
|
@NotThreadSafe
|
||||||
@@ -117,7 +119,7 @@ class StreamDecrypterImpl implements StreamDecrypter {
|
|||||||
|
|
||||||
private void readStreamHeader() throws IOException {
|
private void readStreamHeader() throws IOException {
|
||||||
byte[] streamHeaderCiphertext = new byte[STREAM_HEADER_LENGTH];
|
byte[] streamHeaderCiphertext = new byte[STREAM_HEADER_LENGTH];
|
||||||
byte[] streamHeaderPlaintext = new byte[SecretKey.LENGTH];
|
byte[] streamHeaderPlaintext = new byte[STREAM_HEADER_PLAINTEXT_LENGTH];
|
||||||
// Read the stream header
|
// Read the stream header
|
||||||
int offset = 0;
|
int offset = 0;
|
||||||
while (offset < STREAM_HEADER_LENGTH) {
|
while (offset < STREAM_HEADER_LENGTH) {
|
||||||
@@ -126,21 +128,35 @@ class StreamDecrypterImpl implements StreamDecrypter {
|
|||||||
if (read == -1) throw new EOFException();
|
if (read == -1) throw new EOFException();
|
||||||
offset += read;
|
offset += read;
|
||||||
}
|
}
|
||||||
// The nonce consists of the stream number followed by the IV
|
// Extract the nonce
|
||||||
byte[] streamHeaderNonce = new byte[STREAM_HEADER_NONCE_LENGTH];
|
byte[] streamHeaderNonce = new byte[STREAM_HEADER_NONCE_LENGTH];
|
||||||
ByteUtils.writeUint64(streamNumber, streamHeaderNonce, 0);
|
System.arraycopy(streamHeaderCiphertext, 0, streamHeaderNonce, 0,
|
||||||
System.arraycopy(streamHeaderCiphertext, 0, streamHeaderNonce,
|
STREAM_HEADER_NONCE_LENGTH);
|
||||||
INT_64_BYTES, STREAM_HEADER_IV_LENGTH);
|
|
||||||
// Decrypt and authenticate the stream header
|
// Decrypt and authenticate the stream header
|
||||||
try {
|
try {
|
||||||
cipher.init(false, streamHeaderKey, streamHeaderNonce);
|
cipher.init(false, streamHeaderKey, streamHeaderNonce);
|
||||||
int decrypted = cipher.process(streamHeaderCiphertext,
|
int decrypted = cipher.process(streamHeaderCiphertext,
|
||||||
STREAM_HEADER_IV_LENGTH, SecretKey.LENGTH + MAC_LENGTH,
|
STREAM_HEADER_NONCE_LENGTH,
|
||||||
|
STREAM_HEADER_PLAINTEXT_LENGTH + MAC_LENGTH,
|
||||||
streamHeaderPlaintext, 0);
|
streamHeaderPlaintext, 0);
|
||||||
if (decrypted != SecretKey.LENGTH) throw new RuntimeException();
|
if (decrypted != STREAM_HEADER_PLAINTEXT_LENGTH)
|
||||||
|
throw new RuntimeException();
|
||||||
} catch (GeneralSecurityException e) {
|
} catch (GeneralSecurityException e) {
|
||||||
throw new FormatException();
|
throw new FormatException();
|
||||||
}
|
}
|
||||||
frameKey = new SecretKey(streamHeaderPlaintext);
|
// Check the protocol version
|
||||||
|
int receivedProtocolVersion =
|
||||||
|
ByteUtils.readUint16(streamHeaderPlaintext, 0);
|
||||||
|
if (receivedProtocolVersion != PROTOCOL_VERSION)
|
||||||
|
throw new FormatException();
|
||||||
|
// Check the stream number
|
||||||
|
long receivedStreamNumber = ByteUtils.readUint64(streamHeaderPlaintext,
|
||||||
|
INT_16_BYTES);
|
||||||
|
if (receivedStreamNumber != streamNumber) throw new FormatException();
|
||||||
|
// Extract the frame key
|
||||||
|
byte[] frameKeyBytes = new byte[SecretKey.LENGTH];
|
||||||
|
System.arraycopy(streamHeaderPlaintext, INT_16_BYTES + INT_64_BYTES,
|
||||||
|
frameKeyBytes, 0, SecretKey.LENGTH);
|
||||||
|
frameKey = new SecretKey(frameKeyBytes);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -13,7 +13,8 @@ import javax.annotation.concurrent.Immutable;
|
|||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
import javax.inject.Provider;
|
import javax.inject.Provider;
|
||||||
|
|
||||||
import static org.briarproject.bramble.api.transport.TransportConstants.STREAM_HEADER_IV_LENGTH;
|
import static org.briarproject.bramble.api.transport.TransportConstants.PROTOCOL_VERSION;
|
||||||
|
import static org.briarproject.bramble.api.transport.TransportConstants.STREAM_HEADER_NONCE_LENGTH;
|
||||||
import static org.briarproject.bramble.api.transport.TransportConstants.TAG_LENGTH;
|
import static org.briarproject.bramble.api.transport.TransportConstants.TAG_LENGTH;
|
||||||
|
|
||||||
@Immutable
|
@Immutable
|
||||||
@@ -36,22 +37,22 @@ class StreamEncrypterFactoryImpl implements StreamEncrypterFactory {
|
|||||||
AuthenticatedCipher cipher = cipherProvider.get();
|
AuthenticatedCipher cipher = cipherProvider.get();
|
||||||
long streamNumber = ctx.getStreamNumber();
|
long streamNumber = ctx.getStreamNumber();
|
||||||
byte[] tag = new byte[TAG_LENGTH];
|
byte[] tag = new byte[TAG_LENGTH];
|
||||||
crypto.encodeTag(tag, ctx.getTagKey(), streamNumber);
|
crypto.encodeTag(tag, ctx.getTagKey(), PROTOCOL_VERSION, streamNumber);
|
||||||
byte[] streamHeaderIv = new byte[STREAM_HEADER_IV_LENGTH];
|
byte[] streamHeaderNonce = new byte[STREAM_HEADER_NONCE_LENGTH];
|
||||||
crypto.getSecureRandom().nextBytes(streamHeaderIv);
|
crypto.getSecureRandom().nextBytes(streamHeaderNonce);
|
||||||
SecretKey frameKey = crypto.generateSecretKey();
|
SecretKey frameKey = crypto.generateSecretKey();
|
||||||
return new StreamEncrypterImpl(out, cipher, streamNumber, tag,
|
return new StreamEncrypterImpl(out, cipher, streamNumber, tag,
|
||||||
streamHeaderIv, ctx.getHeaderKey(), frameKey);
|
streamHeaderNonce, ctx.getHeaderKey(), frameKey);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public StreamEncrypter createInvitationStreamEncrypter(OutputStream out,
|
public StreamEncrypter createContactExchangeStreamDecrypter(
|
||||||
SecretKey headerKey) {
|
OutputStream out, SecretKey headerKey) {
|
||||||
AuthenticatedCipher cipher = cipherProvider.get();
|
AuthenticatedCipher cipher = cipherProvider.get();
|
||||||
byte[] streamHeaderIv = new byte[STREAM_HEADER_IV_LENGTH];
|
byte[] streamHeaderNonce = new byte[STREAM_HEADER_NONCE_LENGTH];
|
||||||
crypto.getSecureRandom().nextBytes(streamHeaderIv);
|
crypto.getSecureRandom().nextBytes(streamHeaderNonce);
|
||||||
SecretKey frameKey = crypto.generateSecretKey();
|
SecretKey frameKey = crypto.generateSecretKey();
|
||||||
return new StreamEncrypterImpl(out, cipher, 0, null, streamHeaderIv,
|
return new StreamEncrypterImpl(out, cipher, 0, null, streamHeaderNonce,
|
||||||
headerKey, frameKey);
|
headerKey, frameKey);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,9 +18,11 @@ import static org.briarproject.bramble.api.transport.TransportConstants.FRAME_NO
|
|||||||
import static org.briarproject.bramble.api.transport.TransportConstants.MAC_LENGTH;
|
import static org.briarproject.bramble.api.transport.TransportConstants.MAC_LENGTH;
|
||||||
import static org.briarproject.bramble.api.transport.TransportConstants.MAX_FRAME_LENGTH;
|
import static org.briarproject.bramble.api.transport.TransportConstants.MAX_FRAME_LENGTH;
|
||||||
import static org.briarproject.bramble.api.transport.TransportConstants.MAX_PAYLOAD_LENGTH;
|
import static org.briarproject.bramble.api.transport.TransportConstants.MAX_PAYLOAD_LENGTH;
|
||||||
import static org.briarproject.bramble.api.transport.TransportConstants.STREAM_HEADER_IV_LENGTH;
|
import static org.briarproject.bramble.api.transport.TransportConstants.PROTOCOL_VERSION;
|
||||||
import static org.briarproject.bramble.api.transport.TransportConstants.STREAM_HEADER_LENGTH;
|
import static org.briarproject.bramble.api.transport.TransportConstants.STREAM_HEADER_LENGTH;
|
||||||
import static org.briarproject.bramble.api.transport.TransportConstants.STREAM_HEADER_NONCE_LENGTH;
|
import static org.briarproject.bramble.api.transport.TransportConstants.STREAM_HEADER_NONCE_LENGTH;
|
||||||
|
import static org.briarproject.bramble.api.transport.TransportConstants.STREAM_HEADER_PLAINTEXT_LENGTH;
|
||||||
|
import static org.briarproject.bramble.util.ByteUtils.INT_16_BYTES;
|
||||||
import static org.briarproject.bramble.util.ByteUtils.INT_64_BYTES;
|
import static org.briarproject.bramble.util.ByteUtils.INT_64_BYTES;
|
||||||
|
|
||||||
@NotThreadSafe
|
@NotThreadSafe
|
||||||
@@ -33,7 +35,7 @@ class StreamEncrypterImpl implements StreamEncrypter {
|
|||||||
private final long streamNumber;
|
private final long streamNumber;
|
||||||
@Nullable
|
@Nullable
|
||||||
private final byte[] tag;
|
private final byte[] tag;
|
||||||
private final byte[] streamHeaderIv;
|
private final byte[] streamHeaderNonce;
|
||||||
private final byte[] frameNonce, frameHeader;
|
private final byte[] frameNonce, frameHeader;
|
||||||
private final byte[] framePlaintext, frameCiphertext;
|
private final byte[] framePlaintext, frameCiphertext;
|
||||||
|
|
||||||
@@ -41,13 +43,13 @@ class StreamEncrypterImpl implements StreamEncrypter {
|
|||||||
private boolean writeTag, writeStreamHeader;
|
private boolean writeTag, writeStreamHeader;
|
||||||
|
|
||||||
StreamEncrypterImpl(OutputStream out, AuthenticatedCipher cipher,
|
StreamEncrypterImpl(OutputStream out, AuthenticatedCipher cipher,
|
||||||
long streamNumber, @Nullable byte[] tag, byte[] streamHeaderIv,
|
long streamNumber, @Nullable byte[] tag, byte[] streamHeaderNonce,
|
||||||
SecretKey streamHeaderKey, SecretKey frameKey) {
|
SecretKey streamHeaderKey, SecretKey frameKey) {
|
||||||
this.out = out;
|
this.out = out;
|
||||||
this.cipher = cipher;
|
this.cipher = cipher;
|
||||||
this.streamNumber = streamNumber;
|
this.streamNumber = streamNumber;
|
||||||
this.tag = tag;
|
this.tag = tag;
|
||||||
this.streamHeaderIv = streamHeaderIv;
|
this.streamHeaderNonce = streamHeaderNonce;
|
||||||
this.streamHeaderKey = streamHeaderKey;
|
this.streamHeaderKey = streamHeaderKey;
|
||||||
this.frameKey = frameKey;
|
this.frameKey = frameKey;
|
||||||
frameNonce = new byte[FRAME_NONCE_LENGTH];
|
frameNonce = new byte[FRAME_NONCE_LENGTH];
|
||||||
@@ -114,22 +116,23 @@ class StreamEncrypterImpl implements StreamEncrypter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void writeStreamHeader() throws IOException {
|
private void writeStreamHeader() throws IOException {
|
||||||
// The nonce consists of the stream number followed by the IV
|
// The header contains the protocol version, stream number and frame key
|
||||||
byte[] streamHeaderNonce = new byte[STREAM_HEADER_NONCE_LENGTH];
|
byte[] streamHeaderPlaintext = new byte[STREAM_HEADER_PLAINTEXT_LENGTH];
|
||||||
ByteUtils.writeUint64(streamNumber, streamHeaderNonce, 0);
|
ByteUtils.writeUint16(PROTOCOL_VERSION, streamHeaderPlaintext, 0);
|
||||||
System.arraycopy(streamHeaderIv, 0, streamHeaderNonce, INT_64_BYTES,
|
ByteUtils.writeUint64(streamNumber, streamHeaderPlaintext,
|
||||||
STREAM_HEADER_IV_LENGTH);
|
INT_16_BYTES);
|
||||||
byte[] streamHeaderPlaintext = frameKey.getBytes();
|
System.arraycopy(frameKey.getBytes(), 0, streamHeaderPlaintext,
|
||||||
|
INT_16_BYTES + INT_64_BYTES, SecretKey.LENGTH);
|
||||||
byte[] streamHeaderCiphertext = new byte[STREAM_HEADER_LENGTH];
|
byte[] streamHeaderCiphertext = new byte[STREAM_HEADER_LENGTH];
|
||||||
System.arraycopy(streamHeaderIv, 0, streamHeaderCiphertext, 0,
|
System.arraycopy(streamHeaderNonce, 0, streamHeaderCiphertext, 0,
|
||||||
STREAM_HEADER_IV_LENGTH);
|
STREAM_HEADER_NONCE_LENGTH);
|
||||||
// Encrypt and authenticate the frame key
|
// Encrypt and authenticate the stream header key
|
||||||
try {
|
try {
|
||||||
cipher.init(true, streamHeaderKey, streamHeaderNonce);
|
cipher.init(true, streamHeaderKey, streamHeaderNonce);
|
||||||
int encrypted = cipher.process(streamHeaderPlaintext, 0,
|
int encrypted = cipher.process(streamHeaderPlaintext, 0,
|
||||||
SecretKey.LENGTH, streamHeaderCiphertext,
|
STREAM_HEADER_PLAINTEXT_LENGTH, streamHeaderCiphertext,
|
||||||
STREAM_HEADER_IV_LENGTH);
|
STREAM_HEADER_NONCE_LENGTH);
|
||||||
if (encrypted != SecretKey.LENGTH + MAC_LENGTH)
|
if (encrypted != STREAM_HEADER_PLAINTEXT_LENGTH + MAC_LENGTH)
|
||||||
throw new RuntimeException();
|
throw new RuntimeException();
|
||||||
} catch (GeneralSecurityException badCipher) {
|
} catch (GeneralSecurityException badCipher) {
|
||||||
throw new RuntimeException(badCipher);
|
throw new RuntimeException(badCipher);
|
||||||
|
|||||||
@@ -70,25 +70,7 @@ class XSalsa20Poly1305AuthenticatedCipher implements AuthenticatedCipher {
|
|||||||
byte[] subKey = new byte[SUBKEY_LENGTH];
|
byte[] subKey = new byte[SUBKEY_LENGTH];
|
||||||
xSalsa20Engine.processBytes(zero, 0, SUBKEY_LENGTH, subKey, 0);
|
xSalsa20Engine.processBytes(zero, 0, SUBKEY_LENGTH, subKey, 0);
|
||||||
|
|
||||||
// Reverse the order of the Poly130 subkey
|
// Clamp the subkey
|
||||||
//
|
|
||||||
// NaCl and libsodium use the first 32 bytes of XSalsa20 as the
|
|
||||||
// subkey for crypto_onetimeauth_poly1305, which interprets it
|
|
||||||
// as r[0] ... r[15], k[0] ... k[15]. See section 9 of the NaCl
|
|
||||||
// paper (http://cr.yp.to/highspeed/naclcrypto-20090310.pdf),
|
|
||||||
// where the XSalsa20 output is defined as (r, s, t, ...).
|
|
||||||
//
|
|
||||||
// BC's Poly1305 implementation interprets the subkey as
|
|
||||||
// k[0] ... k[15], r[0] ... r[15] (per poly1305_aes_clamp in
|
|
||||||
// the reference implementation).
|
|
||||||
//
|
|
||||||
// To be NaCl-compatible, we reverse the subkey.
|
|
||||||
System.arraycopy(subKey, 0, zero, 0, SUBKEY_LENGTH / 2);
|
|
||||||
System.arraycopy(subKey, SUBKEY_LENGTH / 2, subKey, 0,
|
|
||||||
SUBKEY_LENGTH / 2);
|
|
||||||
System.arraycopy(zero, 0, subKey, SUBKEY_LENGTH / 2,
|
|
||||||
SUBKEY_LENGTH / 2);
|
|
||||||
// Now we can clamp the correct part of the subkey
|
|
||||||
Poly1305KeyGenerator.clamp(subKey);
|
Poly1305KeyGenerator.clamp(subKey);
|
||||||
|
|
||||||
// Initialize Poly1305 with the subkey
|
// Initialize Poly1305 with the subkey
|
||||||
|
|||||||
@@ -1,119 +0,0 @@
|
|||||||
package org.briarproject.bramble.invitation;
|
|
||||||
|
|
||||||
import org.briarproject.bramble.api.contact.ContactExchangeTask;
|
|
||||||
import org.briarproject.bramble.api.crypto.CryptoComponent;
|
|
||||||
import org.briarproject.bramble.api.crypto.PseudoRandom;
|
|
||||||
import org.briarproject.bramble.api.crypto.SecretKey;
|
|
||||||
import org.briarproject.bramble.api.data.BdfReader;
|
|
||||||
import org.briarproject.bramble.api.data.BdfReaderFactory;
|
|
||||||
import org.briarproject.bramble.api.data.BdfWriter;
|
|
||||||
import org.briarproject.bramble.api.data.BdfWriterFactory;
|
|
||||||
import org.briarproject.bramble.api.identity.LocalAuthor;
|
|
||||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
|
||||||
import org.briarproject.bramble.api.plugin.duplex.DuplexPlugin;
|
|
||||||
import org.briarproject.bramble.api.plugin.duplex.DuplexTransportConnection;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.InputStream;
|
|
||||||
import java.io.OutputStream;
|
|
||||||
import java.security.GeneralSecurityException;
|
|
||||||
import java.util.logging.Logger;
|
|
||||||
|
|
||||||
import static java.util.logging.Level.INFO;
|
|
||||||
import static java.util.logging.Level.WARNING;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A connection thread for the peer being Alice in the invitation protocol.
|
|
||||||
*/
|
|
||||||
@NotNullByDefault
|
|
||||||
class AliceConnector extends Connector {
|
|
||||||
|
|
||||||
private static final Logger LOG =
|
|
||||||
Logger.getLogger(AliceConnector.class.getName());
|
|
||||||
|
|
||||||
AliceConnector(CryptoComponent crypto, BdfReaderFactory bdfReaderFactory,
|
|
||||||
BdfWriterFactory bdfWriterFactory,
|
|
||||||
ContactExchangeTask contactExchangeTask, ConnectorGroup group,
|
|
||||||
DuplexPlugin plugin, LocalAuthor localAuthor, PseudoRandom random) {
|
|
||||||
super(crypto, bdfReaderFactory, bdfWriterFactory, contactExchangeTask,
|
|
||||||
group, plugin, localAuthor, random);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
// Create an incoming or outgoing connection
|
|
||||||
DuplexTransportConnection conn = createInvitationConnection(true);
|
|
||||||
if (conn == null) return;
|
|
||||||
if (LOG.isLoggable(INFO)) LOG.info(pluginName + " connected");
|
|
||||||
// Don't proceed with more than one connection
|
|
||||||
if (group.getAndSetConnected()) {
|
|
||||||
if (LOG.isLoggable(INFO)) LOG.info(pluginName + " redundant");
|
|
||||||
tryToClose(conn, false);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
// Carry out the key agreement protocol
|
|
||||||
InputStream in;
|
|
||||||
OutputStream out;
|
|
||||||
BdfReader r;
|
|
||||||
BdfWriter w;
|
|
||||||
SecretKey master;
|
|
||||||
try {
|
|
||||||
in = conn.getReader().getInputStream();
|
|
||||||
out = conn.getWriter().getOutputStream();
|
|
||||||
r = bdfReaderFactory.createReader(in);
|
|
||||||
w = bdfWriterFactory.createWriter(out);
|
|
||||||
// Alice goes first
|
|
||||||
sendPublicKeyHash(w);
|
|
||||||
byte[] hash = receivePublicKeyHash(r);
|
|
||||||
sendPublicKey(w);
|
|
||||||
byte[] key = receivePublicKey(r);
|
|
||||||
master = deriveMasterSecret(hash, key, true);
|
|
||||||
} catch (IOException e) {
|
|
||||||
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
|
||||||
group.keyAgreementFailed();
|
|
||||||
tryToClose(conn, true);
|
|
||||||
return;
|
|
||||||
} catch (GeneralSecurityException e) {
|
|
||||||
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
|
||||||
group.keyAgreementFailed();
|
|
||||||
tryToClose(conn, true);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
// The key agreement succeeded - derive the confirmation codes
|
|
||||||
if (LOG.isLoggable(INFO)) LOG.info(pluginName + " agreement succeeded");
|
|
||||||
int aliceCode = crypto.deriveBTConfirmationCode(master, true);
|
|
||||||
int bobCode = crypto.deriveBTConfirmationCode(master, false);
|
|
||||||
group.keyAgreementSucceeded(aliceCode, bobCode);
|
|
||||||
// Exchange confirmation results
|
|
||||||
boolean localMatched, remoteMatched;
|
|
||||||
try {
|
|
||||||
localMatched = group.waitForLocalConfirmationResult();
|
|
||||||
sendConfirmation(w, localMatched);
|
|
||||||
remoteMatched = receiveConfirmation(r);
|
|
||||||
} catch (IOException e) {
|
|
||||||
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
|
||||||
group.remoteConfirmationFailed();
|
|
||||||
tryToClose(conn, true);
|
|
||||||
return;
|
|
||||||
} catch (InterruptedException e) {
|
|
||||||
LOG.warning("Interrupted while waiting for confirmation");
|
|
||||||
group.remoteConfirmationFailed();
|
|
||||||
tryToClose(conn, true);
|
|
||||||
Thread.currentThread().interrupt();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (remoteMatched) group.remoteConfirmationSucceeded();
|
|
||||||
else group.remoteConfirmationFailed();
|
|
||||||
if (!(localMatched && remoteMatched)) {
|
|
||||||
if (LOG.isLoggable(INFO))
|
|
||||||
LOG.info(pluginName + " confirmation failed");
|
|
||||||
tryToClose(conn, false);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
// Confirmation succeeded - upgrade to a secure connection
|
|
||||||
if (LOG.isLoggable(INFO))
|
|
||||||
LOG.info(pluginName + " confirmation succeeded");
|
|
||||||
contactExchangeTask.startExchange(group, localAuthor, master, conn,
|
|
||||||
plugin.getId(), true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,119 +0,0 @@
|
|||||||
package org.briarproject.bramble.invitation;
|
|
||||||
|
|
||||||
import org.briarproject.bramble.api.contact.ContactExchangeTask;
|
|
||||||
import org.briarproject.bramble.api.crypto.CryptoComponent;
|
|
||||||
import org.briarproject.bramble.api.crypto.PseudoRandom;
|
|
||||||
import org.briarproject.bramble.api.crypto.SecretKey;
|
|
||||||
import org.briarproject.bramble.api.data.BdfReader;
|
|
||||||
import org.briarproject.bramble.api.data.BdfReaderFactory;
|
|
||||||
import org.briarproject.bramble.api.data.BdfWriter;
|
|
||||||
import org.briarproject.bramble.api.data.BdfWriterFactory;
|
|
||||||
import org.briarproject.bramble.api.identity.LocalAuthor;
|
|
||||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
|
||||||
import org.briarproject.bramble.api.plugin.duplex.DuplexPlugin;
|
|
||||||
import org.briarproject.bramble.api.plugin.duplex.DuplexTransportConnection;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.InputStream;
|
|
||||||
import java.io.OutputStream;
|
|
||||||
import java.security.GeneralSecurityException;
|
|
||||||
import java.util.logging.Logger;
|
|
||||||
|
|
||||||
import static java.util.logging.Level.INFO;
|
|
||||||
import static java.util.logging.Level.WARNING;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A connection thread for the peer being Bob in the invitation protocol.
|
|
||||||
*/
|
|
||||||
@NotNullByDefault
|
|
||||||
class BobConnector extends Connector {
|
|
||||||
|
|
||||||
private static final Logger LOG =
|
|
||||||
Logger.getLogger(BobConnector.class.getName());
|
|
||||||
|
|
||||||
BobConnector(CryptoComponent crypto, BdfReaderFactory bdfReaderFactory,
|
|
||||||
BdfWriterFactory bdfWriterFactory,
|
|
||||||
ContactExchangeTask contactExchangeTask, ConnectorGroup group,
|
|
||||||
DuplexPlugin plugin, LocalAuthor localAuthor, PseudoRandom random) {
|
|
||||||
super(crypto, bdfReaderFactory, bdfWriterFactory, contactExchangeTask,
|
|
||||||
group, plugin, localAuthor, random);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
// Create an incoming or outgoing connection
|
|
||||||
DuplexTransportConnection conn = createInvitationConnection(false);
|
|
||||||
if (conn == null) return;
|
|
||||||
if (LOG.isLoggable(INFO)) LOG.info(pluginName + " connected");
|
|
||||||
// Carry out the key agreement protocol
|
|
||||||
InputStream in;
|
|
||||||
OutputStream out;
|
|
||||||
BdfReader r;
|
|
||||||
BdfWriter w;
|
|
||||||
SecretKey master;
|
|
||||||
try {
|
|
||||||
in = conn.getReader().getInputStream();
|
|
||||||
out = conn.getWriter().getOutputStream();
|
|
||||||
r = bdfReaderFactory.createReader(in);
|
|
||||||
w = bdfWriterFactory.createWriter(out);
|
|
||||||
// Alice goes first
|
|
||||||
byte[] hash = receivePublicKeyHash(r);
|
|
||||||
// Don't proceed with more than one connection
|
|
||||||
if (group.getAndSetConnected()) {
|
|
||||||
if (LOG.isLoggable(INFO)) LOG.info(pluginName + " redundant");
|
|
||||||
tryToClose(conn, false);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
sendPublicKeyHash(w);
|
|
||||||
byte[] key = receivePublicKey(r);
|
|
||||||
sendPublicKey(w);
|
|
||||||
master = deriveMasterSecret(hash, key, false);
|
|
||||||
} catch (IOException e) {
|
|
||||||
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
|
||||||
group.keyAgreementFailed();
|
|
||||||
tryToClose(conn, true);
|
|
||||||
return;
|
|
||||||
} catch (GeneralSecurityException e) {
|
|
||||||
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
|
||||||
group.keyAgreementFailed();
|
|
||||||
tryToClose(conn, true);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
// The key agreement succeeded - derive the confirmation codes
|
|
||||||
if (LOG.isLoggable(INFO)) LOG.info(pluginName + " agreement succeeded");
|
|
||||||
int aliceCode = crypto.deriveBTConfirmationCode(master, true);
|
|
||||||
int bobCode = crypto.deriveBTConfirmationCode(master, false);
|
|
||||||
group.keyAgreementSucceeded(bobCode, aliceCode);
|
|
||||||
// Exchange confirmation results
|
|
||||||
boolean localMatched, remoteMatched;
|
|
||||||
try {
|
|
||||||
remoteMatched = receiveConfirmation(r);
|
|
||||||
localMatched = group.waitForLocalConfirmationResult();
|
|
||||||
sendConfirmation(w, localMatched);
|
|
||||||
} catch (IOException e) {
|
|
||||||
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
|
||||||
group.remoteConfirmationFailed();
|
|
||||||
tryToClose(conn, true);
|
|
||||||
return;
|
|
||||||
} catch (InterruptedException e) {
|
|
||||||
LOG.warning("Interrupted while waiting for confirmation");
|
|
||||||
group.remoteConfirmationFailed();
|
|
||||||
tryToClose(conn, true);
|
|
||||||
Thread.currentThread().interrupt();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (remoteMatched) group.remoteConfirmationSucceeded();
|
|
||||||
else group.remoteConfirmationFailed();
|
|
||||||
if (!(localMatched && remoteMatched)) {
|
|
||||||
if (LOG.isLoggable(INFO))
|
|
||||||
LOG.info(pluginName + " confirmation failed");
|
|
||||||
tryToClose(conn, false);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
// Confirmation succeeded - upgrade to a secure connection
|
|
||||||
if (LOG.isLoggable(INFO))
|
|
||||||
LOG.info(pluginName + " confirmation succeeded");
|
|
||||||
contactExchangeTask.startExchange(group, localAuthor, master, conn,
|
|
||||||
plugin.getId(), false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,150 +0,0 @@
|
|||||||
package org.briarproject.bramble.invitation;
|
|
||||||
|
|
||||||
import org.briarproject.bramble.api.FormatException;
|
|
||||||
import org.briarproject.bramble.api.contact.ContactExchangeTask;
|
|
||||||
import org.briarproject.bramble.api.crypto.CryptoComponent;
|
|
||||||
import org.briarproject.bramble.api.crypto.KeyPair;
|
|
||||||
import org.briarproject.bramble.api.crypto.KeyParser;
|
|
||||||
import org.briarproject.bramble.api.crypto.PseudoRandom;
|
|
||||||
import org.briarproject.bramble.api.crypto.SecretKey;
|
|
||||||
import org.briarproject.bramble.api.data.BdfReader;
|
|
||||||
import org.briarproject.bramble.api.data.BdfReaderFactory;
|
|
||||||
import org.briarproject.bramble.api.data.BdfWriter;
|
|
||||||
import org.briarproject.bramble.api.data.BdfWriterFactory;
|
|
||||||
import org.briarproject.bramble.api.identity.LocalAuthor;
|
|
||||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
|
||||||
import org.briarproject.bramble.api.plugin.duplex.DuplexPlugin;
|
|
||||||
import org.briarproject.bramble.api.plugin.duplex.DuplexTransportConnection;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.security.GeneralSecurityException;
|
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.logging.Logger;
|
|
||||||
|
|
||||||
import javax.annotation.Nullable;
|
|
||||||
|
|
||||||
import static java.util.logging.Level.INFO;
|
|
||||||
import static java.util.logging.Level.WARNING;
|
|
||||||
import static org.briarproject.bramble.api.identity.AuthorConstants.MAX_PUBLIC_KEY_LENGTH;
|
|
||||||
import static org.briarproject.bramble.api.invitation.InvitationConstants.CONNECTION_TIMEOUT;
|
|
||||||
|
|
||||||
// FIXME: This class has way too many dependencies
|
|
||||||
@NotNullByDefault
|
|
||||||
abstract class Connector extends Thread {
|
|
||||||
|
|
||||||
private static final Logger LOG =
|
|
||||||
Logger.getLogger(Connector.class.getName());
|
|
||||||
private static final String LABEL_PUBLIC_KEY =
|
|
||||||
"org.briarproject.bramble.invitation.PUBLIC_KEY";
|
|
||||||
|
|
||||||
protected final CryptoComponent crypto;
|
|
||||||
protected final BdfReaderFactory bdfReaderFactory;
|
|
||||||
protected final BdfWriterFactory bdfWriterFactory;
|
|
||||||
protected final ContactExchangeTask contactExchangeTask;
|
|
||||||
protected final ConnectorGroup group;
|
|
||||||
protected final DuplexPlugin plugin;
|
|
||||||
protected final LocalAuthor localAuthor;
|
|
||||||
protected final PseudoRandom random;
|
|
||||||
protected final String pluginName;
|
|
||||||
|
|
||||||
private final KeyPair keyPair;
|
|
||||||
private final KeyParser keyParser;
|
|
||||||
|
|
||||||
Connector(CryptoComponent crypto, BdfReaderFactory bdfReaderFactory,
|
|
||||||
BdfWriterFactory bdfWriterFactory,
|
|
||||||
ContactExchangeTask contactExchangeTask, ConnectorGroup group,
|
|
||||||
DuplexPlugin plugin, LocalAuthor localAuthor, PseudoRandom random) {
|
|
||||||
super("Connector");
|
|
||||||
this.crypto = crypto;
|
|
||||||
this.bdfReaderFactory = bdfReaderFactory;
|
|
||||||
this.bdfWriterFactory = bdfWriterFactory;
|
|
||||||
this.contactExchangeTask = contactExchangeTask;
|
|
||||||
this.group = group;
|
|
||||||
this.plugin = plugin;
|
|
||||||
this.localAuthor = localAuthor;
|
|
||||||
this.random = random;
|
|
||||||
pluginName = plugin.getClass().getName();
|
|
||||||
keyPair = crypto.generateAgreementKeyPair();
|
|
||||||
keyParser = crypto.getAgreementKeyParser();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Nullable
|
|
||||||
DuplexTransportConnection createInvitationConnection(boolean alice) {
|
|
||||||
if (LOG.isLoggable(INFO))
|
|
||||||
LOG.info(pluginName + " creating invitation connection");
|
|
||||||
return plugin.createInvitationConnection(random, CONNECTION_TIMEOUT,
|
|
||||||
alice);
|
|
||||||
}
|
|
||||||
|
|
||||||
void sendPublicKeyHash(BdfWriter w) throws IOException {
|
|
||||||
byte[] hash =
|
|
||||||
crypto.hash(LABEL_PUBLIC_KEY, keyPair.getPublic().getEncoded());
|
|
||||||
w.writeRaw(hash);
|
|
||||||
w.flush();
|
|
||||||
if (LOG.isLoggable(INFO)) LOG.info(pluginName + " sent hash");
|
|
||||||
}
|
|
||||||
|
|
||||||
byte[] receivePublicKeyHash(BdfReader r) throws IOException {
|
|
||||||
int hashLength = crypto.getHashLength();
|
|
||||||
byte[] b = r.readRaw(hashLength);
|
|
||||||
if (b.length < hashLength) throw new FormatException();
|
|
||||||
if (LOG.isLoggable(INFO)) LOG.info(pluginName + " received hash");
|
|
||||||
return b;
|
|
||||||
}
|
|
||||||
|
|
||||||
void sendPublicKey(BdfWriter w) throws IOException {
|
|
||||||
byte[] key = keyPair.getPublic().getEncoded();
|
|
||||||
w.writeRaw(key);
|
|
||||||
w.flush();
|
|
||||||
if (LOG.isLoggable(INFO)) LOG.info(pluginName + " sent key");
|
|
||||||
}
|
|
||||||
|
|
||||||
byte[] receivePublicKey(BdfReader r)
|
|
||||||
throws GeneralSecurityException, IOException {
|
|
||||||
byte[] b = r.readRaw(MAX_PUBLIC_KEY_LENGTH);
|
|
||||||
keyParser.parsePublicKey(b);
|
|
||||||
if (LOG.isLoggable(INFO)) LOG.info(pluginName + " received key");
|
|
||||||
return b;
|
|
||||||
}
|
|
||||||
|
|
||||||
SecretKey deriveMasterSecret(byte[] hash, byte[] key, boolean alice)
|
|
||||||
throws GeneralSecurityException {
|
|
||||||
// Check that the hash matches the key
|
|
||||||
byte[] keyHash =
|
|
||||||
crypto.hash(LABEL_PUBLIC_KEY, keyPair.getPublic().getEncoded());
|
|
||||||
if (!Arrays.equals(hash, keyHash)) {
|
|
||||||
if (LOG.isLoggable(INFO))
|
|
||||||
LOG.info(pluginName + " hash does not match key");
|
|
||||||
throw new GeneralSecurityException();
|
|
||||||
}
|
|
||||||
// Derive the master secret
|
|
||||||
if (LOG.isLoggable(INFO))
|
|
||||||
LOG.info(pluginName + " deriving master secret");
|
|
||||||
return crypto.deriveMasterSecret(key, keyPair, alice);
|
|
||||||
}
|
|
||||||
|
|
||||||
void sendConfirmation(BdfWriter w, boolean confirmed) throws IOException {
|
|
||||||
w.writeBoolean(confirmed);
|
|
||||||
w.flush();
|
|
||||||
if (LOG.isLoggable(INFO))
|
|
||||||
LOG.info(pluginName + " sent confirmation: " + confirmed);
|
|
||||||
}
|
|
||||||
|
|
||||||
boolean receiveConfirmation(BdfReader r) throws IOException {
|
|
||||||
boolean confirmed = r.readBoolean();
|
|
||||||
if (LOG.isLoggable(INFO))
|
|
||||||
LOG.info(pluginName + " received confirmation: " + confirmed);
|
|
||||||
return confirmed;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void tryToClose(DuplexTransportConnection conn,
|
|
||||||
boolean exception) {
|
|
||||||
try {
|
|
||||||
LOG.info("Closing connection");
|
|
||||||
conn.getReader().dispose(exception, true);
|
|
||||||
conn.getWriter().dispose(exception);
|
|
||||||
} catch (IOException e) {
|
|
||||||
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,278 +0,0 @@
|
|||||||
package org.briarproject.bramble.invitation;
|
|
||||||
|
|
||||||
import org.briarproject.bramble.api.contact.ContactExchangeListener;
|
|
||||||
import org.briarproject.bramble.api.contact.ContactExchangeTask;
|
|
||||||
import org.briarproject.bramble.api.crypto.CryptoComponent;
|
|
||||||
import org.briarproject.bramble.api.crypto.PseudoRandom;
|
|
||||||
import org.briarproject.bramble.api.data.BdfReaderFactory;
|
|
||||||
import org.briarproject.bramble.api.data.BdfWriterFactory;
|
|
||||||
import org.briarproject.bramble.api.db.DbException;
|
|
||||||
import org.briarproject.bramble.api.identity.Author;
|
|
||||||
import org.briarproject.bramble.api.identity.IdentityManager;
|
|
||||||
import org.briarproject.bramble.api.identity.LocalAuthor;
|
|
||||||
import org.briarproject.bramble.api.invitation.InvitationListener;
|
|
||||||
import org.briarproject.bramble.api.invitation.InvitationState;
|
|
||||||
import org.briarproject.bramble.api.invitation.InvitationTask;
|
|
||||||
import org.briarproject.bramble.api.nullsafety.MethodsNotNullByDefault;
|
|
||||||
import org.briarproject.bramble.api.nullsafety.ParametersNotNullByDefault;
|
|
||||||
import org.briarproject.bramble.api.plugin.PluginManager;
|
|
||||||
import org.briarproject.bramble.api.plugin.duplex.DuplexPlugin;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Collection;
|
|
||||||
import java.util.concurrent.CopyOnWriteArrayList;
|
|
||||||
import java.util.concurrent.CountDownLatch;
|
|
||||||
import java.util.concurrent.atomic.AtomicBoolean;
|
|
||||||
import java.util.concurrent.locks.Lock;
|
|
||||||
import java.util.concurrent.locks.ReentrantLock;
|
|
||||||
import java.util.logging.Logger;
|
|
||||||
|
|
||||||
import static java.util.concurrent.TimeUnit.MILLISECONDS;
|
|
||||||
import static java.util.logging.Level.WARNING;
|
|
||||||
import static org.briarproject.bramble.api.invitation.InvitationConstants.CONFIRMATION_TIMEOUT;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A task consisting of one or more parallel connection attempts.
|
|
||||||
*/
|
|
||||||
@MethodsNotNullByDefault
|
|
||||||
@ParametersNotNullByDefault
|
|
||||||
class ConnectorGroup extends Thread implements InvitationTask,
|
|
||||||
ContactExchangeListener {
|
|
||||||
|
|
||||||
private static final Logger LOG =
|
|
||||||
Logger.getLogger(ConnectorGroup.class.getName());
|
|
||||||
|
|
||||||
private final CryptoComponent crypto;
|
|
||||||
private final BdfReaderFactory bdfReaderFactory;
|
|
||||||
private final BdfWriterFactory bdfWriterFactory;
|
|
||||||
private final ContactExchangeTask contactExchangeTask;
|
|
||||||
private final IdentityManager identityManager;
|
|
||||||
private final PluginManager pluginManager;
|
|
||||||
private final int localInvitationCode, remoteInvitationCode;
|
|
||||||
private final Collection<InvitationListener> listeners;
|
|
||||||
private final AtomicBoolean connected;
|
|
||||||
private final CountDownLatch localConfirmationLatch;
|
|
||||||
private final Lock lock = new ReentrantLock();
|
|
||||||
|
|
||||||
// The following are locking: lock
|
|
||||||
private int localConfirmationCode = -1, remoteConfirmationCode = -1;
|
|
||||||
private boolean connectionFailed = false;
|
|
||||||
private boolean localCompared = false, remoteCompared = false;
|
|
||||||
private boolean localMatched = false, remoteMatched = false;
|
|
||||||
private String remoteName = null;
|
|
||||||
|
|
||||||
ConnectorGroup(CryptoComponent crypto, BdfReaderFactory bdfReaderFactory,
|
|
||||||
BdfWriterFactory bdfWriterFactory,
|
|
||||||
ContactExchangeTask contactExchangeTask,
|
|
||||||
IdentityManager identityManager, PluginManager pluginManager,
|
|
||||||
int localInvitationCode, int remoteInvitationCode) {
|
|
||||||
super("ConnectorGroup");
|
|
||||||
this.crypto = crypto;
|
|
||||||
this.bdfReaderFactory = bdfReaderFactory;
|
|
||||||
this.bdfWriterFactory = bdfWriterFactory;
|
|
||||||
this.contactExchangeTask = contactExchangeTask;
|
|
||||||
this.identityManager = identityManager;
|
|
||||||
this.pluginManager = pluginManager;
|
|
||||||
this.localInvitationCode = localInvitationCode;
|
|
||||||
this.remoteInvitationCode = remoteInvitationCode;
|
|
||||||
listeners = new CopyOnWriteArrayList<InvitationListener>();
|
|
||||||
connected = new AtomicBoolean(false);
|
|
||||||
localConfirmationLatch = new CountDownLatch(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public InvitationState addListener(InvitationListener l) {
|
|
||||||
lock.lock();
|
|
||||||
try {
|
|
||||||
listeners.add(l);
|
|
||||||
return new InvitationState(localInvitationCode,
|
|
||||||
remoteInvitationCode, localConfirmationCode,
|
|
||||||
remoteConfirmationCode, connected.get(), connectionFailed,
|
|
||||||
localCompared, remoteCompared, localMatched, remoteMatched,
|
|
||||||
remoteName);
|
|
||||||
} finally {
|
|
||||||
lock.unlock();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void removeListener(InvitationListener l) {
|
|
||||||
listeners.remove(l);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void connect() {
|
|
||||||
start();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
LocalAuthor localAuthor;
|
|
||||||
// Load the local pseudonym
|
|
||||||
try {
|
|
||||||
localAuthor = identityManager.getLocalAuthor();
|
|
||||||
} catch (DbException e) {
|
|
||||||
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
|
||||||
lock.lock();
|
|
||||||
try {
|
|
||||||
connectionFailed = true;
|
|
||||||
} finally {
|
|
||||||
lock.unlock();
|
|
||||||
}
|
|
||||||
for (InvitationListener l : listeners) l.connectionFailed();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
// Start the connection threads
|
|
||||||
Collection<Connector> connectors = new ArrayList<Connector>();
|
|
||||||
// Alice is the party with the smaller invitation code
|
|
||||||
if (localInvitationCode < remoteInvitationCode) {
|
|
||||||
for (DuplexPlugin plugin : pluginManager.getInvitationPlugins()) {
|
|
||||||
Connector c = createAliceConnector(plugin, localAuthor);
|
|
||||||
connectors.add(c);
|
|
||||||
c.start();
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
for (DuplexPlugin plugin : pluginManager.getInvitationPlugins()) {
|
|
||||||
Connector c = createBobConnector(plugin, localAuthor);
|
|
||||||
connectors.add(c);
|
|
||||||
c.start();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Wait for the connection threads to finish
|
|
||||||
try {
|
|
||||||
for (Connector c : connectors) c.join();
|
|
||||||
} catch (InterruptedException e) {
|
|
||||||
LOG.warning("Interrupted while waiting for connectors");
|
|
||||||
Thread.currentThread().interrupt();
|
|
||||||
}
|
|
||||||
// If none of the threads connected, inform the listeners
|
|
||||||
if (!connected.get()) {
|
|
||||||
lock.lock();
|
|
||||||
try {
|
|
||||||
connectionFailed = true;
|
|
||||||
} finally {
|
|
||||||
lock.unlock();
|
|
||||||
}
|
|
||||||
for (InvitationListener l : listeners) l.connectionFailed();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private Connector createAliceConnector(DuplexPlugin plugin,
|
|
||||||
LocalAuthor localAuthor) {
|
|
||||||
PseudoRandom random = crypto.getPseudoRandom(localInvitationCode,
|
|
||||||
remoteInvitationCode);
|
|
||||||
return new AliceConnector(crypto, bdfReaderFactory, bdfWriterFactory,
|
|
||||||
contactExchangeTask, this, plugin, localAuthor, random);
|
|
||||||
}
|
|
||||||
|
|
||||||
private Connector createBobConnector(DuplexPlugin plugin,
|
|
||||||
LocalAuthor localAuthor) {
|
|
||||||
PseudoRandom random = crypto.getPseudoRandom(remoteInvitationCode,
|
|
||||||
localInvitationCode);
|
|
||||||
return new BobConnector(crypto, bdfReaderFactory, bdfWriterFactory,
|
|
||||||
contactExchangeTask, this, plugin, localAuthor, random);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void localConfirmationSucceeded() {
|
|
||||||
lock.lock();
|
|
||||||
try {
|
|
||||||
localCompared = true;
|
|
||||||
localMatched = true;
|
|
||||||
} finally {
|
|
||||||
lock.unlock();
|
|
||||||
}
|
|
||||||
localConfirmationLatch.countDown();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void localConfirmationFailed() {
|
|
||||||
lock.lock();
|
|
||||||
try {
|
|
||||||
localCompared = true;
|
|
||||||
localMatched = false;
|
|
||||||
} finally {
|
|
||||||
lock.unlock();
|
|
||||||
}
|
|
||||||
localConfirmationLatch.countDown();
|
|
||||||
}
|
|
||||||
|
|
||||||
boolean getAndSetConnected() {
|
|
||||||
boolean redundant = connected.getAndSet(true);
|
|
||||||
if (!redundant)
|
|
||||||
for (InvitationListener l : listeners) l.connectionSucceeded();
|
|
||||||
return redundant;
|
|
||||||
}
|
|
||||||
|
|
||||||
void keyAgreementSucceeded(int localCode, int remoteCode) {
|
|
||||||
lock.lock();
|
|
||||||
try {
|
|
||||||
localConfirmationCode = localCode;
|
|
||||||
remoteConfirmationCode = remoteCode;
|
|
||||||
} finally {
|
|
||||||
lock.unlock();
|
|
||||||
}
|
|
||||||
for (InvitationListener l : listeners)
|
|
||||||
l.keyAgreementSucceeded(localCode, remoteCode);
|
|
||||||
}
|
|
||||||
|
|
||||||
void keyAgreementFailed() {
|
|
||||||
for (InvitationListener l : listeners) l.keyAgreementFailed();
|
|
||||||
}
|
|
||||||
|
|
||||||
boolean waitForLocalConfirmationResult() throws InterruptedException {
|
|
||||||
localConfirmationLatch.await(CONFIRMATION_TIMEOUT, MILLISECONDS);
|
|
||||||
lock.lock();
|
|
||||||
try {
|
|
||||||
return localMatched;
|
|
||||||
} finally {
|
|
||||||
lock.unlock();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void remoteConfirmationSucceeded() {
|
|
||||||
lock.lock();
|
|
||||||
try {
|
|
||||||
remoteCompared = true;
|
|
||||||
remoteMatched = true;
|
|
||||||
} finally {
|
|
||||||
lock.unlock();
|
|
||||||
}
|
|
||||||
for (InvitationListener l : listeners) l.remoteConfirmationSucceeded();
|
|
||||||
}
|
|
||||||
|
|
||||||
void remoteConfirmationFailed() {
|
|
||||||
lock.lock();
|
|
||||||
try {
|
|
||||||
remoteCompared = true;
|
|
||||||
remoteMatched = false;
|
|
||||||
} finally {
|
|
||||||
lock.unlock();
|
|
||||||
}
|
|
||||||
for (InvitationListener l : listeners) l.remoteConfirmationFailed();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void contactExchangeSucceeded(Author remoteAuthor) {
|
|
||||||
String name = remoteAuthor.getName();
|
|
||||||
lock.lock();
|
|
||||||
try {
|
|
||||||
remoteName = name;
|
|
||||||
} finally {
|
|
||||||
lock.unlock();
|
|
||||||
}
|
|
||||||
for (InvitationListener l : listeners)
|
|
||||||
l.pseudonymExchangeSucceeded(name);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void duplicateContact(Author remoteAuthor) {
|
|
||||||
// TODO differentiate
|
|
||||||
for (InvitationListener l : listeners) l.pseudonymExchangeFailed();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void contactExchangeFailed() {
|
|
||||||
for (InvitationListener l : listeners) l.pseudonymExchangeFailed();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,16 +0,0 @@
|
|||||||
package org.briarproject.bramble.invitation;
|
|
||||||
|
|
||||||
import org.briarproject.bramble.api.invitation.InvitationTaskFactory;
|
|
||||||
|
|
||||||
import dagger.Module;
|
|
||||||
import dagger.Provides;
|
|
||||||
|
|
||||||
@Module
|
|
||||||
public class InvitationModule {
|
|
||||||
|
|
||||||
@Provides
|
|
||||||
InvitationTaskFactory provideInvitationTaskFactory(
|
|
||||||
InvitationTaskFactoryImpl invitationTaskFactory) {
|
|
||||||
return invitationTaskFactory;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,47 +0,0 @@
|
|||||||
package org.briarproject.bramble.invitation;
|
|
||||||
|
|
||||||
import org.briarproject.bramble.api.contact.ContactExchangeTask;
|
|
||||||
import org.briarproject.bramble.api.crypto.CryptoComponent;
|
|
||||||
import org.briarproject.bramble.api.data.BdfReaderFactory;
|
|
||||||
import org.briarproject.bramble.api.data.BdfWriterFactory;
|
|
||||||
import org.briarproject.bramble.api.identity.IdentityManager;
|
|
||||||
import org.briarproject.bramble.api.invitation.InvitationTask;
|
|
||||||
import org.briarproject.bramble.api.invitation.InvitationTaskFactory;
|
|
||||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
|
||||||
import org.briarproject.bramble.api.plugin.PluginManager;
|
|
||||||
|
|
||||||
import javax.annotation.concurrent.Immutable;
|
|
||||||
import javax.inject.Inject;
|
|
||||||
|
|
||||||
@Immutable
|
|
||||||
@NotNullByDefault
|
|
||||||
class InvitationTaskFactoryImpl implements InvitationTaskFactory {
|
|
||||||
|
|
||||||
private final CryptoComponent crypto;
|
|
||||||
private final BdfReaderFactory bdfReaderFactory;
|
|
||||||
private final BdfWriterFactory bdfWriterFactory;
|
|
||||||
private final ContactExchangeTask contactExchangeTask;
|
|
||||||
private final IdentityManager identityManager;
|
|
||||||
private final PluginManager pluginManager;
|
|
||||||
|
|
||||||
@Inject
|
|
||||||
InvitationTaskFactoryImpl(CryptoComponent crypto,
|
|
||||||
BdfReaderFactory bdfReaderFactory,
|
|
||||||
BdfWriterFactory bdfWriterFactory,
|
|
||||||
ContactExchangeTask contactExchangeTask,
|
|
||||||
IdentityManager identityManager, PluginManager pluginManager) {
|
|
||||||
this.crypto = crypto;
|
|
||||||
this.bdfReaderFactory = bdfReaderFactory;
|
|
||||||
this.bdfWriterFactory = bdfWriterFactory;
|
|
||||||
this.contactExchangeTask = contactExchangeTask;
|
|
||||||
this.identityManager = identityManager;
|
|
||||||
this.pluginManager = pluginManager;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public InvitationTask createTask(int localCode, int remoteCode) {
|
|
||||||
return new ConnectorGroup(crypto, bdfReaderFactory, bdfWriterFactory,
|
|
||||||
contactExchangeTask, identityManager, pluginManager,
|
|
||||||
localCode, remoteCode);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -164,14 +164,6 @@ class PluginManagerImpl implements PluginManager, Service {
|
|||||||
return new ArrayList<DuplexPlugin>(duplexPlugins);
|
return new ArrayList<DuplexPlugin>(duplexPlugins);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public Collection<DuplexPlugin> getInvitationPlugins() {
|
|
||||||
List<DuplexPlugin> supported = new ArrayList<DuplexPlugin>();
|
|
||||||
for (DuplexPlugin d : duplexPlugins)
|
|
||||||
if (d.supportsInvitations()) supported.add(d);
|
|
||||||
return supported;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Collection<DuplexPlugin> getKeyAgreementPlugins() {
|
public Collection<DuplexPlugin> getKeyAgreementPlugins() {
|
||||||
List<DuplexPlugin> supported = new ArrayList<DuplexPlugin>();
|
List<DuplexPlugin> supported = new ArrayList<DuplexPlugin>();
|
||||||
@@ -291,6 +283,16 @@ class PluginManagerImpl implements PluginManager, Service {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@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 {
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
package org.briarproject.bramble.plugin.tcp;
|
package org.briarproject.bramble.plugin.tcp;
|
||||||
|
|
||||||
import org.briarproject.bramble.api.FormatException;
|
import org.briarproject.bramble.api.FormatException;
|
||||||
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.KeyAgreementConnection;
|
import org.briarproject.bramble.api.keyagreement.KeyAgreementConnection;
|
||||||
import org.briarproject.bramble.api.keyagreement.KeyAgreementListener;
|
import org.briarproject.bramble.api.keyagreement.KeyAgreementListener;
|
||||||
@@ -35,6 +34,7 @@ import static java.util.logging.Level.WARNING;
|
|||||||
import static org.briarproject.bramble.api.keyagreement.KeyAgreementConstants.TRANSPORT_ID_LAN;
|
import static org.briarproject.bramble.api.keyagreement.KeyAgreementConstants.TRANSPORT_ID_LAN;
|
||||||
import static org.briarproject.bramble.api.plugin.LanTcpConstants.ID;
|
import static org.briarproject.bramble.api.plugin.LanTcpConstants.ID;
|
||||||
import static org.briarproject.bramble.api.plugin.LanTcpConstants.PREF_LAN_IP_PORTS;
|
import static org.briarproject.bramble.api.plugin.LanTcpConstants.PREF_LAN_IP_PORTS;
|
||||||
|
import static org.briarproject.bramble.api.plugin.LanTcpConstants.PROP_IP_PORTS;
|
||||||
import static org.briarproject.bramble.util.ByteUtils.MAX_16_BIT_UNSIGNED;
|
import static org.briarproject.bramble.util.ByteUtils.MAX_16_BIT_UNSIGNED;
|
||||||
import static org.briarproject.bramble.util.PrivacyUtils.scrubSocketAddress;
|
import static org.briarproject.bramble.util.PrivacyUtils.scrubSocketAddress;
|
||||||
|
|
||||||
@@ -45,7 +45,6 @@ class LanTcpPlugin extends TcpPlugin {
|
|||||||
Logger.getLogger(LanTcpPlugin.class.getName());
|
Logger.getLogger(LanTcpPlugin.class.getName());
|
||||||
|
|
||||||
private static final int MAX_ADDRESSES = 4;
|
private static final int MAX_ADDRESSES = 4;
|
||||||
private static final String PROP_IP_PORTS = "ipPorts";
|
|
||||||
private static final String SEPARATOR = ",";
|
private static final String SEPARATOR = ",";
|
||||||
|
|
||||||
LanTcpPlugin(Executor ioExecutor, Backoff backoff,
|
LanTcpPlugin(Executor ioExecutor, Backoff backoff,
|
||||||
@@ -126,9 +125,8 @@ class LanTcpPlugin extends TcpPlugin {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected List<InetSocketAddress> getRemoteSocketAddresses(ContactId c) {
|
protected List<InetSocketAddress> getRemoteSocketAddresses(
|
||||||
TransportProperties p = callback.getRemoteProperties().get(c);
|
TransportProperties p) {
|
||||||
if (p == null) return Collections.emptyList();
|
|
||||||
return parseSocketAddresses(p.get(PROP_IP_PORTS));
|
return parseSocketAddresses(p.get(PROP_IP_PORTS));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
package org.briarproject.bramble.plugin.tcp;
|
package org.briarproject.bramble.plugin.tcp;
|
||||||
|
|
||||||
import org.briarproject.bramble.api.contact.ContactId;
|
import org.briarproject.bramble.api.contact.ContactId;
|
||||||
import org.briarproject.bramble.api.crypto.PseudoRandom;
|
|
||||||
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.MethodsNotNullByDefault;
|
import org.briarproject.bramble.api.nullsafety.MethodsNotNullByDefault;
|
||||||
@@ -10,6 +9,7 @@ import org.briarproject.bramble.api.plugin.Backoff;
|
|||||||
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.DuplexTransportConnection;
|
import org.briarproject.bramble.api.plugin.duplex.DuplexTransportConnection;
|
||||||
|
import org.briarproject.bramble.api.properties.TransportProperties;
|
||||||
import org.briarproject.bramble.util.StringUtils;
|
import org.briarproject.bramble.util.StringUtils;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
@@ -25,6 +25,8 @@ import java.util.ArrayList;
|
|||||||
import java.util.Collection;
|
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.Entry;
|
||||||
import java.util.concurrent.Executor;
|
import java.util.concurrent.Executor;
|
||||||
import java.util.concurrent.atomic.AtomicBoolean;
|
import java.util.concurrent.atomic.AtomicBoolean;
|
||||||
import java.util.logging.Logger;
|
import java.util.logging.Logger;
|
||||||
@@ -67,11 +69,11 @@ abstract class TcpPlugin implements DuplexPlugin {
|
|||||||
protected abstract void setLocalSocketAddress(InetSocketAddress a);
|
protected abstract void setLocalSocketAddress(InetSocketAddress a);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns zero or more socket addresses for connecting to the given
|
* Returns zero or more socket addresses for connecting to a contact with
|
||||||
* contact.
|
* the given transport properties.
|
||||||
*/
|
*/
|
||||||
protected abstract List<InetSocketAddress> getRemoteSocketAddresses(
|
protected abstract List<InetSocketAddress> getRemoteSocketAddresses(
|
||||||
ContactId c);
|
TransportProperties p);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns true if connections to the given address can be attempted.
|
* Returns true if connections to the given address can be attempted.
|
||||||
@@ -208,16 +210,21 @@ abstract class TcpPlugin implements DuplexPlugin {
|
|||||||
public void poll(Collection<ContactId> connected) {
|
public void poll(Collection<ContactId> connected) {
|
||||||
if (!isRunning()) return;
|
if (!isRunning()) return;
|
||||||
backoff.increment();
|
backoff.increment();
|
||||||
// TODO: Pass properties to connectAndCallBack()
|
Map<ContactId, TransportProperties> remote =
|
||||||
for (ContactId c : callback.getRemoteProperties().keySet())
|
callback.getRemoteProperties();
|
||||||
if (!connected.contains(c)) connectAndCallBack(c);
|
for (Entry<ContactId, TransportProperties> e : remote.entrySet()) {
|
||||||
|
ContactId c = e.getKey();
|
||||||
|
if (!connected.contains(c)) connectAndCallBack(c, e.getValue());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void connectAndCallBack(final ContactId c) {
|
private void connectAndCallBack(final ContactId c,
|
||||||
|
final TransportProperties p) {
|
||||||
ioExecutor.execute(new Runnable() {
|
ioExecutor.execute(new Runnable() {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
DuplexTransportConnection d = createConnection(c);
|
if (!isRunning()) return;
|
||||||
|
DuplexTransportConnection d = createConnection(p);
|
||||||
if (d != null) {
|
if (d != null) {
|
||||||
backoff.reset();
|
backoff.reset();
|
||||||
callback.outgoingConnectionCreated(c, d);
|
callback.outgoingConnectionCreated(c, d);
|
||||||
@@ -229,7 +236,12 @@ abstract class TcpPlugin implements DuplexPlugin {
|
|||||||
@Override
|
@Override
|
||||||
public DuplexTransportConnection createConnection(ContactId c) {
|
public DuplexTransportConnection createConnection(ContactId c) {
|
||||||
if (!isRunning()) return null;
|
if (!isRunning()) return null;
|
||||||
for (InetSocketAddress remote : getRemoteSocketAddresses(c)) {
|
return createConnection(callback.getRemoteProperties(c));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
private DuplexTransportConnection createConnection(TransportProperties p) {
|
||||||
|
for (InetSocketAddress remote : getRemoteSocketAddresses(p)) {
|
||||||
if (!isConnectable(remote)) {
|
if (!isConnectable(remote)) {
|
||||||
if (LOG.isLoggable(INFO)) {
|
if (LOG.isLoggable(INFO)) {
|
||||||
SocketAddress local = socket.getLocalSocketAddress();
|
SocketAddress local = socket.getLocalSocketAddress();
|
||||||
@@ -281,17 +293,6 @@ abstract class TcpPlugin implements DuplexPlugin {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean supportsInvitations() {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public DuplexTransportConnection createInvitationConnection(PseudoRandom r,
|
|
||||||
long timeout, boolean alice) {
|
|
||||||
throw new UnsupportedOperationException();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean supportsKeyAgreement() {
|
public boolean supportsKeyAgreement() {
|
||||||
return false;
|
return false;
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ package org.briarproject.bramble.plugin.tcp;
|
|||||||
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.duplex.AbstractDuplexTransportConnection;
|
import org.briarproject.bramble.api.plugin.duplex.AbstractDuplexTransportConnection;
|
||||||
|
import org.briarproject.bramble.util.IoUtils;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
@@ -24,12 +25,12 @@ class TcpTransportConnection extends AbstractDuplexTransportConnection {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected InputStream getInputStream() throws IOException {
|
protected InputStream getInputStream() throws IOException {
|
||||||
return socket.getInputStream();
|
return IoUtils.getInputStream(socket);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected OutputStream getOutputStream() throws IOException {
|
protected OutputStream getOutputStream() throws IOException {
|
||||||
return socket.getOutputStream();
|
return IoUtils.getOutputStream(socket);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
package org.briarproject.bramble.plugin.tcp;
|
package org.briarproject.bramble.plugin.tcp;
|
||||||
|
|
||||||
import org.briarproject.bramble.api.contact.ContactId;
|
|
||||||
import org.briarproject.bramble.api.nullsafety.MethodsNotNullByDefault;
|
import org.briarproject.bramble.api.nullsafety.MethodsNotNullByDefault;
|
||||||
import org.briarproject.bramble.api.nullsafety.ParametersNotNullByDefault;
|
import org.briarproject.bramble.api.nullsafety.ParametersNotNullByDefault;
|
||||||
import org.briarproject.bramble.api.plugin.Backoff;
|
import org.briarproject.bramble.api.plugin.Backoff;
|
||||||
@@ -78,9 +77,8 @@ class WanTcpPlugin extends TcpPlugin {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected List<InetSocketAddress> getRemoteSocketAddresses(ContactId c) {
|
protected List<InetSocketAddress> getRemoteSocketAddresses(
|
||||||
TransportProperties p = callback.getRemoteProperties().get(c);
|
TransportProperties p) {
|
||||||
if (p == null) return Collections.emptyList();
|
|
||||||
InetSocketAddress parsed = parseSocketAddress(p.get(PROP_IP_PORT));
|
InetSocketAddress parsed = parseSocketAddress(p.get(PROP_IP_PORT));
|
||||||
if (parsed == null) return Collections.emptyList();
|
if (parsed == null) return Collections.emptyList();
|
||||||
return Collections.singletonList(parsed);
|
return Collections.singletonList(parsed);
|
||||||
|
|||||||
@@ -160,35 +160,52 @@ class TransportPropertyManagerImpl implements TransportPropertyManager,
|
|||||||
@Override
|
@Override
|
||||||
public Map<ContactId, TransportProperties> getRemoteProperties(
|
public Map<ContactId, TransportProperties> getRemoteProperties(
|
||||||
TransportId t) throws DbException {
|
TransportId t) throws DbException {
|
||||||
|
Map<ContactId, TransportProperties> remote =
|
||||||
|
new HashMap<ContactId, TransportProperties>();
|
||||||
|
Transaction txn = db.startTransaction(true);
|
||||||
try {
|
try {
|
||||||
Map<ContactId, TransportProperties> remote =
|
for (Contact c : db.getContacts(txn))
|
||||||
new HashMap<ContactId, TransportProperties>();
|
remote.put(c.getId(), getRemoteProperties(txn, c, t));
|
||||||
Transaction txn = db.startTransaction(true);
|
db.commitTransaction(txn);
|
||||||
try {
|
} finally {
|
||||||
for (Contact c : db.getContacts(txn)) {
|
db.endTransaction(txn);
|
||||||
// Don't return properties for inactive contacts
|
}
|
||||||
if (!c.isActive()) continue;
|
return remote;
|
||||||
Group g = getContactGroup(c);
|
}
|
||||||
// Find the latest remote update
|
|
||||||
LatestUpdate latest = findLatest(txn, g.getId(), t, false);
|
private TransportProperties getRemoteProperties(Transaction txn, Contact c,
|
||||||
if (latest != null) {
|
TransportId t) throws DbException {
|
||||||
// Retrieve and parse the latest remote properties
|
// Don't return properties for inactive contacts
|
||||||
BdfList message = clientHelper.getMessageAsList(txn,
|
if (!c.isActive()) return new TransportProperties();
|
||||||
latest.messageId);
|
Group g = getContactGroup(c);
|
||||||
if (message == null) throw new DbException();
|
try {
|
||||||
remote.put(c.getId(), parseProperties(message));
|
// Find the latest remote update
|
||||||
}
|
LatestUpdate latest = findLatest(txn, g.getId(), t, false);
|
||||||
}
|
if (latest == null) return new TransportProperties();
|
||||||
db.commitTransaction(txn);
|
// Retrieve and parse the latest remote properties
|
||||||
} finally {
|
BdfList message =
|
||||||
db.endTransaction(txn);
|
clientHelper.getMessageAsList(txn, latest.messageId);
|
||||||
}
|
if (message == null) throw new DbException();
|
||||||
return remote;
|
return parseProperties(message);
|
||||||
} catch (FormatException e) {
|
} catch (FormatException e) {
|
||||||
throw new DbException(e);
|
throw new DbException(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public TransportProperties getRemoteProperties(ContactId c, TransportId t)
|
||||||
|
throws DbException {
|
||||||
|
TransportProperties p;
|
||||||
|
Transaction txn = db.startTransaction(true);
|
||||||
|
try {
|
||||||
|
p = getRemoteProperties(txn, db.getContact(txn, c), t);
|
||||||
|
db.commitTransaction(txn);
|
||||||
|
} finally {
|
||||||
|
db.endTransaction(txn);
|
||||||
|
}
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void mergeLocalProperties(TransportId t, TransportProperties p)
|
public void mergeLocalProperties(TransportId t, TransportProperties p)
|
||||||
throws DbException {
|
throws DbException {
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package org.briarproject.bramble.reporting;
|
package org.briarproject.bramble.reporting;
|
||||||
|
|
||||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||||
|
import org.briarproject.bramble.util.IoUtils;
|
||||||
|
|
||||||
import java.io.Closeable;
|
import java.io.Closeable;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
@@ -130,7 +131,7 @@ public class DevReportServer {
|
|||||||
OutputStream out = null;
|
OutputStream out = null;
|
||||||
try {
|
try {
|
||||||
socket.setSoTimeout(SOCKET_TIMEOUT_MS);
|
socket.setSoTimeout(SOCKET_TIMEOUT_MS);
|
||||||
in = socket.getInputStream();
|
in = IoUtils.getInputStream(socket);
|
||||||
reportDir.mkdirs();
|
reportDir.mkdirs();
|
||||||
reportFile = File.createTempFile(FILE_PREFIX, FILE_SUFFIX,
|
reportFile = File.createTempFile(FILE_PREFIX, FILE_SUFFIX,
|
||||||
reportDir);
|
reportDir);
|
||||||
|
|||||||
@@ -93,7 +93,7 @@ class DevReporterImpl implements DevReporter {
|
|||||||
InputStream in = null;
|
InputStream in = null;
|
||||||
try {
|
try {
|
||||||
Socket s = connectToDevelopers();
|
Socket s = connectToDevelopers();
|
||||||
out = s.getOutputStream();
|
out = IoUtils.getOutputStream(s);
|
||||||
in = new FileInputStream(f);
|
in = new FileInputStream(f);
|
||||||
IoUtils.copyAndClose(in, out);
|
IoUtils.copyAndClose(in, out);
|
||||||
f.delete();
|
f.delete();
|
||||||
|
|||||||
@@ -57,8 +57,8 @@ class SocksSocket extends Socket {
|
|||||||
|
|
||||||
// Connect to the proxy
|
// Connect to the proxy
|
||||||
super.connect(proxy, connectToProxyTimeout);
|
super.connect(proxy, connectToProxyTimeout);
|
||||||
OutputStream out = getOutputStream();
|
OutputStream out = IoUtils.getOutputStream(this);
|
||||||
InputStream in = getInputStream();
|
InputStream in = IoUtils.getInputStream(this);
|
||||||
|
|
||||||
// Request SOCKS 5 with no authentication
|
// Request SOCKS 5 with no authentication
|
||||||
sendMethodRequest(out);
|
sendMethodRequest(out);
|
||||||
|
|||||||
@@ -29,10 +29,10 @@ class StreamReaderFactoryImpl implements StreamReaderFactory {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public InputStream createInvitationStreamReader(InputStream in,
|
public InputStream createContactExchangeStreamReader(InputStream in,
|
||||||
SecretKey headerKey) {
|
SecretKey headerKey) {
|
||||||
return new StreamReaderImpl(
|
return new StreamReaderImpl(
|
||||||
streamDecrypterFactory.createInvitationStreamDecrypter(in,
|
streamDecrypterFactory.createContactExchangeStreamDecrypter(in,
|
||||||
headerKey));
|
headerKey));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -30,10 +30,10 @@ class StreamWriterFactoryImpl implements StreamWriterFactory {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public OutputStream createInvitationStreamWriter(OutputStream out,
|
public OutputStream createContactExchangeStreamWriter(OutputStream out,
|
||||||
SecretKey headerKey) {
|
SecretKey headerKey) {
|
||||||
return new StreamWriterImpl(
|
return new StreamWriterImpl(
|
||||||
streamEncrypterFactory.createInvitationStreamEncrypter(out,
|
streamEncrypterFactory.createContactExchangeStreamDecrypter(out,
|
||||||
headerKey));
|
headerKey));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -29,6 +29,7 @@ import javax.annotation.concurrent.ThreadSafe;
|
|||||||
import static java.util.concurrent.TimeUnit.MILLISECONDS;
|
import static java.util.concurrent.TimeUnit.MILLISECONDS;
|
||||||
import static java.util.logging.Level.WARNING;
|
import static java.util.logging.Level.WARNING;
|
||||||
import static org.briarproject.bramble.api.transport.TransportConstants.MAX_CLOCK_DIFFERENCE;
|
import static org.briarproject.bramble.api.transport.TransportConstants.MAX_CLOCK_DIFFERENCE;
|
||||||
|
import static org.briarproject.bramble.api.transport.TransportConstants.PROTOCOL_VERSION;
|
||||||
import static org.briarproject.bramble.api.transport.TransportConstants.TAG_LENGTH;
|
import static org.briarproject.bramble.api.transport.TransportConstants.TAG_LENGTH;
|
||||||
import static org.briarproject.bramble.util.ByteUtils.MAX_32_BIT_UNSIGNED;
|
import static org.briarproject.bramble.util.ByteUtils.MAX_32_BIT_UNSIGNED;
|
||||||
|
|
||||||
@@ -126,7 +127,8 @@ class TransportKeyManagerImpl implements TransportKeyManager {
|
|||||||
for (long streamNumber : inKeys.getWindow().getUnseen()) {
|
for (long streamNumber : inKeys.getWindow().getUnseen()) {
|
||||||
TagContext tagCtx = new TagContext(c, inKeys, streamNumber);
|
TagContext tagCtx = new TagContext(c, inKeys, streamNumber);
|
||||||
byte[] tag = new byte[TAG_LENGTH];
|
byte[] tag = new byte[TAG_LENGTH];
|
||||||
crypto.encodeTag(tag, inKeys.getTagKey(), streamNumber);
|
crypto.encodeTag(tag, inKeys.getTagKey(), PROTOCOL_VERSION,
|
||||||
|
streamNumber);
|
||||||
inContexts.put(new Bytes(tag), tagCtx);
|
inContexts.put(new Bytes(tag), tagCtx);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -242,7 +244,8 @@ class TransportKeyManagerImpl implements TransportKeyManager {
|
|||||||
// Add tags for any stream numbers added to the window
|
// Add tags for any stream numbers added to the window
|
||||||
for (long streamNumber : change.getAdded()) {
|
for (long streamNumber : change.getAdded()) {
|
||||||
byte[] addTag = new byte[TAG_LENGTH];
|
byte[] addTag = new byte[TAG_LENGTH];
|
||||||
crypto.encodeTag(addTag, inKeys.getTagKey(), streamNumber);
|
crypto.encodeTag(addTag, inKeys.getTagKey(), PROTOCOL_VERSION,
|
||||||
|
streamNumber);
|
||||||
inContexts.put(new Bytes(addTag), new TagContext(
|
inContexts.put(new Bytes(addTag), new TagContext(
|
||||||
tagCtx.contactId, inKeys, streamNumber));
|
tagCtx.contactId, inKeys, streamNumber));
|
||||||
}
|
}
|
||||||
@@ -250,7 +253,8 @@ class TransportKeyManagerImpl implements TransportKeyManager {
|
|||||||
for (long streamNumber : change.getRemoved()) {
|
for (long streamNumber : change.getRemoved()) {
|
||||||
if (streamNumber == tagCtx.streamNumber) continue;
|
if (streamNumber == tagCtx.streamNumber) continue;
|
||||||
byte[] removeTag = new byte[TAG_LENGTH];
|
byte[] removeTag = new byte[TAG_LENGTH];
|
||||||
crypto.encodeTag(removeTag, inKeys.getTagKey(), streamNumber);
|
crypto.encodeTag(removeTag, inKeys.getTagKey(),
|
||||||
|
PROTOCOL_VERSION, streamNumber);
|
||||||
inContexts.remove(new Bytes(removeTag));
|
inContexts.remove(new Bytes(removeTag));
|
||||||
}
|
}
|
||||||
// Write the window back to the DB
|
// Write the window back to the DB
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ import org.briarproject.bramble.api.sync.Message;
|
|||||||
import org.briarproject.bramble.api.sync.MessageFactory;
|
import org.briarproject.bramble.api.sync.MessageFactory;
|
||||||
import org.briarproject.bramble.api.sync.MessageId;
|
import org.briarproject.bramble.api.sync.MessageId;
|
||||||
import org.briarproject.bramble.test.BrambleTestCase;
|
import org.briarproject.bramble.test.BrambleTestCase;
|
||||||
import org.briarproject.bramble.test.TestUtils;
|
import org.briarproject.bramble.util.StringUtils;
|
||||||
import org.jmock.Expectations;
|
import org.jmock.Expectations;
|
||||||
import org.jmock.Mockery;
|
import org.jmock.Mockery;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
@@ -65,7 +65,7 @@ public class ClientHelperImplTest extends BrambleTestCase {
|
|||||||
new Message(messageId, groupId, timestamp, rawMessage);
|
new Message(messageId, groupId, timestamp, rawMessage);
|
||||||
private final Metadata metadata = new Metadata();
|
private final Metadata metadata = new Metadata();
|
||||||
private final BdfList list = BdfList.of("Sign this!", getRandomBytes(42));
|
private final BdfList list = BdfList.of("Sign this!", getRandomBytes(42));
|
||||||
private final String label = TestUtils.getRandomString(5);
|
private final String label = StringUtils.getRandomString(5);
|
||||||
|
|
||||||
public ClientHelperImplTest() {
|
public ClientHelperImplTest() {
|
||||||
clientHelper =
|
clientHelper =
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import org.briarproject.bramble.api.crypto.CryptoComponent;
|
|||||||
import org.briarproject.bramble.test.BrambleTestCase;
|
import org.briarproject.bramble.test.BrambleTestCase;
|
||||||
import org.briarproject.bramble.test.TestSecureRandomProvider;
|
import org.briarproject.bramble.test.TestSecureRandomProvider;
|
||||||
import org.briarproject.bramble.test.TestUtils;
|
import org.briarproject.bramble.test.TestUtils;
|
||||||
|
import org.briarproject.bramble.util.StringUtils;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
@@ -15,7 +16,7 @@ public class HashTest extends BrambleTestCase {
|
|||||||
|
|
||||||
private final CryptoComponent crypto;
|
private final CryptoComponent crypto;
|
||||||
|
|
||||||
private final String label = TestUtils.getRandomString(42);
|
private final String label = StringUtils.getRandomString(42);
|
||||||
private final byte[] inputBytes = TestUtils.getRandomBytes(123);
|
private final byte[] inputBytes = TestUtils.getRandomBytes(123);
|
||||||
private final byte[] inputBytes1 = TestUtils.getRandomBytes(234);
|
private final byte[] inputBytes1 = TestUtils.getRandomBytes(234);
|
||||||
private final byte[] inputBytes2 = new byte[0];
|
private final byte[] inputBytes2 = new byte[0];
|
||||||
@@ -40,7 +41,7 @@ public class HashTest extends BrambleTestCase {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testDifferentLabelsProduceDifferentHashes() {
|
public void testDifferentLabelsProduceDifferentHashes() {
|
||||||
String label2 = TestUtils.getRandomString(42);
|
String label2 = StringUtils.getRandomString(42);
|
||||||
byte[] hash1 = crypto.hash(label, inputBytes, inputBytes1, inputBytes2);
|
byte[] hash1 = crypto.hash(label, inputBytes, inputBytes1, inputBytes2);
|
||||||
byte[] hash2 =
|
byte[] hash2 =
|
||||||
crypto.hash(label2, inputBytes, inputBytes1, inputBytes2);
|
crypto.hash(label2, inputBytes, inputBytes1, inputBytes2);
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
package org.briarproject.bramble.crypto;
|
package org.briarproject.bramble.crypto;
|
||||||
|
|
||||||
import org.briarproject.bramble.api.crypto.PseudoRandom;
|
|
||||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||||
import org.spongycastle.crypto.Digest;
|
import org.spongycastle.crypto.Digest;
|
||||||
import org.spongycastle.crypto.engines.Salsa20Engine;
|
import org.spongycastle.crypto.engines.Salsa20Engine;
|
||||||
@@ -11,11 +10,11 @@ import javax.annotation.concurrent.NotThreadSafe;
|
|||||||
|
|
||||||
@NotThreadSafe
|
@NotThreadSafe
|
||||||
@NotNullByDefault
|
@NotNullByDefault
|
||||||
class PseudoRandomImpl implements PseudoRandom {
|
class PseudoRandom {
|
||||||
|
|
||||||
private final Salsa20Engine cipher = new Salsa20Engine();
|
private final Salsa20Engine cipher = new Salsa20Engine();
|
||||||
|
|
||||||
PseudoRandomImpl(byte[] seed) {
|
PseudoRandom(byte[] seed) {
|
||||||
// Hash the seed to produce a 32-byte key
|
// Hash the seed to produce a 32-byte key
|
||||||
byte[] key = new byte[32];
|
byte[] key = new byte[32];
|
||||||
Digest digest = new Blake2sDigest();
|
Digest digest = new Blake2sDigest();
|
||||||
@@ -26,8 +25,7 @@ class PseudoRandomImpl implements PseudoRandom {
|
|||||||
cipher.init(true, new ParametersWithIV(new KeyParameter(key), nonce));
|
cipher.init(true, new ParametersWithIV(new KeyParameter(key), nonce));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
byte[] nextBytes(int length) {
|
||||||
public byte[] nextBytes(int length) {
|
|
||||||
byte[] in = new byte[length], out = new byte[length];
|
byte[] in = new byte[length], out = new byte[length];
|
||||||
cipher.processBytes(in, 0, length, out, 0);
|
cipher.processBytes(in, 0, length, out, 0);
|
||||||
return out;
|
return out;
|
||||||
@@ -1,7 +1,5 @@
|
|||||||
package org.briarproject.bramble.crypto;
|
package org.briarproject.bramble.crypto;
|
||||||
|
|
||||||
import org.briarproject.bramble.api.crypto.PseudoRandom;
|
|
||||||
|
|
||||||
import java.security.Provider;
|
import java.security.Provider;
|
||||||
import java.security.SecureRandom;
|
import java.security.SecureRandom;
|
||||||
import java.security.SecureRandomSpi;
|
import java.security.SecureRandomSpi;
|
||||||
@@ -19,7 +17,7 @@ class PseudoSecureRandom extends SecureRandom {
|
|||||||
private final PseudoRandom pseudoRandom;
|
private final PseudoRandom pseudoRandom;
|
||||||
|
|
||||||
private PseudoSecureRandomSpi(byte[] seed) {
|
private PseudoSecureRandomSpi(byte[] seed) {
|
||||||
pseudoRandom = new PseudoRandomImpl(seed);
|
pseudoRandom = new PseudoRandom(seed);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import org.briarproject.bramble.api.crypto.KeyPair;
|
|||||||
import org.briarproject.bramble.test.BrambleTestCase;
|
import org.briarproject.bramble.test.BrambleTestCase;
|
||||||
import org.briarproject.bramble.test.TestSecureRandomProvider;
|
import org.briarproject.bramble.test.TestSecureRandomProvider;
|
||||||
import org.briarproject.bramble.test.TestUtils;
|
import org.briarproject.bramble.test.TestUtils;
|
||||||
|
import org.briarproject.bramble.util.StringUtils;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
@@ -18,7 +19,7 @@ public class SignatureTest extends BrambleTestCase {
|
|||||||
private final CryptoComponent crypto;
|
private final CryptoComponent crypto;
|
||||||
|
|
||||||
private final byte[] publicKey, privateKey;
|
private final byte[] publicKey, privateKey;
|
||||||
private final String label = TestUtils.getRandomString(42);
|
private final String label = StringUtils.getRandomString(42);
|
||||||
private final byte[] inputBytes = TestUtils.getRandomBytes(123);
|
private final byte[] inputBytes = TestUtils.getRandomBytes(123);
|
||||||
|
|
||||||
public SignatureTest() {
|
public SignatureTest() {
|
||||||
@@ -64,7 +65,7 @@ public class SignatureTest extends BrambleTestCase {
|
|||||||
public void testDifferentLabelsProduceDifferentSignatures()
|
public void testDifferentLabelsProduceDifferentSignatures()
|
||||||
throws Exception {
|
throws Exception {
|
||||||
// Generate a second label
|
// Generate a second label
|
||||||
String label2 = TestUtils.getRandomString(42);
|
String label2 = StringUtils.getRandomString(42);
|
||||||
// Calculate the signature with different inputs
|
// Calculate the signature with different inputs
|
||||||
// the results should be different
|
// the results should be different
|
||||||
byte[] sig1 = crypto.sign(label, inputBytes, privateKey);
|
byte[] sig1 = crypto.sign(label, inputBytes, privateKey);
|
||||||
@@ -100,7 +101,7 @@ public class SignatureTest extends BrambleTestCase {
|
|||||||
@Test
|
@Test
|
||||||
public void testDifferentLabelFailsVerification() throws Exception {
|
public void testDifferentLabelFailsVerification() throws Exception {
|
||||||
// Generate a second label
|
// Generate a second label
|
||||||
String label2 = TestUtils.getRandomString(42);
|
String label2 = StringUtils.getRandomString(42);
|
||||||
// calculate the signature with different label, should fail to verify
|
// calculate the signature with different label, should fail to verify
|
||||||
byte[] sig = crypto.sign(label, inputBytes, privateKey);
|
byte[] sig = crypto.sign(label, inputBytes, privateKey);
|
||||||
assertFalse(crypto.verify(label2, inputBytes, publicKey, sig));
|
assertFalse(crypto.verify(label2, inputBytes, publicKey, sig));
|
||||||
|
|||||||
@@ -14,7 +14,8 @@ import static junit.framework.Assert.assertEquals;
|
|||||||
import static org.briarproject.bramble.api.transport.TransportConstants.FRAME_HEADER_LENGTH;
|
import static org.briarproject.bramble.api.transport.TransportConstants.FRAME_HEADER_LENGTH;
|
||||||
import static org.briarproject.bramble.api.transport.TransportConstants.MAC_LENGTH;
|
import static org.briarproject.bramble.api.transport.TransportConstants.MAC_LENGTH;
|
||||||
import static org.briarproject.bramble.api.transport.TransportConstants.MAX_PAYLOAD_LENGTH;
|
import static org.briarproject.bramble.api.transport.TransportConstants.MAX_PAYLOAD_LENGTH;
|
||||||
import static org.briarproject.bramble.api.transport.TransportConstants.STREAM_HEADER_IV_LENGTH;
|
import static org.briarproject.bramble.api.transport.TransportConstants.PROTOCOL_VERSION;
|
||||||
|
import static org.briarproject.bramble.api.transport.TransportConstants.STREAM_HEADER_NONCE_LENGTH;
|
||||||
import static org.briarproject.bramble.util.ByteUtils.INT_16_BYTES;
|
import static org.briarproject.bramble.util.ByteUtils.INT_16_BYTES;
|
||||||
import static org.junit.Assert.assertArrayEquals;
|
import static org.junit.Assert.assertArrayEquals;
|
||||||
|
|
||||||
@@ -22,7 +23,8 @@ public class StreamDecrypterImplTest extends BrambleTestCase {
|
|||||||
|
|
||||||
private final AuthenticatedCipher cipher;
|
private final AuthenticatedCipher cipher;
|
||||||
private final SecretKey streamHeaderKey, frameKey;
|
private final SecretKey streamHeaderKey, frameKey;
|
||||||
private final byte[] streamHeaderIv, payload;
|
private final byte[] streamHeaderNonce, protocolVersionBytes;
|
||||||
|
private final byte[] streamNumberBytes, payload;
|
||||||
private final int payloadLength = 123, paddingLength = 234;
|
private final int payloadLength = 123, paddingLength = 234;
|
||||||
private final long streamNumber = 1234;
|
private final long streamNumber = 1234;
|
||||||
|
|
||||||
@@ -30,7 +32,12 @@ public class StreamDecrypterImplTest extends BrambleTestCase {
|
|||||||
cipher = new TestAuthenticatedCipher(); // Null cipher
|
cipher = new TestAuthenticatedCipher(); // Null cipher
|
||||||
streamHeaderKey = TestUtils.getSecretKey();
|
streamHeaderKey = TestUtils.getSecretKey();
|
||||||
frameKey = TestUtils.getSecretKey();
|
frameKey = TestUtils.getSecretKey();
|
||||||
streamHeaderIv = TestUtils.getRandomBytes(STREAM_HEADER_IV_LENGTH);
|
streamHeaderNonce =
|
||||||
|
TestUtils.getRandomBytes(STREAM_HEADER_NONCE_LENGTH);
|
||||||
|
protocolVersionBytes = new byte[2];
|
||||||
|
ByteUtils.writeUint16(PROTOCOL_VERSION, protocolVersionBytes, 0);
|
||||||
|
streamNumberBytes = new byte[8];
|
||||||
|
ByteUtils.writeUint64(streamNumber, streamNumberBytes, 0);
|
||||||
payload = TestUtils.getRandomBytes(payloadLength);
|
payload = TestUtils.getRandomBytes(payloadLength);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -47,7 +54,9 @@ public class StreamDecrypterImplTest extends BrambleTestCase {
|
|||||||
byte[] payload1 = TestUtils.getRandomBytes(payloadLength1);
|
byte[] payload1 = TestUtils.getRandomBytes(payloadLength1);
|
||||||
|
|
||||||
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||||
out.write(streamHeaderIv);
|
out.write(streamHeaderNonce);
|
||||||
|
out.write(protocolVersionBytes);
|
||||||
|
out.write(streamNumberBytes);
|
||||||
out.write(frameKey.getBytes());
|
out.write(frameKey.getBytes());
|
||||||
out.write(new byte[MAC_LENGTH]);
|
out.write(new byte[MAC_LENGTH]);
|
||||||
out.write(frameHeader);
|
out.write(frameHeader);
|
||||||
@@ -76,6 +85,85 @@ public class StreamDecrypterImplTest extends BrambleTestCase {
|
|||||||
assertEquals(-1, s.readFrame(buffer));
|
assertEquals(-1, s.readFrame(buffer));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test(expected = IOException.class)
|
||||||
|
public void testWrongProtocolVersionThrowsException() throws Exception {
|
||||||
|
byte[] wrongProtocolVersionBytes = new byte[2];
|
||||||
|
ByteUtils.writeUint16(PROTOCOL_VERSION + 1, wrongProtocolVersionBytes,
|
||||||
|
0);
|
||||||
|
|
||||||
|
byte[] frameHeader = new byte[FRAME_HEADER_LENGTH];
|
||||||
|
FrameEncoder.encodeHeader(frameHeader, false, payloadLength,
|
||||||
|
paddingLength);
|
||||||
|
|
||||||
|
byte[] frameHeader1 = new byte[FRAME_HEADER_LENGTH];
|
||||||
|
int payloadLength1 = 345, paddingLength1 = 456;
|
||||||
|
FrameEncoder.encodeHeader(frameHeader1, true, payloadLength1,
|
||||||
|
paddingLength1);
|
||||||
|
byte[] payload1 = TestUtils.getRandomBytes(payloadLength1);
|
||||||
|
|
||||||
|
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||||
|
out.write(streamHeaderNonce);
|
||||||
|
out.write(wrongProtocolVersionBytes);
|
||||||
|
out.write(streamNumberBytes);
|
||||||
|
out.write(frameKey.getBytes());
|
||||||
|
out.write(new byte[MAC_LENGTH]);
|
||||||
|
out.write(frameHeader);
|
||||||
|
out.write(payload);
|
||||||
|
out.write(new byte[paddingLength]);
|
||||||
|
out.write(new byte[MAC_LENGTH]);
|
||||||
|
out.write(frameHeader1);
|
||||||
|
out.write(payload1);
|
||||||
|
out.write(new byte[paddingLength1]);
|
||||||
|
out.write(new byte[MAC_LENGTH]);
|
||||||
|
|
||||||
|
ByteArrayInputStream in = new ByteArrayInputStream(out.toByteArray());
|
||||||
|
StreamDecrypterImpl s = new StreamDecrypterImpl(in, cipher,
|
||||||
|
streamNumber, streamHeaderKey);
|
||||||
|
|
||||||
|
// Try to read the first frame
|
||||||
|
byte[] buffer = new byte[MAX_PAYLOAD_LENGTH];
|
||||||
|
s.readFrame(buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expected = IOException.class)
|
||||||
|
public void testWrongStreamNumberThrowsException() throws Exception {
|
||||||
|
byte[] wrongStreamNumberBytes = new byte[8];
|
||||||
|
ByteUtils.writeUint64(streamNumber + 1, wrongStreamNumberBytes, 0);
|
||||||
|
|
||||||
|
byte[] frameHeader = new byte[FRAME_HEADER_LENGTH];
|
||||||
|
FrameEncoder.encodeHeader(frameHeader, false, payloadLength,
|
||||||
|
paddingLength);
|
||||||
|
|
||||||
|
byte[] frameHeader1 = new byte[FRAME_HEADER_LENGTH];
|
||||||
|
int payloadLength1 = 345, paddingLength1 = 456;
|
||||||
|
FrameEncoder.encodeHeader(frameHeader1, true, payloadLength1,
|
||||||
|
paddingLength1);
|
||||||
|
byte[] payload1 = TestUtils.getRandomBytes(payloadLength1);
|
||||||
|
|
||||||
|
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||||
|
out.write(streamHeaderNonce);
|
||||||
|
out.write(protocolVersionBytes);
|
||||||
|
out.write(wrongStreamNumberBytes);
|
||||||
|
out.write(frameKey.getBytes());
|
||||||
|
out.write(new byte[MAC_LENGTH]);
|
||||||
|
out.write(frameHeader);
|
||||||
|
out.write(payload);
|
||||||
|
out.write(new byte[paddingLength]);
|
||||||
|
out.write(new byte[MAC_LENGTH]);
|
||||||
|
out.write(frameHeader1);
|
||||||
|
out.write(payload1);
|
||||||
|
out.write(new byte[paddingLength1]);
|
||||||
|
out.write(new byte[MAC_LENGTH]);
|
||||||
|
|
||||||
|
ByteArrayInputStream in = new ByteArrayInputStream(out.toByteArray());
|
||||||
|
StreamDecrypterImpl s = new StreamDecrypterImpl(in, cipher,
|
||||||
|
streamNumber, streamHeaderKey);
|
||||||
|
|
||||||
|
// Try to read the first frame
|
||||||
|
byte[] buffer = new byte[MAX_PAYLOAD_LENGTH];
|
||||||
|
s.readFrame(buffer);
|
||||||
|
}
|
||||||
|
|
||||||
@Test(expected = IOException.class)
|
@Test(expected = IOException.class)
|
||||||
public void testTruncatedFrameThrowsException() throws Exception {
|
public void testTruncatedFrameThrowsException() throws Exception {
|
||||||
byte[] frameHeader = new byte[FRAME_HEADER_LENGTH];
|
byte[] frameHeader = new byte[FRAME_HEADER_LENGTH];
|
||||||
@@ -83,7 +171,9 @@ public class StreamDecrypterImplTest extends BrambleTestCase {
|
|||||||
paddingLength);
|
paddingLength);
|
||||||
|
|
||||||
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||||
out.write(streamHeaderIv);
|
out.write(streamHeaderNonce);
|
||||||
|
out.write(protocolVersionBytes);
|
||||||
|
out.write(streamNumberBytes);
|
||||||
out.write(frameKey.getBytes());
|
out.write(frameKey.getBytes());
|
||||||
out.write(new byte[MAC_LENGTH]);
|
out.write(new byte[MAC_LENGTH]);
|
||||||
out.write(frameHeader);
|
out.write(frameHeader);
|
||||||
@@ -111,7 +201,9 @@ public class StreamDecrypterImplTest extends BrambleTestCase {
|
|||||||
byte[] payload = TestUtils.getRandomBytes(payloadLength);
|
byte[] payload = TestUtils.getRandomBytes(payloadLength);
|
||||||
|
|
||||||
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||||
out.write(streamHeaderIv);
|
out.write(streamHeaderNonce);
|
||||||
|
out.write(protocolVersionBytes);
|
||||||
|
out.write(streamNumberBytes);
|
||||||
out.write(frameKey.getBytes());
|
out.write(frameKey.getBytes());
|
||||||
out.write(new byte[MAC_LENGTH]);
|
out.write(new byte[MAC_LENGTH]);
|
||||||
out.write(frameHeader);
|
out.write(frameHeader);
|
||||||
@@ -138,7 +230,9 @@ public class StreamDecrypterImplTest extends BrambleTestCase {
|
|||||||
padding[paddingLength - 1] = 1;
|
padding[paddingLength - 1] = 1;
|
||||||
|
|
||||||
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||||
out.write(streamHeaderIv);
|
out.write(streamHeaderNonce);
|
||||||
|
out.write(protocolVersionBytes);
|
||||||
|
out.write(streamNumberBytes);
|
||||||
out.write(frameKey.getBytes());
|
out.write(frameKey.getBytes());
|
||||||
out.write(new byte[MAC_LENGTH]);
|
out.write(new byte[MAC_LENGTH]);
|
||||||
out.write(frameHeader);
|
out.write(frameHeader);
|
||||||
@@ -162,7 +256,9 @@ public class StreamDecrypterImplTest extends BrambleTestCase {
|
|||||||
paddingLength);
|
paddingLength);
|
||||||
|
|
||||||
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||||
out.write(streamHeaderIv);
|
out.write(streamHeaderNonce);
|
||||||
|
out.write(protocolVersionBytes);
|
||||||
|
out.write(streamNumberBytes);
|
||||||
out.write(frameKey.getBytes());
|
out.write(frameKey.getBytes());
|
||||||
out.write(new byte[MAC_LENGTH]);
|
out.write(new byte[MAC_LENGTH]);
|
||||||
out.write(frameHeader);
|
out.write(frameHeader);
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ package org.briarproject.bramble.crypto;
|
|||||||
import org.briarproject.bramble.api.crypto.SecretKey;
|
import org.briarproject.bramble.api.crypto.SecretKey;
|
||||||
import org.briarproject.bramble.test.BrambleTestCase;
|
import org.briarproject.bramble.test.BrambleTestCase;
|
||||||
import org.briarproject.bramble.test.TestUtils;
|
import org.briarproject.bramble.test.TestUtils;
|
||||||
|
import org.briarproject.bramble.util.ByteUtils;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
import java.io.ByteArrayOutputStream;
|
import java.io.ByteArrayOutputStream;
|
||||||
@@ -11,8 +12,9 @@ import static org.briarproject.bramble.api.transport.TransportConstants.FRAME_HE
|
|||||||
import static org.briarproject.bramble.api.transport.TransportConstants.MAC_LENGTH;
|
import static org.briarproject.bramble.api.transport.TransportConstants.MAC_LENGTH;
|
||||||
import static org.briarproject.bramble.api.transport.TransportConstants.MAX_FRAME_LENGTH;
|
import static org.briarproject.bramble.api.transport.TransportConstants.MAX_FRAME_LENGTH;
|
||||||
import static org.briarproject.bramble.api.transport.TransportConstants.MAX_PAYLOAD_LENGTH;
|
import static org.briarproject.bramble.api.transport.TransportConstants.MAX_PAYLOAD_LENGTH;
|
||||||
import static org.briarproject.bramble.api.transport.TransportConstants.STREAM_HEADER_IV_LENGTH;
|
import static org.briarproject.bramble.api.transport.TransportConstants.PROTOCOL_VERSION;
|
||||||
import static org.briarproject.bramble.api.transport.TransportConstants.STREAM_HEADER_LENGTH;
|
import static org.briarproject.bramble.api.transport.TransportConstants.STREAM_HEADER_LENGTH;
|
||||||
|
import static org.briarproject.bramble.api.transport.TransportConstants.STREAM_HEADER_NONCE_LENGTH;
|
||||||
import static org.briarproject.bramble.api.transport.TransportConstants.TAG_LENGTH;
|
import static org.briarproject.bramble.api.transport.TransportConstants.TAG_LENGTH;
|
||||||
import static org.junit.Assert.assertArrayEquals;
|
import static org.junit.Assert.assertArrayEquals;
|
||||||
import static org.junit.Assert.assertEquals;
|
import static org.junit.Assert.assertEquals;
|
||||||
@@ -21,7 +23,8 @@ public class StreamEncrypterImplTest extends BrambleTestCase {
|
|||||||
|
|
||||||
private final AuthenticatedCipher cipher;
|
private final AuthenticatedCipher cipher;
|
||||||
private final SecretKey streamHeaderKey, frameKey;
|
private final SecretKey streamHeaderKey, frameKey;
|
||||||
private final byte[] tag, streamHeaderIv, payload;
|
private final byte[] tag, streamHeaderNonce, protocolVersionBytes;
|
||||||
|
private final byte[] streamNumberBytes, payload;
|
||||||
private final long streamNumber = 1234;
|
private final long streamNumber = 1234;
|
||||||
private final int payloadLength = 123, paddingLength = 234;
|
private final int payloadLength = 123, paddingLength = 234;
|
||||||
|
|
||||||
@@ -30,7 +33,12 @@ public class StreamEncrypterImplTest extends BrambleTestCase {
|
|||||||
streamHeaderKey = TestUtils.getSecretKey();
|
streamHeaderKey = TestUtils.getSecretKey();
|
||||||
frameKey = TestUtils.getSecretKey();
|
frameKey = TestUtils.getSecretKey();
|
||||||
tag = TestUtils.getRandomBytes(TAG_LENGTH);
|
tag = TestUtils.getRandomBytes(TAG_LENGTH);
|
||||||
streamHeaderIv = TestUtils.getRandomBytes(STREAM_HEADER_IV_LENGTH);
|
streamHeaderNonce =
|
||||||
|
TestUtils.getRandomBytes(STREAM_HEADER_NONCE_LENGTH);
|
||||||
|
protocolVersionBytes = new byte[2];
|
||||||
|
ByteUtils.writeUint16(PROTOCOL_VERSION, protocolVersionBytes, 0);
|
||||||
|
streamNumberBytes = new byte[8];
|
||||||
|
ByteUtils.writeUint64(streamNumber, streamNumberBytes, 0);
|
||||||
payload = TestUtils.getRandomBytes(payloadLength);
|
payload = TestUtils.getRandomBytes(payloadLength);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -38,7 +46,8 @@ public class StreamEncrypterImplTest extends BrambleTestCase {
|
|||||||
public void testRejectsNegativePayloadLength() throws Exception {
|
public void testRejectsNegativePayloadLength() throws Exception {
|
||||||
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||||
StreamEncrypterImpl s = new StreamEncrypterImpl(out, cipher,
|
StreamEncrypterImpl s = new StreamEncrypterImpl(out, cipher,
|
||||||
streamNumber, tag, streamHeaderIv, streamHeaderKey, frameKey);
|
streamNumber, tag, streamHeaderNonce, streamHeaderKey,
|
||||||
|
frameKey);
|
||||||
|
|
||||||
s.writeFrame(payload, -1, 0, false);
|
s.writeFrame(payload, -1, 0, false);
|
||||||
}
|
}
|
||||||
@@ -47,7 +56,8 @@ public class StreamEncrypterImplTest extends BrambleTestCase {
|
|||||||
public void testRejectsNegativePaddingLength() throws Exception {
|
public void testRejectsNegativePaddingLength() throws Exception {
|
||||||
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||||
StreamEncrypterImpl s = new StreamEncrypterImpl(out, cipher,
|
StreamEncrypterImpl s = new StreamEncrypterImpl(out, cipher,
|
||||||
streamNumber, tag, streamHeaderIv, streamHeaderKey, frameKey);
|
streamNumber, tag, streamHeaderNonce, streamHeaderKey,
|
||||||
|
frameKey);
|
||||||
|
|
||||||
s.writeFrame(payload, 0, -1, false);
|
s.writeFrame(payload, 0, -1, false);
|
||||||
}
|
}
|
||||||
@@ -56,7 +66,8 @@ public class StreamEncrypterImplTest extends BrambleTestCase {
|
|||||||
public void testRejectsMaxPayloadPlusPadding() throws Exception {
|
public void testRejectsMaxPayloadPlusPadding() throws Exception {
|
||||||
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||||
StreamEncrypterImpl s = new StreamEncrypterImpl(out, cipher,
|
StreamEncrypterImpl s = new StreamEncrypterImpl(out, cipher,
|
||||||
streamNumber, tag, streamHeaderIv, streamHeaderKey, frameKey);
|
streamNumber, tag, streamHeaderNonce, streamHeaderKey,
|
||||||
|
frameKey);
|
||||||
|
|
||||||
byte[] bigPayload = new byte[MAX_PAYLOAD_LENGTH + 1];
|
byte[] bigPayload = new byte[MAX_PAYLOAD_LENGTH + 1];
|
||||||
s.writeFrame(bigPayload, MAX_PAYLOAD_LENGTH, 1, false);
|
s.writeFrame(bigPayload, MAX_PAYLOAD_LENGTH, 1, false);
|
||||||
@@ -66,7 +77,8 @@ public class StreamEncrypterImplTest extends BrambleTestCase {
|
|||||||
public void testAcceptsMaxPayloadIncludingPadding() throws Exception {
|
public void testAcceptsMaxPayloadIncludingPadding() throws Exception {
|
||||||
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||||
StreamEncrypterImpl s = new StreamEncrypterImpl(out, cipher,
|
StreamEncrypterImpl s = new StreamEncrypterImpl(out, cipher,
|
||||||
streamNumber, tag, streamHeaderIv, streamHeaderKey, frameKey);
|
streamNumber, tag, streamHeaderNonce, streamHeaderKey,
|
||||||
|
frameKey);
|
||||||
|
|
||||||
byte[] bigPayload = new byte[MAX_PAYLOAD_LENGTH];
|
byte[] bigPayload = new byte[MAX_PAYLOAD_LENGTH];
|
||||||
s.writeFrame(bigPayload, MAX_PAYLOAD_LENGTH - 1, 1, false);
|
s.writeFrame(bigPayload, MAX_PAYLOAD_LENGTH - 1, 1, false);
|
||||||
@@ -78,7 +90,8 @@ public class StreamEncrypterImplTest extends BrambleTestCase {
|
|||||||
public void testAcceptsMaxPayloadWithoutPadding() throws Exception {
|
public void testAcceptsMaxPayloadWithoutPadding() throws Exception {
|
||||||
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||||
StreamEncrypterImpl s = new StreamEncrypterImpl(out, cipher,
|
StreamEncrypterImpl s = new StreamEncrypterImpl(out, cipher,
|
||||||
streamNumber, tag, streamHeaderIv, streamHeaderKey, frameKey);
|
streamNumber, tag, streamHeaderNonce, streamHeaderKey,
|
||||||
|
frameKey);
|
||||||
|
|
||||||
byte[] bigPayload = new byte[MAX_PAYLOAD_LENGTH];
|
byte[] bigPayload = new byte[MAX_PAYLOAD_LENGTH];
|
||||||
s.writeFrame(bigPayload, MAX_PAYLOAD_LENGTH, 0, false);
|
s.writeFrame(bigPayload, MAX_PAYLOAD_LENGTH, 0, false);
|
||||||
@@ -90,14 +103,17 @@ public class StreamEncrypterImplTest extends BrambleTestCase {
|
|||||||
public void testWriteUnpaddedNonFinalFrameWithTag() throws Exception {
|
public void testWriteUnpaddedNonFinalFrameWithTag() throws Exception {
|
||||||
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||||
StreamEncrypterImpl s = new StreamEncrypterImpl(out, cipher,
|
StreamEncrypterImpl s = new StreamEncrypterImpl(out, cipher,
|
||||||
streamNumber, tag, streamHeaderIv, streamHeaderKey, frameKey);
|
streamNumber, tag, streamHeaderNonce, streamHeaderKey,
|
||||||
|
frameKey);
|
||||||
|
|
||||||
s.writeFrame(payload, payloadLength, 0, false);
|
s.writeFrame(payload, payloadLength, 0, false);
|
||||||
|
|
||||||
// Expect the tag, stream header, frame header, payload and MAC
|
// Expect the tag, stream header, frame header, payload and MAC
|
||||||
ByteArrayOutputStream expected = new ByteArrayOutputStream();
|
ByteArrayOutputStream expected = new ByteArrayOutputStream();
|
||||||
expected.write(tag);
|
expected.write(tag);
|
||||||
expected.write(streamHeaderIv);
|
expected.write(streamHeaderNonce);
|
||||||
|
expected.write(protocolVersionBytes);
|
||||||
|
expected.write(streamNumberBytes);
|
||||||
expected.write(frameKey.getBytes());
|
expected.write(frameKey.getBytes());
|
||||||
expected.write(new byte[MAC_LENGTH]);
|
expected.write(new byte[MAC_LENGTH]);
|
||||||
byte[] expectedFrameHeader = new byte[FRAME_HEADER_LENGTH];
|
byte[] expectedFrameHeader = new byte[FRAME_HEADER_LENGTH];
|
||||||
@@ -113,14 +129,17 @@ public class StreamEncrypterImplTest extends BrambleTestCase {
|
|||||||
public void testWriteUnpaddedFinalFrameWithTag() throws Exception {
|
public void testWriteUnpaddedFinalFrameWithTag() throws Exception {
|
||||||
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||||
StreamEncrypterImpl s = new StreamEncrypterImpl(out, cipher,
|
StreamEncrypterImpl s = new StreamEncrypterImpl(out, cipher,
|
||||||
streamNumber, tag, streamHeaderIv, streamHeaderKey, frameKey);
|
streamNumber, tag, streamHeaderNonce, streamHeaderKey,
|
||||||
|
frameKey);
|
||||||
|
|
||||||
s.writeFrame(payload, payloadLength, 0, true);
|
s.writeFrame(payload, payloadLength, 0, true);
|
||||||
|
|
||||||
// Expect the tag, stream header, frame header, payload and MAC
|
// Expect the tag, stream header, frame header, payload and MAC
|
||||||
ByteArrayOutputStream expected = new ByteArrayOutputStream();
|
ByteArrayOutputStream expected = new ByteArrayOutputStream();
|
||||||
expected.write(tag);
|
expected.write(tag);
|
||||||
expected.write(streamHeaderIv);
|
expected.write(streamHeaderNonce);
|
||||||
|
expected.write(protocolVersionBytes);
|
||||||
|
expected.write(streamNumberBytes);
|
||||||
expected.write(frameKey.getBytes());
|
expected.write(frameKey.getBytes());
|
||||||
expected.write(new byte[MAC_LENGTH]);
|
expected.write(new byte[MAC_LENGTH]);
|
||||||
byte[] expectedFrameHeader = new byte[FRAME_HEADER_LENGTH];
|
byte[] expectedFrameHeader = new byte[FRAME_HEADER_LENGTH];
|
||||||
@@ -136,13 +155,16 @@ public class StreamEncrypterImplTest extends BrambleTestCase {
|
|||||||
public void testWriteUnpaddedNonFinalFrameWithoutTag() throws Exception {
|
public void testWriteUnpaddedNonFinalFrameWithoutTag() throws Exception {
|
||||||
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||||
StreamEncrypterImpl s = new StreamEncrypterImpl(out, cipher,
|
StreamEncrypterImpl s = new StreamEncrypterImpl(out, cipher,
|
||||||
streamNumber, null, streamHeaderIv, streamHeaderKey, frameKey);
|
streamNumber, null, streamHeaderNonce, streamHeaderKey,
|
||||||
|
frameKey);
|
||||||
|
|
||||||
s.writeFrame(payload, payloadLength, 0, false);
|
s.writeFrame(payload, payloadLength, 0, false);
|
||||||
|
|
||||||
// Expect the stream header, frame header, payload and MAC
|
// Expect the stream header, frame header, payload and MAC
|
||||||
ByteArrayOutputStream expected = new ByteArrayOutputStream();
|
ByteArrayOutputStream expected = new ByteArrayOutputStream();
|
||||||
expected.write(streamHeaderIv);
|
expected.write(streamHeaderNonce);
|
||||||
|
expected.write(protocolVersionBytes);
|
||||||
|
expected.write(streamNumberBytes);
|
||||||
expected.write(frameKey.getBytes());
|
expected.write(frameKey.getBytes());
|
||||||
expected.write(new byte[MAC_LENGTH]);
|
expected.write(new byte[MAC_LENGTH]);
|
||||||
byte[] expectedFrameHeader = new byte[FRAME_HEADER_LENGTH];
|
byte[] expectedFrameHeader = new byte[FRAME_HEADER_LENGTH];
|
||||||
@@ -158,13 +180,16 @@ public class StreamEncrypterImplTest extends BrambleTestCase {
|
|||||||
public void testWriteUnpaddedFinalFrameWithoutTag() throws Exception {
|
public void testWriteUnpaddedFinalFrameWithoutTag() throws Exception {
|
||||||
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||||
StreamEncrypterImpl s = new StreamEncrypterImpl(out, cipher,
|
StreamEncrypterImpl s = new StreamEncrypterImpl(out, cipher,
|
||||||
streamNumber, null, streamHeaderIv, streamHeaderKey, frameKey);
|
streamNumber, null, streamHeaderNonce, streamHeaderKey,
|
||||||
|
frameKey);
|
||||||
|
|
||||||
s.writeFrame(payload, payloadLength, 0, true);
|
s.writeFrame(payload, payloadLength, 0, true);
|
||||||
|
|
||||||
// Expect the stream header, frame header, payload and MAC
|
// Expect the stream header, frame header, payload and MAC
|
||||||
ByteArrayOutputStream expected = new ByteArrayOutputStream();
|
ByteArrayOutputStream expected = new ByteArrayOutputStream();
|
||||||
expected.write(streamHeaderIv);
|
expected.write(streamHeaderNonce);
|
||||||
|
expected.write(protocolVersionBytes);
|
||||||
|
expected.write(streamNumberBytes);
|
||||||
expected.write(frameKey.getBytes());
|
expected.write(frameKey.getBytes());
|
||||||
expected.write(new byte[MAC_LENGTH]);
|
expected.write(new byte[MAC_LENGTH]);
|
||||||
byte[] expectedFrameHeader = new byte[FRAME_HEADER_LENGTH];
|
byte[] expectedFrameHeader = new byte[FRAME_HEADER_LENGTH];
|
||||||
@@ -180,14 +205,17 @@ public class StreamEncrypterImplTest extends BrambleTestCase {
|
|||||||
public void testWritePaddedNonFinalFrameWithTag() throws Exception {
|
public void testWritePaddedNonFinalFrameWithTag() throws Exception {
|
||||||
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||||
StreamEncrypterImpl s = new StreamEncrypterImpl(out, cipher,
|
StreamEncrypterImpl s = new StreamEncrypterImpl(out, cipher,
|
||||||
streamNumber, tag, streamHeaderIv, streamHeaderKey, frameKey);
|
streamNumber, tag, streamHeaderNonce, streamHeaderKey,
|
||||||
|
frameKey);
|
||||||
|
|
||||||
s.writeFrame(payload, payloadLength, paddingLength, false);
|
s.writeFrame(payload, payloadLength, paddingLength, false);
|
||||||
|
|
||||||
// Expect the tag, stream header, frame header, payload, padding and MAC
|
// Expect the tag, stream header, frame header, payload, padding and MAC
|
||||||
ByteArrayOutputStream expected = new ByteArrayOutputStream();
|
ByteArrayOutputStream expected = new ByteArrayOutputStream();
|
||||||
expected.write(tag);
|
expected.write(tag);
|
||||||
expected.write(streamHeaderIv);
|
expected.write(streamHeaderNonce);
|
||||||
|
expected.write(protocolVersionBytes);
|
||||||
|
expected.write(streamNumberBytes);
|
||||||
expected.write(frameKey.getBytes());
|
expected.write(frameKey.getBytes());
|
||||||
expected.write(new byte[MAC_LENGTH]);
|
expected.write(new byte[MAC_LENGTH]);
|
||||||
byte[] expectedFrameHeader = new byte[FRAME_HEADER_LENGTH];
|
byte[] expectedFrameHeader = new byte[FRAME_HEADER_LENGTH];
|
||||||
@@ -205,14 +233,17 @@ public class StreamEncrypterImplTest extends BrambleTestCase {
|
|||||||
public void testWritePaddedFinalFrameWithTag() throws Exception {
|
public void testWritePaddedFinalFrameWithTag() throws Exception {
|
||||||
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||||
StreamEncrypterImpl s = new StreamEncrypterImpl(out, cipher,
|
StreamEncrypterImpl s = new StreamEncrypterImpl(out, cipher,
|
||||||
streamNumber, tag, streamHeaderIv, streamHeaderKey, frameKey);
|
streamNumber, tag, streamHeaderNonce, streamHeaderKey,
|
||||||
|
frameKey);
|
||||||
|
|
||||||
s.writeFrame(payload, payloadLength, paddingLength, true);
|
s.writeFrame(payload, payloadLength, paddingLength, true);
|
||||||
|
|
||||||
// Expect the tag, stream header, frame header, payload, padding and MAC
|
// Expect the tag, stream header, frame header, payload, padding and MAC
|
||||||
ByteArrayOutputStream expected = new ByteArrayOutputStream();
|
ByteArrayOutputStream expected = new ByteArrayOutputStream();
|
||||||
expected.write(tag);
|
expected.write(tag);
|
||||||
expected.write(streamHeaderIv);
|
expected.write(streamHeaderNonce);
|
||||||
|
expected.write(protocolVersionBytes);
|
||||||
|
expected.write(streamNumberBytes);
|
||||||
expected.write(frameKey.getBytes());
|
expected.write(frameKey.getBytes());
|
||||||
expected.write(new byte[MAC_LENGTH]);
|
expected.write(new byte[MAC_LENGTH]);
|
||||||
byte[] expectedFrameHeader = new byte[FRAME_HEADER_LENGTH];
|
byte[] expectedFrameHeader = new byte[FRAME_HEADER_LENGTH];
|
||||||
@@ -230,13 +261,16 @@ public class StreamEncrypterImplTest extends BrambleTestCase {
|
|||||||
public void testWritePaddedNonFinalFrameWithoutTag() throws Exception {
|
public void testWritePaddedNonFinalFrameWithoutTag() throws Exception {
|
||||||
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||||
StreamEncrypterImpl s = new StreamEncrypterImpl(out, cipher,
|
StreamEncrypterImpl s = new StreamEncrypterImpl(out, cipher,
|
||||||
streamNumber, null, streamHeaderIv, streamHeaderKey, frameKey);
|
streamNumber, null, streamHeaderNonce, streamHeaderKey,
|
||||||
|
frameKey);
|
||||||
|
|
||||||
s.writeFrame(payload, payloadLength, paddingLength, false);
|
s.writeFrame(payload, payloadLength, paddingLength, false);
|
||||||
|
|
||||||
// Expect the stream header, frame header, payload, padding and MAC
|
// Expect the stream header, frame header, payload, padding and MAC
|
||||||
ByteArrayOutputStream expected = new ByteArrayOutputStream();
|
ByteArrayOutputStream expected = new ByteArrayOutputStream();
|
||||||
expected.write(streamHeaderIv);
|
expected.write(streamHeaderNonce);
|
||||||
|
expected.write(protocolVersionBytes);
|
||||||
|
expected.write(streamNumberBytes);
|
||||||
expected.write(frameKey.getBytes());
|
expected.write(frameKey.getBytes());
|
||||||
expected.write(new byte[MAC_LENGTH]);
|
expected.write(new byte[MAC_LENGTH]);
|
||||||
byte[] expectedFrameHeader = new byte[FRAME_HEADER_LENGTH];
|
byte[] expectedFrameHeader = new byte[FRAME_HEADER_LENGTH];
|
||||||
@@ -254,13 +288,16 @@ public class StreamEncrypterImplTest extends BrambleTestCase {
|
|||||||
public void testWritePaddedFinalFrameWithoutTag() throws Exception {
|
public void testWritePaddedFinalFrameWithoutTag() throws Exception {
|
||||||
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||||
StreamEncrypterImpl s = new StreamEncrypterImpl(out, cipher,
|
StreamEncrypterImpl s = new StreamEncrypterImpl(out, cipher,
|
||||||
streamNumber, null, streamHeaderIv, streamHeaderKey, frameKey);
|
streamNumber, null, streamHeaderNonce, streamHeaderKey,
|
||||||
|
frameKey);
|
||||||
|
|
||||||
s.writeFrame(payload, payloadLength, paddingLength, true);
|
s.writeFrame(payload, payloadLength, paddingLength, true);
|
||||||
|
|
||||||
// Expect the stream header, frame header, payload, padding and MAC
|
// Expect the stream header, frame header, payload, padding and MAC
|
||||||
ByteArrayOutputStream expected = new ByteArrayOutputStream();
|
ByteArrayOutputStream expected = new ByteArrayOutputStream();
|
||||||
expected.write(streamHeaderIv);
|
expected.write(streamHeaderNonce);
|
||||||
|
expected.write(protocolVersionBytes);
|
||||||
|
expected.write(streamNumberBytes);
|
||||||
expected.write(frameKey.getBytes());
|
expected.write(frameKey.getBytes());
|
||||||
expected.write(new byte[MAC_LENGTH]);
|
expected.write(new byte[MAC_LENGTH]);
|
||||||
byte[] expectedFrameHeader = new byte[FRAME_HEADER_LENGTH];
|
byte[] expectedFrameHeader = new byte[FRAME_HEADER_LENGTH];
|
||||||
@@ -278,7 +315,8 @@ public class StreamEncrypterImplTest extends BrambleTestCase {
|
|||||||
public void testWriteTwoFramesWithTag() throws Exception {
|
public void testWriteTwoFramesWithTag() throws Exception {
|
||||||
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||||
StreamEncrypterImpl s = new StreamEncrypterImpl(out, cipher,
|
StreamEncrypterImpl s = new StreamEncrypterImpl(out, cipher,
|
||||||
streamNumber, tag, streamHeaderIv, streamHeaderKey, frameKey);
|
streamNumber, tag, streamHeaderNonce, streamHeaderKey,
|
||||||
|
frameKey);
|
||||||
int payloadLength1 = 345, paddingLength1 = 456;
|
int payloadLength1 = 345, paddingLength1 = 456;
|
||||||
byte[] payload1 = TestUtils.getRandomBytes(payloadLength1);
|
byte[] payload1 = TestUtils.getRandomBytes(payloadLength1);
|
||||||
|
|
||||||
@@ -289,7 +327,9 @@ public class StreamEncrypterImplTest extends BrambleTestCase {
|
|||||||
// MAC, second frame header, payload, padding, MAC
|
// MAC, second frame header, payload, padding, MAC
|
||||||
ByteArrayOutputStream expected = new ByteArrayOutputStream();
|
ByteArrayOutputStream expected = new ByteArrayOutputStream();
|
||||||
expected.write(tag);
|
expected.write(tag);
|
||||||
expected.write(streamHeaderIv);
|
expected.write(streamHeaderNonce);
|
||||||
|
expected.write(protocolVersionBytes);
|
||||||
|
expected.write(streamNumberBytes);
|
||||||
expected.write(frameKey.getBytes());
|
expected.write(frameKey.getBytes());
|
||||||
expected.write(new byte[MAC_LENGTH]);
|
expected.write(new byte[MAC_LENGTH]);
|
||||||
byte[] expectedFrameHeader = new byte[FRAME_HEADER_LENGTH];
|
byte[] expectedFrameHeader = new byte[FRAME_HEADER_LENGTH];
|
||||||
@@ -315,7 +355,8 @@ public class StreamEncrypterImplTest extends BrambleTestCase {
|
|||||||
throws Exception {
|
throws Exception {
|
||||||
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||||
StreamEncrypterImpl s = new StreamEncrypterImpl(out, cipher,
|
StreamEncrypterImpl s = new StreamEncrypterImpl(out, cipher,
|
||||||
streamNumber, tag, streamHeaderIv, streamHeaderKey, frameKey);
|
streamNumber, tag, streamHeaderNonce, streamHeaderKey,
|
||||||
|
frameKey);
|
||||||
|
|
||||||
// Flush the stream once
|
// Flush the stream once
|
||||||
s.flush();
|
s.flush();
|
||||||
@@ -323,7 +364,9 @@ public class StreamEncrypterImplTest extends BrambleTestCase {
|
|||||||
// Expect the tag and stream header
|
// Expect the tag and stream header
|
||||||
ByteArrayOutputStream expected = new ByteArrayOutputStream();
|
ByteArrayOutputStream expected = new ByteArrayOutputStream();
|
||||||
expected.write(tag);
|
expected.write(tag);
|
||||||
expected.write(streamHeaderIv);
|
expected.write(streamHeaderNonce);
|
||||||
|
expected.write(protocolVersionBytes);
|
||||||
|
expected.write(streamNumberBytes);
|
||||||
expected.write(frameKey.getBytes());
|
expected.write(frameKey.getBytes());
|
||||||
expected.write(new byte[MAC_LENGTH]);
|
expected.write(new byte[MAC_LENGTH]);
|
||||||
|
|
||||||
@@ -335,7 +378,8 @@ public class StreamEncrypterImplTest extends BrambleTestCase {
|
|||||||
throws Exception {
|
throws Exception {
|
||||||
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||||
StreamEncrypterImpl s = new StreamEncrypterImpl(out, cipher,
|
StreamEncrypterImpl s = new StreamEncrypterImpl(out, cipher,
|
||||||
streamNumber, tag, streamHeaderIv, streamHeaderKey, frameKey);
|
streamNumber, tag, streamHeaderNonce, streamHeaderKey,
|
||||||
|
frameKey);
|
||||||
|
|
||||||
// Flush the stream twice
|
// Flush the stream twice
|
||||||
s.flush();
|
s.flush();
|
||||||
@@ -344,7 +388,9 @@ public class StreamEncrypterImplTest extends BrambleTestCase {
|
|||||||
// Expect the tag and stream header
|
// Expect the tag and stream header
|
||||||
ByteArrayOutputStream expected = new ByteArrayOutputStream();
|
ByteArrayOutputStream expected = new ByteArrayOutputStream();
|
||||||
expected.write(tag);
|
expected.write(tag);
|
||||||
expected.write(streamHeaderIv);
|
expected.write(streamHeaderNonce);
|
||||||
|
expected.write(protocolVersionBytes);
|
||||||
|
expected.write(streamNumberBytes);
|
||||||
expected.write(frameKey.getBytes());
|
expected.write(frameKey.getBytes());
|
||||||
expected.write(new byte[MAC_LENGTH]);
|
expected.write(new byte[MAC_LENGTH]);
|
||||||
|
|
||||||
@@ -355,14 +401,17 @@ public class StreamEncrypterImplTest extends BrambleTestCase {
|
|||||||
public void testFlushDoesNotWriteTagIfNull() throws Exception {
|
public void testFlushDoesNotWriteTagIfNull() throws Exception {
|
||||||
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||||
StreamEncrypterImpl s = new StreamEncrypterImpl(out, cipher,
|
StreamEncrypterImpl s = new StreamEncrypterImpl(out, cipher,
|
||||||
streamNumber, null, streamHeaderIv, streamHeaderKey, frameKey);
|
streamNumber, null, streamHeaderNonce, streamHeaderKey,
|
||||||
|
frameKey);
|
||||||
|
|
||||||
// Flush the stream once
|
// Flush the stream once
|
||||||
s.flush();
|
s.flush();
|
||||||
|
|
||||||
// Expect the stream header
|
// Expect the stream header
|
||||||
ByteArrayOutputStream expected = new ByteArrayOutputStream();
|
ByteArrayOutputStream expected = new ByteArrayOutputStream();
|
||||||
expected.write(streamHeaderIv);
|
expected.write(streamHeaderNonce);
|
||||||
|
expected.write(protocolVersionBytes);
|
||||||
|
expected.write(streamNumberBytes);
|
||||||
expected.write(frameKey.getBytes());
|
expected.write(frameKey.getBytes());
|
||||||
expected.write(new byte[MAC_LENGTH]);
|
expected.write(new byte[MAC_LENGTH]);
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,59 @@
|
|||||||
|
package org.briarproject.bramble.crypto;
|
||||||
|
|
||||||
|
import org.briarproject.bramble.api.Bytes;
|
||||||
|
import org.briarproject.bramble.api.crypto.CryptoComponent;
|
||||||
|
import org.briarproject.bramble.api.crypto.SecretKey;
|
||||||
|
import org.briarproject.bramble.test.BrambleTestCase;
|
||||||
|
import org.briarproject.bramble.test.TestSecureRandomProvider;
|
||||||
|
import org.briarproject.bramble.test.TestUtils;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
import static junit.framework.TestCase.assertTrue;
|
||||||
|
import static org.briarproject.bramble.api.transport.TransportConstants.PROTOCOL_VERSION;
|
||||||
|
import static org.briarproject.bramble.api.transport.TransportConstants.TAG_LENGTH;
|
||||||
|
|
||||||
|
public class TagEncodingTest extends BrambleTestCase {
|
||||||
|
|
||||||
|
private final CryptoComponent crypto;
|
||||||
|
private final SecretKey tagKey;
|
||||||
|
private final long streamNumber = 1234567890;
|
||||||
|
|
||||||
|
public TagEncodingTest() {
|
||||||
|
crypto = new CryptoComponentImpl(new TestSecureRandomProvider());
|
||||||
|
tagKey = TestUtils.getSecretKey();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testKeyAffectsTag() throws Exception {
|
||||||
|
Set<Bytes> set = new HashSet<Bytes>();
|
||||||
|
for (int i = 0; i < 100; i++) {
|
||||||
|
byte[] tag = new byte[TAG_LENGTH];
|
||||||
|
SecretKey tagKey = TestUtils.getSecretKey();
|
||||||
|
crypto.encodeTag(tag, tagKey, PROTOCOL_VERSION, streamNumber);
|
||||||
|
assertTrue(set.add(new Bytes(tag)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testProtocolVersionAffectsTag() throws Exception {
|
||||||
|
Set<Bytes> set = new HashSet<Bytes>();
|
||||||
|
for (int i = 0; i < 100; i++) {
|
||||||
|
byte[] tag = new byte[TAG_LENGTH];
|
||||||
|
crypto.encodeTag(tag, tagKey, PROTOCOL_VERSION + i, streamNumber);
|
||||||
|
assertTrue(set.add(new Bytes(tag)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testStreamNumberAffectsTag() throws Exception {
|
||||||
|
Set<Bytes> set = new HashSet<Bytes>();
|
||||||
|
for (int i = 0; i < 100; i++) {
|
||||||
|
byte[] tag = new byte[TAG_LENGTH];
|
||||||
|
crypto.encodeTag(tag, tagKey, PROTOCOL_VERSION, streamNumber + i);
|
||||||
|
assertTrue(set.add(new Bytes(tag)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -4,7 +4,6 @@ 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.test.TestUtils;
|
|
||||||
import org.briarproject.bramble.util.StringUtils;
|
import org.briarproject.bramble.util.StringUtils;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
@@ -159,7 +158,7 @@ public class BdfReaderImplTest extends BrambleTestCase {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testReadString8() throws Exception {
|
public void testReadString8() throws Exception {
|
||||||
String longest = TestUtils.getRandomString(Byte.MAX_VALUE);
|
String longest = StringUtils.getRandomString(Byte.MAX_VALUE);
|
||||||
String longHex = StringUtils.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" +
|
||||||
@@ -181,7 +180,7 @@ public class BdfReaderImplTest extends BrambleTestCase {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testSkipString8() throws Exception {
|
public void testSkipString8() throws Exception {
|
||||||
String longest = TestUtils.getRandomString(Byte.MAX_VALUE);
|
String longest = StringUtils.getRandomString(Byte.MAX_VALUE);
|
||||||
String longHex = StringUtils.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" +
|
||||||
@@ -194,9 +193,9 @@ public class BdfReaderImplTest extends BrambleTestCase {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testReadString16() throws Exception {
|
public void testReadString16() throws Exception {
|
||||||
String shortest = TestUtils.getRandomString(Byte.MAX_VALUE + 1);
|
String shortest = StringUtils.getRandomString(Byte.MAX_VALUE + 1);
|
||||||
String shortHex = StringUtils.toHexString(shortest.getBytes("UTF-8"));
|
String shortHex = StringUtils.toHexString(shortest.getBytes("UTF-8"));
|
||||||
String longest = TestUtils.getRandomString(Short.MAX_VALUE);
|
String longest = StringUtils.getRandomString(Short.MAX_VALUE);
|
||||||
String longHex = StringUtils.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);
|
||||||
@@ -207,7 +206,7 @@ public class BdfReaderImplTest extends BrambleTestCase {
|
|||||||
|
|
||||||
@Test(expected = FormatException.class)
|
@Test(expected = FormatException.class)
|
||||||
public void testReadString16ChecksMaxLength() throws Exception {
|
public void testReadString16ChecksMaxLength() throws Exception {
|
||||||
String shortest = TestUtils.getRandomString(Byte.MAX_VALUE + 1);
|
String shortest = StringUtils.getRandomString(Byte.MAX_VALUE + 1);
|
||||||
String shortHex = StringUtils.toHexString(shortest.getBytes("UTF-8"));
|
String shortHex = StringUtils.toHexString(shortest.getBytes("UTF-8"));
|
||||||
// 128 random letters, twice
|
// 128 random letters, twice
|
||||||
setContents("42" + "0080" + shortHex + "42" + "0080" + shortHex);
|
setContents("42" + "0080" + shortHex + "42" + "0080" + shortHex);
|
||||||
@@ -218,9 +217,9 @@ public class BdfReaderImplTest extends BrambleTestCase {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testSkipString16() throws Exception {
|
public void testSkipString16() throws Exception {
|
||||||
String shortest = TestUtils.getRandomString(Byte.MAX_VALUE + 1);
|
String shortest = StringUtils.getRandomString(Byte.MAX_VALUE + 1);
|
||||||
String shortHex = StringUtils.toHexString(shortest.getBytes("UTF-8"));
|
String shortHex = StringUtils.toHexString(shortest.getBytes("UTF-8"));
|
||||||
String longest = TestUtils.getRandomString(Short.MAX_VALUE);
|
String longest = StringUtils.getRandomString(Short.MAX_VALUE);
|
||||||
String longHex = StringUtils.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);
|
||||||
@@ -231,7 +230,7 @@ public class BdfReaderImplTest extends BrambleTestCase {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testReadString32() throws Exception {
|
public void testReadString32() throws Exception {
|
||||||
String shortest = TestUtils.getRandomString(Short.MAX_VALUE + 1);
|
String shortest = StringUtils.getRandomString(Short.MAX_VALUE + 1);
|
||||||
String shortHex = StringUtils.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);
|
||||||
@@ -241,7 +240,7 @@ public class BdfReaderImplTest extends BrambleTestCase {
|
|||||||
|
|
||||||
@Test(expected = FormatException.class)
|
@Test(expected = FormatException.class)
|
||||||
public void testReadString32ChecksMaxLength() throws Exception {
|
public void testReadString32ChecksMaxLength() throws Exception {
|
||||||
String shortest = TestUtils.getRandomString(Short.MAX_VALUE + 1);
|
String shortest = StringUtils.getRandomString(Short.MAX_VALUE + 1);
|
||||||
String shortHex = StringUtils.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 +
|
||||||
@@ -253,7 +252,7 @@ public class BdfReaderImplTest extends BrambleTestCase {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testSkipString32() throws Exception {
|
public void testSkipString32() throws Exception {
|
||||||
String shortest = TestUtils.getRandomString(Short.MAX_VALUE + 1);
|
String shortest = StringUtils.getRandomString(Short.MAX_VALUE + 1);
|
||||||
String shortHex = StringUtils.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 +
|
||||||
|
|||||||
@@ -81,7 +81,7 @@ public class BdfWriterImplTest extends BrambleTestCase {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testWriteString8() throws IOException {
|
public void testWriteString8() throws IOException {
|
||||||
String longest = TestUtils.getRandomString(Byte.MAX_VALUE);
|
String longest = StringUtils.getRandomString(Byte.MAX_VALUE);
|
||||||
String longHex = StringUtils.toHexString(longest.getBytes("UTF-8"));
|
String longHex = StringUtils.toHexString(longest.getBytes("UTF-8"));
|
||||||
w.writeString("foo bar baz bam ");
|
w.writeString("foo bar baz bam ");
|
||||||
w.writeString(longest);
|
w.writeString(longest);
|
||||||
@@ -93,9 +93,9 @@ public class BdfWriterImplTest extends BrambleTestCase {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testWriteString16() throws IOException {
|
public void testWriteString16() throws IOException {
|
||||||
String shortest = TestUtils.getRandomString(Byte.MAX_VALUE + 1);
|
String shortest = StringUtils.getRandomString(Byte.MAX_VALUE + 1);
|
||||||
String shortHex = StringUtils.toHexString(shortest.getBytes("UTF-8"));
|
String shortHex = StringUtils.toHexString(shortest.getBytes("UTF-8"));
|
||||||
String longest = TestUtils.getRandomString(Short.MAX_VALUE);
|
String longest = StringUtils.getRandomString(Short.MAX_VALUE);
|
||||||
String longHex = StringUtils.toHexString(longest.getBytes("UTF-8"));
|
String longHex = StringUtils.toHexString(longest.getBytes("UTF-8"));
|
||||||
w.writeString(shortest);
|
w.writeString(shortest);
|
||||||
w.writeString(longest);
|
w.writeString(longest);
|
||||||
@@ -106,7 +106,7 @@ public class BdfWriterImplTest extends BrambleTestCase {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testWriteString32() throws IOException {
|
public void testWriteString32() throws IOException {
|
||||||
String shortest = TestUtils.getRandomString(Short.MAX_VALUE + 1);
|
String shortest = StringUtils.getRandomString(Short.MAX_VALUE + 1);
|
||||||
String shortHex = StringUtils.toHexString(shortest.getBytes("UTF-8"));
|
String shortHex = StringUtils.toHexString(shortest.getBytes("UTF-8"));
|
||||||
w.writeString(shortest);
|
w.writeString(shortest);
|
||||||
// STRING_32 tag, length 2^15, UTF-8 bytes
|
// STRING_32 tag, length 2^15, UTF-8 bytes
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ package org.briarproject.bramble.db;
|
|||||||
|
|
||||||
import org.briarproject.bramble.test.BrambleTestCase;
|
import org.briarproject.bramble.test.BrambleTestCase;
|
||||||
import org.briarproject.bramble.test.TestUtils;
|
import org.briarproject.bramble.test.TestUtils;
|
||||||
|
import org.briarproject.bramble.util.StringUtils;
|
||||||
import org.junit.After;
|
import org.junit.After;
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
@@ -48,8 +49,8 @@ public class BasicH2Test extends BrambleTestCase {
|
|||||||
createTable(connection);
|
createTable(connection);
|
||||||
// Generate an ID and two names
|
// Generate an ID and two names
|
||||||
byte[] id = TestUtils.getRandomId();
|
byte[] id = TestUtils.getRandomId();
|
||||||
String oldName = TestUtils.getRandomString(50);
|
String oldName = StringUtils.getRandomString(50);
|
||||||
String newName = TestUtils.getRandomString(50);
|
String newName = StringUtils.getRandomString(50);
|
||||||
// Insert the ID and old name into the table
|
// Insert the ID and old name into the table
|
||||||
insertRow(id, oldName);
|
insertRow(id, oldName);
|
||||||
// Check that the old name can be retrieved using the ID
|
// Check that the old name can be retrieved using the ID
|
||||||
@@ -78,8 +79,8 @@ public class BasicH2Test extends BrambleTestCase {
|
|||||||
String[] newNames = new String[BATCH_SIZE];
|
String[] newNames = new String[BATCH_SIZE];
|
||||||
for (int i = 0; i < BATCH_SIZE; i++) {
|
for (int i = 0; i < BATCH_SIZE; i++) {
|
||||||
ids[i] = TestUtils.getRandomId();
|
ids[i] = TestUtils.getRandomId();
|
||||||
oldNames[i] = TestUtils.getRandomString(50);
|
oldNames[i] = StringUtils.getRandomString(50);
|
||||||
newNames[i] = TestUtils.getRandomString(50);
|
newNames[i] = StringUtils.getRandomString(50);
|
||||||
}
|
}
|
||||||
// Insert the IDs and old names into the table as a batch
|
// Insert the IDs and old names into the table as a batch
|
||||||
insertBatch(ids, oldNames);
|
insertBatch(ids, oldNames);
|
||||||
|
|||||||
@@ -49,6 +49,7 @@ import org.briarproject.bramble.api.transport.OutgoingKeys;
|
|||||||
import org.briarproject.bramble.api.transport.TransportKeys;
|
import org.briarproject.bramble.api.transport.TransportKeys;
|
||||||
import org.briarproject.bramble.test.BrambleTestCase;
|
import org.briarproject.bramble.test.BrambleTestCase;
|
||||||
import org.briarproject.bramble.test.TestUtils;
|
import org.briarproject.bramble.test.TestUtils;
|
||||||
|
import org.briarproject.bramble.util.StringUtils;
|
||||||
import org.jmock.Expectations;
|
import org.jmock.Expectations;
|
||||||
import org.jmock.Mockery;
|
import org.jmock.Mockery;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
@@ -94,7 +95,7 @@ public class DatabaseComponentImplTest extends BrambleTestCase {
|
|||||||
private final Contact contact;
|
private final Contact contact;
|
||||||
|
|
||||||
public DatabaseComponentImplTest() {
|
public DatabaseComponentImplTest() {
|
||||||
clientId = new ClientId(TestUtils.getRandomString(5));
|
clientId = new ClientId(StringUtils.getRandomString(5));
|
||||||
groupId = new GroupId(TestUtils.getRandomId());
|
groupId = new GroupId(TestUtils.getRandomId());
|
||||||
byte[] descriptor = new byte[MAX_GROUP_DESCRIPTOR_LENGTH];
|
byte[] descriptor = new byte[MAX_GROUP_DESCRIPTOR_LENGTH];
|
||||||
group = new Group(groupId, clientId, descriptor);
|
group = new Group(groupId, clientId, descriptor);
|
||||||
|
|||||||
@@ -24,6 +24,7 @@ import org.briarproject.bramble.system.SystemClock;
|
|||||||
import org.briarproject.bramble.test.BrambleTestCase;
|
import org.briarproject.bramble.test.BrambleTestCase;
|
||||||
import org.briarproject.bramble.test.TestDatabaseConfig;
|
import org.briarproject.bramble.test.TestDatabaseConfig;
|
||||||
import org.briarproject.bramble.test.TestUtils;
|
import org.briarproject.bramble.test.TestUtils;
|
||||||
|
import org.briarproject.bramble.util.StringUtils;
|
||||||
import org.junit.After;
|
import org.junit.After;
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
@@ -84,7 +85,7 @@ public class H2DatabaseTest extends BrambleTestCase {
|
|||||||
|
|
||||||
public H2DatabaseTest() throws Exception {
|
public H2DatabaseTest() throws Exception {
|
||||||
groupId = new GroupId(TestUtils.getRandomId());
|
groupId = new GroupId(TestUtils.getRandomId());
|
||||||
clientId = new ClientId(TestUtils.getRandomString(5));
|
clientId = new ClientId(StringUtils.getRandomString(5));
|
||||||
byte[] descriptor = new byte[MAX_GROUP_DESCRIPTOR_LENGTH];
|
byte[] descriptor = new byte[MAX_GROUP_DESCRIPTOR_LENGTH];
|
||||||
group = new Group(groupId, clientId, descriptor);
|
group = new Group(groupId, clientId, descriptor);
|
||||||
AuthorId authorId = new AuthorId(TestUtils.getRandomId());
|
AuthorId authorId = new AuthorId(TestUtils.getRandomId());
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ import org.briarproject.bramble.api.identity.IdentityManager;
|
|||||||
import org.briarproject.bramble.api.identity.LocalAuthor;
|
import org.briarproject.bramble.api.identity.LocalAuthor;
|
||||||
import org.briarproject.bramble.test.BrambleMockTestCase;
|
import org.briarproject.bramble.test.BrambleMockTestCase;
|
||||||
import org.briarproject.bramble.test.TestUtils;
|
import org.briarproject.bramble.test.TestUtils;
|
||||||
|
import org.briarproject.bramble.util.StringUtils;
|
||||||
import org.jmock.Expectations;
|
import org.jmock.Expectations;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
@@ -31,8 +32,9 @@ public class IdentityManagerImplTest extends BrambleMockTestCase {
|
|||||||
private final Transaction txn = new Transaction(null, false);
|
private final Transaction txn = new Transaction(null, false);
|
||||||
private final LocalAuthor localAuthor =
|
private final LocalAuthor localAuthor =
|
||||||
new LocalAuthor(new AuthorId(TestUtils.getRandomId()),
|
new LocalAuthor(new AuthorId(TestUtils.getRandomId()),
|
||||||
TestUtils.getRandomString(8), TestUtils.getRandomBytes(42),
|
StringUtils.getRandomString(8),
|
||||||
TestUtils.getRandomBytes(42), 0);
|
TestUtils.getRandomBytes(42), TestUtils.getRandomBytes(42),
|
||||||
|
0);
|
||||||
private final Collection<LocalAuthor> localAuthors =
|
private final Collection<LocalAuthor> localAuthors =
|
||||||
Collections.singletonList(localAuthor);
|
Collections.singletonList(localAuthor);
|
||||||
|
|
||||||
@@ -93,7 +95,7 @@ public class IdentityManagerImplTest extends BrambleMockTestCase {
|
|||||||
assertEquals(UNKNOWN, identityManager.getAuthorStatus(authorId));
|
assertEquals(UNKNOWN, identityManager.getAuthorStatus(authorId));
|
||||||
|
|
||||||
// add one unverified contact
|
// add one unverified contact
|
||||||
Author author = new Author(authorId, TestUtils.getRandomString(8),
|
Author author = new Author(authorId, StringUtils.getRandomString(8),
|
||||||
TestUtils.getRandomBytes(42));
|
TestUtils.getRandomBytes(42));
|
||||||
Contact contact =
|
Contact contact =
|
||||||
new Contact(new ContactId(1), author, localAuthor.getId(),
|
new Contact(new ContactId(1), author, localAuthor.getId(),
|
||||||
|
|||||||
@@ -311,6 +311,11 @@ public class LanTcpPluginTest extends BrambleTestCase {
|
|||||||
return remote;
|
return remote;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public TransportProperties getRemoteProperties(ContactId c) {
|
||||||
|
return remote.get(c);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void mergeSettings(Settings s) {
|
public void mergeSettings(Settings s) {
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ import org.briarproject.bramble.api.sync.MessageId;
|
|||||||
import org.briarproject.bramble.api.system.Clock;
|
import org.briarproject.bramble.api.system.Clock;
|
||||||
import org.briarproject.bramble.test.BrambleTestCase;
|
import org.briarproject.bramble.test.BrambleTestCase;
|
||||||
import org.briarproject.bramble.test.TestUtils;
|
import org.briarproject.bramble.test.TestUtils;
|
||||||
|
import org.briarproject.bramble.util.StringUtils;
|
||||||
import org.jmock.Mockery;
|
import org.jmock.Mockery;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
@@ -36,7 +37,7 @@ public class TransportPropertyValidatorTest extends BrambleTestCase {
|
|||||||
bdfDictionary = new BdfDictionary();
|
bdfDictionary = new BdfDictionary();
|
||||||
|
|
||||||
GroupId groupId = new GroupId(TestUtils.getRandomId());
|
GroupId groupId = new GroupId(TestUtils.getRandomId());
|
||||||
ClientId clientId = new ClientId(TestUtils.getRandomString(5));
|
ClientId clientId = new ClientId(StringUtils.getRandomString(5));
|
||||||
byte[] descriptor = TestUtils.getRandomBytes(12);
|
byte[] descriptor = TestUtils.getRandomBytes(12);
|
||||||
group = new Group(groupId, clientId, descriptor);
|
group = new Group(groupId, clientId, descriptor);
|
||||||
|
|
||||||
@@ -85,7 +86,7 @@ public class TransportPropertyValidatorTest extends BrambleTestCase {
|
|||||||
public void testValidateLongTransportId() throws IOException {
|
public void testValidateLongTransportId() throws IOException {
|
||||||
|
|
||||||
String wrongTransportIdString =
|
String wrongTransportIdString =
|
||||||
TestUtils.getRandomString(MAX_TRANSPORT_ID_LENGTH + 1);
|
StringUtils.getRandomString(MAX_TRANSPORT_ID_LENGTH + 1);
|
||||||
BdfList body = BdfList.of(wrongTransportIdString, 4, bdfDictionary);
|
BdfList body = BdfList.of(wrongTransportIdString, 4, bdfDictionary);
|
||||||
tpv.validateMessage(message, group, body);
|
tpv.validateMessage(message, group, body);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ import org.briarproject.bramble.api.transport.StreamReaderFactory;
|
|||||||
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;
|
||||||
|
import org.briarproject.bramble.util.StringUtils;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
import java.io.ByteArrayInputStream;
|
import java.io.ByteArrayInputStream;
|
||||||
@@ -34,6 +35,7 @@ import java.util.Collection;
|
|||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
|
|
||||||
import static org.briarproject.bramble.api.sync.SyncConstants.MAX_GROUP_DESCRIPTOR_LENGTH;
|
import static org.briarproject.bramble.api.sync.SyncConstants.MAX_GROUP_DESCRIPTOR_LENGTH;
|
||||||
|
import static org.briarproject.bramble.api.transport.TransportConstants.PROTOCOL_VERSION;
|
||||||
import static org.briarproject.bramble.api.transport.TransportConstants.TAG_LENGTH;
|
import static org.briarproject.bramble.api.transport.TransportConstants.TAG_LENGTH;
|
||||||
import static org.junit.Assert.assertArrayEquals;
|
import static org.junit.Assert.assertArrayEquals;
|
||||||
import static org.junit.Assert.assertEquals;
|
import static org.junit.Assert.assertEquals;
|
||||||
@@ -77,7 +79,7 @@ public class SyncIntegrationTest extends BrambleTestCase {
|
|||||||
headerKey = TestUtils.getSecretKey();
|
headerKey = TestUtils.getSecretKey();
|
||||||
streamNumber = 123;
|
streamNumber = 123;
|
||||||
// Create a group
|
// Create a group
|
||||||
ClientId clientId = new ClientId(TestUtils.getRandomString(5));
|
ClientId clientId = new ClientId(StringUtils.getRandomString(5));
|
||||||
byte[] descriptor = new byte[MAX_GROUP_DESCRIPTOR_LENGTH];
|
byte[] descriptor = new byte[MAX_GROUP_DESCRIPTOR_LENGTH];
|
||||||
Group group = groupFactory.createGroup(clientId, descriptor);
|
Group group = groupFactory.createGroup(clientId, descriptor);
|
||||||
// Add two messages to the group
|
// Add two messages to the group
|
||||||
@@ -115,7 +117,7 @@ public class SyncIntegrationTest extends BrambleTestCase {
|
|||||||
private void read(byte[] connectionData) throws Exception {
|
private void read(byte[] connectionData) throws Exception {
|
||||||
// Calculate the expected tag
|
// Calculate the expected tag
|
||||||
byte[] expectedTag = new byte[TAG_LENGTH];
|
byte[] expectedTag = new byte[TAG_LENGTH];
|
||||||
crypto.encodeTag(expectedTag, tagKey, streamNumber);
|
crypto.encodeTag(expectedTag, tagKey, PROTOCOL_VERSION, streamNumber);
|
||||||
|
|
||||||
// Read the tag
|
// Read the tag
|
||||||
InputStream in = new ByteArrayInputStream(connectionData);
|
InputStream in = new ByteArrayInputStream(connectionData);
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ 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.briarproject.bramble.test.TestUtils;
|
||||||
import org.briarproject.bramble.util.ByteUtils;
|
import org.briarproject.bramble.util.ByteUtils;
|
||||||
|
import org.briarproject.bramble.util.StringUtils;
|
||||||
import org.jmock.Expectations;
|
import org.jmock.Expectations;
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
@@ -51,7 +52,7 @@ public class ValidationManagerImplTest extends BrambleMockTestCase {
|
|||||||
private final Executor dbExecutor = new ImmediateExecutor();
|
private final Executor dbExecutor = new ImmediateExecutor();
|
||||||
private final Executor validationExecutor = new ImmediateExecutor();
|
private final Executor validationExecutor = new ImmediateExecutor();
|
||||||
private final ClientId clientId =
|
private final ClientId clientId =
|
||||||
new ClientId(TestUtils.getRandomString(5));
|
new ClientId(StringUtils.getRandomString(5));
|
||||||
private final MessageId messageId = new MessageId(TestUtils.getRandomId());
|
private final MessageId messageId = new MessageId(TestUtils.getRandomId());
|
||||||
private final MessageId messageId1 = new MessageId(TestUtils.getRandomId());
|
private final MessageId messageId1 = new MessageId(TestUtils.getRandomId());
|
||||||
private final MessageId messageId2 = new MessageId(TestUtils.getRandomId());
|
private final MessageId messageId2 = new MessageId(TestUtils.getRandomId());
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ import org.briarproject.bramble.api.sync.GroupId;
|
|||||||
import org.briarproject.bramble.api.sync.Message;
|
import org.briarproject.bramble.api.sync.Message;
|
||||||
import org.briarproject.bramble.api.sync.MessageId;
|
import org.briarproject.bramble.api.sync.MessageId;
|
||||||
import org.briarproject.bramble.api.system.Clock;
|
import org.briarproject.bramble.api.system.Clock;
|
||||||
|
import org.briarproject.bramble.util.StringUtils;
|
||||||
|
|
||||||
public abstract class ValidatorTestCase extends BrambleMockTestCase {
|
public abstract class ValidatorTestCase extends BrambleMockTestCase {
|
||||||
|
|
||||||
@@ -28,7 +29,7 @@ public abstract class ValidatorTestCase extends BrambleMockTestCase {
|
|||||||
protected final Message message =
|
protected final Message message =
|
||||||
new Message(messageId, groupId, timestamp, raw);
|
new Message(messageId, groupId, timestamp, raw);
|
||||||
protected final ClientId clientId =
|
protected final ClientId clientId =
|
||||||
new ClientId(TestUtils.getRandomString(123));
|
new ClientId(StringUtils.getRandomString(123));
|
||||||
protected final byte[] descriptor = TestUtils.getRandomBytes(123);
|
protected final byte[] descriptor = TestUtils.getRandomBytes(123);
|
||||||
protected final Group group = new Group(groupId, clientId, descriptor);
|
protected final Group group = new Group(groupId, clientId, descriptor);
|
||||||
|
|
||||||
|
|||||||
@@ -33,6 +33,7 @@ import java.util.concurrent.ScheduledExecutorService;
|
|||||||
|
|
||||||
import static java.util.concurrent.TimeUnit.MILLISECONDS;
|
import static java.util.concurrent.TimeUnit.MILLISECONDS;
|
||||||
import static org.briarproject.bramble.api.transport.TransportConstants.MAX_CLOCK_DIFFERENCE;
|
import static org.briarproject.bramble.api.transport.TransportConstants.MAX_CLOCK_DIFFERENCE;
|
||||||
|
import static org.briarproject.bramble.api.transport.TransportConstants.PROTOCOL_VERSION;
|
||||||
import static org.briarproject.bramble.api.transport.TransportConstants.REORDERING_WINDOW_SIZE;
|
import static org.briarproject.bramble.api.transport.TransportConstants.REORDERING_WINDOW_SIZE;
|
||||||
import static org.briarproject.bramble.api.transport.TransportConstants.TAG_LENGTH;
|
import static org.briarproject.bramble.api.transport.TransportConstants.TAG_LENGTH;
|
||||||
import static org.briarproject.bramble.util.ByteUtils.MAX_32_BIT_UNSIGNED;
|
import static org.briarproject.bramble.util.ByteUtils.MAX_32_BIT_UNSIGNED;
|
||||||
@@ -86,7 +87,7 @@ public class TransportKeyManagerImplTest extends BrambleTestCase {
|
|||||||
// 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(crypto).encodeTag(with(any(byte[].class)),
|
exactly(6).of(crypto).encodeTag(with(any(byte[].class)),
|
||||||
with(tagKey), with(i));
|
with(tagKey), with(PROTOCOL_VERSION), with(i));
|
||||||
will(new EncodeTagAction());
|
will(new EncodeTagAction());
|
||||||
}
|
}
|
||||||
// Save the keys that were rotated
|
// Save the keys that were rotated
|
||||||
@@ -133,7 +134,7 @@ public class TransportKeyManagerImplTest extends BrambleTestCase {
|
|||||||
// Encode the tags (3 sets)
|
// 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(crypto).encodeTag(with(any(byte[].class)),
|
exactly(3).of(crypto).encodeTag(with(any(byte[].class)),
|
||||||
with(tagKey), with(i));
|
with(tagKey), with(PROTOCOL_VERSION), with(i));
|
||||||
will(new EncodeTagAction());
|
will(new EncodeTagAction());
|
||||||
}
|
}
|
||||||
// Save the keys
|
// Save the keys
|
||||||
@@ -199,7 +200,7 @@ public class TransportKeyManagerImplTest extends BrambleTestCase {
|
|||||||
// Encode the tags (3 sets)
|
// 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(crypto).encodeTag(with(any(byte[].class)),
|
exactly(3).of(crypto).encodeTag(with(any(byte[].class)),
|
||||||
with(tagKey), with(i));
|
with(tagKey), with(PROTOCOL_VERSION), with(i));
|
||||||
will(new EncodeTagAction());
|
will(new EncodeTagAction());
|
||||||
}
|
}
|
||||||
// Rotate the transport keys (the keys are unaffected)
|
// Rotate the transport keys (the keys are unaffected)
|
||||||
@@ -247,7 +248,7 @@ public class TransportKeyManagerImplTest extends BrambleTestCase {
|
|||||||
// Encode the tags (3 sets)
|
// 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(crypto).encodeTag(with(any(byte[].class)),
|
exactly(3).of(crypto).encodeTag(with(any(byte[].class)),
|
||||||
with(tagKey), with(i));
|
with(tagKey), with(PROTOCOL_VERSION), with(i));
|
||||||
will(new EncodeTagAction());
|
will(new EncodeTagAction());
|
||||||
}
|
}
|
||||||
// Rotate the transport keys (the keys are unaffected)
|
// Rotate the transport keys (the keys are unaffected)
|
||||||
@@ -306,7 +307,7 @@ public class TransportKeyManagerImplTest extends BrambleTestCase {
|
|||||||
// Encode the tags (3 sets)
|
// 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(crypto).encodeTag(with(any(byte[].class)),
|
exactly(3).of(crypto).encodeTag(with(any(byte[].class)),
|
||||||
with(tagKey), with(i));
|
with(tagKey), with(PROTOCOL_VERSION), with(i));
|
||||||
will(new EncodeTagAction());
|
will(new EncodeTagAction());
|
||||||
}
|
}
|
||||||
// Rotate the transport keys (the keys are unaffected)
|
// Rotate the transport keys (the keys are unaffected)
|
||||||
@@ -355,7 +356,7 @@ public class TransportKeyManagerImplTest extends BrambleTestCase {
|
|||||||
// Encode the tags (3 sets)
|
// 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(crypto).encodeTag(with(any(byte[].class)),
|
exactly(3).of(crypto).encodeTag(with(any(byte[].class)),
|
||||||
with(tagKey), with(i));
|
with(tagKey), with(PROTOCOL_VERSION), with(i));
|
||||||
will(new EncodeTagAction(tags));
|
will(new EncodeTagAction(tags));
|
||||||
}
|
}
|
||||||
// Rotate the transport keys (the keys are unaffected)
|
// Rotate the transport keys (the keys are unaffected)
|
||||||
@@ -365,7 +366,8 @@ public class TransportKeyManagerImplTest extends BrambleTestCase {
|
|||||||
oneOf(db).addTransportKeys(txn, contactId, transportKeys);
|
oneOf(db).addTransportKeys(txn, contactId, transportKeys);
|
||||||
// Encode a new tag after sliding the window
|
// Encode a new tag after sliding the window
|
||||||
oneOf(crypto).encodeTag(with(any(byte[].class)),
|
oneOf(crypto).encodeTag(with(any(byte[].class)),
|
||||||
with(tagKey), with((long) REORDERING_WINDOW_SIZE));
|
with(tagKey), with(PROTOCOL_VERSION),
|
||||||
|
with((long) REORDERING_WINDOW_SIZE));
|
||||||
will(new EncodeTagAction(tags));
|
will(new EncodeTagAction(tags));
|
||||||
// Save the reordering window (previous rotation period, base 1)
|
// Save the reordering window (previous rotation period, base 1)
|
||||||
oneOf(db).setReorderingWindow(txn, contactId, transportId, 999,
|
oneOf(db).setReorderingWindow(txn, contactId, transportId, 999,
|
||||||
@@ -428,7 +430,7 @@ public class TransportKeyManagerImplTest extends BrambleTestCase {
|
|||||||
// Encode the tags (3 sets)
|
// 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(crypto).encodeTag(with(any(byte[].class)),
|
exactly(3).of(crypto).encodeTag(with(any(byte[].class)),
|
||||||
with(tagKey), with(i));
|
with(tagKey), with(PROTOCOL_VERSION), with(i));
|
||||||
will(new EncodeTagAction());
|
will(new EncodeTagAction());
|
||||||
}
|
}
|
||||||
// Schedule key rotation at the start of the next rotation period
|
// Schedule key rotation at the start of the next rotation period
|
||||||
@@ -450,7 +452,7 @@ public class TransportKeyManagerImplTest extends BrambleTestCase {
|
|||||||
// Encode the tags (3 sets)
|
// 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(crypto).encodeTag(with(any(byte[].class)),
|
exactly(3).of(crypto).encodeTag(with(any(byte[].class)),
|
||||||
with(tagKey), with(i));
|
with(tagKey), with(PROTOCOL_VERSION), with(i));
|
||||||
will(new EncodeTagAction());
|
will(new EncodeTagAction());
|
||||||
}
|
}
|
||||||
// Save the keys that were rotated
|
// Save the keys that were rotated
|
||||||
|
|||||||
@@ -7,10 +7,19 @@ apply plugin: 'witness'
|
|||||||
dependencies {
|
dependencies {
|
||||||
compile project(':bramble-core')
|
compile project(':bramble-core')
|
||||||
compile fileTree(dir: 'libs', include: '*.jar')
|
compile fileTree(dir: 'libs', include: '*.jar')
|
||||||
|
compile 'net.java.dev.jna:jna:4.4.0'
|
||||||
|
compile 'net.java.dev.jna:jna-platform:4.4.0'
|
||||||
|
|
||||||
testCompile project(path: ':bramble-core', configuration: 'testOutput')
|
testCompile project(path: ':bramble-core', configuration: 'testOutput')
|
||||||
}
|
}
|
||||||
|
|
||||||
|
dependencyVerification {
|
||||||
|
verify = [
|
||||||
|
'net.java.dev.jna:jna:c4dadeeecaa90c8847902082aee5eb107fcf59c5d0e63a17fcaf273c0e2d2bd1',
|
||||||
|
'net.java.dev.jna:jna-platform:e9dda9e884fc107eb6367710540789a12dfa8ad28be9326b22ca6e352e325499',
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
tasks.withType(Test) {
|
tasks.withType(Test) {
|
||||||
systemProperty 'java.library.path', 'libs'
|
systemProperty 'java.library.path', 'libs'
|
||||||
}
|
}
|
||||||
|
|||||||
Binary file not shown.
Binary file not shown.
@@ -2,7 +2,6 @@ package org.briarproject.bramble.plugin.bluetooth;
|
|||||||
|
|
||||||
import org.briarproject.bramble.api.FormatException;
|
import org.briarproject.bramble.api.FormatException;
|
||||||
import org.briarproject.bramble.api.contact.ContactId;
|
import org.briarproject.bramble.api.contact.ContactId;
|
||||||
import org.briarproject.bramble.api.crypto.PseudoRandom;
|
|
||||||
import org.briarproject.bramble.api.data.BdfList;
|
import org.briarproject.bramble.api.data.BdfList;
|
||||||
import org.briarproject.bramble.api.keyagreement.KeyAgreementConnection;
|
import org.briarproject.bramble.api.keyagreement.KeyAgreementConnection;
|
||||||
import org.briarproject.bramble.api.keyagreement.KeyAgreementListener;
|
import org.briarproject.bramble.api.keyagreement.KeyAgreementListener;
|
||||||
@@ -19,33 +18,23 @@ import org.briarproject.bramble.util.OsUtils;
|
|||||||
import org.briarproject.bramble.util.StringUtils;
|
import org.briarproject.bramble.util.StringUtils;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
|
||||||
import java.security.SecureRandom;
|
import java.security.SecureRandom;
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Map.Entry;
|
import java.util.Map.Entry;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
import java.util.concurrent.Callable;
|
import java.util.concurrent.Callable;
|
||||||
import java.util.concurrent.CompletionService;
|
|
||||||
import java.util.concurrent.ExecutionException;
|
|
||||||
import java.util.concurrent.Executor;
|
import java.util.concurrent.Executor;
|
||||||
import java.util.concurrent.ExecutorCompletionService;
|
|
||||||
import java.util.concurrent.Future;
|
|
||||||
import java.util.concurrent.Semaphore;
|
|
||||||
import java.util.concurrent.atomic.AtomicBoolean;
|
import java.util.concurrent.atomic.AtomicBoolean;
|
||||||
import java.util.logging.Logger;
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
import javax.bluetooth.BluetoothStateException;
|
import javax.bluetooth.BluetoothStateException;
|
||||||
import javax.bluetooth.DiscoveryAgent;
|
|
||||||
import javax.bluetooth.LocalDevice;
|
import javax.bluetooth.LocalDevice;
|
||||||
import javax.microedition.io.Connector;
|
import javax.microedition.io.Connector;
|
||||||
import javax.microedition.io.StreamConnection;
|
import javax.microedition.io.StreamConnection;
|
||||||
import javax.microedition.io.StreamConnectionNotifier;
|
import javax.microedition.io.StreamConnectionNotifier;
|
||||||
|
|
||||||
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;
|
import static java.util.logging.Level.WARNING;
|
||||||
import static javax.bluetooth.DiscoveryAgent.GIAC;
|
import static javax.bluetooth.DiscoveryAgent.GIAC;
|
||||||
@@ -67,7 +56,6 @@ class BluetoothPlugin implements DuplexPlugin {
|
|||||||
private final Backoff backoff;
|
private final Backoff backoff;
|
||||||
private final DuplexPluginCallback callback;
|
private final DuplexPluginCallback callback;
|
||||||
private final int maxLatency;
|
private final int maxLatency;
|
||||||
private final Semaphore discoverySemaphore = new Semaphore(1);
|
|
||||||
private final AtomicBoolean used = new AtomicBoolean(false);
|
private final AtomicBoolean used = new AtomicBoolean(false);
|
||||||
|
|
||||||
private volatile boolean running = false;
|
private volatile boolean running = false;
|
||||||
@@ -261,8 +249,7 @@ class BluetoothPlugin implements DuplexPlugin {
|
|||||||
@Override
|
@Override
|
||||||
public DuplexTransportConnection createConnection(ContactId c) {
|
public DuplexTransportConnection createConnection(ContactId c) {
|
||||||
if (!running) return null;
|
if (!running) return null;
|
||||||
TransportProperties p = callback.getRemoteProperties().get(c);
|
TransportProperties p = callback.getRemoteProperties(c);
|
||||||
if (p == null) return null;
|
|
||||||
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);
|
||||||
@@ -273,95 +260,6 @@ class BluetoothPlugin implements DuplexPlugin {
|
|||||||
return new BluetoothTransportConnection(this, s);
|
return new BluetoothTransportConnection(this, s);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean supportsInvitations() {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public DuplexTransportConnection createInvitationConnection(PseudoRandom r,
|
|
||||||
long timeout, boolean alice) {
|
|
||||||
if (!running) return null;
|
|
||||||
// Use the invitation codes to generate the UUID
|
|
||||||
byte[] b = r.nextBytes(UUID_BYTES);
|
|
||||||
String uuid = UUID.nameUUIDFromBytes(b).toString();
|
|
||||||
String url = makeUrl("localhost", uuid);
|
|
||||||
// Make the device discoverable if possible
|
|
||||||
makeDeviceDiscoverable();
|
|
||||||
// Bind a server socket for receiving invitation connections
|
|
||||||
final StreamConnectionNotifier ss;
|
|
||||||
try {
|
|
||||||
ss = (StreamConnectionNotifier) Connector.open(url);
|
|
||||||
} catch (IOException e) {
|
|
||||||
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
if (!running) {
|
|
||||||
tryToClose(ss);
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
// Create the background tasks
|
|
||||||
CompletionService<StreamConnection> complete =
|
|
||||||
new ExecutorCompletionService<>(ioExecutor);
|
|
||||||
List<Future<StreamConnection>> futures = new ArrayList<>();
|
|
||||||
if (alice) {
|
|
||||||
// Return the first connected socket
|
|
||||||
futures.add(complete.submit(new ListeningTask(ss)));
|
|
||||||
futures.add(complete.submit(new DiscoveryTask(uuid)));
|
|
||||||
} else {
|
|
||||||
// Return the first socket with readable data
|
|
||||||
futures.add(complete.submit(new ReadableTask(
|
|
||||||
new ListeningTask(ss))));
|
|
||||||
futures.add(complete.submit(new ReadableTask(
|
|
||||||
new DiscoveryTask(uuid))));
|
|
||||||
}
|
|
||||||
StreamConnection chosen = null;
|
|
||||||
try {
|
|
||||||
Future<StreamConnection> f = complete.poll(timeout, MILLISECONDS);
|
|
||||||
if (f == null) return null; // No task completed within the timeout
|
|
||||||
chosen = f.get();
|
|
||||||
return new BluetoothTransportConnection(this, chosen);
|
|
||||||
} catch (InterruptedException e) {
|
|
||||||
LOG.info("Interrupted while exchanging invitations");
|
|
||||||
Thread.currentThread().interrupt();
|
|
||||||
return null;
|
|
||||||
} catch (ExecutionException e) {
|
|
||||||
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
|
||||||
return null;
|
|
||||||
} finally {
|
|
||||||
// Closing the socket will terminate the listener task
|
|
||||||
tryToClose(ss);
|
|
||||||
closeSockets(futures, chosen);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void closeSockets(final List<Future<StreamConnection>> futures,
|
|
||||||
@Nullable final StreamConnection chosen) {
|
|
||||||
ioExecutor.execute(new Runnable() {
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
for (Future<StreamConnection> f : futures) {
|
|
||||||
try {
|
|
||||||
if (f.cancel(true)) {
|
|
||||||
LOG.info("Cancelled task");
|
|
||||||
} else {
|
|
||||||
StreamConnection s = f.get();
|
|
||||||
if (s != null && s != chosen) {
|
|
||||||
LOG.info("Closing unwanted socket");
|
|
||||||
s.close();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (InterruptedException e) {
|
|
||||||
LOG.info("Interrupted while closing sockets");
|
|
||||||
return;
|
|
||||||
} catch (ExecutionException | IOException e) {
|
|
||||||
if (LOG.isLoggable(INFO)) LOG.info(e.toString());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean supportsKeyAgreement() {
|
public boolean supportsKeyAgreement() {
|
||||||
return true;
|
return true;
|
||||||
@@ -376,7 +274,7 @@ class BluetoothPlugin implements DuplexPlugin {
|
|||||||
String url = makeUrl("localhost", uuid);
|
String url = makeUrl("localhost", uuid);
|
||||||
// Make the device discoverable if possible
|
// Make the device discoverable if possible
|
||||||
makeDeviceDiscoverable();
|
makeDeviceDiscoverable();
|
||||||
// Bind a server socket for receiving invitation connections
|
// Bind a server socket for receiving key agreementconnections
|
||||||
final StreamConnectionNotifier ss;
|
final StreamConnectionNotifier ss;
|
||||||
try {
|
try {
|
||||||
ss = (StreamConnectionNotifier) Connector.open(url);
|
ss = (StreamConnectionNotifier) Connector.open(url);
|
||||||
@@ -431,77 +329,6 @@ class BluetoothPlugin implements DuplexPlugin {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private class DiscoveryTask implements Callable<StreamConnection> {
|
|
||||||
|
|
||||||
private final String uuid;
|
|
||||||
|
|
||||||
private DiscoveryTask(String uuid) {
|
|
||||||
this.uuid = uuid;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public StreamConnection call() throws Exception {
|
|
||||||
// Repeat discovery until we connect or get interrupted
|
|
||||||
DiscoveryAgent discoveryAgent = localDevice.getDiscoveryAgent();
|
|
||||||
while (true) {
|
|
||||||
if (!discoverySemaphore.tryAcquire())
|
|
||||||
throw new Exception("Discovery is already in progress");
|
|
||||||
try {
|
|
||||||
InvitationListener listener =
|
|
||||||
new InvitationListener(discoveryAgent, uuid);
|
|
||||||
discoveryAgent.startInquiry(GIAC, listener);
|
|
||||||
String url = listener.waitForUrl();
|
|
||||||
if (url != null) {
|
|
||||||
StreamConnection s = connect(url);
|
|
||||||
if (s != null) {
|
|
||||||
LOG.info("Outgoing connection");
|
|
||||||
return s;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} finally {
|
|
||||||
discoverySemaphore.release();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static class ListeningTask implements Callable<StreamConnection> {
|
|
||||||
|
|
||||||
private final StreamConnectionNotifier serverSocket;
|
|
||||||
|
|
||||||
private ListeningTask(StreamConnectionNotifier serverSocket) {
|
|
||||||
this.serverSocket = serverSocket;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public StreamConnection call() throws Exception {
|
|
||||||
StreamConnection s = serverSocket.acceptAndOpen();
|
|
||||||
LOG.info("Incoming connection");
|
|
||||||
return s;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static class ReadableTask implements Callable<StreamConnection> {
|
|
||||||
|
|
||||||
private final Callable<StreamConnection> connectionTask;
|
|
||||||
|
|
||||||
private ReadableTask(Callable<StreamConnection> connectionTask) {
|
|
||||||
this.connectionTask = connectionTask;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public StreamConnection call() throws Exception {
|
|
||||||
StreamConnection s = connectionTask.call();
|
|
||||||
InputStream in = s.openInputStream();
|
|
||||||
while (in.available() == 0) {
|
|
||||||
LOG.info("Waiting for data");
|
|
||||||
Thread.sleep(1000);
|
|
||||||
}
|
|
||||||
LOG.info("Data available");
|
|
||||||
return s;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private class BluetoothKeyAgreementListener extends KeyAgreementListener {
|
private class BluetoothKeyAgreementListener extends KeyAgreementListener {
|
||||||
|
|
||||||
private final StreamConnectionNotifier ss;
|
private final StreamConnectionNotifier ss;
|
||||||
|
|||||||
@@ -1,109 +0,0 @@
|
|||||||
package org.briarproject.bramble.plugin.bluetooth;
|
|
||||||
|
|
||||||
import java.util.Collection;
|
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.Enumeration;
|
|
||||||
import java.util.TreeSet;
|
|
||||||
import java.util.concurrent.CountDownLatch;
|
|
||||||
import java.util.concurrent.atomic.AtomicInteger;
|
|
||||||
import java.util.logging.Logger;
|
|
||||||
|
|
||||||
import javax.bluetooth.BluetoothStateException;
|
|
||||||
import javax.bluetooth.DataElement;
|
|
||||||
import javax.bluetooth.DeviceClass;
|
|
||||||
import javax.bluetooth.DiscoveryAgent;
|
|
||||||
import javax.bluetooth.DiscoveryListener;
|
|
||||||
import javax.bluetooth.RemoteDevice;
|
|
||||||
import javax.bluetooth.ServiceRecord;
|
|
||||||
import javax.bluetooth.UUID;
|
|
||||||
|
|
||||||
import static java.util.logging.Level.WARNING;
|
|
||||||
|
|
||||||
class InvitationListener implements DiscoveryListener {
|
|
||||||
|
|
||||||
private static final Logger LOG =
|
|
||||||
Logger.getLogger(InvitationListener.class.getName());
|
|
||||||
|
|
||||||
private final AtomicInteger searches = new AtomicInteger(1);
|
|
||||||
private final CountDownLatch finished = new CountDownLatch(1);
|
|
||||||
private final DiscoveryAgent discoveryAgent;
|
|
||||||
private final String uuid;
|
|
||||||
|
|
||||||
private volatile String url = null;
|
|
||||||
|
|
||||||
InvitationListener(DiscoveryAgent discoveryAgent, String uuid) {
|
|
||||||
this.discoveryAgent = discoveryAgent;
|
|
||||||
this.uuid = uuid;
|
|
||||||
}
|
|
||||||
|
|
||||||
String waitForUrl() throws InterruptedException {
|
|
||||||
finished.await();
|
|
||||||
return url;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void deviceDiscovered(RemoteDevice device, DeviceClass deviceClass) {
|
|
||||||
UUID[] uuids = new UUID[] {new UUID(uuid, false)};
|
|
||||||
// Try to discover the services associated with the UUID
|
|
||||||
try {
|
|
||||||
discoveryAgent.searchServices(null, uuids, device, this);
|
|
||||||
searches.incrementAndGet();
|
|
||||||
} catch (BluetoothStateException e) {
|
|
||||||
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void servicesDiscovered(int transaction, ServiceRecord[] services) {
|
|
||||||
for (ServiceRecord record : services) {
|
|
||||||
// Does this service have a URL?
|
|
||||||
String serviceUrl = record.getConnectionURL(
|
|
||||||
ServiceRecord.NOAUTHENTICATE_NOENCRYPT, false);
|
|
||||||
if (serviceUrl == null) continue;
|
|
||||||
// Does this service have the UUID we're looking for?
|
|
||||||
Collection<String> uuids = new TreeSet<>();
|
|
||||||
findNestedClassIds(record.getAttributeValue(0x1), uuids);
|
|
||||||
for (String u : uuids) {
|
|
||||||
if (uuid.equalsIgnoreCase(u)) {
|
|
||||||
// The UUID matches - store the URL
|
|
||||||
url = serviceUrl;
|
|
||||||
finished.countDown();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void inquiryCompleted(int discoveryType) {
|
|
||||||
if (searches.decrementAndGet() == 0) finished.countDown();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void serviceSearchCompleted(int transaction, int response) {
|
|
||||||
if (searches.decrementAndGet() == 0) finished.countDown();
|
|
||||||
}
|
|
||||||
|
|
||||||
// UUIDs are sometimes buried in nested data elements
|
|
||||||
private void findNestedClassIds(Object o, Collection<String> ids) {
|
|
||||||
o = getDataElementValue(o);
|
|
||||||
if (o instanceof Enumeration<?>) {
|
|
||||||
for (Object o1 : Collections.list((Enumeration<?>) o))
|
|
||||||
findNestedClassIds(o1, ids);
|
|
||||||
} else if (o instanceof UUID) {
|
|
||||||
ids.add(o.toString());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private Object getDataElementValue(Object o) {
|
|
||||||
if (o instanceof DataElement) {
|
|
||||||
// Bluecove throws an exception if the type is unknown
|
|
||||||
try {
|
|
||||||
return ((DataElement) o).getValue();
|
|
||||||
} catch (ClassCastException e) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,7 +1,6 @@
|
|||||||
package org.briarproject.bramble.plugin.modem;
|
package org.briarproject.bramble.plugin.modem;
|
||||||
|
|
||||||
import org.briarproject.bramble.api.contact.ContactId;
|
import org.briarproject.bramble.api.contact.ContactId;
|
||||||
import org.briarproject.bramble.api.crypto.PseudoRandom;
|
|
||||||
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.MethodsNotNullByDefault;
|
import org.briarproject.bramble.api.nullsafety.MethodsNotNullByDefault;
|
||||||
@@ -146,8 +145,7 @@ class ModemPlugin implements DuplexPlugin, Modem.Callback {
|
|||||||
String fromIso = callback.getLocalProperties().get("iso3166");
|
String fromIso = callback.getLocalProperties().get("iso3166");
|
||||||
if (StringUtils.isNullOrEmpty(fromIso)) return null;
|
if (StringUtils.isNullOrEmpty(fromIso)) return null;
|
||||||
// Get the ISO 3166 code for the callee's country
|
// Get the ISO 3166 code for the callee's country
|
||||||
TransportProperties properties = callback.getRemoteProperties().get(c);
|
TransportProperties properties = callback.getRemoteProperties(c);
|
||||||
if (properties == null) return null;
|
|
||||||
String toIso = properties.get("iso3166");
|
String toIso = properties.get("iso3166");
|
||||||
if (StringUtils.isNullOrEmpty(toIso)) return null;
|
if (StringUtils.isNullOrEmpty(toIso)) return null;
|
||||||
// Get the callee's phone number
|
// Get the callee's phone number
|
||||||
@@ -167,17 +165,6 @@ class ModemPlugin implements DuplexPlugin, Modem.Callback {
|
|||||||
return new ModemTransportConnection();
|
return new ModemTransportConnection();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean supportsInvitations() {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public DuplexTransportConnection createInvitationConnection(PseudoRandom r,
|
|
||||||
long timeout, boolean alice) {
|
|
||||||
throw new UnsupportedOperationException();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean supportsKeyAgreement() {
|
public boolean supportsKeyAgreement() {
|
||||||
return false;
|
return false;
|
||||||
|
|||||||
@@ -9,8 +9,6 @@ import org.jmock.Mockery;
|
|||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
import static org.junit.Assert.assertNotNull;
|
import static org.junit.Assert.assertNotNull;
|
||||||
import static org.junit.Assert.assertNull;
|
import static org.junit.Assert.assertNull;
|
||||||
@@ -65,12 +63,10 @@ public class ModemPluginTest extends BrambleTestCase {
|
|||||||
final Modem modem = context.mock(Modem.class);
|
final Modem modem = context.mock(Modem.class);
|
||||||
final TransportProperties local = new TransportProperties();
|
final TransportProperties local = new TransportProperties();
|
||||||
local.put("iso3166", ISO_1336);
|
local.put("iso3166", ISO_1336);
|
||||||
TransportProperties p = new TransportProperties();
|
final TransportProperties remote = new TransportProperties();
|
||||||
p.put("iso3166", ISO_1336);
|
remote.put("iso3166", ISO_1336);
|
||||||
p.put("number", NUMBER);
|
remote.put("number", NUMBER);
|
||||||
ContactId contactId = new ContactId(234);
|
final ContactId contactId = new ContactId(234);
|
||||||
final Map<ContactId, TransportProperties> remote =
|
|
||||||
Collections.singletonMap(contactId, p);
|
|
||||||
context.checking(new Expectations() {{
|
context.checking(new Expectations() {{
|
||||||
// start()
|
// start()
|
||||||
oneOf(serialPortList).getPortNames();
|
oneOf(serialPortList).getPortNames();
|
||||||
@@ -82,7 +78,7 @@ public class ModemPluginTest extends BrambleTestCase {
|
|||||||
// createConnection()
|
// createConnection()
|
||||||
oneOf(callback).getLocalProperties();
|
oneOf(callback).getLocalProperties();
|
||||||
will(returnValue(local));
|
will(returnValue(local));
|
||||||
oneOf(callback).getRemoteProperties();
|
oneOf(callback).getRemoteProperties(contactId);
|
||||||
will(returnValue(remote));
|
will(returnValue(remote));
|
||||||
oneOf(modem).dial(NUMBER);
|
oneOf(modem).dial(NUMBER);
|
||||||
will(returnValue(true));
|
will(returnValue(true));
|
||||||
@@ -106,12 +102,10 @@ public class ModemPluginTest extends BrambleTestCase {
|
|||||||
final Modem modem = context.mock(Modem.class);
|
final Modem modem = context.mock(Modem.class);
|
||||||
final TransportProperties local = new TransportProperties();
|
final TransportProperties local = new TransportProperties();
|
||||||
local.put("iso3166", ISO_1336);
|
local.put("iso3166", ISO_1336);
|
||||||
TransportProperties p = new TransportProperties();
|
final TransportProperties remote = new TransportProperties();
|
||||||
p.put("iso3166", ISO_1336);
|
remote.put("iso3166", ISO_1336);
|
||||||
p.put("number", NUMBER);
|
remote.put("number", NUMBER);
|
||||||
ContactId contactId = new ContactId(234);
|
final ContactId contactId = new ContactId(234);
|
||||||
final Map<ContactId, TransportProperties> remote =
|
|
||||||
Collections.singletonMap(contactId, p);
|
|
||||||
context.checking(new Expectations() {{
|
context.checking(new Expectations() {{
|
||||||
// start()
|
// start()
|
||||||
oneOf(serialPortList).getPortNames();
|
oneOf(serialPortList).getPortNames();
|
||||||
@@ -123,7 +117,7 @@ public class ModemPluginTest extends BrambleTestCase {
|
|||||||
// createConnection()
|
// createConnection()
|
||||||
oneOf(callback).getLocalProperties();
|
oneOf(callback).getLocalProperties();
|
||||||
will(returnValue(local));
|
will(returnValue(local));
|
||||||
oneOf(callback).getRemoteProperties();
|
oneOf(callback).getRemoteProperties(contactId);
|
||||||
will(returnValue(remote));
|
will(returnValue(remote));
|
||||||
oneOf(modem).dial(NUMBER);
|
oneOf(modem).dial(NUMBER);
|
||||||
will(returnValue(false));
|
will(returnValue(false));
|
||||||
@@ -147,12 +141,10 @@ public class ModemPluginTest extends BrambleTestCase {
|
|||||||
final Modem modem = context.mock(Modem.class);
|
final Modem modem = context.mock(Modem.class);
|
||||||
final TransportProperties local = new TransportProperties();
|
final TransportProperties local = new TransportProperties();
|
||||||
local.put("iso3166", ISO_1336);
|
local.put("iso3166", ISO_1336);
|
||||||
TransportProperties p = new TransportProperties();
|
final TransportProperties remote = new TransportProperties();
|
||||||
p.put("iso3166", ISO_1336);
|
remote.put("iso3166", ISO_1336);
|
||||||
p.put("number", NUMBER);
|
remote.put("number", NUMBER);
|
||||||
ContactId contactId = new ContactId(234);
|
final ContactId contactId = new ContactId(234);
|
||||||
final Map<ContactId, TransportProperties> remote =
|
|
||||||
Collections.singletonMap(contactId, p);
|
|
||||||
context.checking(new Expectations() {{
|
context.checking(new Expectations() {{
|
||||||
// start()
|
// start()
|
||||||
oneOf(serialPortList).getPortNames();
|
oneOf(serialPortList).getPortNames();
|
||||||
@@ -164,7 +156,7 @@ public class ModemPluginTest extends BrambleTestCase {
|
|||||||
// createConnection()
|
// createConnection()
|
||||||
oneOf(callback).getLocalProperties();
|
oneOf(callback).getLocalProperties();
|
||||||
will(returnValue(local));
|
will(returnValue(local));
|
||||||
oneOf(callback).getRemoteProperties();
|
oneOf(callback).getRemoteProperties(contactId);
|
||||||
will(returnValue(remote));
|
will(returnValue(remote));
|
||||||
oneOf(modem).dial(NUMBER);
|
oneOf(modem).dial(NUMBER);
|
||||||
will(throwException(new IOException()));
|
will(throwException(new IOException()));
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
[main]
|
[main]
|
||||||
host = https://www.transifex.com
|
host = https://www.transifex.com
|
||||||
lang_map = pt_BR: pt-rBR, fr_FR: fr
|
lang_map = pt_BR: pt-rBR, fr_FR: fr, nb_NO: nb, zh-Hans: zh-rCN
|
||||||
|
|
||||||
[briar.stringsxml-5]
|
[briar.stringsxml-5]
|
||||||
file_filter = src/main/res/values-<lang>/strings.xml
|
file_filter = src/main/res/values-<lang>/strings.xml
|
||||||
|
|||||||
@@ -5,13 +5,10 @@ dependencies {
|
|||||||
def supportVersion = '23.2.1'
|
def supportVersion = '23.2.1'
|
||||||
compile project(':briar-core')
|
compile project(':briar-core')
|
||||||
compile project(':bramble-android')
|
compile project(':bramble-android')
|
||||||
compile fileTree(dir: 'libs', include: '*.jar')
|
|
||||||
|
|
||||||
compile "com.android.support:support-v4:$supportVersion"
|
compile "com.android.support:support-v4:$supportVersion"
|
||||||
compile("com.android.support:appcompat-v7:$supportVersion") {
|
compile("com.android.support:appcompat-v7:$supportVersion") {
|
||||||
exclude module: 'support-v4'
|
exclude module: 'support-v4'
|
||||||
}
|
}
|
||||||
|
|
||||||
compile("com.android.support:preference-v14:$supportVersion") {
|
compile("com.android.support:preference-v14:$supportVersion") {
|
||||||
exclude module: 'support-v4'
|
exclude module: 'support-v4'
|
||||||
}
|
}
|
||||||
@@ -20,7 +17,7 @@ dependencies {
|
|||||||
exclude module: 'recyclerview-v7'
|
exclude module: 'recyclerview-v7'
|
||||||
}
|
}
|
||||||
compile "com.android.support:cardview-v7:$supportVersion"
|
compile "com.android.support:cardview-v7:$supportVersion"
|
||||||
compile 'com.android.support:support-annotations:23.4.0'
|
compile "com.android.support:support-annotations:$supportVersion"
|
||||||
compile('ch.acra:acra:4.8.5') {
|
compile('ch.acra:acra:4.8.5') {
|
||||||
exclude module: 'support-v4'
|
exclude module: 'support-v4'
|
||||||
exclude module: 'support-annotations'
|
exclude module: 'support-annotations'
|
||||||
@@ -28,15 +25,16 @@ dependencies {
|
|||||||
compile 'info.guardianproject.panic:panic:0.5'
|
compile 'info.guardianproject.panic:panic:0.5'
|
||||||
compile 'info.guardianproject.trustedintents:trustedintents:0.2'
|
compile 'info.guardianproject.trustedintents:trustedintents:0.2'
|
||||||
compile 'de.hdodenhof:circleimageview:2.1.0'
|
compile 'de.hdodenhof:circleimageview:2.1.0'
|
||||||
compile 'com.google.zxing:core:3.2.1'
|
compile 'com.google.zxing:core:3.3.0'
|
||||||
provided 'javax.annotation:jsr250-api:1.0'
|
|
||||||
compile 'com.jpardogo.materialtabstrip:library:1.1.0'
|
compile 'com.jpardogo.materialtabstrip:library:1.1.0'
|
||||||
compile 'com.github.bumptech.glide:glide:3.7.0'
|
compile 'com.github.bumptech.glide:glide:3.8.0'
|
||||||
compile 'uk.co.samuelwall:material-tap-target-prompt:1.3.0'
|
compile 'uk.co.samuelwall:material-tap-target-prompt:1.9.2'
|
||||||
|
|
||||||
|
provided 'javax.annotation:jsr250-api:1.0'
|
||||||
|
|
||||||
testCompile project(path: ':bramble-core', configuration: 'testOutput')
|
testCompile project(path: ':bramble-core', configuration: 'testOutput')
|
||||||
testCompile 'org.robolectric:robolectric:3.0'
|
testCompile 'org.robolectric:robolectric:3.0'
|
||||||
testCompile 'org.mockito:mockito-core:1.10.19'
|
testCompile 'org.mockito:mockito-core:2.8.9'
|
||||||
}
|
}
|
||||||
|
|
||||||
dependencyVerification {
|
dependencyVerification {
|
||||||
@@ -45,20 +43,18 @@ dependencyVerification {
|
|||||||
'info.guardianproject.panic:panic:a7ed9439826db2e9901649892cf9afbe76f00991b768d8f4c26332d7c9406cb2',
|
'info.guardianproject.panic:panic:a7ed9439826db2e9901649892cf9afbe76f00991b768d8f4c26332d7c9406cb2',
|
||||||
'info.guardianproject.trustedintents:trustedintents:6221456d8821a8d974c2acf86306900237cf6afaaa94a4c9c44e161350f80f3e',
|
'info.guardianproject.trustedintents:trustedintents:6221456d8821a8d974c2acf86306900237cf6afaaa94a4c9c44e161350f80f3e',
|
||||||
'de.hdodenhof:circleimageview:bcbc588e19e6dcf8c120b1957776bfe229efba5d2fbe5da7156372eeacf65503',
|
'de.hdodenhof:circleimageview:bcbc588e19e6dcf8c120b1957776bfe229efba5d2fbe5da7156372eeacf65503',
|
||||||
'com.google.zxing:core:b4d82452e7a6bf6ec2698904b332431717ed8f9a850224f295aec89de80f2259',
|
'com.google.zxing:core:bba7724e02a997cec38213af77133ee8e24b0d5cf5fa7ecbc16a4fa93f11ee0d',
|
||||||
'com.android.support:support-v4:81ce890f26d35c75ad17d0f998a7e3230330c3b41e0b629566bc744bee89e448',
|
'com.jpardogo.materialtabstrip:library:24d19232b319f8c73e25793432357919a7ed972186f57a3b2c9093ea74ad8311',
|
||||||
|
'com.github.bumptech.glide:glide:750d9e7b940dc0ee48f8680623b55d46e14e8727acc922d7b156e57e7c549655',
|
||||||
|
'uk.co.samuelwall:material-tap-target-prompt:5d4951124366bc5c52e57beaa294db7611f0aa2a8d80e0163e1383e1966ba5b2',
|
||||||
'com.android.support:appcompat-v7:00f9d93acacd6731f309724054bf51492814b4b2869f16d7d5c0038dcb8c9a0d',
|
'com.android.support:appcompat-v7:00f9d93acacd6731f309724054bf51492814b4b2869f16d7d5c0038dcb8c9a0d',
|
||||||
'com.android.support:preference-v14:44881bb46094e86d0bc2426f205419674a5b4eb514b44b5a4659b5de29f71eb7',
|
'com.android.support:preference-v14:44881bb46094e86d0bc2426f205419674a5b4eb514b44b5a4659b5de29f71eb7',
|
||||||
'com.android.support:design:003e0c0bea0a6891f8b2bc43f20ae7af2a49a17363e5bb10df5ee0bae12fa686',
|
'com.android.support:design:003e0c0bea0a6891f8b2bc43f20ae7af2a49a17363e5bb10df5ee0bae12fa686',
|
||||||
'com.android.support:support-annotations:e91a88dd0c5e99069b7f09d4a46b5e06f1e9c4c72fc0a8e987e25d86af480f01',
|
'com.android.support:cardview-v7:4595f1c4a28cfa083b6c0920ad4d49e1c2ca4b8302a955e548f68eb63b74931b',
|
||||||
'com.android.support:animated-vector-drawable:06d1963b85aa917099d7757e6a7b3e4dc06889413dc747f625ae8683606db3a1',
|
'com.android.support:animated-vector-drawable:06d1963b85aa917099d7757e6a7b3e4dc06889413dc747f625ae8683606db3a1',
|
||||||
'com.android.support:support-vector-drawable:799bafe4c3de812386f0b291f744d5d6876452722dd40189b9ab87dbbf594ea1',
|
'com.android.support:support-vector-drawable:799bafe4c3de812386f0b291f744d5d6876452722dd40189b9ab87dbbf594ea1',
|
||||||
'com.android.support:recyclerview-v7:44040a888e23e0c93162a3377cfe06751080e3c22d369ab0d4301ef60d63b0fe',
|
'com.android.support:recyclerview-v7:44040a888e23e0c93162a3377cfe06751080e3c22d369ab0d4301ef60d63b0fe',
|
||||||
'com.android.support:preference-v7:775101bd07bd052e455761c5c5d9523d7ad59f2f320e3e8cbde241fd6b1d6025',
|
'com.android.support:preference-v7:775101bd07bd052e455761c5c5d9523d7ad59f2f320e3e8cbde241fd6b1d6025',
|
||||||
'com.android.support:cardview-v7:4595f1c4a28cfa083b6c0920ad4d49e1c2ca4b8302a955e548f68eb63b74931b',
|
|
||||||
'com.jpardogo.materialtabstrip:library:24d19232b319f8c73e25793432357919a7ed972186f57a3b2c9093ea74ad8311',
|
|
||||||
'com.github.bumptech.glide:glide:76ef123957b5fbaebb05fcbe6606dd58c3bc3fcdadb257f99811d0ac9ea9b88b',
|
|
||||||
'uk.co.samuelwall:material-tap-target-prompt:f67e1caead12a914525b32cbf6da52a96b93ff89573f93cb41102ef3130fb64a',
|
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -82,12 +78,19 @@ android {
|
|||||||
defaultConfig {
|
defaultConfig {
|
||||||
minSdkVersion 14
|
minSdkVersion 14
|
||||||
targetSdkVersion 22
|
targetSdkVersion 22
|
||||||
resValue "string", "app_package", "org.briarproject.briar"
|
versionCode 1611
|
||||||
|
versionName "0.16.11"
|
||||||
|
applicationId "org.briarproject.briar.beta"
|
||||||
|
resValue "string", "app_package", "org.briarproject.briar.beta"
|
||||||
|
resValue "string", "app_name", "Briar Beta"
|
||||||
buildConfigField "String", "GitHash", "\"${getGitHash()}\""
|
buildConfigField "String", "GitHash", "\"${getGitHash()}\""
|
||||||
}
|
}
|
||||||
|
|
||||||
buildTypes {
|
buildTypes {
|
||||||
debug {
|
debug {
|
||||||
|
applicationIdSuffix ".debug"
|
||||||
|
resValue "string", "app_package", "org.briarproject.briar.beta.debug"
|
||||||
|
resValue "string", "app_name", "Briar Debug"
|
||||||
shrinkResources false
|
shrinkResources false
|
||||||
minifyEnabled true
|
minifyEnabled true
|
||||||
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.txt'
|
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.txt'
|
||||||
@@ -104,8 +107,13 @@ android {
|
|||||||
targetCompatibility JavaVersion.VERSION_1_7
|
targetCompatibility JavaVersion.VERSION_1_7
|
||||||
}
|
}
|
||||||
|
|
||||||
|
aaptOptions {
|
||||||
|
cruncherEnabled = false
|
||||||
|
}
|
||||||
|
|
||||||
lintOptions {
|
lintOptions {
|
||||||
warning 'MissingTranslation'
|
warning 'MissingTranslation'
|
||||||
warning 'ImpliedQuantity'
|
warning 'ImpliedQuantity'
|
||||||
|
warning 'ExtraTranslation'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,9 +1,7 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<manifest
|
<manifest
|
||||||
package="org.briarproject.briar"
|
package="org.briarproject.briar"
|
||||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
android:versionCode="13"
|
|
||||||
android:versionName="0.13">
|
|
||||||
|
|
||||||
<uses-feature android:name="android.hardware.bluetooth"/>
|
<uses-feature android:name="android.hardware.bluetooth"/>
|
||||||
<uses-feature android:name="android.hardware.camera" />
|
<uses-feature android:name="android.hardware.camera" />
|
||||||
@@ -17,11 +15,9 @@
|
|||||||
<uses-permission android:name="android.permission.READ_LOGS"/>
|
<uses-permission android:name="android.permission.READ_LOGS"/>
|
||||||
<uses-permission android:name="android.permission.VIBRATE" />
|
<uses-permission android:name="android.permission.VIBRATE" />
|
||||||
<uses-permission android:name="android.permission.WAKE_LOCK" />
|
<uses-permission android:name="android.permission.WAKE_LOCK" />
|
||||||
<!-- Since API 23, this is needed to add contacts via Bluetooth -->
|
|
||||||
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
|
|
||||||
|
|
||||||
<application
|
<application
|
||||||
android:name=".android.BriarApplicationImpl"
|
android:name="org.briarproject.briar.android.BriarApplicationImpl"
|
||||||
android:allowBackup="false"
|
android:allowBackup="false"
|
||||||
android:icon="@mipmap/ic_launcher_round"
|
android:icon="@mipmap/ic_launcher_round"
|
||||||
android:label="@string/app_name"
|
android:label="@string/app_name"
|
||||||
@@ -29,15 +25,20 @@
|
|||||||
android:theme="@style/BriarTheme">
|
android:theme="@style/BriarTheme">
|
||||||
|
|
||||||
<service
|
<service
|
||||||
android:name=".android.BriarService"
|
android:name="org.briarproject.briar.android.BriarService"
|
||||||
android:exported="false">
|
android:exported="false">
|
||||||
<intent-filter>
|
<intent-filter>
|
||||||
<action android:name="org.briarproject.briar.android.BriarService"/>
|
<action android:name="org.briarproject.briar.android.BriarService"/>
|
||||||
</intent-filter>
|
</intent-filter>
|
||||||
</service>
|
</service>
|
||||||
|
|
||||||
|
<service
|
||||||
|
android:name="org.briarproject.briar.android.NotificationCleanupService"
|
||||||
|
android:exported="false">
|
||||||
|
</service>
|
||||||
|
|
||||||
<activity
|
<activity
|
||||||
android:name=".android.reporting.DevReportActivity"
|
android:name="org.briarproject.briar.android.reporting.DevReportActivity"
|
||||||
android:excludeFromRecents="true"
|
android:excludeFromRecents="true"
|
||||||
android:exported="false"
|
android:exported="false"
|
||||||
android:finishOnTaskLaunch="true"
|
android:finishOnTaskLaunch="true"
|
||||||
@@ -49,24 +50,24 @@
|
|||||||
</activity>
|
</activity>
|
||||||
|
|
||||||
<activity
|
<activity
|
||||||
android:name=".android.splash.ExpiredActivity"
|
android:name="org.briarproject.briar.android.splash.ExpiredActivity"
|
||||||
android:label="@string/app_name">
|
android:label="@string/app_name">
|
||||||
</activity>
|
</activity>
|
||||||
|
|
||||||
<activity
|
<activity
|
||||||
android:name=".android.login.PasswordActivity"
|
android:name="org.briarproject.briar.android.login.PasswordActivity"
|
||||||
android:label="@string/app_name"
|
android:label="@string/app_name"
|
||||||
android:windowSoftInputMode="stateVisible">
|
android:windowSoftInputMode="stateVisible">
|
||||||
</activity>
|
</activity>
|
||||||
|
|
||||||
<activity
|
<activity
|
||||||
android:name=".android.login.SetupActivity"
|
android:name="org.briarproject.briar.android.login.SetupActivity"
|
||||||
android:label="@string/setup_title"
|
android:label="@string/setup_title"
|
||||||
android:windowSoftInputMode="adjustResize">
|
android:windowSoftInputMode="adjustResize">
|
||||||
</activity>
|
</activity>
|
||||||
|
|
||||||
<activity
|
<activity
|
||||||
android:name=".android.splash.SplashScreenActivity"
|
android:name="org.briarproject.briar.android.splash.SplashScreenActivity"
|
||||||
android:theme="@style/BriarTheme.NoActionBar"
|
android:theme="@style/BriarTheme.NoActionBar"
|
||||||
android:label="@string/app_name">
|
android:label="@string/app_name">
|
||||||
<intent-filter>
|
<intent-filter>
|
||||||
@@ -76,268 +77,258 @@
|
|||||||
</activity>
|
</activity>
|
||||||
|
|
||||||
<activity
|
<activity
|
||||||
android:name=".android.navdrawer.NavDrawerActivity"
|
android:name="org.briarproject.briar.android.navdrawer.NavDrawerActivity"
|
||||||
android:theme="@style/BriarTheme.NoActionBar"
|
android:theme="@style/BriarTheme.NoActionBar"
|
||||||
android:launchMode="singleTop">
|
android:launchMode="singleTop">
|
||||||
</activity>
|
</activity>
|
||||||
|
|
||||||
<activity
|
<activity
|
||||||
android:name=".android.contact.ConversationActivity"
|
android:name="org.briarproject.briar.android.contact.ConversationActivity"
|
||||||
android:label="@string/app_name"
|
android:label="@string/app_name"
|
||||||
android:theme="@style/BriarTheme.NoActionBar"
|
android:theme="@style/BriarTheme.NoActionBar"
|
||||||
android:parentActivityName=".android.navdrawer.NavDrawerActivity"
|
android:parentActivityName="org.briarproject.briar.android.navdrawer.NavDrawerActivity"
|
||||||
android:windowSoftInputMode="stateHidden|adjustResize">
|
android:windowSoftInputMode="stateHidden|adjustResize">
|
||||||
<meta-data
|
<meta-data
|
||||||
android:name="android.support.PARENT_ACTIVITY"
|
android:name="android.support.PARENT_ACTIVITY"
|
||||||
android:value=".android.navdrawer.NavDrawerActivity"
|
android:value="org.briarproject.briar.android.navdrawer.NavDrawerActivity"
|
||||||
/>
|
/>
|
||||||
</activity>
|
</activity>
|
||||||
|
|
||||||
<activity
|
<activity
|
||||||
android:name=".android.privategroup.creation.CreateGroupActivity"
|
android:name="org.briarproject.briar.android.privategroup.creation.CreateGroupActivity"
|
||||||
android:label="@string/groups_create_group_title"
|
android:label="@string/groups_create_group_title"
|
||||||
android:parentActivityName=".android.navdrawer.NavDrawerActivity"
|
android:parentActivityName="org.briarproject.briar.android.navdrawer.NavDrawerActivity"
|
||||||
android:windowSoftInputMode="adjustResize">
|
android:windowSoftInputMode="adjustResize">
|
||||||
<meta-data
|
<meta-data
|
||||||
android:name="android.support.PARENT_ACTIVITY"
|
android:name="android.support.PARENT_ACTIVITY"
|
||||||
android:value=".android.navdrawer.NavDrawerActivity"
|
android:value="org.briarproject.briar.android.navdrawer.NavDrawerActivity"
|
||||||
/>
|
/>
|
||||||
</activity>
|
</activity>
|
||||||
|
|
||||||
<activity
|
<activity
|
||||||
android:name=".android.privategroup.conversation.GroupActivity"
|
android:name="org.briarproject.briar.android.privategroup.conversation.GroupActivity"
|
||||||
android:label="@string/app_name"
|
android:label="@string/app_name"
|
||||||
android:parentActivityName=".android.navdrawer.NavDrawerActivity"
|
android:parentActivityName="org.briarproject.briar.android.navdrawer.NavDrawerActivity"
|
||||||
android:theme="@style/BriarTheme.NoActionBar"
|
android:theme="@style/BriarTheme.NoActionBar"
|
||||||
android:windowSoftInputMode="adjustResize|stateHidden">
|
android:windowSoftInputMode="adjustResize|stateHidden">
|
||||||
<meta-data
|
<meta-data
|
||||||
android:name="android.support.PARENT_ACTIVITY"
|
android:name="android.support.PARENT_ACTIVITY"
|
||||||
android:value=".android.navdrawer.NavDrawerActivity"
|
android:value="org.briarproject.briar.android.navdrawer.NavDrawerActivity"
|
||||||
/>
|
/>
|
||||||
</activity>
|
</activity>
|
||||||
|
|
||||||
<activity
|
<activity
|
||||||
android:name=".android.privategroup.invitation.GroupInvitationActivity"
|
android:name="org.briarproject.briar.android.privategroup.invitation.GroupInvitationActivity"
|
||||||
android:label="@string/groups_invitations_title"
|
android:label="@string/groups_invitations_title"
|
||||||
android:parentActivityName=".android.navdrawer.NavDrawerActivity">
|
android:parentActivityName="org.briarproject.briar.android.navdrawer.NavDrawerActivity">
|
||||||
<meta-data
|
<meta-data
|
||||||
android:name="android.support.PARENT_ACTIVITY"
|
android:name="android.support.PARENT_ACTIVITY"
|
||||||
android:value=".android.navdrawer.NavDrawerActivity"/>
|
android:value="org.briarproject.briar.android.navdrawer.NavDrawerActivity"/>
|
||||||
</activity>
|
</activity>
|
||||||
|
|
||||||
<activity
|
<activity
|
||||||
android:name=".android.privategroup.memberlist.GroupMemberListActivity"
|
android:name="org.briarproject.briar.android.privategroup.memberlist.GroupMemberListActivity"
|
||||||
android:label="@string/groups_member_list"
|
android:label="@string/groups_member_list"
|
||||||
android:parentActivityName=".android.privategroup.conversation.GroupActivity"
|
android:parentActivityName="org.briarproject.briar.android.privategroup.conversation.GroupActivity"
|
||||||
android:windowSoftInputMode="adjustResize|stateHidden">
|
android:windowSoftInputMode="adjustResize|stateHidden">
|
||||||
<meta-data
|
<meta-data
|
||||||
android:name="android.support.PARENT_ACTIVITY"
|
android:name="android.support.PARENT_ACTIVITY"
|
||||||
android:value=".android.privategroup.conversation.GroupActivity"
|
android:value="org.briarproject.briar.android.privategroup.conversation.GroupActivity"
|
||||||
/>
|
/>
|
||||||
</activity>
|
</activity>
|
||||||
|
|
||||||
<activity
|
<activity
|
||||||
android:name=".android.privategroup.reveal.RevealContactsActivity"
|
android:name="org.briarproject.briar.android.privategroup.reveal.RevealContactsActivity"
|
||||||
android:label="@string/groups_reveal_contacts"
|
android:label="@string/groups_reveal_contacts"
|
||||||
android:parentActivityName=".android.privategroup.conversation.GroupActivity"
|
android:parentActivityName="org.briarproject.briar.android.privategroup.conversation.GroupActivity"
|
||||||
android:windowSoftInputMode="adjustResize|stateAlwaysHidden">
|
android:windowSoftInputMode="adjustResize|stateAlwaysHidden">
|
||||||
<meta-data
|
<meta-data
|
||||||
android:name="android.support.PARENT_ACTIVITY"
|
android:name="android.support.PARENT_ACTIVITY"
|
||||||
android:value=".android.privategroup.conversation.GroupActivity"
|
android:value="org.briarproject.briar.android.privategroup.conversation.GroupActivity"
|
||||||
/>
|
/>
|
||||||
</activity>
|
</activity>
|
||||||
|
|
||||||
<activity
|
<activity
|
||||||
android:name=".android.privategroup.creation.GroupInviteActivity"
|
android:name="org.briarproject.briar.android.privategroup.creation.GroupInviteActivity"
|
||||||
android:label="@string/groups_invite_members"
|
android:label="@string/groups_invite_members"
|
||||||
android:parentActivityName=".android.privategroup.conversation.GroupActivity"
|
android:parentActivityName="org.briarproject.briar.android.privategroup.conversation.GroupActivity"
|
||||||
android:windowSoftInputMode="adjustResize|stateHidden">
|
android:windowSoftInputMode="adjustResize|stateHidden">
|
||||||
<meta-data
|
<meta-data
|
||||||
android:name="android.support.PARENT_ACTIVITY"
|
android:name="android.support.PARENT_ACTIVITY"
|
||||||
android:value=".android.privategroup.conversation.GroupActivity"/>
|
android:value="org.briarproject.briar.android.privategroup.conversation.GroupActivity"/>
|
||||||
</activity>
|
</activity>
|
||||||
|
|
||||||
<activity
|
<activity
|
||||||
android:name=".android.sharing.ForumInvitationActivity"
|
android:name="org.briarproject.briar.android.sharing.ForumInvitationActivity"
|
||||||
android:label="@string/forum_invitations_title"
|
android:label="@string/forum_invitations_title"
|
||||||
android:parentActivityName=".android.navdrawer.NavDrawerActivity">
|
android:parentActivityName="org.briarproject.briar.android.navdrawer.NavDrawerActivity">
|
||||||
<meta-data
|
<meta-data
|
||||||
android:name="android.support.PARENT_ACTIVITY"
|
android:name="android.support.PARENT_ACTIVITY"
|
||||||
android:value=".android.navdrawer.NavDrawerActivity"
|
android:value="org.briarproject.briar.android.navdrawer.NavDrawerActivity"
|
||||||
/>
|
/>
|
||||||
</activity>
|
</activity>
|
||||||
|
|
||||||
<activity
|
<activity
|
||||||
android:name=".android.sharing.BlogInvitationActivity"
|
android:name="org.briarproject.briar.android.sharing.BlogInvitationActivity"
|
||||||
android:label="@string/blogs_sharing_invitations_title"
|
android:label="@string/blogs_sharing_invitations_title"
|
||||||
android:parentActivityName=".android.contact.ConversationActivity">
|
android:parentActivityName="org.briarproject.briar.android.contact.ConversationActivity">
|
||||||
<meta-data
|
<meta-data
|
||||||
android:name="android.support.PARENT_ACTIVITY"
|
android:name="android.support.PARENT_ACTIVITY"
|
||||||
android:value=".android.contact.ConversationActivity"
|
android:value="org.briarproject.briar.android.contact.ConversationActivity"
|
||||||
/>
|
/>
|
||||||
</activity>
|
</activity>
|
||||||
|
|
||||||
<activity
|
<activity
|
||||||
android:name=".android.forum.CreateForumActivity"
|
android:name="org.briarproject.briar.android.forum.CreateForumActivity"
|
||||||
android:label="@string/create_forum_title"
|
android:label="@string/create_forum_title"
|
||||||
android:parentActivityName=".android.navdrawer.NavDrawerActivity"
|
android:parentActivityName="org.briarproject.briar.android.navdrawer.NavDrawerActivity"
|
||||||
android:windowSoftInputMode="stateVisible">
|
android:windowSoftInputMode="adjustResize">
|
||||||
<meta-data
|
<meta-data
|
||||||
android:name="android.support.PARENT_ACTIVITY"
|
android:name="android.support.PARENT_ACTIVITY"
|
||||||
android:value=".android.navdrawer.NavDrawerActivity"
|
android:value="org.briarproject.briar.android.navdrawer.NavDrawerActivity"
|
||||||
/>
|
/>
|
||||||
</activity>
|
</activity>
|
||||||
|
|
||||||
<activity
|
<activity
|
||||||
android:name=".android.forum.ForumActivity"
|
android:name="org.briarproject.briar.android.forum.ForumActivity"
|
||||||
android:label="@string/app_name"
|
android:label="@string/app_name"
|
||||||
android:parentActivityName=".android.navdrawer.NavDrawerActivity"
|
android:parentActivityName="org.briarproject.briar.android.navdrawer.NavDrawerActivity"
|
||||||
android:theme="@style/BriarTheme.NoActionBar"
|
android:theme="@style/BriarTheme.NoActionBar"
|
||||||
android:windowSoftInputMode="adjustResize|stateHidden">
|
android:windowSoftInputMode="adjustResize|stateHidden">
|
||||||
<meta-data
|
<meta-data
|
||||||
android:name="android.support.PARENT_ACTIVITY"
|
android:name="android.support.PARENT_ACTIVITY"
|
||||||
android:value=".android.navdrawer.NavDrawerActivity"
|
android:value="org.briarproject.briar.android.navdrawer.NavDrawerActivity"
|
||||||
/>
|
/>
|
||||||
</activity>
|
</activity>
|
||||||
|
|
||||||
<activity
|
<activity
|
||||||
android:name=".android.sharing.ShareForumActivity"
|
android:name="org.briarproject.briar.android.sharing.ShareForumActivity"
|
||||||
android:label="@string/activity_share_toolbar_header"
|
android:label="@string/activity_share_toolbar_header"
|
||||||
android:parentActivityName=".android.forum.ForumActivity"
|
android:parentActivityName="org.briarproject.briar.android.forum.ForumActivity"
|
||||||
android:windowSoftInputMode="adjustResize|stateHidden">
|
android:windowSoftInputMode="adjustResize|stateHidden">
|
||||||
<meta-data
|
<meta-data
|
||||||
android:name="android.support.PARENT_ACTIVITY"
|
android:name="android.support.PARENT_ACTIVITY"
|
||||||
android:value=".android.forum.ForumActivity"
|
android:value="org.briarproject.briar.android.forum.ForumActivity"
|
||||||
/>
|
/>
|
||||||
</activity>
|
</activity>
|
||||||
|
|
||||||
<activity
|
<activity
|
||||||
android:name=".android.sharing.ShareBlogActivity"
|
android:name="org.briarproject.briar.android.sharing.ShareBlogActivity"
|
||||||
android:label="@string/activity_share_toolbar_header"
|
android:label="@string/activity_share_toolbar_header"
|
||||||
android:parentActivityName=".android.blog.BlogActivity"
|
android:parentActivityName="org.briarproject.briar.android.blog.BlogActivity"
|
||||||
android:windowSoftInputMode="adjustResize|stateHidden">
|
android:windowSoftInputMode="adjustResize|stateHidden">
|
||||||
<meta-data
|
<meta-data
|
||||||
android:name="android.support.PARENT_ACTIVITY"
|
android:name="android.support.PARENT_ACTIVITY"
|
||||||
android:value=".android.blog.BlogActivity"
|
android:value="org.briarproject.briar.android.blog.BlogActivity"
|
||||||
/>
|
/>
|
||||||
</activity>
|
</activity>
|
||||||
|
|
||||||
<activity
|
<activity
|
||||||
android:name=".android.sharing.ForumSharingStatusActivity"
|
android:name="org.briarproject.briar.android.sharing.ForumSharingStatusActivity"
|
||||||
android:label="@string/sharing_status"
|
android:label="@string/sharing_status"
|
||||||
android:parentActivityName=".android.forum.ForumActivity">
|
android:parentActivityName="org.briarproject.briar.android.forum.ForumActivity">
|
||||||
<meta-data
|
<meta-data
|
||||||
android:name="android.support.PARENT_ACTIVITY"
|
android:name="android.support.PARENT_ACTIVITY"
|
||||||
android:value=".android.forum.ForumActivity"
|
android:value="org.briarproject.briar.android.forum.ForumActivity"
|
||||||
/>
|
/>
|
||||||
</activity>
|
</activity>
|
||||||
|
|
||||||
<activity
|
<activity
|
||||||
android:name=".android.sharing.BlogSharingStatusActivity"
|
android:name="org.briarproject.briar.android.sharing.BlogSharingStatusActivity"
|
||||||
android:label="@string/sharing_status"
|
android:label="@string/sharing_status"
|
||||||
android:parentActivityName=".android.blog.BlogActivity">
|
android:parentActivityName="org.briarproject.briar.android.blog.BlogActivity">
|
||||||
<meta-data
|
<meta-data
|
||||||
android:name="android.support.PARENT_ACTIVITY"
|
android:name="android.support.PARENT_ACTIVITY"
|
||||||
android:value=".android.blog.BlogActivity"
|
android:value="org.briarproject.briar.android.blog.BlogActivity"
|
||||||
/>
|
/>
|
||||||
</activity>
|
</activity>
|
||||||
|
|
||||||
<activity
|
<activity
|
||||||
android:name=".android.blog.BlogActivity"
|
android:name="org.briarproject.briar.android.blog.BlogActivity"
|
||||||
android:parentActivityName=".android.navdrawer.NavDrawerActivity"
|
android:parentActivityName="org.briarproject.briar.android.navdrawer.NavDrawerActivity"
|
||||||
android:theme="@style/BriarTheme.NoActionBar">
|
android:theme="@style/BriarTheme.NoActionBar">
|
||||||
<meta-data
|
<meta-data
|
||||||
android:name="android.support.PARENT_ACTIVITY"
|
android:name="android.support.PARENT_ACTIVITY"
|
||||||
android:value=".android.navdrawer.NavDrawerActivity"/>
|
android:value="org.briarproject.briar.android.navdrawer.NavDrawerActivity"/>
|
||||||
</activity>
|
</activity>
|
||||||
|
|
||||||
<activity
|
<activity
|
||||||
android:name=".android.blog.WriteBlogPostActivity"
|
android:name="org.briarproject.briar.android.blog.WriteBlogPostActivity"
|
||||||
android:label="@string/blogs_write_blog_post"
|
android:label="@string/blogs_write_blog_post"
|
||||||
android:parentActivityName=".android.blog.BlogActivity"
|
android:parentActivityName="org.briarproject.briar.android.blog.BlogActivity"
|
||||||
android:windowSoftInputMode="stateVisible|adjustResize">
|
android:windowSoftInputMode="stateVisible|adjustResize">
|
||||||
<meta-data
|
<meta-data
|
||||||
android:name="android.support.PARENT_ACTIVITY"
|
android:name="android.support.PARENT_ACTIVITY"
|
||||||
android:value=".android.blog.BlogActivity"
|
android:value="org.briarproject.briar.android.blog.BlogActivity"
|
||||||
/>
|
/>
|
||||||
</activity>
|
</activity>
|
||||||
|
|
||||||
<activity
|
<activity
|
||||||
android:name=".android.blog.ReblogActivity"
|
android:name="org.briarproject.briar.android.blog.ReblogActivity"
|
||||||
android:label="@string/blogs_reblog_button"
|
android:label="@string/blogs_reblog_button"
|
||||||
android:parentActivityName=".android.blog.BlogActivity"
|
android:parentActivityName="org.briarproject.briar.android.blog.BlogActivity"
|
||||||
android:windowSoftInputMode="stateHidden">
|
android:windowSoftInputMode="stateHidden">
|
||||||
<meta-data
|
<meta-data
|
||||||
android:name="android.support.PARENT_ACTIVITY"
|
android:name="android.support.PARENT_ACTIVITY"
|
||||||
android:value=".android.blog.BlogActivity"
|
android:value="org.briarproject.briar.android.blog.BlogActivity"
|
||||||
/>
|
/>
|
||||||
</activity>
|
</activity>
|
||||||
|
|
||||||
<activity
|
<activity
|
||||||
android:name=".android.blog.RssFeedImportActivity"
|
android:name="org.briarproject.briar.android.blog.RssFeedImportActivity"
|
||||||
android:label="@string/blogs_rss_feeds_import"
|
android:label="@string/blogs_rss_feeds_import"
|
||||||
android:parentActivityName=".android.navdrawer.NavDrawerActivity"
|
android:parentActivityName="org.briarproject.briar.android.navdrawer.NavDrawerActivity"
|
||||||
android:windowSoftInputMode="stateVisible|adjustResize">
|
android:windowSoftInputMode="stateVisible|adjustResize">
|
||||||
<meta-data
|
<meta-data
|
||||||
android:name="android.support.PARENT_ACTIVITY"
|
android:name="android.support.PARENT_ACTIVITY"
|
||||||
android:value=".android.navdrawer.NavDrawerActivity"
|
android:value="org.briarproject.briar.android.navdrawer.NavDrawerActivity"
|
||||||
/>
|
/>
|
||||||
</activity>
|
</activity>
|
||||||
|
|
||||||
<activity
|
<activity
|
||||||
android:name=".android.blog.RssFeedManageActivity"
|
android:name="org.briarproject.briar.android.blog.RssFeedManageActivity"
|
||||||
android:label="@string/blogs_rss_feeds_manage"
|
android:label="@string/blogs_rss_feeds_manage"
|
||||||
android:parentActivityName=".android.navdrawer.NavDrawerActivity">
|
android:parentActivityName="org.briarproject.briar.android.navdrawer.NavDrawerActivity">
|
||||||
<meta-data
|
<meta-data
|
||||||
android:name="android.support.PARENT_ACTIVITY"
|
android:name="android.support.PARENT_ACTIVITY"
|
||||||
android:value=".android.navdrawer.NavDrawerActivity"
|
android:value="org.briarproject.briar.android.navdrawer.NavDrawerActivity"
|
||||||
/>
|
/>
|
||||||
</activity>
|
</activity>
|
||||||
|
|
||||||
<activity
|
<activity
|
||||||
android:name=".android.invitation.AddContactActivity"
|
android:name="org.briarproject.briar.android.keyagreement.KeyAgreementActivity"
|
||||||
android:label="@string/add_contact_title"
|
|
||||||
android:parentActivityName=".android.navdrawer.NavDrawerActivity">
|
|
||||||
<meta-data
|
|
||||||
android:name="android.support.PARENT_ACTIVITY"
|
|
||||||
android:value=".android.navdrawer.NavDrawerActivity"
|
|
||||||
/>
|
|
||||||
</activity>
|
|
||||||
|
|
||||||
<activity
|
|
||||||
android:name=".android.keyagreement.KeyAgreementActivity"
|
|
||||||
android:label="@string/add_contact_title"
|
android:label="@string/add_contact_title"
|
||||||
android:theme="@style/BriarTheme.NoActionBar"
|
android:theme="@style/BriarTheme.NoActionBar"
|
||||||
android:parentActivityName=".android.navdrawer.NavDrawerActivity">
|
android:parentActivityName="org.briarproject.briar.android.navdrawer.NavDrawerActivity">
|
||||||
<meta-data
|
<meta-data
|
||||||
android:name="android.support.PARENT_ACTIVITY"
|
android:name="android.support.PARENT_ACTIVITY"
|
||||||
android:value=".android.navdrawer.NavDrawerActivity"/>
|
android:value="org.briarproject.briar.android.navdrawer.NavDrawerActivity"/>
|
||||||
</activity>
|
</activity>
|
||||||
|
|
||||||
<activity
|
<activity
|
||||||
android:name=".android.introduction.IntroductionActivity"
|
android:name="org.briarproject.briar.android.introduction.IntroductionActivity"
|
||||||
android:label="@string/introduction_activity_title"
|
android:label="@string/introduction_activity_title"
|
||||||
android:parentActivityName=".android.contact.ConversationActivity"
|
android:parentActivityName="org.briarproject.briar.android.contact.ConversationActivity"
|
||||||
android:windowSoftInputMode="stateHidden|adjustResize">
|
android:windowSoftInputMode="stateHidden|adjustResize">
|
||||||
<meta-data
|
<meta-data
|
||||||
android:name="android.support.PARENT_ACTIVITY"
|
android:name="android.support.PARENT_ACTIVITY"
|
||||||
android:value=".android.contact.ConversationActivity"
|
android:value="org.briarproject.briar.android.contact.ConversationActivity"
|
||||||
/>
|
/>
|
||||||
</activity>
|
</activity>
|
||||||
|
|
||||||
<activity
|
<activity
|
||||||
android:name=".android.StartupFailureActivity"
|
android:name="org.briarproject.briar.android.StartupFailureActivity"
|
||||||
android:label="@string/startup_failed_activity_title">
|
android:label="@string/startup_failed_activity_title">
|
||||||
</activity>
|
</activity>
|
||||||
|
|
||||||
<activity
|
<activity
|
||||||
android:name=".android.settings.SettingsActivity"
|
android:name="org.briarproject.briar.android.settings.SettingsActivity"
|
||||||
android:label="@string/settings_button"
|
android:label="@string/settings_button"
|
||||||
android:parentActivityName=".android.navdrawer.NavDrawerActivity"
|
android:parentActivityName="org.briarproject.briar.android.navdrawer.NavDrawerActivity"
|
||||||
android:permission="android.permission.READ_NETWORK_USAGE_HISTORY">
|
android:permission="android.permission.READ_NETWORK_USAGE_HISTORY">
|
||||||
<meta-data
|
<meta-data
|
||||||
android:name="android.support.PARENT_ACTIVITY"
|
android:name="android.support.PARENT_ACTIVITY"
|
||||||
android:value=".android.navdrawer.NavDrawerActivity"
|
android:value="org.briarproject.briar.android.navdrawer.NavDrawerActivity"
|
||||||
/>
|
/>
|
||||||
<intent-filter>
|
<intent-filter>
|
||||||
<action android:name="android.intent.action.MANAGE_NETWORK_USAGE"/>
|
<action android:name="android.intent.action.MANAGE_NETWORK_USAGE"/>
|
||||||
@@ -346,27 +337,27 @@
|
|||||||
</activity>
|
</activity>
|
||||||
|
|
||||||
<activity
|
<activity
|
||||||
android:name=".android.login.ChangePasswordActivity"
|
android:name="org.briarproject.briar.android.login.ChangePasswordActivity"
|
||||||
android:label="@string/change_password"
|
android:label="@string/change_password"
|
||||||
android:parentActivityName=".android.settings.SettingsActivity">
|
android:parentActivityName="org.briarproject.briar.android.settings.SettingsActivity">
|
||||||
<meta-data
|
<meta-data
|
||||||
android:name="android.support.PARENT_ACTIVITY"
|
android:name="android.support.PARENT_ACTIVITY"
|
||||||
android:value=".android.settings.SettingsActivity"
|
android:value="org.briarproject.briar.android.settings.SettingsActivity"
|
||||||
/>
|
/>
|
||||||
</activity>
|
</activity>
|
||||||
|
|
||||||
<activity
|
<activity
|
||||||
android:name=".android.panic.PanicPreferencesActivity"
|
android:name="org.briarproject.briar.android.panic.PanicPreferencesActivity"
|
||||||
android:label="@string/panic_setting"
|
android:label="@string/panic_setting"
|
||||||
android:parentActivityName=".android.settings.SettingsActivity">
|
android:parentActivityName="org.briarproject.briar.android.settings.SettingsActivity">
|
||||||
<meta-data
|
<meta-data
|
||||||
android:name="android.support.PARENT_ACTIVITY"
|
android:name="android.support.PARENT_ACTIVITY"
|
||||||
android:value=".android.settings.SettingsActivity"
|
android:value="org.briarproject.briar.android.settings.SettingsActivity"
|
||||||
/>
|
/>
|
||||||
</activity>
|
</activity>
|
||||||
|
|
||||||
<activity
|
<activity
|
||||||
android:name=".android.panic.PanicResponderActivity"
|
android:name="org.briarproject.briar.android.panic.PanicResponderActivity"
|
||||||
android:noHistory="true"
|
android:noHistory="true"
|
||||||
android:theme="@android:style/Theme.NoDisplay">
|
android:theme="@android:style/Theme.NoDisplay">
|
||||||
<!-- this can never have launchMode singleTask or singleInstance! -->
|
<!-- this can never have launchMode singleTask or singleInstance! -->
|
||||||
@@ -377,7 +368,7 @@
|
|||||||
</activity>
|
</activity>
|
||||||
|
|
||||||
<activity
|
<activity
|
||||||
android:name=".android.panic.ExitActivity"
|
android:name="org.briarproject.briar.android.panic.ExitActivity"
|
||||||
android:theme="@android:style/Theme.NoDisplay">
|
android:theme="@android:style/Theme.NoDisplay">
|
||||||
</activity>
|
</activity>
|
||||||
|
|
||||||
|
|||||||
@@ -12,7 +12,6 @@ import org.briarproject.bramble.api.db.DatabaseConfig;
|
|||||||
import org.briarproject.bramble.api.db.DatabaseExecutor;
|
import org.briarproject.bramble.api.db.DatabaseExecutor;
|
||||||
import org.briarproject.bramble.api.event.EventBus;
|
import org.briarproject.bramble.api.event.EventBus;
|
||||||
import org.briarproject.bramble.api.identity.IdentityManager;
|
import org.briarproject.bramble.api.identity.IdentityManager;
|
||||||
import org.briarproject.bramble.api.invitation.InvitationTaskFactory;
|
|
||||||
import org.briarproject.bramble.api.keyagreement.KeyAgreementTaskFactory;
|
import org.briarproject.bramble.api.keyagreement.KeyAgreementTaskFactory;
|
||||||
import org.briarproject.bramble.api.keyagreement.PayloadEncoder;
|
import org.briarproject.bramble.api.keyagreement.PayloadEncoder;
|
||||||
import org.briarproject.bramble.api.keyagreement.PayloadParser;
|
import org.briarproject.bramble.api.keyagreement.PayloadParser;
|
||||||
@@ -27,11 +26,11 @@ import org.briarproject.briar.BriarCoreEagerSingletons;
|
|||||||
import org.briarproject.briar.BriarCoreModule;
|
import org.briarproject.briar.BriarCoreModule;
|
||||||
import org.briarproject.briar.android.reporting.BriarReportSender;
|
import org.briarproject.briar.android.reporting.BriarReportSender;
|
||||||
import org.briarproject.briar.api.android.AndroidNotificationManager;
|
import org.briarproject.briar.api.android.AndroidNotificationManager;
|
||||||
import org.briarproject.briar.api.android.ReferenceManager;
|
|
||||||
import org.briarproject.briar.api.android.ScreenFilterMonitor;
|
import org.briarproject.briar.api.android.ScreenFilterMonitor;
|
||||||
import org.briarproject.briar.api.blog.BlogManager;
|
import org.briarproject.briar.api.blog.BlogManager;
|
||||||
import org.briarproject.briar.api.blog.BlogPostFactory;
|
import org.briarproject.briar.api.blog.BlogPostFactory;
|
||||||
import org.briarproject.briar.api.blog.BlogSharingManager;
|
import org.briarproject.briar.api.blog.BlogSharingManager;
|
||||||
|
import org.briarproject.briar.api.client.MessageTracker;
|
||||||
import org.briarproject.briar.api.feed.FeedManager;
|
import org.briarproject.briar.api.feed.FeedManager;
|
||||||
import org.briarproject.briar.api.forum.ForumManager;
|
import org.briarproject.briar.api.forum.ForumManager;
|
||||||
import org.briarproject.briar.api.forum.ForumSharingManager;
|
import org.briarproject.briar.api.forum.ForumSharingManager;
|
||||||
@@ -44,6 +43,7 @@ import org.briarproject.briar.api.privategroup.PrivateGroupFactory;
|
|||||||
import org.briarproject.briar.api.privategroup.PrivateGroupManager;
|
import org.briarproject.briar.api.privategroup.PrivateGroupManager;
|
||||||
import org.briarproject.briar.api.privategroup.invitation.GroupInvitationFactory;
|
import org.briarproject.briar.api.privategroup.invitation.GroupInvitationFactory;
|
||||||
import org.briarproject.briar.api.privategroup.invitation.GroupInvitationManager;
|
import org.briarproject.briar.api.privategroup.invitation.GroupInvitationManager;
|
||||||
|
import org.briarproject.briar.api.test.TestDataCreator;
|
||||||
import org.thoughtcrime.securesms.components.emoji.EmojiProvider;
|
import org.thoughtcrime.securesms.components.emoji.EmojiProvider;
|
||||||
import org.thoughtcrime.securesms.components.emoji.RecentEmojiPageModel;
|
import org.thoughtcrime.securesms.components.emoji.RecentEmojiPageModel;
|
||||||
|
|
||||||
@@ -73,11 +73,11 @@ public interface AndroidComponent
|
|||||||
|
|
||||||
DatabaseConfig databaseConfig();
|
DatabaseConfig databaseConfig();
|
||||||
|
|
||||||
ReferenceManager referenceMangager();
|
|
||||||
|
|
||||||
@DatabaseExecutor
|
@DatabaseExecutor
|
||||||
Executor databaseExecutor();
|
Executor databaseExecutor();
|
||||||
|
|
||||||
|
MessageTracker messageTracker();
|
||||||
|
|
||||||
LifecycleManager lifecycleManager();
|
LifecycleManager lifecycleManager();
|
||||||
|
|
||||||
IdentityManager identityManager();
|
IdentityManager identityManager();
|
||||||
@@ -86,8 +86,6 @@ public interface AndroidComponent
|
|||||||
|
|
||||||
EventBus eventBus();
|
EventBus eventBus();
|
||||||
|
|
||||||
InvitationTaskFactory invitationTaskFactory();
|
|
||||||
|
|
||||||
AndroidNotificationManager androidNotificationManager();
|
AndroidNotificationManager androidNotificationManager();
|
||||||
|
|
||||||
ScreenFilterMonitor screenFilterMonitor();
|
ScreenFilterMonitor screenFilterMonitor();
|
||||||
@@ -140,6 +138,8 @@ public interface AndroidComponent
|
|||||||
|
|
||||||
Clock clock();
|
Clock clock();
|
||||||
|
|
||||||
|
TestDataCreator testDataCreator();
|
||||||
|
|
||||||
@IoExecutor
|
@IoExecutor
|
||||||
Executor ioExecutor();
|
Executor ioExecutor();
|
||||||
|
|
||||||
@@ -151,6 +151,8 @@ public interface AndroidComponent
|
|||||||
|
|
||||||
void inject(RecentEmojiPageModel recentEmojiPageModel);
|
void inject(RecentEmojiPageModel recentEmojiPageModel);
|
||||||
|
|
||||||
|
void inject(NotificationCleanupService notificationCleanupService);
|
||||||
|
|
||||||
// Eager singleton load
|
// Eager singleton load
|
||||||
void inject(AppModule.EagerSingletons init);
|
void inject(AppModule.EagerSingletons init);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,14 +2,12 @@ package org.briarproject.briar.android;
|
|||||||
|
|
||||||
import android.app.Application;
|
import android.app.Application;
|
||||||
import android.app.NotificationManager;
|
import android.app.NotificationManager;
|
||||||
|
import android.app.PendingIntent;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
import android.os.Build;
|
|
||||||
import android.support.annotation.UiThread;
|
import android.support.annotation.UiThread;
|
||||||
import android.support.v4.app.NotificationCompat;
|
|
||||||
import android.support.v4.app.TaskStackBuilder;
|
import android.support.v4.app.TaskStackBuilder;
|
||||||
import android.support.v4.content.ContextCompat;
|
|
||||||
|
|
||||||
import org.briarproject.bramble.api.contact.ContactId;
|
import org.briarproject.bramble.api.contact.ContactId;
|
||||||
import org.briarproject.bramble.api.db.DatabaseExecutor;
|
import org.briarproject.bramble.api.db.DatabaseExecutor;
|
||||||
@@ -25,12 +23,14 @@ import org.briarproject.bramble.api.settings.SettingsManager;
|
|||||||
import org.briarproject.bramble.api.settings.event.SettingsUpdatedEvent;
|
import org.briarproject.bramble.api.settings.event.SettingsUpdatedEvent;
|
||||||
import org.briarproject.bramble.api.sync.GroupId;
|
import org.briarproject.bramble.api.sync.GroupId;
|
||||||
import org.briarproject.bramble.api.system.AndroidExecutor;
|
import org.briarproject.bramble.api.system.AndroidExecutor;
|
||||||
|
import org.briarproject.bramble.api.system.Clock;
|
||||||
import org.briarproject.bramble.util.StringUtils;
|
import org.briarproject.bramble.util.StringUtils;
|
||||||
import org.briarproject.briar.R;
|
import org.briarproject.briar.R;
|
||||||
import org.briarproject.briar.android.contact.ConversationActivity;
|
import org.briarproject.briar.android.contact.ConversationActivity;
|
||||||
import org.briarproject.briar.android.forum.ForumActivity;
|
import org.briarproject.briar.android.forum.ForumActivity;
|
||||||
import org.briarproject.briar.android.navdrawer.NavDrawerActivity;
|
import org.briarproject.briar.android.navdrawer.NavDrawerActivity;
|
||||||
import org.briarproject.briar.android.privategroup.conversation.GroupActivity;
|
import org.briarproject.briar.android.privategroup.conversation.GroupActivity;
|
||||||
|
import org.briarproject.briar.android.util.BriarNotificationBuilder;
|
||||||
import org.briarproject.briar.api.android.AndroidNotificationManager;
|
import org.briarproject.briar.api.android.AndroidNotificationManager;
|
||||||
import org.briarproject.briar.api.blog.event.BlogPostAddedEvent;
|
import org.briarproject.briar.api.blog.event.BlogPostAddedEvent;
|
||||||
import org.briarproject.briar.api.forum.event.ForumPostReceivedEvent;
|
import org.briarproject.briar.api.forum.event.ForumPostReceivedEvent;
|
||||||
@@ -48,6 +48,7 @@ import java.util.concurrent.Callable;
|
|||||||
import java.util.concurrent.ExecutionException;
|
import java.util.concurrent.ExecutionException;
|
||||||
import java.util.concurrent.Executor;
|
import java.util.concurrent.Executor;
|
||||||
import java.util.concurrent.Future;
|
import java.util.concurrent.Future;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
import java.util.concurrent.atomic.AtomicBoolean;
|
import java.util.concurrent.atomic.AtomicBoolean;
|
||||||
import java.util.logging.Logger;
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
@@ -61,7 +62,6 @@ import static android.content.Context.NOTIFICATION_SERVICE;
|
|||||||
import static android.content.Intent.FLAG_ACTIVITY_CLEAR_TOP;
|
import static android.content.Intent.FLAG_ACTIVITY_CLEAR_TOP;
|
||||||
import static android.support.v4.app.NotificationCompat.CATEGORY_MESSAGE;
|
import static android.support.v4.app.NotificationCompat.CATEGORY_MESSAGE;
|
||||||
import static android.support.v4.app.NotificationCompat.CATEGORY_SOCIAL;
|
import static android.support.v4.app.NotificationCompat.CATEGORY_SOCIAL;
|
||||||
import static android.support.v4.app.NotificationCompat.VISIBILITY_SECRET;
|
|
||||||
import static java.util.logging.Level.WARNING;
|
import static java.util.logging.Level.WARNING;
|
||||||
import static org.briarproject.briar.android.activity.BriarActivity.GROUP_ID;
|
import static org.briarproject.briar.android.activity.BriarActivity.GROUP_ID;
|
||||||
import static org.briarproject.briar.android.contact.ConversationActivity.CONTACT_ID;
|
import static org.briarproject.briar.android.contact.ConversationActivity.CONTACT_ID;
|
||||||
@@ -84,15 +84,7 @@ class AndroidNotificationManagerImpl implements AndroidNotificationManager,
|
|||||||
private static final int BLOG_POST_NOTIFICATION_ID = 6;
|
private static final int BLOG_POST_NOTIFICATION_ID = 6;
|
||||||
private static final int INTRODUCTION_SUCCESS_NOTIFICATION_ID = 7;
|
private static final int INTRODUCTION_SUCCESS_NOTIFICATION_ID = 7;
|
||||||
|
|
||||||
// Content URIs to differentiate between pending intents
|
private static final long SOUND_DELAY = TimeUnit.SECONDS.toMillis(2);
|
||||||
private static final String CONTACT_URI =
|
|
||||||
"content://org.briarproject.briar/contact";
|
|
||||||
private static final String GROUP_URI =
|
|
||||||
"content://org.briarproject.briar/group";
|
|
||||||
private static final String FORUM_URI =
|
|
||||||
"content://org.briarproject.briar/forum";
|
|
||||||
private static final String BLOG_URI =
|
|
||||||
"content://org.briarproject.briar/blog";
|
|
||||||
|
|
||||||
private static final Logger LOG =
|
private static final Logger LOG =
|
||||||
Logger.getLogger(AndroidNotificationManagerImpl.class.getName());
|
Logger.getLogger(AndroidNotificationManagerImpl.class.getName());
|
||||||
@@ -101,6 +93,7 @@ class AndroidNotificationManagerImpl implements AndroidNotificationManager,
|
|||||||
private final SettingsManager settingsManager;
|
private final SettingsManager settingsManager;
|
||||||
private final AndroidExecutor androidExecutor;
|
private final AndroidExecutor androidExecutor;
|
||||||
private final Context appContext;
|
private final Context appContext;
|
||||||
|
private final Clock clock;
|
||||||
private final AtomicBoolean used = new AtomicBoolean(false);
|
private final AtomicBoolean used = new AtomicBoolean(false);
|
||||||
|
|
||||||
// The following must only be accessed on the main UI thread
|
// The following must only be accessed on the main UI thread
|
||||||
@@ -116,16 +109,18 @@ class AndroidNotificationManagerImpl implements AndroidNotificationManager,
|
|||||||
private boolean blockContacts = false, blockGroups = false;
|
private boolean blockContacts = false, blockGroups = false;
|
||||||
private boolean blockForums = false, blockBlogs = false;
|
private boolean blockForums = false, blockBlogs = false;
|
||||||
private boolean blockIntroductions = false;
|
private boolean blockIntroductions = false;
|
||||||
|
private long lastSound = 0;
|
||||||
|
|
||||||
private volatile Settings settings = new Settings();
|
private volatile Settings settings = new Settings();
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
AndroidNotificationManagerImpl(@DatabaseExecutor Executor dbExecutor,
|
AndroidNotificationManagerImpl(@DatabaseExecutor Executor dbExecutor,
|
||||||
SettingsManager settingsManager, AndroidExecutor androidExecutor,
|
SettingsManager settingsManager, AndroidExecutor androidExecutor,
|
||||||
Application app) {
|
Application app, Clock clock) {
|
||||||
this.dbExecutor = dbExecutor;
|
this.dbExecutor = dbExecutor;
|
||||||
this.settingsManager = settingsManager;
|
this.settingsManager = settingsManager;
|
||||||
this.androidExecutor = androidExecutor;
|
this.androidExecutor = androidExecutor;
|
||||||
|
this.clock = clock;
|
||||||
appContext = app.getApplicationContext();
|
appContext = app.getApplicationContext();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -264,7 +259,7 @@ class AndroidNotificationManagerImpl implements AndroidNotificationManager,
|
|||||||
if (count == null) contactCounts.put(c, 1);
|
if (count == null) contactCounts.put(c, 1);
|
||||||
else contactCounts.put(c, count + 1);
|
else contactCounts.put(c, count + 1);
|
||||||
contactTotal++;
|
contactTotal++;
|
||||||
updateContactNotification();
|
updateContactNotification(true);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -277,32 +272,30 @@ class AndroidNotificationManagerImpl implements AndroidNotificationManager,
|
|||||||
Integer count = contactCounts.remove(c);
|
Integer count = contactCounts.remove(c);
|
||||||
if (count == null) return; // Already cleared
|
if (count == null) return; // Already cleared
|
||||||
contactTotal -= count;
|
contactTotal -= count;
|
||||||
updateContactNotification();
|
updateContactNotification(false);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@UiThread
|
@UiThread
|
||||||
private void updateContactNotification() {
|
private void updateContactNotification(boolean mayAlertAgain) {
|
||||||
if (contactTotal == 0) {
|
if (contactTotal == 0) {
|
||||||
clearContactNotification();
|
clearContactNotification();
|
||||||
} else if (settings.getBoolean(PREF_NOTIFY_PRIVATE, true)) {
|
} else if (settings.getBoolean(PREF_NOTIFY_PRIVATE, true)) {
|
||||||
NotificationCompat.Builder b =
|
BriarNotificationBuilder b =
|
||||||
new NotificationCompat.Builder(appContext);
|
new BriarNotificationBuilder(appContext);
|
||||||
b.setSmallIcon(R.drawable.notification_private_message);
|
b.setSmallIcon(R.drawable.notification_private_message);
|
||||||
b.setColor(ContextCompat.getColor(appContext,
|
b.setColorRes(R.color.briar_primary);
|
||||||
R.color.briar_primary));
|
|
||||||
b.setContentTitle(appContext.getText(R.string.app_name));
|
b.setContentTitle(appContext.getText(R.string.app_name));
|
||||||
b.setContentText(appContext.getResources().getQuantityString(
|
b.setContentText(appContext.getResources().getQuantityString(
|
||||||
R.plurals.private_message_notification_text, contactTotal,
|
R.plurals.private_message_notification_text, contactTotal,
|
||||||
contactTotal));
|
contactTotal));
|
||||||
boolean sound = settings.getBoolean(PREF_NOTIFY_SOUND, true);
|
b.setNumber(contactTotal);
|
||||||
String ringtoneUri = settings.get(PREF_NOTIFY_RINGTONE_URI);
|
boolean showOnLockScreen =
|
||||||
if (sound && !StringUtils.isNullOrEmpty(ringtoneUri))
|
settings.getBoolean(PREF_NOTIFY_LOCK_SCREEN, false);
|
||||||
b.setSound(Uri.parse(ringtoneUri));
|
b.setLockscreenVisibility(CATEGORY_MESSAGE, showOnLockScreen);
|
||||||
b.setDefaults(getDefaults());
|
if (mayAlertAgain) setAlertProperties(b);
|
||||||
b.setOnlyAlertOnce(true);
|
setDeleteIntent(b, CONTACT_URI);
|
||||||
b.setAutoCancel(true);
|
|
||||||
if (contactCounts.size() == 1) {
|
if (contactCounts.size() == 1) {
|
||||||
// Touching the notification shows the relevant conversation
|
// Touching the notification shows the relevant conversation
|
||||||
Intent i = new Intent(appContext, ConversationActivity.class);
|
Intent i = new Intent(appContext, ConversationActivity.class);
|
||||||
@@ -325,16 +318,25 @@ class AndroidNotificationManagerImpl implements AndroidNotificationManager,
|
|||||||
t.addNextIntent(i);
|
t.addNextIntent(i);
|
||||||
b.setContentIntent(t.getPendingIntent(nextRequestId++, 0));
|
b.setContentIntent(t.getPendingIntent(nextRequestId++, 0));
|
||||||
}
|
}
|
||||||
if (Build.VERSION.SDK_INT >= 21) {
|
|
||||||
b.setCategory(CATEGORY_MESSAGE);
|
|
||||||
b.setVisibility(VISIBILITY_SECRET);
|
|
||||||
}
|
|
||||||
Object o = appContext.getSystemService(NOTIFICATION_SERVICE);
|
Object o = appContext.getSystemService(NOTIFICATION_SERVICE);
|
||||||
NotificationManager nm = (NotificationManager) o;
|
NotificationManager nm = (NotificationManager) o;
|
||||||
nm.notify(PRIVATE_MESSAGE_NOTIFICATION_ID, b.build());
|
nm.notify(PRIVATE_MESSAGE_NOTIFICATION_ID, b.build());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@UiThread
|
||||||
|
private void setAlertProperties(BriarNotificationBuilder b) {
|
||||||
|
long currentTime = clock.currentTimeMillis();
|
||||||
|
if (currentTime - lastSound > SOUND_DELAY) {
|
||||||
|
boolean sound = settings.getBoolean(PREF_NOTIFY_SOUND, true);
|
||||||
|
String ringtoneUri = settings.get(PREF_NOTIFY_RINGTONE_URI);
|
||||||
|
if (sound && !StringUtils.isNullOrEmpty(ringtoneUri))
|
||||||
|
b.setSound(Uri.parse(ringtoneUri));
|
||||||
|
b.setDefaults(getDefaults());
|
||||||
|
lastSound = currentTime;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@UiThread
|
@UiThread
|
||||||
private int getDefaults() {
|
private int getDefaults() {
|
||||||
int defaults = DEFAULT_LIGHTS;
|
int defaults = DEFAULT_LIGHTS;
|
||||||
@@ -347,13 +349,19 @@ class AndroidNotificationManagerImpl implements AndroidNotificationManager,
|
|||||||
return defaults;
|
return defaults;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void setDeleteIntent(BriarNotificationBuilder b, String uri) {
|
||||||
|
Intent i = new Intent(appContext, NotificationCleanupService.class);
|
||||||
|
i.setData(Uri.parse(uri));
|
||||||
|
b.setDeleteIntent(PendingIntent.getService(appContext, nextRequestId++,
|
||||||
|
i, 0));
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void clearAllContactNotifications() {
|
public void clearAllContactNotifications() {
|
||||||
androidExecutor.runOnUiThread(new Runnable() {
|
androidExecutor.runOnUiThread(new Runnable() {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
clearContactNotification();
|
clearContactNotification();
|
||||||
clearIntroductionSuccessNotification();
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -369,7 +377,7 @@ class AndroidNotificationManagerImpl implements AndroidNotificationManager,
|
|||||||
if (count == null) groupCounts.put(g, 1);
|
if (count == null) groupCounts.put(g, 1);
|
||||||
else groupCounts.put(g, count + 1);
|
else groupCounts.put(g, count + 1);
|
||||||
groupTotal++;
|
groupTotal++;
|
||||||
updateGroupMessageNotification();
|
updateGroupMessageNotification(true);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -382,31 +390,30 @@ class AndroidNotificationManagerImpl implements AndroidNotificationManager,
|
|||||||
Integer count = groupCounts.remove(g);
|
Integer count = groupCounts.remove(g);
|
||||||
if (count == null) return; // Already cleared
|
if (count == null) return; // Already cleared
|
||||||
groupTotal -= count;
|
groupTotal -= count;
|
||||||
updateGroupMessageNotification();
|
updateGroupMessageNotification(false);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@UiThread
|
@UiThread
|
||||||
private void updateGroupMessageNotification() {
|
private void updateGroupMessageNotification(boolean mayAlertAgain) {
|
||||||
if (groupTotal == 0) {
|
if (groupTotal == 0) {
|
||||||
clearGroupMessageNotification();
|
clearGroupMessageNotification();
|
||||||
} else if (settings.getBoolean(PREF_NOTIFY_GROUP, true)) {
|
} else if (settings.getBoolean(PREF_NOTIFY_GROUP, true)) {
|
||||||
NotificationCompat.Builder b =
|
BriarNotificationBuilder b =
|
||||||
new NotificationCompat.Builder(appContext);
|
new BriarNotificationBuilder(appContext);
|
||||||
b.setSmallIcon(R.drawable.notification_private_group);
|
b.setSmallIcon(R.drawable.notification_private_group);
|
||||||
b.setColor(ContextCompat.getColor(appContext,
|
b.setColorRes(R.color.briar_primary);
|
||||||
R.color.briar_primary));
|
|
||||||
b.setContentTitle(appContext.getText(R.string.app_name));
|
b.setContentTitle(appContext.getText(R.string.app_name));
|
||||||
b.setContentText(appContext.getResources().getQuantityString(
|
b.setContentText(appContext.getResources().getQuantityString(
|
||||||
R.plurals.group_message_notification_text, groupTotal,
|
R.plurals.group_message_notification_text, groupTotal,
|
||||||
groupTotal));
|
groupTotal));
|
||||||
String ringtoneUri = settings.get(PREF_NOTIFY_RINGTONE_URI);
|
b.setNumber(groupTotal);
|
||||||
if (!StringUtils.isNullOrEmpty(ringtoneUri))
|
boolean showOnLockScreen =
|
||||||
b.setSound(Uri.parse(ringtoneUri));
|
settings.getBoolean(PREF_NOTIFY_LOCK_SCREEN, false);
|
||||||
b.setDefaults(getDefaults());
|
b.setLockscreenVisibility(CATEGORY_SOCIAL, showOnLockScreen);
|
||||||
b.setOnlyAlertOnce(true);
|
if (mayAlertAgain) setAlertProperties(b);
|
||||||
b.setAutoCancel(true);
|
setDeleteIntent(b, GROUP_URI);
|
||||||
if (groupCounts.size() == 1) {
|
if (groupCounts.size() == 1) {
|
||||||
// Touching the notification shows the relevant group
|
// Touching the notification shows the relevant group
|
||||||
Intent i = new Intent(appContext, GroupActivity.class);
|
Intent i = new Intent(appContext, GroupActivity.class);
|
||||||
@@ -430,10 +437,6 @@ class AndroidNotificationManagerImpl implements AndroidNotificationManager,
|
|||||||
t.addNextIntent(i);
|
t.addNextIntent(i);
|
||||||
b.setContentIntent(t.getPendingIntent(nextRequestId++, 0));
|
b.setContentIntent(t.getPendingIntent(nextRequestId++, 0));
|
||||||
}
|
}
|
||||||
if (Build.VERSION.SDK_INT >= 21) {
|
|
||||||
b.setCategory(CATEGORY_SOCIAL);
|
|
||||||
b.setVisibility(VISIBILITY_SECRET);
|
|
||||||
}
|
|
||||||
Object o = appContext.getSystemService(NOTIFICATION_SERVICE);
|
Object o = appContext.getSystemService(NOTIFICATION_SERVICE);
|
||||||
NotificationManager nm = (NotificationManager) o;
|
NotificationManager nm = (NotificationManager) o;
|
||||||
nm.notify(GROUP_MESSAGE_NOTIFICATION_ID, b.build());
|
nm.notify(GROUP_MESSAGE_NOTIFICATION_ID, b.build());
|
||||||
@@ -461,7 +464,7 @@ class AndroidNotificationManagerImpl implements AndroidNotificationManager,
|
|||||||
if (count == null) forumCounts.put(g, 1);
|
if (count == null) forumCounts.put(g, 1);
|
||||||
else forumCounts.put(g, count + 1);
|
else forumCounts.put(g, count + 1);
|
||||||
forumTotal++;
|
forumTotal++;
|
||||||
updateForumPostNotification();
|
updateForumPostNotification(true);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -474,31 +477,30 @@ class AndroidNotificationManagerImpl implements AndroidNotificationManager,
|
|||||||
Integer count = forumCounts.remove(g);
|
Integer count = forumCounts.remove(g);
|
||||||
if (count == null) return; // Already cleared
|
if (count == null) return; // Already cleared
|
||||||
forumTotal -= count;
|
forumTotal -= count;
|
||||||
updateForumPostNotification();
|
updateForumPostNotification(false);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@UiThread
|
@UiThread
|
||||||
private void updateForumPostNotification() {
|
private void updateForumPostNotification(boolean mayAlertAgain) {
|
||||||
if (forumTotal == 0) {
|
if (forumTotal == 0) {
|
||||||
clearForumPostNotification();
|
clearForumPostNotification();
|
||||||
} else if (settings.getBoolean(PREF_NOTIFY_FORUM, true)) {
|
} else if (settings.getBoolean(PREF_NOTIFY_FORUM, true)) {
|
||||||
NotificationCompat.Builder b =
|
BriarNotificationBuilder b =
|
||||||
new NotificationCompat.Builder(appContext);
|
new BriarNotificationBuilder(appContext);
|
||||||
b.setSmallIcon(R.drawable.notification_forum);
|
b.setSmallIcon(R.drawable.notification_forum);
|
||||||
b.setColor(ContextCompat.getColor(appContext,
|
b.setColorRes(R.color.briar_primary);
|
||||||
R.color.briar_primary));
|
|
||||||
b.setContentTitle(appContext.getText(R.string.app_name));
|
b.setContentTitle(appContext.getText(R.string.app_name));
|
||||||
b.setContentText(appContext.getResources().getQuantityString(
|
b.setContentText(appContext.getResources().getQuantityString(
|
||||||
R.plurals.forum_post_notification_text, forumTotal,
|
R.plurals.forum_post_notification_text, forumTotal,
|
||||||
forumTotal));
|
forumTotal));
|
||||||
String ringtoneUri = settings.get(PREF_NOTIFY_RINGTONE_URI);
|
b.setNumber(forumTotal);
|
||||||
if (!StringUtils.isNullOrEmpty(ringtoneUri))
|
boolean showOnLockScreen =
|
||||||
b.setSound(Uri.parse(ringtoneUri));
|
settings.getBoolean(PREF_NOTIFY_LOCK_SCREEN, false);
|
||||||
b.setDefaults(getDefaults());
|
b.setLockscreenVisibility(CATEGORY_SOCIAL, showOnLockScreen);
|
||||||
b.setOnlyAlertOnce(true);
|
if (mayAlertAgain) setAlertProperties(b);
|
||||||
b.setAutoCancel(true);
|
setDeleteIntent(b, FORUM_URI);
|
||||||
if (forumCounts.size() == 1) {
|
if (forumCounts.size() == 1) {
|
||||||
// Touching the notification shows the relevant forum
|
// Touching the notification shows the relevant forum
|
||||||
Intent i = new Intent(appContext, ForumActivity.class);
|
Intent i = new Intent(appContext, ForumActivity.class);
|
||||||
@@ -522,10 +524,6 @@ class AndroidNotificationManagerImpl implements AndroidNotificationManager,
|
|||||||
t.addNextIntent(i);
|
t.addNextIntent(i);
|
||||||
b.setContentIntent(t.getPendingIntent(nextRequestId++, 0));
|
b.setContentIntent(t.getPendingIntent(nextRequestId++, 0));
|
||||||
}
|
}
|
||||||
if (Build.VERSION.SDK_INT >= 21) {
|
|
||||||
b.setCategory(CATEGORY_SOCIAL);
|
|
||||||
b.setVisibility(VISIBILITY_SECRET);
|
|
||||||
}
|
|
||||||
Object o = appContext.getSystemService(NOTIFICATION_SERVICE);
|
Object o = appContext.getSystemService(NOTIFICATION_SERVICE);
|
||||||
NotificationManager nm = (NotificationManager) o;
|
NotificationManager nm = (NotificationManager) o;
|
||||||
nm.notify(FORUM_POST_NOTIFICATION_ID, b.build());
|
nm.notify(FORUM_POST_NOTIFICATION_ID, b.build());
|
||||||
@@ -553,7 +551,7 @@ class AndroidNotificationManagerImpl implements AndroidNotificationManager,
|
|||||||
if (count == null) blogCounts.put(g, 1);
|
if (count == null) blogCounts.put(g, 1);
|
||||||
else blogCounts.put(g, count + 1);
|
else blogCounts.put(g, count + 1);
|
||||||
blogTotal++;
|
blogTotal++;
|
||||||
updateBlogPostNotification();
|
updateBlogPostNotification(true);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -566,31 +564,30 @@ class AndroidNotificationManagerImpl implements AndroidNotificationManager,
|
|||||||
Integer count = blogCounts.remove(g);
|
Integer count = blogCounts.remove(g);
|
||||||
if (count == null) return; // Already cleared
|
if (count == null) return; // Already cleared
|
||||||
blogTotal -= count;
|
blogTotal -= count;
|
||||||
updateBlogPostNotification();
|
updateBlogPostNotification(false);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@UiThread
|
@UiThread
|
||||||
private void updateBlogPostNotification() {
|
private void updateBlogPostNotification(boolean mayAlertAgain) {
|
||||||
if (blogTotal == 0) {
|
if (blogTotal == 0) {
|
||||||
clearBlogPostNotification();
|
clearBlogPostNotification();
|
||||||
} else if (settings.getBoolean(PREF_NOTIFY_BLOG, true)) {
|
} else if (settings.getBoolean(PREF_NOTIFY_BLOG, true)) {
|
||||||
NotificationCompat.Builder b =
|
BriarNotificationBuilder b =
|
||||||
new NotificationCompat.Builder(appContext);
|
new BriarNotificationBuilder(appContext);
|
||||||
b.setSmallIcon(R.drawable.notification_blog);
|
b.setSmallIcon(R.drawable.notification_blog);
|
||||||
b.setColor(ContextCompat.getColor(appContext,
|
b.setColorRes(R.color.briar_primary);
|
||||||
R.color.briar_primary));
|
|
||||||
b.setContentTitle(appContext.getText(R.string.app_name));
|
b.setContentTitle(appContext.getText(R.string.app_name));
|
||||||
b.setContentText(appContext.getResources().getQuantityString(
|
b.setContentText(appContext.getResources().getQuantityString(
|
||||||
R.plurals.blog_post_notification_text, blogTotal,
|
R.plurals.blog_post_notification_text, blogTotal,
|
||||||
blogTotal));
|
blogTotal));
|
||||||
String ringtoneUri = settings.get(PREF_NOTIFY_RINGTONE_URI);
|
b.setNumber(blogTotal);
|
||||||
if (!StringUtils.isNullOrEmpty(ringtoneUri))
|
boolean showOnLockScreen =
|
||||||
b.setSound(Uri.parse(ringtoneUri));
|
settings.getBoolean(PREF_NOTIFY_LOCK_SCREEN, false);
|
||||||
b.setDefaults(getDefaults());
|
b.setLockscreenVisibility(CATEGORY_SOCIAL, showOnLockScreen);
|
||||||
b.setOnlyAlertOnce(true);
|
if (mayAlertAgain) setAlertProperties(b);
|
||||||
b.setAutoCancel(true);
|
setDeleteIntent(b, BLOG_URI);
|
||||||
// Touching the notification shows the combined blog feed
|
// Touching the notification shows the combined blog feed
|
||||||
Intent i = new Intent(appContext, NavDrawerActivity.class);
|
Intent i = new Intent(appContext, NavDrawerActivity.class);
|
||||||
i.putExtra(INTENT_BLOGS, true);
|
i.putExtra(INTENT_BLOGS, true);
|
||||||
@@ -600,10 +597,7 @@ class AndroidNotificationManagerImpl implements AndroidNotificationManager,
|
|||||||
t.addParentStack(NavDrawerActivity.class);
|
t.addParentStack(NavDrawerActivity.class);
|
||||||
t.addNextIntent(i);
|
t.addNextIntent(i);
|
||||||
b.setContentIntent(t.getPendingIntent(nextRequestId++, 0));
|
b.setContentIntent(t.getPendingIntent(nextRequestId++, 0));
|
||||||
if (Build.VERSION.SDK_INT >= 21) {
|
|
||||||
b.setCategory(CATEGORY_SOCIAL);
|
|
||||||
b.setVisibility(VISIBILITY_SECRET);
|
|
||||||
}
|
|
||||||
Object o = appContext.getSystemService(NOTIFICATION_SERVICE);
|
Object o = appContext.getSystemService(NOTIFICATION_SERVICE);
|
||||||
NotificationManager nm = (NotificationManager) o;
|
NotificationManager nm = (NotificationManager) o;
|
||||||
nm.notify(BLOG_POST_NOTIFICATION_ID, b.build());
|
nm.notify(BLOG_POST_NOTIFICATION_ID, b.build());
|
||||||
@@ -633,20 +627,18 @@ class AndroidNotificationManagerImpl implements AndroidNotificationManager,
|
|||||||
|
|
||||||
@UiThread
|
@UiThread
|
||||||
private void updateIntroductionNotification() {
|
private void updateIntroductionNotification() {
|
||||||
NotificationCompat.Builder b =
|
BriarNotificationBuilder b = new BriarNotificationBuilder(appContext);
|
||||||
new NotificationCompat.Builder(appContext);
|
|
||||||
b.setSmallIcon(R.drawable.notification_introduction);
|
b.setSmallIcon(R.drawable.notification_introduction);
|
||||||
b.setColor(ContextCompat.getColor(appContext, R.color.briar_primary));
|
b.setColorRes(R.color.briar_primary);
|
||||||
b.setContentTitle(appContext.getText(R.string.app_name));
|
b.setContentTitle(appContext.getText(R.string.app_name));
|
||||||
b.setContentText(appContext.getResources().getQuantityString(
|
b.setContentText(appContext.getResources().getQuantityString(
|
||||||
R.plurals.introduction_notification_text, introductionTotal,
|
R.plurals.introduction_notification_text, introductionTotal,
|
||||||
introductionTotal));
|
introductionTotal));
|
||||||
String ringtoneUri = settings.get(PREF_NOTIFY_RINGTONE_URI);
|
boolean showOnLockScreen =
|
||||||
if (!StringUtils.isNullOrEmpty(ringtoneUri))
|
settings.getBoolean(PREF_NOTIFY_LOCK_SCREEN, false);
|
||||||
b.setSound(Uri.parse(ringtoneUri));
|
b.setLockscreenVisibility(CATEGORY_MESSAGE, showOnLockScreen);
|
||||||
b.setDefaults(getDefaults());
|
setAlertProperties(b);
|
||||||
b.setOnlyAlertOnce(true);
|
setDeleteIntent(b, INTRODUCTION_URI);
|
||||||
b.setAutoCancel(true);
|
|
||||||
// Touching the notification shows the contact list
|
// Touching the notification shows the contact list
|
||||||
Intent i = new Intent(appContext, NavDrawerActivity.class);
|
Intent i = new Intent(appContext, NavDrawerActivity.class);
|
||||||
i.putExtra(INTENT_CONTACTS, true);
|
i.putExtra(INTENT_CONTACTS, true);
|
||||||
@@ -656,15 +648,22 @@ class AndroidNotificationManagerImpl implements AndroidNotificationManager,
|
|||||||
t.addParentStack(NavDrawerActivity.class);
|
t.addParentStack(NavDrawerActivity.class);
|
||||||
t.addNextIntent(i);
|
t.addNextIntent(i);
|
||||||
b.setContentIntent(t.getPendingIntent(nextRequestId++, 0));
|
b.setContentIntent(t.getPendingIntent(nextRequestId++, 0));
|
||||||
if (Build.VERSION.SDK_INT >= 21) {
|
|
||||||
b.setCategory(CATEGORY_MESSAGE);
|
|
||||||
b.setVisibility(VISIBILITY_SECRET);
|
|
||||||
}
|
|
||||||
Object o = appContext.getSystemService(NOTIFICATION_SERVICE);
|
Object o = appContext.getSystemService(NOTIFICATION_SERVICE);
|
||||||
NotificationManager nm = (NotificationManager) o;
|
NotificationManager nm = (NotificationManager) o;
|
||||||
nm.notify(INTRODUCTION_SUCCESS_NOTIFICATION_ID, b.build());
|
nm.notify(INTRODUCTION_SUCCESS_NOTIFICATION_ID, b.build());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void clearAllIntroductionNotifications() {
|
||||||
|
androidExecutor.runOnUiThread(new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
clearIntroductionSuccessNotification();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void blockNotification(final GroupId g) {
|
public void blockNotification(final GroupId g) {
|
||||||
androidExecutor.runOnUiThread(new Runnable() {
|
androidExecutor.runOnUiThread(new Runnable() {
|
||||||
@@ -705,68 +704,6 @@ class AndroidNotificationManagerImpl implements AndroidNotificationManager,
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void blockAllContactNotifications() {
|
|
||||||
androidExecutor.runOnUiThread(new Runnable() {
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
blockContacts = true;
|
|
||||||
blockIntroductions = true;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void unblockAllContactNotifications() {
|
|
||||||
androidExecutor.runOnUiThread(new Runnable() {
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
blockContacts = false;
|
|
||||||
blockIntroductions = false;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void blockAllGroupMessageNotifications() {
|
|
||||||
androidExecutor.runOnUiThread(new Runnable() {
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
blockGroups = true;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void unblockAllGroupMessageNotifications() {
|
|
||||||
androidExecutor.runOnUiThread(new Runnable() {
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
blockGroups = false;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void blockAllForumPostNotifications() {
|
|
||||||
androidExecutor.runOnUiThread(new Runnable() {
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
blockForums = true;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void unblockAllForumPostNotifications() {
|
|
||||||
androidExecutor.runOnUiThread(new Runnable() {
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
blockForums = false;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void blockAllBlogPostNotifications() {
|
public void blockAllBlogPostNotifications() {
|
||||||
androidExecutor.runOnUiThread(new Runnable() {
|
androidExecutor.runOnUiThread(new Runnable() {
|
||||||
@@ -786,5 +723,4 @@ class AndroidNotificationManagerImpl implements AndroidNotificationManager,
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -38,8 +38,6 @@ public class AppModule {
|
|||||||
static class EagerSingletons {
|
static class EagerSingletons {
|
||||||
@Inject
|
@Inject
|
||||||
AndroidNotificationManager androidNotificationManager;
|
AndroidNotificationManager androidNotificationManager;
|
||||||
@Inject
|
|
||||||
ScreenFilterMonitor screenFilterMonitor;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private final Application application;
|
private final Application application;
|
||||||
@@ -171,10 +169,8 @@ public class AppModule {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Provides
|
@Provides
|
||||||
@Singleton
|
|
||||||
ScreenFilterMonitor provideScreenFilterMonitor(
|
ScreenFilterMonitor provideScreenFilterMonitor(
|
||||||
LifecycleManager lifecycleManager, ScreenFilterMonitorImpl sfm) {
|
ScreenFilterMonitorImpl screenFilterMonitor) {
|
||||||
lifecycleManager.registerService(sfm);
|
return screenFilterMonitor;
|
||||||
return sfm;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,5 +6,9 @@ package org.briarproject.briar.android;
|
|||||||
*/
|
*/
|
||||||
public interface BriarApplication {
|
public interface BriarApplication {
|
||||||
|
|
||||||
|
// This build expires on 31 December 2017
|
||||||
|
long EXPIRY_DATE = 1514761200 * 1000L;
|
||||||
|
|
||||||
AndroidComponent getApplicationComponent();
|
AndroidComponent getApplicationComponent();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,6 +2,9 @@ package org.briarproject.briar.android;
|
|||||||
|
|
||||||
import android.app.Application;
|
import android.app.Application;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
|
import android.os.StrictMode;
|
||||||
|
import android.os.StrictMode.ThreadPolicy;
|
||||||
|
import android.os.StrictMode.VmPolicy;
|
||||||
|
|
||||||
import org.acra.ACRA;
|
import org.acra.ACRA;
|
||||||
import org.acra.ReportingInteractionMode;
|
import org.acra.ReportingInteractionMode;
|
||||||
@@ -33,6 +36,8 @@ import static org.acra.ReportField.REPORT_ID;
|
|||||||
import static org.acra.ReportField.STACK_TRACE;
|
import static org.acra.ReportField.STACK_TRACE;
|
||||||
import static org.acra.ReportField.USER_APP_START_DATE;
|
import static org.acra.ReportField.USER_APP_START_DATE;
|
||||||
import static org.acra.ReportField.USER_CRASH_DATE;
|
import static org.acra.ReportField.USER_CRASH_DATE;
|
||||||
|
import static org.briarproject.briar.android.TestingConstants.DEFAULT_LOG_LEVEL;
|
||||||
|
import static org.briarproject.briar.android.TestingConstants.IS_DEBUG_BUILD;
|
||||||
|
|
||||||
@ReportsCrashes(
|
@ReportsCrashes(
|
||||||
reportPrimerClass = BriarReportPrimer.class,
|
reportPrimerClass = BriarReportPrimer.class,
|
||||||
@@ -72,6 +77,9 @@ public class BriarApplicationImpl extends Application
|
|||||||
@Override
|
@Override
|
||||||
public void onCreate() {
|
public void onCreate() {
|
||||||
super.onCreate();
|
super.onCreate();
|
||||||
|
|
||||||
|
if (IS_DEBUG_BUILD) enableStrictMode();
|
||||||
|
Logger.getLogger("").setLevel(DEFAULT_LOG_LEVEL);
|
||||||
LOG.info("Created");
|
LOG.info("Created");
|
||||||
|
|
||||||
applicationComponent = DaggerAndroidComponent.builder()
|
applicationComponent = DaggerAndroidComponent.builder()
|
||||||
@@ -85,6 +93,17 @@ public class BriarApplicationImpl extends Application
|
|||||||
AndroidEagerSingletons.initEagerSingletons(applicationComponent);
|
AndroidEagerSingletons.initEagerSingletons(applicationComponent);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void enableStrictMode() {
|
||||||
|
ThreadPolicy.Builder threadPolicy = new ThreadPolicy.Builder();
|
||||||
|
threadPolicy.detectAll();
|
||||||
|
threadPolicy.penaltyLog();
|
||||||
|
StrictMode.setThreadPolicy(threadPolicy.build());
|
||||||
|
VmPolicy.Builder vmPolicy = new VmPolicy.Builder();
|
||||||
|
vmPolicy.detectAll();
|
||||||
|
vmPolicy.penaltyLog();
|
||||||
|
StrictMode.setVmPolicy(vmPolicy.build());
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public AndroidComponent getApplicationComponent() {
|
public AndroidComponent getApplicationComponent() {
|
||||||
return applicationComponent;
|
return applicationComponent;
|
||||||
|
|||||||
@@ -0,0 +1,53 @@
|
|||||||
|
package org.briarproject.briar.android;
|
||||||
|
|
||||||
|
import android.app.IntentService;
|
||||||
|
import android.content.Intent;
|
||||||
|
import android.support.annotation.Nullable;
|
||||||
|
|
||||||
|
import org.briarproject.briar.api.android.AndroidNotificationManager;
|
||||||
|
|
||||||
|
import javax.inject.Inject;
|
||||||
|
|
||||||
|
import static org.briarproject.briar.api.android.AndroidNotificationManager.BLOG_URI;
|
||||||
|
import static org.briarproject.briar.api.android.AndroidNotificationManager.CONTACT_URI;
|
||||||
|
import static org.briarproject.briar.api.android.AndroidNotificationManager.FORUM_URI;
|
||||||
|
import static org.briarproject.briar.api.android.AndroidNotificationManager.GROUP_URI;
|
||||||
|
import static org.briarproject.briar.api.android.AndroidNotificationManager.INTRODUCTION_URI;
|
||||||
|
|
||||||
|
public class NotificationCleanupService extends IntentService {
|
||||||
|
|
||||||
|
private static final String TAG =
|
||||||
|
NotificationCleanupService.class.getName();
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
AndroidNotificationManager notificationManager;
|
||||||
|
|
||||||
|
public NotificationCleanupService() {
|
||||||
|
super(TAG);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onCreate() {
|
||||||
|
super.onCreate();
|
||||||
|
AndroidComponent applicationComponent =
|
||||||
|
((BriarApplication) getApplication()).getApplicationComponent();
|
||||||
|
applicationComponent.inject(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onHandleIntent(@Nullable Intent i) {
|
||||||
|
if (i == null || i.getData() == null) return;
|
||||||
|
String uri = i.getData().toString();
|
||||||
|
if (uri.equals(CONTACT_URI)) {
|
||||||
|
notificationManager.clearAllContactNotifications();
|
||||||
|
} else if (uri.equals(GROUP_URI)) {
|
||||||
|
notificationManager.clearAllGroupMessageNotifications();
|
||||||
|
} else if (uri.equals(FORUM_URI)) {
|
||||||
|
notificationManager.clearAllForumPostNotifications();
|
||||||
|
} else if (uri.equals(BLOG_URI)) {
|
||||||
|
notificationManager.clearAllBlogPostNotifications();
|
||||||
|
} else if (uri.equals(INTRODUCTION_URI)) {
|
||||||
|
notificationManager.clearAllIntroductionNotifications();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,24 +1,13 @@
|
|||||||
package org.briarproject.briar.android;
|
package org.briarproject.briar.android;
|
||||||
|
|
||||||
import android.app.Application;
|
import android.app.Application;
|
||||||
import android.content.BroadcastReceiver;
|
|
||||||
import android.content.Context;
|
|
||||||
import android.content.Intent;
|
|
||||||
import android.content.IntentFilter;
|
|
||||||
import android.content.SharedPreferences;
|
|
||||||
import android.content.pm.PackageInfo;
|
import android.content.pm.PackageInfo;
|
||||||
import android.content.pm.PackageManager;
|
import android.content.pm.PackageManager;
|
||||||
import android.content.pm.PackageManager.NameNotFoundException;
|
import android.content.pm.PackageManager.NameNotFoundException;
|
||||||
import android.content.pm.Signature;
|
import android.content.pm.Signature;
|
||||||
import android.support.annotation.Nullable;
|
|
||||||
import android.support.annotation.UiThread;
|
import android.support.annotation.UiThread;
|
||||||
import android.support.v7.preference.PreferenceManager;
|
|
||||||
|
|
||||||
import org.briarproject.bramble.api.lifecycle.Service;
|
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||||
import org.briarproject.bramble.api.lifecycle.ServiceException;
|
|
||||||
import org.briarproject.bramble.api.nullsafety.MethodsNotNullByDefault;
|
|
||||||
import org.briarproject.bramble.api.nullsafety.ParametersNotNullByDefault;
|
|
||||||
import org.briarproject.bramble.api.system.AndroidExecutor;
|
|
||||||
import org.briarproject.bramble.util.StringUtils;
|
import org.briarproject.bramble.util.StringUtils;
|
||||||
import org.briarproject.briar.api.android.ScreenFilterMonitor;
|
import org.briarproject.briar.api.android.ScreenFilterMonitor;
|
||||||
|
|
||||||
@@ -27,37 +16,26 @@ import java.io.InputStream;
|
|||||||
import java.security.cert.CertificateException;
|
import java.security.cert.CertificateException;
|
||||||
import java.security.cert.CertificateFactory;
|
import java.security.cert.CertificateFactory;
|
||||||
import java.security.cert.X509Certificate;
|
import java.security.cert.X509Certificate;
|
||||||
import java.util.Collection;
|
|
||||||
import java.util.HashSet;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.TreeSet;
|
import java.util.TreeSet;
|
||||||
import java.util.concurrent.Callable;
|
|
||||||
import java.util.concurrent.ExecutionException;
|
|
||||||
import java.util.concurrent.Future;
|
|
||||||
import java.util.concurrent.atomic.AtomicBoolean;
|
|
||||||
import java.util.logging.Logger;
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
|
import javax.annotation.Nullable;
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
|
|
||||||
import static android.Manifest.permission.SYSTEM_ALERT_WINDOW;
|
import static android.Manifest.permission.SYSTEM_ALERT_WINDOW;
|
||||||
import static android.content.Intent.ACTION_PACKAGE_ADDED;
|
|
||||||
import static android.content.Intent.EXTRA_REPLACING;
|
|
||||||
import static android.content.pm.ApplicationInfo.FLAG_SYSTEM;
|
import static android.content.pm.ApplicationInfo.FLAG_SYSTEM;
|
||||||
import static android.content.pm.ApplicationInfo.FLAG_UPDATED_SYSTEM_APP;
|
import static android.content.pm.ApplicationInfo.FLAG_UPDATED_SYSTEM_APP;
|
||||||
import static android.content.pm.PackageManager.GET_PERMISSIONS;
|
import static android.content.pm.PackageManager.GET_PERMISSIONS;
|
||||||
import static android.content.pm.PackageManager.GET_SIGNATURES;
|
import static android.content.pm.PackageManager.GET_SIGNATURES;
|
||||||
import static java.util.logging.Level.WARNING;
|
import static java.util.logging.Level.WARNING;
|
||||||
|
|
||||||
@MethodsNotNullByDefault
|
@NotNullByDefault
|
||||||
@ParametersNotNullByDefault
|
class ScreenFilterMonitorImpl implements ScreenFilterMonitor {
|
||||||
public class ScreenFilterMonitorImpl extends BroadcastReceiver
|
|
||||||
implements Service, ScreenFilterMonitor {
|
|
||||||
|
|
||||||
private static final Logger LOG =
|
private static final Logger LOG =
|
||||||
Logger.getLogger(ScreenFilterMonitorImpl.class.getName());
|
Logger.getLogger(ScreenFilterMonitorImpl.class.getName());
|
||||||
private static final String PREF_SCREEN_FILTER_APPS =
|
|
||||||
"shownScreenFilterApps";
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Ignore Play Services if it uses this package name and public key - it's
|
* Ignore Play Services if it uses this package name and public key - it's
|
||||||
@@ -78,124 +56,17 @@ public class ScreenFilterMonitorImpl extends BroadcastReceiver
|
|||||||
"82BA35E003C1B4B10DD244A8EE24FFFD333872AB5221985EDAB0FC0D" +
|
"82BA35E003C1B4B10DD244A8EE24FFFD333872AB5221985EDAB0FC0D" +
|
||||||
"0B145B6AA192858E79020103";
|
"0B145B6AA192858E79020103";
|
||||||
|
|
||||||
private final Context appContext;
|
|
||||||
private final AndroidExecutor androidExecutor;
|
|
||||||
private final PackageManager pm;
|
private final PackageManager pm;
|
||||||
private final SharedPreferences prefs;
|
|
||||||
private final AtomicBoolean used = new AtomicBoolean(false);
|
|
||||||
|
|
||||||
// The following must only be accessed on the UI thread
|
|
||||||
private final Set<String> apps = new HashSet<>();
|
|
||||||
private final Set<String> shownApps;
|
|
||||||
private boolean serviceStarted = false;
|
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
ScreenFilterMonitorImpl(AndroidExecutor executor, Application app) {
|
ScreenFilterMonitorImpl(Application app) {
|
||||||
this.androidExecutor = executor;
|
pm = app.getPackageManager();
|
||||||
this.appContext = app;
|
|
||||||
pm = appContext.getPackageManager();
|
|
||||||
prefs = PreferenceManager.getDefaultSharedPreferences(appContext);
|
|
||||||
shownApps = getShownScreenFilterApps();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void startService() throws ServiceException {
|
|
||||||
if (used.getAndSet(true)) throw new IllegalStateException();
|
|
||||||
Future<Void> f = androidExecutor.runOnUiThread(new Callable<Void>() {
|
|
||||||
@Override
|
|
||||||
public Void call() {
|
|
||||||
IntentFilter intentFilter = new IntentFilter();
|
|
||||||
intentFilter.addAction(ACTION_PACKAGE_ADDED);
|
|
||||||
intentFilter.addDataScheme("package");
|
|
||||||
appContext.registerReceiver(ScreenFilterMonitorImpl.this,
|
|
||||||
intentFilter);
|
|
||||||
apps.addAll(getInstalledScreenFilterApps());
|
|
||||||
serviceStarted = true;
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
try {
|
|
||||||
f.get();
|
|
||||||
} catch (InterruptedException | ExecutionException e) {
|
|
||||||
throw new ServiceException(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void stopService() throws ServiceException {
|
|
||||||
Future<Void> f = androidExecutor.runOnUiThread(new Callable<Void>() {
|
|
||||||
@Override
|
|
||||||
public Void call() {
|
|
||||||
serviceStarted = false;
|
|
||||||
appContext.unregisterReceiver(ScreenFilterMonitorImpl.this);
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
try {
|
|
||||||
f.get();
|
|
||||||
} catch (InterruptedException | ExecutionException e) {
|
|
||||||
throw new ServiceException(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private Set<String> getShownScreenFilterApps() {
|
|
||||||
// Result must not be modified
|
|
||||||
Set<String> s = prefs.getStringSet(PREF_SCREEN_FILTER_APPS, null);
|
|
||||||
HashSet<String> result = new HashSet<>();
|
|
||||||
if (s != null) {
|
|
||||||
result.addAll(s);
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onReceive(Context context, Intent intent) {
|
|
||||||
if (!intent.getBooleanExtra(EXTRA_REPLACING, false)) {
|
|
||||||
final String packageName =
|
|
||||||
intent.getData().getEncodedSchemeSpecificPart();
|
|
||||||
androidExecutor.runOnUiThread(new Runnable() {
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
String pkg = isOverlayApp(packageName);
|
|
||||||
if (pkg == null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
apps.add(pkg);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@UiThread
|
@UiThread
|
||||||
public Set<String> getApps() {
|
public Set<String> getApps() {
|
||||||
if (!serviceStarted) {
|
Set<String> screenFilterApps = new TreeSet<>();
|
||||||
apps.addAll(getInstalledScreenFilterApps());
|
|
||||||
}
|
|
||||||
TreeSet<String> buf = new TreeSet<>();
|
|
||||||
if (apps.isEmpty()) {
|
|
||||||
return buf;
|
|
||||||
}
|
|
||||||
buf.addAll(apps);
|
|
||||||
buf.removeAll(shownApps);
|
|
||||||
return buf;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
@UiThread
|
|
||||||
public void storeAppsAsShown(Collection<String> s, boolean persistent) {
|
|
||||||
HashSet<String> buf = new HashSet<>(s);
|
|
||||||
shownApps.addAll(buf);
|
|
||||||
if (persistent && !s.isEmpty()) {
|
|
||||||
buf.addAll(getShownScreenFilterApps());
|
|
||||||
prefs.edit()
|
|
||||||
.putStringSet(PREF_SCREEN_FILTER_APPS, buf)
|
|
||||||
.apply();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private Set<String> getInstalledScreenFilterApps() {
|
|
||||||
HashSet<String> screenFilterApps = new HashSet<>();
|
|
||||||
List<PackageInfo> packageInfos =
|
List<PackageInfo> packageInfos =
|
||||||
pm.getInstalledPackages(GET_PERMISSIONS);
|
pm.getInstalledPackages(GET_PERMISSIONS);
|
||||||
for (PackageInfo packageInfo : packageInfos) {
|
for (PackageInfo packageInfo : packageInfos) {
|
||||||
@@ -209,21 +80,6 @@ public class ScreenFilterMonitorImpl extends BroadcastReceiver
|
|||||||
return screenFilterApps;
|
return screenFilterApps;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Checks if a package uses the SYSTEM_ALERT_WINDOW permission and if so
|
|
||||||
// returns the app name.
|
|
||||||
@Nullable
|
|
||||||
private String isOverlayApp(String pkg) {
|
|
||||||
try {
|
|
||||||
PackageInfo pkgInfo = pm.getPackageInfo(pkg, GET_PERMISSIONS);
|
|
||||||
if (isOverlayApp(pkgInfo)) {
|
|
||||||
return pkgToString(pkgInfo);
|
|
||||||
}
|
|
||||||
} catch (NameNotFoundException e) {
|
|
||||||
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Fetches the application name for a given package.
|
// Fetches the application name for a given package.
|
||||||
@Nullable
|
@Nullable
|
||||||
private String pkgToString(PackageInfo pkgInfo) {
|
private String pkgToString(PackageInfo pkgInfo) {
|
||||||
|
|||||||
@@ -10,13 +10,21 @@ import static java.util.logging.Level.OFF;
|
|||||||
public interface TestingConstants {
|
public interface TestingConstants {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Whether this is an alpha or beta build. This should be set to false for
|
* Whether this is a debug build.
|
||||||
|
*/
|
||||||
|
boolean IS_DEBUG_BUILD = BuildConfig.DEBUG;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether this is a beta build. This should be set to false for final
|
||||||
* release builds.
|
* release builds.
|
||||||
*/
|
*/
|
||||||
boolean TESTING = BuildConfig.DEBUG;
|
boolean IS_BETA_BUILD = true;
|
||||||
|
|
||||||
/** Default log level. */
|
/**
|
||||||
Level DEFAULT_LOG_LEVEL = TESTING ? INFO : OFF;
|
* Default log level. Disable logging for final release builds.
|
||||||
|
*/
|
||||||
|
@SuppressWarnings("ConstantConditions")
|
||||||
|
Level DEFAULT_LOG_LEVEL = IS_DEBUG_BUILD || IS_BETA_BUILD ? INFO : OFF;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Whether to prevent screenshots from being taken. Setting this to true
|
* Whether to prevent screenshots from being taken. Setting this to true
|
||||||
@@ -24,5 +32,5 @@ public interface TestingConstants {
|
|||||||
* Unfortunately this also prevents the user from taking screenshots
|
* Unfortunately this also prevents the user from taking screenshots
|
||||||
* intentionally.
|
* intentionally.
|
||||||
*/
|
*/
|
||||||
boolean PREVENT_SCREENSHOTS = !TESTING;
|
boolean PREVENT_SCREENSHOTS = !IS_DEBUG_BUILD;
|
||||||
}
|
}
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user