mirror of
https://code.briarproject.org/briar/briar.git
synced 2026-02-12 18:59:06 +01:00
Compare commits
126 Commits
release-1.
...
macos
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e6a4dd6ff5 | ||
|
|
d963e75bd1 | ||
|
|
b5283146b1 | ||
|
|
3dbf327937 | ||
|
|
73d806f8b9 | ||
|
|
f1ae57b213 | ||
|
|
cae9efb4bf | ||
|
|
39ac737015 | ||
|
|
edd3310d03 | ||
|
|
a09d88daa8 | ||
|
|
3dc984659d | ||
|
|
fbf0f63ff7 | ||
|
|
ee9234e12e | ||
|
|
2657e2bc08 | ||
|
|
3c40c11dfb | ||
|
|
3bdbabf38a | ||
|
|
a378c24af8 | ||
|
|
b09ea495e7 | ||
|
|
070165f608 | ||
|
|
445f174275 | ||
|
|
ea5af72878 | ||
|
|
ecf2e75424 | ||
|
|
feebd89029 | ||
|
|
cf723f8002 | ||
|
|
b8e743021c | ||
|
|
b785b6c10f | ||
|
|
26ec200f50 | ||
|
|
82efb0d044 | ||
|
|
4ac4ba13d4 | ||
|
|
0844cd3547 | ||
|
|
69e6648ded | ||
|
|
518aeb38b9 | ||
|
|
7e5e61fc05 | ||
|
|
6ecb44bcaa | ||
|
|
f02bbebf6c | ||
|
|
b8612715f8 | ||
|
|
b86ddfa22f | ||
|
|
0dd4d86f4a | ||
|
|
17e0829f42 | ||
|
|
938d8b71a0 | ||
|
|
1b808584b6 | ||
|
|
36db5b48ef | ||
|
|
ccd6ed9ff0 | ||
|
|
0ced10b3a9 | ||
|
|
98064e9efe | ||
|
|
63172ef2e4 | ||
|
|
7a854e70cb | ||
|
|
ac8a4db457 | ||
|
|
5a09530670 | ||
|
|
4fe91bacc6 | ||
|
|
7f70a1519b | ||
|
|
c92ee0458e | ||
|
|
10b1fe756d | ||
|
|
1a2a250be0 | ||
|
|
a621b8077e | ||
|
|
19084d4060 | ||
|
|
2f73ee1b57 | ||
|
|
45fa12c0b3 | ||
|
|
4253bbaaf5 | ||
|
|
8c2e58796b | ||
|
|
3f13e7e9c3 | ||
|
|
421a93b9a6 | ||
|
|
8a088638db | ||
|
|
a888c5f632 | ||
|
|
0b94814620 | ||
|
|
e82e11acfa | ||
|
|
795461d9a8 | ||
|
|
7b8d01cfe0 | ||
|
|
abd04ee7f5 | ||
|
|
cc5365eaf0 | ||
|
|
6b20b03698 | ||
|
|
9da7fbf4f6 | ||
|
|
f64f442fcf | ||
|
|
6eda2f6d13 | ||
|
|
6faa095dfb | ||
|
|
4007fca668 | ||
|
|
28a747f7f3 | ||
|
|
fd2d5c9173 | ||
|
|
8f7bb9d26b | ||
|
|
dc220200b6 | ||
|
|
0cea137d75 | ||
|
|
2eef34f424 | ||
|
|
a68fff9dd2 | ||
|
|
ddc8f4a7d7 | ||
|
|
f961b6a80b | ||
|
|
93439d9c17 | ||
|
|
f3ee884816 | ||
|
|
8ca22043cf | ||
|
|
9353b78da8 | ||
|
|
429bbe1275 | ||
|
|
c5fb1416bd | ||
|
|
e52cbd896e | ||
|
|
ab1b8784b7 | ||
|
|
55a4daa92f | ||
|
|
e52250f1e4 | ||
|
|
33d01aac8c | ||
|
|
b920382e44 | ||
|
|
1a2f85f701 | ||
|
|
186bcc0b47 | ||
|
|
8b9140f477 | ||
|
|
f959c32935 | ||
|
|
1c060bc6db | ||
|
|
5e44e4d308 | ||
|
|
75d5dec45f | ||
|
|
d825227eb5 | ||
|
|
967dd1f18d | ||
|
|
4a4147b563 | ||
|
|
08b72af647 | ||
|
|
528e090c6f | ||
|
|
652f9e5705 | ||
|
|
6a91ec7a6b | ||
|
|
c3a9eff96b | ||
|
|
bd05d893eb | ||
|
|
6965bc0acd | ||
|
|
c6e9554026 | ||
|
|
ab8734e373 | ||
|
|
267956b36c | ||
|
|
ec84ddb38b | ||
|
|
ba2db48d8e | ||
|
|
186f61f771 | ||
|
|
7a3ffcbae6 | ||
|
|
95d8783852 | ||
|
|
b4f3604584 | ||
|
|
badccac90c | ||
|
|
1b8d1a5a8d | ||
|
|
2fe57d2597 |
@@ -83,7 +83,8 @@ android test:
|
|||||||
test_reproducible:
|
test_reproducible:
|
||||||
stage: check_reproducibility
|
stage: check_reproducibility
|
||||||
script:
|
script:
|
||||||
- "curl -X POST -F token=${RELEASE_CHECK_TOKEN} -F ref=master -F variables[RELEASE_TAG]=${CI_COMMIT_REF_NAME} https://code.briarproject.org/api/v4/projects/61/trigger/pipeline"
|
- "curl -X POST -F token=${RELEASE_CHECK_TOKEN} -F ref=master -F variables[APP]='briar' -F variables[RELEASE_TAG]=${CI_COMMIT_REF_NAME} https://code.briarproject.org/api/v4/projects/61/trigger/pipeline"
|
||||||
|
- "curl -X POST -F token=${RELEASE_JAR_CHECK_TOKEN} -F ref=main -F variables[APP]='briar-headless' -F variables[RELEASE_TAG]=${CI_COMMIT_REF_NAME} https://code.briarproject.org/api/v4/projects/307/trigger/pipeline"
|
||||||
only:
|
only:
|
||||||
- tags
|
- tags
|
||||||
|
|
||||||
|
|||||||
@@ -13,8 +13,8 @@ android {
|
|||||||
defaultConfig {
|
defaultConfig {
|
||||||
minSdkVersion 16
|
minSdkVersion 16
|
||||||
targetSdkVersion 31
|
targetSdkVersion 31
|
||||||
versionCode 10418
|
versionCode 10423
|
||||||
versionName "1.4.18"
|
versionName "1.4.23"
|
||||||
consumerProguardFiles 'proguard-rules.txt'
|
consumerProguardFiles 'proguard-rules.txt'
|
||||||
|
|
||||||
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
||||||
@@ -71,7 +71,7 @@ def torLibsDir = 'src/main/jniLibs'
|
|||||||
task cleanTorBinaries {
|
task cleanTorBinaries {
|
||||||
outputs.dir torLibsDir
|
outputs.dir torLibsDir
|
||||||
doLast {
|
doLast {
|
||||||
delete fileTree(torLibsDir) { include '**/*.so' }
|
delete fileTree(torLibsDir)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -80,34 +80,9 @@ clean.dependsOn cleanTorBinaries
|
|||||||
task unpackTorBinaries {
|
task unpackTorBinaries {
|
||||||
outputs.dir torLibsDir
|
outputs.dir torLibsDir
|
||||||
doLast {
|
doLast {
|
||||||
configurations.tor.each { outer ->
|
copy {
|
||||||
zipTree(outer).each { inner ->
|
from configurations.tor.collect { zipTree(it) }
|
||||||
if (inner.name.endsWith('_arm_pie.zip')) {
|
into torLibsDir
|
||||||
copy {
|
|
||||||
from zipTree(inner)
|
|
||||||
into torLibsDir
|
|
||||||
rename '(.*)', 'armeabi-v7a/lib$1.so'
|
|
||||||
}
|
|
||||||
} else if (inner.name.endsWith('_arm64_pie.zip')) {
|
|
||||||
copy {
|
|
||||||
from zipTree(inner)
|
|
||||||
into torLibsDir
|
|
||||||
rename '(.*)', 'arm64-v8a/lib$1.so'
|
|
||||||
}
|
|
||||||
} else if (inner.name.endsWith('_x86_pie.zip')) {
|
|
||||||
copy {
|
|
||||||
from zipTree(inner)
|
|
||||||
into torLibsDir
|
|
||||||
rename '(.*)', 'x86/lib$1.so'
|
|
||||||
}
|
|
||||||
} else if (inner.name.endsWith('_x86_64_pie.zip')) {
|
|
||||||
copy {
|
|
||||||
from zipTree(inner)
|
|
||||||
into torLibsDir
|
|
||||||
rename '(.*)', 'x86_64/lib$1.so'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
dependsOn cleanTorBinaries
|
dependsOn cleanTorBinaries
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
package="org.briarproject.bramble">
|
package="org.briarproject.bramble">
|
||||||
|
|
||||||
<uses-feature
|
<uses-feature
|
||||||
@@ -7,15 +8,17 @@
|
|||||||
|
|
||||||
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
|
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
|
||||||
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
|
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
|
||||||
|
<!-- The BLUETOOTH permission was supposed to be removed in API 31 but is still needed on some Xiaomi/Redmi/POCO devices running API 31 -->
|
||||||
<uses-permission
|
<uses-permission
|
||||||
android:name="android.permission.BLUETOOTH"
|
android:name="android.permission.BLUETOOTH"
|
||||||
android:maxSdkVersion="30" />
|
android:maxSdkVersion="31" />
|
||||||
<uses-permission
|
<uses-permission
|
||||||
android:name="android.permission.BLUETOOTH_ADMIN"
|
android:name="android.permission.BLUETOOTH_ADMIN"
|
||||||
android:maxSdkVersion="30" />
|
android:maxSdkVersion="30" />
|
||||||
<uses-permission
|
<uses-permission
|
||||||
android:name="android.permission.BLUETOOTH_SCAN"
|
android:name="android.permission.BLUETOOTH_SCAN"
|
||||||
android:usesPermissionFlags="neverForLocation" />
|
android:usesPermissionFlags="neverForLocation"
|
||||||
|
tools:targetApi="31" />
|
||||||
<uses-permission android:name="android.permission.BLUETOOTH_CONNECT" />
|
<uses-permission android:name="android.permission.BLUETOOTH_CONNECT" />
|
||||||
<uses-permission android:name="android.permission.BLUETOOTH_ADVERTISE" />
|
<uses-permission android:name="android.permission.BLUETOOTH_ADVERTISE" />
|
||||||
<uses-permission android:name="android.permission.INTERNET" />
|
<uses-permission android:name="android.permission.INTERNET" />
|
||||||
|
|||||||
@@ -118,6 +118,11 @@ class AndroidNetworkManager implements NetworkManager, Service {
|
|||||||
try {
|
try {
|
||||||
NetworkInfo net = connectivityManager.getActiveNetworkInfo();
|
NetworkInfo net = connectivityManager.getActiveNetworkInfo();
|
||||||
boolean connected = net != null && net.isConnected();
|
boolean connected = net != null && net.isConnected();
|
||||||
|
// Research into Android's behavior to check network connectivity
|
||||||
|
// (https://code.briarproject.org/briar/public-mesh-research/-/issues/19)
|
||||||
|
// has shown that NetworkInfo#isConnected() returns true if the device
|
||||||
|
// is connected to any Wifi, independent of whether any specific IP
|
||||||
|
// address can be reached using it or any domain names can be resolved.
|
||||||
boolean wifi = false, ipv6Only = false;
|
boolean wifi = false, ipv6Only = false;
|
||||||
if (connected) {
|
if (connected) {
|
||||||
wifi = net.getType() == TYPE_WIFI;
|
wifi = net.getType() == TYPE_WIFI;
|
||||||
|
|||||||
@@ -33,8 +33,10 @@ class AndroidBluetoothTransportConnection
|
|||||||
super(plugin);
|
super(plugin);
|
||||||
this.connectionLimiter = connectionLimiter;
|
this.connectionLimiter = connectionLimiter;
|
||||||
this.socket = socket;
|
this.socket = socket;
|
||||||
in = timeoutMonitor.createTimeoutInputStream(
|
InputStream socketIn = socket.getInputStream();
|
||||||
socket.getInputStream(), plugin.getMaxIdleTime() * 2);
|
if (socketIn == null) throw new IOException();
|
||||||
|
in = timeoutMonitor.createTimeoutInputStream(socketIn,
|
||||||
|
plugin.getMaxIdleTime() * 2L);
|
||||||
wakeLock = wakeLockManager.createWakeLock("BluetoothConnection");
|
wakeLock = wakeLockManager.createWakeLock("BluetoothConnection");
|
||||||
wakeLock.acquire();
|
wakeLock.acquire();
|
||||||
String address = socket.getRemoteDevice().getAddress();
|
String address = socket.getRemoteDevice().getAddress();
|
||||||
@@ -48,7 +50,9 @@ class AndroidBluetoothTransportConnection
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected OutputStream getOutputStream() throws IOException {
|
protected OutputStream getOutputStream() throws IOException {
|
||||||
return socket.getOutputStream();
|
OutputStream socketOut = socket.getOutputStream();
|
||||||
|
if (socketOut == null) throw new IOException();
|
||||||
|
return socketOut;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -65,6 +65,9 @@ public class AndroidUtils {
|
|||||||
|
|
||||||
public static Pair<String, String> getBluetoothAddressAndMethod(Context ctx,
|
public static Pair<String, String> getBluetoothAddressAndMethod(Context ctx,
|
||||||
BluetoothAdapter adapter) {
|
BluetoothAdapter adapter) {
|
||||||
|
// If we don't have permission to access the adapter's address, let
|
||||||
|
// the caller know we can't find it
|
||||||
|
if (!hasBtConnectPermission(ctx)) return new Pair<>("", "");
|
||||||
// Return the adapter's address if it's valid and not fake
|
// Return the adapter's address if it's valid and not fake
|
||||||
@SuppressLint("HardwareIds")
|
@SuppressLint("HardwareIds")
|
||||||
String address = adapter.getAddress();
|
String address = adapter.getAddress();
|
||||||
|
|||||||
@@ -24,9 +24,9 @@ dependencyVerification {
|
|||||||
'net.jcip:jcip-annotations:1.0:jcip-annotations-1.0.jar:be5805392060c71474bf6c9a67a099471274d30b83eef84bfc4e0889a4f1dcc0',
|
'net.jcip:jcip-annotations:1.0:jcip-annotations-1.0.jar:be5805392060c71474bf6c9a67a099471274d30b83eef84bfc4e0889a4f1dcc0',
|
||||||
'net.ltgt.gradle.incap:incap:0.2:incap-0.2.jar:b625b9806b0f1e4bc7a2e3457119488de3cd57ea20feedd513db070a573a4ffd',
|
'net.ltgt.gradle.incap:incap:0.2:incap-0.2.jar:b625b9806b0f1e4bc7a2e3457119488de3cd57ea20feedd513db070a573a4ffd',
|
||||||
'org.apache-extras.beanshell:bsh:2.0b6:bsh-2.0b6.jar:a17955976070c0573235ee662f2794a78082758b61accffce8d3f8aedcd91047',
|
'org.apache-extras.beanshell:bsh:2.0b6:bsh-2.0b6.jar:a17955976070c0573235ee662f2794a78082758b61accffce8d3f8aedcd91047',
|
||||||
'org.briarproject:obfs4proxy-android:0.0.14-tor1:obfs4proxy-android-0.0.14-tor1.jar:8b08068778b133484b17956d8f7a7710739c33f671a26a68156f4d34e6f28c30',
|
'org.briarproject:obfs4proxy-android:0.0.14:obfs4proxy-android-0.0.14.jar:ad9b1ee4757b05867a19e993147bbb018bddd1f26ce3da746d5f037d5991a8c8',
|
||||||
'org.briarproject:snowflake-android:2.3.1:snowflake-android-2.3.1.jar:1f83c9a070f87b7074af13627709a8b5aced5460104be7166af736b1bb73c293',
|
'org.briarproject:snowflake-android:2.5.1:snowflake-android-2.5.1.jar:88ec81c17b1b6fa884d06839dec0330e328b45c89f88c970a213ce91ca8eac87',
|
||||||
'org.briarproject:tor-android:0.4.5.14:tor-android-0.4.5.14.jar:7cf1beaa6c1db51fc8fac263aba9624ef289c3db29772509efcbc59f7057330a',
|
'org.briarproject:tor-android:0.4.7.13:tor-android-0.4.7.13.jar:7852aab7d2298b80878c7719f34ce665725b494d673ecf2e6f9e697564638cc6',
|
||||||
'org.checkerframework:checker-compat-qual:2.5.5:checker-compat-qual-2.5.5.jar:11d134b245e9cacc474514d2d66b5b8618f8039a1465cdc55bbc0b34e0008b7a',
|
'org.checkerframework:checker-compat-qual:2.5.5:checker-compat-qual-2.5.5.jar:11d134b245e9cacc474514d2d66b5b8618f8039a1465cdc55bbc0b34e0008b7a',
|
||||||
'org.checkerframework:checker-qual:3.12.0:checker-qual-3.12.0.jar:ff10785ac2a357ec5de9c293cb982a2cbb605c0309ea4cc1cb9b9bc6dbe7f3cb',
|
'org.checkerframework:checker-qual:3.12.0:checker-qual-3.12.0.jar:ff10785ac2a357ec5de9c293cb982a2cbb605c0309ea4cc1cb9b9bc6dbe7f3cb',
|
||||||
'org.hamcrest:hamcrest-core:2.1:hamcrest-core-2.1.jar:e09109e54a289d88506b9bfec987ddd199f4217c9464132668351b9a4f00bee9',
|
'org.hamcrest:hamcrest-core:2.1:hamcrest-core-2.1.jar:e09109e54a289d88506b9bfec987ddd199f4217c9464132668351b9a4f00bee9',
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ import java.util.logging.Logger;
|
|||||||
|
|
||||||
import javax.annotation.concurrent.Immutable;
|
import javax.annotation.concurrent.Immutable;
|
||||||
|
|
||||||
|
import static java.util.logging.Logger.getLogger;
|
||||||
import static org.briarproject.bramble.api.transport.TransportConstants.MAX_CLOCK_DIFFERENCE;
|
import static org.briarproject.bramble.api.transport.TransportConstants.MAX_CLOCK_DIFFERENCE;
|
||||||
|
|
||||||
@Immutable
|
@Immutable
|
||||||
@@ -23,17 +24,24 @@ import static org.briarproject.bramble.api.transport.TransportConstants.MAX_CLOC
|
|||||||
public abstract class BdfMessageValidator implements MessageValidator {
|
public abstract class BdfMessageValidator implements MessageValidator {
|
||||||
|
|
||||||
protected static final Logger LOG =
|
protected static final Logger LOG =
|
||||||
Logger.getLogger(BdfMessageValidator.class.getName());
|
getLogger(BdfMessageValidator.class.getName());
|
||||||
|
|
||||||
protected final ClientHelper clientHelper;
|
protected final ClientHelper clientHelper;
|
||||||
protected final MetadataEncoder metadataEncoder;
|
protected final MetadataEncoder metadataEncoder;
|
||||||
protected final Clock clock;
|
protected final Clock clock;
|
||||||
|
protected final boolean canonical;
|
||||||
|
|
||||||
protected BdfMessageValidator(ClientHelper clientHelper,
|
protected BdfMessageValidator(ClientHelper clientHelper,
|
||||||
MetadataEncoder metadataEncoder, Clock clock) {
|
MetadataEncoder metadataEncoder, Clock clock, boolean canonical) {
|
||||||
this.clientHelper = clientHelper;
|
this.clientHelper = clientHelper;
|
||||||
this.metadataEncoder = metadataEncoder;
|
this.metadataEncoder = metadataEncoder;
|
||||||
this.clock = clock;
|
this.clock = clock;
|
||||||
|
this.canonical = canonical;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected BdfMessageValidator(ClientHelper clientHelper,
|
||||||
|
MetadataEncoder metadataEncoder, Clock clock) {
|
||||||
|
this(clientHelper, metadataEncoder, clock, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected abstract BdfMessageContext validateMessage(Message m, Group g,
|
protected abstract BdfMessageContext validateMessage(Message m, Group g,
|
||||||
@@ -49,7 +57,7 @@ public abstract class BdfMessageValidator implements MessageValidator {
|
|||||||
"Timestamp is too far in the future");
|
"Timestamp is too far in the future");
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
BdfList bodyList = clientHelper.toList(m.getBody());
|
BdfList bodyList = clientHelper.toList(m, canonical);
|
||||||
BdfMessageContext result = validateMessage(m, g, bodyList);
|
BdfMessageContext result = validateMessage(m, g, bodyList);
|
||||||
Metadata meta = metadataEncoder.encode(result.getDictionary());
|
Metadata meta = metadataEncoder.encode(result.getDictionary());
|
||||||
return new MessageContext(meta, result.getDependencies());
|
return new MessageContext(meta, result.getDependencies());
|
||||||
|
|||||||
@@ -49,6 +49,9 @@ public interface ClientHelper {
|
|||||||
BdfList getMessageAsList(Transaction txn, MessageId m) throws DbException,
|
BdfList getMessageAsList(Transaction txn, MessageId m) throws DbException,
|
||||||
FormatException;
|
FormatException;
|
||||||
|
|
||||||
|
BdfList getMessageAsList(Transaction txn, MessageId m, boolean canonical)
|
||||||
|
throws DbException, FormatException;
|
||||||
|
|
||||||
BdfDictionary getGroupMetadataAsDictionary(GroupId g) throws DbException,
|
BdfDictionary getGroupMetadataAsDictionary(GroupId g) throws DbException,
|
||||||
FormatException;
|
FormatException;
|
||||||
|
|
||||||
@@ -106,6 +109,8 @@ public interface ClientHelper {
|
|||||||
|
|
||||||
BdfList toList(Message m) throws FormatException;
|
BdfList toList(Message m) throws FormatException;
|
||||||
|
|
||||||
|
BdfList toList(Message m, boolean canonical) throws FormatException;
|
||||||
|
|
||||||
BdfList toList(Author a);
|
BdfList toList(Author a);
|
||||||
|
|
||||||
byte[] sign(String label, BdfList toSign, PrivateKey privateKey)
|
byte[] sign(String label, BdfList toSign, PrivateKey privateKey)
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ import javax.annotation.Nullable;
|
|||||||
import javax.annotation.concurrent.NotThreadSafe;
|
import javax.annotation.concurrent.NotThreadSafe;
|
||||||
|
|
||||||
@NotThreadSafe
|
@NotThreadSafe
|
||||||
public class BdfDictionary extends TreeMap<String, Object> {
|
public final class BdfDictionary extends TreeMap<String, Object> {
|
||||||
|
|
||||||
public static final Object NULL_VALUE = new Object();
|
public static final Object NULL_VALUE = new Object();
|
||||||
|
|
||||||
@@ -39,9 +39,9 @@ public class BdfDictionary extends TreeMap<String, Object> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public Boolean getBoolean(String key) throws FormatException {
|
public Boolean getBoolean(String key) throws FormatException {
|
||||||
Object o = get(key);
|
Boolean value = getOptionalBoolean(key);
|
||||||
if (o instanceof Boolean) return (Boolean) o;
|
if (value == null) throw new FormatException();
|
||||||
throw new FormatException();
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
@@ -52,19 +52,16 @@ public class BdfDictionary extends TreeMap<String, Object> {
|
|||||||
throw new FormatException();
|
throw new FormatException();
|
||||||
}
|
}
|
||||||
|
|
||||||
public Boolean getBoolean(String key, Boolean defaultValue) {
|
public Boolean getBoolean(String key, Boolean defaultValue)
|
||||||
Object o = get(key);
|
throws FormatException {
|
||||||
if (o instanceof Boolean) return (Boolean) o;
|
Boolean value = getOptionalBoolean(key);
|
||||||
return defaultValue;
|
return value == null ? defaultValue : value;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Long getLong(String key) throws FormatException {
|
public Long getLong(String key) throws FormatException {
|
||||||
Object o = get(key);
|
Long value = getOptionalLong(key);
|
||||||
if (o instanceof Long) return (Long) o;
|
if (value == null) throw new FormatException();
|
||||||
if (o instanceof Integer) return ((Integer) o).longValue();
|
return value;
|
||||||
if (o instanceof Short) return ((Short) o).longValue();
|
|
||||||
if (o instanceof Byte) return ((Byte) o).longValue();
|
|
||||||
throw new FormatException();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
@@ -78,20 +75,37 @@ public class BdfDictionary extends TreeMap<String, Object> {
|
|||||||
throw new FormatException();
|
throw new FormatException();
|
||||||
}
|
}
|
||||||
|
|
||||||
public Long getLong(String key, Long defaultValue) {
|
public Long getLong(String key, Long defaultValue) throws FormatException {
|
||||||
Object o = get(key);
|
Long value = getOptionalLong(key);
|
||||||
if (o instanceof Long) return (Long) o;
|
return value == null ? defaultValue : value;
|
||||||
if (o instanceof Integer) return ((Integer) o).longValue();
|
}
|
||||||
if (o instanceof Short) return ((Short) o).longValue();
|
|
||||||
if (o instanceof Byte) return ((Byte) o).longValue();
|
public Integer getInt(String key) throws FormatException {
|
||||||
return defaultValue;
|
Integer value = getOptionalInt(key);
|
||||||
|
if (value == null) throw new FormatException();
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
public Integer getOptionalInt(String key) throws FormatException {
|
||||||
|
Long value = getOptionalLong(key);
|
||||||
|
if (value == null) return null;
|
||||||
|
if (value < Integer.MIN_VALUE || value > Integer.MAX_VALUE) {
|
||||||
|
throw new FormatException();
|
||||||
|
}
|
||||||
|
return value.intValue();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Integer getInt(String key, Integer defaultValue)
|
||||||
|
throws FormatException {
|
||||||
|
Integer value = getOptionalInt(key);
|
||||||
|
return value == null ? defaultValue : value;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Double getDouble(String key) throws FormatException {
|
public Double getDouble(String key) throws FormatException {
|
||||||
Object o = get(key);
|
Double value = getOptionalDouble(key);
|
||||||
if (o instanceof Double) return (Double) o;
|
if (value == null) throw new FormatException();
|
||||||
if (o instanceof Float) return ((Float) o).doubleValue();
|
return value;
|
||||||
throw new FormatException();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
@@ -103,17 +117,16 @@ public class BdfDictionary extends TreeMap<String, Object> {
|
|||||||
throw new FormatException();
|
throw new FormatException();
|
||||||
}
|
}
|
||||||
|
|
||||||
public Double getDouble(String key, Double defaultValue) {
|
public Double getDouble(String key, Double defaultValue)
|
||||||
Object o = get(key);
|
throws FormatException {
|
||||||
if (o instanceof Double) return (Double) o;
|
Double value = getOptionalDouble(key);
|
||||||
if (o instanceof Float) return ((Float) o).doubleValue();
|
return value == null ? defaultValue : value;
|
||||||
return defaultValue;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getString(String key) throws FormatException {
|
public String getString(String key) throws FormatException {
|
||||||
Object o = get(key);
|
String value = getOptionalString(key);
|
||||||
if (o instanceof String) return (String) o;
|
if (value == null) throw new FormatException();
|
||||||
throw new FormatException();
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
@@ -124,17 +137,16 @@ public class BdfDictionary extends TreeMap<String, Object> {
|
|||||||
throw new FormatException();
|
throw new FormatException();
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getString(String key, String defaultValue) {
|
public String getString(String key, String defaultValue)
|
||||||
Object o = get(key);
|
throws FormatException {
|
||||||
if (o instanceof String) return (String) o;
|
String value = getOptionalString(key);
|
||||||
return defaultValue;
|
return value == null ? defaultValue : value;
|
||||||
}
|
}
|
||||||
|
|
||||||
public byte[] getRaw(String key) throws FormatException {
|
public byte[] getRaw(String key) throws FormatException {
|
||||||
Object o = get(key);
|
byte[] value = getOptionalRaw(key);
|
||||||
if (o instanceof byte[]) return (byte[]) o;
|
if (value == null) throw new FormatException();
|
||||||
if (o instanceof Bytes) return ((Bytes) o).getBytes();
|
return value;
|
||||||
throw new FormatException();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
@@ -146,17 +158,16 @@ public class BdfDictionary extends TreeMap<String, Object> {
|
|||||||
throw new FormatException();
|
throw new FormatException();
|
||||||
}
|
}
|
||||||
|
|
||||||
public byte[] getRaw(String key, byte[] defaultValue) {
|
public byte[] getRaw(String key, byte[] defaultValue)
|
||||||
Object o = get(key);
|
throws FormatException {
|
||||||
if (o instanceof byte[]) return (byte[]) o;
|
byte[] value = getOptionalRaw(key);
|
||||||
if (o instanceof Bytes) return ((Bytes) o).getBytes();
|
return value == null ? defaultValue : value;
|
||||||
return defaultValue;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public BdfList getList(String key) throws FormatException {
|
public BdfList getList(String key) throws FormatException {
|
||||||
Object o = get(key);
|
BdfList value = getOptionalList(key);
|
||||||
if (o instanceof BdfList) return (BdfList) o;
|
if (value == null) throw new FormatException();
|
||||||
throw new FormatException();
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
@@ -167,16 +178,16 @@ public class BdfDictionary extends TreeMap<String, Object> {
|
|||||||
throw new FormatException();
|
throw new FormatException();
|
||||||
}
|
}
|
||||||
|
|
||||||
public BdfList getList(String key, BdfList defaultValue) {
|
public BdfList getList(String key, BdfList defaultValue)
|
||||||
Object o = get(key);
|
throws FormatException {
|
||||||
if (o instanceof BdfList) return (BdfList) o;
|
BdfList value = getOptionalList(key);
|
||||||
return defaultValue;
|
return value == null ? defaultValue : value;
|
||||||
}
|
}
|
||||||
|
|
||||||
public BdfDictionary getDictionary(String key) throws FormatException {
|
public BdfDictionary getDictionary(String key) throws FormatException {
|
||||||
Object o = get(key);
|
BdfDictionary value = getOptionalDictionary(key);
|
||||||
if (o instanceof BdfDictionary) return (BdfDictionary) o;
|
if (value == null) throw new FormatException();
|
||||||
throw new FormatException();
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
@@ -188,9 +199,9 @@ public class BdfDictionary extends TreeMap<String, Object> {
|
|||||||
throw new FormatException();
|
throw new FormatException();
|
||||||
}
|
}
|
||||||
|
|
||||||
public BdfDictionary getDictionary(String key, BdfDictionary defaultValue) {
|
public BdfDictionary getDictionary(String key, BdfDictionary defaultValue)
|
||||||
Object o = get(key);
|
throws FormatException {
|
||||||
if (o instanceof BdfDictionary) return (BdfDictionary) o;
|
BdfDictionary value = getOptionalDictionary(key);
|
||||||
return defaultValue;
|
return value == null ? defaultValue : value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ import javax.annotation.concurrent.NotThreadSafe;
|
|||||||
import static org.briarproject.bramble.api.data.BdfDictionary.NULL_VALUE;
|
import static org.briarproject.bramble.api.data.BdfDictionary.NULL_VALUE;
|
||||||
|
|
||||||
@NotThreadSafe
|
@NotThreadSafe
|
||||||
public class BdfList extends ArrayList<Object> {
|
public final class BdfList extends ArrayList<Object> {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Factory method for constructing lists inline.
|
* Factory method for constructing lists inline.
|
||||||
@@ -33,15 +33,15 @@ public class BdfList extends ArrayList<Object> {
|
|||||||
super(items);
|
super(items);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("BooleanMethodIsAlwaysInverted")
|
||||||
private boolean isInRange(int index) {
|
private boolean isInRange(int index) {
|
||||||
return index >= 0 && index < size();
|
return index >= 0 && index < size();
|
||||||
}
|
}
|
||||||
|
|
||||||
public Boolean getBoolean(int index) throws FormatException {
|
public Boolean getBoolean(int index) throws FormatException {
|
||||||
if (!isInRange(index)) throw new FormatException();
|
Boolean value = getOptionalBoolean(index);
|
||||||
Object o = get(index);
|
if (value == null) throw new FormatException();
|
||||||
if (o instanceof Boolean) return (Boolean) o;
|
return value;
|
||||||
throw new FormatException();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
@@ -53,21 +53,16 @@ public class BdfList extends ArrayList<Object> {
|
|||||||
throw new FormatException();
|
throw new FormatException();
|
||||||
}
|
}
|
||||||
|
|
||||||
public Boolean getBoolean(int index, Boolean defaultValue) {
|
public Boolean getBoolean(int index, Boolean defaultValue)
|
||||||
if (!isInRange(index)) return defaultValue;
|
throws FormatException {
|
||||||
Object o = get(index);
|
Boolean value = getOptionalBoolean(index);
|
||||||
if (o instanceof Boolean) return (Boolean) o;
|
return value == null ? defaultValue : value;
|
||||||
return defaultValue;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public Long getLong(int index) throws FormatException {
|
public Long getLong(int index) throws FormatException {
|
||||||
if (!isInRange(index)) throw new FormatException();
|
Long value = getOptionalLong(index);
|
||||||
Object o = get(index);
|
if (value == null) throw new FormatException();
|
||||||
if (o instanceof Long) return (Long) o;
|
return value;
|
||||||
if (o instanceof Integer) return ((Integer) o).longValue();
|
|
||||||
if (o instanceof Short) return ((Short) o).longValue();
|
|
||||||
if (o instanceof Byte) return ((Byte) o).longValue();
|
|
||||||
throw new FormatException();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
@@ -82,22 +77,37 @@ public class BdfList extends ArrayList<Object> {
|
|||||||
throw new FormatException();
|
throw new FormatException();
|
||||||
}
|
}
|
||||||
|
|
||||||
public Long getLong(int index, Long defaultValue) {
|
public Long getLong(int index, Long defaultValue) throws FormatException {
|
||||||
if (!isInRange(index)) return defaultValue;
|
Long value = getOptionalLong(index);
|
||||||
Object o = get(index);
|
return value == null ? defaultValue : value;
|
||||||
if (o instanceof Long) return (Long) o;
|
}
|
||||||
if (o instanceof Integer) return ((Integer) o).longValue();
|
|
||||||
if (o instanceof Short) return ((Short) o).longValue();
|
public Integer getInt(int index) throws FormatException {
|
||||||
if (o instanceof Byte) return ((Byte) o).longValue();
|
Integer value = getOptionalInt(index);
|
||||||
return defaultValue;
|
if (value == null) throw new FormatException();
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
public Integer getOptionalInt(int index) throws FormatException {
|
||||||
|
Long value = getOptionalLong(index);
|
||||||
|
if (value == null) return null;
|
||||||
|
if (value < Integer.MIN_VALUE || value > Integer.MAX_VALUE) {
|
||||||
|
throw new FormatException();
|
||||||
|
}
|
||||||
|
return value.intValue();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Integer getInt(int index, Integer defaultValue)
|
||||||
|
throws FormatException {
|
||||||
|
Integer value = getOptionalInt(index);
|
||||||
|
return value == null ? defaultValue : value;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Double getDouble(int index) throws FormatException {
|
public Double getDouble(int index) throws FormatException {
|
||||||
if (!isInRange(index)) throw new FormatException();
|
Double value = getOptionalDouble(index);
|
||||||
Object o = get(index);
|
if (value == null) throw new FormatException();
|
||||||
if (o instanceof Double) return (Double) o;
|
return value;
|
||||||
if (o instanceof Float) return ((Float) o).doubleValue();
|
|
||||||
throw new FormatException();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
@@ -110,19 +120,16 @@ public class BdfList extends ArrayList<Object> {
|
|||||||
throw new FormatException();
|
throw new FormatException();
|
||||||
}
|
}
|
||||||
|
|
||||||
public Double getDouble(int index, Double defaultValue) {
|
public Double getDouble(int index, Double defaultValue)
|
||||||
if (!isInRange(index)) return defaultValue;
|
throws FormatException {
|
||||||
Object o = get(index);
|
Double value = getOptionalDouble(index);
|
||||||
if (o instanceof Double) return (Double) o;
|
return value == null ? defaultValue : value;
|
||||||
if (o instanceof Float) return ((Float) o).doubleValue();
|
|
||||||
return defaultValue;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getString(int index) throws FormatException {
|
public String getString(int index) throws FormatException {
|
||||||
if (!isInRange(index)) throw new FormatException();
|
String value = getOptionalString(index);
|
||||||
Object o = get(index);
|
if (value == null) throw new FormatException();
|
||||||
if (o instanceof String) return (String) o;
|
return value;
|
||||||
throw new FormatException();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
@@ -134,19 +141,16 @@ public class BdfList extends ArrayList<Object> {
|
|||||||
throw new FormatException();
|
throw new FormatException();
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getString(int index, String defaultValue) {
|
public String getString(int index, String defaultValue)
|
||||||
if (!isInRange(index)) return defaultValue;
|
throws FormatException {
|
||||||
Object o = get(index);
|
String value = getOptionalString(index);
|
||||||
if (o instanceof String) return (String) o;
|
return value == null ? defaultValue : value;
|
||||||
return defaultValue;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public byte[] getRaw(int index) throws FormatException {
|
public byte[] getRaw(int index) throws FormatException {
|
||||||
if (!isInRange(index)) throw new FormatException();
|
byte[] value = getOptionalRaw(index);
|
||||||
Object o = get(index);
|
if (value == null) throw new FormatException();
|
||||||
if (o instanceof byte[]) return (byte[]) o;
|
return value;
|
||||||
if (o instanceof Bytes) return ((Bytes) o).getBytes();
|
|
||||||
throw new FormatException();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
@@ -159,19 +163,16 @@ public class BdfList extends ArrayList<Object> {
|
|||||||
throw new FormatException();
|
throw new FormatException();
|
||||||
}
|
}
|
||||||
|
|
||||||
public byte[] getRaw(int index, byte[] defaultValue) {
|
public byte[] getRaw(int index, byte[] defaultValue)
|
||||||
if (!isInRange(index)) return defaultValue;
|
throws FormatException {
|
||||||
Object o = get(index);
|
byte[] value = getOptionalRaw(index);
|
||||||
if (o instanceof byte[]) return (byte[]) o;
|
return value == null ? defaultValue : value;
|
||||||
if (o instanceof Bytes) return ((Bytes) o).getBytes();
|
|
||||||
return defaultValue;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public BdfList getList(int index) throws FormatException {
|
public BdfList getList(int index) throws FormatException {
|
||||||
if (!isInRange(index)) throw new FormatException();
|
BdfList value = getOptionalList(index);
|
||||||
Object o = get(index);
|
if (value == null) throw new FormatException();
|
||||||
if (o instanceof BdfList) return (BdfList) o;
|
return value;
|
||||||
throw new FormatException();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
@@ -183,18 +184,16 @@ public class BdfList extends ArrayList<Object> {
|
|||||||
throw new FormatException();
|
throw new FormatException();
|
||||||
}
|
}
|
||||||
|
|
||||||
public BdfList getList(int index, BdfList defaultValue) {
|
public BdfList getList(int index, BdfList defaultValue)
|
||||||
if (!isInRange(index)) return defaultValue;
|
throws FormatException {
|
||||||
Object o = get(index);
|
BdfList value = getOptionalList(index);
|
||||||
if (o instanceof BdfList) return (BdfList) o;
|
return value == null ? defaultValue : value;
|
||||||
return defaultValue;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public BdfDictionary getDictionary(int index) throws FormatException {
|
public BdfDictionary getDictionary(int index) throws FormatException {
|
||||||
if (!isInRange(index)) throw new FormatException();
|
BdfDictionary value = getOptionalDictionary(index);
|
||||||
Object o = get(index);
|
if (value == null) throw new FormatException();
|
||||||
if (o instanceof BdfDictionary) return (BdfDictionary) o;
|
return value;
|
||||||
throw new FormatException();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
@@ -207,10 +206,9 @@ public class BdfList extends ArrayList<Object> {
|
|||||||
throw new FormatException();
|
throw new FormatException();
|
||||||
}
|
}
|
||||||
|
|
||||||
public BdfDictionary getDictionary(int index, BdfDictionary defaultValue) {
|
public BdfDictionary getDictionary(int index, BdfDictionary defaultValue)
|
||||||
if (!isInRange(index)) return defaultValue;
|
throws FormatException {
|
||||||
Object o = get(index);
|
BdfDictionary value = getOptionalDictionary(index);
|
||||||
if (o instanceof BdfDictionary) return (BdfDictionary) o;
|
return value == null ? defaultValue : value;
|
||||||
return defaultValue;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -32,6 +32,12 @@ public interface BdfReader {
|
|||||||
|
|
||||||
void skipLong() throws IOException;
|
void skipLong() throws IOException;
|
||||||
|
|
||||||
|
boolean hasInt() throws IOException;
|
||||||
|
|
||||||
|
int readInt() throws IOException;
|
||||||
|
|
||||||
|
void skipInt() throws IOException;
|
||||||
|
|
||||||
boolean hasDouble() throws IOException;
|
boolean hasDouble() throws IOException;
|
||||||
|
|
||||||
double readDouble() throws IOException;
|
double readDouble() throws IOException;
|
||||||
@@ -54,23 +60,11 @@ public interface BdfReader {
|
|||||||
|
|
||||||
BdfList readList() throws IOException;
|
BdfList readList() throws IOException;
|
||||||
|
|
||||||
void readListStart() throws IOException;
|
|
||||||
|
|
||||||
boolean hasListEnd() throws IOException;
|
|
||||||
|
|
||||||
void readListEnd() throws IOException;
|
|
||||||
|
|
||||||
void skipList() throws IOException;
|
void skipList() throws IOException;
|
||||||
|
|
||||||
boolean hasDictionary() throws IOException;
|
boolean hasDictionary() throws IOException;
|
||||||
|
|
||||||
BdfDictionary readDictionary() throws IOException;
|
BdfDictionary readDictionary() throws IOException;
|
||||||
|
|
||||||
void readDictionaryStart() throws IOException;
|
|
||||||
|
|
||||||
boolean hasDictionaryEnd() throws IOException;
|
|
||||||
|
|
||||||
void readDictionaryEnd() throws IOException;
|
|
||||||
|
|
||||||
void skipDictionary() throws IOException;
|
void skipDictionary() throws IOException;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,6 +9,8 @@ public interface BdfReaderFactory {
|
|||||||
|
|
||||||
BdfReader createReader(InputStream in);
|
BdfReader createReader(InputStream in);
|
||||||
|
|
||||||
|
BdfReader createReader(InputStream in, boolean canonical);
|
||||||
|
|
||||||
BdfReader createReader(InputStream in, int nestedLimit,
|
BdfReader createReader(InputStream in, int nestedLimit,
|
||||||
int maxBufferSize);
|
int maxBufferSize, boolean canonical);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,13 +24,5 @@ public interface BdfWriter {
|
|||||||
|
|
||||||
void writeList(Collection<?> c) throws IOException;
|
void writeList(Collection<?> c) throws IOException;
|
||||||
|
|
||||||
void writeListStart() throws IOException;
|
|
||||||
|
|
||||||
void writeListEnd() throws IOException;
|
|
||||||
|
|
||||||
void writeDictionary(Map<?, ?> m) throws IOException;
|
void writeDictionary(Map<?, ?> m) throws IOException;
|
||||||
|
|
||||||
void writeDictionaryStart() throws IOException;
|
|
||||||
|
|
||||||
void writeDictionaryEnd() throws IOException;
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,18 +1,26 @@
|
|||||||
package org.briarproject.bramble.api.keyagreement;
|
package org.briarproject.bramble.api.keyagreement;
|
||||||
|
|
||||||
public interface KeyAgreementConstants {
|
import org.briarproject.bramble.api.mailbox.MailboxConstants;
|
||||||
|
|
||||||
/**
|
public interface KeyAgreementConstants {
|
||||||
* The version of the BQP protocol used in beta releases. This version
|
|
||||||
* number is reserved.
|
|
||||||
*/
|
|
||||||
byte BETA_PROTOCOL_VERSION = 89;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The current version of the BQP protocol.
|
* The current version of the BQP protocol.
|
||||||
*/
|
*/
|
||||||
byte PROTOCOL_VERSION = 4;
|
byte PROTOCOL_VERSION = 4;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The QR code format identifier, used to distinguish BQP QR codes from
|
||||||
|
* QR codes used for other purposes. See
|
||||||
|
* {@link MailboxConstants#QR_FORMAT_ID}.
|
||||||
|
*/
|
||||||
|
byte QR_FORMAT_ID = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The QR code format version.
|
||||||
|
*/
|
||||||
|
byte QR_FORMAT_VERSION = PROTOCOL_VERSION;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The length of the BQP key commitment in bytes.
|
* The length of the BQP key commitment in bytes.
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -7,5 +7,5 @@ import java.io.IOException;
|
|||||||
@NotNullByDefault
|
@NotNullByDefault
|
||||||
public interface PayloadParser {
|
public interface PayloadParser {
|
||||||
|
|
||||||
Payload parse(byte[] raw) throws IOException;
|
Payload parse(String payload) throws IOException;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
package org.briarproject.bramble.api.mailbox;
|
package org.briarproject.bramble.api.mailbox;
|
||||||
|
|
||||||
|
import org.briarproject.bramble.api.keyagreement.KeyAgreementConstants;
|
||||||
import org.briarproject.bramble.api.plugin.TransportId;
|
import org.briarproject.bramble.api.plugin.TransportId;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@@ -19,6 +20,18 @@ public interface MailboxConstants {
|
|||||||
*/
|
*/
|
||||||
TransportId ID = new TransportId("org.briarproject.bramble.mailbox");
|
TransportId ID = new TransportId("org.briarproject.bramble.mailbox");
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The QR code format identifier, used to distinguish mailbox QR codes
|
||||||
|
* from QR codes used for other purposes. See
|
||||||
|
* {@link KeyAgreementConstants#QR_FORMAT_ID};
|
||||||
|
*/
|
||||||
|
byte QR_FORMAT_ID = 1;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The QR code format version.
|
||||||
|
*/
|
||||||
|
byte QR_FORMAT_VERSION = 0;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Mailbox API versions that we support as a client. This is reported to our
|
* Mailbox API versions that we support as a client. This is reported to our
|
||||||
* contacts by {@link MailboxUpdateManager}.
|
* contacts by {@link MailboxUpdateManager}.
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
package org.briarproject.bramble.api.mailbox;
|
package org.briarproject.bramble.api.mailbox;
|
||||||
|
|
||||||
|
import org.briarproject.bramble.api.FormatException;
|
||||||
import org.briarproject.bramble.api.db.DbException;
|
import org.briarproject.bramble.api.db.DbException;
|
||||||
import org.briarproject.bramble.api.db.Transaction;
|
import org.briarproject.bramble.api.db.Transaction;
|
||||||
import org.briarproject.bramble.api.lifecycle.IoExecutor;
|
import org.briarproject.bramble.api.lifecycle.IoExecutor;
|
||||||
@@ -34,6 +35,16 @@ public interface MailboxManager {
|
|||||||
*/
|
*/
|
||||||
MailboxPairingTask startPairingTask(String qrCodePayload);
|
MailboxPairingTask startPairingTask(String qrCodePayload);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Takes a textual QR code representation in
|
||||||
|
* {@link org.briarproject.bramble.util.Base32} format and converts it
|
||||||
|
* into a qrCodePayload as expected by {@link #startPairingTask(String)}.
|
||||||
|
*
|
||||||
|
* @throws FormatException when the provided payload did not include a
|
||||||
|
* proper briar-mailbox:// link.
|
||||||
|
*/
|
||||||
|
String convertBase32Payload(String base32Payload) throws FormatException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Can be used by the UI to test the mailbox connection.
|
* Can be used by the UI to test the mailbox connection.
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -1,17 +1,44 @@
|
|||||||
package org.briarproject.bramble.api.mailbox;
|
package org.briarproject.bramble.api.mailbox;
|
||||||
|
|
||||||
|
import org.briarproject.bramble.api.qrcode.QrCodeClassifier.QrCodeType;
|
||||||
|
|
||||||
public abstract class MailboxPairingState {
|
public abstract class MailboxPairingState {
|
||||||
|
|
||||||
public static class QrCodeReceived extends MailboxPairingState {
|
public abstract static class Pending extends MailboxPairingState {
|
||||||
|
|
||||||
|
public final long timeStarted;
|
||||||
|
|
||||||
|
private Pending(long timeStarted) {
|
||||||
|
this.timeStarted = timeStarted;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class Pairing extends MailboxPairingState {
|
public static class QrCodeReceived extends Pending {
|
||||||
|
|
||||||
|
public QrCodeReceived(long timeStarted) {
|
||||||
|
super(timeStarted);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class Pairing extends Pending {
|
||||||
|
|
||||||
|
public Pairing(long timeStarted) {
|
||||||
|
super(timeStarted);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class Paired extends MailboxPairingState {
|
public static class Paired extends MailboxPairingState {
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class InvalidQrCode extends MailboxPairingState {
|
public static class InvalidQrCode extends MailboxPairingState {
|
||||||
|
|
||||||
|
public final QrCodeType qrCodeType;
|
||||||
|
public final int formatVersion;
|
||||||
|
|
||||||
|
public InvalidQrCode(QrCodeType qrCodeType, int formatVersion) {
|
||||||
|
this.qrCodeType = qrCodeType;
|
||||||
|
this.formatVersion = formatVersion;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class MailboxAlreadyPaired extends MailboxPairingState {
|
public static class MailboxAlreadyPaired extends MailboxPairingState {
|
||||||
|
|||||||
@@ -27,8 +27,6 @@ public interface TorConstants {
|
|||||||
int PREF_TOR_NETWORK_AUTOMATIC = 0;
|
int PREF_TOR_NETWORK_AUTOMATIC = 0;
|
||||||
int PREF_TOR_NETWORK_WITHOUT_BRIDGES = 1;
|
int PREF_TOR_NETWORK_WITHOUT_BRIDGES = 1;
|
||||||
int PREF_TOR_NETWORK_WITH_BRIDGES = 2;
|
int PREF_TOR_NETWORK_WITH_BRIDGES = 2;
|
||||||
// TODO: Remove when settings migration code is removed
|
|
||||||
int PREF_TOR_NETWORK_NEVER = 3;
|
|
||||||
|
|
||||||
// Default values for local settings
|
// Default values for local settings
|
||||||
boolean DEFAULT_PREF_PLUGIN_ENABLE = true;
|
boolean DEFAULT_PREF_PLUGIN_ENABLE = true;
|
||||||
|
|||||||
@@ -0,0 +1,16 @@
|
|||||||
|
package org.briarproject.bramble.api.qrcode;
|
||||||
|
|
||||||
|
import org.briarproject.bramble.api.Pair;
|
||||||
|
import org.briarproject.nullsafety.NotNullByDefault;
|
||||||
|
|
||||||
|
@NotNullByDefault
|
||||||
|
public interface QrCodeClassifier {
|
||||||
|
|
||||||
|
enum QrCodeType {
|
||||||
|
BQP,
|
||||||
|
MAILBOX,
|
||||||
|
UNKNOWN
|
||||||
|
}
|
||||||
|
|
||||||
|
Pair<QrCodeType, Integer> classifyQrCode(String payload);
|
||||||
|
}
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
package org.briarproject.bramble.api.qrcode;
|
||||||
|
|
||||||
|
import org.briarproject.bramble.api.FormatException;
|
||||||
|
import org.briarproject.bramble.api.qrcode.QrCodeClassifier.QrCodeType;
|
||||||
|
import org.briarproject.nullsafety.NotNullByDefault;
|
||||||
|
|
||||||
|
import javax.annotation.concurrent.Immutable;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Thrown when a QR code that has been scanned does not have the expected type.
|
||||||
|
*/
|
||||||
|
@Immutable
|
||||||
|
@NotNullByDefault
|
||||||
|
public class WrongQrCodeTypeException extends FormatException {
|
||||||
|
|
||||||
|
private final QrCodeType qrCodeType;
|
||||||
|
|
||||||
|
public WrongQrCodeTypeException(QrCodeType qrCodeType) {
|
||||||
|
this.qrCodeType = qrCodeType;
|
||||||
|
}
|
||||||
|
|
||||||
|
public QrCodeType getQrCodeType() {
|
||||||
|
return qrCodeType;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -4,6 +4,8 @@ import org.briarproject.nullsafety.NotNullByDefault;
|
|||||||
|
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
|
|
||||||
|
import static org.briarproject.bramble.util.StringUtils.startsWithIgnoreCase;
|
||||||
|
|
||||||
@NotNullByDefault
|
@NotNullByDefault
|
||||||
public class OsUtils {
|
public class OsUtils {
|
||||||
|
|
||||||
@@ -13,15 +15,15 @@ public class OsUtils {
|
|||||||
private static final String vendor = System.getProperty("java.vendor");
|
private static final String vendor = System.getProperty("java.vendor");
|
||||||
|
|
||||||
public static boolean isWindows() {
|
public static boolean isWindows() {
|
||||||
return os != null && os.contains("Windows");
|
return os != null && startsWithIgnoreCase(os, "Win");
|
||||||
}
|
}
|
||||||
|
|
||||||
public static boolean isMac() {
|
public static boolean isMac() {
|
||||||
return os != null && os.contains("Mac OS");
|
return os != null && os.equalsIgnoreCase("Mac OS X");
|
||||||
}
|
}
|
||||||
|
|
||||||
public static boolean isLinux() {
|
public static boolean isLinux() {
|
||||||
return os != null && os.contains("Linux") && !isAndroid();
|
return os != null && startsWithIgnoreCase(os, "Linux") && !isAndroid();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static boolean isAndroid() {
|
public static boolean isAndroid() {
|
||||||
|
|||||||
@@ -3,7 +3,6 @@ package org.briarproject.bramble.util;
|
|||||||
import org.briarproject.bramble.api.FormatException;
|
import org.briarproject.bramble.api.FormatException;
|
||||||
import org.briarproject.nullsafety.NotNullByDefault;
|
import org.briarproject.nullsafety.NotNullByDefault;
|
||||||
|
|
||||||
import java.io.UnsupportedEncodingException;
|
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
import java.nio.charset.CharacterCodingException;
|
import java.nio.charset.CharacterCodingException;
|
||||||
import java.nio.charset.Charset;
|
import java.nio.charset.Charset;
|
||||||
@@ -15,15 +14,21 @@ import java.util.regex.Pattern;
|
|||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
|
|
||||||
import static java.nio.charset.CodingErrorAction.IGNORE;
|
import static java.nio.charset.CodingErrorAction.IGNORE;
|
||||||
|
import static java.nio.charset.CodingErrorAction.REPORT;
|
||||||
import static java.util.regex.Pattern.CASE_INSENSITIVE;
|
import static java.util.regex.Pattern.CASE_INSENSITIVE;
|
||||||
|
|
||||||
|
@SuppressWarnings("CharsetObjectCanBeUsed")
|
||||||
@NotNullByDefault
|
@NotNullByDefault
|
||||||
public class StringUtils {
|
public class StringUtils {
|
||||||
|
|
||||||
private static final Charset UTF_8 = Charset.forName("UTF-8");
|
public static final Charset UTF_8 = Charset.forName("UTF-8");
|
||||||
private static Pattern MAC = Pattern.compile("[0-9a-f]{2}:[0-9a-f]{2}:" +
|
public static final Charset US_ASCII = Charset.forName("US-ASCII");
|
||||||
"[0-9a-f]{2}:[0-9a-f]{2}:[0-9a-f]{2}:[0-9a-f]{2}",
|
public static final Charset ISO_8859_1 = Charset.forName("ISO-8859-1");
|
||||||
CASE_INSENSITIVE);
|
|
||||||
|
private static final Pattern MAC =
|
||||||
|
Pattern.compile("[0-9a-f]{2}:[0-9a-f]{2}:" +
|
||||||
|
"[0-9a-f]{2}:[0-9a-f]{2}:[0-9a-f]{2}:[0-9a-f]{2}",
|
||||||
|
CASE_INSENSITIVE);
|
||||||
|
|
||||||
private static final char[] HEX = new char[] {
|
private static final char[] HEX = new char[] {
|
||||||
'0', '1', '2', '3', '4', '5', '6', '7',
|
'0', '1', '2', '3', '4', '5', '6', '7',
|
||||||
@@ -45,33 +50,41 @@ public class StringUtils {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static byte[] toUtf8(String s) {
|
public static byte[] toUtf8(String s) {
|
||||||
try {
|
return s.getBytes(UTF_8);
|
||||||
return s.getBytes("UTF-8");
|
|
||||||
} catch (UnsupportedEncodingException e) {
|
|
||||||
throw new AssertionError(e);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static String fromUtf8(byte[] bytes) {
|
public static String fromUtf8(byte[] bytes) throws FormatException {
|
||||||
return fromUtf8(bytes, 0, bytes.length);
|
return fromUtf8(bytes, 0, bytes.length, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static String fromUtf8(byte[] bytes, int off, int len) {
|
public static String fromUtf8(byte[] bytes, int off, int len)
|
||||||
|
throws FormatException {
|
||||||
|
return fromUtf8(bytes, off, len, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static String fromUtf8(byte[] bytes, int off, int len,
|
||||||
|
boolean strict) throws FormatException {
|
||||||
CharsetDecoder decoder = UTF_8.newDecoder();
|
CharsetDecoder decoder = UTF_8.newDecoder();
|
||||||
decoder.onMalformedInput(IGNORE);
|
decoder.onMalformedInput(strict ? REPORT : IGNORE);
|
||||||
decoder.onUnmappableCharacter(IGNORE);
|
decoder.onUnmappableCharacter(strict ? REPORT : IGNORE);
|
||||||
ByteBuffer buffer = ByteBuffer.wrap(bytes, off, len);
|
ByteBuffer buffer = ByteBuffer.wrap(bytes, off, len);
|
||||||
try {
|
try {
|
||||||
return decoder.decode(buffer).toString();
|
return decoder.decode(buffer).toString();
|
||||||
} catch (CharacterCodingException e) {
|
} catch (CharacterCodingException e) {
|
||||||
throw new AssertionError(e);
|
throw new FormatException();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static String truncateUtf8(String s, int maxUtf8Length) {
|
public static String truncateUtf8(String s, int maxUtf8Length) {
|
||||||
byte[] utf8 = toUtf8(s);
|
byte[] utf8 = toUtf8(s);
|
||||||
if (utf8.length <= maxUtf8Length) return s;
|
if (utf8.length <= maxUtf8Length) return s;
|
||||||
return fromUtf8(utf8, 0, maxUtf8Length);
|
// Don't be strict when converting back, so that if we truncate a
|
||||||
|
// multi-byte character the whole character gets dropped
|
||||||
|
try {
|
||||||
|
return fromUtf8(utf8, 0, maxUtf8Length, false);
|
||||||
|
} catch (FormatException e) {
|
||||||
|
throw new AssertionError(e);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -163,4 +176,9 @@ public class StringUtils {
|
|||||||
}
|
}
|
||||||
return new String(c);
|
return new String(c);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// see https://stackoverflow.com/a/38947571
|
||||||
|
static boolean startsWithIgnoreCase(String s, String prefix) {
|
||||||
|
return s.regionMatches(true, 0, prefix, 0, prefix.length());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package org.briarproject.bramble.api.data;
|
package org.briarproject.bramble.api.data;
|
||||||
|
|
||||||
import org.briarproject.bramble.api.Bytes;
|
import org.briarproject.bramble.api.Bytes;
|
||||||
|
import org.briarproject.bramble.api.FormatException;
|
||||||
import org.briarproject.bramble.test.BrambleTestCase;
|
import org.briarproject.bramble.test.BrambleTestCase;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
@@ -8,9 +9,12 @@ import java.util.Collections;
|
|||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
import java.util.Map.Entry;
|
import java.util.Map.Entry;
|
||||||
|
|
||||||
|
import static java.lang.Boolean.TRUE;
|
||||||
|
import static java.util.Collections.singletonMap;
|
||||||
import static org.briarproject.bramble.api.data.BdfDictionary.NULL_VALUE;
|
import static org.briarproject.bramble.api.data.BdfDictionary.NULL_VALUE;
|
||||||
import static org.junit.Assert.assertArrayEquals;
|
import static org.junit.Assert.assertArrayEquals;
|
||||||
import static org.junit.Assert.assertEquals;
|
import static org.junit.Assert.assertEquals;
|
||||||
|
import static org.junit.Assert.assertNull;
|
||||||
import static org.junit.Assert.assertTrue;
|
import static org.junit.Assert.assertTrue;
|
||||||
|
|
||||||
public class BdfDictionaryTest extends BrambleTestCase {
|
public class BdfDictionaryTest extends BrambleTestCase {
|
||||||
@@ -19,20 +23,20 @@ public class BdfDictionaryTest extends BrambleTestCase {
|
|||||||
public void testConstructors() {
|
public void testConstructors() {
|
||||||
assertEquals(Collections.<String, Object>emptyMap(),
|
assertEquals(Collections.<String, Object>emptyMap(),
|
||||||
new BdfDictionary());
|
new BdfDictionary());
|
||||||
assertEquals(Collections.singletonMap("foo", NULL_VALUE),
|
assertEquals(singletonMap("foo", NULL_VALUE),
|
||||||
new BdfDictionary(Collections.singletonMap("foo", NULL_VALUE)));
|
new BdfDictionary(singletonMap("foo", NULL_VALUE)));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testFactoryMethod() {
|
public void testFactoryMethod() {
|
||||||
assertEquals(Collections.<String, Object>emptyMap(),
|
assertEquals(Collections.<String, Object>emptyMap(),
|
||||||
BdfDictionary.of());
|
BdfDictionary.of());
|
||||||
assertEquals(Collections.singletonMap("foo", NULL_VALUE),
|
assertEquals(singletonMap("foo", NULL_VALUE),
|
||||||
BdfDictionary.of(new BdfEntry("foo", NULL_VALUE)));
|
BdfDictionary.of(new BdfEntry("foo", NULL_VALUE)));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testIntegerPromotion() throws Exception {
|
public void testLongPromotion() throws Exception {
|
||||||
BdfDictionary d = new BdfDictionary();
|
BdfDictionary d = new BdfDictionary();
|
||||||
d.put("foo", (byte) 1);
|
d.put("foo", (byte) 1);
|
||||||
d.put("bar", (short) 2);
|
d.put("bar", (short) 2);
|
||||||
@@ -44,6 +48,33 @@ public class BdfDictionaryTest extends BrambleTestCase {
|
|||||||
assertEquals(Long.valueOf(4), d.getLong("bam"));
|
assertEquals(Long.valueOf(4), d.getLong("bam"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testIntPromotionAndDemotion() throws Exception {
|
||||||
|
BdfDictionary d = new BdfDictionary();
|
||||||
|
d.put("foo", (byte) 1);
|
||||||
|
d.put("bar", (short) 2);
|
||||||
|
d.put("baz", 3);
|
||||||
|
d.put("bam", 4L);
|
||||||
|
assertEquals(Integer.valueOf(1), d.getInt("foo"));
|
||||||
|
assertEquals(Integer.valueOf(2), d.getInt("bar"));
|
||||||
|
assertEquals(Integer.valueOf(3), d.getInt("baz"));
|
||||||
|
assertEquals(Integer.valueOf(4), d.getInt("bam"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expected = FormatException.class)
|
||||||
|
public void testIntUnderflow() throws Exception {
|
||||||
|
BdfDictionary d =
|
||||||
|
BdfDictionary.of(new BdfEntry("foo", Integer.MIN_VALUE - 1L));
|
||||||
|
d.getInt("foo");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expected = FormatException.class)
|
||||||
|
public void testIntOverflow() throws Exception {
|
||||||
|
BdfDictionary d =
|
||||||
|
BdfDictionary.of(new BdfEntry("foo", Integer.MAX_VALUE + 1L));
|
||||||
|
d.getInt("foo");
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testFloatPromotion() throws Exception {
|
public void testFloatPromotion() throws Exception {
|
||||||
BdfDictionary d = new BdfDictionary();
|
BdfDictionary d = new BdfDictionary();
|
||||||
@@ -67,7 +98,7 @@ public class BdfDictionaryTest extends BrambleTestCase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testKeySetIteratorIsOrderedByKeys() throws Exception {
|
public void testKeySetIteratorIsOrderedByKeys() {
|
||||||
BdfDictionary d = new BdfDictionary();
|
BdfDictionary d = new BdfDictionary();
|
||||||
d.put("a", 1);
|
d.put("a", 1);
|
||||||
d.put("d", 4);
|
d.put("d", 4);
|
||||||
@@ -86,7 +117,7 @@ public class BdfDictionaryTest extends BrambleTestCase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testValuesIteratorIsOrderedByKeys() throws Exception {
|
public void testValuesIteratorIsOrderedByKeys() {
|
||||||
BdfDictionary d = new BdfDictionary();
|
BdfDictionary d = new BdfDictionary();
|
||||||
d.put("a", 1);
|
d.put("a", 1);
|
||||||
d.put("d", 4);
|
d.put("d", 4);
|
||||||
@@ -105,7 +136,7 @@ public class BdfDictionaryTest extends BrambleTestCase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testEntrySetIteratorIsOrderedByKeys() throws Exception {
|
public void testEntrySetIteratorIsOrderedByKeys() {
|
||||||
BdfDictionary d = new BdfDictionary();
|
BdfDictionary d = new BdfDictionary();
|
||||||
d.put("a", 1);
|
d.put("a", 1);
|
||||||
d.put("d", 4);
|
d.put("d", 4);
|
||||||
@@ -130,4 +161,284 @@ public class BdfDictionaryTest extends BrambleTestCase {
|
|||||||
assertEquals("d", e.getKey());
|
assertEquals("d", e.getKey());
|
||||||
assertEquals(4, e.getValue());
|
assertEquals(4, e.getValue());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test(expected = FormatException.class)
|
||||||
|
public void testMissingValueForBooleanThrowsFormatException()
|
||||||
|
throws Exception {
|
||||||
|
new BdfDictionary().getBoolean("foo");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expected = FormatException.class)
|
||||||
|
public void testMissingValueForLongThrowsFormatException()
|
||||||
|
throws Exception {
|
||||||
|
new BdfDictionary().getLong("foo");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expected = FormatException.class)
|
||||||
|
public void testMissingValueForIntThrowsFormatException() throws Exception {
|
||||||
|
new BdfDictionary().getInt("foo");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expected = FormatException.class)
|
||||||
|
public void testMissingValueForDoubleThrowsFormatException()
|
||||||
|
throws Exception {
|
||||||
|
new BdfDictionary().getDouble("foo");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expected = FormatException.class)
|
||||||
|
public void testMissingValueForStringThrowsFormatException()
|
||||||
|
throws Exception {
|
||||||
|
new BdfDictionary().getString("foo");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expected = FormatException.class)
|
||||||
|
public void testMissingValueForRawThrowsFormatException() throws Exception {
|
||||||
|
new BdfDictionary().getRaw("foo");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expected = FormatException.class)
|
||||||
|
public void testMissingValueForListThrowsFormatException()
|
||||||
|
throws Exception {
|
||||||
|
new BdfDictionary().getList("foo");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expected = FormatException.class)
|
||||||
|
public void testMissingValueForDictionaryThrowsFormatException()
|
||||||
|
throws Exception {
|
||||||
|
new BdfDictionary().getDictionary("foo");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expected = FormatException.class)
|
||||||
|
public void testNullValueForBooleanThrowsFormatException()
|
||||||
|
throws Exception {
|
||||||
|
BdfDictionary.of(new BdfEntry("foo", NULL_VALUE)).getBoolean("foo");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expected = FormatException.class)
|
||||||
|
public void testNullValueForLongThrowsFormatException() throws Exception {
|
||||||
|
BdfDictionary.of(new BdfEntry("foo", NULL_VALUE)).getLong("foo");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expected = FormatException.class)
|
||||||
|
public void testNullValueForIntThrowsFormatException() throws Exception {
|
||||||
|
BdfDictionary.of(new BdfEntry("foo", NULL_VALUE)).getInt("foo");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expected = FormatException.class)
|
||||||
|
public void testNullValueForDoubleThrowsFormatException() throws Exception {
|
||||||
|
BdfDictionary.of(new BdfEntry("foo", NULL_VALUE)).getDouble("foo");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expected = FormatException.class)
|
||||||
|
public void testNullValueForStringThrowsFormatException() throws Exception {
|
||||||
|
BdfDictionary.of(new BdfEntry("foo", NULL_VALUE)).getString("foo");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expected = FormatException.class)
|
||||||
|
public void testNullValueForRawThrowsFormatException() throws Exception {
|
||||||
|
BdfDictionary.of(new BdfEntry("foo", NULL_VALUE)).getRaw("foo");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expected = FormatException.class)
|
||||||
|
public void testNullValueForListThrowsFormatException() throws Exception {
|
||||||
|
BdfDictionary.of(new BdfEntry("foo", NULL_VALUE)).getList("foo");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expected = FormatException.class)
|
||||||
|
public void testNullValueForDictionaryThrowsFormatException()
|
||||||
|
throws Exception {
|
||||||
|
BdfDictionary.of(new BdfEntry("foo", NULL_VALUE)).getDictionary("foo");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testOptionalMethodsReturnNullForMissingValue()
|
||||||
|
throws Exception {
|
||||||
|
testOptionalMethodsReturnNull(new BdfDictionary());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testOptionalMethodsReturnNullForNullValue() throws Exception {
|
||||||
|
BdfDictionary d = BdfDictionary.of(new BdfEntry("foo", NULL_VALUE));
|
||||||
|
testOptionalMethodsReturnNull(d);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void testOptionalMethodsReturnNull(BdfDictionary d)
|
||||||
|
throws Exception {
|
||||||
|
assertNull(d.getOptionalBoolean("foo"));
|
||||||
|
assertNull(d.getOptionalLong("foo"));
|
||||||
|
assertNull(d.getOptionalInt("foo"));
|
||||||
|
assertNull(d.getOptionalDouble("foo"));
|
||||||
|
assertNull(d.getOptionalString("foo"));
|
||||||
|
assertNull(d.getOptionalRaw("foo"));
|
||||||
|
assertNull(d.getOptionalList("foo"));
|
||||||
|
assertNull(d.getOptionalDictionary("foo"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testDefaultMethodsReturnDefaultForMissingValue()
|
||||||
|
throws Exception {
|
||||||
|
testDefaultMethodsReturnDefault(new BdfDictionary());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testDefaultMethodsReturnDefaultForNullValue() throws Exception {
|
||||||
|
BdfDictionary d = BdfDictionary.of(new BdfEntry("foo", NULL_VALUE));
|
||||||
|
testDefaultMethodsReturnDefault(d);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void testDefaultMethodsReturnDefault(BdfDictionary d)
|
||||||
|
throws Exception {
|
||||||
|
assertEquals(TRUE, d.getBoolean("foo", TRUE));
|
||||||
|
assertEquals(Long.valueOf(123L), d.getLong("foo", 123L));
|
||||||
|
assertEquals(Integer.valueOf(123), d.getInt("foo", 123));
|
||||||
|
assertEquals(Double.valueOf(123D), d.getDouble("foo", 123D));
|
||||||
|
assertEquals("123", d.getString("foo", "123"));
|
||||||
|
byte[] defaultRaw = {1, 2, 3};
|
||||||
|
assertArrayEquals(defaultRaw, d.getRaw("foo", defaultRaw));
|
||||||
|
BdfList defaultList = BdfList.of(1, 2, 3);
|
||||||
|
assertEquals(defaultList, d.getList("foo", defaultList));
|
||||||
|
BdfDictionary defaultDict = BdfDictionary.of(new BdfEntry("123", 123));
|
||||||
|
assertEquals(defaultDict, d.getDictionary("foo", defaultDict));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expected = FormatException.class)
|
||||||
|
public void testWrongTypeForBooleanThrowsFormatException()
|
||||||
|
throws Exception {
|
||||||
|
BdfDictionary.of(new BdfEntry("foo", 123)).getBoolean("foo");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expected = FormatException.class)
|
||||||
|
public void testWrongTypeForOptionalBooleanThrowsFormatException()
|
||||||
|
throws Exception {
|
||||||
|
BdfDictionary.of(new BdfEntry("foo", 123)).getOptionalBoolean("foo");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expected = FormatException.class)
|
||||||
|
public void testWrongTypeForDefaultBooleanThrowsFormatException()
|
||||||
|
throws Exception {
|
||||||
|
BdfDictionary.of(new BdfEntry("foo", 123)).getBoolean("foo", true);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expected = FormatException.class)
|
||||||
|
public void testWrongTypeForLongThrowsFormatException() throws Exception {
|
||||||
|
BdfDictionary.of(new BdfEntry("foo", 1.23)).getLong("foo");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expected = FormatException.class)
|
||||||
|
public void testWrongTypeForOptionalLongThrowsFormatException()
|
||||||
|
throws Exception {
|
||||||
|
BdfDictionary.of(new BdfEntry("foo", 1.23)).getOptionalLong("foo");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expected = FormatException.class)
|
||||||
|
public void testWrongTypeForDefaultLongThrowsFormatException()
|
||||||
|
throws Exception {
|
||||||
|
BdfDictionary.of(new BdfEntry("foo", 1.23)).getLong("foo", 1L);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expected = FormatException.class)
|
||||||
|
public void testWrongTypeForIntThrowsFormatException() throws Exception {
|
||||||
|
BdfDictionary.of(new BdfEntry("foo", 1.23)).getInt("foo");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expected = FormatException.class)
|
||||||
|
public void testWrongTypeForOptionalIntThrowsFormatException()
|
||||||
|
throws Exception {
|
||||||
|
BdfDictionary.of(new BdfEntry("foo", 1.23)).getOptionalInt("foo");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expected = FormatException.class)
|
||||||
|
public void testWrongTypeForDefaultIntThrowsFormatException()
|
||||||
|
throws Exception {
|
||||||
|
BdfDictionary.of(new BdfEntry("foo", 1.23)).getInt("foo", 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expected = FormatException.class)
|
||||||
|
public void testWrongTypeForDoubleThrowsFormatException() throws Exception {
|
||||||
|
BdfDictionary.of(new BdfEntry("foo", 123)).getDouble("foo");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expected = FormatException.class)
|
||||||
|
public void testWrongTypeForOptionalDoubleThrowsFormatException()
|
||||||
|
throws Exception {
|
||||||
|
BdfDictionary.of(new BdfEntry("foo", 123)).getOptionalDouble("foo");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expected = FormatException.class)
|
||||||
|
public void testWrongTypeForDefaultDoubleThrowsFormatException()
|
||||||
|
throws Exception {
|
||||||
|
BdfDictionary.of(new BdfEntry("foo", 123)).getDouble("foo", 1D);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expected = FormatException.class)
|
||||||
|
public void testWrongTypeForStringThrowsFormatException() throws Exception {
|
||||||
|
BdfDictionary.of(new BdfEntry("foo", 123)).getString("foo");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expected = FormatException.class)
|
||||||
|
public void testWrongTypeForOptionalStringThrowsFormatException()
|
||||||
|
throws Exception {
|
||||||
|
BdfDictionary.of(new BdfEntry("foo", 123)).getOptionalString("foo");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expected = FormatException.class)
|
||||||
|
public void testWrongTypeForDefaultStringThrowsFormatException()
|
||||||
|
throws Exception {
|
||||||
|
BdfDictionary.of(new BdfEntry("foo", 123)).getString("foo", "");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expected = FormatException.class)
|
||||||
|
public void testWrongTypeForRawThrowsFormatException() throws Exception {
|
||||||
|
BdfDictionary.of(new BdfEntry("foo", 123)).getRaw("foo");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expected = FormatException.class)
|
||||||
|
public void testWrongTypeForOptionalRawThrowsFormatException()
|
||||||
|
throws Exception {
|
||||||
|
BdfDictionary.of(new BdfEntry("foo", 123)).getOptionalRaw("foo");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expected = FormatException.class)
|
||||||
|
public void testWrongTypeForDefaultRawThrowsFormatException()
|
||||||
|
throws Exception {
|
||||||
|
BdfDictionary.of(new BdfEntry("foo", 123)).getRaw("foo", new byte[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expected = FormatException.class)
|
||||||
|
public void testWrongTypeForListThrowsFormatException()
|
||||||
|
throws Exception {
|
||||||
|
BdfDictionary.of(new BdfEntry("foo", 123)).getList("foo");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expected = FormatException.class)
|
||||||
|
public void testWrongTypeForOptionalListThrowsFormatException()
|
||||||
|
throws Exception {
|
||||||
|
BdfDictionary.of(new BdfEntry("foo", 123)).getOptionalList("foo");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expected = FormatException.class)
|
||||||
|
public void testWrongTypeForDefaultListThrowsFormatException()
|
||||||
|
throws Exception {
|
||||||
|
BdfDictionary.of(new BdfEntry("foo", 123)).getList("foo",
|
||||||
|
new BdfList());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expected = FormatException.class)
|
||||||
|
public void testWrongTypeForDictionaryThrowsFormatException()
|
||||||
|
throws Exception {
|
||||||
|
BdfDictionary.of(new BdfEntry("foo", 123)).getDictionary("foo");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expected = FormatException.class)
|
||||||
|
public void testWrongTypeForOptionalDictionaryThrowsFormatException()
|
||||||
|
throws Exception {
|
||||||
|
BdfDictionary.of(new BdfEntry("foo", 123)).getOptionalDictionary("foo");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expected = FormatException.class)
|
||||||
|
public void testWrongTypeForDefaultDictionaryThrowsFormatException()
|
||||||
|
throws Exception {
|
||||||
|
BdfDictionary.of(new BdfEntry("foo", 123)).getDictionary("foo",
|
||||||
|
new BdfDictionary());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,31 +5,31 @@ import org.briarproject.bramble.api.FormatException;
|
|||||||
import org.briarproject.bramble.test.BrambleTestCase;
|
import org.briarproject.bramble.test.BrambleTestCase;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
import java.util.Arrays;
|
import static java.lang.Boolean.TRUE;
|
||||||
import java.util.Collections;
|
import static java.util.Arrays.asList;
|
||||||
|
import static java.util.Collections.emptyList;
|
||||||
import static org.briarproject.bramble.api.data.BdfDictionary.NULL_VALUE;
|
import static org.briarproject.bramble.api.data.BdfDictionary.NULL_VALUE;
|
||||||
import static org.junit.Assert.assertArrayEquals;
|
import static org.junit.Assert.assertArrayEquals;
|
||||||
import static org.junit.Assert.assertEquals;
|
import static org.junit.Assert.assertEquals;
|
||||||
|
import static org.junit.Assert.assertNull;
|
||||||
|
|
||||||
public class BdfListTest extends BrambleTestCase {
|
public class BdfListTest extends BrambleTestCase {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testConstructors() {
|
public void testConstructors() {
|
||||||
assertEquals(Collections.emptyList(), new BdfList());
|
assertEquals(emptyList(), new BdfList());
|
||||||
assertEquals(Arrays.asList(1, 2, NULL_VALUE),
|
assertEquals(asList(1, 2, NULL_VALUE),
|
||||||
new BdfList(Arrays.asList(1, 2, NULL_VALUE)));
|
new BdfList(asList(1, 2, NULL_VALUE)));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testFactoryMethod() {
|
public void testFactoryMethod() {
|
||||||
assertEquals(Collections.emptyList(), BdfList.of());
|
assertEquals(emptyList(), BdfList.of());
|
||||||
assertEquals(Arrays.asList(1, 2, NULL_VALUE),
|
assertEquals(asList(1, 2, NULL_VALUE), BdfList.of(1, 2, NULL_VALUE));
|
||||||
BdfList.of(1, 2, NULL_VALUE));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testIntegerPromotion() throws Exception {
|
public void testLongPromotion() throws Exception {
|
||||||
BdfList list = new BdfList();
|
BdfList list = new BdfList();
|
||||||
list.add((byte) 1);
|
list.add((byte) 1);
|
||||||
list.add((short) 2);
|
list.add((short) 2);
|
||||||
@@ -41,6 +41,31 @@ public class BdfListTest extends BrambleTestCase {
|
|||||||
assertEquals(Long.valueOf(4), list.getLong(3));
|
assertEquals(Long.valueOf(4), list.getLong(3));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testIntPromotionAndDemotion() throws Exception {
|
||||||
|
BdfList list = new BdfList();
|
||||||
|
list.add((byte) 1);
|
||||||
|
list.add((short) 2);
|
||||||
|
list.add(3);
|
||||||
|
list.add(4L);
|
||||||
|
assertEquals(Integer.valueOf(1), list.getInt(0));
|
||||||
|
assertEquals(Integer.valueOf(2), list.getInt(1));
|
||||||
|
assertEquals(Integer.valueOf(3), list.getInt(2));
|
||||||
|
assertEquals(Integer.valueOf(4), list.getInt(3));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expected = FormatException.class)
|
||||||
|
public void testIntUnderflow() throws Exception {
|
||||||
|
BdfList list = BdfList.of(Integer.MIN_VALUE - 1L);
|
||||||
|
list.getInt(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expected = FormatException.class)
|
||||||
|
public void testIntOverflow() throws Exception {
|
||||||
|
BdfList list = BdfList.of(Integer.MAX_VALUE + 1L);
|
||||||
|
list.getInt(0);
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testFloatPromotion() throws Exception {
|
public void testFloatPromotion() throws Exception {
|
||||||
BdfList list = new BdfList();
|
BdfList list = new BdfList();
|
||||||
@@ -63,61 +88,6 @@ public class BdfListTest extends BrambleTestCase {
|
|||||||
assertArrayEquals(new byte[123], second);
|
assertArrayEquals(new byte[123], second);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
|
||||||
@SuppressWarnings("ConstantConditions")
|
|
||||||
public void testIndexOutOfBoundsReturnsDefaultValue() throws Exception {
|
|
||||||
BdfList list = BdfList.of(1, 2, 3);
|
|
||||||
boolean defaultBoolean = true;
|
|
||||||
assertEquals(defaultBoolean, list.getBoolean(-1, defaultBoolean));
|
|
||||||
assertEquals(defaultBoolean, list.getBoolean(3, defaultBoolean));
|
|
||||||
Long defaultLong = 123L;
|
|
||||||
assertEquals(defaultLong, list.getLong(-1, defaultLong));
|
|
||||||
assertEquals(defaultLong, list.getLong(3, defaultLong));
|
|
||||||
Double defaultDouble = 1.23;
|
|
||||||
assertEquals(defaultDouble, list.getDouble(-1, defaultDouble));
|
|
||||||
assertEquals(defaultDouble, list.getDouble(3, defaultDouble));
|
|
||||||
String defaultString = "123";
|
|
||||||
assertEquals(defaultString, list.getString(-1, defaultString));
|
|
||||||
assertEquals(defaultString, list.getString(3, defaultString));
|
|
||||||
byte[] defaultBytes = new byte[] {1, 2, 3};
|
|
||||||
assertArrayEquals(defaultBytes, list.getRaw(-1, defaultBytes));
|
|
||||||
assertArrayEquals(defaultBytes, list.getRaw(3, defaultBytes));
|
|
||||||
BdfList defaultList = BdfList.of(1, 2, 3);
|
|
||||||
assertEquals(defaultList, list.getList(-1, defaultList));
|
|
||||||
assertEquals(defaultList, list.getList(3, defaultList));
|
|
||||||
BdfDictionary defaultDict = BdfDictionary.of(
|
|
||||||
new BdfEntry("1", 1),
|
|
||||||
new BdfEntry("2", 2),
|
|
||||||
new BdfEntry("3", 3)
|
|
||||||
);
|
|
||||||
assertEquals(defaultDict, list.getDictionary(-1, defaultDict));
|
|
||||||
assertEquals(defaultDict, list.getDictionary(3, defaultDict));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
@SuppressWarnings("ConstantConditions")
|
|
||||||
public void testWrongTypeReturnsDefaultValue() throws Exception {
|
|
||||||
BdfList list = BdfList.of(1, 2, 3, true);
|
|
||||||
boolean defaultBoolean = true;
|
|
||||||
assertEquals(defaultBoolean, list.getBoolean(0, defaultBoolean));
|
|
||||||
Long defaultLong = 123L;
|
|
||||||
assertEquals(defaultLong, list.getLong(3, defaultLong));
|
|
||||||
Double defaultDouble = 1.23;
|
|
||||||
assertEquals(defaultDouble, list.getDouble(0, defaultDouble));
|
|
||||||
String defaultString = "123";
|
|
||||||
assertEquals(defaultString, list.getString(0, defaultString));
|
|
||||||
byte[] defaultBytes = new byte[] {1, 2, 3};
|
|
||||||
assertArrayEquals(defaultBytes, list.getRaw(0, defaultBytes));
|
|
||||||
BdfList defaultList = BdfList.of(1, 2, 3);
|
|
||||||
assertEquals(defaultList, list.getList(0, defaultList));
|
|
||||||
BdfDictionary defaultDict = BdfDictionary.of(
|
|
||||||
new BdfEntry("1", 1),
|
|
||||||
new BdfEntry("2", 2),
|
|
||||||
new BdfEntry("3", 3)
|
|
||||||
);
|
|
||||||
assertEquals(defaultDict, list.getDictionary(0, defaultDict));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test(expected = FormatException.class)
|
@Test(expected = FormatException.class)
|
||||||
public void testNegativeIndexForBooleanThrowsFormatException()
|
public void testNegativeIndexForBooleanThrowsFormatException()
|
||||||
throws Exception {
|
throws Exception {
|
||||||
@@ -130,6 +100,12 @@ public class BdfListTest extends BrambleTestCase {
|
|||||||
new BdfList().getOptionalBoolean(-1);
|
new BdfList().getOptionalBoolean(-1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test(expected = FormatException.class)
|
||||||
|
public void testNegativeIndexForDefaultBooleanThrowsFormatException()
|
||||||
|
throws Exception {
|
||||||
|
new BdfList().getBoolean(-1, true);
|
||||||
|
}
|
||||||
|
|
||||||
@Test(expected = FormatException.class)
|
@Test(expected = FormatException.class)
|
||||||
public void testNegativeIndexForLongThrowsFormatException()
|
public void testNegativeIndexForLongThrowsFormatException()
|
||||||
throws Exception {
|
throws Exception {
|
||||||
@@ -142,6 +118,30 @@ public class BdfListTest extends BrambleTestCase {
|
|||||||
new BdfList().getOptionalLong(-1);
|
new BdfList().getOptionalLong(-1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test(expected = FormatException.class)
|
||||||
|
public void testNegativeIndexForDefaultLongThrowsFormatException()
|
||||||
|
throws Exception {
|
||||||
|
new BdfList().getLong(-1, 1L);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expected = FormatException.class)
|
||||||
|
public void testNegativeIndexForIntThrowsFormatException()
|
||||||
|
throws Exception {
|
||||||
|
new BdfList().getInt(-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expected = FormatException.class)
|
||||||
|
public void testNegativeIndexForOptionalIntThrowsFormatException()
|
||||||
|
throws Exception {
|
||||||
|
new BdfList().getOptionalInt(-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expected = FormatException.class)
|
||||||
|
public void testNegativeIndexForDefaultIntThrowsFormatException()
|
||||||
|
throws Exception {
|
||||||
|
new BdfList().getInt(-1, 1);
|
||||||
|
}
|
||||||
|
|
||||||
@Test(expected = FormatException.class)
|
@Test(expected = FormatException.class)
|
||||||
public void testNegativeIndexForDoubleThrowsFormatException()
|
public void testNegativeIndexForDoubleThrowsFormatException()
|
||||||
throws Exception {
|
throws Exception {
|
||||||
@@ -154,6 +154,12 @@ public class BdfListTest extends BrambleTestCase {
|
|||||||
new BdfList().getOptionalDouble(-1);
|
new BdfList().getOptionalDouble(-1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test(expected = FormatException.class)
|
||||||
|
public void testNegativeIndexForDefaultDoubleThrowsFormatException()
|
||||||
|
throws Exception {
|
||||||
|
new BdfList().getDouble(-1, 1D);
|
||||||
|
}
|
||||||
|
|
||||||
@Test(expected = FormatException.class)
|
@Test(expected = FormatException.class)
|
||||||
public void testNegativeIndexForStringThrowsFormatException()
|
public void testNegativeIndexForStringThrowsFormatException()
|
||||||
throws Exception {
|
throws Exception {
|
||||||
@@ -166,6 +172,12 @@ public class BdfListTest extends BrambleTestCase {
|
|||||||
new BdfList().getOptionalString(-1);
|
new BdfList().getOptionalString(-1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test(expected = FormatException.class)
|
||||||
|
public void testNegativeIndexForDefaultStringThrowsFormatException()
|
||||||
|
throws Exception {
|
||||||
|
new BdfList().getString(-1, "");
|
||||||
|
}
|
||||||
|
|
||||||
@Test(expected = FormatException.class)
|
@Test(expected = FormatException.class)
|
||||||
public void testNegativeIndexForRawThrowsFormatException()
|
public void testNegativeIndexForRawThrowsFormatException()
|
||||||
throws Exception {
|
throws Exception {
|
||||||
@@ -178,6 +190,12 @@ public class BdfListTest extends BrambleTestCase {
|
|||||||
new BdfList().getOptionalRaw(-1);
|
new BdfList().getOptionalRaw(-1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test(expected = FormatException.class)
|
||||||
|
public void testNegativeIndexForDefaultRawThrowsFormatException()
|
||||||
|
throws Exception {
|
||||||
|
new BdfList().getRaw(-1, new byte[0]);
|
||||||
|
}
|
||||||
|
|
||||||
@Test(expected = FormatException.class)
|
@Test(expected = FormatException.class)
|
||||||
public void testNegativeIndexForListThrowsFormatException()
|
public void testNegativeIndexForListThrowsFormatException()
|
||||||
throws Exception {
|
throws Exception {
|
||||||
@@ -190,6 +208,11 @@ public class BdfListTest extends BrambleTestCase {
|
|||||||
new BdfList().getOptionalList(-1);
|
new BdfList().getOptionalList(-1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test(expected = FormatException.class)
|
||||||
|
public void testNegativeIndexForDefaultListThrowsFormatException()
|
||||||
|
throws Exception {
|
||||||
|
new BdfList().getList(-1, new BdfList());
|
||||||
|
}
|
||||||
|
|
||||||
@Test(expected = FormatException.class)
|
@Test(expected = FormatException.class)
|
||||||
public void testNegativeIndexForDictionaryThrowsFormatException()
|
public void testNegativeIndexForDictionaryThrowsFormatException()
|
||||||
@@ -203,6 +226,12 @@ public class BdfListTest extends BrambleTestCase {
|
|||||||
new BdfList().getOptionalDictionary(-1);
|
new BdfList().getOptionalDictionary(-1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test(expected = FormatException.class)
|
||||||
|
public void testNegativeIndexForDefaultDictionaryThrowsFormatException()
|
||||||
|
throws Exception {
|
||||||
|
new BdfList().getDictionary(-1, new BdfDictionary());
|
||||||
|
}
|
||||||
|
|
||||||
@Test(expected = FormatException.class)
|
@Test(expected = FormatException.class)
|
||||||
public void testTooLargeIndexForBooleanThrowsFormatException()
|
public void testTooLargeIndexForBooleanThrowsFormatException()
|
||||||
throws Exception {
|
throws Exception {
|
||||||
@@ -215,6 +244,12 @@ public class BdfListTest extends BrambleTestCase {
|
|||||||
new BdfList().getOptionalBoolean(0);
|
new BdfList().getOptionalBoolean(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test(expected = FormatException.class)
|
||||||
|
public void testTooLargeIndexForDefaultBooleanThrowsFormatException()
|
||||||
|
throws Exception {
|
||||||
|
new BdfList().getBoolean(0, true);
|
||||||
|
}
|
||||||
|
|
||||||
@Test(expected = FormatException.class)
|
@Test(expected = FormatException.class)
|
||||||
public void testTooLargeIndexForLongThrowsFormatException()
|
public void testTooLargeIndexForLongThrowsFormatException()
|
||||||
throws Exception {
|
throws Exception {
|
||||||
@@ -227,6 +262,30 @@ public class BdfListTest extends BrambleTestCase {
|
|||||||
new BdfList().getOptionalLong(0);
|
new BdfList().getOptionalLong(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test(expected = FormatException.class)
|
||||||
|
public void testTooLargeIndexForDefaultLongThrowsFormatException()
|
||||||
|
throws Exception {
|
||||||
|
new BdfList().getLong(0, 1L);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expected = FormatException.class)
|
||||||
|
public void testTooLargeIndexForIntThrowsFormatException()
|
||||||
|
throws Exception {
|
||||||
|
new BdfList().getInt(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expected = FormatException.class)
|
||||||
|
public void testTooLargeIndexForOptionalIntThrowsFormatException()
|
||||||
|
throws Exception {
|
||||||
|
new BdfList().getOptionalInt(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expected = FormatException.class)
|
||||||
|
public void testTooLargeIndexForDefaultIntThrowsFormatException()
|
||||||
|
throws Exception {
|
||||||
|
new BdfList().getInt(0, 1);
|
||||||
|
}
|
||||||
|
|
||||||
@Test(expected = FormatException.class)
|
@Test(expected = FormatException.class)
|
||||||
public void testTooLargeIndexForDoubleThrowsFormatException()
|
public void testTooLargeIndexForDoubleThrowsFormatException()
|
||||||
throws Exception {
|
throws Exception {
|
||||||
@@ -239,6 +298,12 @@ public class BdfListTest extends BrambleTestCase {
|
|||||||
new BdfList().getOptionalDouble(0);
|
new BdfList().getOptionalDouble(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test(expected = FormatException.class)
|
||||||
|
public void testTooLargeIndexForDefaultDoubleThrowsFormatException()
|
||||||
|
throws Exception {
|
||||||
|
new BdfList().getDouble(0, 1D);
|
||||||
|
}
|
||||||
|
|
||||||
@Test(expected = FormatException.class)
|
@Test(expected = FormatException.class)
|
||||||
public void testTooLargeIndexForStringThrowsFormatException()
|
public void testTooLargeIndexForStringThrowsFormatException()
|
||||||
throws Exception {
|
throws Exception {
|
||||||
@@ -251,6 +316,12 @@ public class BdfListTest extends BrambleTestCase {
|
|||||||
new BdfList().getOptionalString(0);
|
new BdfList().getOptionalString(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test(expected = FormatException.class)
|
||||||
|
public void testTooLargeIndexForDefaultStringThrowsFormatException()
|
||||||
|
throws Exception {
|
||||||
|
new BdfList().getString(0, "");
|
||||||
|
}
|
||||||
|
|
||||||
@Test(expected = FormatException.class)
|
@Test(expected = FormatException.class)
|
||||||
public void testTooLargeIndexForRawThrowsFormatException()
|
public void testTooLargeIndexForRawThrowsFormatException()
|
||||||
throws Exception {
|
throws Exception {
|
||||||
@@ -263,6 +334,12 @@ public class BdfListTest extends BrambleTestCase {
|
|||||||
new BdfList().getOptionalRaw(0);
|
new BdfList().getOptionalRaw(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test(expected = FormatException.class)
|
||||||
|
public void testTooLargeIndexForDefaultRawThrowsFormatException()
|
||||||
|
throws Exception {
|
||||||
|
new BdfList().getRaw(0, new byte[0]);
|
||||||
|
}
|
||||||
|
|
||||||
@Test(expected = FormatException.class)
|
@Test(expected = FormatException.class)
|
||||||
public void testTooLargeIndexForListThrowsFormatException()
|
public void testTooLargeIndexForListThrowsFormatException()
|
||||||
throws Exception {
|
throws Exception {
|
||||||
@@ -275,6 +352,11 @@ public class BdfListTest extends BrambleTestCase {
|
|||||||
new BdfList().getOptionalList(0);
|
new BdfList().getOptionalList(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test(expected = FormatException.class)
|
||||||
|
public void testTooLargeIndexForDefaultListThrowsFormatException()
|
||||||
|
throws Exception {
|
||||||
|
new BdfList().getList(0, new BdfList());
|
||||||
|
}
|
||||||
|
|
||||||
@Test(expected = FormatException.class)
|
@Test(expected = FormatException.class)
|
||||||
public void testTooLargeIndexForDictionaryThrowsFormatException()
|
public void testTooLargeIndexForDictionaryThrowsFormatException()
|
||||||
@@ -287,6 +369,13 @@ public class BdfListTest extends BrambleTestCase {
|
|||||||
throws Exception {
|
throws Exception {
|
||||||
new BdfList().getOptionalDictionary(0);
|
new BdfList().getOptionalDictionary(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test(expected = FormatException.class)
|
||||||
|
public void testTooLargeIndexForDefaultDictionaryThrowsFormatException()
|
||||||
|
throws Exception {
|
||||||
|
new BdfList().getDictionary(0, new BdfDictionary());
|
||||||
|
}
|
||||||
|
|
||||||
@Test(expected = FormatException.class)
|
@Test(expected = FormatException.class)
|
||||||
public void testWrongTypeForBooleanThrowsFormatException()
|
public void testWrongTypeForBooleanThrowsFormatException()
|
||||||
throws Exception {
|
throws Exception {
|
||||||
@@ -299,6 +388,12 @@ public class BdfListTest extends BrambleTestCase {
|
|||||||
BdfList.of(123).getOptionalBoolean(0);
|
BdfList.of(123).getOptionalBoolean(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test(expected = FormatException.class)
|
||||||
|
public void testWrongTypeForDefaultBooleanThrowsFormatException()
|
||||||
|
throws Exception {
|
||||||
|
BdfList.of(123).getBoolean(0, true);
|
||||||
|
}
|
||||||
|
|
||||||
@Test(expected = FormatException.class)
|
@Test(expected = FormatException.class)
|
||||||
public void testWrongTypeForLongThrowsFormatException() throws Exception {
|
public void testWrongTypeForLongThrowsFormatException() throws Exception {
|
||||||
BdfList.of(1.23).getLong(0);
|
BdfList.of(1.23).getLong(0);
|
||||||
@@ -310,6 +405,29 @@ public class BdfListTest extends BrambleTestCase {
|
|||||||
BdfList.of(1.23).getOptionalLong(0);
|
BdfList.of(1.23).getOptionalLong(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test(expected = FormatException.class)
|
||||||
|
public void testWrongTypeForDefaultLongThrowsFormatException()
|
||||||
|
throws Exception {
|
||||||
|
BdfList.of(1.23).getLong(0, 1L);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expected = FormatException.class)
|
||||||
|
public void testWrongTypeForIntThrowsFormatException() throws Exception {
|
||||||
|
BdfList.of(1.23).getInt(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expected = FormatException.class)
|
||||||
|
public void testWrongTypeForOptionalIntThrowsFormatException()
|
||||||
|
throws Exception {
|
||||||
|
BdfList.of(1.23).getOptionalInt(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expected = FormatException.class)
|
||||||
|
public void testWrongTypeForDefaultIntThrowsFormatException()
|
||||||
|
throws Exception {
|
||||||
|
BdfList.of(1.23).getInt(0, 1);
|
||||||
|
}
|
||||||
|
|
||||||
@Test(expected = FormatException.class)
|
@Test(expected = FormatException.class)
|
||||||
public void testWrongTypeForDoubleThrowsFormatException() throws Exception {
|
public void testWrongTypeForDoubleThrowsFormatException() throws Exception {
|
||||||
BdfList.of(123).getDouble(0);
|
BdfList.of(123).getDouble(0);
|
||||||
@@ -321,6 +439,12 @@ public class BdfListTest extends BrambleTestCase {
|
|||||||
BdfList.of(123).getOptionalDouble(0);
|
BdfList.of(123).getOptionalDouble(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test(expected = FormatException.class)
|
||||||
|
public void testWrongTypeForDefaultDoubleThrowsFormatException()
|
||||||
|
throws Exception {
|
||||||
|
BdfList.of(123).getDouble(0, 1D);
|
||||||
|
}
|
||||||
|
|
||||||
@Test(expected = FormatException.class)
|
@Test(expected = FormatException.class)
|
||||||
public void testWrongTypeForStringThrowsFormatException() throws Exception {
|
public void testWrongTypeForStringThrowsFormatException() throws Exception {
|
||||||
BdfList.of(123).getString(0);
|
BdfList.of(123).getString(0);
|
||||||
@@ -332,6 +456,12 @@ public class BdfListTest extends BrambleTestCase {
|
|||||||
BdfList.of(123).getOptionalString(0);
|
BdfList.of(123).getOptionalString(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test(expected = FormatException.class)
|
||||||
|
public void testWrongTypeForDefaultStringThrowsFormatException()
|
||||||
|
throws Exception {
|
||||||
|
BdfList.of(123).getString(0, "");
|
||||||
|
}
|
||||||
|
|
||||||
@Test(expected = FormatException.class)
|
@Test(expected = FormatException.class)
|
||||||
public void testWrongTypeForRawThrowsFormatException() throws Exception {
|
public void testWrongTypeForRawThrowsFormatException() throws Exception {
|
||||||
BdfList.of(123).getRaw(0);
|
BdfList.of(123).getRaw(0);
|
||||||
@@ -343,6 +473,12 @@ public class BdfListTest extends BrambleTestCase {
|
|||||||
BdfList.of(123).getOptionalRaw(0);
|
BdfList.of(123).getOptionalRaw(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test(expected = FormatException.class)
|
||||||
|
public void testWrongTypeForDefaultRawThrowsFormatException()
|
||||||
|
throws Exception {
|
||||||
|
BdfList.of(123).getRaw(0, new byte[0]);
|
||||||
|
}
|
||||||
|
|
||||||
@Test(expected = FormatException.class)
|
@Test(expected = FormatException.class)
|
||||||
public void testWrongTypeForListThrowsFormatException() throws Exception {
|
public void testWrongTypeForListThrowsFormatException() throws Exception {
|
||||||
BdfList.of(123).getList(0);
|
BdfList.of(123).getList(0);
|
||||||
@@ -354,6 +490,11 @@ public class BdfListTest extends BrambleTestCase {
|
|||||||
BdfList.of(123).getOptionalList(0);
|
BdfList.of(123).getOptionalList(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test(expected = FormatException.class)
|
||||||
|
public void testWrongTypeForDefaultListThrowsFormatException()
|
||||||
|
throws Exception {
|
||||||
|
BdfList.of(123).getList(0, new BdfList());
|
||||||
|
}
|
||||||
|
|
||||||
@Test(expected = FormatException.class)
|
@Test(expected = FormatException.class)
|
||||||
public void testWrongTypeForDictionaryThrowsFormatException()
|
public void testWrongTypeForDictionaryThrowsFormatException()
|
||||||
@@ -366,4 +507,81 @@ public class BdfListTest extends BrambleTestCase {
|
|||||||
throws Exception {
|
throws Exception {
|
||||||
BdfList.of(123).getOptionalDictionary(0);
|
BdfList.of(123).getOptionalDictionary(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test(expected = FormatException.class)
|
||||||
|
public void testWrongTypeForDefaultDictionaryThrowsFormatException()
|
||||||
|
throws Exception {
|
||||||
|
BdfList.of(123).getDictionary(0, new BdfDictionary());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expected = FormatException.class)
|
||||||
|
public void testNullValueForBooleanThrowsFormatException()
|
||||||
|
throws Exception {
|
||||||
|
BdfList.of(NULL_VALUE).getBoolean(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expected = FormatException.class)
|
||||||
|
public void testNullValueForLongThrowsFormatException() throws Exception {
|
||||||
|
BdfList.of(NULL_VALUE).getLong(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expected = FormatException.class)
|
||||||
|
public void testNullValueForIntThrowsFormatException() throws Exception {
|
||||||
|
BdfList.of(NULL_VALUE).getInt(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expected = FormatException.class)
|
||||||
|
public void testNullValueForDoubleThrowsFormatException() throws Exception {
|
||||||
|
BdfList.of(NULL_VALUE).getDouble(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expected = FormatException.class)
|
||||||
|
public void testNullValueForStringThrowsFormatException() throws Exception {
|
||||||
|
BdfList.of(NULL_VALUE).getString(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expected = FormatException.class)
|
||||||
|
public void testNullValueForRawThrowsFormatException() throws Exception {
|
||||||
|
BdfList.of(NULL_VALUE).getRaw(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expected = FormatException.class)
|
||||||
|
public void testNullValueForListThrowsFormatException() throws Exception {
|
||||||
|
BdfList.of(NULL_VALUE).getList(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expected = FormatException.class)
|
||||||
|
public void testNullValueForDictionaryThrowsFormatException()
|
||||||
|
throws Exception {
|
||||||
|
BdfList.of(NULL_VALUE).getDictionary(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testOptionalMethodsReturnNullForNullValue() throws Exception {
|
||||||
|
BdfList list = BdfList.of(NULL_VALUE);
|
||||||
|
assertNull(list.getOptionalBoolean(0));
|
||||||
|
assertNull(list.getOptionalLong(0));
|
||||||
|
assertNull(list.getOptionalInt(0));
|
||||||
|
assertNull(list.getOptionalDouble(0));
|
||||||
|
assertNull(list.getOptionalString(0));
|
||||||
|
assertNull(list.getOptionalRaw(0));
|
||||||
|
assertNull(list.getOptionalList(0));
|
||||||
|
assertNull(list.getOptionalDictionary(0));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testDefaultMethodsReturnDefaultForNullValue() throws Exception {
|
||||||
|
BdfList list = BdfList.of(NULL_VALUE);
|
||||||
|
assertEquals(TRUE, list.getBoolean(0, TRUE));
|
||||||
|
assertEquals(Long.valueOf(123L), list.getLong(0, 123L));
|
||||||
|
assertEquals(Integer.valueOf(123), list.getInt(0, 123));
|
||||||
|
assertEquals(Double.valueOf(123D), list.getDouble(0, 123D));
|
||||||
|
assertEquals("123", list.getString(0, "123"));
|
||||||
|
byte[] defaultRaw = {1, 2, 3};
|
||||||
|
assertArrayEquals(defaultRaw, list.getRaw(0, defaultRaw));
|
||||||
|
BdfList defaultList = BdfList.of(1, 2, 3);
|
||||||
|
assertEquals(defaultList, list.getList(0, defaultList));
|
||||||
|
BdfDictionary defaultDict = BdfDictionary.of(new BdfEntry("123", 123));
|
||||||
|
assertEquals(defaultDict, list.getDictionary(0, defaultDict));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -33,7 +33,7 @@ dependencies {
|
|||||||
testImplementation "org.jmock:jmock:$jmock_version"
|
testImplementation "org.jmock:jmock:$jmock_version"
|
||||||
testImplementation "org.jmock:jmock-junit4:$jmock_version"
|
testImplementation "org.jmock:jmock-junit4:$jmock_version"
|
||||||
testImplementation "org.jmock:jmock-imposters:$jmock_version"
|
testImplementation "org.jmock:jmock-imposters:$jmock_version"
|
||||||
testImplementation "com.squareup.okhttp3:mockwebserver:4.9.3"
|
testImplementation "com.squareup.okhttp3:mockwebserver:$mockwebserver_version"
|
||||||
|
|
||||||
testAnnotationProcessor "com.google.dagger:dagger-compiler:$dagger_version"
|
testAnnotationProcessor "com.google.dagger:dagger-compiler:$dagger_version"
|
||||||
|
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ import org.briarproject.bramble.lifecycle.LifecycleModule;
|
|||||||
import org.briarproject.bramble.mailbox.MailboxModule;
|
import org.briarproject.bramble.mailbox.MailboxModule;
|
||||||
import org.briarproject.bramble.plugin.PluginModule;
|
import org.briarproject.bramble.plugin.PluginModule;
|
||||||
import org.briarproject.bramble.properties.PropertiesModule;
|
import org.briarproject.bramble.properties.PropertiesModule;
|
||||||
|
import org.briarproject.bramble.qrcode.QrCodeModule;
|
||||||
import org.briarproject.bramble.record.RecordModule;
|
import org.briarproject.bramble.record.RecordModule;
|
||||||
import org.briarproject.bramble.reliability.ReliabilityModule;
|
import org.briarproject.bramble.reliability.ReliabilityModule;
|
||||||
import org.briarproject.bramble.rendezvous.RendezvousModule;
|
import org.briarproject.bramble.rendezvous.RendezvousModule;
|
||||||
@@ -47,6 +48,7 @@ import dagger.Module;
|
|||||||
MailboxModule.class,
|
MailboxModule.class,
|
||||||
PluginModule.class,
|
PluginModule.class,
|
||||||
PropertiesModule.class,
|
PropertiesModule.class,
|
||||||
|
QrCodeModule.class,
|
||||||
RecordModule.class,
|
RecordModule.class,
|
||||||
ReliabilityModule.class,
|
ReliabilityModule.class,
|
||||||
RendezvousModule.class,
|
RendezvousModule.class,
|
||||||
|
|||||||
@@ -19,7 +19,6 @@ import java.io.FileInputStream;
|
|||||||
import java.io.FileOutputStream;
|
import java.io.FileOutputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStreamReader;
|
import java.io.InputStreamReader;
|
||||||
import java.nio.charset.Charset;
|
|
||||||
import java.util.logging.Logger;
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
@@ -29,6 +28,7 @@ import javax.inject.Inject;
|
|||||||
import static java.util.logging.Level.WARNING;
|
import static java.util.logging.Level.WARNING;
|
||||||
import static org.briarproject.bramble.api.crypto.DecryptionResult.INVALID_CIPHERTEXT;
|
import static org.briarproject.bramble.api.crypto.DecryptionResult.INVALID_CIPHERTEXT;
|
||||||
import static org.briarproject.bramble.util.LogUtils.logException;
|
import static org.briarproject.bramble.util.LogUtils.logException;
|
||||||
|
import static org.briarproject.bramble.util.StringUtils.UTF_8;
|
||||||
import static org.briarproject.bramble.util.StringUtils.fromHexString;
|
import static org.briarproject.bramble.util.StringUtils.fromHexString;
|
||||||
import static org.briarproject.bramble.util.StringUtils.toHexString;
|
import static org.briarproject.bramble.util.StringUtils.toHexString;
|
||||||
|
|
||||||
@@ -99,7 +99,7 @@ class AccountManagerImpl implements AccountManager {
|
|||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
BufferedReader reader = new BufferedReader(new InputStreamReader(
|
BufferedReader reader = new BufferedReader(new InputStreamReader(
|
||||||
new FileInputStream(f), Charset.forName("UTF-8")));
|
new FileInputStream(f), UTF_8));
|
||||||
String key = reader.readLine();
|
String key = reader.readLine();
|
||||||
reader.close();
|
reader.close();
|
||||||
return key;
|
return key;
|
||||||
@@ -151,7 +151,7 @@ class AccountManagerImpl implements AccountManager {
|
|||||||
@GuardedBy("stateChangeLock")
|
@GuardedBy("stateChangeLock")
|
||||||
private void writeDbKeyToFile(String key, File f) throws IOException {
|
private void writeDbKeyToFile(String key, File f) throws IOException {
|
||||||
FileOutputStream out = new FileOutputStream(f);
|
FileOutputStream out = new FileOutputStream(f);
|
||||||
out.write(key.getBytes(Charset.forName("UTF-8")));
|
out.write(key.getBytes(UTF_8));
|
||||||
out.flush();
|
out.flush();
|
||||||
out.close();
|
out.close();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -155,7 +155,13 @@ class ClientHelperImpl implements ClientHelper {
|
|||||||
@Override
|
@Override
|
||||||
public BdfList getMessageAsList(Transaction txn, MessageId m)
|
public BdfList getMessageAsList(Transaction txn, MessageId m)
|
||||||
throws DbException, FormatException {
|
throws DbException, FormatException {
|
||||||
return toList(db.getMessage(txn, m).getBody());
|
return getMessageAsList(txn, m, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BdfList getMessageAsList(Transaction txn, MessageId m,
|
||||||
|
boolean canonical) throws DbException, FormatException {
|
||||||
|
return toList(db.getMessage(txn, m), canonical);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -313,8 +319,13 @@ class ClientHelperImpl implements ClientHelper {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public BdfList toList(byte[] b, int off, int len) throws FormatException {
|
public BdfList toList(byte[] b, int off, int len) throws FormatException {
|
||||||
|
return toList(b, off, len, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
private BdfList toList(byte[] b, int off, int len, boolean canonical)
|
||||||
|
throws FormatException {
|
||||||
ByteArrayInputStream in = new ByteArrayInputStream(b, off, len);
|
ByteArrayInputStream in = new ByteArrayInputStream(b, off, len);
|
||||||
BdfReader reader = bdfReaderFactory.createReader(in);
|
BdfReader reader = bdfReaderFactory.createReader(in, canonical);
|
||||||
try {
|
try {
|
||||||
BdfList list = reader.readList();
|
BdfList list = reader.readList();
|
||||||
if (!reader.eof()) throw new FormatException();
|
if (!reader.eof()) throw new FormatException();
|
||||||
@@ -328,7 +339,7 @@ class ClientHelperImpl implements ClientHelper {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public BdfList toList(byte[] b) throws FormatException {
|
public BdfList toList(byte[] b) throws FormatException {
|
||||||
return toList(b, 0, b.length);
|
return toList(b, 0, b.length, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -336,6 +347,12 @@ class ClientHelperImpl implements ClientHelper {
|
|||||||
return toList(m.getBody());
|
return toList(m.getBody());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BdfList toList(Message m, boolean canonical) throws FormatException {
|
||||||
|
byte[] b = m.getBody();
|
||||||
|
return toList(b, 0, b.length, canonical);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public BdfList toList(Author a) {
|
public BdfList toList(Author a) {
|
||||||
return BdfList.of(a.getFormatVersion(), a.getName(), a.getPublicKey());
|
return BdfList.of(a.getFormatVersion(), a.getName(), a.getPublicKey());
|
||||||
@@ -361,7 +378,7 @@ class ClientHelperImpl implements ClientHelper {
|
|||||||
public Author parseAndValidateAuthor(BdfList author)
|
public Author parseAndValidateAuthor(BdfList author)
|
||||||
throws FormatException {
|
throws FormatException {
|
||||||
checkSize(author, 3);
|
checkSize(author, 3);
|
||||||
int formatVersion = author.getLong(0).intValue();
|
int formatVersion = author.getInt(0);
|
||||||
if (formatVersion != FORMAT_VERSION) throw new FormatException();
|
if (formatVersion != FORMAT_VERSION) throw new FormatException();
|
||||||
String name = author.getString(1);
|
String name = author.getString(1);
|
||||||
checkLength(name, 1, MAX_AUTHOR_NAME_LENGTH);
|
checkLength(name, 1, MAX_AUTHOR_NAME_LENGTH);
|
||||||
@@ -472,8 +489,7 @@ class ClientHelperImpl implements ClientHelper {
|
|||||||
if (element.size() != 2) {
|
if (element.size() != 2) {
|
||||||
throw new FormatException();
|
throw new FormatException();
|
||||||
}
|
}
|
||||||
list.add(new MailboxVersion(element.getLong(0).intValue(),
|
list.add(new MailboxVersion(element.getInt(0), element.getInt(1)));
|
||||||
element.getLong(1).intValue()));
|
|
||||||
}
|
}
|
||||||
// Sort the list of versions for easier comparison
|
// Sort the list of versions for easier comparison
|
||||||
sort(list);
|
sort(list);
|
||||||
@@ -486,7 +502,7 @@ class ClientHelperImpl implements ClientHelper {
|
|||||||
try {
|
try {
|
||||||
BdfDictionary meta =
|
BdfDictionary meta =
|
||||||
getGroupMetadataAsDictionary(txn, contactGroupId);
|
getGroupMetadataAsDictionary(txn, contactGroupId);
|
||||||
return new ContactId(meta.getLong(GROUP_KEY_CONTACT_ID).intValue());
|
return new ContactId(meta.getInt(GROUP_KEY_CONTACT_ID));
|
||||||
} catch (FormatException e) {
|
} catch (FormatException e) {
|
||||||
throw new DbException(e); // Invalid group metadata
|
throw new DbException(e); // Invalid group metadata
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -29,7 +29,6 @@ import org.briarproject.nullsafety.NotNullByDefault;
|
|||||||
import org.whispersystems.curve25519.Curve25519;
|
import org.whispersystems.curve25519.Curve25519;
|
||||||
import org.whispersystems.curve25519.Curve25519KeyPair;
|
import org.whispersystems.curve25519.Curve25519KeyPair;
|
||||||
|
|
||||||
import java.nio.charset.Charset;
|
|
||||||
import java.security.GeneralSecurityException;
|
import java.security.GeneralSecurityException;
|
||||||
import java.security.NoSuchAlgorithmException;
|
import java.security.NoSuchAlgorithmException;
|
||||||
import java.security.Provider;
|
import java.security.Provider;
|
||||||
@@ -51,6 +50,7 @@ import static org.briarproject.bramble.api.crypto.DecryptionResult.KEY_STRENGTHE
|
|||||||
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.LogUtils.logDuration;
|
import static org.briarproject.bramble.util.LogUtils.logDuration;
|
||||||
import static org.briarproject.bramble.util.LogUtils.now;
|
import static org.briarproject.bramble.util.LogUtils.now;
|
||||||
|
import static org.briarproject.bramble.util.StringUtils.US_ASCII;
|
||||||
|
|
||||||
@NotNullByDefault
|
@NotNullByDefault
|
||||||
class CryptoComponentImpl implements CryptoComponent {
|
class CryptoComponentImpl implements CryptoComponent {
|
||||||
@@ -460,7 +460,7 @@ class CryptoComponentImpl implements CryptoComponent {
|
|||||||
@Override
|
@Override
|
||||||
public String encodeOnion(byte[] publicKey) {
|
public String encodeOnion(byte[] publicKey) {
|
||||||
Digest digest = new SHA3Digest(256);
|
Digest digest = new SHA3Digest(256);
|
||||||
byte[] label = ".onion checksum".getBytes(Charset.forName("US-ASCII"));
|
byte[] label = ".onion checksum".getBytes(US_ASCII);
|
||||||
digest.update(label, 0, label.length);
|
digest.update(label, 0, label.length);
|
||||||
digest.update(publicKey, 0, publicKey.length);
|
digest.update(publicKey, 0, publicKey.length);
|
||||||
digest.update(ONION_HS_PROTOCOL_VERSION);
|
digest.update(ONION_HS_PROTOCOL_VERSION);
|
||||||
|
|||||||
@@ -39,12 +39,13 @@ import java.io.FileOutputStream;
|
|||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.io.PrintStream;
|
import java.io.PrintStream;
|
||||||
import java.nio.charset.Charset;
|
|
||||||
import java.security.SecureRandom;
|
import java.security.SecureRandom;
|
||||||
import java.util.Scanner;
|
import java.util.Scanner;
|
||||||
|
|
||||||
import javax.annotation.concurrent.Immutable;
|
import javax.annotation.concurrent.Immutable;
|
||||||
|
|
||||||
|
import static org.briarproject.bramble.util.StringUtils.UTF_8;
|
||||||
|
|
||||||
@Immutable
|
@Immutable
|
||||||
@NotNullByDefault
|
@NotNullByDefault
|
||||||
public class MessageEncrypter {
|
public class MessageEncrypter {
|
||||||
@@ -228,7 +229,7 @@ public class MessageEncrypter {
|
|||||||
PublicKey publicKey =
|
PublicKey publicKey =
|
||||||
encrypter.getKeyParser().parsePublicKey(keyBytes);
|
encrypter.getKeyParser().parsePublicKey(keyBytes);
|
||||||
String message = readFully(System.in);
|
String message = readFully(System.in);
|
||||||
byte[] plaintext = message.getBytes(Charset.forName("UTF-8"));
|
byte[] plaintext = message.getBytes(UTF_8);
|
||||||
byte[] ciphertext = encrypter.encrypt(publicKey, plaintext);
|
byte[] ciphertext = encrypter.encrypt(publicKey, plaintext);
|
||||||
System.out.println(AsciiArmour.wrap(ciphertext, LINE_LENGTH));
|
System.out.println(AsciiArmour.wrap(ciphertext, LINE_LENGTH));
|
||||||
}
|
}
|
||||||
@@ -242,7 +243,7 @@ public class MessageEncrypter {
|
|||||||
encrypter.getKeyParser().parsePrivateKey(keyBytes);
|
encrypter.getKeyParser().parsePrivateKey(keyBytes);
|
||||||
byte[] ciphertext = AsciiArmour.unwrap(readFully(System.in));
|
byte[] ciphertext = AsciiArmour.unwrap(readFully(System.in));
|
||||||
byte[] plaintext = encrypter.decrypt(privateKey, ciphertext);
|
byte[] plaintext = encrypter.decrypt(privateKey, ciphertext);
|
||||||
System.out.println(new String(plaintext, Charset.forName("UTF-8")));
|
System.out.println(new String(plaintext, UTF_8));
|
||||||
}
|
}
|
||||||
|
|
||||||
private static String readFully(InputStream in) throws IOException {
|
private static String readFully(InputStream in) throws IOException {
|
||||||
|
|||||||
@@ -18,12 +18,18 @@ class BdfReaderFactoryImpl implements BdfReaderFactory {
|
|||||||
@Override
|
@Override
|
||||||
public BdfReader createReader(InputStream in) {
|
public BdfReader createReader(InputStream in) {
|
||||||
return new BdfReaderImpl(in, DEFAULT_NESTED_LIMIT,
|
return new BdfReaderImpl(in, DEFAULT_NESTED_LIMIT,
|
||||||
DEFAULT_MAX_BUFFER_SIZE);
|
DEFAULT_MAX_BUFFER_SIZE, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BdfReader createReader(InputStream in, boolean canonical) {
|
||||||
|
return new BdfReaderImpl(in, DEFAULT_NESTED_LIMIT,
|
||||||
|
DEFAULT_MAX_BUFFER_SIZE, canonical);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public BdfReader createReader(InputStream in, int nestedLimit,
|
public BdfReader createReader(InputStream in, int nestedLimit,
|
||||||
int maxBufferSize) {
|
int maxBufferSize, boolean canonical) {
|
||||||
return new BdfReaderImpl(in, nestedLimit, maxBufferSize);
|
return new BdfReaderImpl(in, nestedLimit, maxBufferSize, canonical);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -33,21 +33,24 @@ import static org.briarproject.bramble.util.StringUtils.fromUtf8;
|
|||||||
|
|
||||||
@NotThreadSafe
|
@NotThreadSafe
|
||||||
@NotNullByDefault
|
@NotNullByDefault
|
||||||
class BdfReaderImpl implements BdfReader {
|
final class BdfReaderImpl implements BdfReader {
|
||||||
|
|
||||||
private static final byte[] EMPTY_BUFFER = new byte[0];
|
private static final byte[] EMPTY_BUFFER = new byte[0];
|
||||||
|
|
||||||
private final InputStream in;
|
private final InputStream in;
|
||||||
private final int nestedLimit, maxBufferSize;
|
private final int nestedLimit, maxBufferSize;
|
||||||
|
private final boolean canonical;
|
||||||
|
|
||||||
private boolean hasLookahead = false, eof = false;
|
private boolean hasLookahead = false, eof = false;
|
||||||
private byte next;
|
private byte next;
|
||||||
private byte[] buf = new byte[8];
|
private byte[] buf = new byte[8];
|
||||||
|
|
||||||
BdfReaderImpl(InputStream in, int nestedLimit, int maxBufferSize) {
|
BdfReaderImpl(InputStream in, int nestedLimit, int maxBufferSize,
|
||||||
|
boolean canonical) {
|
||||||
this.in = in;
|
this.in = in;
|
||||||
this.nestedLimit = nestedLimit;
|
this.nestedLimit = nestedLimit;
|
||||||
this.maxBufferSize = maxBufferSize;
|
this.maxBufferSize = maxBufferSize;
|
||||||
|
this.canonical = canonical;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void readLookahead() throws IOException {
|
private void readLookahead() throws IOException {
|
||||||
@@ -188,13 +191,22 @@ class BdfReaderImpl implements BdfReader {
|
|||||||
|
|
||||||
private short readInt16() throws IOException {
|
private short readInt16() throws IOException {
|
||||||
readIntoBuffer(2);
|
readIntoBuffer(2);
|
||||||
return (short) (((buf[0] & 0xFF) << 8) + (buf[1] & 0xFF));
|
short value = (short) (((buf[0] & 0xFF) << 8) + (buf[1] & 0xFF));
|
||||||
|
if (canonical && value >= Byte.MIN_VALUE && value <= Byte.MAX_VALUE) {
|
||||||
|
// Value could have been encoded as an INT_8
|
||||||
|
throw new FormatException();
|
||||||
|
}
|
||||||
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
private int readInt32() throws IOException {
|
private int readInt32() throws IOException {
|
||||||
readIntoBuffer(4);
|
readIntoBuffer(4);
|
||||||
int value = 0;
|
int value = 0;
|
||||||
for (int i = 0; i < 4; i++) value |= (buf[i] & 0xFF) << (24 - i * 8);
|
for (int i = 0; i < 4; i++) value |= (buf[i] & 0xFF) << (24 - i * 8);
|
||||||
|
if (canonical && value >= Short.MIN_VALUE && value <= Short.MAX_VALUE) {
|
||||||
|
// Value could have been encoded as an INT_16
|
||||||
|
throw new FormatException();
|
||||||
|
}
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -202,6 +214,11 @@ class BdfReaderImpl implements BdfReader {
|
|||||||
readIntoBuffer(8);
|
readIntoBuffer(8);
|
||||||
long value = 0;
|
long value = 0;
|
||||||
for (int i = 0; i < 8; i++) value |= (buf[i] & 0xFFL) << (56 - i * 8);
|
for (int i = 0; i < 8; i++) value |= (buf[i] & 0xFFL) << (56 - i * 8);
|
||||||
|
if (canonical && value >= Integer.MIN_VALUE &&
|
||||||
|
value <= Integer.MAX_VALUE) {
|
||||||
|
// Value could have been encoded as an INT_32
|
||||||
|
throw new FormatException();
|
||||||
|
}
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -215,6 +232,31 @@ class BdfReaderImpl implements BdfReader {
|
|||||||
hasLookahead = false;
|
hasLookahead = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean hasInt() throws IOException {
|
||||||
|
if (!hasLookahead) readLookahead();
|
||||||
|
if (eof) return false;
|
||||||
|
return next == INT_8 || next == INT_16 || next == INT_32;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int readInt() throws IOException {
|
||||||
|
if (!hasInt()) throw new FormatException();
|
||||||
|
hasLookahead = false;
|
||||||
|
if (next == INT_8) return readInt8();
|
||||||
|
if (next == INT_16) return readInt16();
|
||||||
|
return readInt32();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void skipInt() throws IOException {
|
||||||
|
if (!hasInt()) throw new FormatException();
|
||||||
|
if (next == INT_8) skip(1);
|
||||||
|
else if (next == INT_16) skip(2);
|
||||||
|
else skip(4);
|
||||||
|
hasLookahead = false;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean hasDouble() throws IOException {
|
public boolean hasDouble() throws IOException {
|
||||||
if (!hasLookahead) readLookahead();
|
if (!hasLookahead) readLookahead();
|
||||||
@@ -323,22 +365,11 @@ class BdfReaderImpl implements BdfReader {
|
|||||||
private BdfList readList(int level) throws IOException {
|
private BdfList readList(int level) throws IOException {
|
||||||
if (!hasList()) throw new FormatException();
|
if (!hasList()) throw new FormatException();
|
||||||
if (level > nestedLimit) throw new FormatException();
|
if (level > nestedLimit) throw new FormatException();
|
||||||
BdfList list = new BdfList();
|
|
||||||
readListStart();
|
|
||||||
while (!hasListEnd()) list.add(readObject(level + 1));
|
|
||||||
readListEnd();
|
|
||||||
return list;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void readListStart() throws IOException {
|
|
||||||
if (!hasList()) throw new FormatException();
|
|
||||||
hasLookahead = false;
|
hasLookahead = false;
|
||||||
}
|
BdfList list = new BdfList();
|
||||||
|
while (!hasEnd()) list.add(readObject(level + 1));
|
||||||
@Override
|
readEnd();
|
||||||
public boolean hasListEnd() throws IOException {
|
return list;
|
||||||
return hasEnd();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean hasEnd() throws IOException {
|
private boolean hasEnd() throws IOException {
|
||||||
@@ -347,11 +378,6 @@ class BdfReaderImpl implements BdfReader {
|
|||||||
return next == END;
|
return next == END;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void readListEnd() throws IOException {
|
|
||||||
readEnd();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void readEnd() throws IOException {
|
private void readEnd() throws IOException {
|
||||||
if (!hasEnd()) throw new FormatException();
|
if (!hasEnd()) throw new FormatException();
|
||||||
hasLookahead = false;
|
hasLookahead = false;
|
||||||
@@ -361,7 +387,7 @@ class BdfReaderImpl implements BdfReader {
|
|||||||
public void skipList() throws IOException {
|
public void skipList() throws IOException {
|
||||||
if (!hasList()) throw new FormatException();
|
if (!hasList()) throw new FormatException();
|
||||||
hasLookahead = false;
|
hasLookahead = false;
|
||||||
while (!hasListEnd()) skipObject();
|
while (!hasEnd()) skipObject();
|
||||||
hasLookahead = false;
|
hasLookahead = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -380,35 +406,27 @@ class BdfReaderImpl implements BdfReader {
|
|||||||
private BdfDictionary readDictionary(int level) throws IOException {
|
private BdfDictionary readDictionary(int level) throws IOException {
|
||||||
if (!hasDictionary()) throw new FormatException();
|
if (!hasDictionary()) throw new FormatException();
|
||||||
if (level > nestedLimit) throw new FormatException();
|
if (level > nestedLimit) throw new FormatException();
|
||||||
BdfDictionary dictionary = new BdfDictionary();
|
|
||||||
readDictionaryStart();
|
|
||||||
while (!hasDictionaryEnd())
|
|
||||||
dictionary.put(readString(), readObject(level + 1));
|
|
||||||
readDictionaryEnd();
|
|
||||||
return dictionary;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void readDictionaryStart() throws IOException {
|
|
||||||
if (!hasDictionary()) throw new FormatException();
|
|
||||||
hasLookahead = false;
|
hasLookahead = false;
|
||||||
}
|
BdfDictionary dictionary = new BdfDictionary();
|
||||||
|
String prevKey = null;
|
||||||
@Override
|
while (!hasEnd()) {
|
||||||
public boolean hasDictionaryEnd() throws IOException {
|
String key = readString();
|
||||||
return hasEnd();
|
if (canonical && prevKey != null && key.compareTo(prevKey) <= 0) {
|
||||||
}
|
// Keys not unique and sorted
|
||||||
|
throw new FormatException();
|
||||||
@Override
|
}
|
||||||
public void readDictionaryEnd() throws IOException {
|
dictionary.put(key, readObject(level + 1));
|
||||||
|
prevKey = key;
|
||||||
|
}
|
||||||
readEnd();
|
readEnd();
|
||||||
|
return dictionary;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void skipDictionary() throws IOException {
|
public void skipDictionary() throws IOException {
|
||||||
if (!hasDictionary()) throw new FormatException();
|
if (!hasDictionary()) throw new FormatException();
|
||||||
hasLookahead = false;
|
hasLookahead = false;
|
||||||
while (!hasDictionaryEnd()) {
|
while (!hasEnd()) {
|
||||||
skipString();
|
skipString();
|
||||||
skipObject();
|
skipObject();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,11 +2,13 @@ package org.briarproject.bramble.data;
|
|||||||
|
|
||||||
import org.briarproject.bramble.api.Bytes;
|
import org.briarproject.bramble.api.Bytes;
|
||||||
import org.briarproject.bramble.api.FormatException;
|
import org.briarproject.bramble.api.FormatException;
|
||||||
|
import org.briarproject.bramble.api.data.BdfDictionary;
|
||||||
import org.briarproject.bramble.api.data.BdfWriter;
|
import org.briarproject.bramble.api.data.BdfWriter;
|
||||||
import org.briarproject.nullsafety.NotNullByDefault;
|
import org.briarproject.nullsafety.NotNullByDefault;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.OutputStream;
|
import java.io.OutputStream;
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
@@ -15,6 +17,7 @@ import java.util.Map.Entry;
|
|||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
import javax.annotation.concurrent.NotThreadSafe;
|
import javax.annotation.concurrent.NotThreadSafe;
|
||||||
|
|
||||||
|
import static java.util.Collections.sort;
|
||||||
import static org.briarproject.bramble.api.data.BdfDictionary.NULL_VALUE;
|
import static org.briarproject.bramble.api.data.BdfDictionary.NULL_VALUE;
|
||||||
import static org.briarproject.bramble.data.Types.DICTIONARY;
|
import static org.briarproject.bramble.data.Types.DICTIONARY;
|
||||||
import static org.briarproject.bramble.data.Types.END;
|
import static org.briarproject.bramble.data.Types.END;
|
||||||
@@ -33,10 +36,11 @@ import static org.briarproject.bramble.data.Types.STRING_16;
|
|||||||
import static org.briarproject.bramble.data.Types.STRING_32;
|
import static org.briarproject.bramble.data.Types.STRING_32;
|
||||||
import static org.briarproject.bramble.data.Types.STRING_8;
|
import static org.briarproject.bramble.data.Types.STRING_8;
|
||||||
import static org.briarproject.bramble.data.Types.TRUE;
|
import static org.briarproject.bramble.data.Types.TRUE;
|
||||||
|
import static org.briarproject.bramble.util.StringUtils.UTF_8;
|
||||||
|
|
||||||
@NotThreadSafe
|
@NotThreadSafe
|
||||||
@NotNullByDefault
|
@NotNullByDefault
|
||||||
class BdfWriterImpl implements BdfWriter {
|
final class BdfWriterImpl implements BdfWriter {
|
||||||
|
|
||||||
private final OutputStream out;
|
private final OutputStream out;
|
||||||
|
|
||||||
@@ -113,7 +117,7 @@ class BdfWriterImpl implements BdfWriter {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void writeString(String s) throws IOException {
|
public void writeString(String s) throws IOException {
|
||||||
byte[] b = s.getBytes("UTF-8");
|
byte[] b = s.getBytes(UTF_8);
|
||||||
if (b.length <= Byte.MAX_VALUE) {
|
if (b.length <= Byte.MAX_VALUE) {
|
||||||
out.write(STRING_8);
|
out.write(STRING_8);
|
||||||
out.write((byte) b.length);
|
out.write((byte) b.length);
|
||||||
@@ -161,39 +165,33 @@ class BdfWriterImpl implements BdfWriter {
|
|||||||
else if (o instanceof String) writeString((String) o);
|
else if (o instanceof String) writeString((String) o);
|
||||||
else if (o instanceof byte[]) writeRaw((byte[]) o);
|
else if (o instanceof byte[]) writeRaw((byte[]) o);
|
||||||
else if (o instanceof Bytes) writeRaw(((Bytes) o).getBytes());
|
else if (o instanceof Bytes) writeRaw(((Bytes) o).getBytes());
|
||||||
else if (o instanceof List) writeList((List) o);
|
else if (o instanceof List) writeList((List<?>) o);
|
||||||
else if (o instanceof Map) writeDictionary((Map) o);
|
else if (o instanceof Map) writeDictionary((Map<?, ?>) o);
|
||||||
else throw new FormatException();
|
else throw new FormatException();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void writeListStart() throws IOException {
|
|
||||||
out.write(LIST);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void writeListEnd() throws IOException {
|
|
||||||
out.write(END);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void writeDictionary(Map<?, ?> m) throws IOException {
|
public void writeDictionary(Map<?, ?> m) throws IOException {
|
||||||
out.write(DICTIONARY);
|
out.write(DICTIONARY);
|
||||||
for (Entry<?, ?> e : m.entrySet()) {
|
if (m instanceof BdfDictionary) {
|
||||||
if (!(e.getKey() instanceof String)) throw new FormatException();
|
// Entries are already sorted and keys are known to be strings
|
||||||
writeString((String) e.getKey());
|
for (Entry<String, Object> e : ((BdfDictionary) m).entrySet()) {
|
||||||
writeObject(e.getValue());
|
writeString(e.getKey());
|
||||||
|
writeObject(e.getValue());
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Check that keys are strings, write entries in canonical order
|
||||||
|
List<String> keys = new ArrayList<>(m.size());
|
||||||
|
for (Object k : m.keySet()) {
|
||||||
|
if (!(k instanceof String)) throw new FormatException();
|
||||||
|
keys.add((String) k);
|
||||||
|
}
|
||||||
|
sort(keys);
|
||||||
|
for (String key : keys) {
|
||||||
|
writeString(key);
|
||||||
|
writeObject(m.get(key));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
out.write(END);
|
out.write(END);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void writeDictionaryStart() throws IOException {
|
|
||||||
out.write(DICTIONARY);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void writeDictionaryEnd() throws IOException {
|
|
||||||
out.write(END);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,5 @@
|
|||||||
package org.briarproject.bramble.keyagreement;
|
package org.briarproject.bramble.keyagreement;
|
||||||
|
|
||||||
import org.briarproject.bramble.api.data.BdfReaderFactory;
|
|
||||||
import org.briarproject.bramble.api.data.BdfWriterFactory;
|
|
||||||
import org.briarproject.bramble.api.keyagreement.KeyAgreementTask;
|
import org.briarproject.bramble.api.keyagreement.KeyAgreementTask;
|
||||||
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;
|
||||||
@@ -19,13 +17,13 @@ public class KeyAgreementModule {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Provides
|
@Provides
|
||||||
PayloadEncoder providePayloadEncoder(BdfWriterFactory bdfWriterFactory) {
|
PayloadEncoder providePayloadEncoder(PayloadEncoderImpl payloadEncoder) {
|
||||||
return new PayloadEncoderImpl(bdfWriterFactory);
|
return payloadEncoder;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Provides
|
@Provides
|
||||||
PayloadParser providePayloadParser(BdfReaderFactory bdfReaderFactory) {
|
PayloadParser providePayloadParser(PayloadParserImpl payloadParser) {
|
||||||
return new PayloadParserImpl(bdfReaderFactory);
|
return payloadParser;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Provides
|
@Provides
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
package org.briarproject.bramble.keyagreement;
|
package org.briarproject.bramble.keyagreement;
|
||||||
|
|
||||||
|
import org.briarproject.bramble.api.data.BdfList;
|
||||||
import org.briarproject.bramble.api.data.BdfWriter;
|
import org.briarproject.bramble.api.data.BdfWriter;
|
||||||
import org.briarproject.bramble.api.data.BdfWriterFactory;
|
import org.briarproject.bramble.api.data.BdfWriterFactory;
|
||||||
import org.briarproject.bramble.api.keyagreement.Payload;
|
import org.briarproject.bramble.api.keyagreement.Payload;
|
||||||
@@ -13,7 +14,8 @@ import java.io.IOException;
|
|||||||
import javax.annotation.concurrent.Immutable;
|
import javax.annotation.concurrent.Immutable;
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
|
|
||||||
import static org.briarproject.bramble.api.keyagreement.KeyAgreementConstants.PROTOCOL_VERSION;
|
import static org.briarproject.bramble.api.keyagreement.KeyAgreementConstants.QR_FORMAT_ID;
|
||||||
|
import static org.briarproject.bramble.api.keyagreement.KeyAgreementConstants.QR_FORMAT_VERSION;
|
||||||
|
|
||||||
@Immutable
|
@Immutable
|
||||||
@NotNullByDefault
|
@NotNullByDefault
|
||||||
@@ -29,14 +31,16 @@ class PayloadEncoderImpl implements PayloadEncoder {
|
|||||||
@Override
|
@Override
|
||||||
public byte[] encode(Payload p) {
|
public byte[] encode(Payload p) {
|
||||||
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||||
out.write(PROTOCOL_VERSION);
|
int formatIdAndVersion = (QR_FORMAT_ID << 5) | QR_FORMAT_VERSION;
|
||||||
|
out.write(formatIdAndVersion);
|
||||||
|
BdfList payload = new BdfList();
|
||||||
|
payload.add(p.getCommitment());
|
||||||
|
for (TransportDescriptor d : p.getTransportDescriptors()) {
|
||||||
|
payload.add(d.getDescriptor());
|
||||||
|
}
|
||||||
BdfWriter w = bdfWriterFactory.createWriter(out);
|
BdfWriter w = bdfWriterFactory.createWriter(out);
|
||||||
try {
|
try {
|
||||||
w.writeListStart(); // Payload start
|
w.writeList(payload);
|
||||||
w.writeRaw(p.getCommitment());
|
|
||||||
for (TransportDescriptor d : p.getTransportDescriptors())
|
|
||||||
w.writeList(d.getDescriptor());
|
|
||||||
w.writeListEnd(); // Payload end
|
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
// Shouldn't happen with ByteArrayOutputStream
|
// Shouldn't happen with ByteArrayOutputStream
|
||||||
throw new AssertionError(e);
|
throw new AssertionError(e);
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package org.briarproject.bramble.keyagreement;
|
package org.briarproject.bramble.keyagreement;
|
||||||
|
|
||||||
import org.briarproject.bramble.api.FormatException;
|
import org.briarproject.bramble.api.FormatException;
|
||||||
|
import org.briarproject.bramble.api.Pair;
|
||||||
import org.briarproject.bramble.api.UnsupportedVersionException;
|
import org.briarproject.bramble.api.UnsupportedVersionException;
|
||||||
import org.briarproject.bramble.api.data.BdfList;
|
import org.briarproject.bramble.api.data.BdfList;
|
||||||
import org.briarproject.bramble.api.data.BdfReader;
|
import org.briarproject.bramble.api.data.BdfReader;
|
||||||
@@ -11,6 +12,9 @@ import org.briarproject.bramble.api.keyagreement.TransportDescriptor;
|
|||||||
import org.briarproject.bramble.api.plugin.BluetoothConstants;
|
import org.briarproject.bramble.api.plugin.BluetoothConstants;
|
||||||
import org.briarproject.bramble.api.plugin.LanTcpConstants;
|
import org.briarproject.bramble.api.plugin.LanTcpConstants;
|
||||||
import org.briarproject.bramble.api.plugin.TransportId;
|
import org.briarproject.bramble.api.plugin.TransportId;
|
||||||
|
import org.briarproject.bramble.api.qrcode.QrCodeClassifier;
|
||||||
|
import org.briarproject.bramble.api.qrcode.QrCodeClassifier.QrCodeType;
|
||||||
|
import org.briarproject.bramble.api.qrcode.WrongQrCodeTypeException;
|
||||||
import org.briarproject.nullsafety.NotNullByDefault;
|
import org.briarproject.nullsafety.NotNullByDefault;
|
||||||
|
|
||||||
import java.io.ByteArrayInputStream;
|
import java.io.ByteArrayInputStream;
|
||||||
@@ -21,34 +25,42 @@ import java.util.List;
|
|||||||
import javax.annotation.concurrent.Immutable;
|
import javax.annotation.concurrent.Immutable;
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
|
|
||||||
import static org.briarproject.bramble.api.keyagreement.KeyAgreementConstants.BETA_PROTOCOL_VERSION;
|
|
||||||
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.keyagreement.KeyAgreementConstants.PROTOCOL_VERSION;
|
import static org.briarproject.bramble.api.keyagreement.KeyAgreementConstants.QR_FORMAT_VERSION;
|
||||||
import static org.briarproject.bramble.api.keyagreement.KeyAgreementConstants.TRANSPORT_ID_BLUETOOTH;
|
import static org.briarproject.bramble.api.keyagreement.KeyAgreementConstants.TRANSPORT_ID_BLUETOOTH;
|
||||||
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.qrcode.QrCodeClassifier.QrCodeType.BQP;
|
||||||
|
import static org.briarproject.bramble.util.StringUtils.ISO_8859_1;
|
||||||
|
|
||||||
@Immutable
|
@Immutable
|
||||||
@NotNullByDefault
|
@NotNullByDefault
|
||||||
class PayloadParserImpl implements PayloadParser {
|
class PayloadParserImpl implements PayloadParser {
|
||||||
|
|
||||||
private final BdfReaderFactory bdfReaderFactory;
|
private final BdfReaderFactory bdfReaderFactory;
|
||||||
|
private final QrCodeClassifier qrCodeClassifier;
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
PayloadParserImpl(BdfReaderFactory bdfReaderFactory) {
|
PayloadParserImpl(BdfReaderFactory bdfReaderFactory,
|
||||||
|
QrCodeClassifier qrCodeClassifier) {
|
||||||
this.bdfReaderFactory = bdfReaderFactory;
|
this.bdfReaderFactory = bdfReaderFactory;
|
||||||
|
this.qrCodeClassifier = qrCodeClassifier;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Payload parse(byte[] raw) throws IOException {
|
public Payload parse(String payloadString) throws IOException {
|
||||||
ByteArrayInputStream in = new ByteArrayInputStream(raw);
|
Pair<QrCodeType, Integer> typeAndVersion =
|
||||||
// First byte: the protocol version
|
qrCodeClassifier.classifyQrCode(payloadString);
|
||||||
int protocolVersion = in.read();
|
QrCodeType qrCodeType = typeAndVersion.getFirst();
|
||||||
if (protocolVersion == -1) throw new FormatException();
|
if (qrCodeType != BQP) throw new WrongQrCodeTypeException(qrCodeType);
|
||||||
if (protocolVersion != PROTOCOL_VERSION) {
|
int formatVersion = typeAndVersion.getSecond();
|
||||||
boolean tooOld = protocolVersion < PROTOCOL_VERSION ||
|
if (formatVersion != QR_FORMAT_VERSION) {
|
||||||
protocolVersion == BETA_PROTOCOL_VERSION;
|
boolean tooOld = formatVersion < QR_FORMAT_VERSION;
|
||||||
throw new UnsupportedVersionException(tooOld);
|
throw new UnsupportedVersionException(tooOld);
|
||||||
}
|
}
|
||||||
|
byte[] raw = payloadString.getBytes(ISO_8859_1);
|
||||||
|
ByteArrayInputStream in = new ByteArrayInputStream(raw);
|
||||||
|
// First byte: the format identifier and version (already parsed)
|
||||||
|
if (in.read() == -1) throw new AssertionError();
|
||||||
// The rest of the payload is a BDF list with one or more elements
|
// The rest of the payload is a BDF list with one or more elements
|
||||||
BdfReader r = bdfReaderFactory.createReader(in);
|
BdfReader r = bdfReaderFactory.createReader(in);
|
||||||
BdfList payload = r.readList();
|
BdfList payload = r.readList();
|
||||||
@@ -61,7 +73,7 @@ class PayloadParserImpl implements PayloadParser {
|
|||||||
List<TransportDescriptor> recognised = new ArrayList<>();
|
List<TransportDescriptor> recognised = new ArrayList<>();
|
||||||
for (int i = 1; i < payload.size(); i++) {
|
for (int i = 1; i < payload.size(); i++) {
|
||||||
BdfList descriptor = payload.getList(i);
|
BdfList descriptor = payload.getList(i);
|
||||||
long transportId = descriptor.getLong(0);
|
int transportId = descriptor.getInt(0);
|
||||||
if (transportId == TRANSPORT_ID_BLUETOOTH) {
|
if (transportId == TRANSPORT_ID_BLUETOOTH) {
|
||||||
TransportId id = BluetoothConstants.ID;
|
TransportId id = BluetoothConstants.ID;
|
||||||
recognised.add(new TransportDescriptor(id, descriptor));
|
recognised.add(new TransportDescriptor(id, descriptor));
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
package org.briarproject.bramble.mailbox;
|
package org.briarproject.bramble.mailbox;
|
||||||
|
|
||||||
|
import org.briarproject.bramble.api.FormatException;
|
||||||
import org.briarproject.bramble.api.db.DbException;
|
import org.briarproject.bramble.api.db.DbException;
|
||||||
import org.briarproject.bramble.api.db.Transaction;
|
import org.briarproject.bramble.api.db.Transaction;
|
||||||
import org.briarproject.bramble.api.db.TransactionManager;
|
import org.briarproject.bramble.api.db.TransactionManager;
|
||||||
@@ -11,12 +12,15 @@ import org.briarproject.bramble.api.mailbox.MailboxSettingsManager;
|
|||||||
import org.briarproject.bramble.api.mailbox.MailboxStatus;
|
import org.briarproject.bramble.api.mailbox.MailboxStatus;
|
||||||
import org.briarproject.bramble.api.mailbox.MailboxVersion;
|
import org.briarproject.bramble.api.mailbox.MailboxVersion;
|
||||||
import org.briarproject.bramble.api.system.Clock;
|
import org.briarproject.bramble.api.system.Clock;
|
||||||
|
import org.briarproject.bramble.util.Base32;
|
||||||
import org.briarproject.nullsafety.NotNullByDefault;
|
import org.briarproject.nullsafety.NotNullByDefault;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.concurrent.Executor;
|
import java.util.concurrent.Executor;
|
||||||
import java.util.logging.Logger;
|
import java.util.logging.Logger;
|
||||||
|
import java.util.regex.Matcher;
|
||||||
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
import javax.annotation.concurrent.GuardedBy;
|
import javax.annotation.concurrent.GuardedBy;
|
||||||
@@ -26,6 +30,7 @@ import javax.inject.Inject;
|
|||||||
import static java.util.logging.Level.WARNING;
|
import static java.util.logging.Level.WARNING;
|
||||||
import static java.util.logging.Logger.getLogger;
|
import static java.util.logging.Logger.getLogger;
|
||||||
import static org.briarproject.bramble.util.LogUtils.logException;
|
import static org.briarproject.bramble.util.LogUtils.logException;
|
||||||
|
import static org.briarproject.bramble.util.StringUtils.ISO_8859_1;
|
||||||
|
|
||||||
@Immutable
|
@Immutable
|
||||||
@NotNullByDefault
|
@NotNullByDefault
|
||||||
@@ -98,6 +103,22 @@ class MailboxManagerImpl implements MailboxManager {
|
|||||||
return created;
|
return created;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String convertBase32Payload(String base32Payload)
|
||||||
|
throws FormatException {
|
||||||
|
Pattern regex = Pattern.compile("(briar-mailbox://)?([a-z2-7]{104})");
|
||||||
|
Matcher matcher = regex.matcher(base32Payload);
|
||||||
|
if (!matcher.find()) throw new FormatException();
|
||||||
|
String base32 = matcher.group(2);
|
||||||
|
byte[] payloadBytes;
|
||||||
|
try {
|
||||||
|
payloadBytes = Base32.decode(base32, false);
|
||||||
|
} catch (IllegalArgumentException e) {
|
||||||
|
throw new FormatException();
|
||||||
|
}
|
||||||
|
return new String(payloadBytes, ISO_8859_1);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean checkConnection() {
|
public boolean checkConnection() {
|
||||||
List<MailboxVersion> versions = null;
|
List<MailboxVersion> versions = null;
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import org.briarproject.bramble.api.event.EventExecutor;
|
|||||||
import org.briarproject.bramble.api.mailbox.MailboxPairingTask;
|
import org.briarproject.bramble.api.mailbox.MailboxPairingTask;
|
||||||
import org.briarproject.bramble.api.mailbox.MailboxSettingsManager;
|
import org.briarproject.bramble.api.mailbox.MailboxSettingsManager;
|
||||||
import org.briarproject.bramble.api.mailbox.MailboxUpdateManager;
|
import org.briarproject.bramble.api.mailbox.MailboxUpdateManager;
|
||||||
|
import org.briarproject.bramble.api.qrcode.QrCodeClassifier;
|
||||||
import org.briarproject.bramble.api.system.Clock;
|
import org.briarproject.bramble.api.system.Clock;
|
||||||
import org.briarproject.nullsafety.NotNullByDefault;
|
import org.briarproject.nullsafety.NotNullByDefault;
|
||||||
|
|
||||||
@@ -25,6 +26,7 @@ class MailboxPairingTaskFactoryImpl implements MailboxPairingTaskFactory {
|
|||||||
private final MailboxApi api;
|
private final MailboxApi api;
|
||||||
private final MailboxSettingsManager mailboxSettingsManager;
|
private final MailboxSettingsManager mailboxSettingsManager;
|
||||||
private final MailboxUpdateManager mailboxUpdateManager;
|
private final MailboxUpdateManager mailboxUpdateManager;
|
||||||
|
private final QrCodeClassifier qrCodeClassifier;
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
MailboxPairingTaskFactoryImpl(
|
MailboxPairingTaskFactoryImpl(
|
||||||
@@ -34,7 +36,8 @@ class MailboxPairingTaskFactoryImpl implements MailboxPairingTaskFactory {
|
|||||||
Clock clock,
|
Clock clock,
|
||||||
MailboxApi api,
|
MailboxApi api,
|
||||||
MailboxSettingsManager mailboxSettingsManager,
|
MailboxSettingsManager mailboxSettingsManager,
|
||||||
MailboxUpdateManager mailboxUpdateManager) {
|
MailboxUpdateManager mailboxUpdateManager,
|
||||||
|
QrCodeClassifier qrCodeClassifier) {
|
||||||
this.eventExecutor = eventExecutor;
|
this.eventExecutor = eventExecutor;
|
||||||
this.db = db;
|
this.db = db;
|
||||||
this.crypto = crypto;
|
this.crypto = crypto;
|
||||||
@@ -42,12 +45,13 @@ class MailboxPairingTaskFactoryImpl implements MailboxPairingTaskFactory {
|
|||||||
this.api = api;
|
this.api = api;
|
||||||
this.mailboxSettingsManager = mailboxSettingsManager;
|
this.mailboxSettingsManager = mailboxSettingsManager;
|
||||||
this.mailboxUpdateManager = mailboxUpdateManager;
|
this.mailboxUpdateManager = mailboxUpdateManager;
|
||||||
|
this.qrCodeClassifier = qrCodeClassifier;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public MailboxPairingTask createPairingTask(String qrCodePayload) {
|
public MailboxPairingTask createPairingTask(String qrCodePayload) {
|
||||||
return new MailboxPairingTaskImpl(qrCodePayload, eventExecutor, db,
|
return new MailboxPairingTaskImpl(qrCodePayload, eventExecutor, db,
|
||||||
crypto, clock, api, mailboxSettingsManager,
|
crypto, clock, api, mailboxSettingsManager,
|
||||||
mailboxUpdateManager);
|
mailboxUpdateManager, qrCodeClassifier);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ package org.briarproject.bramble.mailbox;
|
|||||||
|
|
||||||
import org.briarproject.bramble.api.Consumer;
|
import org.briarproject.bramble.api.Consumer;
|
||||||
import org.briarproject.bramble.api.FormatException;
|
import org.briarproject.bramble.api.FormatException;
|
||||||
|
import org.briarproject.bramble.api.Pair;
|
||||||
import org.briarproject.bramble.api.contact.Contact;
|
import org.briarproject.bramble.api.contact.Contact;
|
||||||
import org.briarproject.bramble.api.crypto.CryptoComponent;
|
import org.briarproject.bramble.api.crypto.CryptoComponent;
|
||||||
import org.briarproject.bramble.api.db.DatabaseComponent;
|
import org.briarproject.bramble.api.db.DatabaseComponent;
|
||||||
@@ -9,18 +10,26 @@ import org.briarproject.bramble.api.db.DbException;
|
|||||||
import org.briarproject.bramble.api.event.EventExecutor;
|
import org.briarproject.bramble.api.event.EventExecutor;
|
||||||
import org.briarproject.bramble.api.mailbox.MailboxAuthToken;
|
import org.briarproject.bramble.api.mailbox.MailboxAuthToken;
|
||||||
import org.briarproject.bramble.api.mailbox.MailboxPairingState;
|
import org.briarproject.bramble.api.mailbox.MailboxPairingState;
|
||||||
|
import org.briarproject.bramble.api.mailbox.MailboxPairingState.ConnectionError;
|
||||||
|
import org.briarproject.bramble.api.mailbox.MailboxPairingState.InvalidQrCode;
|
||||||
|
import org.briarproject.bramble.api.mailbox.MailboxPairingState.MailboxAlreadyPaired;
|
||||||
|
import org.briarproject.bramble.api.mailbox.MailboxPairingState.Paired;
|
||||||
|
import org.briarproject.bramble.api.mailbox.MailboxPairingState.Pairing;
|
||||||
|
import org.briarproject.bramble.api.mailbox.MailboxPairingState.QrCodeReceived;
|
||||||
|
import org.briarproject.bramble.api.mailbox.MailboxPairingState.UnexpectedError;
|
||||||
import org.briarproject.bramble.api.mailbox.MailboxPairingTask;
|
import org.briarproject.bramble.api.mailbox.MailboxPairingTask;
|
||||||
import org.briarproject.bramble.api.mailbox.MailboxProperties;
|
import org.briarproject.bramble.api.mailbox.MailboxProperties;
|
||||||
import org.briarproject.bramble.api.mailbox.MailboxSettingsManager;
|
import org.briarproject.bramble.api.mailbox.MailboxSettingsManager;
|
||||||
import org.briarproject.bramble.api.mailbox.MailboxUpdate;
|
import org.briarproject.bramble.api.mailbox.MailboxUpdate;
|
||||||
import org.briarproject.bramble.api.mailbox.MailboxUpdateManager;
|
import org.briarproject.bramble.api.mailbox.MailboxUpdateManager;
|
||||||
|
import org.briarproject.bramble.api.qrcode.QrCodeClassifier;
|
||||||
|
import org.briarproject.bramble.api.qrcode.QrCodeClassifier.QrCodeType;
|
||||||
import org.briarproject.bramble.api.system.Clock;
|
import org.briarproject.bramble.api.system.Clock;
|
||||||
import org.briarproject.bramble.mailbox.MailboxApi.ApiException;
|
import org.briarproject.bramble.mailbox.MailboxApi.ApiException;
|
||||||
import org.briarproject.bramble.mailbox.MailboxApi.MailboxAlreadyPairedException;
|
import org.briarproject.bramble.mailbox.MailboxApi.MailboxAlreadyPairedException;
|
||||||
import org.briarproject.nullsafety.NotNullByDefault;
|
import org.briarproject.nullsafety.NotNullByDefault;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.nio.charset.Charset;
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@@ -32,7 +41,10 @@ import javax.annotation.concurrent.ThreadSafe;
|
|||||||
|
|
||||||
import static java.util.logging.Level.WARNING;
|
import static java.util.logging.Level.WARNING;
|
||||||
import static java.util.logging.Logger.getLogger;
|
import static java.util.logging.Logger.getLogger;
|
||||||
|
import static org.briarproject.bramble.api.mailbox.MailboxConstants.QR_FORMAT_VERSION;
|
||||||
|
import static org.briarproject.bramble.api.qrcode.QrCodeClassifier.QrCodeType.MAILBOX;
|
||||||
import static org.briarproject.bramble.util.LogUtils.logException;
|
import static org.briarproject.bramble.util.LogUtils.logException;
|
||||||
|
import static org.briarproject.bramble.util.StringUtils.ISO_8859_1;
|
||||||
|
|
||||||
@ThreadSafe
|
@ThreadSafe
|
||||||
@NotNullByDefault
|
@NotNullByDefault
|
||||||
@@ -40,9 +52,6 @@ class MailboxPairingTaskImpl implements MailboxPairingTask {
|
|||||||
|
|
||||||
private final static Logger LOG =
|
private final static Logger LOG =
|
||||||
getLogger(MailboxPairingTaskImpl.class.getName());
|
getLogger(MailboxPairingTaskImpl.class.getName());
|
||||||
@SuppressWarnings("CharsetObjectCanBeUsed") // Requires minSdkVersion >= 19
|
|
||||||
private static final Charset ISO_8859_1 = Charset.forName("ISO-8859-1");
|
|
||||||
private static final int VERSION_REQUIRED = 32;
|
|
||||||
|
|
||||||
private final String payload;
|
private final String payload;
|
||||||
private final Executor eventExecutor;
|
private final Executor eventExecutor;
|
||||||
@@ -52,6 +61,8 @@ class MailboxPairingTaskImpl implements MailboxPairingTask {
|
|||||||
private final MailboxApi api;
|
private final MailboxApi api;
|
||||||
private final MailboxSettingsManager mailboxSettingsManager;
|
private final MailboxSettingsManager mailboxSettingsManager;
|
||||||
private final MailboxUpdateManager mailboxUpdateManager;
|
private final MailboxUpdateManager mailboxUpdateManager;
|
||||||
|
private final QrCodeClassifier qrCodeClassifier;
|
||||||
|
private final long timeStarted;
|
||||||
|
|
||||||
private final Object lock = new Object();
|
private final Object lock = new Object();
|
||||||
@GuardedBy("lock")
|
@GuardedBy("lock")
|
||||||
@@ -68,7 +79,8 @@ class MailboxPairingTaskImpl implements MailboxPairingTask {
|
|||||||
Clock clock,
|
Clock clock,
|
||||||
MailboxApi api,
|
MailboxApi api,
|
||||||
MailboxSettingsManager mailboxSettingsManager,
|
MailboxSettingsManager mailboxSettingsManager,
|
||||||
MailboxUpdateManager mailboxUpdateManager) {
|
MailboxUpdateManager mailboxUpdateManager,
|
||||||
|
QrCodeClassifier qrCodeClassifier) {
|
||||||
this.payload = payload;
|
this.payload = payload;
|
||||||
this.eventExecutor = eventExecutor;
|
this.eventExecutor = eventExecutor;
|
||||||
this.db = db;
|
this.db = db;
|
||||||
@@ -77,7 +89,9 @@ class MailboxPairingTaskImpl implements MailboxPairingTask {
|
|||||||
this.api = api;
|
this.api = api;
|
||||||
this.mailboxSettingsManager = mailboxSettingsManager;
|
this.mailboxSettingsManager = mailboxSettingsManager;
|
||||||
this.mailboxUpdateManager = mailboxUpdateManager;
|
this.mailboxUpdateManager = mailboxUpdateManager;
|
||||||
state = new MailboxPairingState.QrCodeReceived();
|
this.qrCodeClassifier = qrCodeClassifier;
|
||||||
|
timeStarted = clock.currentTimeMillis();
|
||||||
|
state = new QrCodeReceived(timeStarted);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -99,22 +113,30 @@ class MailboxPairingTaskImpl implements MailboxPairingTask {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
|
Pair<QrCodeType, Integer> typeAndVersion =
|
||||||
|
qrCodeClassifier.classifyQrCode(payload);
|
||||||
|
QrCodeType qrCodeType = typeAndVersion.getFirst();
|
||||||
|
int formatVersion = typeAndVersion.getSecond();
|
||||||
|
if (qrCodeType != MAILBOX || formatVersion != QR_FORMAT_VERSION) {
|
||||||
|
setState(new InvalidQrCode(qrCodeType, formatVersion));
|
||||||
|
return;
|
||||||
|
}
|
||||||
try {
|
try {
|
||||||
pairMailbox();
|
pairMailbox();
|
||||||
} catch (FormatException e) {
|
} catch (FormatException e) {
|
||||||
onMailboxError(e, new MailboxPairingState.InvalidQrCode());
|
onMailboxError(e, new InvalidQrCode(qrCodeType, formatVersion));
|
||||||
} catch (MailboxAlreadyPairedException e) {
|
} catch (MailboxAlreadyPairedException e) {
|
||||||
onMailboxError(e, new MailboxPairingState.MailboxAlreadyPaired());
|
onMailboxError(e, new MailboxAlreadyPaired());
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
onMailboxError(e, new MailboxPairingState.ConnectionError());
|
onMailboxError(e, new ConnectionError());
|
||||||
} catch (ApiException | DbException e) {
|
} catch (ApiException | DbException e) {
|
||||||
onMailboxError(e, new MailboxPairingState.UnexpectedError());
|
onMailboxError(e, new UnexpectedError());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void pairMailbox() throws IOException, ApiException, DbException {
|
private void pairMailbox() throws IOException, ApiException, DbException {
|
||||||
MailboxProperties mailboxProperties = decodeQrCodePayload(payload);
|
MailboxProperties mailboxProperties = decodeQrCodePayload(payload);
|
||||||
setState(new MailboxPairingState.Pairing());
|
setState(new Pairing(timeStarted));
|
||||||
MailboxProperties ownerProperties = api.setup(mailboxProperties);
|
MailboxProperties ownerProperties = api.setup(mailboxProperties);
|
||||||
long time = clock.currentTimeMillis();
|
long time = clock.currentTimeMillis();
|
||||||
db.transaction(false, txn -> {
|
db.transaction(false, txn -> {
|
||||||
@@ -133,7 +155,7 @@ class MailboxPairingTaskImpl implements MailboxPairingTask {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
setState(new MailboxPairingState.Paired());
|
setState(new Paired());
|
||||||
}
|
}
|
||||||
|
|
||||||
private void onMailboxError(Exception e, MailboxPairingState state) {
|
private void onMailboxError(Exception e, MailboxPairingState state) {
|
||||||
@@ -167,14 +189,6 @@ class MailboxPairingTaskImpl implements MailboxPairingTask {
|
|||||||
}
|
}
|
||||||
throw new FormatException();
|
throw new FormatException();
|
||||||
}
|
}
|
||||||
int version = bytes[0] & 0xFF;
|
|
||||||
if (version != VERSION_REQUIRED) {
|
|
||||||
if (LOG.isLoggable(WARNING)) {
|
|
||||||
LOG.warning("QR code has not version " + VERSION_REQUIRED +
|
|
||||||
": " + version);
|
|
||||||
}
|
|
||||||
throw new FormatException();
|
|
||||||
}
|
|
||||||
LOG.info("QR code is valid");
|
LOG.info("QR code is valid");
|
||||||
byte[] onionPubKey = Arrays.copyOfRange(bytes, 1, 33);
|
byte[] onionPubKey = Arrays.copyOfRange(bytes, 1, 33);
|
||||||
String onion = crypto.encodeOnion(onionPubKey);
|
String onion = crypto.encodeOnion(onionPubKey);
|
||||||
|
|||||||
@@ -419,7 +419,7 @@ class LanTcpPlugin extends TcpPlugin {
|
|||||||
private InetSocketAddress parseSocketAddress(BdfList descriptor)
|
private InetSocketAddress parseSocketAddress(BdfList descriptor)
|
||||||
throws FormatException {
|
throws FormatException {
|
||||||
byte[] address = descriptor.getRaw(1);
|
byte[] address = descriptor.getRaw(1);
|
||||||
int port = descriptor.getLong(2).intValue();
|
int port = descriptor.getInt(2);
|
||||||
if (port < 1 || port > MAX_16_BIT_UNSIGNED) throw new FormatException();
|
if (port < 1 || port > MAX_16_BIT_UNSIGNED) throw new FormatException();
|
||||||
try {
|
try {
|
||||||
InetAddress addr = InetAddress.getByAddress(address);
|
InetAddress addr = InetAddress.getByAddress(address);
|
||||||
|
|||||||
@@ -46,7 +46,6 @@ import java.io.OutputStream;
|
|||||||
import java.net.InetSocketAddress;
|
import java.net.InetSocketAddress;
|
||||||
import java.net.ServerSocket;
|
import java.net.ServerSocket;
|
||||||
import java.net.Socket;
|
import java.net.Socket;
|
||||||
import java.nio.charset.Charset;
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@@ -56,7 +55,6 @@ 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;
|
||||||
import java.util.regex.Pattern;
|
import java.util.regex.Pattern;
|
||||||
import java.util.zip.ZipInputStream;
|
|
||||||
|
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
import javax.annotation.concurrent.GuardedBy;
|
import javax.annotation.concurrent.GuardedBy;
|
||||||
@@ -100,7 +98,9 @@ import static org.briarproject.bramble.util.IoUtils.copyAndClose;
|
|||||||
import static org.briarproject.bramble.util.IoUtils.tryToClose;
|
import static org.briarproject.bramble.util.IoUtils.tryToClose;
|
||||||
import static org.briarproject.bramble.util.LogUtils.logException;
|
import static org.briarproject.bramble.util.LogUtils.logException;
|
||||||
import static org.briarproject.bramble.util.PrivacyUtils.scrubOnion;
|
import static org.briarproject.bramble.util.PrivacyUtils.scrubOnion;
|
||||||
|
import static org.briarproject.bramble.util.StringUtils.UTF_8;
|
||||||
import static org.briarproject.bramble.util.StringUtils.isNullOrEmpty;
|
import static org.briarproject.bramble.util.StringUtils.isNullOrEmpty;
|
||||||
|
import static org.briarproject.nullsafety.NullSafety.requireNonNull;
|
||||||
|
|
||||||
@MethodsNotNullByDefault
|
@MethodsNotNullByDefault
|
||||||
@ParametersNotNullByDefault
|
@ParametersNotNullByDefault
|
||||||
@@ -140,7 +140,8 @@ abstract class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
|
|||||||
private final long maxLatency;
|
private final long maxLatency;
|
||||||
private final int maxIdleTime;
|
private final int maxIdleTime;
|
||||||
private final int socketTimeout;
|
private final int socketTimeout;
|
||||||
private final File torDirectory, geoIpFile, configFile;
|
private final File torDirectory;
|
||||||
|
private final File configFile;
|
||||||
private final int torSocksPort;
|
private final int torSocksPort;
|
||||||
private final int torControlPort;
|
private final int torControlPort;
|
||||||
private final File doneFile, cookieFile;
|
private final File doneFile, cookieFile;
|
||||||
@@ -195,7 +196,6 @@ abstract class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
|
|||||||
this.torDirectory = torDirectory;
|
this.torDirectory = torDirectory;
|
||||||
this.torSocksPort = torSocksPort;
|
this.torSocksPort = torSocksPort;
|
||||||
this.torControlPort = torControlPort;
|
this.torControlPort = torControlPort;
|
||||||
geoIpFile = new File(torDirectory, "geoip");
|
|
||||||
configFile = new File(torDirectory, "torrc");
|
configFile = new File(torDirectory, "torrc");
|
||||||
doneFile = new File(torDirectory, "done");
|
doneFile = new File(torDirectory, "done");
|
||||||
cookieFile = new File(torDirectory, ".tor/control_auth_cookie");
|
cookieFile = new File(torDirectory, ".tor/control_auth_cookie");
|
||||||
@@ -208,6 +208,10 @@ abstract class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
|
|||||||
return new File(torDirectory, "tor");
|
return new File(torDirectory, "tor");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private File getLibEventFile() {
|
||||||
|
return new File(torDirectory, "libevent-2.1.7.dylib");
|
||||||
|
}
|
||||||
|
|
||||||
protected File getObfs4ExecutableFile() {
|
protected File getObfs4ExecutableFile() {
|
||||||
return new File(torDirectory, "obfs4proxy");
|
return new File(torDirectory, "obfs4proxy");
|
||||||
}
|
}
|
||||||
@@ -332,12 +336,6 @@ abstract class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
|
|||||||
// The done file may already exist from a previous installation
|
// The done file may already exist from a previous installation
|
||||||
//noinspection ResultOfMethodCallIgnored
|
//noinspection ResultOfMethodCallIgnored
|
||||||
doneFile.delete();
|
doneFile.delete();
|
||||||
// The GeoIP file may exist from a previous installation - we can
|
|
||||||
// save some space by deleting it.
|
|
||||||
// TODO: Remove after a reasonable migration period
|
|
||||||
// (added 2022-03-29)
|
|
||||||
//noinspection ResultOfMethodCallIgnored
|
|
||||||
geoIpFile.delete();
|
|
||||||
installTorExecutable();
|
installTorExecutable();
|
||||||
installObfs4Executable();
|
installObfs4Executable();
|
||||||
installSnowflakeExecutable();
|
installSnowflakeExecutable();
|
||||||
@@ -354,7 +352,9 @@ abstract class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
|
|||||||
if (LOG.isLoggable(INFO))
|
if (LOG.isLoggable(INFO))
|
||||||
LOG.info("Installing Tor binary for " + architecture);
|
LOG.info("Installing Tor binary for " + architecture);
|
||||||
File torFile = getTorExecutableFile();
|
File torFile = getTorExecutableFile();
|
||||||
extract(getTorInputStream(), torFile);
|
File libEventFile = getLibEventFile();
|
||||||
|
extract(getExecutableInputStream("tor"), torFile);
|
||||||
|
extract(getExecutableInputStream("libevent-2.1.7.dylib"), libEventFile);
|
||||||
if (!torFile.setExecutable(true, true)) throw new IOException();
|
if (!torFile.setExecutable(true, true)) throw new IOException();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -362,7 +362,7 @@ abstract class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
|
|||||||
if (LOG.isLoggable(INFO))
|
if (LOG.isLoggable(INFO))
|
||||||
LOG.info("Installing obfs4proxy binary for " + architecture);
|
LOG.info("Installing obfs4proxy binary for " + architecture);
|
||||||
File obfs4File = getObfs4ExecutableFile();
|
File obfs4File = getObfs4ExecutableFile();
|
||||||
extract(getObfs4InputStream(), obfs4File);
|
extract(getExecutableInputStream("obfs4proxy"), obfs4File);
|
||||||
if (!obfs4File.setExecutable(true, true)) throw new IOException();
|
if (!obfs4File.setExecutable(true, true)) throw new IOException();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -370,28 +370,18 @@ abstract class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
|
|||||||
if (LOG.isLoggable(INFO))
|
if (LOG.isLoggable(INFO))
|
||||||
LOG.info("Installing snowflake binary for " + architecture);
|
LOG.info("Installing snowflake binary for " + architecture);
|
||||||
File snowflakeFile = getSnowflakeExecutableFile();
|
File snowflakeFile = getSnowflakeExecutableFile();
|
||||||
extract(getSnowflakeInputStream(), snowflakeFile);
|
extract(getExecutableInputStream("snowflake"), snowflakeFile);
|
||||||
if (!snowflakeFile.setExecutable(true, true)) throw new IOException();
|
if (!snowflakeFile.setExecutable(true, true)) throw new IOException();
|
||||||
}
|
}
|
||||||
|
|
||||||
private InputStream getTorInputStream() throws IOException {
|
private InputStream getExecutableInputStream(String basename) {
|
||||||
return getZipInputStream("tor");
|
String ext = getExecutableExtension();
|
||||||
|
return requireNonNull(resourceProvider
|
||||||
|
.getResourceInputStream(architecture + "/" + basename, ext));
|
||||||
}
|
}
|
||||||
|
|
||||||
private InputStream getObfs4InputStream() throws IOException {
|
protected String getExecutableExtension() {
|
||||||
return getZipInputStream("obfs4proxy");
|
return "";
|
||||||
}
|
|
||||||
|
|
||||||
private InputStream getSnowflakeInputStream() throws IOException {
|
|
||||||
return getZipInputStream("snowflake");
|
|
||||||
}
|
|
||||||
|
|
||||||
private InputStream getZipInputStream(String basename) throws IOException {
|
|
||||||
InputStream in = resourceProvider
|
|
||||||
.getResourceInputStream(basename + "_" + architecture, ".zip");
|
|
||||||
ZipInputStream zin = new ZipInputStream(in);
|
|
||||||
if (zin.getNextEntry() == null) throw new IOException();
|
|
||||||
return zin;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void append(StringBuilder strb, String name, Object value) {
|
private static void append(StringBuilder strb, String name, Object value) {
|
||||||
@@ -419,9 +409,7 @@ abstract class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
|
|||||||
append(strb, "ClientTransportPlugin meek_lite exec", obfs4Path);
|
append(strb, "ClientTransportPlugin meek_lite exec", obfs4Path);
|
||||||
String snowflakePath = getSnowflakeExecutableFile().getAbsolutePath();
|
String snowflakePath = getSnowflakeExecutableFile().getAbsolutePath();
|
||||||
append(strb, "ClientTransportPlugin snowflake exec", snowflakePath);
|
append(strb, "ClientTransportPlugin snowflake exec", snowflakePath);
|
||||||
//noinspection CharsetObjectCanBeUsed
|
return new ByteArrayInputStream(strb.toString().getBytes(UTF_8));
|
||||||
return new ByteArrayInputStream(
|
|
||||||
strb.toString().getBytes(Charset.forName("UTF-8")));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void listFiles(File f) {
|
private void listFiles(File f) {
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ import net.i2p.crypto.eddsa.spec.EdDSAPrivateKeySpec;
|
|||||||
import org.bouncycastle.util.encoders.Base64;
|
import org.bouncycastle.util.encoders.Base64;
|
||||||
import org.briarproject.bramble.api.crypto.CryptoComponent;
|
import org.briarproject.bramble.api.crypto.CryptoComponent;
|
||||||
|
|
||||||
import java.nio.charset.Charset;
|
import static org.briarproject.bramble.util.StringUtils.US_ASCII;
|
||||||
|
|
||||||
class TorRendezvousCryptoImpl implements TorRendezvousCrypto {
|
class TorRendezvousCryptoImpl implements TorRendezvousCrypto {
|
||||||
|
|
||||||
@@ -31,6 +31,6 @@ class TorRendezvousCryptoImpl implements TorRendezvousCrypto {
|
|||||||
EdDSAPrivateKeySpec spec = new EdDSAPrivateKeySpec(seed, CURVE_SPEC);
|
EdDSAPrivateKeySpec spec = new EdDSAPrivateKeySpec(seed, CURVE_SPEC);
|
||||||
byte[] hash = spec.getH();
|
byte[] hash = spec.getH();
|
||||||
byte[] base64 = Base64.encode(hash);
|
byte[] base64 = Base64.encode(hash);
|
||||||
return "ED25519-V3:" + new String(base64, Charset.forName("US-ASCII"));
|
return "ED25519-V3:" + new String(base64, US_ASCII);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -201,7 +201,7 @@ class TransportPropertyManagerImpl implements TransportPropertyManager,
|
|||||||
// Retrieve and parse the latest local properties
|
// Retrieve and parse the latest local properties
|
||||||
for (Entry<TransportId, LatestUpdate> e : latest.entrySet()) {
|
for (Entry<TransportId, LatestUpdate> e : latest.entrySet()) {
|
||||||
BdfList message = clientHelper.getMessageAsList(txn,
|
BdfList message = clientHelper.getMessageAsList(txn,
|
||||||
e.getValue().messageId);
|
e.getValue().messageId, false);
|
||||||
local.put(e.getKey(), parseProperties(message));
|
local.put(e.getKey(), parseProperties(message));
|
||||||
}
|
}
|
||||||
return local;
|
return local;
|
||||||
@@ -222,7 +222,7 @@ class TransportPropertyManagerImpl implements TransportPropertyManager,
|
|||||||
if (latest != null) {
|
if (latest != null) {
|
||||||
// Retrieve and parse the latest local properties
|
// Retrieve and parse the latest local properties
|
||||||
BdfList message = clientHelper.getMessageAsList(txn,
|
BdfList message = clientHelper.getMessageAsList(txn,
|
||||||
latest.messageId);
|
latest.messageId, false);
|
||||||
p = parseProperties(message);
|
p = parseProperties(message);
|
||||||
}
|
}
|
||||||
return p == null ? new TransportProperties() : p;
|
return p == null ? new TransportProperties() : p;
|
||||||
@@ -252,7 +252,7 @@ class TransportPropertyManagerImpl implements TransportPropertyManager,
|
|||||||
local = new TransportProperties();
|
local = new TransportProperties();
|
||||||
} else {
|
} else {
|
||||||
BdfList message = clientHelper.getMessageAsList(txn,
|
BdfList message = clientHelper.getMessageAsList(txn,
|
||||||
latest.messageId);
|
latest.messageId, false);
|
||||||
local = parseProperties(message);
|
local = parseProperties(message);
|
||||||
}
|
}
|
||||||
storeLocalProperties(txn, c, t, local);
|
storeLocalProperties(txn, c, t, local);
|
||||||
@@ -272,8 +272,8 @@ class TransportPropertyManagerImpl implements TransportPropertyManager,
|
|||||||
remote = new TransportProperties();
|
remote = new TransportProperties();
|
||||||
} else {
|
} else {
|
||||||
// Retrieve and parse the latest remote properties
|
// Retrieve and parse the latest remote properties
|
||||||
BdfList message =
|
BdfList message = clientHelper.getMessageAsList(txn,
|
||||||
clientHelper.getMessageAsList(txn, latest.messageId);
|
latest.messageId, false);
|
||||||
remote = parseProperties(message);
|
remote = parseProperties(message);
|
||||||
}
|
}
|
||||||
// Merge in any discovered properties
|
// Merge in any discovered properties
|
||||||
@@ -317,7 +317,7 @@ class TransportPropertyManagerImpl implements TransportPropertyManager,
|
|||||||
changed = true;
|
changed = true;
|
||||||
} else {
|
} else {
|
||||||
BdfList message = clientHelper.getMessageAsList(txn,
|
BdfList message = clientHelper.getMessageAsList(txn,
|
||||||
latest.messageId);
|
latest.messageId, false);
|
||||||
TransportProperties old = parseProperties(message);
|
TransportProperties old = parseProperties(message);
|
||||||
merged = new TransportProperties(old);
|
merged = new TransportProperties(old);
|
||||||
for (Entry<String, String> e : p.entrySet()) {
|
for (Entry<String, String> e : p.entrySet()) {
|
||||||
|
|||||||
@@ -27,7 +27,10 @@ class TransportPropertyValidator extends BdfMessageValidator {
|
|||||||
|
|
||||||
TransportPropertyValidator(ClientHelper clientHelper,
|
TransportPropertyValidator(ClientHelper clientHelper,
|
||||||
MetadataEncoder metadataEncoder, Clock clock) {
|
MetadataEncoder metadataEncoder, Clock clock) {
|
||||||
super(clientHelper, metadataEncoder, clock);
|
// Accept transport properties in non-canonical form
|
||||||
|
// TODO: Remove this after a reasonable migration period
|
||||||
|
// (added 2023-02-17)
|
||||||
|
super(clientHelper, metadataEncoder, clock, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -0,0 +1,42 @@
|
|||||||
|
package org.briarproject.bramble.qrcode;
|
||||||
|
|
||||||
|
import org.briarproject.bramble.api.Pair;
|
||||||
|
import org.briarproject.bramble.api.keyagreement.KeyAgreementConstants;
|
||||||
|
import org.briarproject.bramble.api.mailbox.MailboxConstants;
|
||||||
|
import org.briarproject.bramble.api.qrcode.QrCodeClassifier;
|
||||||
|
import org.briarproject.nullsafety.NotNullByDefault;
|
||||||
|
|
||||||
|
import javax.annotation.concurrent.Immutable;
|
||||||
|
import javax.inject.Inject;
|
||||||
|
|
||||||
|
import static org.briarproject.bramble.api.qrcode.QrCodeClassifier.QrCodeType.BQP;
|
||||||
|
import static org.briarproject.bramble.api.qrcode.QrCodeClassifier.QrCodeType.MAILBOX;
|
||||||
|
import static org.briarproject.bramble.api.qrcode.QrCodeClassifier.QrCodeType.UNKNOWN;
|
||||||
|
import static org.briarproject.bramble.util.StringUtils.ISO_8859_1;
|
||||||
|
|
||||||
|
@Immutable
|
||||||
|
@NotNullByDefault
|
||||||
|
class QrCodeClassifierImpl implements QrCodeClassifier {
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
QrCodeClassifierImpl() {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Pair<QrCodeType, Integer> classifyQrCode(String payload) {
|
||||||
|
byte[] bytes = payload.getBytes(ISO_8859_1);
|
||||||
|
if (bytes.length == 0) return new Pair<>(UNKNOWN, 0);
|
||||||
|
// If this is a Bramble QR code then the first byte encodes the
|
||||||
|
// format ID (3 bits) and version (5 bits)
|
||||||
|
int formatIdAndVersion = bytes[0] & 0xFF;
|
||||||
|
int formatId = formatIdAndVersion >> 5;
|
||||||
|
int formatVersion = formatIdAndVersion & 0x1F;
|
||||||
|
if (formatId == KeyAgreementConstants.QR_FORMAT_ID) {
|
||||||
|
return new Pair<>(BQP, formatVersion);
|
||||||
|
}
|
||||||
|
if (formatId == MailboxConstants.QR_FORMAT_ID) {
|
||||||
|
return new Pair<>(MAILBOX, formatVersion);
|
||||||
|
}
|
||||||
|
return new Pair<>(UNKNOWN, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
package org.briarproject.bramble.qrcode;
|
||||||
|
|
||||||
|
import org.briarproject.bramble.api.qrcode.QrCodeClassifier;
|
||||||
|
|
||||||
|
import dagger.Module;
|
||||||
|
import dagger.Provides;
|
||||||
|
|
||||||
|
@Module
|
||||||
|
public class QrCodeModule {
|
||||||
|
|
||||||
|
@Provides
|
||||||
|
QrCodeClassifier provideQrCodeClassifier(
|
||||||
|
QrCodeClassifierImpl qrCodeClassifier) {
|
||||||
|
return qrCodeClassifier;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -30,6 +30,7 @@ import static org.briarproject.bramble.api.sync.RecordTypes.OFFER;
|
|||||||
import static org.briarproject.bramble.api.sync.RecordTypes.PRIORITY;
|
import static org.briarproject.bramble.api.sync.RecordTypes.PRIORITY;
|
||||||
import static org.briarproject.bramble.api.sync.RecordTypes.REQUEST;
|
import static org.briarproject.bramble.api.sync.RecordTypes.REQUEST;
|
||||||
import static org.briarproject.bramble.api.sync.RecordTypes.VERSIONS;
|
import static org.briarproject.bramble.api.sync.RecordTypes.VERSIONS;
|
||||||
|
import static org.briarproject.bramble.api.sync.SyncConstants.MAX_MESSAGE_LENGTH;
|
||||||
import static org.briarproject.bramble.api.sync.SyncConstants.MAX_SUPPORTED_VERSIONS;
|
import static org.briarproject.bramble.api.sync.SyncConstants.MAX_SUPPORTED_VERSIONS;
|
||||||
import static org.briarproject.bramble.api.sync.SyncConstants.MESSAGE_HEADER_LENGTH;
|
import static org.briarproject.bramble.api.sync.SyncConstants.MESSAGE_HEADER_LENGTH;
|
||||||
import static org.briarproject.bramble.api.sync.SyncConstants.PRIORITY_NONCE_BYTES;
|
import static org.briarproject.bramble.api.sync.SyncConstants.PRIORITY_NONCE_BYTES;
|
||||||
@@ -126,6 +127,8 @@ class SyncRecordReaderImpl implements SyncRecordReader {
|
|||||||
byte[] payload = nextRecord.getPayload();
|
byte[] payload = nextRecord.getPayload();
|
||||||
if (payload.length <= MESSAGE_HEADER_LENGTH)
|
if (payload.length <= MESSAGE_HEADER_LENGTH)
|
||||||
throw new FormatException();
|
throw new FormatException();
|
||||||
|
if (payload.length > MAX_MESSAGE_LENGTH)
|
||||||
|
throw new FormatException();
|
||||||
// Validate timestamp
|
// Validate timestamp
|
||||||
long timestamp = ByteUtils.readUint64(payload, UniqueId.LENGTH);
|
long timestamp = ByteUtils.readUint64(payload, UniqueId.LENGTH);
|
||||||
if (timestamp < 0) throw new FormatException();
|
if (timestamp < 0) throw new FormatException();
|
||||||
|
|||||||
@@ -32,8 +32,7 @@ class SessionParserImpl implements SessionParser {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Session parseSession(BdfDictionary meta) throws FormatException {
|
public Session parseSession(BdfDictionary meta) throws FormatException {
|
||||||
State state =
|
State state = State.fromValue(meta.getInt(SESSION_KEY_STATE));
|
||||||
State.fromValue(meta.getLong(SESSION_KEY_STATE).intValue());
|
|
||||||
|
|
||||||
MessageId lastLocalMessageId = null;
|
MessageId lastLocalMessageId = null;
|
||||||
byte[] lastLocalMessageIdBytes =
|
byte[] lastLocalMessageIdBytes =
|
||||||
@@ -56,9 +55,9 @@ class SessionParserImpl implements SessionParser {
|
|||||||
Long localTimestamp = meta.getOptionalLong(SESSION_KEY_LOCAL_TIMESTAMP);
|
Long localTimestamp = meta.getOptionalLong(SESSION_KEY_LOCAL_TIMESTAMP);
|
||||||
|
|
||||||
KeySetId keySetId = null;
|
KeySetId keySetId = null;
|
||||||
Long keySetIdLong = meta.getOptionalLong(SESSION_KEY_KEY_SET_ID);
|
Integer keySetIdInt = meta.getOptionalInt(SESSION_KEY_KEY_SET_ID);
|
||||||
if (keySetIdLong != null) {
|
if (keySetIdInt != null) {
|
||||||
keySetId = new KeySetId(keySetIdLong.intValue());
|
keySetId = new KeySetId(keySetIdInt);
|
||||||
}
|
}
|
||||||
|
|
||||||
return new Session(state, lastLocalMessageId, localKeyPair,
|
return new Session(state, lastLocalMessageId, localKeyPair,
|
||||||
|
|||||||
@@ -177,8 +177,8 @@ class TransportKeyAgreementManagerImpl extends BdfIncomingMessageHook
|
|||||||
protected DeliveryAction incomingMessage(Transaction txn, Message m,
|
protected DeliveryAction incomingMessage(Transaction txn, Message m,
|
||||||
BdfList body, BdfDictionary meta)
|
BdfList body, BdfDictionary meta)
|
||||||
throws DbException, FormatException {
|
throws DbException, FormatException {
|
||||||
MessageType type = MessageType.fromValue(
|
MessageType type =
|
||||||
meta.getLong(MSG_KEY_MESSAGE_TYPE).intValue());
|
MessageType.fromValue(meta.getInt(MSG_KEY_MESSAGE_TYPE));
|
||||||
TransportId t = new TransportId(meta.getString(MSG_KEY_TRANSPORT_ID));
|
TransportId t = new TransportId(meta.getString(MSG_KEY_TRANSPORT_ID));
|
||||||
if (LOG.isLoggable(INFO)) {
|
if (LOG.isLoggable(INFO)) {
|
||||||
LOG.info("Received " + type + " message for " + t);
|
LOG.info("Received " + type + " message for " + t);
|
||||||
|
|||||||
@@ -42,7 +42,7 @@ class TransportKeyAgreementValidator extends BdfMessageValidator {
|
|||||||
@Override
|
@Override
|
||||||
protected BdfMessageContext validateMessage(Message m, Group g,
|
protected BdfMessageContext validateMessage(Message m, Group g,
|
||||||
BdfList body) throws FormatException {
|
BdfList body) throws FormatException {
|
||||||
MessageType type = MessageType.fromValue(body.getLong(0).intValue());
|
MessageType type = MessageType.fromValue(body.getInt(0));
|
||||||
if (type == KEY) return validateKeyMessage(m.getTimestamp(), body);
|
if (type == KEY) return validateKeyMessage(m.getTimestamp(), body);
|
||||||
else if (type == ACTIVATE) return validateActivateMessage(body);
|
else if (type == ACTIVATE) return validateActivateMessage(body);
|
||||||
else throw new AssertionError();
|
else throw new AssertionError();
|
||||||
|
|||||||
@@ -301,8 +301,8 @@ class ClientVersioningManagerImpl implements ClientVersioningManager,
|
|||||||
for (int i = 0; i < size; i++) {
|
for (int i = 0; i < size; i++) {
|
||||||
BdfList cv = body.getList(i);
|
BdfList cv = body.getList(i);
|
||||||
ClientId clientId = new ClientId(cv.getString(0));
|
ClientId clientId = new ClientId(cv.getString(0));
|
||||||
int majorVersion = cv.getLong(1).intValue();
|
int majorVersion = cv.getInt(1);
|
||||||
int minorVersion = cv.getLong(2).intValue();
|
int minorVersion = cv.getInt(2);
|
||||||
parsed.add(new ClientVersion(clientId, majorVersion, minorVersion));
|
parsed.add(new ClientVersion(clientId, majorVersion, minorVersion));
|
||||||
}
|
}
|
||||||
return parsed;
|
return parsed;
|
||||||
@@ -408,8 +408,8 @@ class ClientVersioningManagerImpl implements ClientVersioningManager,
|
|||||||
throws FormatException {
|
throws FormatException {
|
||||||
// Client ID, major version, minor version, active
|
// Client ID, major version, minor version, active
|
||||||
ClientId clientId = new ClientId(clientState.getString(0));
|
ClientId clientId = new ClientId(clientState.getString(0));
|
||||||
int majorVersion = clientState.getLong(1).intValue();
|
int majorVersion = clientState.getInt(1);
|
||||||
int minorVersion = clientState.getLong(2).intValue();
|
int minorVersion = clientState.getInt(2);
|
||||||
boolean active = clientState.getBoolean(3);
|
boolean active = clientState.getBoolean(3);
|
||||||
return new ClientState(clientId, majorVersion, minorVersion, active);
|
return new ClientState(clientId, majorVersion, minorVersion, active);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -43,9 +43,9 @@ class ClientVersioningValidator extends BdfMessageValidator {
|
|||||||
checkSize(clientState, 4);
|
checkSize(clientState, 4);
|
||||||
String clientId = clientState.getString(0);
|
String clientId = clientState.getString(0);
|
||||||
checkLength(clientId, 1, MAX_CLIENT_ID_LENGTH);
|
checkLength(clientId, 1, MAX_CLIENT_ID_LENGTH);
|
||||||
int majorVersion = clientState.getLong(1).intValue();
|
int majorVersion = clientState.getInt(1);
|
||||||
if (majorVersion < 0) throw new FormatException();
|
if (majorVersion < 0) throw new FormatException();
|
||||||
int minorVersion = clientState.getLong(2).intValue();
|
int minorVersion = clientState.getInt(2);
|
||||||
if (minorVersion < 0) throw new FormatException();
|
if (minorVersion < 0) throw new FormatException();
|
||||||
clientState.getBoolean(3);
|
clientState.getBoolean(3);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,22 +10,21 @@ d Bridge obfs4 146.57.248.225:22 10A6CD36A537FCE513A322361547444B393989F0 cert=K
|
|||||||
d Bridge obfs4 45.145.95.6:27015 C5B7CD6946FF10C5B3E89691A7D3F2C122D2117C cert=TD7PbUO0/0k6xYHMPW3vJxICfkMZNdkRrb63Zhl5j9dW3iRGiCx0A7mPhe5T2EDzQ35+Zw iat-mode=0
|
d Bridge obfs4 45.145.95.6:27015 C5B7CD6946FF10C5B3E89691A7D3F2C122D2117C cert=TD7PbUO0/0k6xYHMPW3vJxICfkMZNdkRrb63Zhl5j9dW3iRGiCx0A7mPhe5T2EDzQ35+Zw iat-mode=0
|
||||||
d Bridge obfs4 51.222.13.177:80 5EDAC3B810E12B01F6FD8050D2FD3E277B289A08 cert=2uplIpLQ0q9+0qMFrK5pkaYRDOe460LL9WHBvatgkuRr/SL31wBOEupaMMJ6koRE6Ld0ew iat-mode=0
|
d Bridge obfs4 51.222.13.177:80 5EDAC3B810E12B01F6FD8050D2FD3E277B289A08 cert=2uplIpLQ0q9+0qMFrK5pkaYRDOe460LL9WHBvatgkuRr/SL31wBOEupaMMJ6koRE6Ld0ew iat-mode=0
|
||||||
n Bridge obfs4 185.181.11.86:443 A961609729E7FDF520B4E81F1F1B8FA1045285C3 cert=e5faG9Zk4Ni+e7z2YgGfevyKPQlMvkVGi4ublSsHYjaBovKeNXpOhbeFxzbZZoAzxAoGUQ iat-mode=0
|
n Bridge obfs4 185.181.11.86:443 A961609729E7FDF520B4E81F1F1B8FA1045285C3 cert=e5faG9Zk4Ni+e7z2YgGfevyKPQlMvkVGi4ublSsHYjaBovKeNXpOhbeFxzbZZoAzxAoGUQ iat-mode=0
|
||||||
n Bridge obfs4 93.95.226.151:41185 460B0CFFC0CF1D965F3DE064E08BA1915E7C916A cert=inluPzp5Jp5OzZar1eQb4dcQ/YlAj/v0kHAUCoCr3rmLt03+pVuVTjoH4mRy4+acXpn+Gw iat-mode=0
|
|
||||||
n Bridge obfs4 120.29.217.52:5223 40FE3DB9800272F9CDC76422F8ED7883280EE96D cert=/71PS4l8c/XJ4DIItlH9xMqNvPFg2RUTrHvPlQWh48u5et8h/yyyjCcYphUadDsfBWpaGQ iat-mode=0
|
n Bridge obfs4 120.29.217.52:5223 40FE3DB9800272F9CDC76422F8ED7883280EE96D cert=/71PS4l8c/XJ4DIItlH9xMqNvPFg2RUTrHvPlQWh48u5et8h/yyyjCcYphUadDsfBWpaGQ iat-mode=0
|
||||||
n Bridge obfs4 185.177.207.138:8443 53716FE26F23C8C6A71A2BC5D9D8DC64747278C7 cert=6jcYVilMEzxdsWghSrQFpYYJlkkir/GPIXw/EnddUK3S8ToVpMG8u1SwMOEdEs735RrMHw iat-mode=0
|
n Bridge obfs4 185.177.207.138:8443 53716FE26F23C8C6A71A2BC5D9D8DC64747278C7 cert=6jcYVilMEzxdsWghSrQFpYYJlkkir/GPIXw/EnddUK3S8ToVpMG8u1SwMOEdEs735RrMHw iat-mode=0
|
||||||
n Bridge obfs4 104.168.68.90:443 ED55B3C321E44EA7E50EF568C8A63CF75E89A58C cert=fgonxDvltTp8nmcOE9sUG94eOAALxETVVXAwnTZJLPpf7rjPuTp+abKl4VyFkxfcLRr5KQ iat-mode=0
|
|
||||||
n Bridge obfs4 45.142.181.131:42069 6EBCF6B02DA2B982F4080A7119D737366AFB74FA cert=9HyWH/BCwWzNirZdTQtluCgJk+gFhpOqydIuyQ1iDvpnqsAynKF+zcPE/INZFefm86UlBg iat-mode=0
|
n Bridge obfs4 45.142.181.131:42069 6EBCF6B02DA2B982F4080A7119D737366AFB74FA cert=9HyWH/BCwWzNirZdTQtluCgJk+gFhpOqydIuyQ1iDvpnqsAynKF+zcPE/INZFefm86UlBg iat-mode=0
|
||||||
n Bridge obfs4 85.214.28.204:47111 78A36E46BB082A471848239D3F4390A8F8C6084D cert=96sr3eaUFBDu4wFVAQIfNFElh0UNuutJ/3/Fh2Vu2PHfacQ8bwfY02bwG351U8BZpLnfUQ iat-mode=0
|
|
||||||
n Bridge obfs4 152.67.77.101:4096 B82DB9CDDF887AB8A859420E07DF298E30AF8A6E cert=21OWn3yFo+hulmQNAOtF5uwwOqWtdT5PrLhk8BG9DpOd0/k5DEkQEYPyDdXbS9nZ0E5BJA iat-mode=0
|
n Bridge obfs4 152.67.77.101:4096 B82DB9CDDF887AB8A859420E07DF298E30AF8A6E cert=21OWn3yFo+hulmQNAOtF5uwwOqWtdT5PrLhk8BG9DpOd0/k5DEkQEYPyDdXbS9nZ0E5BJA iat-mode=0
|
||||||
n Bridge obfs4 185.103.252.72:443 75F15E9339FF572F88F5588D429FEA379744BC53 cert=nOZ/SaRE3L1dChvjfe0Ks/wM/F8iFhwd3g2G5zgtcLB8x+wiZRWCwjRrbbiQyb3Gh2mxRQ iat-mode=0
|
|
||||||
n Bridge obfs4 76.255.201.112:8888 96CF36C2ECCFB7376AB6BE905BECD2C2AE8AEFCD cert=+q0pjaiM0JMqHL/BKqCRD+pjflaw/S406eUDF7CnFgamvQW3l2HVLJhQ6uX9P8zff0PLGg iat-mode=0
|
|
||||||
n Bridge obfs4 94.142.246.132:8088 135C158527AA9FE9A2F26EC515EB6999D813D347 cert=wTUz0/5FhAZRkitil5MprGbSF3JzjxjxI1kAmxAdSeDy98NgcLr11f/qUXWDC76Y97RiSg iat-mode=0
|
n Bridge obfs4 94.142.246.132:8088 135C158527AA9FE9A2F26EC515EB6999D813D347 cert=wTUz0/5FhAZRkitil5MprGbSF3JzjxjxI1kAmxAdSeDy98NgcLr11f/qUXWDC76Y97RiSg iat-mode=0
|
||||||
n Bridge obfs4 20.102.79.78:22022 B5705F7E616DAB0F477E3E1ADC23E40413F683FE cert=1Cc/hwPtPjzFKGHVOP0j/qmBgnvquRx8+im35/u5TIYjDQ3FlMfA5VvTrQ/hbX8BZZooLQ iat-mode=0
|
|
||||||
n Bridge obfs4 207.154.242.137:80 8E67A1B2A342652EE27376BD61BECF5806700E7F cert=qUrR9fan3XPNGNOwn9WGlXLJNZZx0grXH4AZXR+yoBbtbbj5Ak1n4a7TtjYgXcWcs/gHXw iat-mode=0
|
|
||||||
n Bridge obfs4 152.70.180.20:1993 3327C43587E66AD5F874C4234A1D72C938AD7318 cert=s7xLRUO2psaX7TMUP2YhXdxItR4U6K7D+E3gQaS/+yWUppevtazIibq4dN1g5Reu6dD2QQ iat-mode=0
|
n Bridge obfs4 152.70.180.20:1993 3327C43587E66AD5F874C4234A1D72C938AD7318 cert=s7xLRUO2psaX7TMUP2YhXdxItR4U6K7D+E3gQaS/+yWUppevtazIibq4dN1g5Reu6dD2QQ iat-mode=0
|
||||||
n Bridge obfs4 144.202.12.254:10002 4E220F45CD404C8A3082A36326A5ED19BB8D4404 cert=iLz5YYWO4pUw7U7MRNOSvE0qO+IVeE4kVfFVWPO3coH3FmZtrkvlaTklfXxHZaCcXWBgaA iat-mode=0
|
n Bridge obfs4 144.202.12.254:10002 4E220F45CD404C8A3082A36326A5ED19BB8D4404 cert=iLz5YYWO4pUw7U7MRNOSvE0qO+IVeE4kVfFVWPO3coH3FmZtrkvlaTklfXxHZaCcXWBgaA iat-mode=0
|
||||||
n Bridge obfs4 15.235.47.204:42058 869133925B3CD07683BDF01805C36448D090CE88 cert=PFwh4mzZlSTUdcEskpe20t998n5jbr81s+XoX7gmazqzUGHNhkendK5K1j2gOxesz9AkBw iat-mode=0
|
n Bridge obfs4 109.14.168.159:5082 BFE1416DEFFE969581F016A4A319A87FFB26BA91 cert=n3X1CDdKBPXPIzfKh83p3ydfMzb0AD9gKC+/gIpHb7+xjjAnYO9x3LT+T/MvOIfAXxYySg iat-mode=0
|
||||||
n Bridge obfs4 51.75.93.136:45532 8402B84833527BC249B21AC885134197E624FB5A cert=LwXEf/Dgo0tKdMJByXdlvWiJqyyPw4T284Cg5qygDuIJJNFuz3ED9UhGil6H4Of3gM7wSg iat-mode=0
|
n Bridge obfs4 185.177.207.132:8443 4FB781F7A9DD39DA53A7996907817FC479874D19 cert=UL2gCAXWW5kEWY4TQ0lNeu6OAmzh40bXYVhMnTWVG8USnyy/zEKGSIPgmwTDMumWr9c1Pg iat-mode=0
|
||||||
|
n Bridge obfs4 213.108.110.149:7499 519344140473CF91030B08F91521F9A6C144ED6C cert=k9fSL/d491qAkGmi2VeSwVlfuyO02jBeN54qxzzQISxpfm3b+a6kJpo8/Bfy1ACbHZIJUg iat-mode=0
|
||||||
|
n Bridge obfs4 158.174.114.97:3456 32665CD4CBE19092CA47A53D317B8BFF5810441C cert=ne5Zt0TcMedSGmFwAs/AV6J6E9Hn7mG5mR6vQNpEfyuCZK1VRpQvU1LvvtesSu4CXqZtYQ iat-mode=0
|
||||||
|
n Bridge obfs4 64.4.175.62:8000 8B72740D150795ACB5101AA5F95D1ACDA4FE6B3E cert=vduuNhJ5U/8hjZmllP6AFfXSlSZsnrimdR8Tm8DY9dxWS4n2j92fNc0qHihUwRqwcOfIcg iat-mode=0
|
||||||
|
n Bridge obfs4 82.64.115.17:990 B08238781C2CD80DBD95AEABEB6F6C75F2E2CEB6 cert=1udeMlFNs3sJ20zwpPE6nShZqqwDb3F1ET4KzfSfD+fktkue9zNx9H3t+yLCPAsg+6UTUA iat-mode=1
|
||||||
|
n Bridge obfs4 87.161.120.147:9292 9418EEBE8AEAE32CC381AF51610366E8B24651E0 cert=DFRm74qsD1i2/ypaGochpX6CS1j9JTFAKEYaHXrgrx6M2LG5Cvppdt3Ob7lULfhqgtAUdg iat-mode=0
|
||||||
|
n Bridge obfs4 157.90.245.231:8599 C23CD468EC04555E2B37BE81A771E681049DEA6A cert=UsmDelrbwg4jc6BMvZJ0TS8klUIa2qkbRu3xwQc3ZXPEgpMqyTYUxcVwyPbIU5KmAHsmAA iat-mode=0
|
||||||
v Bridge 92.243.15.235:9001 477EAD3C04036B48235F1F27FC91420A286A4B7F
|
v Bridge 92.243.15.235:9001 477EAD3C04036B48235F1F27FC91420A286A4B7F
|
||||||
v Bridge 213.108.108.145:17674 A39C0FE47963B6E8CFE9815549864DE544935A31
|
v Bridge 213.108.108.145:17674 A39C0FE47963B6E8CFE9815549864DE544935A31
|
||||||
v Bridge 213.196.191.96:9060 05E222E2A8C234234FE0CEB58B08A93B8FC360DB
|
v Bridge 213.196.191.96:9060 05E222E2A8C234234FE0CEB58B08A93B8FC360DB
|
||||||
|
|||||||
@@ -20,7 +20,6 @@ import java.io.FileInputStream;
|
|||||||
import java.io.FileOutputStream;
|
import java.io.FileOutputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStreamReader;
|
import java.io.InputStreamReader;
|
||||||
import java.nio.charset.Charset;
|
|
||||||
|
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
|
|
||||||
@@ -34,6 +33,7 @@ import static org.briarproject.bramble.test.TestUtils.getIdentity;
|
|||||||
import static org.briarproject.bramble.test.TestUtils.getRandomBytes;
|
import static org.briarproject.bramble.test.TestUtils.getRandomBytes;
|
||||||
import static org.briarproject.bramble.test.TestUtils.getSecretKey;
|
import static org.briarproject.bramble.test.TestUtils.getSecretKey;
|
||||||
import static org.briarproject.bramble.test.TestUtils.getTestDirectory;
|
import static org.briarproject.bramble.test.TestUtils.getTestDirectory;
|
||||||
|
import static org.briarproject.bramble.util.StringUtils.UTF_8;
|
||||||
import static org.briarproject.bramble.util.StringUtils.getRandomString;
|
import static org.briarproject.bramble.util.StringUtils.getRandomString;
|
||||||
import static org.briarproject.bramble.util.StringUtils.toHexString;
|
import static org.briarproject.bramble.util.StringUtils.toHexString;
|
||||||
import static org.junit.Assert.assertArrayEquals;
|
import static org.junit.Assert.assertArrayEquals;
|
||||||
@@ -342,7 +342,7 @@ public class AccountManagerImplTest extends BrambleMockTestCase {
|
|||||||
private void storeDatabaseKey(File f, String hex) throws IOException {
|
private void storeDatabaseKey(File f, String hex) throws IOException {
|
||||||
f.getParentFile().mkdirs();
|
f.getParentFile().mkdirs();
|
||||||
FileOutputStream out = new FileOutputStream(f);
|
FileOutputStream out = new FileOutputStream(f);
|
||||||
out.write(hex.getBytes(Charset.forName("UTF-8")));
|
out.write(hex.getBytes(UTF_8));
|
||||||
out.flush();
|
out.flush();
|
||||||
out.close();
|
out.close();
|
||||||
}
|
}
|
||||||
@@ -350,7 +350,7 @@ public class AccountManagerImplTest extends BrambleMockTestCase {
|
|||||||
@Nullable
|
@Nullable
|
||||||
private String loadDatabaseKey(File f) throws IOException {
|
private String loadDatabaseKey(File f) throws IOException {
|
||||||
BufferedReader reader = new BufferedReader(new InputStreamReader(
|
BufferedReader reader = new BufferedReader(new InputStreamReader(
|
||||||
new FileInputStream(f), Charset.forName("UTF-8")));
|
new FileInputStream(f), UTF_8));
|
||||||
String hex = reader.readLine();
|
String hex = reader.readLine();
|
||||||
reader.close();
|
reader.close();
|
||||||
return hex;
|
return hex;
|
||||||
|
|||||||
@@ -56,7 +56,7 @@ public class BdfMessageValidatorTest extends ValidatorTestCase {
|
|||||||
context.checking(new Expectations() {{
|
context.checking(new Expectations() {{
|
||||||
oneOf(clock).currentTimeMillis();
|
oneOf(clock).currentTimeMillis();
|
||||||
will(returnValue(timestamp - MAX_CLOCK_DIFFERENCE));
|
will(returnValue(timestamp - MAX_CLOCK_DIFFERENCE));
|
||||||
oneOf(clientHelper).toList(message.getBody());
|
oneOf(clientHelper).toList(message, true);
|
||||||
will(returnValue(body));
|
will(returnValue(body));
|
||||||
oneOf(metadataEncoder).encode(dictionary);
|
oneOf(metadataEncoder).encode(dictionary);
|
||||||
will(returnValue(meta));
|
will(returnValue(meta));
|
||||||
@@ -86,7 +86,7 @@ public class BdfMessageValidatorTest extends ValidatorTestCase {
|
|||||||
context.checking(new Expectations() {{
|
context.checking(new Expectations() {{
|
||||||
oneOf(clock).currentTimeMillis();
|
oneOf(clock).currentTimeMillis();
|
||||||
will(returnValue(timestamp));
|
will(returnValue(timestamp));
|
||||||
oneOf(clientHelper).toList(shortMessage.getBody());
|
oneOf(clientHelper).toList(shortMessage, true);
|
||||||
will(returnValue(body));
|
will(returnValue(body));
|
||||||
oneOf(metadataEncoder).encode(dictionary);
|
oneOf(metadataEncoder).encode(dictionary);
|
||||||
will(returnValue(meta));
|
will(returnValue(meta));
|
||||||
@@ -114,7 +114,7 @@ public class BdfMessageValidatorTest extends ValidatorTestCase {
|
|||||||
context.checking(new Expectations() {{
|
context.checking(new Expectations() {{
|
||||||
oneOf(clock).currentTimeMillis();
|
oneOf(clock).currentTimeMillis();
|
||||||
will(returnValue(timestamp));
|
will(returnValue(timestamp));
|
||||||
oneOf(clientHelper).toList(message.getBody());
|
oneOf(clientHelper).toList(message, true);
|
||||||
will(throwException(new FormatException()));
|
will(throwException(new FormatException()));
|
||||||
}});
|
}});
|
||||||
|
|
||||||
@@ -126,7 +126,7 @@ public class BdfMessageValidatorTest extends ValidatorTestCase {
|
|||||||
context.checking(new Expectations() {{
|
context.checking(new Expectations() {{
|
||||||
oneOf(clock).currentTimeMillis();
|
oneOf(clock).currentTimeMillis();
|
||||||
will(returnValue(timestamp));
|
will(returnValue(timestamp));
|
||||||
oneOf(clientHelper).toList(message.getBody());
|
oneOf(clientHelper).toList(message, true);
|
||||||
will(returnValue(body));
|
will(returnValue(body));
|
||||||
}});
|
}});
|
||||||
|
|
||||||
|
|||||||
@@ -546,7 +546,7 @@ public class ClientHelperImplTest extends BrambleMockTestCase {
|
|||||||
|
|
||||||
context.checking(new Expectations() {{
|
context.checking(new Expectations() {{
|
||||||
oneOf(bdfReaderFactory)
|
oneOf(bdfReaderFactory)
|
||||||
.createReader(with(any(InputStream.class)));
|
.createReader(with(any(InputStream.class)), with(true));
|
||||||
will(returnValue(bdfReader));
|
will(returnValue(bdfReader));
|
||||||
oneOf(bdfReader).readList();
|
oneOf(bdfReader).readList();
|
||||||
will(returnValue(list));
|
will(returnValue(list));
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
package org.briarproject.bramble.data;
|
package org.briarproject.bramble.data;
|
||||||
|
|
||||||
|
import org.briarproject.bramble.api.FormatException;
|
||||||
import org.briarproject.bramble.test.BrambleTestCase;
|
import org.briarproject.bramble.test.BrambleTestCase;
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
@@ -31,11 +32,14 @@ public class BdfReaderImplFuzzingTest extends BrambleTestCase {
|
|||||||
buf[1] = 0x14; // Length 20 bytes
|
buf[1] = 0x14; // Length 20 bytes
|
||||||
in.reset();
|
in.reset();
|
||||||
BdfReaderImpl r = new BdfReaderImpl(in, DEFAULT_NESTED_LIMIT,
|
BdfReaderImpl r = new BdfReaderImpl(in, DEFAULT_NESTED_LIMIT,
|
||||||
DEFAULT_MAX_BUFFER_SIZE);
|
DEFAULT_MAX_BUFFER_SIZE, true);
|
||||||
int length = r.readString().length();
|
try {
|
||||||
assertTrue(length >= 0);
|
int length = r.readString().length();
|
||||||
assertTrue(length <= 20);
|
assertTrue(length <= 20);
|
||||||
assertTrue(r.eof());
|
assertTrue(r.eof());
|
||||||
|
} catch (FormatException e) {
|
||||||
|
// Expected when bytes are not valid UTF-8
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ import java.io.ByteArrayInputStream;
|
|||||||
import static org.briarproject.bramble.api.data.BdfDictionary.NULL_VALUE;
|
import static org.briarproject.bramble.api.data.BdfDictionary.NULL_VALUE;
|
||||||
import static org.briarproject.bramble.api.data.BdfReader.DEFAULT_MAX_BUFFER_SIZE;
|
import static org.briarproject.bramble.api.data.BdfReader.DEFAULT_MAX_BUFFER_SIZE;
|
||||||
import static org.briarproject.bramble.data.BdfReaderImpl.DEFAULT_NESTED_LIMIT;
|
import static org.briarproject.bramble.data.BdfReaderImpl.DEFAULT_NESTED_LIMIT;
|
||||||
|
import static org.briarproject.bramble.util.StringUtils.UTF_8;
|
||||||
import static org.briarproject.bramble.util.StringUtils.fromHexString;
|
import static org.briarproject.bramble.util.StringUtils.fromHexString;
|
||||||
import static org.briarproject.bramble.util.StringUtils.getRandomString;
|
import static org.briarproject.bramble.util.StringUtils.getRandomString;
|
||||||
import static org.briarproject.bramble.util.StringUtils.toHexString;
|
import static org.briarproject.bramble.util.StringUtils.toHexString;
|
||||||
@@ -88,6 +89,18 @@ public class BdfReaderImplTest extends BrambleTestCase {
|
|||||||
assertTrue(r.eof());
|
assertTrue(r.eof());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test(expected = FormatException.class)
|
||||||
|
public void testReadLong16CouldHaveBeenLong8Max() throws Exception {
|
||||||
|
setContents("22" + "007F");
|
||||||
|
r.readLong();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expected = FormatException.class)
|
||||||
|
public void testReadLong16CouldHaveBeenLong8Min() throws Exception {
|
||||||
|
setContents("22" + "FF80");
|
||||||
|
r.readLong();
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testSkipLong16() throws Exception {
|
public void testSkipLong16() throws Exception {
|
||||||
setContents("22" + "0080");
|
setContents("22" + "0080");
|
||||||
@@ -106,6 +119,18 @@ public class BdfReaderImplTest extends BrambleTestCase {
|
|||||||
assertTrue(r.eof());
|
assertTrue(r.eof());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test(expected = FormatException.class)
|
||||||
|
public void testReadLong32CouldHaveBeenLong16Max() throws Exception {
|
||||||
|
setContents("24" + "00007FFF");
|
||||||
|
r.readLong();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expected = FormatException.class)
|
||||||
|
public void testReadLong32CouldHaveBeenLong16Min() throws Exception {
|
||||||
|
setContents("24" + "FFFF8000");
|
||||||
|
r.readLong();
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testSkipLong32() throws Exception {
|
public void testSkipLong32() throws Exception {
|
||||||
setContents("24" + "00008000");
|
setContents("24" + "00008000");
|
||||||
@@ -124,13 +149,48 @@ public class BdfReaderImplTest extends BrambleTestCase {
|
|||||||
assertTrue(r.eof());
|
assertTrue(r.eof());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test(expected = FormatException.class)
|
||||||
|
public void testReadLong64CouldHaveBeenLong32Max() throws Exception {
|
||||||
|
setContents("28" + "000000007FFFFFFF");
|
||||||
|
r.readLong();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expected = FormatException.class)
|
||||||
|
public void testReadLong64CouldHaveBeenLong32Min() throws Exception {
|
||||||
|
setContents("28" + "FFFFFFFF80000000");
|
||||||
|
r.readLong();
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testSkipLong() throws Exception {
|
public void testSkipLong64() throws Exception {
|
||||||
setContents("28" + "0000000080000000");
|
setContents("28" + "0000000080000000");
|
||||||
r.skipLong();
|
r.skipLong();
|
||||||
assertTrue(r.eof());
|
assertTrue(r.eof());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testReadInt() throws Exception {
|
||||||
|
setContents("21" + "7F" + "21" + "80"
|
||||||
|
+ "22" + "7FFF" + "22" + "8000"
|
||||||
|
+ "24" + "7FFFFFFF" + "24" + "80000000");
|
||||||
|
assertEquals(Byte.MAX_VALUE, r.readInt());
|
||||||
|
assertEquals(Byte.MIN_VALUE, r.readInt());
|
||||||
|
assertEquals(Short.MAX_VALUE, r.readInt());
|
||||||
|
assertEquals(Short.MIN_VALUE, r.readInt());
|
||||||
|
assertEquals(Integer.MAX_VALUE, r.readInt());
|
||||||
|
assertEquals(Integer.MIN_VALUE, r.readInt());
|
||||||
|
assertTrue(r.eof());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testSkipInt() throws Exception {
|
||||||
|
setContents("21" + "7F" + "22" + "7FFF" + "24" + "7FFFFFFF");
|
||||||
|
r.skipInt();
|
||||||
|
r.skipInt();
|
||||||
|
r.skipInt();
|
||||||
|
assertTrue(r.eof());
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testReadDouble() throws Exception {
|
public void testReadDouble() throws Exception {
|
||||||
// http://babbage.cs.qc.edu/IEEE-754/Decimal.html
|
// http://babbage.cs.qc.edu/IEEE-754/Decimal.html
|
||||||
@@ -162,7 +222,7 @@ public class BdfReaderImplTest extends BrambleTestCase {
|
|||||||
@Test
|
@Test
|
||||||
public void testReadString8() throws Exception {
|
public void testReadString8() throws Exception {
|
||||||
String longest = getRandomString(Byte.MAX_VALUE);
|
String longest = getRandomString(Byte.MAX_VALUE);
|
||||||
String longHex = toHexString(longest.getBytes("UTF-8"));
|
String longHex = toHexString(longest.getBytes(UTF_8));
|
||||||
// "foo", the empty string, and 127 random letters
|
// "foo", the empty string, and 127 random letters
|
||||||
setContents("41" + "03" + "666F6F" + "41" + "00" +
|
setContents("41" + "03" + "666F6F" + "41" + "00" +
|
||||||
"41" + "7F" + longHex);
|
"41" + "7F" + longHex);
|
||||||
@@ -186,7 +246,7 @@ public class BdfReaderImplTest extends BrambleTestCase {
|
|||||||
@Test
|
@Test
|
||||||
public void testSkipString8() throws Exception {
|
public void testSkipString8() throws Exception {
|
||||||
String longest = getRandomString(Byte.MAX_VALUE);
|
String longest = getRandomString(Byte.MAX_VALUE);
|
||||||
String longHex = toHexString(longest.getBytes("UTF-8"));
|
String longHex = toHexString(longest.getBytes(UTF_8));
|
||||||
// "foo", the empty string, and 127 random letters
|
// "foo", the empty string, and 127 random letters
|
||||||
setContents("41" + "03" + "666F6F" + "41" + "00" +
|
setContents("41" + "03" + "666F6F" + "41" + "00" +
|
||||||
"41" + "7F" + longHex);
|
"41" + "7F" + longHex);
|
||||||
@@ -199,9 +259,9 @@ public class BdfReaderImplTest extends BrambleTestCase {
|
|||||||
@Test
|
@Test
|
||||||
public void testReadString16() throws Exception {
|
public void testReadString16() throws Exception {
|
||||||
String shortest = getRandomString(Byte.MAX_VALUE + 1);
|
String shortest = getRandomString(Byte.MAX_VALUE + 1);
|
||||||
String shortHex = toHexString(shortest.getBytes("UTF-8"));
|
String shortHex = toHexString(shortest.getBytes(UTF_8));
|
||||||
String longest = getRandomString(Short.MAX_VALUE);
|
String longest = getRandomString(Short.MAX_VALUE);
|
||||||
String longHex = toHexString(longest.getBytes("UTF-8"));
|
String longHex = toHexString(longest.getBytes(UTF_8));
|
||||||
// 128 random letters and 2^15 -1 random letters
|
// 128 random letters and 2^15 -1 random letters
|
||||||
setContents("42" + "0080" + shortHex + "42" + "7FFF" + longHex);
|
setContents("42" + "0080" + shortHex + "42" + "7FFF" + longHex);
|
||||||
assertEquals(shortest, r.readString());
|
assertEquals(shortest, r.readString());
|
||||||
@@ -213,7 +273,7 @@ public class BdfReaderImplTest extends BrambleTestCase {
|
|||||||
public void testReadString16ChecksMaxLength() throws Exception {
|
public void testReadString16ChecksMaxLength() throws Exception {
|
||||||
int maxBufferSize = Byte.MAX_VALUE + 1;
|
int maxBufferSize = Byte.MAX_VALUE + 1;
|
||||||
String valid = getRandomString(Byte.MAX_VALUE + 1);
|
String valid = getRandomString(Byte.MAX_VALUE + 1);
|
||||||
String validHex = toHexString(valid.getBytes("UTF-8"));
|
String validHex = toHexString(valid.getBytes(UTF_8));
|
||||||
String invalidhex = validHex + "20";
|
String invalidhex = validHex + "20";
|
||||||
// 128 random letters, the same plus a space
|
// 128 random letters, the same plus a space
|
||||||
setContents("42" + "0080" + validHex
|
setContents("42" + "0080" + validHex
|
||||||
@@ -223,12 +283,20 @@ public class BdfReaderImplTest extends BrambleTestCase {
|
|||||||
r.readString();
|
r.readString();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test(expected = FormatException.class)
|
||||||
|
public void testReadString16CouldHaveBeenString8() throws Exception {
|
||||||
|
String longest = getRandomString(Byte.MAX_VALUE);
|
||||||
|
String longHex = toHexString(longest.getBytes(UTF_8));
|
||||||
|
setContents("42" + "007F" + longHex);
|
||||||
|
r.readString();
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testSkipString16() throws Exception {
|
public void testSkipString16() throws Exception {
|
||||||
String shortest = getRandomString(Byte.MAX_VALUE + 1);
|
String shortest = getRandomString(Byte.MAX_VALUE + 1);
|
||||||
String shortHex = toHexString(shortest.getBytes("UTF-8"));
|
String shortHex = toHexString(shortest.getBytes(UTF_8));
|
||||||
String longest = getRandomString(Short.MAX_VALUE);
|
String longest = getRandomString(Short.MAX_VALUE);
|
||||||
String longHex = toHexString(longest.getBytes("UTF-8"));
|
String longHex = toHexString(longest.getBytes(UTF_8));
|
||||||
// 128 random letters and 2^15 - 1 random letters
|
// 128 random letters and 2^15 - 1 random letters
|
||||||
setContents("42" + "0080" + shortHex + "42" + "7FFF" + longHex);
|
setContents("42" + "0080" + shortHex + "42" + "7FFF" + longHex);
|
||||||
r.skipString();
|
r.skipString();
|
||||||
@@ -239,7 +307,7 @@ public class BdfReaderImplTest extends BrambleTestCase {
|
|||||||
@Test
|
@Test
|
||||||
public void testReadString32() throws Exception {
|
public void testReadString32() throws Exception {
|
||||||
String shortest = getRandomString(Short.MAX_VALUE + 1);
|
String shortest = getRandomString(Short.MAX_VALUE + 1);
|
||||||
String shortHex = toHexString(shortest.getBytes("UTF-8"));
|
String shortHex = toHexString(shortest.getBytes(UTF_8));
|
||||||
// 2^15 random letters
|
// 2^15 random letters
|
||||||
setContents("44" + "00008000" + shortHex);
|
setContents("44" + "00008000" + shortHex);
|
||||||
assertEquals(shortest, r.readString());
|
assertEquals(shortest, r.readString());
|
||||||
@@ -250,7 +318,7 @@ public class BdfReaderImplTest extends BrambleTestCase {
|
|||||||
public void testReadString32ChecksMaxLength() throws Exception {
|
public void testReadString32ChecksMaxLength() throws Exception {
|
||||||
int maxBufferSize = Short.MAX_VALUE + 1;
|
int maxBufferSize = Short.MAX_VALUE + 1;
|
||||||
String valid = getRandomString(maxBufferSize);
|
String valid = getRandomString(maxBufferSize);
|
||||||
String validHex = toHexString(valid.getBytes("UTF-8"));
|
String validHex = toHexString(valid.getBytes(UTF_8));
|
||||||
String invalidHex = validHex + "20";
|
String invalidHex = validHex + "20";
|
||||||
// 2^15 random letters, the same plus a space
|
// 2^15 random letters, the same plus a space
|
||||||
setContents("44" + "00008000" + validHex +
|
setContents("44" + "00008000" + validHex +
|
||||||
@@ -260,10 +328,18 @@ public class BdfReaderImplTest extends BrambleTestCase {
|
|||||||
r.readString();
|
r.readString();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test(expected = FormatException.class)
|
||||||
|
public void testReadString32CouldHaveBeenString16() throws Exception {
|
||||||
|
String longest = getRandomString(Short.MAX_VALUE);
|
||||||
|
String longHex = toHexString(longest.getBytes(UTF_8));
|
||||||
|
setContents("44" + "00007FFF" + longHex);
|
||||||
|
r.readString();
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testSkipString32() throws Exception {
|
public void testSkipString32() throws Exception {
|
||||||
String shortest = getRandomString(Short.MAX_VALUE + 1);
|
String shortest = getRandomString(Short.MAX_VALUE + 1);
|
||||||
String shortHex = toHexString(shortest.getBytes("UTF-8"));
|
String shortHex = toHexString(shortest.getBytes(UTF_8));
|
||||||
// 2^15 random letters, twice
|
// 2^15 random letters, twice
|
||||||
setContents("44" + "00008000" + shortHex +
|
setContents("44" + "00008000" + shortHex +
|
||||||
"44" + "00008000" + shortHex);
|
"44" + "00008000" + shortHex);
|
||||||
@@ -275,7 +351,7 @@ public class BdfReaderImplTest extends BrambleTestCase {
|
|||||||
@Test
|
@Test
|
||||||
public void testReadUtf8String() throws Exception {
|
public void testReadUtf8String() throws Exception {
|
||||||
String unicode = "\uFDD0\uFDD1\uFDD2\uFDD3";
|
String unicode = "\uFDD0\uFDD1\uFDD2\uFDD3";
|
||||||
String hex = toHexString(unicode.getBytes("UTF-8"));
|
String hex = toHexString(unicode.getBytes(UTF_8));
|
||||||
// STRING_8 tag, "foo", the empty string, and the test string
|
// STRING_8 tag, "foo", the empty string, and the test string
|
||||||
setContents("41" + "03" + "666F6F" + "41" + "00" + "41" + "0C" + hex);
|
setContents("41" + "03" + "666F6F" + "41" + "00" + "41" + "0C" + hex);
|
||||||
assertEquals("foo", r.readString());
|
assertEquals("foo", r.readString());
|
||||||
@@ -348,6 +424,14 @@ public class BdfReaderImplTest extends BrambleTestCase {
|
|||||||
r.readRaw();
|
r.readRaw();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test(expected = FormatException.class)
|
||||||
|
public void testReadRaw16CouldHaveBeenRaw8() throws Exception {
|
||||||
|
byte[] longest = new byte[Byte.MAX_VALUE];
|
||||||
|
String longHex = toHexString(longest);
|
||||||
|
setContents("52" + "007F" + longHex);
|
||||||
|
r.readRaw();
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testSkipRaw16() throws Exception {
|
public void testSkipRaw16() throws Exception {
|
||||||
byte[] shortest = new byte[Byte.MAX_VALUE + 1];
|
byte[] shortest = new byte[Byte.MAX_VALUE + 1];
|
||||||
@@ -385,6 +469,14 @@ public class BdfReaderImplTest extends BrambleTestCase {
|
|||||||
r.readRaw();
|
r.readRaw();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test(expected = FormatException.class)
|
||||||
|
public void testReadRaw32CouldHaveBeenRaw16() throws Exception {
|
||||||
|
byte[] longest = new byte[Short.MAX_VALUE];
|
||||||
|
String longHex = toHexString(longest);
|
||||||
|
setContents("54" + "00007FFF" + longHex);
|
||||||
|
r.readRaw();
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testSkipRaw32() throws Exception {
|
public void testSkipRaw32() throws Exception {
|
||||||
byte[] shortest = new byte[Short.MAX_VALUE + 1];
|
byte[] shortest = new byte[Short.MAX_VALUE + 1];
|
||||||
@@ -434,25 +526,6 @@ public class BdfReaderImplTest extends BrambleTestCase {
|
|||||||
r.readList();
|
r.readList();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testReadListManually() throws Exception {
|
|
||||||
// A list containing 1, "foo", and null
|
|
||||||
setContents("60" + "21" + "01" +
|
|
||||||
"41" + "03" + "666F6F" +
|
|
||||||
"00" + "80");
|
|
||||||
r.readListStart();
|
|
||||||
assertFalse(r.hasListEnd());
|
|
||||||
assertEquals(1, r.readLong());
|
|
||||||
assertFalse(r.hasListEnd());
|
|
||||||
assertEquals("foo", r.readString());
|
|
||||||
assertFalse(r.hasListEnd());
|
|
||||||
assertTrue(r.hasNull());
|
|
||||||
r.readNull();
|
|
||||||
assertTrue(r.hasListEnd());
|
|
||||||
r.readListEnd();
|
|
||||||
assertTrue(r.eof());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testSkipList() throws Exception {
|
public void testSkipList() throws Exception {
|
||||||
// A list containing 1, "foo", and 128
|
// A list containing 1, "foo", and 128
|
||||||
@@ -465,9 +538,9 @@ public class BdfReaderImplTest extends BrambleTestCase {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testReadDictionary() throws Exception {
|
public void testReadDictionary() throws Exception {
|
||||||
// A dictionary containing "foo" -> 123 and "bar" -> null
|
// A dictionary containing "bar" -> null and "foo" -> 123
|
||||||
setContents("70" + "41" + "03" + "666F6F" + "21" + "7B" +
|
setContents("70" + "41" + "03" + "626172" + "00" +
|
||||||
"41" + "03" + "626172" + "00" + "80");
|
"41" + "03" + "666F6F" + "21" + "7B" + "80");
|
||||||
BdfDictionary dictionary = r.readDictionary();
|
BdfDictionary dictionary = r.readDictionary();
|
||||||
assertEquals(2, dictionary.size());
|
assertEquals(2, dictionary.size());
|
||||||
assertTrue(dictionary.containsKey("foo"));
|
assertTrue(dictionary.containsKey("foo"));
|
||||||
@@ -517,26 +590,6 @@ public class BdfReaderImplTest extends BrambleTestCase {
|
|||||||
r.readDictionary();
|
r.readDictionary();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testReadDictionaryManually() throws Exception {
|
|
||||||
// A dictionary containing "foo" -> 123 and "bar" -> null
|
|
||||||
setContents("70" + "41" + "03" + "666F6F" + "21" + "7B" +
|
|
||||||
"41" + "03" + "626172" + "00" + "80");
|
|
||||||
r.readDictionaryStart();
|
|
||||||
assertFalse(r.hasDictionaryEnd());
|
|
||||||
assertEquals("foo", r.readString());
|
|
||||||
assertFalse(r.hasDictionaryEnd());
|
|
||||||
assertEquals(123, r.readLong());
|
|
||||||
assertFalse(r.hasDictionaryEnd());
|
|
||||||
assertEquals("bar", r.readString());
|
|
||||||
assertFalse(r.hasDictionaryEnd());
|
|
||||||
assertTrue(r.hasNull());
|
|
||||||
r.readNull();
|
|
||||||
assertTrue(r.hasDictionaryEnd());
|
|
||||||
r.readDictionaryEnd();
|
|
||||||
assertTrue(r.eof());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testSkipDictionary() throws Exception {
|
public void testSkipDictionary() throws Exception {
|
||||||
// A map containing "foo" -> 123 and "bar" -> null
|
// A map containing "foo" -> 123 and "bar" -> null
|
||||||
@@ -557,10 +610,10 @@ public class BdfReaderImplTest extends BrambleTestCase {
|
|||||||
@Test
|
@Test
|
||||||
public void testNestedListWithinDepthLimit() throws Exception {
|
public void testNestedListWithinDepthLimit() throws Exception {
|
||||||
// A list containing a list containing a list containing a list...
|
// A list containing a list containing a list containing a list...
|
||||||
String lists = "";
|
StringBuilder lists = new StringBuilder();
|
||||||
for (int i = 1; i <= DEFAULT_NESTED_LIMIT; i++) lists += "60";
|
for (int i = 1; i <= DEFAULT_NESTED_LIMIT; i++) lists.append("60");
|
||||||
for (int i = 1; i <= DEFAULT_NESTED_LIMIT; i++) lists += "80";
|
for (int i = 1; i <= DEFAULT_NESTED_LIMIT; i++) lists.append("80");
|
||||||
setContents(lists);
|
setContents(lists.toString());
|
||||||
r.readList();
|
r.readList();
|
||||||
assertTrue(r.eof());
|
assertTrue(r.eof());
|
||||||
}
|
}
|
||||||
@@ -568,23 +621,25 @@ public class BdfReaderImplTest extends BrambleTestCase {
|
|||||||
@Test(expected = FormatException.class)
|
@Test(expected = FormatException.class)
|
||||||
public void testNestedListOutsideDepthLimit() throws Exception {
|
public void testNestedListOutsideDepthLimit() throws Exception {
|
||||||
// A list containing a list containing a list containing a list...
|
// A list containing a list containing a list containing a list...
|
||||||
String lists = "";
|
StringBuilder lists = new StringBuilder();
|
||||||
for (int i = 1; i <= DEFAULT_NESTED_LIMIT + 1; i++) lists += "60";
|
for (int i = 1; i <= DEFAULT_NESTED_LIMIT + 1; i++) lists.append("60");
|
||||||
for (int i = 1; i <= DEFAULT_NESTED_LIMIT + 1; i++) lists += "80";
|
for (int i = 1; i <= DEFAULT_NESTED_LIMIT + 1; i++) lists.append("80");
|
||||||
setContents(lists);
|
setContents(lists.toString());
|
||||||
r.readList();
|
r.readList();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testNestedDictionaryWithinDepthLimit() throws Exception {
|
public void testNestedDictionaryWithinDepthLimit() throws Exception {
|
||||||
// A dictionary containing a dictionary containing a dictionary...
|
// A dictionary containing a dictionary containing a dictionary...
|
||||||
String dicts = "";
|
StringBuilder dicts = new StringBuilder();
|
||||||
for (int i = 1; i <= DEFAULT_NESTED_LIMIT; i++)
|
for (int i = 1; i <= DEFAULT_NESTED_LIMIT; i++) {
|
||||||
dicts += "70" + "41" + "03" + "666F6F";
|
dicts.append("70").append("41").append("03").append("666F6F");
|
||||||
dicts += "11";
|
}
|
||||||
for (int i = 1; i <= DEFAULT_NESTED_LIMIT; i++)
|
dicts.append("11");
|
||||||
dicts += "80";
|
for (int i = 1; i <= DEFAULT_NESTED_LIMIT; i++) {
|
||||||
setContents(dicts);
|
dicts.append("80");
|
||||||
|
}
|
||||||
|
setContents(dicts.toString());
|
||||||
r.readDictionary();
|
r.readDictionary();
|
||||||
assertTrue(r.eof());
|
assertTrue(r.eof());
|
||||||
}
|
}
|
||||||
@@ -592,13 +647,15 @@ public class BdfReaderImplTest extends BrambleTestCase {
|
|||||||
@Test(expected = FormatException.class)
|
@Test(expected = FormatException.class)
|
||||||
public void testNestedDictionaryOutsideDepthLimit() throws Exception {
|
public void testNestedDictionaryOutsideDepthLimit() throws Exception {
|
||||||
// A dictionary containing a dictionary containing a dictionary...
|
// A dictionary containing a dictionary containing a dictionary...
|
||||||
String dicts = "";
|
StringBuilder dicts = new StringBuilder();
|
||||||
for (int i = 1; i <= DEFAULT_NESTED_LIMIT + 1; i++)
|
for (int i = 1; i <= DEFAULT_NESTED_LIMIT + 1; i++) {
|
||||||
dicts += "70" + "41" + "03" + "666F6F";
|
dicts.append("70").append("41").append("03").append("666F6F");
|
||||||
dicts += "11";
|
}
|
||||||
for (int i = 1; i <= DEFAULT_NESTED_LIMIT + 1; i++)
|
dicts.append("11");
|
||||||
dicts += "80";
|
for (int i = 1; i <= DEFAULT_NESTED_LIMIT + 1; i++) {
|
||||||
setContents(dicts);
|
dicts.append("80");
|
||||||
|
}
|
||||||
|
setContents(dicts.toString());
|
||||||
r.readDictionary();
|
r.readDictionary();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -625,6 +682,6 @@ public class BdfReaderImplTest extends BrambleTestCase {
|
|||||||
private void setContents(String hex, int maxBufferSize)
|
private void setContents(String hex, int maxBufferSize)
|
||||||
throws FormatException {
|
throws FormatException {
|
||||||
ByteArrayInputStream in = new ByteArrayInputStream(fromHexString(hex));
|
ByteArrayInputStream in = new ByteArrayInputStream(fromHexString(hex));
|
||||||
r = new BdfReaderImpl(in, DEFAULT_NESTED_LIMIT, maxBufferSize);
|
r = new BdfReaderImpl(in, DEFAULT_NESTED_LIMIT, maxBufferSize, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,80 @@
|
|||||||
|
package org.briarproject.bramble.data;
|
||||||
|
|
||||||
|
import org.briarproject.bramble.api.data.BdfDictionary;
|
||||||
|
import org.briarproject.bramble.api.data.BdfReader;
|
||||||
|
import org.briarproject.bramble.api.data.BdfWriter;
|
||||||
|
import org.briarproject.bramble.test.BrambleTestCase;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import java.io.ByteArrayInputStream;
|
||||||
|
import java.io.ByteArrayOutputStream;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.util.Iterator;
|
||||||
|
import java.util.LinkedHashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Map.Entry;
|
||||||
|
|
||||||
|
import static org.briarproject.bramble.api.data.BdfReader.DEFAULT_MAX_BUFFER_SIZE;
|
||||||
|
import static org.briarproject.bramble.api.data.BdfReader.DEFAULT_NESTED_LIMIT;
|
||||||
|
import static org.briarproject.bramble.util.StringUtils.fromHexString;
|
||||||
|
import static org.briarproject.bramble.util.StringUtils.toHexString;
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
import static org.junit.Assert.assertTrue;
|
||||||
|
|
||||||
|
public class BdfReaderWriterIntegrationTest extends BrambleTestCase {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testConvertStringToCanonicalForm() throws Exception {
|
||||||
|
// 'foo' as a STRING_16 (not canonical, should be a STRING_8)
|
||||||
|
String hexIn = "42" + "0003" + "666F6F";
|
||||||
|
InputStream in = new ByteArrayInputStream(fromHexString(hexIn));
|
||||||
|
BdfReader r = new BdfReaderImpl(in, DEFAULT_NESTED_LIMIT,
|
||||||
|
DEFAULT_MAX_BUFFER_SIZE, false); // Accept non-canonical
|
||||||
|
String s = r.readString();
|
||||||
|
assertEquals("foo", s);
|
||||||
|
assertTrue(r.eof());
|
||||||
|
// Convert the string back to BDF
|
||||||
|
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||||
|
BdfWriter w = new BdfWriterImpl(out);
|
||||||
|
w.writeString(s);
|
||||||
|
w.flush();
|
||||||
|
String hexOut = toHexString(out.toByteArray());
|
||||||
|
// The BDF should now be in canonical form
|
||||||
|
assertEquals("41" + "03" + "666F6F", hexOut);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testConvertDictionaryToCanonicalForm() throws Exception {
|
||||||
|
// A dictionary with keys in non-canonical order: 'foo' then 'bar'
|
||||||
|
String hexIn = "70" + "41" + "03" + "666F6F" + "21" + "01"
|
||||||
|
+ "41" + "03" + "626172" + "21" + "02" + "80";
|
||||||
|
InputStream in = new ByteArrayInputStream(fromHexString(hexIn));
|
||||||
|
BdfReader r = new BdfReaderImpl(in, DEFAULT_NESTED_LIMIT,
|
||||||
|
DEFAULT_MAX_BUFFER_SIZE, false); // Accept non-canonical
|
||||||
|
BdfDictionary d = r.readDictionary();
|
||||||
|
assertEquals(2, d.size());
|
||||||
|
assertTrue(r.eof());
|
||||||
|
// The entries should be returned in canonical order
|
||||||
|
Iterator<Entry<String, Object>> it = d.entrySet().iterator();
|
||||||
|
Entry<String, Object> first = it.next();
|
||||||
|
assertEquals("bar", first.getKey());
|
||||||
|
assertEquals(2L, first.getValue());
|
||||||
|
Entry<String, Object> second = it.next();
|
||||||
|
assertEquals("foo", second.getKey());
|
||||||
|
assertEquals(1L, second.getValue());
|
||||||
|
|
||||||
|
// Convert a non-canonical map to BDF (use LinkedHashMap so we know
|
||||||
|
// the entries will be iterated over in non-canonical order)
|
||||||
|
Map<String, Object> m = new LinkedHashMap<>();
|
||||||
|
m.put("foo", 1);
|
||||||
|
m.put("bar", 2);
|
||||||
|
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||||
|
BdfWriter w = new BdfWriterImpl(out);
|
||||||
|
w.writeDictionary(m);
|
||||||
|
w.flush();
|
||||||
|
String hexOut = toHexString(out.toByteArray());
|
||||||
|
// The entries should be in canonical order: 'bar' then 'foo'
|
||||||
|
assertEquals("70" + "41" + "03" + "626172" + "21" + "02"
|
||||||
|
+ "41" + "03" + "666F6F" + "21" + "01" + "80", hexOut);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,5 +1,6 @@
|
|||||||
package org.briarproject.bramble.data;
|
package org.briarproject.bramble.data;
|
||||||
|
|
||||||
|
import org.briarproject.bramble.api.data.BdfDictionary;
|
||||||
import org.briarproject.bramble.test.BrambleTestCase;
|
import org.briarproject.bramble.test.BrambleTestCase;
|
||||||
import org.briarproject.bramble.util.StringUtils;
|
import org.briarproject.bramble.util.StringUtils;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
@@ -168,9 +169,11 @@ public class BdfWriterImplTest extends BrambleTestCase {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testWriteDictionary() throws IOException {
|
public void testWriteDictionary() throws IOException {
|
||||||
// Use LinkedHashMap to get predictable iteration order
|
// Add entries to dictionary in descending order - they should be
|
||||||
|
// output in ascending order. Use LinkedHashMap to get predictable
|
||||||
|
// iteration order
|
||||||
Map<String, Object> m = new LinkedHashMap<>();
|
Map<String, Object> m = new LinkedHashMap<>();
|
||||||
for (int i = 0; i < 4; i++) m.put(String.valueOf(i), i);
|
for (int i = 3; i >= 0; i--) m.put(String.valueOf(i), i);
|
||||||
w.writeDictionary(m);
|
w.writeDictionary(m);
|
||||||
// DICTIONARY tag, keys as strings and values as integers, END tag
|
// DICTIONARY tag, keys as strings and values as integers, END tag
|
||||||
checkContents("70" + "41" + "01" + "30" + "21" + "00" +
|
checkContents("70" + "41" + "01" + "30" + "21" + "00" +
|
||||||
@@ -180,30 +183,17 @@ public class BdfWriterImplTest extends BrambleTestCase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testWriteDelimitedList() throws IOException {
|
public void testWriteBdfDictionary() throws IOException {
|
||||||
w.writeListStart();
|
// Add entries to dictionary in descending order - they should be
|
||||||
w.writeLong(1);
|
// output in ascending order
|
||||||
w.writeString("foo");
|
BdfDictionary d = new BdfDictionary();
|
||||||
w.writeLong(128);
|
for (int i = 3; i >= 0; i--) d.put(String.valueOf(i), i);
|
||||||
w.writeListEnd();
|
w.writeDictionary(d);
|
||||||
// LIST tag, 1 as integer, "foo" as string, 128 as integer, END tag
|
// DICTIONARY tag, keys as strings and values as integers, END tag
|
||||||
checkContents("60" + "21" + "01" +
|
checkContents("70" + "41" + "01" + "30" + "21" + "00" +
|
||||||
"41" + "03" + "666F6F" +
|
"41" + "01" + "31" + "21" + "01" +
|
||||||
"22" + "0080" + "80");
|
"41" + "01" + "32" + "21" + "02" +
|
||||||
}
|
"41" + "01" + "33" + "21" + "03" + "80");
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testWriteDelimitedDictionary() throws IOException {
|
|
||||||
w.writeDictionaryStart();
|
|
||||||
w.writeString("foo");
|
|
||||||
w.writeLong(123);
|
|
||||||
w.writeString("bar");
|
|
||||||
w.writeNull();
|
|
||||||
w.writeDictionaryEnd();
|
|
||||||
// DICTIONARY tag, "foo" as string, 123 as integer, "bar" as string,
|
|
||||||
// NULL tag, END tag
|
|
||||||
checkContents("70" + "41" + "03" + "666F6F" +
|
|
||||||
"21" + "7B" + "41" + "03" + "626172" + "00" + "80");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|||||||
@@ -2,21 +2,27 @@ package org.briarproject.bramble.keyagreement;
|
|||||||
|
|
||||||
import org.briarproject.bramble.api.Bytes;
|
import org.briarproject.bramble.api.Bytes;
|
||||||
import org.briarproject.bramble.api.FormatException;
|
import org.briarproject.bramble.api.FormatException;
|
||||||
|
import org.briarproject.bramble.api.Pair;
|
||||||
import org.briarproject.bramble.api.UnsupportedVersionException;
|
import org.briarproject.bramble.api.UnsupportedVersionException;
|
||||||
import org.briarproject.bramble.api.data.BdfList;
|
import org.briarproject.bramble.api.data.BdfList;
|
||||||
import org.briarproject.bramble.api.data.BdfReader;
|
import org.briarproject.bramble.api.data.BdfReader;
|
||||||
import org.briarproject.bramble.api.data.BdfReaderFactory;
|
import org.briarproject.bramble.api.data.BdfReaderFactory;
|
||||||
import org.briarproject.bramble.api.keyagreement.Payload;
|
import org.briarproject.bramble.api.keyagreement.Payload;
|
||||||
|
import org.briarproject.bramble.api.qrcode.QrCodeClassifier;
|
||||||
|
import org.briarproject.bramble.api.qrcode.QrCodeClassifier.QrCodeType;
|
||||||
|
import org.briarproject.bramble.api.qrcode.WrongQrCodeTypeException;
|
||||||
import org.briarproject.bramble.test.BrambleMockTestCase;
|
import org.briarproject.bramble.test.BrambleMockTestCase;
|
||||||
import org.jmock.Expectations;
|
import org.jmock.Expectations;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
import java.io.ByteArrayInputStream;
|
import java.io.ByteArrayInputStream;
|
||||||
|
|
||||||
import static org.briarproject.bramble.api.keyagreement.KeyAgreementConstants.BETA_PROTOCOL_VERSION;
|
|
||||||
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.keyagreement.KeyAgreementConstants.PROTOCOL_VERSION;
|
import static org.briarproject.bramble.api.keyagreement.KeyAgreementConstants.QR_FORMAT_VERSION;
|
||||||
|
import static org.briarproject.bramble.api.qrcode.QrCodeClassifier.QrCodeType.BQP;
|
||||||
|
import static org.briarproject.bramble.api.qrcode.QrCodeClassifier.QrCodeType.MAILBOX;
|
||||||
import static org.briarproject.bramble.test.TestUtils.getRandomBytes;
|
import static org.briarproject.bramble.test.TestUtils.getRandomBytes;
|
||||||
|
import static org.briarproject.bramble.util.StringUtils.getRandomString;
|
||||||
import static org.junit.Assert.assertArrayEquals;
|
import static org.junit.Assert.assertArrayEquals;
|
||||||
import static org.junit.Assert.assertFalse;
|
import static org.junit.Assert.assertFalse;
|
||||||
import static org.junit.Assert.assertTrue;
|
import static org.junit.Assert.assertTrue;
|
||||||
@@ -26,32 +32,29 @@ public class PayloadParserImplTest extends BrambleMockTestCase {
|
|||||||
|
|
||||||
private final BdfReaderFactory bdfReaderFactory =
|
private final BdfReaderFactory bdfReaderFactory =
|
||||||
context.mock(BdfReaderFactory.class);
|
context.mock(BdfReaderFactory.class);
|
||||||
|
private final QrCodeClassifier qrCodeClassifier =
|
||||||
|
context.mock(QrCodeClassifier.class);
|
||||||
private final BdfReader bdfReader = context.mock(BdfReader.class);
|
private final BdfReader bdfReader = context.mock(BdfReader.class);
|
||||||
|
|
||||||
private final PayloadParserImpl payloadParser =
|
private final String payload = getRandomString(123);
|
||||||
new PayloadParserImpl(bdfReaderFactory);
|
|
||||||
|
|
||||||
@Test(expected = FormatException.class)
|
private final PayloadParserImpl payloadParser =
|
||||||
public void testThrowsFormatExceptionIfPayloadIsEmpty() throws Exception {
|
new PayloadParserImpl(bdfReaderFactory, qrCodeClassifier);
|
||||||
payloadParser.parse(new byte[0]);
|
|
||||||
|
@Test(expected = WrongQrCodeTypeException.class)
|
||||||
|
public void testThrowsExceptionForWrongQrCodeType() throws Exception {
|
||||||
|
expectClassifyQrCode(payload, MAILBOX, QR_FORMAT_VERSION);
|
||||||
|
|
||||||
|
payloadParser.parse(payload);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testThrowsUnsupportedVersionExceptionForOldVersion()
|
public void testThrowsUnsupportedVersionExceptionForOldVersion()
|
||||||
throws Exception {
|
throws Exception {
|
||||||
try {
|
expectClassifyQrCode(payload, BQP, QR_FORMAT_VERSION - 1);
|
||||||
payloadParser.parse(new byte[] {PROTOCOL_VERSION - 1});
|
|
||||||
fail();
|
|
||||||
} catch (UnsupportedVersionException e) {
|
|
||||||
assertTrue(e.isTooOld());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testThrowsUnsupportedVersionExceptionForBetaVersion()
|
|
||||||
throws Exception {
|
|
||||||
try {
|
try {
|
||||||
payloadParser.parse(new byte[] {BETA_PROTOCOL_VERSION});
|
payloadParser.parse(payload);
|
||||||
fail();
|
fail();
|
||||||
} catch (UnsupportedVersionException e) {
|
} catch (UnsupportedVersionException e) {
|
||||||
assertTrue(e.isTooOld());
|
assertTrue(e.isTooOld());
|
||||||
@@ -61,8 +64,10 @@ public class PayloadParserImplTest extends BrambleMockTestCase {
|
|||||||
@Test
|
@Test
|
||||||
public void testThrowsUnsupportedVersionExceptionForNewVersion()
|
public void testThrowsUnsupportedVersionExceptionForNewVersion()
|
||||||
throws Exception {
|
throws Exception {
|
||||||
|
expectClassifyQrCode(payload, BQP, QR_FORMAT_VERSION + 1);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
payloadParser.parse(new byte[] {PROTOCOL_VERSION + 1});
|
payloadParser.parse(payload);
|
||||||
fail();
|
fail();
|
||||||
} catch (UnsupportedVersionException e) {
|
} catch (UnsupportedVersionException e) {
|
||||||
assertFalse(e.isTooOld());
|
assertFalse(e.isTooOld());
|
||||||
@@ -71,6 +76,8 @@ public class PayloadParserImplTest extends BrambleMockTestCase {
|
|||||||
|
|
||||||
@Test(expected = FormatException.class)
|
@Test(expected = FormatException.class)
|
||||||
public void testThrowsFormatExceptionForEmptyList() throws Exception {
|
public void testThrowsFormatExceptionForEmptyList() throws Exception {
|
||||||
|
expectClassifyQrCode(payload, BQP, QR_FORMAT_VERSION);
|
||||||
|
|
||||||
context.checking(new Expectations() {{
|
context.checking(new Expectations() {{
|
||||||
oneOf(bdfReaderFactory).createReader(
|
oneOf(bdfReaderFactory).createReader(
|
||||||
with(any(ByteArrayInputStream.class)));
|
with(any(ByteArrayInputStream.class)));
|
||||||
@@ -79,7 +86,7 @@ public class PayloadParserImplTest extends BrambleMockTestCase {
|
|||||||
will(returnValue(new BdfList()));
|
will(returnValue(new BdfList()));
|
||||||
}});
|
}});
|
||||||
|
|
||||||
payloadParser.parse(new byte[] {PROTOCOL_VERSION});
|
payloadParser.parse(payload);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test(expected = FormatException.class)
|
@Test(expected = FormatException.class)
|
||||||
@@ -87,6 +94,8 @@ public class PayloadParserImplTest extends BrambleMockTestCase {
|
|||||||
throws Exception {
|
throws Exception {
|
||||||
byte[] commitment = getRandomBytes(COMMIT_LENGTH);
|
byte[] commitment = getRandomBytes(COMMIT_LENGTH);
|
||||||
|
|
||||||
|
expectClassifyQrCode(payload, BQP, QR_FORMAT_VERSION);
|
||||||
|
|
||||||
context.checking(new Expectations() {{
|
context.checking(new Expectations() {{
|
||||||
oneOf(bdfReaderFactory).createReader(
|
oneOf(bdfReaderFactory).createReader(
|
||||||
with(any(ByteArrayInputStream.class)));
|
with(any(ByteArrayInputStream.class)));
|
||||||
@@ -97,7 +106,7 @@ public class PayloadParserImplTest extends BrambleMockTestCase {
|
|||||||
will(returnValue(false));
|
will(returnValue(false));
|
||||||
}});
|
}});
|
||||||
|
|
||||||
payloadParser.parse(new byte[] {PROTOCOL_VERSION});
|
payloadParser.parse(payload);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test(expected = FormatException.class)
|
@Test(expected = FormatException.class)
|
||||||
@@ -105,6 +114,7 @@ public class PayloadParserImplTest extends BrambleMockTestCase {
|
|||||||
throws Exception {
|
throws Exception {
|
||||||
byte[] commitment = getRandomBytes(COMMIT_LENGTH - 1);
|
byte[] commitment = getRandomBytes(COMMIT_LENGTH - 1);
|
||||||
|
|
||||||
|
expectClassifyQrCode(payload, BQP, QR_FORMAT_VERSION);
|
||||||
context.checking(new Expectations() {{
|
context.checking(new Expectations() {{
|
||||||
oneOf(bdfReaderFactory).createReader(
|
oneOf(bdfReaderFactory).createReader(
|
||||||
with(any(ByteArrayInputStream.class)));
|
with(any(ByteArrayInputStream.class)));
|
||||||
@@ -115,7 +125,7 @@ public class PayloadParserImplTest extends BrambleMockTestCase {
|
|||||||
will(returnValue(true));
|
will(returnValue(true));
|
||||||
}});
|
}});
|
||||||
|
|
||||||
payloadParser.parse(new byte[] {PROTOCOL_VERSION});
|
payloadParser.parse(payload);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test(expected = FormatException.class)
|
@Test(expected = FormatException.class)
|
||||||
@@ -123,6 +133,7 @@ public class PayloadParserImplTest extends BrambleMockTestCase {
|
|||||||
throws Exception {
|
throws Exception {
|
||||||
byte[] commitment = getRandomBytes(COMMIT_LENGTH + 1);
|
byte[] commitment = getRandomBytes(COMMIT_LENGTH + 1);
|
||||||
|
|
||||||
|
expectClassifyQrCode(payload, BQP, QR_FORMAT_VERSION);
|
||||||
context.checking(new Expectations() {{
|
context.checking(new Expectations() {{
|
||||||
oneOf(bdfReaderFactory).createReader(
|
oneOf(bdfReaderFactory).createReader(
|
||||||
with(any(ByteArrayInputStream.class)));
|
with(any(ByteArrayInputStream.class)));
|
||||||
@@ -133,12 +144,14 @@ public class PayloadParserImplTest extends BrambleMockTestCase {
|
|||||||
will(returnValue(true));
|
will(returnValue(true));
|
||||||
}});
|
}});
|
||||||
|
|
||||||
payloadParser.parse(new byte[] {PROTOCOL_VERSION});
|
payloadParser.parse(payload);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testAcceptsPayloadWithNoDescriptors() throws Exception {
|
public void testAcceptsPayloadWithNoDescriptors() throws Exception {
|
||||||
byte[] commitment = getRandomBytes(COMMIT_LENGTH);
|
byte[] commitment = getRandomBytes(COMMIT_LENGTH);
|
||||||
|
|
||||||
|
expectClassifyQrCode(payload, BQP, QR_FORMAT_VERSION);
|
||||||
context.checking(new Expectations() {{
|
context.checking(new Expectations() {{
|
||||||
oneOf(bdfReaderFactory).createReader(
|
oneOf(bdfReaderFactory).createReader(
|
||||||
with(any(ByteArrayInputStream.class)));
|
with(any(ByteArrayInputStream.class)));
|
||||||
@@ -149,8 +162,16 @@ public class PayloadParserImplTest extends BrambleMockTestCase {
|
|||||||
will(returnValue(true));
|
will(returnValue(true));
|
||||||
}});
|
}});
|
||||||
|
|
||||||
Payload p = payloadParser.parse(new byte[] {PROTOCOL_VERSION});
|
Payload p = payloadParser.parse(payload);
|
||||||
assertArrayEquals(commitment, p.getCommitment());
|
assertArrayEquals(commitment, p.getCommitment());
|
||||||
assertTrue(p.getTransportDescriptors().isEmpty());
|
assertTrue(p.getTransportDescriptors().isEmpty());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void expectClassifyQrCode(String payload, QrCodeType qrCodeType,
|
||||||
|
int formatVersion) {
|
||||||
|
context.checking(new Expectations() {{
|
||||||
|
oneOf(qrCodeClassifier).classifyQrCode(payload);
|
||||||
|
will(returnValue(new Pair<>(qrCodeType, formatVersion)));
|
||||||
|
}});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
package org.briarproject.bramble.mailbox;
|
package org.briarproject.bramble.mailbox;
|
||||||
|
|
||||||
|
import org.briarproject.bramble.api.FormatException;
|
||||||
import org.briarproject.bramble.api.db.DbException;
|
import org.briarproject.bramble.api.db.DbException;
|
||||||
import org.briarproject.bramble.api.db.Transaction;
|
import org.briarproject.bramble.api.db.Transaction;
|
||||||
import org.briarproject.bramble.api.db.TransactionManager;
|
import org.briarproject.bramble.api.db.TransactionManager;
|
||||||
@@ -9,17 +10,23 @@ import org.briarproject.bramble.api.mailbox.event.OwnMailboxConnectionStatusEven
|
|||||||
import org.briarproject.bramble.api.system.Clock;
|
import org.briarproject.bramble.api.system.Clock;
|
||||||
import org.briarproject.bramble.test.BrambleMockTestCase;
|
import org.briarproject.bramble.test.BrambleMockTestCase;
|
||||||
import org.briarproject.bramble.test.DbExpectations;
|
import org.briarproject.bramble.test.DbExpectations;
|
||||||
|
import org.briarproject.bramble.util.Base32;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.util.Locale;
|
||||||
import java.util.Random;
|
import java.util.Random;
|
||||||
import java.util.concurrent.Executor;
|
import java.util.concurrent.Executor;
|
||||||
|
|
||||||
|
import static org.briarproject.bramble.util.StringUtils.ISO_8859_1;
|
||||||
import static org.briarproject.bramble.api.mailbox.MailboxConstants.CLIENT_SUPPORTS;
|
import static org.briarproject.bramble.api.mailbox.MailboxConstants.CLIENT_SUPPORTS;
|
||||||
import static org.briarproject.bramble.test.TestUtils.getMailboxProperties;
|
import static org.briarproject.bramble.test.TestUtils.getMailboxProperties;
|
||||||
|
import static org.briarproject.bramble.test.TestUtils.getRandomBytes;
|
||||||
import static org.briarproject.bramble.test.TestUtils.hasEvent;
|
import static org.briarproject.bramble.test.TestUtils.hasEvent;
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
import static org.junit.Assert.assertFalse;
|
import static org.junit.Assert.assertFalse;
|
||||||
import static org.junit.Assert.assertTrue;
|
import static org.junit.Assert.assertTrue;
|
||||||
|
import static org.junit.Assert.fail;
|
||||||
|
|
||||||
public class MailboxManagerImplTest extends BrambleMockTestCase {
|
public class MailboxManagerImplTest extends BrambleMockTestCase {
|
||||||
|
|
||||||
@@ -125,4 +132,32 @@ public class MailboxManagerImplTest extends BrambleMockTestCase {
|
|||||||
assertTrue(manager.checkConnection());
|
assertTrue(manager.checkConnection());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testConvertBase32Payload() throws FormatException {
|
||||||
|
byte[] payload = getRandomBytes(65);
|
||||||
|
String base32payload = Base32.encode(payload).toLowerCase(Locale.ROOT);
|
||||||
|
String expected = new String(payload, ISO_8859_1);
|
||||||
|
try {
|
||||||
|
manager.convertBase32Payload("foo bar");
|
||||||
|
fail();
|
||||||
|
} catch (FormatException e) {
|
||||||
|
// expected
|
||||||
|
}
|
||||||
|
try { // doesn't work with shorter link
|
||||||
|
manager.convertBase32Payload("briar-mailbox://" +
|
||||||
|
base32payload.substring(0, base32payload.length() - 1));
|
||||||
|
fail();
|
||||||
|
} catch (FormatException e) {
|
||||||
|
// expected
|
||||||
|
}
|
||||||
|
// works with white-spaces
|
||||||
|
assertEquals(expected, manager.convertBase32Payload(
|
||||||
|
"foo bar briar-mailbox://" + base32payload + " foo bar"));
|
||||||
|
// even works without white-space at the end
|
||||||
|
assertEquals(expected, manager.convertBase32Payload(
|
||||||
|
"foo bar briar-mailbox://" + base32payload + "foobar"));
|
||||||
|
// even works without schema and extra chars at end
|
||||||
|
assertEquals(expected, manager.convertBase32Payload(
|
||||||
|
"foo bar " + base32payload + "foobar"));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
package org.briarproject.bramble.mailbox;
|
package org.briarproject.bramble.mailbox;
|
||||||
|
|
||||||
|
import org.briarproject.bramble.api.Pair;
|
||||||
import org.briarproject.bramble.api.contact.Contact;
|
import org.briarproject.bramble.api.contact.Contact;
|
||||||
import org.briarproject.bramble.api.crypto.CryptoComponent;
|
import org.briarproject.bramble.api.crypto.CryptoComponent;
|
||||||
import org.briarproject.bramble.api.db.DatabaseComponent;
|
import org.briarproject.bramble.api.db.DatabaseComponent;
|
||||||
@@ -7,13 +8,24 @@ import org.briarproject.bramble.api.db.DbException;
|
|||||||
import org.briarproject.bramble.api.db.Transaction;
|
import org.briarproject.bramble.api.db.Transaction;
|
||||||
import org.briarproject.bramble.api.mailbox.MailboxAuthToken;
|
import org.briarproject.bramble.api.mailbox.MailboxAuthToken;
|
||||||
import org.briarproject.bramble.api.mailbox.MailboxPairingState;
|
import org.briarproject.bramble.api.mailbox.MailboxPairingState;
|
||||||
|
import org.briarproject.bramble.api.mailbox.MailboxPairingState.ConnectionError;
|
||||||
|
import org.briarproject.bramble.api.mailbox.MailboxPairingState.InvalidQrCode;
|
||||||
|
import org.briarproject.bramble.api.mailbox.MailboxPairingState.MailboxAlreadyPaired;
|
||||||
|
import org.briarproject.bramble.api.mailbox.MailboxPairingState.Paired;
|
||||||
|
import org.briarproject.bramble.api.mailbox.MailboxPairingState.Pairing;
|
||||||
|
import org.briarproject.bramble.api.mailbox.MailboxPairingState.QrCodeReceived;
|
||||||
|
import org.briarproject.bramble.api.mailbox.MailboxPairingState.UnexpectedError;
|
||||||
import org.briarproject.bramble.api.mailbox.MailboxPairingTask;
|
import org.briarproject.bramble.api.mailbox.MailboxPairingTask;
|
||||||
import org.briarproject.bramble.api.mailbox.MailboxProperties;
|
import org.briarproject.bramble.api.mailbox.MailboxProperties;
|
||||||
import org.briarproject.bramble.api.mailbox.MailboxSettingsManager;
|
import org.briarproject.bramble.api.mailbox.MailboxSettingsManager;
|
||||||
import org.briarproject.bramble.api.mailbox.MailboxUpdate;
|
import org.briarproject.bramble.api.mailbox.MailboxUpdate;
|
||||||
import org.briarproject.bramble.api.mailbox.MailboxUpdateManager;
|
import org.briarproject.bramble.api.mailbox.MailboxUpdateManager;
|
||||||
import org.briarproject.bramble.api.mailbox.MailboxVersion;
|
import org.briarproject.bramble.api.mailbox.MailboxVersion;
|
||||||
|
import org.briarproject.bramble.api.qrcode.QrCodeClassifier;
|
||||||
|
import org.briarproject.bramble.api.qrcode.QrCodeClassifier.QrCodeType;
|
||||||
import org.briarproject.bramble.api.system.Clock;
|
import org.briarproject.bramble.api.system.Clock;
|
||||||
|
import org.briarproject.bramble.mailbox.MailboxApi.ApiException;
|
||||||
|
import org.briarproject.bramble.mailbox.MailboxApi.MailboxAlreadyPairedException;
|
||||||
import org.briarproject.bramble.test.BrambleMockTestCase;
|
import org.briarproject.bramble.test.BrambleMockTestCase;
|
||||||
import org.briarproject.bramble.test.DbExpectations;
|
import org.briarproject.bramble.test.DbExpectations;
|
||||||
import org.briarproject.bramble.test.ImmediateExecutor;
|
import org.briarproject.bramble.test.ImmediateExecutor;
|
||||||
@@ -27,6 +39,9 @@ import java.util.concurrent.Executor;
|
|||||||
import java.util.concurrent.atomic.AtomicInteger;
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
|
|
||||||
import static java.util.Collections.singletonList;
|
import static java.util.Collections.singletonList;
|
||||||
|
import static org.briarproject.bramble.api.mailbox.MailboxConstants.QR_FORMAT_VERSION;
|
||||||
|
import static org.briarproject.bramble.api.qrcode.QrCodeClassifier.QrCodeType.BQP;
|
||||||
|
import static org.briarproject.bramble.api.qrcode.QrCodeClassifier.QrCodeType.MAILBOX;
|
||||||
import static org.briarproject.bramble.mailbox.MailboxTestUtils.getQrCodePayload;
|
import static org.briarproject.bramble.mailbox.MailboxTestUtils.getQrCodePayload;
|
||||||
import static org.briarproject.bramble.test.TestUtils.getContact;
|
import static org.briarproject.bramble.test.TestUtils.getContact;
|
||||||
import static org.briarproject.bramble.test.TestUtils.getRandomBytes;
|
import static org.briarproject.bramble.test.TestUtils.getRandomBytes;
|
||||||
@@ -48,9 +63,8 @@ public class MailboxPairingTaskImplTest extends BrambleMockTestCase {
|
|||||||
context.mock(MailboxSettingsManager.class);
|
context.mock(MailboxSettingsManager.class);
|
||||||
private final MailboxUpdateManager mailboxUpdateManager =
|
private final MailboxUpdateManager mailboxUpdateManager =
|
||||||
context.mock(MailboxUpdateManager.class);
|
context.mock(MailboxUpdateManager.class);
|
||||||
private final MailboxPairingTaskFactory factory =
|
private final QrCodeClassifier qrCodeClassifier =
|
||||||
new MailboxPairingTaskFactoryImpl(executor, db, crypto, clock, api,
|
context.mock(QrCodeClassifier.class);
|
||||||
mailboxSettingsManager, mailboxUpdateManager);
|
|
||||||
|
|
||||||
private final String onion = getRandomString(56);
|
private final String onion = getRandomString(56);
|
||||||
private final byte[] onionBytes = getRandomBytes(32);
|
private final byte[] onionBytes = getRandomBytes(32);
|
||||||
@@ -68,32 +82,50 @@ public class MailboxPairingTaskImplTest extends BrambleMockTestCase {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testInitialQrCodeReceivedState() {
|
public void testInitialQrCodeReceivedState() {
|
||||||
MailboxPairingTask task =
|
MailboxPairingTask task = createPairingTask(getRandomString(42));
|
||||||
factory.createPairingTask(getRandomString(42));
|
|
||||||
task.addObserver(state ->
|
task.addObserver(state ->
|
||||||
assertTrue(state instanceof MailboxPairingState.QrCodeReceived)
|
assertTrue(state instanceof QrCodeReceived));
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testInvalidQrCode() {
|
public void testInvalidQrCodeType() {
|
||||||
MailboxPairingTask task1 =
|
String payload = getRandomString(65);
|
||||||
factory.createPairingTask(getRandomString(42));
|
MailboxPairingTask task = createPairingTask(payload);
|
||||||
task1.run();
|
|
||||||
task1.addObserver(state ->
|
|
||||||
assertTrue(state instanceof MailboxPairingState.InvalidQrCode)
|
|
||||||
);
|
|
||||||
|
|
||||||
String goodLength = "00" + getRandomString(63);
|
expectClassifyQrCode(payload, BQP, QR_FORMAT_VERSION);
|
||||||
MailboxPairingTask task2 = factory.createPairingTask(goodLength);
|
|
||||||
task2.run();
|
task.run();
|
||||||
task2.addObserver(state ->
|
task.addObserver(state ->
|
||||||
assertTrue(state instanceof MailboxPairingState.InvalidQrCode)
|
assertTrue(state instanceof InvalidQrCode));
|
||||||
);
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testInvalidQrCodeVersion() {
|
||||||
|
String payload = getRandomString(65);
|
||||||
|
MailboxPairingTask task = createPairingTask(payload);
|
||||||
|
|
||||||
|
expectClassifyQrCode(payload, MAILBOX, QR_FORMAT_VERSION + 1);
|
||||||
|
|
||||||
|
task.run();
|
||||||
|
task.addObserver(state ->
|
||||||
|
assertTrue(state instanceof InvalidQrCode));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testInvalidQrCodeLength() {
|
||||||
|
String payload = getRandomString(42);
|
||||||
|
MailboxPairingTask task = createPairingTask(payload);
|
||||||
|
|
||||||
|
expectClassifyQrCode(payload, MAILBOX, QR_FORMAT_VERSION);
|
||||||
|
|
||||||
|
task.run();
|
||||||
|
task.addObserver(state ->
|
||||||
|
assertTrue(state instanceof InvalidQrCode));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testSuccessfulPairing() throws Exception {
|
public void testSuccessfulPairing() throws Exception {
|
||||||
|
expectClassifyQrCode(validPayload, MAILBOX, QR_FORMAT_VERSION);
|
||||||
context.checking(new Expectations() {{
|
context.checking(new Expectations() {{
|
||||||
oneOf(crypto).encodeOnion(onionBytes);
|
oneOf(crypto).encodeOnion(onionBytes);
|
||||||
will(returnValue(onion));
|
will(returnValue(onion));
|
||||||
@@ -121,17 +153,14 @@ public class MailboxPairingTaskImplTest extends BrambleMockTestCase {
|
|||||||
}});
|
}});
|
||||||
|
|
||||||
AtomicInteger i = new AtomicInteger(0);
|
AtomicInteger i = new AtomicInteger(0);
|
||||||
MailboxPairingTask task = factory.createPairingTask(validPayload);
|
MailboxPairingTask task = createPairingTask(validPayload);
|
||||||
task.addObserver(state -> {
|
task.addObserver(state -> {
|
||||||
if (i.get() == 0) {
|
if (i.get() == 0) {
|
||||||
assertEquals(MailboxPairingState.QrCodeReceived.class,
|
assertEquals(QrCodeReceived.class, state.getClass());
|
||||||
state.getClass());
|
|
||||||
} else if (i.get() == 1) {
|
} else if (i.get() == 1) {
|
||||||
assertEquals(MailboxPairingState.Pairing.class,
|
assertEquals(Pairing.class, state.getClass());
|
||||||
state.getClass());
|
|
||||||
} else if (i.get() == 2) {
|
} else if (i.get() == 2) {
|
||||||
assertEquals(MailboxPairingState.Paired.class,
|
assertEquals(Paired.class, state.getClass());
|
||||||
state.getClass());
|
|
||||||
} else fail("Unexpected change of state " + state.getClass());
|
} else fail("Unexpected change of state " + state.getClass());
|
||||||
i.getAndIncrement();
|
i.getAndIncrement();
|
||||||
});
|
});
|
||||||
@@ -140,24 +169,23 @@ public class MailboxPairingTaskImplTest extends BrambleMockTestCase {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testAlreadyPaired() throws Exception {
|
public void testAlreadyPaired() throws Exception {
|
||||||
testApiException(new MailboxApi.MailboxAlreadyPairedException(),
|
testApiException(new MailboxAlreadyPairedException(),
|
||||||
MailboxPairingState.MailboxAlreadyPaired.class);
|
MailboxAlreadyPaired.class);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testMailboxApiException() throws Exception {
|
public void testMailboxApiException() throws Exception {
|
||||||
testApiException(new MailboxApi.ApiException(),
|
testApiException(new ApiException(), UnexpectedError.class);
|
||||||
MailboxPairingState.UnexpectedError.class);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testApiIOException() throws Exception {
|
public void testApiIOException() throws Exception {
|
||||||
testApiException(new IOException(),
|
testApiException(new IOException(), ConnectionError.class);
|
||||||
MailboxPairingState.ConnectionError.class);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void testApiException(Exception e,
|
private void testApiException(Exception e,
|
||||||
Class<? extends MailboxPairingState> s) throws Exception {
|
Class<? extends MailboxPairingState> s) throws Exception {
|
||||||
|
expectClassifyQrCode(validPayload, MAILBOX, QR_FORMAT_VERSION);
|
||||||
context.checking(new Expectations() {{
|
context.checking(new Expectations() {{
|
||||||
oneOf(crypto).encodeOnion(onionBytes);
|
oneOf(crypto).encodeOnion(onionBytes);
|
||||||
will(returnValue(onion));
|
will(returnValue(onion));
|
||||||
@@ -165,13 +193,14 @@ public class MailboxPairingTaskImplTest extends BrambleMockTestCase {
|
|||||||
will(throwException(e));
|
will(throwException(e));
|
||||||
}});
|
}});
|
||||||
|
|
||||||
MailboxPairingTask task = factory.createPairingTask(validPayload);
|
MailboxPairingTask task = createPairingTask(validPayload);
|
||||||
task.run();
|
task.run();
|
||||||
task.addObserver(state -> assertEquals(state.getClass(), s));
|
task.addObserver(state -> assertEquals(state.getClass(), s));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testDbException() throws Exception {
|
public void testDbException() throws Exception {
|
||||||
|
expectClassifyQrCode(validPayload, MAILBOX, QR_FORMAT_VERSION);
|
||||||
context.checking(new Expectations() {{
|
context.checking(new Expectations() {{
|
||||||
oneOf(crypto).encodeOnion(onionBytes);
|
oneOf(crypto).encodeOnion(onionBytes);
|
||||||
will(returnValue(onion));
|
will(returnValue(onion));
|
||||||
@@ -188,10 +217,10 @@ public class MailboxPairingTaskImplTest extends BrambleMockTestCase {
|
|||||||
will(throwException(new DbException()));
|
will(throwException(new DbException()));
|
||||||
}});
|
}});
|
||||||
|
|
||||||
MailboxPairingTask task = factory.createPairingTask(validPayload);
|
MailboxPairingTask task = createPairingTask(validPayload);
|
||||||
task.run();
|
task.run();
|
||||||
task.addObserver(state -> assertEquals(state.getClass(),
|
task.addObserver(state ->
|
||||||
MailboxPairingState.UnexpectedError.class));
|
assertEquals(state.getClass(), UnexpectedError.class));
|
||||||
}
|
}
|
||||||
|
|
||||||
private PredicateMatcher<MailboxProperties> matches(MailboxProperties p2) {
|
private PredicateMatcher<MailboxProperties> matches(MailboxProperties p2) {
|
||||||
@@ -202,4 +231,22 @@ public class MailboxPairingTaskImplTest extends BrambleMockTestCase {
|
|||||||
p1.getServerSupports().equals(p2.getServerSupports()));
|
p1.getServerSupports().equals(p2.getServerSupports()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private MailboxPairingTask createPairingTask(String qrCodePayload) {
|
||||||
|
context.checking(new Expectations() {{
|
||||||
|
oneOf(clock).currentTimeMillis();
|
||||||
|
will(returnValue(time));
|
||||||
|
}});
|
||||||
|
|
||||||
|
return new MailboxPairingTaskImpl(qrCodePayload, executor, db,
|
||||||
|
crypto, clock, api, mailboxSettingsManager,
|
||||||
|
mailboxUpdateManager, qrCodeClassifier);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void expectClassifyQrCode(String payload, QrCodeType qrCodeType,
|
||||||
|
int formatVersion) {
|
||||||
|
context.checking(new Expectations() {{
|
||||||
|
oneOf(qrCodeClassifier).classifyQrCode(payload);
|
||||||
|
will(returnValue(new Pair<>(qrCodeType, formatVersion)));
|
||||||
|
}});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,7 +3,6 @@ package org.briarproject.bramble.mailbox;
|
|||||||
import org.briarproject.bramble.api.WeakSingletonProvider;
|
import org.briarproject.bramble.api.WeakSingletonProvider;
|
||||||
|
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
import java.nio.charset.Charset;
|
|
||||||
|
|
||||||
import javax.annotation.Nonnull;
|
import javax.annotation.Nonnull;
|
||||||
import javax.net.SocketFactory;
|
import javax.net.SocketFactory;
|
||||||
@@ -11,20 +10,24 @@ import javax.net.SocketFactory;
|
|||||||
import okhttp3.OkHttpClient;
|
import okhttp3.OkHttpClient;
|
||||||
|
|
||||||
import static java.util.concurrent.TimeUnit.MILLISECONDS;
|
import static java.util.concurrent.TimeUnit.MILLISECONDS;
|
||||||
|
import static org.briarproject.bramble.api.mailbox.MailboxConstants.QR_FORMAT_ID;
|
||||||
|
import static org.briarproject.bramble.api.mailbox.MailboxConstants.QR_FORMAT_VERSION;
|
||||||
import static org.briarproject.bramble.test.TestUtils.getRandomId;
|
import static org.briarproject.bramble.test.TestUtils.getRandomId;
|
||||||
|
import static org.briarproject.bramble.util.StringUtils.ISO_8859_1;
|
||||||
|
|
||||||
class MailboxTestUtils {
|
class MailboxTestUtils {
|
||||||
|
|
||||||
static String getQrCodePayload(byte[] onionBytes, byte[] setupToken) {
|
static String getQrCodePayload(byte[] onionBytes, byte[] setupToken) {
|
||||||
|
int formatIdAndVersion = (QR_FORMAT_ID << 5) | QR_FORMAT_VERSION;
|
||||||
byte[] payloadBytes = ByteBuffer.allocate(65)
|
byte[] payloadBytes = ByteBuffer.allocate(65)
|
||||||
.put((byte) 32) // 1
|
.put((byte) formatIdAndVersion) // 1
|
||||||
.put(onionBytes) // 32
|
.put(onionBytes) // 32
|
||||||
.put(setupToken) // 32
|
.put(setupToken) // 32
|
||||||
.array();
|
.array();
|
||||||
//noinspection CharsetObjectCanBeUsed
|
return new String(payloadBytes, ISO_8859_1);
|
||||||
return new String(payloadBytes, Charset.forName("ISO-8859-1"));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Used by mailbox integration tests
|
||||||
static String getQrCodePayload(byte[] setupToken) {
|
static String getQrCodePayload(byte[] setupToken) {
|
||||||
return getQrCodePayload(getRandomId(), setupToken);
|
return getQrCodePayload(getRandomId(), setupToken);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -217,13 +217,13 @@ public class LanTcpPluginTest extends BrambleTestCase {
|
|||||||
// The plugin should have bound a socket and stored the port number
|
// The plugin should have bound a socket and stored the port number
|
||||||
BdfList descriptor = kal.getDescriptor();
|
BdfList descriptor = kal.getDescriptor();
|
||||||
assertEquals(3, descriptor.size());
|
assertEquals(3, descriptor.size());
|
||||||
assertEquals(TRANSPORT_ID_LAN, descriptor.getLong(0).longValue());
|
assertEquals(TRANSPORT_ID_LAN, descriptor.getInt(0).intValue());
|
||||||
byte[] address = descriptor.getRaw(1);
|
byte[] address = descriptor.getRaw(1);
|
||||||
InetAddress addr = InetAddress.getByAddress(address);
|
InetAddress addr = InetAddress.getByAddress(address);
|
||||||
assertTrue(addr instanceof Inet4Address);
|
assertTrue(addr instanceof Inet4Address);
|
||||||
assertFalse(addr.isLoopbackAddress());
|
assertFalse(addr.isLoopbackAddress());
|
||||||
assertTrue(addr.isLinkLocalAddress() || addr.isSiteLocalAddress());
|
assertTrue(addr.isLinkLocalAddress() || addr.isSiteLocalAddress());
|
||||||
int port = descriptor.getLong(2).intValue();
|
int port = descriptor.getInt(2);
|
||||||
assertTrue(port > 0 && port < 65536);
|
assertTrue(port > 0 && port < 65536);
|
||||||
// The plugin should be listening on the port
|
// The plugin should be listening on the port
|
||||||
InetSocketAddress socketAddr = new InetSocketAddress(addr, port);
|
InetSocketAddress socketAddr = new InetSocketAddress(addr, port);
|
||||||
|
|||||||
@@ -404,7 +404,7 @@ public class TransportPropertyManagerImplTest extends BrambleMockTestCase {
|
|||||||
oneOf(clientHelper).getMessageMetadataAsDictionary(txn,
|
oneOf(clientHelper).getMessageMetadataAsDictionary(txn,
|
||||||
localGroup.getId());
|
localGroup.getId());
|
||||||
will(returnValue(messageMetadata));
|
will(returnValue(messageMetadata));
|
||||||
oneOf(clientHelper).getMessageAsList(txn, fooUpdateId);
|
oneOf(clientHelper).getMessageAsList(txn, fooUpdateId, false);
|
||||||
will(returnValue(fooUpdate));
|
will(returnValue(fooUpdate));
|
||||||
oneOf(clientHelper).parseAndValidateTransportProperties(
|
oneOf(clientHelper).parseAndValidateTransportProperties(
|
||||||
fooPropertiesDict);
|
fooPropertiesDict);
|
||||||
@@ -471,7 +471,7 @@ public class TransportPropertyManagerImplTest extends BrambleMockTestCase {
|
|||||||
oneOf(clientHelper).getMessageMetadataAsDictionary(txn,
|
oneOf(clientHelper).getMessageMetadataAsDictionary(txn,
|
||||||
contactGroup2.getId());
|
contactGroup2.getId());
|
||||||
will(returnValue(messageMetadata));
|
will(returnValue(messageMetadata));
|
||||||
oneOf(clientHelper).getMessageAsList(txn, fooUpdateId);
|
oneOf(clientHelper).getMessageAsList(txn, fooUpdateId, false);
|
||||||
will(returnValue(fooUpdate));
|
will(returnValue(fooUpdate));
|
||||||
oneOf(clientHelper).parseAndValidateTransportProperties(
|
oneOf(clientHelper).parseAndValidateTransportProperties(
|
||||||
fooPropertiesDict);
|
fooPropertiesDict);
|
||||||
@@ -526,7 +526,7 @@ public class TransportPropertyManagerImplTest extends BrambleMockTestCase {
|
|||||||
oneOf(clientHelper).getMessageMetadataAsDictionary(txn,
|
oneOf(clientHelper).getMessageMetadataAsDictionary(txn,
|
||||||
contactGroup.getId());
|
contactGroup.getId());
|
||||||
will(returnValue(messageMetadata));
|
will(returnValue(messageMetadata));
|
||||||
oneOf(clientHelper).getMessageAsList(txn, updateId);
|
oneOf(clientHelper).getMessageAsList(txn, updateId, false);
|
||||||
will(returnValue(update));
|
will(returnValue(update));
|
||||||
oneOf(clientHelper).parseAndValidateTransportProperties(
|
oneOf(clientHelper).parseAndValidateTransportProperties(
|
||||||
fooPropertiesDict);
|
fooPropertiesDict);
|
||||||
@@ -564,7 +564,7 @@ public class TransportPropertyManagerImplTest extends BrambleMockTestCase {
|
|||||||
oneOf(clientHelper).getMessageMetadataAsDictionary(txn,
|
oneOf(clientHelper).getMessageMetadataAsDictionary(txn,
|
||||||
localGroup.getId());
|
localGroup.getId());
|
||||||
will(returnValue(messageMetadata));
|
will(returnValue(messageMetadata));
|
||||||
oneOf(clientHelper).getMessageAsList(txn, updateId);
|
oneOf(clientHelper).getMessageAsList(txn, updateId, false);
|
||||||
will(returnValue(update));
|
will(returnValue(update));
|
||||||
oneOf(clientHelper).parseAndValidateTransportProperties(
|
oneOf(clientHelper).parseAndValidateTransportProperties(
|
||||||
fooPropertiesDict);
|
fooPropertiesDict);
|
||||||
@@ -695,7 +695,8 @@ public class TransportPropertyManagerImplTest extends BrambleMockTestCase {
|
|||||||
oneOf(clientHelper).getMessageMetadataAsDictionary(txn,
|
oneOf(clientHelper).getMessageMetadataAsDictionary(txn,
|
||||||
localGroup.getId());
|
localGroup.getId());
|
||||||
will(returnValue(localGroupMessageMetadata));
|
will(returnValue(localGroupMessageMetadata));
|
||||||
oneOf(clientHelper).getMessageAsList(txn, localGroupUpdateId);
|
oneOf(clientHelper).getMessageAsList(txn, localGroupUpdateId,
|
||||||
|
false);
|
||||||
will(returnValue(oldUpdate));
|
will(returnValue(oldUpdate));
|
||||||
oneOf(clientHelper).parseAndValidateTransportProperties(
|
oneOf(clientHelper).parseAndValidateTransportProperties(
|
||||||
oldPropertiesDict);
|
oldPropertiesDict);
|
||||||
@@ -760,7 +761,8 @@ public class TransportPropertyManagerImplTest extends BrambleMockTestCase {
|
|||||||
oneOf(clientHelper).getMessageMetadataAsDictionary(txn,
|
oneOf(clientHelper).getMessageMetadataAsDictionary(txn,
|
||||||
localGroup.getId());
|
localGroup.getId());
|
||||||
will(returnValue(localGroupMessageMetadata));
|
will(returnValue(localGroupMessageMetadata));
|
||||||
oneOf(clientHelper).getMessageAsList(txn, localGroupUpdateId);
|
oneOf(clientHelper).getMessageAsList(txn, localGroupUpdateId,
|
||||||
|
false);
|
||||||
will(returnValue(oldUpdate));
|
will(returnValue(oldUpdate));
|
||||||
oneOf(clientHelper).parseAndValidateTransportProperties(
|
oneOf(clientHelper).parseAndValidateTransportProperties(
|
||||||
oldPropertiesDict);
|
oldPropertiesDict);
|
||||||
@@ -819,12 +821,12 @@ public class TransportPropertyManagerImplTest extends BrambleMockTestCase {
|
|||||||
localGroup.getId());
|
localGroup.getId());
|
||||||
will(returnValue(messageMetadata));
|
will(returnValue(messageMetadata));
|
||||||
// Retrieve and parse the latest local properties
|
// Retrieve and parse the latest local properties
|
||||||
oneOf(clientHelper).getMessageAsList(txn, fooVersion999);
|
oneOf(clientHelper).getMessageAsList(txn, fooVersion999, false);
|
||||||
will(returnValue(fooUpdate));
|
will(returnValue(fooUpdate));
|
||||||
oneOf(clientHelper).parseAndValidateTransportProperties(
|
oneOf(clientHelper).parseAndValidateTransportProperties(
|
||||||
fooPropertiesDict);
|
fooPropertiesDict);
|
||||||
will(returnValue(fooProperties));
|
will(returnValue(fooProperties));
|
||||||
oneOf(clientHelper).getMessageAsList(txn, barVersion3);
|
oneOf(clientHelper).getMessageAsList(txn, barVersion3, false);
|
||||||
will(returnValue(barUpdate));
|
will(returnValue(barUpdate));
|
||||||
oneOf(clientHelper).parseAndValidateTransportProperties(
|
oneOf(clientHelper).parseAndValidateTransportProperties(
|
||||||
barPropertiesDict);
|
barPropertiesDict);
|
||||||
|
|||||||
@@ -0,0 +1,70 @@
|
|||||||
|
package org.briarproject.bramble.qrcode;
|
||||||
|
|
||||||
|
import org.briarproject.bramble.api.Pair;
|
||||||
|
import org.briarproject.bramble.api.keyagreement.KeyAgreementConstants;
|
||||||
|
import org.briarproject.bramble.api.mailbox.MailboxConstants;
|
||||||
|
import org.briarproject.bramble.api.qrcode.QrCodeClassifier;
|
||||||
|
import org.briarproject.bramble.api.qrcode.QrCodeClassifier.QrCodeType;
|
||||||
|
import org.briarproject.bramble.test.BrambleTestCase;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import static org.briarproject.bramble.api.qrcode.QrCodeClassifier.QrCodeType.BQP;
|
||||||
|
import static org.briarproject.bramble.api.qrcode.QrCodeClassifier.QrCodeType.MAILBOX;
|
||||||
|
import static org.briarproject.bramble.api.qrcode.QrCodeClassifier.QrCodeType.UNKNOWN;
|
||||||
|
import static org.briarproject.bramble.test.TestUtils.getRandomBytes;
|
||||||
|
import static org.briarproject.bramble.util.StringUtils.ISO_8859_1;
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
|
||||||
|
public class QrCodeClassifierImplTest extends BrambleTestCase {
|
||||||
|
|
||||||
|
private final QrCodeClassifier classifier = new QrCodeClassifierImpl();
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testClassifiesEmptyStringAsUnknown() {
|
||||||
|
Pair<QrCodeType, Integer> result = classifier.classifyQrCode("");
|
||||||
|
assertEquals(UNKNOWN, result.getFirst());
|
||||||
|
assertEquals(0, result.getSecond().intValue());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testClassifiesKeyAgreement() {
|
||||||
|
byte[] payloadBytes = getRandomBytes(123);
|
||||||
|
for (int version = 0; version < 32; version++) {
|
||||||
|
int typeAndVersion =
|
||||||
|
(KeyAgreementConstants.QR_FORMAT_ID << 5) | version;
|
||||||
|
payloadBytes[0] = (byte) typeAndVersion;
|
||||||
|
String payload = new String(payloadBytes, ISO_8859_1);
|
||||||
|
Pair<QrCodeType, Integer> result =
|
||||||
|
classifier.classifyQrCode(payload);
|
||||||
|
assertEquals(BQP, result.getFirst());
|
||||||
|
assertEquals(version, result.getSecond().intValue());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testClassifiesMailbox() {
|
||||||
|
byte[] payloadBytes = getRandomBytes(123);
|
||||||
|
for (int version = 0; version < 32; version++) {
|
||||||
|
int typeAndVersion =
|
||||||
|
(MailboxConstants.QR_FORMAT_ID << 5) | version;
|
||||||
|
payloadBytes[0] = (byte) typeAndVersion;
|
||||||
|
String payload = new String(payloadBytes, ISO_8859_1);
|
||||||
|
Pair<QrCodeType, Integer> result =
|
||||||
|
classifier.classifyQrCode(payload);
|
||||||
|
assertEquals(MAILBOX, result.getFirst());
|
||||||
|
assertEquals(version, result.getSecond().intValue());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testClassifiesUnknownFormatIdAsUnknown() {
|
||||||
|
byte[] payloadBytes = getRandomBytes(123);
|
||||||
|
int unknownFormatId = MailboxConstants.QR_FORMAT_ID + 1;
|
||||||
|
int typeAndVersion = unknownFormatId << 5;
|
||||||
|
payloadBytes[0] = (byte) typeAndVersion;
|
||||||
|
String payload = new String(payloadBytes, ISO_8859_1);
|
||||||
|
Pair<QrCodeType, Integer> result = classifier.classifyQrCode(payload);
|
||||||
|
assertEquals(UNKNOWN, result.getFirst());
|
||||||
|
assertEquals(0, result.getSecond().intValue());
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -6,13 +6,18 @@ import org.briarproject.bramble.api.UniqueId;
|
|||||||
import org.briarproject.bramble.api.record.Record;
|
import org.briarproject.bramble.api.record.Record;
|
||||||
import org.briarproject.bramble.api.record.RecordReader;
|
import org.briarproject.bramble.api.record.RecordReader;
|
||||||
import org.briarproject.bramble.api.sync.Ack;
|
import org.briarproject.bramble.api.sync.Ack;
|
||||||
|
import org.briarproject.bramble.api.sync.GroupId;
|
||||||
|
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.Offer;
|
import org.briarproject.bramble.api.sync.Offer;
|
||||||
import org.briarproject.bramble.api.sync.Priority;
|
import org.briarproject.bramble.api.sync.Priority;
|
||||||
import org.briarproject.bramble.api.sync.Request;
|
import org.briarproject.bramble.api.sync.Request;
|
||||||
import org.briarproject.bramble.api.sync.SyncRecordReader;
|
import org.briarproject.bramble.api.sync.SyncRecordReader;
|
||||||
import org.briarproject.bramble.api.sync.Versions;
|
import org.briarproject.bramble.api.sync.Versions;
|
||||||
import org.briarproject.bramble.test.BrambleMockTestCase;
|
import org.briarproject.bramble.test.BrambleMockTestCase;
|
||||||
|
import org.briarproject.bramble.test.PredicateMatcher;
|
||||||
|
import org.hamcrest.Matcher;
|
||||||
import org.jmock.Expectations;
|
import org.jmock.Expectations;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
@@ -23,12 +28,15 @@ import javax.annotation.Nullable;
|
|||||||
|
|
||||||
import static org.briarproject.bramble.api.record.Record.MAX_RECORD_PAYLOAD_BYTES;
|
import static org.briarproject.bramble.api.record.Record.MAX_RECORD_PAYLOAD_BYTES;
|
||||||
import static org.briarproject.bramble.api.sync.RecordTypes.ACK;
|
import static org.briarproject.bramble.api.sync.RecordTypes.ACK;
|
||||||
|
import static org.briarproject.bramble.api.sync.RecordTypes.MESSAGE;
|
||||||
import static org.briarproject.bramble.api.sync.RecordTypes.OFFER;
|
import static org.briarproject.bramble.api.sync.RecordTypes.OFFER;
|
||||||
import static org.briarproject.bramble.api.sync.RecordTypes.PRIORITY;
|
import static org.briarproject.bramble.api.sync.RecordTypes.PRIORITY;
|
||||||
import static org.briarproject.bramble.api.sync.RecordTypes.REQUEST;
|
import static org.briarproject.bramble.api.sync.RecordTypes.REQUEST;
|
||||||
import static org.briarproject.bramble.api.sync.RecordTypes.VERSIONS;
|
import static org.briarproject.bramble.api.sync.RecordTypes.VERSIONS;
|
||||||
|
import static org.briarproject.bramble.api.sync.SyncConstants.MAX_MESSAGE_BODY_LENGTH;
|
||||||
import static org.briarproject.bramble.api.sync.SyncConstants.MAX_MESSAGE_IDS;
|
import static org.briarproject.bramble.api.sync.SyncConstants.MAX_MESSAGE_IDS;
|
||||||
import static org.briarproject.bramble.api.sync.SyncConstants.MAX_SUPPORTED_VERSIONS;
|
import static org.briarproject.bramble.api.sync.SyncConstants.MAX_SUPPORTED_VERSIONS;
|
||||||
|
import static org.briarproject.bramble.api.sync.SyncConstants.MESSAGE_HEADER_LENGTH;
|
||||||
import static org.briarproject.bramble.api.sync.SyncConstants.PRIORITY_NONCE_BYTES;
|
import static org.briarproject.bramble.api.sync.SyncConstants.PRIORITY_NONCE_BYTES;
|
||||||
import static org.briarproject.bramble.api.sync.SyncConstants.PROTOCOL_VERSION;
|
import static org.briarproject.bramble.api.sync.SyncConstants.PROTOCOL_VERSION;
|
||||||
import static org.briarproject.bramble.test.TestUtils.getRandomBytes;
|
import static org.briarproject.bramble.test.TestUtils.getRandomBytes;
|
||||||
@@ -46,6 +54,38 @@ public class SyncRecordReaderImplTest extends BrambleMockTestCase {
|
|||||||
private final SyncRecordReader reader =
|
private final SyncRecordReader reader =
|
||||||
new SyncRecordReaderImpl(messageFactory, recordReader);
|
new SyncRecordReaderImpl(messageFactory, recordReader);
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testNoFormatExceptionIfMessageIsMinimumSize() throws Exception {
|
||||||
|
expectReadRecord(createMessage(MESSAGE_HEADER_LENGTH + 1));
|
||||||
|
expectCreateMessage(1);
|
||||||
|
|
||||||
|
reader.readMessage();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expected = FormatException.class)
|
||||||
|
public void testFormatExceptionIfMessageIsTooSmall() throws Exception {
|
||||||
|
expectReadRecord(createMessage(MESSAGE_HEADER_LENGTH));
|
||||||
|
|
||||||
|
reader.readMessage();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testNoFormatExceptionIfMessageIsMaximumSize() throws Exception {
|
||||||
|
expectReadRecord(createMessage(MESSAGE_HEADER_LENGTH
|
||||||
|
+ MAX_MESSAGE_BODY_LENGTH));
|
||||||
|
expectCreateMessage(MAX_MESSAGE_BODY_LENGTH);
|
||||||
|
|
||||||
|
reader.readMessage();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expected = FormatException.class)
|
||||||
|
public void testFormatExceptionIfMessageIsTooLarge() throws Exception {
|
||||||
|
expectReadRecord(createMessage(MESSAGE_HEADER_LENGTH
|
||||||
|
+ MAX_MESSAGE_BODY_LENGTH + 1));
|
||||||
|
|
||||||
|
reader.readMessage();
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testNoFormatExceptionIfAckIsMaximumSize() throws Exception {
|
public void testNoFormatExceptionIfAckIsMaximumSize() throws Exception {
|
||||||
expectReadRecord(createAck());
|
expectReadRecord(createAck());
|
||||||
@@ -158,6 +198,20 @@ public class SyncRecordReaderImplTest extends BrambleMockTestCase {
|
|||||||
assertTrue(reader.eof());
|
assertTrue(reader.eof());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void expectCreateMessage(int bodyLength) {
|
||||||
|
MessageId messageId = new MessageId(getRandomId());
|
||||||
|
GroupId groupId = new GroupId(getRandomId());
|
||||||
|
long timestamp = System.currentTimeMillis();
|
||||||
|
|
||||||
|
context.checking(new Expectations() {{
|
||||||
|
Matcher<byte[]> matcher = new PredicateMatcher<>(byte[].class,
|
||||||
|
b -> b.length == MESSAGE_HEADER_LENGTH + bodyLength);
|
||||||
|
oneOf(messageFactory).createMessage(with(matcher));
|
||||||
|
will(returnValue(new Message(messageId, groupId, timestamp,
|
||||||
|
new byte[bodyLength])));
|
||||||
|
}});
|
||||||
|
}
|
||||||
|
|
||||||
private void expectReadRecord(@Nullable Record record) throws Exception {
|
private void expectReadRecord(@Nullable Record record) throws Exception {
|
||||||
context.checking(new Expectations() {{
|
context.checking(new Expectations() {{
|
||||||
//noinspection unchecked
|
//noinspection unchecked
|
||||||
@@ -167,6 +221,10 @@ public class SyncRecordReaderImplTest extends BrambleMockTestCase {
|
|||||||
}});
|
}});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private Record createMessage(int payloadLength) {
|
||||||
|
return new Record(PROTOCOL_VERSION, MESSAGE, new byte[payloadLength]);
|
||||||
|
}
|
||||||
|
|
||||||
private Record createAck() throws Exception {
|
private Record createAck() throws Exception {
|
||||||
return new Record(PROTOCOL_VERSION, ACK, createPayload());
|
return new Record(PROTOCOL_VERSION, ACK, createPayload());
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,6 +10,8 @@ import java.util.List;
|
|||||||
|
|
||||||
import javax.annotation.Nonnull;
|
import javax.annotation.Nonnull;
|
||||||
|
|
||||||
|
import static java.lang.Double.compare;
|
||||||
|
import static java.lang.Double.parseDouble;
|
||||||
import static org.briarproject.bramble.test.UTest.Result.INCONCLUSIVE;
|
import static org.briarproject.bramble.test.UTest.Result.INCONCLUSIVE;
|
||||||
import static org.briarproject.bramble.test.UTest.Result.LARGER;
|
import static org.briarproject.bramble.test.UTest.Result.LARGER;
|
||||||
import static org.briarproject.bramble.test.UTest.Result.SMALLER;
|
import static org.briarproject.bramble.test.UTest.Result.SMALLER;
|
||||||
@@ -134,7 +136,7 @@ public class UTest {
|
|||||||
if (nA < 5 || nB < 5) die("Too few values for U test\n");
|
if (nA < 5 || nB < 5) die("Too few values for U test\n");
|
||||||
|
|
||||||
double zCritical;
|
double zCritical;
|
||||||
if (args.length == 3) zCritical = Double.valueOf(args[2]);
|
if (args.length == 3) zCritical = parseDouble(args[2]);
|
||||||
else zCritical = Z_CRITICAL_0_01;
|
else zCritical = Z_CRITICAL_0_01;
|
||||||
|
|
||||||
switch (test(a, b, zCritical)) {
|
switch (test(a, b, zCritical)) {
|
||||||
@@ -161,7 +163,7 @@ public class UTest {
|
|||||||
BufferedReader in;
|
BufferedReader in;
|
||||||
in = new BufferedReader(new FileReader(filename));
|
in = new BufferedReader(new FileReader(filename));
|
||||||
String s;
|
String s;
|
||||||
while ((s = in.readLine()) != null) values.add(new Double(s));
|
while ((s = in.readLine()) != null) values.add(parseDouble(s));
|
||||||
in.close();
|
in.close();
|
||||||
} catch (FileNotFoundException fnf) {
|
} catch (FileNotFoundException fnf) {
|
||||||
die(filename + " not found");
|
die(filename + " not found");
|
||||||
@@ -187,9 +189,7 @@ public class UTest {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int compareTo(@Nonnull Value v) {
|
public int compareTo(@Nonnull Value v) {
|
||||||
if (value < v.value) return -1;
|
return compare(value, v.value);
|
||||||
if (value > v.value) return 1;
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -88,51 +88,58 @@ public class StringUtilsTest extends BrambleTestCase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testFromUtf8AcceptsNullCharacterUsingStandardUtf8() {
|
public void testFromUtf8AcceptsNullCharacterUsingStandardUtf8()
|
||||||
|
throws Exception {
|
||||||
// The UTF-8 encoding of the null character is valid
|
// The UTF-8 encoding of the null character is valid
|
||||||
assertEquals("\u0000", StringUtils.fromUtf8(new byte[1]));
|
byte[] utf8 = new byte[1];
|
||||||
|
String actual = StringUtils.fromUtf8(utf8);
|
||||||
|
assertEquals("\u0000", actual);
|
||||||
|
// When we convert back to UTF-8 we should get the original encoding
|
||||||
|
assertArrayEquals(utf8, StringUtils.toUtf8(actual));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test(expected = FormatException.class)
|
||||||
public void testFromUtf8RemovesNullCharacterUsingModifiedUtf8() {
|
public void testFromUtf8RejectsNullCharacterUsingModifiedUtf8()
|
||||||
|
throws Exception {
|
||||||
// The modified UTF-8 encoding of the null character is not valid
|
// The modified UTF-8 encoding of the null character is not valid
|
||||||
byte[] b = new byte[] {
|
byte[] b = new byte[] {
|
||||||
(byte) 0xC0, (byte) 0x80, // Null character as modified UTF-8
|
(byte) 0xC0, (byte) 0x80, // Null character as modified UTF-8
|
||||||
(byte) 0xC8, (byte) 0x85 // U+0205
|
(byte) 0xC8, (byte) 0x85 // U+0205
|
||||||
};
|
};
|
||||||
// Conversion should ignore the invalid character and return the rest
|
StringUtils.fromUtf8(b);
|
||||||
String expected = "\u0205";
|
|
||||||
assertEquals(expected, StringUtils.fromUtf8(b));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testFromUtf8AcceptsSupplementaryCharacterUsingStandardUtf8() {
|
public void testFromUtf8AcceptsSupplementaryCharacterUsingStandardUtf8()
|
||||||
|
throws Exception {
|
||||||
// The UTF-8 encoding of a supplementary character is valid and should
|
// The UTF-8 encoding of a supplementary character is valid and should
|
||||||
// be converted to a surrogate pair
|
// be converted to a surrogate pair
|
||||||
byte[] b = new byte[] {
|
byte[] utf8 = new byte[] {
|
||||||
(byte) 0xF0, (byte) 0x90, (byte) 0x90, (byte) 0x80, // U+10400
|
(byte) 0xF0, (byte) 0x90, (byte) 0x90, (byte) 0x80, // U+10400
|
||||||
(byte) 0xC8, (byte) 0x85 // U+0205
|
(byte) 0xC8, (byte) 0x85 // U+0205
|
||||||
};
|
};
|
||||||
String expected = "\uD801\uDC00\u0205"; // Surrogate pair
|
String expected = "\uD801\uDC00\u0205"; // Surrogate pair
|
||||||
assertEquals(expected, StringUtils.fromUtf8(b));
|
String actual = StringUtils.fromUtf8(utf8);
|
||||||
|
assertEquals(expected, actual);
|
||||||
|
// When we convert back to UTF-8 we should get the original encoding
|
||||||
|
assertArrayEquals(utf8, StringUtils.toUtf8(actual));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test(expected = FormatException.class)
|
||||||
public void testFromUtf8RemovesSupplementaryCharacterUsingModifiedUtf8() {
|
public void testFromUtf8RejectsSupplementaryCharacterUsingModifiedUtf8()
|
||||||
|
throws Exception {
|
||||||
// The CESU-8 or modified UTF-8 encoding of a supplementary character
|
// The CESU-8 or modified UTF-8 encoding of a supplementary character
|
||||||
// is not valid
|
// is not valid
|
||||||
byte[] b = new byte[] {
|
byte[] utf8 = new byte[] {
|
||||||
(byte) 0xED, (byte) 0xA0, (byte) 0x81, // U+10400 as CSEU-8
|
(byte) 0xED, (byte) 0xA0, (byte) 0x81, // U+10400 as CSEU-8
|
||||||
(byte) 0xED, (byte) 0xB0, (byte) 0x80,
|
(byte) 0xED, (byte) 0xB0, (byte) 0x80,
|
||||||
(byte) 0xC8, (byte) 0x85 // U+0205
|
(byte) 0xC8, (byte) 0x85 // U+0205
|
||||||
};
|
};
|
||||||
// Conversion should ignore the invalid character and return the rest
|
StringUtils.fromUtf8(utf8);
|
||||||
String expected = "\u0205";
|
|
||||||
assertEquals(expected, StringUtils.fromUtf8(b));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testFromUtf8EmptyInput() {
|
public void testFromUtf8EmptyInput() throws Exception {
|
||||||
assertEquals("", StringUtils.fromUtf8(new byte[0]));
|
assertEquals("", StringUtils.fromUtf8(new byte[0]));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -7,24 +7,17 @@ apply plugin: 'witness'
|
|||||||
apply from: 'witness.gradle'
|
apply from: 'witness.gradle'
|
||||||
apply from: '../dagger.gradle'
|
apply from: '../dagger.gradle'
|
||||||
|
|
||||||
configurations {
|
|
||||||
tor
|
|
||||||
}
|
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
implementation project(':bramble-core')
|
implementation project(':bramble-core')
|
||||||
|
|
||||||
implementation fileTree(dir: 'libs', include: '*.jar')
|
implementation fileTree(dir: 'libs', include: '*.jar')
|
||||||
def jna_version = '4.5.2'
|
def jna_version = '5.10.0'
|
||||||
implementation "net.java.dev.jna:jna:$jna_version"
|
implementation "net.java.dev.jna:jna:$jna_version"
|
||||||
implementation "net.java.dev.jna:jna-platform:$jna_version"
|
implementation "net.java.dev.jna:jna-platform:$jna_version"
|
||||||
|
|
||||||
tor "org.briarproject:tor-linux:$tor_version"
|
testImplementation "org.briarproject:tor-linux:$tor_version"
|
||||||
tor "org.briarproject:tor-windows:$tor_version"
|
testImplementation "org.briarproject:obfs4proxy-linux:$obfs4proxy_version"
|
||||||
tor "org.briarproject:obfs4proxy-linux:$obfs4proxy_version"
|
testImplementation "org.briarproject:snowflake-linux:$snowflake_version"
|
||||||
tor "org.briarproject:obfs4proxy-windows:$obfs4proxy_version"
|
|
||||||
tor "org.briarproject:snowflake-linux:$snowflake_version"
|
|
||||||
tor "org.briarproject:snowflake-windows:$snowflake_version"
|
|
||||||
|
|
||||||
annotationProcessor "com.google.dagger:dagger-compiler:$dagger_version"
|
annotationProcessor "com.google.dagger:dagger-compiler:$dagger_version"
|
||||||
|
|
||||||
@@ -39,31 +32,6 @@ dependencies {
|
|||||||
testAnnotationProcessor "com.google.dagger:dagger-compiler:$dagger_version"
|
testAnnotationProcessor "com.google.dagger:dagger-compiler:$dagger_version"
|
||||||
}
|
}
|
||||||
|
|
||||||
def torBinariesDir = 'src/main/resources'
|
|
||||||
|
|
||||||
task cleanTorBinaries {
|
|
||||||
doLast {
|
|
||||||
delete fileTree(torBinariesDir) { include '*.zip' }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
clean.dependsOn cleanTorBinaries
|
|
||||||
|
|
||||||
task unpackTorBinaries {
|
|
||||||
doLast {
|
|
||||||
copy {
|
|
||||||
from configurations.tor.collect { zipTree(it) }
|
|
||||||
into torBinariesDir
|
|
||||||
}
|
|
||||||
}
|
|
||||||
dependsOn cleanTorBinaries
|
|
||||||
}
|
|
||||||
|
|
||||||
processResources {
|
|
||||||
inputs.dir torBinariesDir
|
|
||||||
dependsOn unpackTorBinaries
|
|
||||||
}
|
|
||||||
|
|
||||||
tasks.withType(Test) {
|
tasks.withType(Test) {
|
||||||
systemProperty 'java.library.path', 'libs'
|
systemProperty 'java.library.path', 'libs'
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,7 +12,6 @@ import java.io.InputStream;
|
|||||||
import java.io.OutputStream;
|
import java.io.OutputStream;
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
import java.nio.charset.CharacterCodingException;
|
import java.nio.charset.CharacterCodingException;
|
||||||
import java.nio.charset.Charset;
|
|
||||||
import java.nio.charset.CharsetDecoder;
|
import java.nio.charset.CharsetDecoder;
|
||||||
import java.util.concurrent.Executor;
|
import java.util.concurrent.Executor;
|
||||||
import java.util.concurrent.Semaphore;
|
import java.util.concurrent.Semaphore;
|
||||||
@@ -33,6 +32,7 @@ import static java.util.logging.Level.WARNING;
|
|||||||
import static jssc.SerialPort.PURGE_RXCLEAR;
|
import static jssc.SerialPort.PURGE_RXCLEAR;
|
||||||
import static jssc.SerialPort.PURGE_TXCLEAR;
|
import static jssc.SerialPort.PURGE_TXCLEAR;
|
||||||
import static org.briarproject.bramble.util.LogUtils.logException;
|
import static org.briarproject.bramble.util.LogUtils.logException;
|
||||||
|
import static org.briarproject.bramble.util.StringUtils.US_ASCII;
|
||||||
|
|
||||||
@MethodsNotNullByDefault
|
@MethodsNotNullByDefault
|
||||||
@ParametersNotNullByDefault
|
@ParametersNotNullByDefault
|
||||||
@@ -41,7 +41,6 @@ class ModemImpl implements Modem, WriteHandler, SerialPortEventListener {
|
|||||||
private static final Logger LOG =
|
private static final Logger LOG =
|
||||||
Logger.getLogger(ModemImpl.class.getName());
|
Logger.getLogger(ModemImpl.class.getName());
|
||||||
|
|
||||||
private static final Charset US_ASCII = Charset.forName("US-ASCII");
|
|
||||||
private static final int MAX_LINE_LENGTH = 256;
|
private static final int MAX_LINE_LENGTH = 256;
|
||||||
private static final int[] BAUD_RATES = {
|
private static final int[] BAUD_RATES = {
|
||||||
256000, 128000, 115200, 57600, 38400, 19200, 14400, 9600, 4800, 1200
|
256000, 128000, 115200, 57600, 38400, 19200, 14400, 9600, 4800, 1200
|
||||||
|
|||||||
@@ -53,7 +53,7 @@ class UnixTorPlugin extends JavaTorPlugin {
|
|||||||
|
|
||||||
private interface CLibrary extends Library {
|
private interface CLibrary extends Library {
|
||||||
|
|
||||||
CLibrary INSTANCE = Native.loadLibrary("c", CLibrary.class);
|
CLibrary INSTANCE = Native.load("c", CLibrary.class);
|
||||||
|
|
||||||
int getpid();
|
int getpid();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -27,6 +27,7 @@ import javax.net.SocketFactory;
|
|||||||
|
|
||||||
import static java.util.logging.Level.INFO;
|
import static java.util.logging.Level.INFO;
|
||||||
import static org.briarproject.bramble.util.OsUtils.isLinux;
|
import static org.briarproject.bramble.util.OsUtils.isLinux;
|
||||||
|
import static org.briarproject.bramble.util.OsUtils.isMac;
|
||||||
|
|
||||||
@Immutable
|
@Immutable
|
||||||
@NotNullByDefault
|
@NotNullByDefault
|
||||||
@@ -57,14 +58,18 @@ public class UnixTorPluginFactory extends TorPluginFactory {
|
|||||||
@Nullable
|
@Nullable
|
||||||
@Override
|
@Override
|
||||||
String getArchitectureForTorBinary() {
|
String getArchitectureForTorBinary() {
|
||||||
if (!isLinux()) return null;
|
if (!isLinux() && !isMac()) return null;
|
||||||
String arch = System.getProperty("os.arch");
|
String arch = System.getProperty("os.arch");
|
||||||
if (LOG.isLoggable(INFO)) {
|
if (LOG.isLoggable(INFO)) {
|
||||||
LOG.info("System's os.arch is " + arch);
|
LOG.info("System's os.arch is " + arch);
|
||||||
}
|
}
|
||||||
if (arch.equals("amd64")) return "linux-x86_64";
|
if (isLinux()) {
|
||||||
else if (arch.equals("aarch64")) return "linux-aarch64";
|
if (arch.equals("amd64")) return "x86_64";
|
||||||
else if (arch.equals("arm")) return "linux-armhf";
|
else if (arch.equals("aarch64")) return "aarch64";
|
||||||
|
else if (arch.equals("arm")) return "armhf";
|
||||||
|
} else if (isMac()) {
|
||||||
|
return "any";
|
||||||
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -94,4 +94,8 @@ class WindowsTorPlugin extends JavaTorPlugin {
|
|||||||
if (!success.take()) throw new PluginException();
|
if (!success.take()) throw new PluginException();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected String getExecutableExtension() {
|
||||||
|
return ".exe";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -62,7 +62,7 @@ public class WindowsTorPluginFactory extends TorPluginFactory {
|
|||||||
if (LOG.isLoggable(INFO)) {
|
if (LOG.isLoggable(INFO)) {
|
||||||
LOG.info("System's os.arch is " + arch);
|
LOG.info("System's os.arch is " + arch);
|
||||||
}
|
}
|
||||||
if (arch.equals("amd64")) return "windows-x86_64";
|
if (arch.equals("amd64")) return "x86_64";
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,40 @@
|
|||||||
|
package org.briarproject.bramble.test;
|
||||||
|
|
||||||
|
import org.briarproject.bramble.util.OsUtils;
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import java.io.InputStream;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertNotNull;
|
||||||
|
import static org.junit.Assume.assumeTrue;
|
||||||
|
|
||||||
|
public class TestResources {
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void isRunningOnLinux() {
|
||||||
|
assumeTrue(OsUtils.isLinux());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void canReadTorLinux() {
|
||||||
|
InputStream input = Thread.currentThread().getContextClassLoader()
|
||||||
|
.getResourceAsStream("x86_64/tor");
|
||||||
|
assertNotNull(input);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void canReadObfs4ProxyLinux() {
|
||||||
|
InputStream input = Thread.currentThread().getContextClassLoader()
|
||||||
|
.getResourceAsStream("x86_64/obfs4proxy");
|
||||||
|
assertNotNull(input);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void canReadSnowflakeLinux() {
|
||||||
|
InputStream input = Thread.currentThread().getContextClassLoader()
|
||||||
|
.getResourceAsStream("x86_64/snowflake");
|
||||||
|
assertNotNull(input);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -21,17 +21,14 @@ dependencyVerification {
|
|||||||
'javax.inject:javax.inject:1:javax.inject-1.jar:91c77044a50c481636c32d916fd89c9118a72195390452c81065080f957de7ff',
|
'javax.inject:javax.inject:1:javax.inject-1.jar:91c77044a50c481636c32d916fd89c9118a72195390452c81065080f957de7ff',
|
||||||
'junit:junit:4.13.2:junit-4.13.2.jar:8e495b634469d64fb8acfa3495a065cbacc8a0fff55ce1e31007be4c16dc57d3',
|
'junit:junit:4.13.2:junit-4.13.2.jar:8e495b634469d64fb8acfa3495a065cbacc8a0fff55ce1e31007be4c16dc57d3',
|
||||||
'net.bytebuddy:byte-buddy:1.9.12:byte-buddy-1.9.12.jar:3688c3d434bebc3edc5516296a2ed0f47b65e451071b4afecad84f902f0efc11',
|
'net.bytebuddy:byte-buddy:1.9.12:byte-buddy-1.9.12.jar:3688c3d434bebc3edc5516296a2ed0f47b65e451071b4afecad84f902f0efc11',
|
||||||
'net.java.dev.jna:jna-platform:4.5.2:jna-platform-4.5.2.jar:f1d00c167d8921c6e23c626ef9f1c3ae0be473c95c68ffa012bc7ae55a87e2d6',
|
'net.java.dev.jna:jna-platform:5.10.0:jna-platform-5.10.0.jar:1f71afd977051bf0109ef5e3767d4e2afd777be894d89788cc0f38ad68f6a16f',
|
||||||
'net.java.dev.jna:jna:4.5.2:jna-4.5.2.jar:0c8eb7acf67261656d79005191debaba3b6bf5dd60a43735a245429381dbecff',
|
'net.java.dev.jna:jna:5.10.0:jna-5.10.0.jar:e335c10679f743207d822c5f7948e930319835492575a9dba6b94f8a3b96fcc8',
|
||||||
'net.jcip:jcip-annotations:1.0:jcip-annotations-1.0.jar:be5805392060c71474bf6c9a67a099471274d30b83eef84bfc4e0889a4f1dcc0',
|
'net.jcip:jcip-annotations:1.0:jcip-annotations-1.0.jar:be5805392060c71474bf6c9a67a099471274d30b83eef84bfc4e0889a4f1dcc0',
|
||||||
'net.ltgt.gradle.incap:incap:0.2:incap-0.2.jar:b625b9806b0f1e4bc7a2e3457119488de3cd57ea20feedd513db070a573a4ffd',
|
'net.ltgt.gradle.incap:incap:0.2:incap-0.2.jar:b625b9806b0f1e4bc7a2e3457119488de3cd57ea20feedd513db070a573a4ffd',
|
||||||
'org.apache-extras.beanshell:bsh:2.0b6:bsh-2.0b6.jar:a17955976070c0573235ee662f2794a78082758b61accffce8d3f8aedcd91047',
|
'org.apache-extras.beanshell:bsh:2.0b6:bsh-2.0b6.jar:a17955976070c0573235ee662f2794a78082758b61accffce8d3f8aedcd91047',
|
||||||
'org.briarproject:obfs4proxy-linux:0.0.14-tor1:obfs4proxy-linux-0.0.14-tor1.jar:9783b9c7ec588a5246f534a9c5782783c8c9821825f81c3e0c6f1ecee61cfcbb',
|
'org.briarproject:obfs4proxy-linux:0.0.14:obfs4proxy-linux-0.0.14.jar:6391d323d45a279362236c7c62e21b903d07d4f31f5e0c8d49d009769b720cc6',
|
||||||
'org.briarproject:obfs4proxy-windows:0.0.14-tor1:obfs4proxy-windows-0.0.14-tor1.jar:9dd122b31b3cd1616f168091dcdb01de049d1e052fe5c089b7627618a8a2694b',
|
'org.briarproject:snowflake-linux:2.5.1:snowflake-linux-2.5.1.jar:edc807dcb7758365970d95525e4749349a27f462d0e2df6505ad1ca65fb296d2',
|
||||||
'org.briarproject:snowflake-linux:2.3.1:snowflake-linux-2.3.1.jar:99ecf4546d8f79eb8408168c09380fec596558ac934554bf7d4247ea7ef2c9f3',
|
'org.briarproject:tor-linux:0.4.7.13:tor-linux-0.4.7.13.jar:9819ee973cbcdc133f7d04aef9d4b957a35087627a790e532142d15412a9636f',
|
||||||
'org.briarproject:snowflake-windows:2.3.1:snowflake-windows-2.3.1.jar:d011f1a72c00a221f56380c19aad8ff11db8c2bb1adb0784125572d80b4d275a',
|
|
||||||
'org.briarproject:tor-linux:0.4.5.14:tor-linux-0.4.5.14.jar:1844e54cf6df0c85cec219381a3364c759ae444a6b63f7558b757becb7d41d08',
|
|
||||||
'org.briarproject:tor-windows:0.4.5.14:tor-windows-0.4.5.14.jar:d337afa1043f0cfa7e6e8c2473d682a5663a2c8052bb97a770450893c78c9b4f',
|
|
||||||
'org.checkerframework:checker-compat-qual:2.5.5:checker-compat-qual-2.5.5.jar:11d134b245e9cacc474514d2d66b5b8618f8039a1465cdc55bbc0b34e0008b7a',
|
'org.checkerframework:checker-compat-qual:2.5.5:checker-compat-qual-2.5.5.jar:11d134b245e9cacc474514d2d66b5b8618f8039a1465cdc55bbc0b34e0008b7a',
|
||||||
'org.checkerframework:checker-qual:3.12.0:checker-qual-3.12.0.jar:ff10785ac2a357ec5de9c293cb982a2cbb605c0309ea4cc1cb9b9bc6dbe7f3cb',
|
'org.checkerframework:checker-qual:3.12.0:checker-qual-3.12.0.jar:ff10785ac2a357ec5de9c293cb982a2cbb605c0309ea4cc1cb9b9bc6dbe7f3cb',
|
||||||
'org.hamcrest:hamcrest-core:2.1:hamcrest-core-2.1.jar:e09109e54a289d88506b9bfec987ddd199f4217c9464132668351b9a4f00bee9',
|
'org.hamcrest:hamcrest-core:2.1:hamcrest-core-2.1.jar:e09109e54a289d88506b9bfec987ddd199f4217c9464132668351b9a4f00bee9',
|
||||||
|
|||||||
@@ -26,8 +26,8 @@ android {
|
|||||||
defaultConfig {
|
defaultConfig {
|
||||||
minSdkVersion 16
|
minSdkVersion 16
|
||||||
targetSdkVersion 31
|
targetSdkVersion 31
|
||||||
versionCode 10418
|
versionCode 10423
|
||||||
versionName "1.4.18"
|
versionName "1.4.23"
|
||||||
applicationId "org.briarproject.briar.android"
|
applicationId "org.briarproject.briar.android"
|
||||||
buildConfigField "String", "TorVersion", "\"$tor_version\""
|
buildConfigField "String", "TorVersion", "\"$tor_version\""
|
||||||
|
|
||||||
|
|||||||
@@ -52,7 +52,6 @@ import static org.briarproject.bramble.api.lifecycle.LifecycleManager.StartResul
|
|||||||
import static org.briarproject.bramble.api.lifecycle.LifecycleManager.StartResult.SUCCESS;
|
import static org.briarproject.bramble.api.lifecycle.LifecycleManager.StartResult.SUCCESS;
|
||||||
import static org.briarproject.bramble.util.AndroidUtils.isUiThread;
|
import static org.briarproject.bramble.util.AndroidUtils.isUiThread;
|
||||||
import static org.briarproject.briar.android.BriarApplication.ENTRY_ACTIVITY;
|
import static org.briarproject.briar.android.BriarApplication.ENTRY_ACTIVITY;
|
||||||
import static org.briarproject.briar.api.android.AndroidNotificationManager.FAILURE_CHANNEL_ID;
|
|
||||||
import static org.briarproject.briar.api.android.AndroidNotificationManager.ONGOING_CHANNEL_ID;
|
import static org.briarproject.briar.api.android.AndroidNotificationManager.ONGOING_CHANNEL_ID;
|
||||||
import static org.briarproject.briar.api.android.AndroidNotificationManager.ONGOING_CHANNEL_OLD_ID;
|
import static org.briarproject.briar.api.android.AndroidNotificationManager.ONGOING_CHANNEL_OLD_ID;
|
||||||
import static org.briarproject.briar.api.android.AndroidNotificationManager.ONGOING_NOTIFICATION_ID;
|
import static org.briarproject.briar.api.android.AndroidNotificationManager.ONGOING_NOTIFICATION_ID;
|
||||||
@@ -141,11 +140,6 @@ public class BriarService extends Service {
|
|||||||
ongoingChannel.setLockscreenVisibility(VISIBILITY_SECRET);
|
ongoingChannel.setLockscreenVisibility(VISIBILITY_SECRET);
|
||||||
ongoingChannel.setShowBadge(false);
|
ongoingChannel.setShowBadge(false);
|
||||||
nm.createNotificationChannel(ongoingChannel);
|
nm.createNotificationChannel(ongoingChannel);
|
||||||
// Delete the unused channel previously used for startup
|
|
||||||
// failure notifications
|
|
||||||
// TODO: Remove this ID after a reasonable upgrade period
|
|
||||||
// (added 2021-07-12)
|
|
||||||
nm.deleteNotificationChannel(FAILURE_CHANNEL_ID);
|
|
||||||
}
|
}
|
||||||
Notification foregroundNotification =
|
Notification foregroundNotification =
|
||||||
notificationManager.getForegroundNotification();
|
notificationManager.getForegroundNotification();
|
||||||
|
|||||||
@@ -65,7 +65,8 @@ public class SetPasswordFragment extends SetupFragment {
|
|||||||
|
|
||||||
if (!viewModel.needToShowDozeFragment()) {
|
if (!viewModel.needToShowDozeFragment()) {
|
||||||
nextButton.setText(R.string.create_account_button);
|
nextButton.setText(R.string.create_account_button);
|
||||||
passwordConfirmation.setImeOptions(IME_ACTION_DONE);
|
int options = passwordConfirmation.getImeOptions();
|
||||||
|
passwordConfirmation.setImeOptions(options | IME_ACTION_DONE);
|
||||||
}
|
}
|
||||||
|
|
||||||
viewModel.getIsCreatingAccount()
|
viewModel.getIsCreatingAccount()
|
||||||
|
|||||||
@@ -41,7 +41,6 @@ import static java.util.logging.Logger.getLogger;
|
|||||||
import static org.briarproject.bramble.util.LogUtils.logDuration;
|
import static org.briarproject.bramble.util.LogUtils.logDuration;
|
||||||
import static org.briarproject.bramble.util.LogUtils.logException;
|
import static org.briarproject.bramble.util.LogUtils.logException;
|
||||||
import static org.briarproject.bramble.util.LogUtils.now;
|
import static org.briarproject.bramble.util.LogUtils.now;
|
||||||
import static org.briarproject.briar.util.HtmlUtils.ARTICLE;
|
|
||||||
|
|
||||||
@NotNullByDefault
|
@NotNullByDefault
|
||||||
abstract class BaseViewModel extends DbViewModel implements EventListener {
|
abstract class BaseViewModel extends DbViewModel implements EventListener {
|
||||||
@@ -115,7 +114,7 @@ abstract class BaseViewModel extends DbViewModel implements EventListener {
|
|||||||
@DatabaseExecutor
|
@DatabaseExecutor
|
||||||
private String getPostText(Transaction txn, MessageId m)
|
private String getPostText(Transaction txn, MessageId m)
|
||||||
throws DbException {
|
throws DbException {
|
||||||
return HtmlUtils.clean(blogManager.getPostText(txn, m), ARTICLE);
|
return HtmlUtils.cleanArticle(blogManager.getPostText(txn, m));
|
||||||
}
|
}
|
||||||
|
|
||||||
LiveData<LiveResult<BlogPostItem>> loadBlogPost(GroupId g, MessageId m) {
|
LiveData<LiveResult<BlogPostItem>> loadBlogPost(GroupId g, MessageId m) {
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ package org.briarproject.briar.android.blog;
|
|||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.text.Spanned;
|
import android.text.Spanned;
|
||||||
|
import android.text.util.Linkify;
|
||||||
import android.view.LayoutInflater;
|
import android.view.LayoutInflater;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
@@ -170,7 +171,12 @@ class BlogPostViewHolder extends RecyclerView.ViewHolder {
|
|||||||
// TODO make author clickable #624
|
// TODO make author clickable #624
|
||||||
|
|
||||||
text.setText(c.getComment());
|
text.setText(c.getComment());
|
||||||
if (fullText) text.setTextIsSelectable(true);
|
Linkify.addLinks(text, Linkify.WEB_URLS);
|
||||||
|
text.setMovementMethod(null);
|
||||||
|
if (fullText) {
|
||||||
|
text.setTextIsSelectable(true);
|
||||||
|
makeLinksClickable(text, listener::onLinkClick);
|
||||||
|
}
|
||||||
|
|
||||||
commentContainer.addView(v);
|
commentContainer.addView(v);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,24 +1,28 @@
|
|||||||
package org.briarproject.briar.android.blog;
|
package org.briarproject.briar.android.blog;
|
||||||
|
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.widget.Toast;
|
|
||||||
|
|
||||||
import org.briarproject.briar.R;
|
import org.briarproject.briar.R;
|
||||||
import org.briarproject.briar.android.activity.ActivityComponent;
|
import org.briarproject.briar.android.activity.ActivityComponent;
|
||||||
import org.briarproject.briar.android.activity.BriarActivity;
|
import org.briarproject.briar.android.activity.BriarActivity;
|
||||||
|
import org.briarproject.briar.android.blog.RssImportResult.FileImportError;
|
||||||
|
import org.briarproject.briar.android.blog.RssImportResult.FileImportSuccess;
|
||||||
|
import org.briarproject.briar.android.blog.RssImportResult.UrlImportError;
|
||||||
|
import org.briarproject.briar.android.blog.RssImportResult.UrlImportSuccess;
|
||||||
import org.briarproject.briar.android.fragment.BaseFragment.BaseFragmentListener;
|
import org.briarproject.briar.android.fragment.BaseFragment.BaseFragmentListener;
|
||||||
|
import org.briarproject.briar.android.fragment.ErrorFragment;
|
||||||
import org.briarproject.nullsafety.MethodsNotNullByDefault;
|
import org.briarproject.nullsafety.MethodsNotNullByDefault;
|
||||||
import org.briarproject.nullsafety.ParametersNotNullByDefault;
|
import org.briarproject.nullsafety.ParametersNotNullByDefault;
|
||||||
|
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
|
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
|
import androidx.fragment.app.Fragment;
|
||||||
import androidx.fragment.app.FragmentManager;
|
import androidx.fragment.app.FragmentManager;
|
||||||
import androidx.lifecycle.ViewModelProvider;
|
import androidx.lifecycle.ViewModelProvider;
|
||||||
|
|
||||||
import static org.briarproject.briar.android.blog.RssFeedViewModel.ImportResult.EXISTS;
|
import static androidx.fragment.app.FragmentManager.POP_BACK_STACK_INCLUSIVE;
|
||||||
import static org.briarproject.briar.android.blog.RssFeedViewModel.ImportResult.FAILED;
|
import static org.briarproject.briar.android.util.UiUtils.showFragment;
|
||||||
import static org.briarproject.briar.android.blog.RssFeedViewModel.ImportResult.IMPORTED;
|
|
||||||
|
|
||||||
@MethodsNotNullByDefault
|
@MethodsNotNullByDefault
|
||||||
@ParametersNotNullByDefault
|
@ParametersNotNullByDefault
|
||||||
@@ -50,24 +54,29 @@ public class RssFeedActivity extends BriarActivity
|
|||||||
viewModel.getImportResult().observeEvent(this, this::onImportResult);
|
viewModel.getImportResult().observeEvent(this, this::onImportResult);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void onImportResult(RssFeedViewModel.ImportResult result) {
|
private void onImportResult(@Nullable RssImportResult result) {
|
||||||
if (result == IMPORTED) {
|
FragmentManager fm = getSupportFragmentManager();
|
||||||
FragmentManager fm = getSupportFragmentManager();
|
if (result instanceof UrlImportSuccess) {
|
||||||
if (fm.findFragmentByTag(RssFeedImportFragment.TAG) != null) {
|
if (fm.findFragmentByTag(RssFeedImportFragment.TAG) != null) {
|
||||||
onBackPressed();
|
onBackPressed();
|
||||||
}
|
}
|
||||||
} else if (result == FAILED) {
|
} else if (result instanceof UrlImportError) {
|
||||||
String url = viewModel.getUrlFailedImport();
|
String url = ((UrlImportError) result).url;
|
||||||
if (url == null) {
|
|
||||||
throw new AssertionError();
|
|
||||||
}
|
|
||||||
RssFeedImportFailedDialogFragment dialog =
|
RssFeedImportFailedDialogFragment dialog =
|
||||||
RssFeedImportFailedDialogFragment.newInstance(url);
|
RssFeedImportFailedDialogFragment.newInstance(url);
|
||||||
dialog.show(getSupportFragmentManager(),
|
dialog.show(fm, RssFeedImportFailedDialogFragment.TAG);
|
||||||
RssFeedImportFailedDialogFragment.TAG);
|
} else if (result instanceof FileImportSuccess) {
|
||||||
} else if (result == EXISTS) {
|
// pop stack back to before the initial import fragment
|
||||||
Toast.makeText(this, R.string.blogs_rss_feeds_import_exists,
|
fm.popBackStackImmediate(RssFeedImportFragment.TAG,
|
||||||
Toast.LENGTH_LONG).show();
|
POP_BACK_STACK_INCLUSIVE);
|
||||||
|
} else if (result instanceof FileImportError) {
|
||||||
|
// pop stack back to initial import fragment
|
||||||
|
fm.popBackStackImmediate(RssFeedImportFragment.TAG, 0);
|
||||||
|
// show error fragment
|
||||||
|
Fragment f = ErrorFragment.newInstance(
|
||||||
|
getString(R.string.blogs_rss_feeds_import_error));
|
||||||
|
String tag = ErrorFragment.TAG;
|
||||||
|
showFragment(fm, f, tag);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -28,8 +28,7 @@ class RssFeedAdapter extends ListAdapter<Feed, RssFeedAdapter.FeedViewHolder> {
|
|||||||
super(new DiffUtil.ItemCallback<Feed>() {
|
super(new DiffUtil.ItemCallback<Feed>() {
|
||||||
@Override
|
@Override
|
||||||
public boolean areItemsTheSame(Feed a, Feed b) {
|
public boolean areItemsTheSame(Feed a, Feed b) {
|
||||||
return a.getUrl().equals(b.getUrl()) &&
|
return a.getBlogId().equals(b.getBlogId()) &&
|
||||||
a.getBlogId().equals(b.getBlogId()) &&
|
|
||||||
a.getAdded() == b.getAdded();
|
a.getAdded() == b.getAdded();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -86,8 +85,8 @@ class RssFeedAdapter extends ListAdapter<Feed, RssFeedAdapter.FeedViewHolder> {
|
|||||||
delete.setOnClickListener(v -> listener.onDeleteClick(item));
|
delete.setOnClickListener(v -> listener.onDeleteClick(item));
|
||||||
|
|
||||||
// Author
|
// Author
|
||||||
if (item.getRssAuthor() != null) {
|
if (item.getProperties().getAuthor() != null) {
|
||||||
author.setText(item.getRssAuthor());
|
author.setText(item.getProperties().getAuthor());
|
||||||
author.setVisibility(VISIBLE);
|
author.setVisibility(VISIBLE);
|
||||||
authorLabel.setVisibility(VISIBLE);
|
authorLabel.setVisibility(VISIBLE);
|
||||||
} else {
|
} else {
|
||||||
@@ -100,8 +99,8 @@ class RssFeedAdapter extends ListAdapter<Feed, RssFeedAdapter.FeedViewHolder> {
|
|||||||
updated.setText(formatDate(ctx, item.getUpdated()));
|
updated.setText(formatDate(ctx, item.getUpdated()));
|
||||||
|
|
||||||
// Description
|
// Description
|
||||||
if (item.getDescription() != null) {
|
if (item.getProperties().getDescription() != null) {
|
||||||
description.setText(item.getDescription());
|
description.setText(item.getProperties().getDescription());
|
||||||
description.setVisibility(VISIBLE);
|
description.setVisibility(VISIBLE);
|
||||||
} else {
|
} else {
|
||||||
description.setVisibility(GONE);
|
description.setVisibility(GONE);
|
||||||
|
|||||||
@@ -1,9 +1,13 @@
|
|||||||
package org.briarproject.briar.android.blog;
|
package org.briarproject.briar.android.blog;
|
||||||
|
|
||||||
|
import android.net.Uri;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.text.Editable;
|
import android.text.Editable;
|
||||||
import android.text.TextWatcher;
|
import android.text.TextWatcher;
|
||||||
import android.view.LayoutInflater;
|
import android.view.LayoutInflater;
|
||||||
|
import android.view.Menu;
|
||||||
|
import android.view.MenuInflater;
|
||||||
|
import android.view.MenuItem;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
import android.widget.Button;
|
import android.widget.Button;
|
||||||
@@ -13,18 +17,27 @@ import android.widget.ProgressBar;
|
|||||||
import org.briarproject.briar.R;
|
import org.briarproject.briar.R;
|
||||||
import org.briarproject.briar.android.activity.ActivityComponent;
|
import org.briarproject.briar.android.activity.ActivityComponent;
|
||||||
import org.briarproject.briar.android.fragment.BaseFragment;
|
import org.briarproject.briar.android.fragment.BaseFragment;
|
||||||
|
import org.briarproject.briar.android.fragment.ProgressFragment;
|
||||||
|
import org.briarproject.briar.android.util.ActivityLaunchers.GetContentAdvanced;
|
||||||
|
import org.briarproject.briar.android.util.ActivityLaunchers.OpenDocumentAdvanced;
|
||||||
import org.briarproject.nullsafety.MethodsNotNullByDefault;
|
import org.briarproject.nullsafety.MethodsNotNullByDefault;
|
||||||
import org.briarproject.nullsafety.ParametersNotNullByDefault;
|
import org.briarproject.nullsafety.ParametersNotNullByDefault;
|
||||||
|
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
|
|
||||||
|
import androidx.activity.result.ActivityResultLauncher;
|
||||||
|
import androidx.annotation.RequiresApi;
|
||||||
|
import androidx.fragment.app.Fragment;
|
||||||
import androidx.lifecycle.ViewModelProvider;
|
import androidx.lifecycle.ViewModelProvider;
|
||||||
|
|
||||||
|
import static android.os.Build.VERSION.SDK_INT;
|
||||||
import static android.view.View.GONE;
|
import static android.view.View.GONE;
|
||||||
import static android.view.View.VISIBLE;
|
import static android.view.View.VISIBLE;
|
||||||
import static android.view.inputmethod.EditorInfo.IME_ACTION_DONE;
|
import static android.view.inputmethod.EditorInfo.IME_ACTION_DONE;
|
||||||
import static org.briarproject.briar.android.util.UiUtils.hideSoftKeyboard;
|
import static org.briarproject.briar.android.util.UiUtils.hideSoftKeyboard;
|
||||||
|
import static org.briarproject.briar.android.util.UiUtils.launchActivityToOpenFile;
|
||||||
|
import static org.briarproject.briar.android.util.UiUtils.showFragment;
|
||||||
|
|
||||||
@MethodsNotNullByDefault
|
@MethodsNotNullByDefault
|
||||||
@ParametersNotNullByDefault
|
@ParametersNotNullByDefault
|
||||||
@@ -39,6 +52,15 @@ public class RssFeedImportFragment extends BaseFragment {
|
|||||||
private Button importButton;
|
private Button importButton;
|
||||||
private ProgressBar progressBar;
|
private ProgressBar progressBar;
|
||||||
|
|
||||||
|
@RequiresApi(19)
|
||||||
|
private final ActivityResultLauncher<String[]> docLauncher =
|
||||||
|
registerForActivityResult(new OpenDocumentAdvanced(),
|
||||||
|
this::onFileChosen);
|
||||||
|
|
||||||
|
private final ActivityResultLauncher<String> contentLauncher =
|
||||||
|
registerForActivityResult(new GetContentAdvanced(),
|
||||||
|
this::onFileChosen);
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void injectFragment(ActivityComponent component) {
|
public void injectFragment(ActivityComponent component) {
|
||||||
component.inject(this);
|
component.inject(this);
|
||||||
@@ -52,6 +74,7 @@ public class RssFeedImportFragment extends BaseFragment {
|
|||||||
@Nullable ViewGroup container,
|
@Nullable ViewGroup container,
|
||||||
@Nullable Bundle savedInstanceState) {
|
@Nullable Bundle savedInstanceState) {
|
||||||
requireActivity().setTitle(getString(R.string.blogs_rss_feeds_import));
|
requireActivity().setTitle(getString(R.string.blogs_rss_feeds_import));
|
||||||
|
if (SDK_INT >= 19) setHasOptionsMenu(true);
|
||||||
View v = inflater.inflate(R.layout.fragment_rss_feed_import,
|
View v = inflater.inflate(R.layout.fragment_rss_feed_import,
|
||||||
container, false);
|
container, false);
|
||||||
|
|
||||||
@@ -92,11 +115,40 @@ public class RssFeedImportFragment extends BaseFragment {
|
|||||||
return v;
|
return v;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
|
||||||
|
if (SDK_INT >= 19) {
|
||||||
|
inflater.inflate(R.menu.rss_feed_import_actions, menu);
|
||||||
|
}
|
||||||
|
super.onCreateOptionsMenu(menu, inflater);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean onOptionsItemSelected(MenuItem item) {
|
||||||
|
if (item.getItemId() == R.id.action_import_file && SDK_INT >= 19) {
|
||||||
|
launchActivityToOpenFile(requireContext(), docLauncher,
|
||||||
|
contentLauncher, "*/*");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return super.onOptionsItemSelected(item);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getUniqueTag() {
|
public String getUniqueTag() {
|
||||||
return TAG;
|
return TAG;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void onFileChosen(@Nullable Uri uri) {
|
||||||
|
if (uri == null) return;
|
||||||
|
// show progress fragment
|
||||||
|
Fragment f = ProgressFragment.newInstance(
|
||||||
|
getString(R.string.blogs_rss_feeds_import_progress));
|
||||||
|
String tag = ProgressFragment.TAG;
|
||||||
|
showFragment(getParentFragmentManager(), f, tag);
|
||||||
|
// view model will import and change state that activity will react to
|
||||||
|
viewModel.importFeed(uri);
|
||||||
|
}
|
||||||
|
|
||||||
private void enableOrDisableImportButton() {
|
private void enableOrDisableImportButton() {
|
||||||
String url = urlInput.getText().toString();
|
String url = urlInput.getText().toString();
|
||||||
importButton.setEnabled(viewModel.validateAndNormaliseUrl(url) != null);
|
importButton.setEnabled(viewModel.validateAndNormaliseUrl(url) != null);
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
package org.briarproject.briar.android.blog;
|
package org.briarproject.briar.android.blog;
|
||||||
|
|
||||||
import android.app.Application;
|
import android.app.Application;
|
||||||
|
import android.content.ContentResolver;
|
||||||
|
import android.net.Uri;
|
||||||
import android.util.Patterns;
|
import android.util.Patterns;
|
||||||
|
|
||||||
import org.briarproject.bramble.api.db.DatabaseExecutor;
|
import org.briarproject.bramble.api.db.DatabaseExecutor;
|
||||||
@@ -11,6 +13,10 @@ import org.briarproject.bramble.api.lifecycle.IoExecutor;
|
|||||||
import org.briarproject.bramble.api.lifecycle.LifecycleManager;
|
import org.briarproject.bramble.api.lifecycle.LifecycleManager;
|
||||||
import org.briarproject.bramble.api.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.briar.android.blog.RssImportResult.FileImportError;
|
||||||
|
import org.briarproject.briar.android.blog.RssImportResult.FileImportSuccess;
|
||||||
|
import org.briarproject.briar.android.blog.RssImportResult.UrlImportError;
|
||||||
|
import org.briarproject.briar.android.blog.RssImportResult.UrlImportSuccess;
|
||||||
import org.briarproject.briar.android.viewmodel.DbViewModel;
|
import org.briarproject.briar.android.viewmodel.DbViewModel;
|
||||||
import org.briarproject.briar.android.viewmodel.LiveEvent;
|
import org.briarproject.briar.android.viewmodel.LiveEvent;
|
||||||
import org.briarproject.briar.android.viewmodel.LiveResult;
|
import org.briarproject.briar.android.viewmodel.LiveResult;
|
||||||
@@ -20,9 +26,10 @@ import org.briarproject.briar.api.feed.FeedManager;
|
|||||||
import org.briarproject.nullsafety.NotNullByDefault;
|
import org.briarproject.nullsafety.NotNullByDefault;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
import java.net.MalformedURLException;
|
import java.net.MalformedURLException;
|
||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
import java.util.Collections;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.concurrent.Executor;
|
import java.util.concurrent.Executor;
|
||||||
import java.util.logging.Logger;
|
import java.util.logging.Logger;
|
||||||
@@ -30,6 +37,7 @@ import java.util.logging.Logger;
|
|||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
|
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
|
import androidx.annotation.UiThread;
|
||||||
import androidx.lifecycle.LiveData;
|
import androidx.lifecycle.LiveData;
|
||||||
import androidx.lifecycle.MutableLiveData;
|
import androidx.lifecycle.MutableLiveData;
|
||||||
|
|
||||||
@@ -38,13 +46,9 @@ import static java.util.logging.Logger.getLogger;
|
|||||||
import static org.briarproject.bramble.util.LogUtils.logDuration;
|
import static org.briarproject.bramble.util.LogUtils.logDuration;
|
||||||
import static org.briarproject.bramble.util.LogUtils.logException;
|
import static org.briarproject.bramble.util.LogUtils.logException;
|
||||||
import static org.briarproject.bramble.util.LogUtils.now;
|
import static org.briarproject.bramble.util.LogUtils.now;
|
||||||
import static org.briarproject.briar.android.blog.RssFeedViewModel.ImportResult.EXISTS;
|
|
||||||
import static org.briarproject.briar.android.blog.RssFeedViewModel.ImportResult.FAILED;
|
|
||||||
import static org.briarproject.briar.android.blog.RssFeedViewModel.ImportResult.IMPORTED;
|
|
||||||
|
|
||||||
@NotNullByDefault
|
@NotNullByDefault
|
||||||
class RssFeedViewModel extends DbViewModel {
|
class RssFeedViewModel extends DbViewModel {
|
||||||
enum ImportResult {IMPORTED, FAILED, EXISTS}
|
|
||||||
|
|
||||||
private static final Logger LOG =
|
private static final Logger LOG =
|
||||||
getLogger(RssFeedViewModel.class.getName());
|
getLogger(RssFeedViewModel.class.getName());
|
||||||
@@ -56,11 +60,9 @@ class RssFeedViewModel extends DbViewModel {
|
|||||||
private final MutableLiveData<LiveResult<List<Feed>>> feeds =
|
private final MutableLiveData<LiveResult<List<Feed>>> feeds =
|
||||||
new MutableLiveData<>();
|
new MutableLiveData<>();
|
||||||
|
|
||||||
@Nullable
|
|
||||||
private volatile String urlFailedImport = null;
|
|
||||||
private final MutableLiveData<Boolean> isImporting =
|
private final MutableLiveData<Boolean> isImporting =
|
||||||
new MutableLiveData<>(false);
|
new MutableLiveData<>(false);
|
||||||
private final MutableLiveEvent<ImportResult> importResult =
|
private final MutableLiveEvent<RssImportResult> importResult =
|
||||||
new MutableLiveEvent<>();
|
new MutableLiveEvent<>();
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
@@ -101,7 +103,6 @@ class RssFeedViewModel extends DbViewModel {
|
|||||||
private List<Feed> loadFeeds(Transaction txn) throws DbException {
|
private List<Feed> loadFeeds(Transaction txn) throws DbException {
|
||||||
long start = now();
|
long start = now();
|
||||||
List<Feed> feeds = feedManager.getFeeds(txn);
|
List<Feed> feeds = feedManager.getFeeds(txn);
|
||||||
Collections.sort(feeds);
|
|
||||||
logDuration(LOG, "Loading feeds", start);
|
logDuration(LOG, "Loading feeds", start);
|
||||||
return feeds;
|
return feeds;
|
||||||
}
|
}
|
||||||
@@ -125,7 +126,7 @@ class RssFeedViewModel extends DbViewModel {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
LiveEvent<ImportResult> getImportResult() {
|
LiveEvent<RssImportResult> getImportResult() {
|
||||||
return importResult;
|
return importResult;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -135,44 +136,52 @@ class RssFeedViewModel extends DbViewModel {
|
|||||||
|
|
||||||
void importFeed(String url) {
|
void importFeed(String url) {
|
||||||
isImporting.setValue(true);
|
isImporting.setValue(true);
|
||||||
urlFailedImport = null;
|
|
||||||
ioExecutor.execute(() -> {
|
ioExecutor.execute(() -> {
|
||||||
try {
|
try {
|
||||||
if (exists(url)) {
|
|
||||||
importResult.postEvent(EXISTS);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
Feed feed = feedManager.addFeed(url);
|
Feed feed = feedManager.addFeed(url);
|
||||||
List<Feed> updated = addListItem(getList(feeds), feed);
|
// Update the feed if it was already present
|
||||||
if (updated != null) {
|
List<Feed> feedList = getList(feeds);
|
||||||
Collections.sort(updated);
|
if (feedList == null) feedList = new ArrayList<>();
|
||||||
feeds.postValue(new LiveResult<>(updated));
|
List<Feed> updated = updateListItems(feedList,
|
||||||
|
f -> f.equals(feed), f -> feed);
|
||||||
|
// Add the feed if it wasn't already present
|
||||||
|
if (updated == null) {
|
||||||
|
feedList.add(feed);
|
||||||
|
updated = feedList;
|
||||||
}
|
}
|
||||||
importResult.postEvent(IMPORTED);
|
feeds.postValue(new LiveResult<>(updated));
|
||||||
|
importResult.postEvent(new UrlImportSuccess());
|
||||||
} catch (DbException | IOException e) {
|
} catch (DbException | IOException e) {
|
||||||
logException(LOG, WARNING, e);
|
logException(LOG, WARNING, e);
|
||||||
urlFailedImport = url;
|
importResult.postEvent(new UrlImportError(url));
|
||||||
importResult.postEvent(FAILED);
|
|
||||||
} finally {
|
} finally {
|
||||||
isImporting.postValue(false);
|
isImporting.postValue(false);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nullable
|
@UiThread
|
||||||
String getUrlFailedImport() {
|
void importFeed(Uri uri) {
|
||||||
return urlFailedImport;
|
ContentResolver contentResolver = getApplication().getContentResolver();
|
||||||
}
|
ioExecutor.execute(() -> {
|
||||||
|
try (InputStream is = contentResolver.openInputStream(uri)) {
|
||||||
private boolean exists(String url) {
|
Feed feed = feedManager.addFeed(is);
|
||||||
List<Feed> list = getList(feeds);
|
// Update the feed if it was already present
|
||||||
if (list != null) {
|
List<Feed> feedList = getList(feeds);
|
||||||
for (Feed feed : list) {
|
if (feedList == null) feedList = new ArrayList<>();
|
||||||
if (url.equals(feed.getUrl())) {
|
List<Feed> updated = updateListItems(feedList,
|
||||||
return true;
|
f -> f.equals(feed), f -> feed);
|
||||||
|
// Add the feed if it wasn't already present
|
||||||
|
if (updated == null) {
|
||||||
|
feedList.add(feed);
|
||||||
|
updated = feedList;
|
||||||
}
|
}
|
||||||
|
feeds.postValue(new LiveResult<>(updated));
|
||||||
|
importResult.postEvent(new FileImportSuccess());
|
||||||
|
} catch (IOException | DbException e) {
|
||||||
|
logException(LOG, WARNING, e);
|
||||||
|
importResult.postEvent(new FileImportError());
|
||||||
}
|
}
|
||||||
}
|
});
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,24 @@
|
|||||||
|
package org.briarproject.briar.android.blog;
|
||||||
|
|
||||||
|
import org.briarproject.nullsafety.NotNullByDefault;
|
||||||
|
|
||||||
|
@NotNullByDefault
|
||||||
|
abstract class RssImportResult {
|
||||||
|
|
||||||
|
static class UrlImportSuccess extends RssImportResult {
|
||||||
|
}
|
||||||
|
|
||||||
|
static class UrlImportError extends RssImportResult {
|
||||||
|
final String url;
|
||||||
|
|
||||||
|
UrlImportError(String url) {
|
||||||
|
this.url = url;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static class FileImportSuccess extends RssImportResult {
|
||||||
|
}
|
||||||
|
|
||||||
|
static class FileImportError extends RssImportResult {
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -3,12 +3,14 @@ package org.briarproject.briar.android.contact.add.nearby;
|
|||||||
import android.graphics.Bitmap;
|
import android.graphics.Bitmap;
|
||||||
|
|
||||||
import org.briarproject.bramble.api.identity.Author;
|
import org.briarproject.bramble.api.identity.Author;
|
||||||
|
import org.briarproject.bramble.api.qrcode.QrCodeClassifier.QrCodeType;
|
||||||
|
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
|
|
||||||
abstract class AddContactState {
|
abstract class AddContactState {
|
||||||
|
|
||||||
static class KeyAgreementListening extends AddContactState {
|
static class KeyAgreementListening extends AddContactState {
|
||||||
|
|
||||||
final Bitmap qrCode;
|
final Bitmap qrCode;
|
||||||
|
|
||||||
KeyAgreementListening(Bitmap qrCode) {
|
KeyAgreementListening(Bitmap qrCode) {
|
||||||
@@ -29,6 +31,7 @@ abstract class AddContactState {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static class ContactExchangeFinished extends AddContactState {
|
static class ContactExchangeFinished extends AddContactState {
|
||||||
|
|
||||||
final ContactExchangeResult result;
|
final ContactExchangeResult result;
|
||||||
|
|
||||||
ContactExchangeFinished(ContactExchangeResult result) {
|
ContactExchangeFinished(ContactExchangeResult result) {
|
||||||
@@ -37,25 +40,34 @@ abstract class AddContactState {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static class Failed extends AddContactState {
|
static class Failed extends AddContactState {
|
||||||
/**
|
|
||||||
* Non-null if failed due to the scanned QR code version.
|
|
||||||
* True if the app producing the code is too old.
|
|
||||||
* False if the scanning app is too old.
|
|
||||||
*/
|
|
||||||
@Nullable
|
|
||||||
final Boolean qrCodeTooOld;
|
|
||||||
|
|
||||||
Failed(@Nullable Boolean qrCodeTooOld) {
|
static class WrongQrCodeType extends Failed {
|
||||||
this.qrCodeTooOld = qrCodeTooOld;
|
|
||||||
|
final QrCodeType qrCodeType;
|
||||||
|
|
||||||
|
WrongQrCodeType(QrCodeType qrCodeType) {
|
||||||
|
this.qrCodeType = qrCodeType;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Failed() {
|
static class WrongQrCodeVersion extends Failed {
|
||||||
this(null);
|
|
||||||
|
/**
|
||||||
|
* True if the app producing the code is too old.
|
||||||
|
* False if the scanning app is too old.
|
||||||
|
*/
|
||||||
|
final boolean qrCodeTooOld;
|
||||||
|
|
||||||
|
WrongQrCodeVersion(boolean qrCodeTooOld) {
|
||||||
|
this.qrCodeTooOld = qrCodeTooOld;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
abstract static class ContactExchangeResult {
|
abstract static class ContactExchangeResult {
|
||||||
|
|
||||||
static class Success extends ContactExchangeResult {
|
static class Success extends ContactExchangeResult {
|
||||||
|
|
||||||
final Author remoteAuthor;
|
final Author remoteAuthor;
|
||||||
|
|
||||||
Success(Author remoteAuthor) {
|
Success(Author remoteAuthor) {
|
||||||
@@ -64,6 +76,7 @@ abstract class AddContactState {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static class Error extends ContactExchangeResult {
|
static class Error extends ContactExchangeResult {
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
final Author duplicateAuthor;
|
final Author duplicateAuthor;
|
||||||
|
|
||||||
|
|||||||
@@ -6,12 +6,15 @@ import android.view.MenuItem;
|
|||||||
import android.widget.Toast;
|
import android.widget.Toast;
|
||||||
|
|
||||||
import org.briarproject.bramble.api.identity.Author;
|
import org.briarproject.bramble.api.identity.Author;
|
||||||
|
import org.briarproject.bramble.api.qrcode.QrCodeClassifier.QrCodeType;
|
||||||
import org.briarproject.briar.R;
|
import org.briarproject.briar.R;
|
||||||
import org.briarproject.briar.android.activity.ActivityComponent;
|
import org.briarproject.briar.android.activity.ActivityComponent;
|
||||||
import org.briarproject.briar.android.activity.BriarActivity;
|
import org.briarproject.briar.android.activity.BriarActivity;
|
||||||
import org.briarproject.briar.android.contact.add.nearby.AddContactState.ContactExchangeFinished;
|
import org.briarproject.briar.android.contact.add.nearby.AddContactState.ContactExchangeFinished;
|
||||||
import org.briarproject.briar.android.contact.add.nearby.AddContactState.ContactExchangeResult;
|
import org.briarproject.briar.android.contact.add.nearby.AddContactState.ContactExchangeResult;
|
||||||
import org.briarproject.briar.android.contact.add.nearby.AddContactState.Failed;
|
import org.briarproject.briar.android.contact.add.nearby.AddContactState.Failed;
|
||||||
|
import org.briarproject.briar.android.contact.add.nearby.AddContactState.Failed.WrongQrCodeType;
|
||||||
|
import org.briarproject.briar.android.contact.add.nearby.AddContactState.Failed.WrongQrCodeVersion;
|
||||||
import org.briarproject.briar.android.contact.add.nearby.AddNearbyContactViewModel.BluetoothDecision;
|
import org.briarproject.briar.android.contact.add.nearby.AddNearbyContactViewModel.BluetoothDecision;
|
||||||
import org.briarproject.briar.android.fragment.BaseFragment;
|
import org.briarproject.briar.android.fragment.BaseFragment;
|
||||||
import org.briarproject.briar.android.fragment.BaseFragment.BaseFragmentListener;
|
import org.briarproject.briar.android.fragment.BaseFragment.BaseFragmentListener;
|
||||||
@@ -34,6 +37,7 @@ import static android.content.Intent.FLAG_ACTIVITY_CLEAR_TOP;
|
|||||||
import static android.widget.Toast.LENGTH_LONG;
|
import static android.widget.Toast.LENGTH_LONG;
|
||||||
import static java.util.Objects.requireNonNull;
|
import static java.util.Objects.requireNonNull;
|
||||||
import static java.util.logging.Logger.getLogger;
|
import static java.util.logging.Logger.getLogger;
|
||||||
|
import static org.briarproject.bramble.api.qrcode.QrCodeClassifier.QrCodeType.MAILBOX;
|
||||||
import static org.briarproject.briar.android.contact.add.nearby.AddNearbyContactViewModel.BluetoothDecision.ACCEPTED;
|
import static org.briarproject.briar.android.contact.add.nearby.AddNearbyContactViewModel.BluetoothDecision.ACCEPTED;
|
||||||
import static org.briarproject.briar.android.contact.add.nearby.AddNearbyContactViewModel.BluetoothDecision.REFUSED;
|
import static org.briarproject.briar.android.contact.add.nearby.AddNearbyContactViewModel.BluetoothDecision.REFUSED;
|
||||||
|
|
||||||
@@ -141,9 +145,15 @@ public class AddNearbyContactActivity extends BriarActivity
|
|||||||
ContactExchangeResult result =
|
ContactExchangeResult result =
|
||||||
((ContactExchangeFinished) state).result;
|
((ContactExchangeFinished) state).result;
|
||||||
onContactExchangeResult(result);
|
onContactExchangeResult(result);
|
||||||
|
} else if (state instanceof WrongQrCodeType) {
|
||||||
|
QrCodeType qrCodeType = ((WrongQrCodeType) state).qrCodeType;
|
||||||
|
if (qrCodeType == MAILBOX) onMailboxQrCodeScanned();
|
||||||
|
else onWrongQrCodeType();
|
||||||
|
} else if (state instanceof WrongQrCodeVersion) {
|
||||||
|
boolean qrCodeTooOld = ((WrongQrCodeVersion) state).qrCodeTooOld;
|
||||||
|
onWrongQrCodeVersion(qrCodeTooOld);
|
||||||
} else if (state instanceof Failed) {
|
} else if (state instanceof Failed) {
|
||||||
Boolean qrCodeTooOld = ((Failed) state).qrCodeTooOld;
|
showErrorFragment();
|
||||||
onAddingContactFailed(qrCodeTooOld);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -170,15 +180,27 @@ public class AddNearbyContactActivity extends BriarActivity
|
|||||||
} else throw new AssertionError();
|
} else throw new AssertionError();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void onAddingContactFailed(@Nullable Boolean qrCodeTooOld) {
|
private void onMailboxQrCodeScanned() {
|
||||||
if (qrCodeTooOld == null) {
|
String title = getString(R.string.qr_code_invalid);
|
||||||
showErrorFragment();
|
String msg = getString(R.string.mailbox_qr_code_for_contact);
|
||||||
} else {
|
showNextFragment(
|
||||||
String msg;
|
AddNearbyContactErrorFragment.newInstance(title, msg, false));
|
||||||
if (qrCodeTooOld) msg = getString(R.string.qr_code_too_old_1);
|
}
|
||||||
else msg = getString(R.string.qr_code_too_new_1);
|
|
||||||
showNextFragment(AddNearbyContactErrorFragment.newInstance(msg));
|
private void onWrongQrCodeType() {
|
||||||
}
|
String title = getString(R.string.qr_code_invalid);
|
||||||
|
String msg = getString(R.string.qr_code_format_unknown);
|
||||||
|
showNextFragment(
|
||||||
|
AddNearbyContactErrorFragment.newInstance(title, msg, false));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void onWrongQrCodeVersion(boolean qrCodeTooOld) {
|
||||||
|
String title = getString(R.string.qr_code_invalid);
|
||||||
|
String msg;
|
||||||
|
if (qrCodeTooOld) msg = getString(R.string.qr_code_too_old_1);
|
||||||
|
else msg = getString(R.string.qr_code_too_new_1);
|
||||||
|
showNextFragment(
|
||||||
|
AddNearbyContactErrorFragment.newInstance(title, msg, false));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void showErrorFragment() {
|
private void showErrorFragment() {
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ import androidx.fragment.app.FragmentActivity;
|
|||||||
import androidx.lifecycle.ViewModelProvider;
|
import androidx.lifecycle.ViewModelProvider;
|
||||||
|
|
||||||
import static android.content.Intent.FLAG_ACTIVITY_CLEAR_TOP;
|
import static android.content.Intent.FLAG_ACTIVITY_CLEAR_TOP;
|
||||||
|
import static android.view.View.GONE;
|
||||||
import static org.briarproject.briar.android.util.UiUtils.hideViewOnSmallScreen;
|
import static org.briarproject.briar.android.util.UiUtils.hideViewOnSmallScreen;
|
||||||
import static org.briarproject.briar.android.util.UiUtils.onSingleLinkClick;
|
import static org.briarproject.briar.android.util.UiUtils.onSingleLinkClick;
|
||||||
|
|
||||||
@@ -31,17 +32,22 @@ public class AddNearbyContactErrorFragment extends BaseFragment {
|
|||||||
|
|
||||||
public static final String TAG =
|
public static final String TAG =
|
||||||
AddNearbyContactErrorFragment.class.getName();
|
AddNearbyContactErrorFragment.class.getName();
|
||||||
private static final String ERROR_MSG = "errorMessage";
|
private static final String ARG_TITLE = "title";
|
||||||
|
private static final String ARG_ERROR_MSG = "message";
|
||||||
|
private static final String ARG_FEEDBACK = "feedback";
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
ViewModelProvider.Factory viewModelFactory;
|
ViewModelProvider.Factory viewModelFactory;
|
||||||
|
|
||||||
private AddNearbyContactViewModel viewModel;
|
private AddNearbyContactViewModel viewModel;
|
||||||
|
|
||||||
public static AddNearbyContactErrorFragment newInstance(String errorMsg) {
|
public static AddNearbyContactErrorFragment newInstance(String title,
|
||||||
|
String errorMessage, boolean feedback) {
|
||||||
AddNearbyContactErrorFragment f = new AddNearbyContactErrorFragment();
|
AddNearbyContactErrorFragment f = new AddNearbyContactErrorFragment();
|
||||||
Bundle args = new Bundle();
|
Bundle args = new Bundle();
|
||||||
args.putString(ERROR_MSG, errorMsg);
|
args.putString(ARG_TITLE, title);
|
||||||
|
args.putString(ARG_ERROR_MSG, errorMessage);
|
||||||
|
args.putBoolean(ARG_FEEDBACK, feedback);
|
||||||
f.setArguments(args);
|
f.setArguments(args);
|
||||||
return f;
|
return f;
|
||||||
}
|
}
|
||||||
@@ -66,19 +72,32 @@ public class AddNearbyContactErrorFragment extends BaseFragment {
|
|||||||
View v = inflater.inflate(R.layout.fragment_error_contact_exchange,
|
View v = inflater.inflate(R.layout.fragment_error_contact_exchange,
|
||||||
container, false);
|
container, false);
|
||||||
|
|
||||||
// set optional error message
|
String title = null, errorMessage = null;
|
||||||
TextView explanation = v.findViewById(R.id.errorMessage);
|
boolean feedback = true;
|
||||||
Bundle args = getArguments();
|
Bundle args = getArguments();
|
||||||
String errorMessage = args == null ? null : args.getString(ERROR_MSG);
|
if (args != null) {
|
||||||
if (errorMessage == null) {
|
title = args.getString(ARG_TITLE);
|
||||||
explanation.setText(getString(R.string.add_contact_error_two_way));
|
errorMessage = args.getString(ARG_ERROR_MSG);
|
||||||
} else {
|
feedback = args.getBoolean(ARG_FEEDBACK, true);
|
||||||
explanation.setText(args.getString(ERROR_MSG));
|
}
|
||||||
|
|
||||||
|
if (title != null) {
|
||||||
|
TextView titleView = v.findViewById(R.id.errorTitle);
|
||||||
|
titleView.setText(title);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (errorMessage != null) {
|
||||||
|
TextView messageView = v.findViewById(R.id.errorMessage);
|
||||||
|
messageView.setText(errorMessage);
|
||||||
}
|
}
|
||||||
|
|
||||||
// make feedback link clickable
|
|
||||||
TextView sendFeedback = v.findViewById(R.id.sendFeedback);
|
TextView sendFeedback = v.findViewById(R.id.sendFeedback);
|
||||||
onSingleLinkClick(sendFeedback, this::triggerFeedback);
|
if (feedback) {
|
||||||
|
// make feedback link clickable
|
||||||
|
onSingleLinkClick(sendFeedback, this::triggerFeedback);
|
||||||
|
} else {
|
||||||
|
sendFeedback.setVisibility(GONE);
|
||||||
|
}
|
||||||
|
|
||||||
// buttons
|
// buttons
|
||||||
Button tryAgain = v.findViewById(R.id.tryAgainButton);
|
Button tryAgain = v.findViewById(R.id.tryAgainButton);
|
||||||
|
|||||||
@@ -43,6 +43,7 @@ import org.briarproject.bramble.api.plugin.PluginManager;
|
|||||||
import org.briarproject.bramble.api.plugin.TransportId;
|
import org.briarproject.bramble.api.plugin.TransportId;
|
||||||
import org.briarproject.bramble.api.plugin.duplex.DuplexTransportConnection;
|
import org.briarproject.bramble.api.plugin.duplex.DuplexTransportConnection;
|
||||||
import org.briarproject.bramble.api.plugin.event.TransportStateEvent;
|
import org.briarproject.bramble.api.plugin.event.TransportStateEvent;
|
||||||
|
import org.briarproject.bramble.api.qrcode.WrongQrCodeTypeException;
|
||||||
import org.briarproject.bramble.api.system.AndroidExecutor;
|
import org.briarproject.bramble.api.system.AndroidExecutor;
|
||||||
import org.briarproject.bramble.plugin.bluetooth.BluetoothPlugin;
|
import org.briarproject.bramble.plugin.bluetooth.BluetoothPlugin;
|
||||||
import org.briarproject.briar.R;
|
import org.briarproject.briar.R;
|
||||||
@@ -50,9 +51,13 @@ import org.briarproject.briar.android.contact.add.nearby.AddContactState.Contact
|
|||||||
import org.briarproject.briar.android.contact.add.nearby.AddContactState.ContactExchangeResult.Error;
|
import org.briarproject.briar.android.contact.add.nearby.AddContactState.ContactExchangeResult.Error;
|
||||||
import org.briarproject.briar.android.contact.add.nearby.AddContactState.ContactExchangeResult.Success;
|
import org.briarproject.briar.android.contact.add.nearby.AddContactState.ContactExchangeResult.Success;
|
||||||
import org.briarproject.briar.android.contact.add.nearby.AddContactState.ContactExchangeStarted;
|
import org.briarproject.briar.android.contact.add.nearby.AddContactState.ContactExchangeStarted;
|
||||||
|
import org.briarproject.briar.android.contact.add.nearby.AddContactState.Failed;
|
||||||
|
import org.briarproject.briar.android.contact.add.nearby.AddContactState.Failed.WrongQrCodeType;
|
||||||
|
import org.briarproject.briar.android.contact.add.nearby.AddContactState.Failed.WrongQrCodeVersion;
|
||||||
import org.briarproject.briar.android.contact.add.nearby.AddContactState.KeyAgreementListening;
|
import org.briarproject.briar.android.contact.add.nearby.AddContactState.KeyAgreementListening;
|
||||||
import org.briarproject.briar.android.contact.add.nearby.AddContactState.KeyAgreementStarted;
|
import org.briarproject.briar.android.contact.add.nearby.AddContactState.KeyAgreementStarted;
|
||||||
import org.briarproject.briar.android.contact.add.nearby.AddContactState.KeyAgreementWaiting;
|
import org.briarproject.briar.android.contact.add.nearby.AddContactState.KeyAgreementWaiting;
|
||||||
|
import org.briarproject.briar.android.contact.add.nearby.AddContactState.QrCodeScanned;
|
||||||
import org.briarproject.briar.android.qrcode.QrCodeDecoder;
|
import org.briarproject.briar.android.qrcode.QrCodeDecoder;
|
||||||
import org.briarproject.briar.android.qrcode.QrCodeUtils;
|
import org.briarproject.briar.android.qrcode.QrCodeUtils;
|
||||||
import org.briarproject.briar.android.viewmodel.LiveEvent;
|
import org.briarproject.briar.android.viewmodel.LiveEvent;
|
||||||
@@ -60,7 +65,6 @@ import org.briarproject.briar.android.viewmodel.MutableLiveEvent;
|
|||||||
import org.briarproject.nullsafety.NotNullByDefault;
|
import org.briarproject.nullsafety.NotNullByDefault;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.nio.charset.Charset;
|
|
||||||
import java.util.concurrent.Executor;
|
import java.util.concurrent.Executor;
|
||||||
import java.util.logging.Logger;
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
@@ -85,6 +89,7 @@ import static org.briarproject.bramble.api.plugin.Plugin.State.DISABLED;
|
|||||||
import static org.briarproject.bramble.api.plugin.Plugin.State.INACTIVE;
|
import static org.briarproject.bramble.api.plugin.Plugin.State.INACTIVE;
|
||||||
import static org.briarproject.bramble.api.plugin.Plugin.State.STARTING_STOPPING;
|
import static org.briarproject.bramble.api.plugin.Plugin.State.STARTING_STOPPING;
|
||||||
import static org.briarproject.bramble.util.LogUtils.logException;
|
import static org.briarproject.bramble.util.LogUtils.logException;
|
||||||
|
import static org.briarproject.bramble.util.StringUtils.ISO_8859_1;
|
||||||
import static org.briarproject.briar.android.contact.add.nearby.AddNearbyContactPermissionManager.areEssentialPermissionsGranted;
|
import static org.briarproject.briar.android.contact.add.nearby.AddNearbyContactPermissionManager.areEssentialPermissionsGranted;
|
||||||
import static org.briarproject.briar.android.contact.add.nearby.AddNearbyContactViewModel.BluetoothDecision.NO_ADAPTER;
|
import static org.briarproject.briar.android.contact.add.nearby.AddNearbyContactViewModel.BluetoothDecision.NO_ADAPTER;
|
||||||
import static org.briarproject.briar.android.contact.add.nearby.AddNearbyContactViewModel.BluetoothDecision.REFUSED;
|
import static org.briarproject.briar.android.contact.add.nearby.AddNearbyContactViewModel.BluetoothDecision.REFUSED;
|
||||||
@@ -126,9 +131,6 @@ class AddNearbyContactViewModel extends AndroidViewModel
|
|||||||
REFUSED
|
REFUSED
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("CharsetObjectCanBeUsed") // Requires minSdkVersion >= 19
|
|
||||||
private static final Charset ISO_8859_1 = Charset.forName("ISO-8859-1");
|
|
||||||
|
|
||||||
private final EventBus eventBus;
|
private final EventBus eventBus;
|
||||||
private final AndroidExecutor androidExecutor;
|
private final AndroidExecutor androidExecutor;
|
||||||
private final Executor ioExecutor;
|
private final Executor ioExecutor;
|
||||||
@@ -376,11 +378,11 @@ class AddNearbyContactViewModel extends AndroidViewModel
|
|||||||
} else if (e instanceof KeyAgreementAbortedEvent) {
|
} else if (e instanceof KeyAgreementAbortedEvent) {
|
||||||
LOG.info("KeyAgreementAbortedEvent received");
|
LOG.info("KeyAgreementAbortedEvent received");
|
||||||
resetPayloadFlags();
|
resetPayloadFlags();
|
||||||
state.setValue(new AddContactState.Failed());
|
state.setValue(new Failed());
|
||||||
} else if (e instanceof KeyAgreementFailedEvent) {
|
} else if (e instanceof KeyAgreementFailedEvent) {
|
||||||
LOG.info("KeyAgreementFailedEvent received");
|
LOG.info("KeyAgreementFailedEvent received");
|
||||||
resetPayloadFlags();
|
resetPayloadFlags();
|
||||||
state.setValue(new AddContactState.Failed());
|
state.setValue(new Failed());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -446,22 +448,22 @@ class AddNearbyContactViewModel extends AndroidViewModel
|
|||||||
// Ignore results until the KeyAgreementTask is ready
|
// Ignore results until the KeyAgreementTask is ready
|
||||||
if (!gotLocalPayload || gotRemotePayload || currentTask == null) return;
|
if (!gotLocalPayload || gotRemotePayload || currentTask == null) return;
|
||||||
try {
|
try {
|
||||||
byte[] payloadBytes = result.getText().getBytes(ISO_8859_1);
|
Payload remotePayload = payloadParser.parse(result.getText());
|
||||||
if (LOG.isLoggable(INFO))
|
|
||||||
LOG.info("Remote payload is " + payloadBytes.length + " bytes");
|
|
||||||
Payload remotePayload = payloadParser.parse(payloadBytes);
|
|
||||||
gotRemotePayload = true;
|
gotRemotePayload = true;
|
||||||
currentTask.connectAndRunProtocol(remotePayload);
|
currentTask.connectAndRunProtocol(remotePayload);
|
||||||
state.postValue(new AddContactState.QrCodeScanned());
|
state.postValue(new QrCodeScanned());
|
||||||
|
} catch (WrongQrCodeTypeException e) {
|
||||||
|
resetPayloadFlags();
|
||||||
|
state.postValue(new WrongQrCodeType(e.getQrCodeType()));
|
||||||
} catch (UnsupportedVersionException e) {
|
} catch (UnsupportedVersionException e) {
|
||||||
resetPayloadFlags();
|
resetPayloadFlags();
|
||||||
state.postValue(new AddContactState.Failed(e.isTooOld()));
|
state.postValue(new WrongQrCodeVersion(e.isTooOld()));
|
||||||
} catch (IOException | IllegalArgumentException e) {
|
} catch (IOException | IllegalArgumentException e) {
|
||||||
LOG.log(WARNING, "QR Code Invalid", e);
|
LOG.log(WARNING, "QR Code Invalid", e);
|
||||||
androidExecutor.runOnUiThread(() -> Toast.makeText(getApplication(),
|
androidExecutor.runOnUiThread(() -> Toast.makeText(getApplication(),
|
||||||
R.string.qr_code_invalid, LENGTH_LONG).show());
|
R.string.qr_code_invalid, LENGTH_LONG).show());
|
||||||
resetPayloadFlags();
|
resetPayloadFlags();
|
||||||
state.postValue(new AddContactState.Failed());
|
state.postValue(new Failed());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -171,7 +171,7 @@ public class NicknameFragment extends BaseFragment {
|
|||||||
private void handleExistingContact(String name, Author existing) {
|
private void handleExistingContact(String name, Author existing) {
|
||||||
OnClickListener listener = (d, w) -> {
|
OnClickListener listener = (d, w) -> {
|
||||||
d.dismiss();
|
d.dismiss();
|
||||||
String str = getString(R.string.contact_already_exists, name);
|
String str = getString(R.string.contact_already_exists_general);
|
||||||
Toast.makeText(getContext(), str, LENGTH_LONG).show();
|
Toast.makeText(getContext(), str, LENGTH_LONG).show();
|
||||||
finish();
|
finish();
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ import java.util.ArrayList;
|
|||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
|
|
||||||
@NotNullByDefault
|
@NotNullByDefault
|
||||||
public abstract class BaseContactSelectorAdapter<I extends SelectableContactItem, H extends ContactItemViewHolder<I>>
|
public abstract class BaseContactSelectorAdapter<I extends BaseSelectableContactItem, H extends ContactItemViewHolder<I>>
|
||||||
extends BaseContactListAdapter<I, H> {
|
extends BaseContactListAdapter<I, H> {
|
||||||
|
|
||||||
public BaseContactSelectorAdapter(Context context, Class<I> c,
|
public BaseContactSelectorAdapter(Context context, Class<I> c,
|
||||||
@@ -24,7 +24,7 @@ public abstract class BaseContactSelectorAdapter<I extends SelectableContactItem
|
|||||||
Collection<ContactId> selected = new ArrayList<>();
|
Collection<ContactId> selected = new ArrayList<>();
|
||||||
|
|
||||||
for (int i = 0; i < items.size(); i++) {
|
for (int i = 0; i < items.size(); i++) {
|
||||||
SelectableContactItem item = items.get(i);
|
BaseSelectableContactItem item = items.get(i);
|
||||||
if (item.isSelected()) selected.add(item.getContact().getId());
|
if (item.isSelected()) selected.add(item.getContact().getId());
|
||||||
}
|
}
|
||||||
return selected;
|
return selected;
|
||||||
|
|||||||
@@ -33,7 +33,7 @@ import static org.briarproject.briar.android.contactselection.ContactSelectorAct
|
|||||||
|
|
||||||
@MethodsNotNullByDefault
|
@MethodsNotNullByDefault
|
||||||
@ParametersNotNullByDefault
|
@ParametersNotNullByDefault
|
||||||
public abstract class BaseContactSelectorFragment<I extends SelectableContactItem, A extends BaseContactSelectorAdapter<I, ? extends ContactItemViewHolder<I>>>
|
public abstract class BaseContactSelectorFragment<I extends BaseSelectableContactItem, A extends BaseContactSelectorAdapter<I, ? extends ContactItemViewHolder<I>>>
|
||||||
extends BaseFragment
|
extends BaseFragment
|
||||||
implements OnContactClickListener<I> {
|
implements OnContactClickListener<I> {
|
||||||
|
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ import static org.briarproject.briar.android.util.UiUtils.GREY_OUT;
|
|||||||
|
|
||||||
@UiThread
|
@UiThread
|
||||||
@NotNullByDefault
|
@NotNullByDefault
|
||||||
public class BaseSelectableContactHolder<I extends SelectableContactItem>
|
public abstract class BaseSelectableContactHolder<I extends BaseSelectableContactItem>
|
||||||
extends ContactItemViewHolder<I> {
|
extends ContactItemViewHolder<I> {
|
||||||
|
|
||||||
private final CheckBox checkBox;
|
private final CheckBox checkBox;
|
||||||
|
|||||||
@@ -0,0 +1,32 @@
|
|||||||
|
package org.briarproject.briar.android.contactselection;
|
||||||
|
|
||||||
|
import org.briarproject.bramble.api.contact.Contact;
|
||||||
|
import org.briarproject.briar.android.contact.ContactItem;
|
||||||
|
import org.briarproject.briar.api.identity.AuthorInfo;
|
||||||
|
import org.briarproject.nullsafety.NotNullByDefault;
|
||||||
|
|
||||||
|
import javax.annotation.concurrent.NotThreadSafe;
|
||||||
|
|
||||||
|
@NotThreadSafe
|
||||||
|
@NotNullByDefault
|
||||||
|
public abstract class BaseSelectableContactItem extends ContactItem {
|
||||||
|
|
||||||
|
private boolean selected;
|
||||||
|
|
||||||
|
public BaseSelectableContactItem(Contact contact, AuthorInfo authorInfo,
|
||||||
|
boolean selected) {
|
||||||
|
super(contact, authorInfo);
|
||||||
|
this.selected = selected;
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean isSelected() {
|
||||||
|
return selected;
|
||||||
|
}
|
||||||
|
|
||||||
|
void toggleSelected() {
|
||||||
|
selected = !selected;
|
||||||
|
}
|
||||||
|
|
||||||
|
public abstract boolean isDisabled();
|
||||||
|
|
||||||
|
}
|
||||||
@@ -10,7 +10,7 @@ import org.briarproject.nullsafety.NotNullByDefault;
|
|||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
|
|
||||||
@NotNullByDefault
|
@NotNullByDefault
|
||||||
public interface ContactSelectorController<I extends SelectableContactItem>
|
public interface ContactSelectorController<I extends BaseSelectableContactItem>
|
||||||
extends DbController {
|
extends DbController {
|
||||||
|
|
||||||
void loadContacts(GroupId g, Collection<ContactId> selection,
|
void loadContacts(GroupId g, Collection<ContactId> selection,
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user