mirror of
https://code.briarproject.org/briar/briar.git
synced 2026-02-21 07:09:56 +01:00
Merge branch '346-smaller-qr-codes' into 'master'
Encode transport properties more compactly in QR codes The [original BQP spec](https://code.briarproject.org/akwizgran/briar/wikis/BQP) described a compact encoding for transport properties, with the goal of making the QR code as small as possible. At some point during the implementation, I asked @str4d to use TransportIds and TransportProperties instead, as described in the [current spec](https://code.briarproject.org/akwizgran/briar-spec/blob/master/protocols/BQP.md). That was a mistake. Using the original format reduces the payload from 60 to 34 bytes (43% smaller) for Bluetooth only, and from 96 to 49 bytes (49% smaller) for Bluetooth and LAN. This makes it easier to scan codes from low-resolution screens using fixed-focus and/or low-resolution cameras. Using this branch I can exchange codes between the Sony Xperia Tipo (320x480 screen, fixed focus, 640x480 preview size) and the Huawei Ascend Y300 (480x800 screen, infinity focus, 1280x720 preview size). This also removes an obstacle to implementing #558, as TransportIds are no longer included in QR codes. Closes #346. See merge request !394
This commit is contained in:
@@ -57,6 +57,7 @@ import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_NOSENSOR;
|
|||||||
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 java.util.logging.Level.INFO;
|
||||||
import static java.util.logging.Level.WARNING;
|
import static java.util.logging.Level.WARNING;
|
||||||
|
|
||||||
public class ShowQrCodeFragment extends BaseEventFragment
|
public class ShowQrCodeFragment extends BaseEventFragment
|
||||||
@@ -244,8 +245,10 @@ public class ShowQrCodeFragment extends BaseEventFragment
|
|||||||
@UiThread
|
@UiThread
|
||||||
private void qrCodeScanned(String content) {
|
private void qrCodeScanned(String content) {
|
||||||
try {
|
try {
|
||||||
Payload remotePayload = payloadParser.parse(
|
byte[] encoded = Base64.decode(content, 0);
|
||||||
Base64.decode(content, 0));
|
if (LOG.isLoggable(INFO))
|
||||||
|
LOG.info("Remote payload is " + encoded.length + " bytes");
|
||||||
|
Payload remotePayload = payloadParser.parse(encoded);
|
||||||
cameraView.setVisibility(INVISIBLE);
|
cameraView.setVisibility(INVISIBLE);
|
||||||
statusView.setVisibility(VISIBLE);
|
statusView.setVisibility(VISIBLE);
|
||||||
status.setText(R.string.connecting_to_device);
|
status.setText(R.string.connecting_to_device);
|
||||||
@@ -293,9 +296,10 @@ public class ShowQrCodeFragment extends BaseEventFragment
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected Bitmap doInBackground(Void... params) {
|
protected Bitmap doInBackground(Void... params) {
|
||||||
String input =
|
byte[] encoded = payloadEncoder.encode(payload);
|
||||||
Base64.encodeToString(payloadEncoder.encode(payload),
|
if (LOG.isLoggable(INFO))
|
||||||
0);
|
LOG.info("Local payload is " + encoded.length + " bytes");
|
||||||
|
String input = Base64.encodeToString(encoded, 0);
|
||||||
return QrCodeUtils.createQrCode(dm, input);
|
return QrCodeUtils.createQrCode(dm, input);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -11,12 +11,15 @@ import android.content.IntentFilter;
|
|||||||
|
|
||||||
import org.briarproject.android.api.AndroidExecutor;
|
import org.briarproject.android.api.AndroidExecutor;
|
||||||
import org.briarproject.android.util.AndroidUtils;
|
import org.briarproject.android.util.AndroidUtils;
|
||||||
|
import org.briarproject.api.FormatException;
|
||||||
import org.briarproject.api.TransportId;
|
import org.briarproject.api.TransportId;
|
||||||
import org.briarproject.api.contact.ContactId;
|
import org.briarproject.api.contact.ContactId;
|
||||||
import org.briarproject.api.crypto.PseudoRandom;
|
import org.briarproject.api.crypto.PseudoRandom;
|
||||||
|
import org.briarproject.api.data.BdfList;
|
||||||
import org.briarproject.api.keyagreement.KeyAgreementConnection;
|
import org.briarproject.api.keyagreement.KeyAgreementConnection;
|
||||||
import org.briarproject.api.keyagreement.KeyAgreementListener;
|
import org.briarproject.api.keyagreement.KeyAgreementListener;
|
||||||
import org.briarproject.api.keyagreement.TransportDescriptor;
|
import org.briarproject.api.nullsafety.MethodsNotNullByDefault;
|
||||||
|
import org.briarproject.api.nullsafety.ParametersNotNullByDefault;
|
||||||
import org.briarproject.api.plugins.Backoff;
|
import org.briarproject.api.plugins.Backoff;
|
||||||
import org.briarproject.api.plugins.duplex.DuplexPlugin;
|
import org.briarproject.api.plugins.duplex.DuplexPlugin;
|
||||||
import org.briarproject.api.plugins.duplex.DuplexPluginCallback;
|
import org.briarproject.api.plugins.duplex.DuplexPluginCallback;
|
||||||
@@ -24,6 +27,7 @@ import org.briarproject.api.plugins.duplex.DuplexTransportConnection;
|
|||||||
import org.briarproject.api.properties.TransportProperties;
|
import org.briarproject.api.properties.TransportProperties;
|
||||||
import org.briarproject.util.StringUtils;
|
import org.briarproject.util.StringUtils;
|
||||||
|
|
||||||
|
import java.io.Closeable;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.security.SecureRandom;
|
import java.security.SecureRandom;
|
||||||
@@ -44,6 +48,8 @@ import java.util.concurrent.Future;
|
|||||||
import java.util.concurrent.atomic.AtomicBoolean;
|
import java.util.concurrent.atomic.AtomicBoolean;
|
||||||
import java.util.logging.Logger;
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
|
import javax.annotation.Nullable;
|
||||||
|
|
||||||
import static android.bluetooth.BluetoothAdapter.ACTION_SCAN_MODE_CHANGED;
|
import static android.bluetooth.BluetoothAdapter.ACTION_SCAN_MODE_CHANGED;
|
||||||
import static android.bluetooth.BluetoothAdapter.ACTION_STATE_CHANGED;
|
import static android.bluetooth.BluetoothAdapter.ACTION_STATE_CHANGED;
|
||||||
import static android.bluetooth.BluetoothAdapter.EXTRA_SCAN_MODE;
|
import static android.bluetooth.BluetoothAdapter.EXTRA_SCAN_MODE;
|
||||||
@@ -57,8 +63,11 @@ import static android.bluetooth.BluetoothDevice.EXTRA_DEVICE;
|
|||||||
import static java.util.concurrent.TimeUnit.MILLISECONDS;
|
import static java.util.concurrent.TimeUnit.MILLISECONDS;
|
||||||
import static java.util.logging.Level.INFO;
|
import static java.util.logging.Level.INFO;
|
||||||
import static java.util.logging.Level.WARNING;
|
import static java.util.logging.Level.WARNING;
|
||||||
|
import static org.briarproject.api.keyagreement.KeyAgreementConstants.TRANSPORT_ID_BLUETOOTH;
|
||||||
import static org.briarproject.util.PrivacyUtils.scrubMacAddress;
|
import static org.briarproject.util.PrivacyUtils.scrubMacAddress;
|
||||||
|
|
||||||
|
@MethodsNotNullByDefault
|
||||||
|
@ParametersNotNullByDefault
|
||||||
class DroidtoothPlugin implements DuplexPlugin {
|
class DroidtoothPlugin implements DuplexPlugin {
|
||||||
|
|
||||||
// Share an ID with the J2SE Bluetooth plugin
|
// Share an ID with the J2SE Bluetooth plugin
|
||||||
@@ -217,7 +226,7 @@ class DroidtoothPlugin implements DuplexPlugin {
|
|||||||
return UUID.fromString(uuid);
|
return UUID.fromString(uuid);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void tryToClose(BluetoothServerSocket ss) {
|
private void tryToClose(@Nullable BluetoothServerSocket ss) {
|
||||||
try {
|
try {
|
||||||
if (ss != null) ss.close();
|
if (ss != null) ss.close();
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
@@ -340,9 +349,9 @@ class DroidtoothPlugin implements DuplexPlugin {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void tryToClose(BluetoothSocket s) {
|
private void tryToClose(@Nullable Closeable c) {
|
||||||
try {
|
try {
|
||||||
if (s != null) s.close();
|
if (c != null) c.close();
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
||||||
}
|
}
|
||||||
@@ -420,7 +429,7 @@ class DroidtoothPlugin implements DuplexPlugin {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void closeSockets(final List<Future<BluetoothSocket>> futures,
|
private void closeSockets(final List<Future<BluetoothSocket>> futures,
|
||||||
final BluetoothSocket chosen) {
|
@Nullable final BluetoothSocket chosen) {
|
||||||
ioExecutor.execute(new Runnable() {
|
ioExecutor.execute(new Runnable() {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
@@ -454,6 +463,9 @@ class DroidtoothPlugin implements DuplexPlugin {
|
|||||||
@Override
|
@Override
|
||||||
public KeyAgreementListener createKeyAgreementListener(byte[] commitment) {
|
public KeyAgreementListener createKeyAgreementListener(byte[] commitment) {
|
||||||
if (!isRunning()) return null;
|
if (!isRunning()) return null;
|
||||||
|
// There's no point listening if we can't discover our own address
|
||||||
|
String address = AndroidUtils.getBluetoothAddress(appContext, adapter);
|
||||||
|
if (address.isEmpty()) return null;
|
||||||
// No truncation necessary because COMMIT_LENGTH = 16
|
// No truncation necessary because COMMIT_LENGTH = 16
|
||||||
UUID uuid = UUID.nameUUIDFromBytes(commitment);
|
UUID uuid = UUID.nameUUIDFromBytes(commitment);
|
||||||
if (LOG.isLoggable(INFO)) LOG.info("Key agreement UUID " + uuid);
|
if (LOG.isLoggable(INFO)) LOG.info("Key agreement UUID " + uuid);
|
||||||
@@ -466,23 +478,23 @@ class DroidtoothPlugin implements DuplexPlugin {
|
|||||||
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
TransportProperties p = new TransportProperties();
|
BdfList descriptor = new BdfList();
|
||||||
String address = AndroidUtils.getBluetoothAddress(appContext, adapter);
|
descriptor.add(TRANSPORT_ID_BLUETOOTH);
|
||||||
if (!StringUtils.isNullOrEmpty(address))
|
descriptor.add(StringUtils.macToBytes(address));
|
||||||
p.put(PROP_ADDRESS, address);
|
return new BluetoothKeyAgreementListener(descriptor, ss);
|
||||||
TransportDescriptor d = new TransportDescriptor(ID, p);
|
|
||||||
return new BluetoothKeyAgreementListener(d, ss);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public DuplexTransportConnection createKeyAgreementConnection(
|
public DuplexTransportConnection createKeyAgreementConnection(
|
||||||
byte[] commitment, TransportDescriptor d, long timeout) {
|
byte[] commitment, BdfList descriptor, long timeout) {
|
||||||
if (!isRunning()) return null;
|
if (!isRunning()) return null;
|
||||||
if (!ID.equals(d.getIdentifier())) return null;
|
String address;
|
||||||
TransportProperties p = d.getProperties();
|
try {
|
||||||
if (p == null) return null;
|
address = parseAddress(descriptor);
|
||||||
String address = p.get(PROP_ADDRESS);
|
} catch (FormatException e) {
|
||||||
if (StringUtils.isNullOrEmpty(address)) return null;
|
LOG.info("Invalid address in key agreement descriptor");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
// No truncation necessary because COMMIT_LENGTH = 16
|
// No truncation necessary because COMMIT_LENGTH = 16
|
||||||
UUID uuid = UUID.nameUUIDFromBytes(commitment);
|
UUID uuid = UUID.nameUUIDFromBytes(commitment);
|
||||||
if (LOG.isLoggable(INFO))
|
if (LOG.isLoggable(INFO))
|
||||||
@@ -492,6 +504,12 @@ class DroidtoothPlugin implements DuplexPlugin {
|
|||||||
return new DroidtoothTransportConnection(this, s);
|
return new DroidtoothTransportConnection(this, s);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private String parseAddress(BdfList descriptor) throws FormatException {
|
||||||
|
byte[] mac = descriptor.getRaw(1);
|
||||||
|
if (mac.length != 6) throw new FormatException();
|
||||||
|
return StringUtils.macToString(mac);
|
||||||
|
}
|
||||||
|
|
||||||
private class BluetoothStateReceiver extends BroadcastReceiver {
|
private class BluetoothStateReceiver extends BroadcastReceiver {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -626,7 +644,7 @@ class DroidtoothPlugin implements DuplexPlugin {
|
|||||||
|
|
||||||
private final BluetoothServerSocket ss;
|
private final BluetoothServerSocket ss;
|
||||||
|
|
||||||
BluetoothKeyAgreementListener(TransportDescriptor descriptor,
|
BluetoothKeyAgreementListener(BdfList descriptor,
|
||||||
BluetoothServerSocket ss) {
|
BluetoothServerSocket ss) {
|
||||||
super(descriptor);
|
super(descriptor);
|
||||||
this.ss = ss;
|
this.ss = ss;
|
||||||
|
|||||||
@@ -7,16 +7,20 @@ import android.content.IntentFilter;
|
|||||||
import android.net.ConnectivityManager;
|
import android.net.ConnectivityManager;
|
||||||
import android.net.NetworkInfo;
|
import android.net.NetworkInfo;
|
||||||
|
|
||||||
|
import org.briarproject.api.nullsafety.NotNullByDefault;
|
||||||
import org.briarproject.api.plugins.Backoff;
|
import org.briarproject.api.plugins.Backoff;
|
||||||
import org.briarproject.api.plugins.duplex.DuplexPluginCallback;
|
import org.briarproject.api.plugins.duplex.DuplexPluginCallback;
|
||||||
|
|
||||||
import java.util.concurrent.Executor;
|
import java.util.concurrent.Executor;
|
||||||
import java.util.logging.Logger;
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
|
import javax.annotation.Nullable;
|
||||||
|
|
||||||
import static android.content.Context.CONNECTIVITY_SERVICE;
|
import static android.content.Context.CONNECTIVITY_SERVICE;
|
||||||
import static android.net.ConnectivityManager.CONNECTIVITY_ACTION;
|
import static android.net.ConnectivityManager.CONNECTIVITY_ACTION;
|
||||||
import static android.net.ConnectivityManager.TYPE_WIFI;
|
import static android.net.ConnectivityManager.TYPE_WIFI;
|
||||||
|
|
||||||
|
@NotNullByDefault
|
||||||
class AndroidLanTcpPlugin extends LanTcpPlugin {
|
class AndroidLanTcpPlugin extends LanTcpPlugin {
|
||||||
|
|
||||||
private static final Logger LOG =
|
private static final Logger LOG =
|
||||||
@@ -24,6 +28,7 @@ class AndroidLanTcpPlugin extends LanTcpPlugin {
|
|||||||
|
|
||||||
private final Context appContext;
|
private final Context appContext;
|
||||||
|
|
||||||
|
@Nullable
|
||||||
private volatile BroadcastReceiver networkStateReceiver = null;
|
private volatile BroadcastReceiver networkStateReceiver = null;
|
||||||
|
|
||||||
AndroidLanTcpPlugin(Executor ioExecutor, Backoff backoff,
|
AndroidLanTcpPlugin(Executor ioExecutor, Backoff backoff,
|
||||||
|
|||||||
@@ -19,11 +19,12 @@ import org.briarproject.android.util.AndroidUtils;
|
|||||||
import org.briarproject.api.TransportId;
|
import org.briarproject.api.TransportId;
|
||||||
import org.briarproject.api.contact.ContactId;
|
import org.briarproject.api.contact.ContactId;
|
||||||
import org.briarproject.api.crypto.PseudoRandom;
|
import org.briarproject.api.crypto.PseudoRandom;
|
||||||
|
import org.briarproject.api.data.BdfList;
|
||||||
import org.briarproject.api.event.Event;
|
import org.briarproject.api.event.Event;
|
||||||
import org.briarproject.api.event.EventListener;
|
import org.briarproject.api.event.EventListener;
|
||||||
import org.briarproject.api.event.SettingsUpdatedEvent;
|
import org.briarproject.api.event.SettingsUpdatedEvent;
|
||||||
import org.briarproject.api.keyagreement.KeyAgreementListener;
|
import org.briarproject.api.keyagreement.KeyAgreementListener;
|
||||||
import org.briarproject.api.keyagreement.TransportDescriptor;
|
import org.briarproject.api.nullsafety.NotNullByDefault;
|
||||||
import org.briarproject.api.plugins.Backoff;
|
import org.briarproject.api.plugins.Backoff;
|
||||||
import org.briarproject.api.plugins.TorConstants;
|
import org.briarproject.api.plugins.TorConstants;
|
||||||
import org.briarproject.api.plugins.duplex.DuplexPlugin;
|
import org.briarproject.api.plugins.duplex.DuplexPlugin;
|
||||||
@@ -60,6 +61,7 @@ import java.util.logging.Logger;
|
|||||||
import java.util.regex.Pattern;
|
import java.util.regex.Pattern;
|
||||||
import java.util.zip.ZipInputStream;
|
import java.util.zip.ZipInputStream;
|
||||||
|
|
||||||
|
import javax.annotation.Nullable;
|
||||||
import javax.net.SocketFactory;
|
import javax.net.SocketFactory;
|
||||||
|
|
||||||
import static android.content.Context.CONNECTIVITY_SERVICE;
|
import static android.content.Context.CONNECTIVITY_SERVICE;
|
||||||
@@ -76,6 +78,7 @@ import static net.freehaven.tor.control.TorControlCommands.HS_PRIVKEY;
|
|||||||
import static org.briarproject.api.plugins.TorConstants.CONTROL_PORT;
|
import static org.briarproject.api.plugins.TorConstants.CONTROL_PORT;
|
||||||
import static org.briarproject.util.PrivacyUtils.scrubOnion;
|
import static org.briarproject.util.PrivacyUtils.scrubOnion;
|
||||||
|
|
||||||
|
@NotNullByDefault
|
||||||
class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
|
class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
|
||||||
|
|
||||||
private static final String PROP_ONION = "onion";
|
private static final String PROP_ONION = "onion";
|
||||||
@@ -104,9 +107,13 @@ class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
|
|||||||
private final AtomicBoolean used = new AtomicBoolean(false);
|
private final AtomicBoolean used = new AtomicBoolean(false);
|
||||||
|
|
||||||
private volatile boolean running = false;
|
private volatile boolean running = false;
|
||||||
|
@Nullable
|
||||||
private volatile ServerSocket socket = null;
|
private volatile ServerSocket socket = null;
|
||||||
|
@Nullable
|
||||||
private volatile Socket controlSocket = null;
|
private volatile Socket controlSocket = null;
|
||||||
|
@Nullable
|
||||||
private volatile TorControlConnection controlConnection = null;
|
private volatile TorControlConnection controlConnection = null;
|
||||||
|
@Nullable
|
||||||
private volatile BroadcastReceiver networkStateReceiver = null;
|
private volatile BroadcastReceiver networkStateReceiver = null;
|
||||||
|
|
||||||
TorPlugin(Executor ioExecutor, Context appContext,
|
TorPlugin(Executor ioExecutor, Context appContext,
|
||||||
@@ -289,7 +296,7 @@ class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
|
|||||||
return appContext.getResources().getAssets().open("torrc");
|
return appContext.getResources().getAssets().open("torrc");
|
||||||
}
|
}
|
||||||
|
|
||||||
private void tryToClose(Closeable c) {
|
private void tryToClose(@Nullable Closeable c) {
|
||||||
try {
|
try {
|
||||||
if (c != null) c.close();
|
if (c != null) c.close();
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
@@ -297,7 +304,7 @@ class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void tryToClose(Socket s) {
|
private void tryToClose(@Nullable Socket s) {
|
||||||
try {
|
try {
|
||||||
if (s != null) s.close();
|
if (s != null) s.close();
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
@@ -385,7 +392,7 @@ class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private void tryToClose(ServerSocket ss) {
|
private void tryToClose(@Nullable ServerSocket ss) {
|
||||||
try {
|
try {
|
||||||
if (ss != null) ss.close();
|
if (ss != null) ss.close();
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
@@ -574,7 +581,7 @@ class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public DuplexTransportConnection createKeyAgreementConnection(
|
public DuplexTransportConnection createKeyAgreementConnection(
|
||||||
byte[] commitment, TransportDescriptor d, long timeout) {
|
byte[] commitment, BdfList descriptor, long timeout) {
|
||||||
throw new UnsupportedOperationException();
|
throw new UnsupportedOperationException();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ package org.briarproject.api.keyagreement;
|
|||||||
public interface KeyAgreementConstants {
|
public interface KeyAgreementConstants {
|
||||||
|
|
||||||
/** The current version of the BQP protocol. */
|
/** The current version of the BQP protocol. */
|
||||||
byte PROTOCOL_VERSION = 1;
|
byte PROTOCOL_VERSION = 2;
|
||||||
|
|
||||||
/** The length of the record header in bytes. */
|
/** The length of the record header in bytes. */
|
||||||
int RECORD_HEADER_LENGTH = 4;
|
int RECORD_HEADER_LENGTH = 4;
|
||||||
@@ -16,4 +16,10 @@ public interface KeyAgreementConstants {
|
|||||||
int COMMIT_LENGTH = 16;
|
int COMMIT_LENGTH = 16;
|
||||||
|
|
||||||
long CONNECTION_TIMEOUT = 20 * 1000; // Milliseconds
|
long CONNECTION_TIMEOUT = 20 * 1000; // Milliseconds
|
||||||
|
|
||||||
|
/** The transport identifier for Bluetooth. */
|
||||||
|
int TRANSPORT_ID_BLUETOOTH = 0;
|
||||||
|
|
||||||
|
/** The transport identifier for LAN. */
|
||||||
|
int TRANSPORT_ID_LAN = 1;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
package org.briarproject.api.keyagreement;
|
package org.briarproject.api.keyagreement;
|
||||||
|
|
||||||
|
import org.briarproject.api.data.BdfList;
|
||||||
|
|
||||||
import java.util.concurrent.Callable;
|
import java.util.concurrent.Callable;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -7,9 +9,9 @@ import java.util.concurrent.Callable;
|
|||||||
*/
|
*/
|
||||||
public abstract class KeyAgreementListener {
|
public abstract class KeyAgreementListener {
|
||||||
|
|
||||||
private final TransportDescriptor descriptor;
|
private final BdfList descriptor;
|
||||||
|
|
||||||
public KeyAgreementListener(TransportDescriptor descriptor) {
|
public KeyAgreementListener(BdfList descriptor) {
|
||||||
this.descriptor = descriptor;
|
this.descriptor = descriptor;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -17,7 +19,7 @@ public abstract class KeyAgreementListener {
|
|||||||
* Returns the descriptor that a remote peer can use to connect to this
|
* Returns the descriptor that a remote peer can use to connect to this
|
||||||
* listener.
|
* listener.
|
||||||
*/
|
*/
|
||||||
public TransportDescriptor getDescriptor() {
|
public BdfList getDescriptor() {
|
||||||
return descriptor;
|
return descriptor;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,29 +1,40 @@
|
|||||||
package org.briarproject.api.keyagreement;
|
package org.briarproject.api.keyagreement;
|
||||||
|
|
||||||
import org.briarproject.api.Bytes;
|
import org.briarproject.api.Bytes;
|
||||||
|
import org.briarproject.api.TransportId;
|
||||||
|
import org.briarproject.api.data.BdfList;
|
||||||
|
import org.briarproject.api.nullsafety.NotNullByDefault;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.Map;
|
||||||
|
|
||||||
|
import javax.annotation.concurrent.Immutable;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A BQP payload.
|
* A BQP payload.
|
||||||
*/
|
*/
|
||||||
|
@Immutable
|
||||||
|
@NotNullByDefault
|
||||||
public class Payload implements Comparable<Payload> {
|
public class Payload implements Comparable<Payload> {
|
||||||
|
|
||||||
private final Bytes commitment;
|
private final Bytes commitment;
|
||||||
private final List<TransportDescriptor> descriptors;
|
private final Map<TransportId, BdfList> descriptors;
|
||||||
|
|
||||||
public Payload(byte[] commitment, List<TransportDescriptor> descriptors) {
|
public Payload(byte[] commitment, Map<TransportId, BdfList> descriptors) {
|
||||||
this.commitment = new Bytes(commitment);
|
this.commitment = new Bytes(commitment);
|
||||||
this.descriptors = descriptors;
|
this.descriptors = descriptors;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Returns the commitment contained in this payload. */
|
/**
|
||||||
|
* Returns the commitment contained in this payload.
|
||||||
|
*/
|
||||||
public byte[] getCommitment() {
|
public byte[] getCommitment() {
|
||||||
return commitment.getBytes();
|
return commitment.getBytes();
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Returns the transport descriptors contained in this payload. */
|
/**
|
||||||
public List<TransportDescriptor> getTransportDescriptors() {
|
* Returns the transport descriptors contained in this payload.
|
||||||
|
*/
|
||||||
|
public Map<TransportId, BdfList> getTransportDescriptors() {
|
||||||
return descriptors;
|
return descriptors;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,10 @@
|
|||||||
package org.briarproject.api.keyagreement;
|
package org.briarproject.api.keyagreement;
|
||||||
|
|
||||||
|
import org.briarproject.api.nullsafety.NotNullByDefault;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
|
||||||
|
@NotNullByDefault
|
||||||
public interface PayloadParser {
|
public interface PayloadParser {
|
||||||
|
|
||||||
Payload parse(byte[] raw) throws IOException;
|
Payload parse(byte[] raw) throws IOException;
|
||||||
|
|||||||
@@ -1,28 +0,0 @@
|
|||||||
package org.briarproject.api.keyagreement;
|
|
||||||
|
|
||||||
import org.briarproject.api.TransportId;
|
|
||||||
import org.briarproject.api.properties.TransportProperties;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Describes how to connect to a device over a short-range transport.
|
|
||||||
*/
|
|
||||||
public class TransportDescriptor {
|
|
||||||
|
|
||||||
private final TransportId id;
|
|
||||||
private final TransportProperties properties;
|
|
||||||
|
|
||||||
public TransportDescriptor(TransportId id, TransportProperties properties) {
|
|
||||||
this.id = id;
|
|
||||||
this.properties = properties;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Returns the transport identifier. */
|
|
||||||
public TransportId getIdentifier() {
|
|
||||||
return id;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Returns the transport properties. */
|
|
||||||
public TransportProperties getProperties() {
|
|
||||||
return properties;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -2,28 +2,42 @@ package org.briarproject.api.plugins;
|
|||||||
|
|
||||||
import org.briarproject.api.TransportId;
|
import org.briarproject.api.TransportId;
|
||||||
import org.briarproject.api.contact.ContactId;
|
import org.briarproject.api.contact.ContactId;
|
||||||
|
import org.briarproject.api.nullsafety.NotNullByDefault;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
|
|
||||||
|
@NotNullByDefault
|
||||||
public interface Plugin {
|
public interface Plugin {
|
||||||
|
|
||||||
/** Returns the plugin's transport identifier. */
|
/**
|
||||||
|
* Returns the plugin's transport identifier.
|
||||||
|
*/
|
||||||
TransportId getId();
|
TransportId getId();
|
||||||
|
|
||||||
/** Returns the transport's maximum latency in milliseconds. */
|
/**
|
||||||
|
* Returns the transport's maximum latency in milliseconds.
|
||||||
|
*/
|
||||||
int getMaxLatency();
|
int getMaxLatency();
|
||||||
|
|
||||||
/** Returns the transport's maximum idle time in milliseconds. */
|
/**
|
||||||
|
* Returns the transport's maximum idle time in milliseconds.
|
||||||
|
*/
|
||||||
int getMaxIdleTime();
|
int getMaxIdleTime();
|
||||||
|
|
||||||
/** Starts the plugin and returns true if it started successfully. */
|
/**
|
||||||
|
* Starts the plugin and returns true if it started successfully.
|
||||||
|
*/
|
||||||
boolean start() throws IOException;
|
boolean start() throws IOException;
|
||||||
|
|
||||||
/** Stops the plugin. */
|
/**
|
||||||
|
* Stops the plugin.
|
||||||
|
*/
|
||||||
void stop() throws IOException;
|
void stop() throws IOException;
|
||||||
|
|
||||||
/** Returns true if the plugin is running. */
|
/**
|
||||||
|
* Returns true if the plugin is running.
|
||||||
|
*/
|
||||||
boolean isRunning();
|
boolean isRunning();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -1,21 +1,26 @@
|
|||||||
package org.briarproject.api.plugins;
|
package org.briarproject.api.plugins;
|
||||||
|
|
||||||
import org.briarproject.api.TransportId;
|
import org.briarproject.api.TransportId;
|
||||||
|
import org.briarproject.api.nullsafety.NotNullByDefault;
|
||||||
import org.briarproject.api.plugins.duplex.DuplexPlugin;
|
import org.briarproject.api.plugins.duplex.DuplexPlugin;
|
||||||
import org.briarproject.api.plugins.simplex.SimplexPlugin;
|
import org.briarproject.api.plugins.simplex.SimplexPlugin;
|
||||||
|
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
|
|
||||||
|
import javax.annotation.Nullable;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Responsible for starting transport plugins at startup and stopping them at
|
* Responsible for starting transport plugins at startup and stopping them at
|
||||||
* shutdown.
|
* shutdown.
|
||||||
*/
|
*/
|
||||||
|
@NotNullByDefault
|
||||||
public interface PluginManager {
|
public interface PluginManager {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the plugin for the given transport, or null if no such plugin
|
* Returns the plugin for the given transport, or null if no such plugin
|
||||||
* has been created.
|
* has been created.
|
||||||
*/
|
*/
|
||||||
|
@Nullable
|
||||||
Plugin getPlugin(TransportId t);
|
Plugin getPlugin(TransportId t);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -2,21 +2,30 @@ package org.briarproject.api.plugins.duplex;
|
|||||||
|
|
||||||
import org.briarproject.api.contact.ContactId;
|
import org.briarproject.api.contact.ContactId;
|
||||||
import org.briarproject.api.crypto.PseudoRandom;
|
import org.briarproject.api.crypto.PseudoRandom;
|
||||||
|
import org.briarproject.api.data.BdfList;
|
||||||
import org.briarproject.api.keyagreement.KeyAgreementListener;
|
import org.briarproject.api.keyagreement.KeyAgreementListener;
|
||||||
import org.briarproject.api.keyagreement.TransportDescriptor;
|
import org.briarproject.api.nullsafety.NotNullByDefault;
|
||||||
import org.briarproject.api.plugins.Plugin;
|
import org.briarproject.api.plugins.Plugin;
|
||||||
|
|
||||||
/** An interface for transport plugins that support duplex communication. */
|
import javax.annotation.Nullable;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An interface for transport plugins that support duplex communication.
|
||||||
|
*/
|
||||||
|
@NotNullByDefault
|
||||||
public interface DuplexPlugin extends Plugin {
|
public interface DuplexPlugin extends Plugin {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Attempts to create and return a connection to the given contact using
|
* Attempts to create and return a connection to the given contact using
|
||||||
* the current transport and configuration properties. Returns null if a
|
* the current transport and configuration properties. Returns null if a
|
||||||
* connection could not be created.
|
* connection cannot be created.
|
||||||
*/
|
*/
|
||||||
|
@Nullable
|
||||||
DuplexTransportConnection createConnection(ContactId c);
|
DuplexTransportConnection createConnection(ContactId c);
|
||||||
|
|
||||||
/** Returns true if the plugin supports exchanging invitations. */
|
/**
|
||||||
|
* Returns true if the plugin supports exchanging invitations.
|
||||||
|
*/
|
||||||
boolean supportsInvitations();
|
boolean supportsInvitations();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -24,21 +33,27 @@ public interface DuplexPlugin extends Plugin {
|
|||||||
* peer. Returns null if no connection can be established within the given
|
* peer. Returns null if no connection can be established within the given
|
||||||
* time.
|
* time.
|
||||||
*/
|
*/
|
||||||
|
@Nullable
|
||||||
DuplexTransportConnection createInvitationConnection(PseudoRandom r,
|
DuplexTransportConnection createInvitationConnection(PseudoRandom r,
|
||||||
long timeout, boolean alice);
|
long timeout, boolean alice);
|
||||||
|
|
||||||
/** Returns true if the plugin supports short-range key agreement. */
|
/**
|
||||||
|
* Returns true if the plugin supports short-range key agreement.
|
||||||
|
*/
|
||||||
boolean supportsKeyAgreement();
|
boolean supportsKeyAgreement();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns a listener that can be used to perform key agreement.
|
* Attempts to create and return a listener that can be used to perform key
|
||||||
|
* agreement. Returns null if a listener cannot be created.
|
||||||
*/
|
*/
|
||||||
|
@Nullable
|
||||||
KeyAgreementListener createKeyAgreementListener(byte[] localCommitment);
|
KeyAgreementListener createKeyAgreementListener(byte[] localCommitment);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Attempts to connect to the remote peer specified in the given descriptor.
|
* Attempts to connect to the remote peer specified in the given descriptor.
|
||||||
* Returns null if no connection can be established within the given time.
|
* Returns null if no connection can be established within the given time.
|
||||||
*/
|
*/
|
||||||
|
@Nullable
|
||||||
DuplexTransportConnection createKeyAgreementConnection(
|
DuplexTransportConnection createKeyAgreementConnection(
|
||||||
byte[] remoteCommitment, TransportDescriptor d, long timeout);
|
byte[] remoteCommitment, BdfList descriptor, long timeout);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,24 +1,32 @@
|
|||||||
package org.briarproject.api.plugins.simplex;
|
package org.briarproject.api.plugins.simplex;
|
||||||
|
|
||||||
import org.briarproject.api.contact.ContactId;
|
import org.briarproject.api.contact.ContactId;
|
||||||
|
import org.briarproject.api.nullsafety.NotNullByDefault;
|
||||||
import org.briarproject.api.plugins.Plugin;
|
import org.briarproject.api.plugins.Plugin;
|
||||||
import org.briarproject.api.plugins.TransportConnectionReader;
|
import org.briarproject.api.plugins.TransportConnectionReader;
|
||||||
import org.briarproject.api.plugins.TransportConnectionWriter;
|
import org.briarproject.api.plugins.TransportConnectionWriter;
|
||||||
|
|
||||||
/** An interface for transport plugins that support simplex communication. */
|
import javax.annotation.Nullable;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An interface for transport plugins that support simplex communication.
|
||||||
|
*/
|
||||||
|
@NotNullByDefault
|
||||||
public interface SimplexPlugin extends Plugin {
|
public interface SimplexPlugin extends Plugin {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Attempts to create and return a reader for the given contact using the
|
* Attempts to create and return a reader for the given contact using the
|
||||||
* current transport and configuration properties. Returns null if a reader
|
* current transport and configuration properties. Returns null if a reader
|
||||||
* could not be created.
|
* cannot be created.
|
||||||
*/
|
*/
|
||||||
|
@Nullable
|
||||||
TransportConnectionReader createReader(ContactId c);
|
TransportConnectionReader createReader(ContactId c);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Attempts to create and return a writer for the given contact using the
|
* Attempts to create and return a writer for the given contact using the
|
||||||
* current transport and configuration properties. Returns null if a writer
|
* current transport and configuration properties. Returns null if a writer
|
||||||
* could not be created.
|
* cannot be created.
|
||||||
*/
|
*/
|
||||||
|
@Nullable
|
||||||
TransportConnectionWriter createWriter(ContactId c);
|
TransportConnectionWriter createWriter(ContactId c);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,11 +1,13 @@
|
|||||||
package org.briarproject.keyagreement;
|
package org.briarproject.keyagreement;
|
||||||
|
|
||||||
|
import org.briarproject.api.TransportId;
|
||||||
import org.briarproject.api.crypto.CryptoComponent;
|
import org.briarproject.api.crypto.CryptoComponent;
|
||||||
import org.briarproject.api.crypto.KeyPair;
|
import org.briarproject.api.crypto.KeyPair;
|
||||||
|
import org.briarproject.api.data.BdfList;
|
||||||
import org.briarproject.api.keyagreement.KeyAgreementConnection;
|
import org.briarproject.api.keyagreement.KeyAgreementConnection;
|
||||||
import org.briarproject.api.keyagreement.KeyAgreementListener;
|
import org.briarproject.api.keyagreement.KeyAgreementListener;
|
||||||
import org.briarproject.api.keyagreement.Payload;
|
import org.briarproject.api.keyagreement.Payload;
|
||||||
import org.briarproject.api.keyagreement.TransportDescriptor;
|
import org.briarproject.api.plugins.Plugin;
|
||||||
import org.briarproject.api.plugins.PluginManager;
|
import org.briarproject.api.plugins.PluginManager;
|
||||||
import org.briarproject.api.plugins.duplex.DuplexPlugin;
|
import org.briarproject.api.plugins.duplex.DuplexPlugin;
|
||||||
import org.briarproject.api.plugins.duplex.DuplexTransportConnection;
|
import org.briarproject.api.plugins.duplex.DuplexTransportConnection;
|
||||||
@@ -14,7 +16,10 @@ import org.briarproject.api.system.Clock;
|
|||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Map.Entry;
|
||||||
import java.util.concurrent.Callable;
|
import java.util.concurrent.Callable;
|
||||||
import java.util.concurrent.CompletionService;
|
import java.util.concurrent.CompletionService;
|
||||||
import java.util.concurrent.ExecutionException;
|
import java.util.concurrent.ExecutionException;
|
||||||
@@ -68,14 +73,13 @@ class KeyAgreementConnector {
|
|||||||
byte[] commitment = crypto.deriveKeyCommitment(
|
byte[] commitment = crypto.deriveKeyCommitment(
|
||||||
localKeyPair.getPublic().getEncoded());
|
localKeyPair.getPublic().getEncoded());
|
||||||
// Start all listeners and collect their descriptors
|
// Start all listeners and collect their descriptors
|
||||||
List<TransportDescriptor> descriptors =
|
Map<TransportId, BdfList> descriptors =
|
||||||
new ArrayList<TransportDescriptor>();
|
new HashMap<TransportId, BdfList>();
|
||||||
for (DuplexPlugin plugin : pluginManager.getKeyAgreementPlugins()) {
|
for (DuplexPlugin plugin : pluginManager.getKeyAgreementPlugins()) {
|
||||||
KeyAgreementListener l = plugin.createKeyAgreementListener(
|
KeyAgreementListener l =
|
||||||
commitment);
|
plugin.createKeyAgreementListener(commitment);
|
||||||
if (l != null) {
|
if (l != null) {
|
||||||
TransportDescriptor d = l.getDescriptor();
|
descriptors.put(plugin.getId(), l.getDescriptor());
|
||||||
descriptors.add(d);
|
|
||||||
pending.add(connect.submit(new ReadableTask(l.listen())));
|
pending.add(connect.submit(new ReadableTask(l.listen())));
|
||||||
listeners.add(l);
|
listeners.add(l);
|
||||||
}
|
}
|
||||||
@@ -100,13 +104,16 @@ class KeyAgreementConnector {
|
|||||||
|
|
||||||
// Start connecting over supported transports
|
// Start connecting over supported transports
|
||||||
LOG.info("Starting outgoing BQP connections");
|
LOG.info("Starting outgoing BQP connections");
|
||||||
for (TransportDescriptor d : remotePayload.getTransportDescriptors()) {
|
Map<TransportId, BdfList> descriptors =
|
||||||
DuplexPlugin plugin = (DuplexPlugin) pluginManager.getPlugin(
|
remotePayload.getTransportDescriptors();
|
||||||
d.getIdentifier());
|
for (Entry<TransportId, BdfList> e : descriptors.entrySet()) {
|
||||||
if (plugin != null)
|
Plugin p = pluginManager.getPlugin(e.getKey());
|
||||||
|
if (p instanceof DuplexPlugin) {
|
||||||
|
DuplexPlugin plugin = (DuplexPlugin) p;
|
||||||
pending.add(connect.submit(new ReadableTask(
|
pending.add(connect.submit(new ReadableTask(
|
||||||
new ConnectorTask(plugin, remotePayload.getCommitment(),
|
new ConnectorTask(plugin, remotePayload.getCommitment(),
|
||||||
d, end))));
|
e.getValue(), end))));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get chosen connection
|
// Get chosen connection
|
||||||
@@ -170,12 +177,12 @@ class KeyAgreementConnector {
|
|||||||
private class ConnectorTask implements Callable<KeyAgreementConnection> {
|
private class ConnectorTask implements Callable<KeyAgreementConnection> {
|
||||||
|
|
||||||
private final byte[] commitment;
|
private final byte[] commitment;
|
||||||
private final TransportDescriptor descriptor;
|
private final BdfList descriptor;
|
||||||
private final long end;
|
private final long end;
|
||||||
private final DuplexPlugin plugin;
|
private final DuplexPlugin plugin;
|
||||||
|
|
||||||
private ConnectorTask(DuplexPlugin plugin, byte[] commitment,
|
private ConnectorTask(DuplexPlugin plugin, byte[] commitment,
|
||||||
TransportDescriptor descriptor, long end) {
|
BdfList descriptor, long end) {
|
||||||
this.plugin = plugin;
|
this.plugin = plugin;
|
||||||
this.commitment = commitment;
|
this.commitment = commitment;
|
||||||
this.descriptor = descriptor;
|
this.descriptor = descriptor;
|
||||||
|
|||||||
@@ -1,24 +1,30 @@
|
|||||||
package org.briarproject.keyagreement;
|
package org.briarproject.keyagreement;
|
||||||
|
|
||||||
|
import org.briarproject.api.TransportId;
|
||||||
|
import org.briarproject.api.data.BdfList;
|
||||||
import org.briarproject.api.data.BdfWriter;
|
import org.briarproject.api.data.BdfWriter;
|
||||||
import org.briarproject.api.data.BdfWriterFactory;
|
import org.briarproject.api.data.BdfWriterFactory;
|
||||||
import org.briarproject.api.keyagreement.Payload;
|
import org.briarproject.api.keyagreement.Payload;
|
||||||
import org.briarproject.api.keyagreement.PayloadEncoder;
|
import org.briarproject.api.keyagreement.PayloadEncoder;
|
||||||
import org.briarproject.api.keyagreement.TransportDescriptor;
|
import org.briarproject.api.nullsafety.NotNullByDefault;
|
||||||
|
|
||||||
import java.io.ByteArrayOutputStream;
|
import java.io.ByteArrayOutputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import javax.annotation.concurrent.Immutable;
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
|
|
||||||
import static org.briarproject.api.keyagreement.KeyAgreementConstants.PROTOCOL_VERSION;
|
import static org.briarproject.api.keyagreement.KeyAgreementConstants.PROTOCOL_VERSION;
|
||||||
|
|
||||||
|
@Immutable
|
||||||
|
@NotNullByDefault
|
||||||
class PayloadEncoderImpl implements PayloadEncoder {
|
class PayloadEncoderImpl implements PayloadEncoder {
|
||||||
|
|
||||||
private final BdfWriterFactory bdfWriterFactory;
|
private final BdfWriterFactory bdfWriterFactory;
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
public PayloadEncoderImpl(BdfWriterFactory bdfWriterFactory) {
|
PayloadEncoderImpl(BdfWriterFactory bdfWriterFactory) {
|
||||||
this.bdfWriterFactory = bdfWriterFactory;
|
this.bdfWriterFactory = bdfWriterFactory;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -30,18 +36,13 @@ class PayloadEncoderImpl implements PayloadEncoder {
|
|||||||
w.writeListStart(); // Payload start
|
w.writeListStart(); // Payload start
|
||||||
w.writeLong(PROTOCOL_VERSION);
|
w.writeLong(PROTOCOL_VERSION);
|
||||||
w.writeRaw(p.getCommitment());
|
w.writeRaw(p.getCommitment());
|
||||||
w.writeListStart(); // Descriptors start
|
Map<TransportId, BdfList> descriptors = p.getTransportDescriptors();
|
||||||
for (TransportDescriptor d : p.getTransportDescriptors()) {
|
for (BdfList descriptor : descriptors.values())
|
||||||
w.writeListStart();
|
w.writeList(descriptor);
|
||||||
w.writeString(d.getIdentifier().getString());
|
|
||||||
w.writeDictionary(d.getProperties());
|
|
||||||
w.writeListEnd();
|
|
||||||
}
|
|
||||||
w.writeListEnd(); // Descriptors end
|
|
||||||
w.writeListEnd(); // Payload end
|
w.writeListEnd(); // Payload end
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
// Shouldn't happen with ByteArrayOutputStream
|
// Shouldn't happen with ByteArrayOutputStream
|
||||||
throw new RuntimeException(e);
|
throw new AssertionError(e);
|
||||||
}
|
}
|
||||||
return out.toByteArray();
|
return out.toByteArray();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,30 +2,34 @@ package org.briarproject.keyagreement;
|
|||||||
|
|
||||||
import org.briarproject.api.FormatException;
|
import org.briarproject.api.FormatException;
|
||||||
import org.briarproject.api.TransportId;
|
import org.briarproject.api.TransportId;
|
||||||
|
import org.briarproject.api.data.BdfList;
|
||||||
import org.briarproject.api.data.BdfReader;
|
import org.briarproject.api.data.BdfReader;
|
||||||
import org.briarproject.api.data.BdfReaderFactory;
|
import org.briarproject.api.data.BdfReaderFactory;
|
||||||
import org.briarproject.api.keyagreement.Payload;
|
import org.briarproject.api.keyagreement.Payload;
|
||||||
import org.briarproject.api.keyagreement.PayloadParser;
|
import org.briarproject.api.keyagreement.PayloadParser;
|
||||||
import org.briarproject.api.keyagreement.TransportDescriptor;
|
import org.briarproject.api.nullsafety.NotNullByDefault;
|
||||||
import org.briarproject.api.properties.TransportProperties;
|
|
||||||
|
|
||||||
import java.io.ByteArrayInputStream;
|
import java.io.ByteArrayInputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.ArrayList;
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.Map;
|
||||||
|
|
||||||
|
import javax.annotation.concurrent.Immutable;
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
|
|
||||||
import static org.briarproject.api.keyagreement.KeyAgreementConstants.COMMIT_LENGTH;
|
import static org.briarproject.api.keyagreement.KeyAgreementConstants.COMMIT_LENGTH;
|
||||||
import static org.briarproject.api.keyagreement.KeyAgreementConstants.PROTOCOL_VERSION;
|
import static org.briarproject.api.keyagreement.KeyAgreementConstants.PROTOCOL_VERSION;
|
||||||
import static org.briarproject.api.properties.TransportPropertyConstants.MAX_PROPERTY_LENGTH;
|
import static org.briarproject.api.keyagreement.KeyAgreementConstants.TRANSPORT_ID_BLUETOOTH;
|
||||||
|
import static org.briarproject.api.keyagreement.KeyAgreementConstants.TRANSPORT_ID_LAN;
|
||||||
|
|
||||||
|
@Immutable
|
||||||
|
@NotNullByDefault
|
||||||
class PayloadParserImpl implements PayloadParser {
|
class PayloadParserImpl implements PayloadParser {
|
||||||
|
|
||||||
private final BdfReaderFactory bdfReaderFactory;
|
private final BdfReaderFactory bdfReaderFactory;
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
public PayloadParserImpl(BdfReaderFactory bdfReaderFactory) {
|
PayloadParserImpl(BdfReaderFactory bdfReaderFactory) {
|
||||||
this.bdfReaderFactory = bdfReaderFactory;
|
this.bdfReaderFactory = bdfReaderFactory;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -33,36 +37,28 @@ class PayloadParserImpl implements PayloadParser {
|
|||||||
public Payload parse(byte[] raw) throws IOException {
|
public Payload parse(byte[] raw) throws IOException {
|
||||||
ByteArrayInputStream in = new ByteArrayInputStream(raw);
|
ByteArrayInputStream in = new ByteArrayInputStream(raw);
|
||||||
BdfReader r = bdfReaderFactory.createReader(in);
|
BdfReader r = bdfReaderFactory.createReader(in);
|
||||||
r.readListStart(); // Payload start
|
// The payload is a BDF list with two or more elements
|
||||||
int proto = (int) r.readLong();
|
BdfList payload = r.readList();
|
||||||
if (proto != PROTOCOL_VERSION)
|
if (payload.size() < 2) throw new FormatException();
|
||||||
throw new FormatException();
|
if (!r.eof()) throw new FormatException();
|
||||||
byte[] commitment = r.readRaw(COMMIT_LENGTH);
|
// First element: the protocol version
|
||||||
if (commitment.length != COMMIT_LENGTH)
|
long protocolVersion = payload.getLong(0);
|
||||||
throw new FormatException();
|
if (protocolVersion != PROTOCOL_VERSION) throw new FormatException();
|
||||||
List<TransportDescriptor> descriptors = new ArrayList<TransportDescriptor>();
|
// Second element: the public key commitment
|
||||||
r.readListStart(); // Descriptors start
|
byte[] commitment = payload.getRaw(1);
|
||||||
while (r.hasList()) {
|
if (commitment.length != COMMIT_LENGTH) throw new FormatException();
|
||||||
r.readListStart();
|
// Remaining elements: transport descriptors
|
||||||
while (!r.hasListEnd()) {
|
Map<TransportId, BdfList> recognised =
|
||||||
TransportId id =
|
new HashMap<TransportId, BdfList>();
|
||||||
new TransportId(r.readString(MAX_PROPERTY_LENGTH));
|
for (int i = 2; i < payload.size(); i++) {
|
||||||
TransportProperties p = new TransportProperties();
|
BdfList descriptor = payload.getList(i);
|
||||||
r.readDictionaryStart();
|
long transportId = descriptor.getLong(0);
|
||||||
while (!r.hasDictionaryEnd()) {
|
if (transportId == TRANSPORT_ID_BLUETOOTH) {
|
||||||
String key = r.readString(MAX_PROPERTY_LENGTH);
|
recognised.put(new TransportId("bt"), descriptor);
|
||||||
String value = r.readString(MAX_PROPERTY_LENGTH);
|
} else if (transportId == TRANSPORT_ID_LAN) {
|
||||||
p.put(key, value);
|
recognised.put(new TransportId("lan"), descriptor);
|
||||||
}
|
|
||||||
r.readDictionaryEnd();
|
|
||||||
descriptors.add(new TransportDescriptor(id, p));
|
|
||||||
}
|
}
|
||||||
r.readListEnd();
|
|
||||||
}
|
}
|
||||||
r.readListEnd(); // Descriptors end
|
return new Payload(commitment, recognised);
|
||||||
r.readListEnd(); // Payload end
|
|
||||||
if (!r.eof())
|
|
||||||
throw new FormatException();
|
|
||||||
return new Payload(commitment, descriptors);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ import org.briarproject.api.event.TransportEnabledEvent;
|
|||||||
import org.briarproject.api.lifecycle.IoExecutor;
|
import org.briarproject.api.lifecycle.IoExecutor;
|
||||||
import org.briarproject.api.lifecycle.Service;
|
import org.briarproject.api.lifecycle.Service;
|
||||||
import org.briarproject.api.lifecycle.ServiceException;
|
import org.briarproject.api.lifecycle.ServiceException;
|
||||||
|
import org.briarproject.api.nullsafety.NotNullByDefault;
|
||||||
import org.briarproject.api.plugins.ConnectionManager;
|
import org.briarproject.api.plugins.ConnectionManager;
|
||||||
import org.briarproject.api.plugins.Plugin;
|
import org.briarproject.api.plugins.Plugin;
|
||||||
import org.briarproject.api.plugins.PluginCallback;
|
import org.briarproject.api.plugins.PluginCallback;
|
||||||
@@ -42,11 +43,14 @@ import java.util.concurrent.Executor;
|
|||||||
import java.util.concurrent.atomic.AtomicBoolean;
|
import java.util.concurrent.atomic.AtomicBoolean;
|
||||||
import java.util.logging.Logger;
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
|
import javax.annotation.concurrent.ThreadSafe;
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
|
|
||||||
import static java.util.logging.Level.INFO;
|
import static java.util.logging.Level.INFO;
|
||||||
import static java.util.logging.Level.WARNING;
|
import static java.util.logging.Level.WARNING;
|
||||||
|
|
||||||
|
@ThreadSafe
|
||||||
|
@NotNullByDefault
|
||||||
class PluginManagerImpl implements PluginManager, Service {
|
class PluginManagerImpl implements PluginManager, Service {
|
||||||
|
|
||||||
private static final Logger LOG =
|
private static final Logger LOG =
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package org.briarproject.plugins.file;
|
package org.briarproject.plugins.file;
|
||||||
|
|
||||||
import org.briarproject.api.contact.ContactId;
|
import org.briarproject.api.contact.ContactId;
|
||||||
|
import org.briarproject.api.nullsafety.NotNullByDefault;
|
||||||
import org.briarproject.api.plugins.TransportConnectionReader;
|
import org.briarproject.api.plugins.TransportConnectionReader;
|
||||||
import org.briarproject.api.plugins.TransportConnectionWriter;
|
import org.briarproject.api.plugins.TransportConnectionWriter;
|
||||||
import org.briarproject.api.plugins.simplex.SimplexPlugin;
|
import org.briarproject.api.plugins.simplex.SimplexPlugin;
|
||||||
@@ -17,10 +18,13 @@ import java.util.concurrent.Executor;
|
|||||||
import java.util.concurrent.atomic.AtomicBoolean;
|
import java.util.concurrent.atomic.AtomicBoolean;
|
||||||
import java.util.logging.Logger;
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
|
import javax.annotation.Nullable;
|
||||||
|
|
||||||
import static java.util.logging.Level.WARNING;
|
import static java.util.logging.Level.WARNING;
|
||||||
import static org.briarproject.api.transport.TransportConstants.MIN_STREAM_LENGTH;
|
import static org.briarproject.api.transport.TransportConstants.MIN_STREAM_LENGTH;
|
||||||
|
|
||||||
public abstract class FilePlugin implements SimplexPlugin {
|
@NotNullByDefault
|
||||||
|
abstract class FilePlugin implements SimplexPlugin {
|
||||||
|
|
||||||
private static final Logger LOG =
|
private static final Logger LOG =
|
||||||
Logger.getLogger(FilePlugin.class.getName());
|
Logger.getLogger(FilePlugin.class.getName());
|
||||||
@@ -32,6 +36,7 @@ public abstract class FilePlugin implements SimplexPlugin {
|
|||||||
|
|
||||||
protected volatile boolean running = false;
|
protected volatile boolean running = false;
|
||||||
|
|
||||||
|
@Nullable
|
||||||
protected abstract File chooseOutputDirectory();
|
protected abstract File chooseOutputDirectory();
|
||||||
protected abstract Collection<File> findFilesByName(String filename);
|
protected abstract Collection<File> findFilesByName(String filename);
|
||||||
protected abstract void writerFinished(File f);
|
protected abstract void writerFinished(File f);
|
||||||
@@ -82,6 +87,7 @@ public abstract class FilePlugin implements SimplexPlugin {
|
|||||||
return filename.toLowerCase(Locale.US).matches("[a-z]{8}\\.dat");
|
return filename.toLowerCase(Locale.US).matches("[a-z]{8}\\.dat");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
private TransportConnectionWriter createWriter(String filename) {
|
private TransportConnectionWriter createWriter(String filename) {
|
||||||
if (!running) return null;
|
if (!running) return null;
|
||||||
File dir = chooseOutputDirectory();
|
File dir = chooseOutputDirectory();
|
||||||
|
|||||||
@@ -1,10 +1,12 @@
|
|||||||
package org.briarproject.plugins.tcp;
|
package org.briarproject.plugins.tcp;
|
||||||
|
|
||||||
|
import org.briarproject.api.FormatException;
|
||||||
import org.briarproject.api.TransportId;
|
import org.briarproject.api.TransportId;
|
||||||
import org.briarproject.api.contact.ContactId;
|
import org.briarproject.api.contact.ContactId;
|
||||||
|
import org.briarproject.api.data.BdfList;
|
||||||
import org.briarproject.api.keyagreement.KeyAgreementConnection;
|
import org.briarproject.api.keyagreement.KeyAgreementConnection;
|
||||||
import org.briarproject.api.keyagreement.KeyAgreementListener;
|
import org.briarproject.api.keyagreement.KeyAgreementListener;
|
||||||
import org.briarproject.api.keyagreement.TransportDescriptor;
|
import org.briarproject.api.nullsafety.NotNullByDefault;
|
||||||
import org.briarproject.api.plugins.Backoff;
|
import org.briarproject.api.plugins.Backoff;
|
||||||
import org.briarproject.api.plugins.duplex.DuplexPluginCallback;
|
import org.briarproject.api.plugins.duplex.DuplexPluginCallback;
|
||||||
import org.briarproject.api.plugins.duplex.DuplexTransportConnection;
|
import org.briarproject.api.plugins.duplex.DuplexTransportConnection;
|
||||||
@@ -19,6 +21,7 @@ import java.net.InetSocketAddress;
|
|||||||
import java.net.ServerSocket;
|
import java.net.ServerSocket;
|
||||||
import java.net.Socket;
|
import java.net.Socket;
|
||||||
import java.net.SocketAddress;
|
import java.net.SocketAddress;
|
||||||
|
import java.net.UnknownHostException;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.LinkedList;
|
import java.util.LinkedList;
|
||||||
@@ -29,8 +32,11 @@ import java.util.logging.Logger;
|
|||||||
|
|
||||||
import static java.util.logging.Level.INFO;
|
import static java.util.logging.Level.INFO;
|
||||||
import static java.util.logging.Level.WARNING;
|
import static java.util.logging.Level.WARNING;
|
||||||
|
import static org.briarproject.api.keyagreement.KeyAgreementConstants.TRANSPORT_ID_LAN;
|
||||||
|
import static org.briarproject.util.ByteUtils.MAX_16_BIT_UNSIGNED;
|
||||||
import static org.briarproject.util.PrivacyUtils.scrubSocketAddress;
|
import static org.briarproject.util.PrivacyUtils.scrubSocketAddress;
|
||||||
|
|
||||||
|
@NotNullByDefault
|
||||||
class LanTcpPlugin extends TcpPlugin {
|
class LanTcpPlugin extends TcpPlugin {
|
||||||
|
|
||||||
static final TransportId ID = new TransportId("lan");
|
static final TransportId ID = new TransportId("lan");
|
||||||
@@ -40,7 +46,6 @@ class LanTcpPlugin extends TcpPlugin {
|
|||||||
|
|
||||||
private static final int MAX_ADDRESSES = 5;
|
private static final int MAX_ADDRESSES = 5;
|
||||||
private static final String PROP_IP_PORTS = "ipPorts";
|
private static final String PROP_IP_PORTS = "ipPorts";
|
||||||
private static final String PROP_IP_PORT = "ipPort";
|
|
||||||
private static final String SEPARATOR = ",";
|
private static final String SEPARATOR = ",";
|
||||||
|
|
||||||
LanTcpPlugin(Executor ioExecutor, Backoff backoff,
|
LanTcpPlugin(Executor ioExecutor, Backoff backoff,
|
||||||
@@ -186,23 +191,26 @@ class LanTcpPlugin extends TcpPlugin {
|
|||||||
LOG.info("Could not bind server socket for key agreement");
|
LOG.info("Could not bind server socket for key agreement");
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
TransportProperties p = new TransportProperties();
|
BdfList descriptor = new BdfList();
|
||||||
SocketAddress local = ss.getLocalSocketAddress();
|
descriptor.add(TRANSPORT_ID_LAN);
|
||||||
p.put(PROP_IP_PORT, getIpPortString((InetSocketAddress) local));
|
InetSocketAddress local =
|
||||||
TransportDescriptor d = new TransportDescriptor(ID, p);
|
(InetSocketAddress) ss.getLocalSocketAddress();
|
||||||
return new LanKeyAgreementListener(d, ss);
|
descriptor.add(local.getAddress().getAddress());
|
||||||
|
descriptor.add(local.getPort());
|
||||||
|
return new LanKeyAgreementListener(descriptor, ss);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public DuplexTransportConnection createKeyAgreementConnection(
|
public DuplexTransportConnection createKeyAgreementConnection(
|
||||||
byte[] commitment, TransportDescriptor d, long timeout) {
|
byte[] commitment, BdfList descriptor, long timeout) {
|
||||||
if (!isRunning()) return null;
|
if (!isRunning()) return null;
|
||||||
if (!ID.equals(d.getIdentifier())) return null;
|
InetSocketAddress remote;
|
||||||
TransportProperties p = d.getProperties();
|
try {
|
||||||
if (p == null) return null;
|
remote = parseSocketAddress(descriptor);
|
||||||
String ipPort = p.get(PROP_IP_PORT);
|
} catch (FormatException e) {
|
||||||
InetSocketAddress remote = parseSocketAddress(ipPort);
|
LOG.info("Invalid IP/port in key agreement descriptor");
|
||||||
if (remote == null) return null;
|
return null;
|
||||||
|
}
|
||||||
if (!isConnectable(remote)) {
|
if (!isConnectable(remote)) {
|
||||||
if (LOG.isLoggable(INFO)) {
|
if (LOG.isLoggable(INFO)) {
|
||||||
SocketAddress local = socket.getLocalSocketAddress();
|
SocketAddress local = socket.getLocalSocketAddress();
|
||||||
@@ -228,11 +236,25 @@ class LanTcpPlugin extends TcpPlugin {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private InetSocketAddress parseSocketAddress(BdfList descriptor)
|
||||||
|
throws FormatException {
|
||||||
|
byte[] address = descriptor.getRaw(1);
|
||||||
|
int port = descriptor.getLong(2).intValue();
|
||||||
|
if (port < 1 || port > MAX_16_BIT_UNSIGNED) throw new FormatException();
|
||||||
|
try {
|
||||||
|
InetAddress addr = InetAddress.getByAddress(address);
|
||||||
|
return new InetSocketAddress(addr, port);
|
||||||
|
} catch (UnknownHostException e) {
|
||||||
|
// Invalid address length
|
||||||
|
throw new FormatException();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private class LanKeyAgreementListener extends KeyAgreementListener {
|
private class LanKeyAgreementListener extends KeyAgreementListener {
|
||||||
|
|
||||||
private final ServerSocket ss;
|
private final ServerSocket ss;
|
||||||
|
|
||||||
public LanKeyAgreementListener(TransportDescriptor descriptor,
|
private LanKeyAgreementListener(BdfList descriptor,
|
||||||
ServerSocket ss) {
|
ServerSocket ss) {
|
||||||
super(descriptor);
|
super(descriptor);
|
||||||
this.ss = ss;
|
this.ss = ss;
|
||||||
|
|||||||
@@ -2,8 +2,10 @@ package org.briarproject.plugins.tcp;
|
|||||||
|
|
||||||
import org.briarproject.api.contact.ContactId;
|
import org.briarproject.api.contact.ContactId;
|
||||||
import org.briarproject.api.crypto.PseudoRandom;
|
import org.briarproject.api.crypto.PseudoRandom;
|
||||||
|
import org.briarproject.api.data.BdfList;
|
||||||
import org.briarproject.api.keyagreement.KeyAgreementListener;
|
import org.briarproject.api.keyagreement.KeyAgreementListener;
|
||||||
import org.briarproject.api.keyagreement.TransportDescriptor;
|
import org.briarproject.api.nullsafety.MethodsNotNullByDefault;
|
||||||
|
import org.briarproject.api.nullsafety.ParametersNotNullByDefault;
|
||||||
import org.briarproject.api.plugins.Backoff;
|
import org.briarproject.api.plugins.Backoff;
|
||||||
import org.briarproject.api.plugins.duplex.DuplexPlugin;
|
import org.briarproject.api.plugins.duplex.DuplexPlugin;
|
||||||
import org.briarproject.api.plugins.duplex.DuplexPluginCallback;
|
import org.briarproject.api.plugins.duplex.DuplexPluginCallback;
|
||||||
@@ -28,10 +30,14 @@ import java.util.concurrent.atomic.AtomicBoolean;
|
|||||||
import java.util.logging.Logger;
|
import java.util.logging.Logger;
|
||||||
import java.util.regex.Pattern;
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
|
import javax.annotation.Nullable;
|
||||||
|
|
||||||
import static java.util.logging.Level.INFO;
|
import static java.util.logging.Level.INFO;
|
||||||
import static java.util.logging.Level.WARNING;
|
import static java.util.logging.Level.WARNING;
|
||||||
import static org.briarproject.util.PrivacyUtils.scrubSocketAddress;
|
import static org.briarproject.util.PrivacyUtils.scrubSocketAddress;
|
||||||
|
|
||||||
|
@MethodsNotNullByDefault
|
||||||
|
@ParametersNotNullByDefault
|
||||||
abstract class TcpPlugin implements DuplexPlugin {
|
abstract class TcpPlugin implements DuplexPlugin {
|
||||||
|
|
||||||
private static final Pattern DOTTED_QUAD =
|
private static final Pattern DOTTED_QUAD =
|
||||||
@@ -141,7 +147,7 @@ abstract class TcpPlugin implements DuplexPlugin {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void tryToClose(ServerSocket ss) {
|
protected void tryToClose(@Nullable ServerSocket ss) {
|
||||||
try {
|
try {
|
||||||
if (ss != null) ss.close();
|
if (ss != null) ss.close();
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
@@ -252,6 +258,7 @@ abstract class TcpPlugin implements DuplexPlugin {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
protected InetSocketAddress parseSocketAddress(String ipPort) {
|
protected InetSocketAddress parseSocketAddress(String ipPort) {
|
||||||
if (StringUtils.isNullOrEmpty(ipPort)) return null;
|
if (StringUtils.isNullOrEmpty(ipPort)) return null;
|
||||||
String[] split = ipPort.split(":");
|
String[] split = ipPort.split(":");
|
||||||
@@ -298,7 +305,7 @@ abstract class TcpPlugin implements DuplexPlugin {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public DuplexTransportConnection createKeyAgreementConnection(
|
public DuplexTransportConnection createKeyAgreementConnection(
|
||||||
byte[] commitment, TransportDescriptor d, long timeout) {
|
byte[] commitment, BdfList descriptor, long timeout) {
|
||||||
throw new UnsupportedOperationException();
|
throw new UnsupportedOperationException();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -2,6 +2,8 @@ package org.briarproject.plugins.tcp;
|
|||||||
|
|
||||||
import org.briarproject.api.TransportId;
|
import org.briarproject.api.TransportId;
|
||||||
import org.briarproject.api.contact.ContactId;
|
import org.briarproject.api.contact.ContactId;
|
||||||
|
import org.briarproject.api.nullsafety.MethodsNotNullByDefault;
|
||||||
|
import org.briarproject.api.nullsafety.ParametersNotNullByDefault;
|
||||||
import org.briarproject.api.plugins.Backoff;
|
import org.briarproject.api.plugins.Backoff;
|
||||||
import org.briarproject.api.plugins.duplex.DuplexPluginCallback;
|
import org.briarproject.api.plugins.duplex.DuplexPluginCallback;
|
||||||
import org.briarproject.api.properties.TransportProperties;
|
import org.briarproject.api.properties.TransportProperties;
|
||||||
@@ -14,6 +16,8 @@ import java.util.LinkedList;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.concurrent.Executor;
|
import java.util.concurrent.Executor;
|
||||||
|
|
||||||
|
@MethodsNotNullByDefault
|
||||||
|
@ParametersNotNullByDefault
|
||||||
class WanTcpPlugin extends TcpPlugin {
|
class WanTcpPlugin extends TcpPlugin {
|
||||||
|
|
||||||
static final TransportId ID = new TransportId("wan");
|
static final TransportId ID = new TransportId("wan");
|
||||||
|
|||||||
@@ -1,24 +1,34 @@
|
|||||||
package org.briarproject.util;
|
package org.briarproject.util;
|
||||||
|
|
||||||
|
import org.briarproject.api.nullsafety.NotNullByDefault;
|
||||||
|
|
||||||
import java.io.UnsupportedEncodingException;
|
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;
|
||||||
import java.nio.charset.CharsetDecoder;
|
import java.nio.charset.CharsetDecoder;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
@NotNullByDefault
|
||||||
public class StringUtils {
|
public class StringUtils {
|
||||||
|
|
||||||
private static final Charset UTF_8 = Charset.forName("UTF-8");
|
private static final Charset UTF_8 = Charset.forName("UTF-8");
|
||||||
|
private static 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',
|
||||||
'8', '9', 'A', 'B', 'C', 'D', 'E', 'F'
|
'8', '9', 'A', 'B', 'C', 'D', 'E', 'F'
|
||||||
};
|
};
|
||||||
|
|
||||||
public static boolean isNullOrEmpty(String s) {
|
public static boolean isNullOrEmpty(@Nullable String s) {
|
||||||
return s == null || s.length() == 0;
|
return s == null || s.length() == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -61,7 +71,9 @@ public class StringUtils {
|
|||||||
return fromUtf8(utf8, 0, maxUtf8Length);
|
return fromUtf8(utf8, 0, maxUtf8Length);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Converts the given byte array to a hex character array. */
|
/**
|
||||||
|
* Converts the given byte array to a hex character array.
|
||||||
|
*/
|
||||||
private static char[] toHexChars(byte[] bytes) {
|
private static char[] toHexChars(byte[] bytes) {
|
||||||
char[] hex = new char[bytes.length * 2];
|
char[] hex = new char[bytes.length * 2];
|
||||||
for (int i = 0, j = 0; i < bytes.length; i++) {
|
for (int i = 0, j = 0; i < bytes.length; i++) {
|
||||||
@@ -71,12 +83,16 @@ public class StringUtils {
|
|||||||
return hex;
|
return hex;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Converts the given byte array to a hex string. */
|
/**
|
||||||
|
* Converts the given byte array to a hex string.
|
||||||
|
*/
|
||||||
public static String toHexString(byte[] bytes) {
|
public static String toHexString(byte[] bytes) {
|
||||||
return new String(toHexChars(bytes));
|
return new String(toHexChars(bytes));
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Converts the given hex string to a byte array. */
|
/**
|
||||||
|
* Converts the given hex string to a byte array.
|
||||||
|
*/
|
||||||
public static byte[] fromHexString(String hex) {
|
public static byte[] fromHexString(String hex) {
|
||||||
int len = hex.length();
|
int len = hex.length();
|
||||||
if (len % 2 != 0)
|
if (len % 2 != 0)
|
||||||
@@ -107,4 +123,20 @@ public class StringUtils {
|
|||||||
public static boolean utf8IsTooLong(String s, int maxLength) {
|
public static boolean utf8IsTooLong(String s, int maxLength) {
|
||||||
return toUtf8(s).length > maxLength;
|
return toUtf8(s).length > maxLength;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static byte[] macToBytes(String mac) {
|
||||||
|
if (!MAC.matcher(mac).matches()) throw new IllegalArgumentException();
|
||||||
|
return fromHexString(mac.replaceAll(":", ""));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String macToString(byte[] mac) {
|
||||||
|
if (mac.length != 6) throw new IllegalArgumentException();
|
||||||
|
StringBuilder s = new StringBuilder();
|
||||||
|
for (byte b : mac) {
|
||||||
|
if (s.length() > 0) s.append(':');
|
||||||
|
s.append(HEX[(b >> 4) & 0xF]);
|
||||||
|
s.append(HEX[b & 0xF]);
|
||||||
|
}
|
||||||
|
return s.toString();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,11 +1,14 @@
|
|||||||
package org.briarproject.plugins.bluetooth;
|
package org.briarproject.plugins.bluetooth;
|
||||||
|
|
||||||
|
import org.briarproject.api.FormatException;
|
||||||
import org.briarproject.api.TransportId;
|
import org.briarproject.api.TransportId;
|
||||||
import org.briarproject.api.contact.ContactId;
|
import org.briarproject.api.contact.ContactId;
|
||||||
import org.briarproject.api.crypto.PseudoRandom;
|
import org.briarproject.api.crypto.PseudoRandom;
|
||||||
|
import org.briarproject.api.data.BdfList;
|
||||||
import org.briarproject.api.keyagreement.KeyAgreementConnection;
|
import org.briarproject.api.keyagreement.KeyAgreementConnection;
|
||||||
import org.briarproject.api.keyagreement.KeyAgreementListener;
|
import org.briarproject.api.keyagreement.KeyAgreementListener;
|
||||||
import org.briarproject.api.keyagreement.TransportDescriptor;
|
import org.briarproject.api.nullsafety.MethodsNotNullByDefault;
|
||||||
|
import org.briarproject.api.nullsafety.ParametersNotNullByDefault;
|
||||||
import org.briarproject.api.plugins.Backoff;
|
import org.briarproject.api.plugins.Backoff;
|
||||||
import org.briarproject.api.plugins.duplex.DuplexPlugin;
|
import org.briarproject.api.plugins.duplex.DuplexPlugin;
|
||||||
import org.briarproject.api.plugins.duplex.DuplexPluginCallback;
|
import org.briarproject.api.plugins.duplex.DuplexPluginCallback;
|
||||||
@@ -33,6 +36,7 @@ import java.util.concurrent.Semaphore;
|
|||||||
import java.util.concurrent.atomic.AtomicBoolean;
|
import java.util.concurrent.atomic.AtomicBoolean;
|
||||||
import java.util.logging.Logger;
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
|
import javax.annotation.Nullable;
|
||||||
import javax.bluetooth.BluetoothStateException;
|
import javax.bluetooth.BluetoothStateException;
|
||||||
import javax.bluetooth.DiscoveryAgent;
|
import javax.bluetooth.DiscoveryAgent;
|
||||||
import javax.bluetooth.LocalDevice;
|
import javax.bluetooth.LocalDevice;
|
||||||
@@ -44,7 +48,10 @@ import static java.util.concurrent.TimeUnit.MILLISECONDS;
|
|||||||
import static java.util.logging.Level.INFO;
|
import static java.util.logging.Level.INFO;
|
||||||
import static java.util.logging.Level.WARNING;
|
import static java.util.logging.Level.WARNING;
|
||||||
import static javax.bluetooth.DiscoveryAgent.GIAC;
|
import static javax.bluetooth.DiscoveryAgent.GIAC;
|
||||||
|
import static org.briarproject.api.keyagreement.KeyAgreementConstants.TRANSPORT_ID_BLUETOOTH;
|
||||||
|
|
||||||
|
@MethodsNotNullByDefault
|
||||||
|
@ParametersNotNullByDefault
|
||||||
class BluetoothPlugin implements DuplexPlugin {
|
class BluetoothPlugin implements DuplexPlugin {
|
||||||
|
|
||||||
// Share an ID with the Android Bluetooth plugin
|
// Share an ID with the Android Bluetooth plugin
|
||||||
@@ -161,7 +168,7 @@ class BluetoothPlugin implements DuplexPlugin {
|
|||||||
return uuid;
|
return uuid;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void tryToClose(StreamConnectionNotifier ss) {
|
private void tryToClose(@Nullable StreamConnectionNotifier ss) {
|
||||||
try {
|
try {
|
||||||
if (ss != null) ss.close();
|
if (ss != null) ss.close();
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
@@ -330,7 +337,7 @@ class BluetoothPlugin implements DuplexPlugin {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void closeSockets(final List<Future<StreamConnection>> futures,
|
private void closeSockets(final List<Future<StreamConnection>> futures,
|
||||||
final StreamConnection chosen) {
|
@Nullable final StreamConnection chosen) {
|
||||||
ioExecutor.execute(new Runnable() {
|
ioExecutor.execute(new Runnable() {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
@@ -382,21 +389,24 @@ class BluetoothPlugin implements DuplexPlugin {
|
|||||||
tryToClose(ss);
|
tryToClose(ss);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
TransportProperties p = new TransportProperties();
|
BdfList descriptor = new BdfList();
|
||||||
p.put(PROP_ADDRESS, localDevice.getBluetoothAddress());
|
descriptor.add(TRANSPORT_ID_BLUETOOTH);
|
||||||
TransportDescriptor d = new TransportDescriptor(ID, p);
|
String address = localDevice.getBluetoothAddress();
|
||||||
return new BluetoothKeyAgreementListener(d, ss);
|
descriptor.add(StringUtils.macToBytes(address));
|
||||||
|
return new BluetoothKeyAgreementListener(descriptor, ss);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public DuplexTransportConnection createKeyAgreementConnection(
|
public DuplexTransportConnection createKeyAgreementConnection(
|
||||||
byte[] commitment, TransportDescriptor d, long timeout) {
|
byte[] commitment, BdfList descriptor, long timeout) {
|
||||||
if (!isRunning()) return null;
|
if (!isRunning()) return null;
|
||||||
if (!ID.equals(d.getIdentifier())) return null;
|
String address;
|
||||||
TransportProperties p = d.getProperties();
|
try {
|
||||||
if (p == null) return null;
|
address = parseAddress(descriptor);
|
||||||
String address = p.get(PROP_ADDRESS);
|
} catch (FormatException e) {
|
||||||
if (StringUtils.isNullOrEmpty(address)) return null;
|
LOG.info("Invalid address in key agreement descriptor");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
// No truncation necessary because COMMIT_LENGTH = 16
|
// No truncation necessary because COMMIT_LENGTH = 16
|
||||||
String uuid = UUID.nameUUIDFromBytes(commitment).toString();
|
String uuid = UUID.nameUUIDFromBytes(commitment).toString();
|
||||||
if (LOG.isLoggable(INFO))
|
if (LOG.isLoggable(INFO))
|
||||||
@@ -407,6 +417,12 @@ class BluetoothPlugin implements DuplexPlugin {
|
|||||||
return new BluetoothTransportConnection(this, s);
|
return new BluetoothTransportConnection(this, s);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private String parseAddress(BdfList descriptor) throws FormatException {
|
||||||
|
byte[] mac = descriptor.getRaw(1);
|
||||||
|
if (mac.length != 6) throw new FormatException();
|
||||||
|
return StringUtils.macToString(mac);
|
||||||
|
}
|
||||||
|
|
||||||
private void makeDeviceDiscoverable() {
|
private void makeDeviceDiscoverable() {
|
||||||
// Try to make the device discoverable (requires root on Linux)
|
// Try to make the device discoverable (requires root on Linux)
|
||||||
try {
|
try {
|
||||||
@@ -491,7 +507,7 @@ class BluetoothPlugin implements DuplexPlugin {
|
|||||||
|
|
||||||
private final StreamConnectionNotifier ss;
|
private final StreamConnectionNotifier ss;
|
||||||
|
|
||||||
BluetoothKeyAgreementListener(TransportDescriptor descriptor,
|
BluetoothKeyAgreementListener(BdfList descriptor,
|
||||||
StreamConnectionNotifier ss) {
|
StreamConnectionNotifier ss) {
|
||||||
super(descriptor);
|
super(descriptor);
|
||||||
this.ss = ss;
|
this.ss = ss;
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ package org.briarproject.plugins.file;
|
|||||||
|
|
||||||
import org.briarproject.api.TransportId;
|
import org.briarproject.api.TransportId;
|
||||||
import org.briarproject.api.contact.ContactId;
|
import org.briarproject.api.contact.ContactId;
|
||||||
|
import org.briarproject.api.nullsafety.NotNullByDefault;
|
||||||
import org.briarproject.api.plugins.simplex.SimplexPluginCallback;
|
import org.briarproject.api.plugins.simplex.SimplexPluginCallback;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
@@ -15,6 +16,7 @@ import java.util.logging.Logger;
|
|||||||
|
|
||||||
import static java.util.logging.Level.WARNING;
|
import static java.util.logging.Level.WARNING;
|
||||||
|
|
||||||
|
@NotNullByDefault
|
||||||
class RemovableDrivePlugin extends FilePlugin
|
class RemovableDrivePlugin extends FilePlugin
|
||||||
implements RemovableDriveMonitor.Callback {
|
implements RemovableDriveMonitor.Callback {
|
||||||
|
|
||||||
|
|||||||
@@ -3,8 +3,10 @@ package org.briarproject.plugins.modem;
|
|||||||
import org.briarproject.api.TransportId;
|
import org.briarproject.api.TransportId;
|
||||||
import org.briarproject.api.contact.ContactId;
|
import org.briarproject.api.contact.ContactId;
|
||||||
import org.briarproject.api.crypto.PseudoRandom;
|
import org.briarproject.api.crypto.PseudoRandom;
|
||||||
|
import org.briarproject.api.data.BdfList;
|
||||||
import org.briarproject.api.keyagreement.KeyAgreementListener;
|
import org.briarproject.api.keyagreement.KeyAgreementListener;
|
||||||
import org.briarproject.api.keyagreement.TransportDescriptor;
|
import org.briarproject.api.nullsafety.MethodsNotNullByDefault;
|
||||||
|
import org.briarproject.api.nullsafety.ParametersNotNullByDefault;
|
||||||
import org.briarproject.api.plugins.duplex.AbstractDuplexTransportConnection;
|
import org.briarproject.api.plugins.duplex.AbstractDuplexTransportConnection;
|
||||||
import org.briarproject.api.plugins.duplex.DuplexPlugin;
|
import org.briarproject.api.plugins.duplex.DuplexPlugin;
|
||||||
import org.briarproject.api.plugins.duplex.DuplexPluginCallback;
|
import org.briarproject.api.plugins.duplex.DuplexPluginCallback;
|
||||||
@@ -22,6 +24,8 @@ import java.util.logging.Logger;
|
|||||||
import static java.util.logging.Level.INFO;
|
import static java.util.logging.Level.INFO;
|
||||||
import static java.util.logging.Level.WARNING;
|
import static java.util.logging.Level.WARNING;
|
||||||
|
|
||||||
|
@MethodsNotNullByDefault
|
||||||
|
@ParametersNotNullByDefault
|
||||||
class ModemPlugin implements DuplexPlugin, Modem.Callback {
|
class ModemPlugin implements DuplexPlugin, Modem.Callback {
|
||||||
|
|
||||||
static final TransportId ID = new TransportId("modem");
|
static final TransportId ID = new TransportId("modem");
|
||||||
@@ -114,7 +118,7 @@ class ModemPlugin implements DuplexPlugin, Modem.Callback {
|
|||||||
throw new UnsupportedOperationException();
|
throw new UnsupportedOperationException();
|
||||||
}
|
}
|
||||||
|
|
||||||
boolean resetModem() {
|
private boolean resetModem() {
|
||||||
if (!running) return false;
|
if (!running) return false;
|
||||||
for (String portName : serialPortList.getPortNames()) {
|
for (String portName : serialPortList.getPortNames()) {
|
||||||
if (LOG.isLoggable(INFO))
|
if (LOG.isLoggable(INFO))
|
||||||
@@ -184,7 +188,7 @@ class ModemPlugin implements DuplexPlugin, Modem.Callback {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public DuplexTransportConnection createKeyAgreementConnection(
|
public DuplexTransportConnection createKeyAgreementConnection(
|
||||||
byte[] commitment, TransportDescriptor d, long timeout) {
|
byte[] commitment, BdfList descriptor, long timeout) {
|
||||||
throw new UnsupportedOperationException();
|
throw new UnsupportedOperationException();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -2,9 +2,9 @@ package org.briarproject.plugins.tcp;
|
|||||||
|
|
||||||
import org.briarproject.BriarTestCase;
|
import org.briarproject.BriarTestCase;
|
||||||
import org.briarproject.api.contact.ContactId;
|
import org.briarproject.api.contact.ContactId;
|
||||||
|
import org.briarproject.api.data.BdfList;
|
||||||
import org.briarproject.api.keyagreement.KeyAgreementConnection;
|
import org.briarproject.api.keyagreement.KeyAgreementConnection;
|
||||||
import org.briarproject.api.keyagreement.KeyAgreementListener;
|
import org.briarproject.api.keyagreement.KeyAgreementListener;
|
||||||
import org.briarproject.api.keyagreement.TransportDescriptor;
|
|
||||||
import org.briarproject.api.plugins.Backoff;
|
import org.briarproject.api.plugins.Backoff;
|
||||||
import org.briarproject.api.plugins.duplex.DuplexPlugin;
|
import org.briarproject.api.plugins.duplex.DuplexPlugin;
|
||||||
import org.briarproject.api.plugins.duplex.DuplexPluginCallback;
|
import org.briarproject.api.plugins.duplex.DuplexPluginCallback;
|
||||||
@@ -27,11 +27,12 @@ import java.util.concurrent.Callable;
|
|||||||
import java.util.concurrent.CountDownLatch;
|
import java.util.concurrent.CountDownLatch;
|
||||||
import java.util.concurrent.Executor;
|
import java.util.concurrent.Executor;
|
||||||
import java.util.concurrent.Executors;
|
import java.util.concurrent.Executors;
|
||||||
import java.util.concurrent.Future;
|
|
||||||
import java.util.concurrent.FutureTask;
|
import java.util.concurrent.FutureTask;
|
||||||
import java.util.concurrent.atomic.AtomicBoolean;
|
import java.util.concurrent.atomic.AtomicBoolean;
|
||||||
|
|
||||||
import static java.util.concurrent.TimeUnit.SECONDS;
|
import static java.util.concurrent.TimeUnit.SECONDS;
|
||||||
|
import static org.briarproject.api.keyagreement.KeyAgreementConstants.COMMIT_LENGTH;
|
||||||
|
import static org.briarproject.api.keyagreement.KeyAgreementConstants.TRANSPORT_ID_LAN;
|
||||||
import static org.junit.Assert.assertEquals;
|
import static org.junit.Assert.assertEquals;
|
||||||
import static org.junit.Assert.assertFalse;
|
import static org.junit.Assert.assertFalse;
|
||||||
import static org.junit.Assert.assertNotNull;
|
import static org.junit.Assert.assertNotNull;
|
||||||
@@ -188,23 +189,22 @@ public class LanTcpPluginTest extends BriarTestCase {
|
|||||||
0, 0);
|
0, 0);
|
||||||
plugin.start();
|
plugin.start();
|
||||||
assertTrue(callback.propertiesLatch.await(5, SECONDS));
|
assertTrue(callback.propertiesLatch.await(5, SECONDS));
|
||||||
KeyAgreementListener kal = plugin.createKeyAgreementListener(null);
|
KeyAgreementListener kal =
|
||||||
|
plugin.createKeyAgreementListener(new byte[COMMIT_LENGTH]);
|
||||||
|
assertNotNull(kal);
|
||||||
Callable<KeyAgreementConnection> c = kal.listen();
|
Callable<KeyAgreementConnection> c = kal.listen();
|
||||||
FutureTask<KeyAgreementConnection> f = new FutureTask<>(c);
|
FutureTask<KeyAgreementConnection> f = new FutureTask<>(c);
|
||||||
new Thread(f).start();
|
new Thread(f).start();
|
||||||
// The plugin should have bound a socket and stored the port number
|
// The plugin should have bound a socket and stored the port number
|
||||||
TransportDescriptor d = kal.getDescriptor();
|
BdfList descriptor = kal.getDescriptor();
|
||||||
TransportProperties p = d.getProperties();
|
assertEquals(3, descriptor.size());
|
||||||
String ipPort = p.get("ipPort");
|
assertEquals(TRANSPORT_ID_LAN, descriptor.getLong(0).longValue());
|
||||||
assertNotNull(ipPort);
|
byte[] address = descriptor.getRaw(1);
|
||||||
String[] split = ipPort.split(":");
|
InetAddress addr = InetAddress.getByAddress(address);
|
||||||
assertEquals(2, split.length);
|
|
||||||
String addrString = split[0], portString = split[1];
|
|
||||||
InetAddress addr = InetAddress.getByName(addrString);
|
|
||||||
assertTrue(addr instanceof Inet4Address);
|
assertTrue(addr instanceof Inet4Address);
|
||||||
assertFalse(addr.isLoopbackAddress());
|
assertFalse(addr.isLoopbackAddress());
|
||||||
assertTrue(addr.isLinkLocalAddress() || addr.isSiteLocalAddress());
|
assertTrue(addr.isLinkLocalAddress() || addr.isSiteLocalAddress());
|
||||||
int port = Integer.parseInt(portString);
|
int port = descriptor.getLong(2).intValue();
|
||||||
assertTrue(port > 0 && port < 65536);
|
assertTrue(port > 0 && port < 65536);
|
||||||
// The plugin should be listening on the port
|
// The plugin should be listening on the port
|
||||||
InetSocketAddress socketAddr = new InetSocketAddress(addr, port);
|
InetSocketAddress socketAddr = new InetSocketAddress(addr, port);
|
||||||
@@ -240,7 +240,6 @@ public class LanTcpPluginTest extends BriarTestCase {
|
|||||||
// Listen on the same interface as the plugin
|
// Listen on the same interface as the plugin
|
||||||
final ServerSocket ss = new ServerSocket();
|
final ServerSocket ss = new ServerSocket();
|
||||||
ss.bind(new InetSocketAddress(addrString, 0), 10);
|
ss.bind(new InetSocketAddress(addrString, 0), 10);
|
||||||
int port = ss.getLocalPort();
|
|
||||||
final CountDownLatch latch = new CountDownLatch(1);
|
final CountDownLatch latch = new CountDownLatch(1);
|
||||||
final AtomicBoolean error = new AtomicBoolean(false);
|
final AtomicBoolean error = new AtomicBoolean(false);
|
||||||
new Thread() {
|
new Thread() {
|
||||||
@@ -255,12 +254,15 @@ public class LanTcpPluginTest extends BriarTestCase {
|
|||||||
}
|
}
|
||||||
}.start();
|
}.start();
|
||||||
// Tell the plugin about the port
|
// Tell the plugin about the port
|
||||||
TransportProperties p = new TransportProperties();
|
BdfList descriptor = new BdfList();
|
||||||
p.put("ipPort", addrString + ":" + port);
|
descriptor.add(TRANSPORT_ID_LAN);
|
||||||
TransportDescriptor desc = new TransportDescriptor(plugin.getId(), p);
|
InetSocketAddress local =
|
||||||
|
(InetSocketAddress) ss.getLocalSocketAddress();
|
||||||
|
descriptor.add(local.getAddress().getAddress());
|
||||||
|
descriptor.add(local.getPort());
|
||||||
// Connect to the port
|
// Connect to the port
|
||||||
DuplexTransportConnection d =
|
DuplexTransportConnection d = plugin.createKeyAgreementConnection(
|
||||||
plugin.createKeyAgreementConnection(null, desc, 5000);
|
new byte[COMMIT_LENGTH], descriptor, 5000);
|
||||||
assertNotNull(d);
|
assertNotNull(d);
|
||||||
// Check that the connection was accepted
|
// Check that the connection was accepted
|
||||||
assertTrue(latch.await(5, SECONDS));
|
assertTrue(latch.await(5, SECONDS));
|
||||||
@@ -291,61 +293,76 @@ public class LanTcpPluginTest extends BriarTestCase {
|
|||||||
private final CountDownLatch connectionsLatch = new CountDownLatch(1);
|
private final CountDownLatch connectionsLatch = new CountDownLatch(1);
|
||||||
private final TransportProperties local = new TransportProperties();
|
private final TransportProperties local = new TransportProperties();
|
||||||
|
|
||||||
|
@Override
|
||||||
public Settings getSettings() {
|
public Settings getSettings() {
|
||||||
return new Settings();
|
return new Settings();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public TransportProperties getLocalProperties() {
|
public TransportProperties getLocalProperties() {
|
||||||
return local;
|
return local;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public Map<ContactId, TransportProperties> getRemoteProperties() {
|
public Map<ContactId, TransportProperties> getRemoteProperties() {
|
||||||
return remote;
|
return remote;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public void mergeSettings(Settings s) {
|
public void mergeSettings(Settings s) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public void mergeLocalProperties(TransportProperties p) {
|
public void mergeLocalProperties(TransportProperties p) {
|
||||||
local.putAll(p);
|
local.putAll(p);
|
||||||
propertiesLatch.countDown();
|
propertiesLatch.countDown();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public int showChoice(String[] options, String... message) {
|
public int showChoice(String[] options, String... message) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public boolean showConfirmationMessage(String... message) {
|
public boolean showConfirmationMessage(String... message) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public void showMessage(String... message) {
|
public void showMessage(String... message) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public void incomingConnectionCreated(DuplexTransportConnection d) {
|
public void incomingConnectionCreated(DuplexTransportConnection d) {
|
||||||
connectionsLatch.countDown();
|
connectionsLatch.countDown();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public void outgoingConnectionCreated(ContactId c,
|
public void outgoingConnectionCreated(ContactId c,
|
||||||
DuplexTransportConnection d) {
|
DuplexTransportConnection d) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public void transportEnabled() {
|
public void transportEnabled() {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public void transportDisabled() {
|
public void transportDisabled() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static class TestBackoff implements Backoff {
|
private static class TestBackoff implements Backoff {
|
||||||
|
|
||||||
|
@Override
|
||||||
public int getPollingInterval() {
|
public int getPollingInterval() {
|
||||||
return 60 * 1000;
|
return 60 * 1000;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public void increment() {
|
public void increment() {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public void reset() {
|
public void reset() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -173,4 +173,55 @@ public class StringUtilsTest extends BriarTestCase {
|
|||||||
public void testTruncateUtf8EmptyInput() {
|
public void testTruncateUtf8EmptyInput() {
|
||||||
assertEquals("", StringUtils.truncateUtf8("", 123));
|
assertEquals("", StringUtils.truncateUtf8("", 123));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test(expected = IllegalArgumentException.class)
|
||||||
|
public void testMacToBytesRejectsShortMac() {
|
||||||
|
StringUtils.macToBytes("00:00:00:00:00");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expected = IllegalArgumentException.class)
|
||||||
|
public void testMacToBytesRejectsLongMac() {
|
||||||
|
StringUtils.macToBytes("00:00:00:00:00:00:00");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expected = IllegalArgumentException.class)
|
||||||
|
public void testMacToBytesRejectsInvalidCharacter() {
|
||||||
|
StringUtils.macToBytes("00:00:00:00:00:0g");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expected = IllegalArgumentException.class)
|
||||||
|
public void testMacToBytesRejectsInvalidFormat() {
|
||||||
|
StringUtils.macToBytes("0:000:00:00:00:00");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testMacToBytesUpperCase() {
|
||||||
|
byte[] expected = new byte[] {0x0A, 0x1B, 0x2C, 0x3D, 0x4E, 0x5F};
|
||||||
|
String mac = "0A:1B:2C:3D:4E:5F";
|
||||||
|
assertArrayEquals(expected, StringUtils.macToBytes(mac));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testMacToBytesLowerCase() {
|
||||||
|
byte[] expected = new byte[] {0x0A, 0x1B, 0x2C, 0x3D, 0x4E, 0x5F};
|
||||||
|
String mac = "0a:1b:2c:3d:4e:5f";
|
||||||
|
assertArrayEquals(expected, StringUtils.macToBytes(mac));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expected = IllegalArgumentException.class)
|
||||||
|
public void testMacToStringRejectsShortMac() {
|
||||||
|
StringUtils.macToString(new byte[5]);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expected = IllegalArgumentException.class)
|
||||||
|
public void testMacToStringRejectsLongMac() {
|
||||||
|
StringUtils.macToString(new byte[7]);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testMacToString() {
|
||||||
|
byte[] mac = new byte[] {0x0a, 0x1b, 0x2c, 0x3d, 0x4e, 0x5f};
|
||||||
|
String expected = "0A:1B:2C:3D:4E:5F";
|
||||||
|
assertEquals(expected, StringUtils.macToString(mac));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user