mirror of
https://code.briarproject.org/briar/briar.git
synced 2026-02-11 18:29:05 +01:00
Merge branch '2397-wrong-type-of-qr-code' into 'master'
Show appropriate error message if user scans wrong kind of QR code Closes #2397 See merge request briar/briar!1748
This commit is contained in:
@@ -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,7 @@
|
|||||||
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 abstract static class Pending extends MailboxPairingState {
|
public abstract static class Pending extends MailboxPairingState {
|
||||||
@@ -29,6 +31,14 @@ public abstract class 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 {
|
||||||
|
|||||||
@@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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;
|
||||||
@@ -17,13 +16,18 @@ import javax.annotation.Nullable;
|
|||||||
import static java.nio.charset.CodingErrorAction.IGNORE;
|
import static java.nio.charset.CodingErrorAction.IGNORE;
|
||||||
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,11 +49,7 @@ 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) {
|
||||||
|
|||||||
@@ -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();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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 {
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -13,7 +13,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,7 +30,8 @@ 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);
|
||||||
BdfWriter w = bdfWriterFactory.createWriter(out);
|
BdfWriter w = bdfWriterFactory.createWriter(out);
|
||||||
try {
|
try {
|
||||||
w.writeListStart(); // Payload start
|
w.writeListStart(); // Payload start
|
||||||
|
|||||||
@@ -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();
|
||||||
|
|||||||
@@ -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,7 @@ 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 long timeStarted;
|
||||||
|
|
||||||
private final Object lock = new Object();
|
private final Object lock = new Object();
|
||||||
@@ -69,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;
|
||||||
@@ -78,8 +89,9 @@ class MailboxPairingTaskImpl implements MailboxPairingTask {
|
|||||||
this.api = api;
|
this.api = api;
|
||||||
this.mailboxSettingsManager = mailboxSettingsManager;
|
this.mailboxSettingsManager = mailboxSettingsManager;
|
||||||
this.mailboxUpdateManager = mailboxUpdateManager;
|
this.mailboxUpdateManager = mailboxUpdateManager;
|
||||||
|
this.qrCodeClassifier = qrCodeClassifier;
|
||||||
timeStarted = clock.currentTimeMillis();
|
timeStarted = clock.currentTimeMillis();
|
||||||
state = new MailboxPairingState.QrCodeReceived(timeStarted);
|
state = new QrCodeReceived(timeStarted);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -101,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(timeStarted));
|
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 -> {
|
||||||
@@ -135,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) {
|
||||||
@@ -169,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);
|
||||||
|
|||||||
@@ -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;
|
||||||
@@ -100,6 +99,7 @@ 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;
|
||||||
|
|
||||||
@MethodsNotNullByDefault
|
@MethodsNotNullByDefault
|
||||||
@@ -419,9 +419,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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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;
|
||||||
|
|||||||
@@ -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.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);
|
||||||
@@ -70,28 +84,48 @@ public class MailboxPairingTaskImplTest extends BrambleMockTestCase {
|
|||||||
public void testInitialQrCodeReceivedState() {
|
public void testInitialQrCodeReceivedState() {
|
||||||
MailboxPairingTask task = createPairingTask(getRandomString(42));
|
MailboxPairingTask task = 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 = createPairingTask(getRandomString(42));
|
String payload = getRandomString(65);
|
||||||
task1.run();
|
MailboxPairingTask task = createPairingTask(payload);
|
||||||
task1.addObserver(state ->
|
|
||||||
assertTrue(state instanceof MailboxPairingState.InvalidQrCode)
|
|
||||||
);
|
|
||||||
|
|
||||||
String goodLength = "00" + getRandomString(63);
|
expectClassifyQrCode(payload, BQP, QR_FORMAT_VERSION);
|
||||||
MailboxPairingTask task2 = 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));
|
||||||
@@ -122,14 +156,11 @@ public class MailboxPairingTaskImplTest extends BrambleMockTestCase {
|
|||||||
MailboxPairingTask task = 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();
|
||||||
});
|
});
|
||||||
@@ -138,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));
|
||||||
@@ -170,6 +200,7 @@ public class MailboxPairingTaskImplTest extends BrambleMockTestCase {
|
|||||||
|
|
||||||
@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,8 +219,8 @@ public class MailboxPairingTaskImplTest extends BrambleMockTestCase {
|
|||||||
|
|
||||||
MailboxPairingTask task = 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) {
|
||||||
@@ -206,6 +237,16 @@ public class MailboxPairingTaskImplTest extends BrambleMockTestCase {
|
|||||||
will(returnValue(time));
|
will(returnValue(time));
|
||||||
}});
|
}});
|
||||||
|
|
||||||
return factory.createPairingTask(qrCodePayload);
|
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);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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());
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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
|
||||||
|
|||||||
@@ -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());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -436,7 +436,7 @@ class HotspotManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private static String createWifiLoginString(String ssid, String password) {
|
private static String createWifiLoginString(String ssid, String password) {
|
||||||
// https://en.wikipedia.org/wiki/QR_code#WiFi_network_login
|
// https://en.wikipedia.org/wiki/QR_code#Joining_a_Wi%E2%80%91Fi_network
|
||||||
// do not remove the dangling ';', it can cause problems to omit it
|
// do not remove the dangling ';', it can cause problems to omit it
|
||||||
return "WIFI:S:" + ssid + ";T:WPA;P:" + password + ";;";
|
return "WIFI:S:" + ssid + ";T:WPA;P:" + password + ";;";
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,10 +6,24 @@ import android.widget.ProgressBar;
|
|||||||
import android.widget.Toast;
|
import android.widget.Toast;
|
||||||
|
|
||||||
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.Pending;
|
||||||
|
import org.briarproject.bramble.api.mailbox.MailboxPairingState.UnexpectedError;
|
||||||
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.fragment.FinalFragment;
|
import org.briarproject.briar.android.fragment.FinalFragment;
|
||||||
|
import org.briarproject.briar.android.mailbox.MailboxState.CameraError;
|
||||||
|
import org.briarproject.briar.android.mailbox.MailboxState.IsPaired;
|
||||||
|
import org.briarproject.briar.android.mailbox.MailboxState.NotSetup;
|
||||||
|
import org.briarproject.briar.android.mailbox.MailboxState.OfflineWhenPairing;
|
||||||
|
import org.briarproject.briar.android.mailbox.MailboxState.Pairing;
|
||||||
|
import org.briarproject.briar.android.mailbox.MailboxState.ScanningQrCode;
|
||||||
|
import org.briarproject.briar.android.mailbox.MailboxState.ShowDownload;
|
||||||
|
import org.briarproject.briar.android.mailbox.MailboxState.WasUnpaired;
|
||||||
import org.briarproject.briar.android.view.BlankFragment;
|
import org.briarproject.briar.android.view.BlankFragment;
|
||||||
import org.briarproject.nullsafety.MethodsNotNullByDefault;
|
import org.briarproject.nullsafety.MethodsNotNullByDefault;
|
||||||
import org.briarproject.nullsafety.ParametersNotNullByDefault;
|
import org.briarproject.nullsafety.ParametersNotNullByDefault;
|
||||||
@@ -25,6 +39,9 @@ import androidx.lifecycle.ViewModelProvider;
|
|||||||
import static android.view.View.INVISIBLE;
|
import static android.view.View.INVISIBLE;
|
||||||
import static android.view.View.VISIBLE;
|
import static android.view.View.VISIBLE;
|
||||||
import static android.widget.Toast.LENGTH_LONG;
|
import static android.widget.Toast.LENGTH_LONG;
|
||||||
|
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.briar.android.util.UiUtils.showFragment;
|
import static org.briarproject.briar.android.util.UiUtils.showFragment;
|
||||||
|
|
||||||
@MethodsNotNullByDefault
|
@MethodsNotNullByDefault
|
||||||
@@ -56,24 +73,23 @@ public class MailboxActivity extends BriarActivity {
|
|||||||
}
|
}
|
||||||
|
|
||||||
viewModel.getPairingState().observeEvent(this, state -> {
|
viewModel.getPairingState().observeEvent(this, state -> {
|
||||||
if (state instanceof MailboxState.NotSetup) {
|
if (state instanceof NotSetup) {
|
||||||
onNotSetup();
|
onNotSetup();
|
||||||
} else if (state instanceof MailboxState.ShowDownload) {
|
} else if (state instanceof ShowDownload) {
|
||||||
onShowDownload();
|
onShowDownload();
|
||||||
} else if (state instanceof MailboxState.ScanningQrCode) {
|
} else if (state instanceof ScanningQrCode) {
|
||||||
onScanningQrCode();
|
onScanningQrCode();
|
||||||
} else if (state instanceof MailboxState.Pairing) {
|
} else if (state instanceof Pairing) {
|
||||||
MailboxPairingState s =
|
MailboxPairingState s = ((Pairing) state).pairingState;
|
||||||
((MailboxState.Pairing) state).pairingState;
|
|
||||||
onMailboxPairingStateChanged(s);
|
onMailboxPairingStateChanged(s);
|
||||||
} else if (state instanceof MailboxState.OfflineWhenPairing) {
|
} else if (state instanceof OfflineWhenPairing) {
|
||||||
onOffline();
|
onOffline();
|
||||||
} else if (state instanceof MailboxState.CameraError) {
|
} else if (state instanceof CameraError) {
|
||||||
onCameraError();
|
onCameraError();
|
||||||
} else if (state instanceof MailboxState.IsPaired) {
|
} else if (state instanceof IsPaired) {
|
||||||
onIsPaired(((MailboxState.IsPaired) state).isOnline);
|
onIsPaired(((IsPaired) state).isOnline);
|
||||||
} else if (state instanceof MailboxState.WasUnpaired) {
|
} else if (state instanceof WasUnpaired) {
|
||||||
MailboxState.WasUnpaired s = (MailboxState.WasUnpaired) state;
|
WasUnpaired s = (WasUnpaired) state;
|
||||||
onUnPaired(s.tellUserToWipeMailbox);
|
onUnPaired(s.tellUserToWipeMailbox);
|
||||||
} else {
|
} else {
|
||||||
throw new AssertionError("Unknown state: " + state);
|
throw new AssertionError("Unknown state: " + state);
|
||||||
@@ -104,7 +120,7 @@ public class MailboxActivity extends BriarActivity {
|
|||||||
@Override
|
@Override
|
||||||
public void onBackPressed() {
|
public void onBackPressed() {
|
||||||
MailboxState s = viewModel.getPairingState().getLastValue();
|
MailboxState s = viewModel.getPairingState().getLastValue();
|
||||||
if (s instanceof MailboxState.Pairing) {
|
if (s instanceof Pairing) {
|
||||||
// don't go back in the flow if we are already pairing
|
// don't go back in the flow if we are already pairing
|
||||||
// with the mailbox. We provide a try-again button instead.
|
// with the mailbox. We provide a try-again button instead.
|
||||||
supportFinishAfterTransition();
|
supportFinishAfterTransition();
|
||||||
@@ -158,31 +174,44 @@ public class MailboxActivity extends BriarActivity {
|
|||||||
}
|
}
|
||||||
Fragment f;
|
Fragment f;
|
||||||
String tag;
|
String tag;
|
||||||
if (s instanceof MailboxPairingState.Pending) {
|
if (s instanceof Pending) {
|
||||||
long timeStarted = ((MailboxPairingState.Pending) s).timeStarted;
|
long timeStarted = ((Pending) s).timeStarted;
|
||||||
f = MailboxConnectingFragment.newInstance(timeStarted);
|
f = MailboxConnectingFragment.newInstance(timeStarted);
|
||||||
tag = MailboxConnectingFragment.TAG;
|
tag = MailboxConnectingFragment.TAG;
|
||||||
} else if (s instanceof MailboxPairingState.InvalidQrCode) {
|
} else if (s instanceof InvalidQrCode) {
|
||||||
f = ErrorFragment.newInstance(
|
InvalidQrCode i = (InvalidQrCode) s;
|
||||||
R.string.mailbox_setup_qr_code_wrong_title,
|
int errorRes;
|
||||||
R.string.mailbox_setup_qr_code_wrong_description);
|
if (i.qrCodeType == MAILBOX) {
|
||||||
|
if (i.formatVersion < QR_FORMAT_VERSION) {
|
||||||
|
errorRes = R.string.mailbox_qr_code_too_old;
|
||||||
|
} else if (i.formatVersion > QR_FORMAT_VERSION) {
|
||||||
|
errorRes = R.string.mailbox_qr_code_too_new;
|
||||||
|
} else {
|
||||||
|
errorRes = R.string.mailbox_setup_qr_code_wrong_description;
|
||||||
|
}
|
||||||
|
} else if (i.qrCodeType == BQP) {
|
||||||
|
errorRes = R.string.contact_qr_code_for_mailbox;
|
||||||
|
} else {
|
||||||
|
errorRes = R.string.mailbox_setup_qr_code_wrong_description;
|
||||||
|
}
|
||||||
|
f = ErrorFragment.newInstance(R.string.qr_code_invalid, errorRes);
|
||||||
tag = ErrorFragment.TAG;
|
tag = ErrorFragment.TAG;
|
||||||
} else if (s instanceof MailboxPairingState.MailboxAlreadyPaired) {
|
} else if (s instanceof MailboxAlreadyPaired) {
|
||||||
f = ErrorFragment.newInstance(
|
f = ErrorFragment.newInstance(
|
||||||
R.string.mailbox_setup_already_paired_title,
|
R.string.mailbox_setup_already_paired_title,
|
||||||
R.string.mailbox_setup_already_paired_description);
|
R.string.mailbox_setup_already_paired_description);
|
||||||
tag = ErrorFragment.TAG;
|
tag = ErrorFragment.TAG;
|
||||||
} else if (s instanceof MailboxPairingState.ConnectionError) {
|
} else if (s instanceof ConnectionError) {
|
||||||
f = ErrorFragment.newInstance(
|
f = ErrorFragment.newInstance(
|
||||||
R.string.mailbox_setup_io_error_title,
|
R.string.mailbox_setup_io_error_title,
|
||||||
R.string.mailbox_setup_io_error_description);
|
R.string.mailbox_setup_io_error_description);
|
||||||
tag = ErrorFragment.TAG;
|
tag = ErrorFragment.TAG;
|
||||||
} else if (s instanceof MailboxPairingState.UnexpectedError) {
|
} else if (s instanceof UnexpectedError) {
|
||||||
f = ErrorFragment.newInstance(
|
f = ErrorFragment.newInstance(
|
||||||
R.string.mailbox_setup_assertion_error_title,
|
R.string.mailbox_setup_assertion_error_title,
|
||||||
R.string.mailbox_setup_assertion_error_description);
|
R.string.mailbox_setup_assertion_error_description);
|
||||||
tag = ErrorFragment.TAG;
|
tag = ErrorFragment.TAG;
|
||||||
} else if (s instanceof MailboxPairingState.Paired) {
|
} else if (s instanceof Paired) {
|
||||||
f = FinalFragment.newInstance(R.string.mailbox_setup_paired_title,
|
f = FinalFragment.newInstance(R.string.mailbox_setup_paired_title,
|
||||||
R.drawable.ic_check_circle_outline,
|
R.drawable.ic_check_circle_outline,
|
||||||
R.color.briar_brand_green,
|
R.color.briar_brand_green,
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ 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.mailbox.MailboxManager;
|
import org.briarproject.bramble.api.mailbox.MailboxManager;
|
||||||
import org.briarproject.bramble.api.mailbox.MailboxPairingState;
|
import org.briarproject.bramble.api.mailbox.MailboxPairingState;
|
||||||
|
import org.briarproject.bramble.api.mailbox.MailboxPairingState.Paired;
|
||||||
import org.briarproject.bramble.api.mailbox.MailboxPairingTask;
|
import org.briarproject.bramble.api.mailbox.MailboxPairingTask;
|
||||||
import org.briarproject.bramble.api.mailbox.MailboxStatus;
|
import org.briarproject.bramble.api.mailbox.MailboxStatus;
|
||||||
import org.briarproject.bramble.api.mailbox.event.OwnMailboxConnectionStatusEvent;
|
import org.briarproject.bramble.api.mailbox.event.OwnMailboxConnectionStatusEvent;
|
||||||
@@ -24,7 +25,14 @@ import org.briarproject.bramble.api.plugin.TorConstants;
|
|||||||
import org.briarproject.bramble.api.plugin.TransportId;
|
import org.briarproject.bramble.api.plugin.TransportId;
|
||||||
import org.briarproject.bramble.api.plugin.event.TransportInactiveEvent;
|
import org.briarproject.bramble.api.plugin.event.TransportInactiveEvent;
|
||||||
import org.briarproject.bramble.api.system.AndroidExecutor;
|
import org.briarproject.bramble.api.system.AndroidExecutor;
|
||||||
|
import org.briarproject.briar.android.mailbox.MailboxState.CameraError;
|
||||||
|
import org.briarproject.briar.android.mailbox.MailboxState.IsPaired;
|
||||||
import org.briarproject.briar.android.mailbox.MailboxState.NotSetup;
|
import org.briarproject.briar.android.mailbox.MailboxState.NotSetup;
|
||||||
|
import org.briarproject.briar.android.mailbox.MailboxState.OfflineWhenPairing;
|
||||||
|
import org.briarproject.briar.android.mailbox.MailboxState.Pairing;
|
||||||
|
import org.briarproject.briar.android.mailbox.MailboxState.ScanningQrCode;
|
||||||
|
import org.briarproject.briar.android.mailbox.MailboxState.ShowDownload;
|
||||||
|
import org.briarproject.briar.android.mailbox.MailboxState.WasUnpaired;
|
||||||
import org.briarproject.briar.android.qrcode.QrCodeDecoder;
|
import org.briarproject.briar.android.qrcode.QrCodeDecoder;
|
||||||
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;
|
||||||
@@ -113,7 +121,7 @@ class MailboxViewModel extends DbViewModel
|
|||||||
MailboxStatus mailboxStatus =
|
MailboxStatus mailboxStatus =
|
||||||
mailboxManager.getMailboxStatus(txn);
|
mailboxManager.getMailboxStatus(txn);
|
||||||
boolean isOnline = isTorActive();
|
boolean isOnline = isTorActive();
|
||||||
pairingState.postEvent(new MailboxState.IsPaired(isOnline));
|
pairingState.postEvent(new IsPaired(isOnline));
|
||||||
status.postValue(mailboxStatus);
|
status.postValue(mailboxStatus);
|
||||||
} else {
|
} else {
|
||||||
pairingState.postEvent(new NotSetup());
|
pairingState.postEvent(new NotSetup());
|
||||||
@@ -142,14 +150,14 @@ class MailboxViewModel extends DbViewModel
|
|||||||
@UiThread
|
@UiThread
|
||||||
private void onTorInactive() {
|
private void onTorInactive() {
|
||||||
MailboxState lastState = pairingState.getLastValue();
|
MailboxState lastState = pairingState.getLastValue();
|
||||||
if (lastState instanceof MailboxState.IsPaired) {
|
if (lastState instanceof IsPaired) {
|
||||||
// we are already paired, so use IsPaired state
|
// we are already paired, so use IsPaired state
|
||||||
pairingState.setEvent(new MailboxState.IsPaired(false));
|
pairingState.setEvent(new IsPaired(false));
|
||||||
} else if (lastState instanceof MailboxState.Pairing) {
|
} else if (lastState instanceof Pairing) {
|
||||||
MailboxState.Pairing p = (MailboxState.Pairing) lastState;
|
Pairing p = (Pairing) lastState;
|
||||||
// check that we not just finished pairing (showing success screen)
|
// check that we not just finished pairing (showing success screen)
|
||||||
if (!(p.pairingState instanceof MailboxPairingState.Paired)) {
|
if (!(p.pairingState instanceof Paired)) {
|
||||||
pairingState.setEvent(new MailboxState.OfflineWhenPairing());
|
pairingState.setEvent(new OfflineWhenPairing());
|
||||||
}
|
}
|
||||||
// else ignore offline event as user will be leaving UI flow anyway
|
// else ignore offline event as user will be leaving UI flow anyway
|
||||||
}
|
}
|
||||||
@@ -158,15 +166,15 @@ class MailboxViewModel extends DbViewModel
|
|||||||
@UiThread
|
@UiThread
|
||||||
void onScanButtonClicked() {
|
void onScanButtonClicked() {
|
||||||
if (isTorActive()) {
|
if (isTorActive()) {
|
||||||
pairingState.setEvent(new MailboxState.ScanningQrCode());
|
pairingState.setEvent(new ScanningQrCode());
|
||||||
} else {
|
} else {
|
||||||
pairingState.setEvent(new MailboxState.OfflineWhenPairing());
|
pairingState.setEvent(new OfflineWhenPairing());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@UiThread
|
@UiThread
|
||||||
void onCameraError() {
|
void onCameraError() {
|
||||||
pairingState.setEvent(new MailboxState.CameraError());
|
pairingState.setEvent(new CameraError());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -182,7 +190,7 @@ class MailboxViewModel extends DbViewModel
|
|||||||
pairingTask = mailboxManager.startPairingTask(qrCodePayload);
|
pairingTask = mailboxManager.startPairingTask(qrCodePayload);
|
||||||
pairingTask.addObserver(this);
|
pairingTask.addObserver(this);
|
||||||
} else {
|
} else {
|
||||||
pairingState.postEvent(new MailboxState.OfflineWhenPairing());
|
pairingState.postEvent(new OfflineWhenPairing());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -193,7 +201,7 @@ class MailboxViewModel extends DbViewModel
|
|||||||
LOG.info("New pairing state: " +
|
LOG.info("New pairing state: " +
|
||||||
mailboxPairingState.getClass().getSimpleName());
|
mailboxPairingState.getClass().getSimpleName());
|
||||||
}
|
}
|
||||||
pairingState.setEvent(new MailboxState.Pairing(mailboxPairingState));
|
pairingState.setEvent(new Pairing(mailboxPairingState));
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean isTorActive() {
|
private boolean isTorActive() {
|
||||||
@@ -203,7 +211,7 @@ class MailboxViewModel extends DbViewModel
|
|||||||
|
|
||||||
@UiThread
|
@UiThread
|
||||||
void showDownloadFragment() {
|
void showDownloadFragment() {
|
||||||
pairingState.setEvent(new MailboxState.ShowDownload());
|
pairingState.setEvent(new ShowDownload());
|
||||||
}
|
}
|
||||||
|
|
||||||
@UiThread
|
@UiThread
|
||||||
@@ -214,7 +222,7 @@ class MailboxViewModel extends DbViewModel
|
|||||||
@UiThread
|
@UiThread
|
||||||
void checkIfOnlineWhenPaired() {
|
void checkIfOnlineWhenPaired() {
|
||||||
boolean isOnline = isTorActive();
|
boolean isOnline = isTorActive();
|
||||||
pairingState.setEvent(new MailboxState.IsPaired(isOnline));
|
pairingState.setEvent(new IsPaired(isOnline));
|
||||||
}
|
}
|
||||||
|
|
||||||
LiveData<Boolean> checkConnection() {
|
LiveData<Boolean> checkConnection() {
|
||||||
@@ -227,7 +235,7 @@ class MailboxViewModel extends DbViewModel
|
|||||||
checkConnection(success -> {
|
checkConnection(success -> {
|
||||||
boolean isOnline = isTorActive();
|
boolean isOnline = isTorActive();
|
||||||
// make UI move back to status fragment by changing pairingState
|
// make UI move back to status fragment by changing pairingState
|
||||||
pairingState.postEvent(new MailboxState.IsPaired(isOnline));
|
pairingState.postEvent(new IsPaired(isOnline));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -246,7 +254,7 @@ class MailboxViewModel extends DbViewModel
|
|||||||
ioExecutor.execute(() -> {
|
ioExecutor.execute(() -> {
|
||||||
try {
|
try {
|
||||||
boolean wasWiped = mailboxManager.unPair();
|
boolean wasWiped = mailboxManager.unPair();
|
||||||
pairingState.postEvent(new MailboxState.WasUnpaired(!wasWiped));
|
pairingState.postEvent(new WasUnpaired(!wasWiped));
|
||||||
} catch (DbException e) {
|
} catch (DbException e) {
|
||||||
handleException(e);
|
handleException(e);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -41,7 +41,6 @@ public class QrCodeDecoder implements PreviewConsumer, PreviewCallback {
|
|||||||
private final ResultCallback callback;
|
private final ResultCallback callback;
|
||||||
|
|
||||||
private Camera camera = null;
|
private Camera camera = null;
|
||||||
private int cameraIndex = 0;
|
|
||||||
|
|
||||||
public QrCodeDecoder(AndroidExecutor androidExecutor,
|
public QrCodeDecoder(AndroidExecutor androidExecutor,
|
||||||
@IoExecutor Executor ioExecutor, ResultCallback callback) {
|
@IoExecutor Executor ioExecutor, ResultCallback callback) {
|
||||||
@@ -53,14 +52,12 @@ public class QrCodeDecoder implements PreviewConsumer, PreviewCallback {
|
|||||||
@Override
|
@Override
|
||||||
public void start(Camera camera, int cameraIndex) {
|
public void start(Camera camera, int cameraIndex) {
|
||||||
this.camera = camera;
|
this.camera = camera;
|
||||||
this.cameraIndex = cameraIndex;
|
|
||||||
askForPreviewFrame();
|
askForPreviewFrame();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void stop() {
|
public void stop() {
|
||||||
camera = null;
|
camera = null;
|
||||||
cameraIndex = 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@UiThread
|
@UiThread
|
||||||
|
|||||||
@@ -51,12 +51,12 @@
|
|||||||
android:layout_width="0dp"
|
android:layout_width="0dp"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginTop="@dimen/margin_xlarge"
|
android:layout_marginTop="@dimen/margin_xlarge"
|
||||||
|
android:text="@string/add_contact_error_two_way"
|
||||||
android:textAppearance="@style/TextAppearance.MaterialComponents.Body1"
|
android:textAppearance="@style/TextAppearance.MaterialComponents.Body1"
|
||||||
app:layout_constraintBottom_toTopOf="@+id/sendFeedback"
|
app:layout_constraintBottom_toTopOf="@+id/sendFeedback"
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
app:layout_constraintTop_toBottomOf="@+id/errorTitle"
|
app:layout_constraintTop_toBottomOf="@+id/errorTitle" />
|
||||||
tools:text="error explanation" />
|
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/sendFeedback"
|
android:id="@+id/sendFeedback"
|
||||||
|
|||||||
@@ -252,6 +252,8 @@
|
|||||||
<string name="qr_code_invalid">The QR code is invalid</string>
|
<string name="qr_code_invalid">The QR code is invalid</string>
|
||||||
<string name="qr_code_too_old_1">The QR code you have scanned comes from an older version of Briar.\n\nPlease ask your contact to upgrade to the latest version and then try again.</string>
|
<string name="qr_code_too_old_1">The QR code you have scanned comes from an older version of Briar.\n\nPlease ask your contact to upgrade to the latest version and then try again.</string>
|
||||||
<string name="qr_code_too_new_1">The QR code you have scanned comes from a newer version of Briar.\n\nPlease upgrade to the latest version and then try again.</string>
|
<string name="qr_code_too_new_1">The QR code you have scanned comes from a newer version of Briar.\n\nPlease upgrade to the latest version and then try again.</string>
|
||||||
|
<string name="mailbox_qr_code_for_contact">The QR code you have scanned comes from Briar Mailbox.\n\nIf you want to link a Mailbox, please choose Settings > Mailbox from the Briar menu.</string>
|
||||||
|
<string name="qr_code_format_unknown">The QR code you have scanned does not come from Briar.\n\nPlease scan the QR code shown on your contact\'s screen.</string>
|
||||||
<string name="camera_error">Camera error</string>
|
<string name="camera_error">Camera error</string>
|
||||||
<string name="connecting_to_device">Connecting to device\u2026</string>
|
<string name="connecting_to_device">Connecting to device\u2026</string>
|
||||||
<string name="authenticating_with_device">Authenticating with device\u2026</string>
|
<string name="authenticating_with_device">Authenticating with device\u2026</string>
|
||||||
@@ -636,8 +638,10 @@
|
|||||||
<string name="mailbox_setup_connecting">Connecting to Mailbox…</string>
|
<string name="mailbox_setup_connecting">Connecting to Mailbox…</string>
|
||||||
<!-- This string is shown when connecting to a Mailbox for the first time. The placeholder will be replaced with a duration, e.g. "2 minutes". -->
|
<!-- This string is shown when connecting to a Mailbox for the first time. The placeholder will be replaced with a duration, e.g. "2 minutes". -->
|
||||||
<string name="mailbox_setup_connecting_info">This may take up to %1s</string>
|
<string name="mailbox_setup_connecting_info">This may take up to %1s</string>
|
||||||
<string name="mailbox_setup_qr_code_wrong_title">Wrong QR code</string>
|
<string name="mailbox_qr_code_too_old">The QR code you have scanned comes from an older version of Briar Mailbox.\n\nPlease upgrade Briar Mailbox to the latest version and then try again.</string>
|
||||||
<string name="mailbox_setup_qr_code_wrong_description">The scanned code is invalid. Please open the Briar Mailbox app on your Mailbox device and scan the QR code it presents.</string>
|
<string name="mailbox_qr_code_too_new">The QR code you have scanned comes from a newer version of Briar Mailbox.\n\nPlease upgrade Briar to the latest version and then try again.</string>
|
||||||
|
<string name="contact_qr_code_for_mailbox">The QR code you have scanned is for adding a Briar contact.\n\nIf you want to add a contact, please go to the contact list and tap the + icon.</string>
|
||||||
|
<string name="mailbox_setup_qr_code_wrong_description">The QR code you have scanned does not come from Briar Mailbox.\n\nPlease open the Briar Mailbox app on your Mailbox device and scan the QR code it presents.</string>
|
||||||
<string name="mailbox_setup_already_paired_title">Mailbox already linked</string>
|
<string name="mailbox_setup_already_paired_title">Mailbox already linked</string>
|
||||||
<string name="mailbox_setup_already_paired_description">Unlink the Mailbox on your other device and try again.</string>
|
<string name="mailbox_setup_already_paired_description">Unlink the Mailbox on your other device and try again.</string>
|
||||||
<string name="mailbox_setup_io_error_title">Could not connect</string>
|
<string name="mailbox_setup_io_error_title">Could not connect</string>
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ import org.briarproject.bramble.api.identity.IdentityManager;
|
|||||||
import org.briarproject.bramble.api.identity.LocalAuthor;
|
import org.briarproject.bramble.api.identity.LocalAuthor;
|
||||||
import org.briarproject.bramble.api.lifecycle.LifecycleManager;
|
import org.briarproject.bramble.api.lifecycle.LifecycleManager;
|
||||||
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.Paired;
|
||||||
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.MailboxUpdateWithMailbox;
|
import org.briarproject.bramble.api.mailbox.MailboxUpdateWithMailbox;
|
||||||
@@ -121,7 +121,7 @@ abstract class AbstractMailboxIntegrationTest
|
|||||||
|
|
||||||
CountDownLatch latch = new CountDownLatch(1);
|
CountDownLatch latch = new CountDownLatch(1);
|
||||||
pairingTask.addObserver((state) -> {
|
pairingTask.addObserver((state) -> {
|
||||||
if (state instanceof MailboxPairingState.Paired) {
|
if (state instanceof Paired) {
|
||||||
latch.countDown();
|
latch.countDown();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user