mirror of
https://code.briarproject.org/briar/briar.git
synced 2026-02-11 18:29:05 +01:00
Encode transport properties more compactly in QR codes.
This commit is contained in:
@@ -11,12 +11,13 @@ import android.content.IntentFilter;
|
||||
|
||||
import org.briarproject.android.api.AndroidExecutor;
|
||||
import org.briarproject.android.util.AndroidUtils;
|
||||
import org.briarproject.api.FormatException;
|
||||
import org.briarproject.api.TransportId;
|
||||
import org.briarproject.api.contact.ContactId;
|
||||
import org.briarproject.api.crypto.PseudoRandom;
|
||||
import org.briarproject.api.data.BdfList;
|
||||
import org.briarproject.api.keyagreement.KeyAgreementConnection;
|
||||
import org.briarproject.api.keyagreement.KeyAgreementListener;
|
||||
import org.briarproject.api.keyagreement.TransportDescriptor;
|
||||
import org.briarproject.api.plugins.Backoff;
|
||||
import org.briarproject.api.plugins.duplex.DuplexPlugin;
|
||||
import org.briarproject.api.plugins.duplex.DuplexPluginCallback;
|
||||
@@ -44,6 +45,8 @@ import java.util.concurrent.Future;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import static android.bluetooth.BluetoothAdapter.ACTION_SCAN_MODE_CHANGED;
|
||||
import static android.bluetooth.BluetoothAdapter.ACTION_STATE_CHANGED;
|
||||
import static android.bluetooth.BluetoothAdapter.EXTRA_SCAN_MODE;
|
||||
@@ -57,6 +60,7 @@ import static android.bluetooth.BluetoothDevice.EXTRA_DEVICE;
|
||||
import static java.util.concurrent.TimeUnit.MILLISECONDS;
|
||||
import static java.util.logging.Level.INFO;
|
||||
import static java.util.logging.Level.WARNING;
|
||||
import static org.briarproject.api.keyagreement.KeyAgreementConstants.TRANSPORT_ID_BLUETOOTH;
|
||||
import static org.briarproject.util.PrivacyUtils.scrubMacAddress;
|
||||
|
||||
class DroidtoothPlugin implements DuplexPlugin {
|
||||
@@ -466,23 +470,25 @@ class DroidtoothPlugin implements DuplexPlugin {
|
||||
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
||||
return null;
|
||||
}
|
||||
TransportProperties p = new TransportProperties();
|
||||
BdfList descriptor = new BdfList();
|
||||
descriptor.add(TRANSPORT_ID_BLUETOOTH);
|
||||
String address = AndroidUtils.getBluetoothAddress(appContext, adapter);
|
||||
if (!StringUtils.isNullOrEmpty(address))
|
||||
p.put(PROP_ADDRESS, address);
|
||||
TransportDescriptor d = new TransportDescriptor(ID, p);
|
||||
return new BluetoothKeyAgreementListener(d, ss);
|
||||
if (!address.isEmpty()) descriptor.add(StringUtils.macToBytes(address));
|
||||
return new BluetoothKeyAgreementListener(descriptor, ss);
|
||||
}
|
||||
|
||||
@Override
|
||||
public DuplexTransportConnection createKeyAgreementConnection(
|
||||
byte[] commitment, TransportDescriptor d, long timeout) {
|
||||
byte[] commitment, BdfList descriptor, long timeout) {
|
||||
if (!isRunning()) return null;
|
||||
if (!ID.equals(d.getIdentifier())) return null;
|
||||
TransportProperties p = d.getProperties();
|
||||
if (p == null) return null;
|
||||
String address = p.get(PROP_ADDRESS);
|
||||
if (StringUtils.isNullOrEmpty(address)) return null;
|
||||
String address;
|
||||
try {
|
||||
address = parseAddress(descriptor);
|
||||
} catch (FormatException e) {
|
||||
LOG.info("Invalid address in key agreement descriptor");
|
||||
return null;
|
||||
}
|
||||
if (address == null) return null;
|
||||
// No truncation necessary because COMMIT_LENGTH = 16
|
||||
UUID uuid = UUID.nameUUIDFromBytes(commitment);
|
||||
if (LOG.isLoggable(INFO))
|
||||
@@ -492,6 +498,14 @@ class DroidtoothPlugin implements DuplexPlugin {
|
||||
return new DroidtoothTransportConnection(this, s);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private String parseAddress(BdfList descriptor) throws FormatException {
|
||||
if (descriptor.size() < 2) return null;
|
||||
byte[] mac = descriptor.getRaw(1);
|
||||
if (mac.length != 6) throw new FormatException();
|
||||
return StringUtils.macToString(mac);
|
||||
}
|
||||
|
||||
private class BluetoothStateReceiver extends BroadcastReceiver {
|
||||
|
||||
@Override
|
||||
@@ -626,7 +640,7 @@ class DroidtoothPlugin implements DuplexPlugin {
|
||||
|
||||
private final BluetoothServerSocket ss;
|
||||
|
||||
BluetoothKeyAgreementListener(TransportDescriptor descriptor,
|
||||
BluetoothKeyAgreementListener(BdfList descriptor,
|
||||
BluetoothServerSocket ss) {
|
||||
super(descriptor);
|
||||
this.ss = ss;
|
||||
|
||||
@@ -19,11 +19,11 @@ import org.briarproject.android.util.AndroidUtils;
|
||||
import org.briarproject.api.TransportId;
|
||||
import org.briarproject.api.contact.ContactId;
|
||||
import org.briarproject.api.crypto.PseudoRandom;
|
||||
import org.briarproject.api.data.BdfList;
|
||||
import org.briarproject.api.event.Event;
|
||||
import org.briarproject.api.event.EventListener;
|
||||
import org.briarproject.api.event.SettingsUpdatedEvent;
|
||||
import org.briarproject.api.keyagreement.KeyAgreementListener;
|
||||
import org.briarproject.api.keyagreement.TransportDescriptor;
|
||||
import org.briarproject.api.plugins.Backoff;
|
||||
import org.briarproject.api.plugins.TorConstants;
|
||||
import org.briarproject.api.plugins.duplex.DuplexPlugin;
|
||||
@@ -574,7 +574,7 @@ class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
|
||||
|
||||
@Override
|
||||
public DuplexTransportConnection createKeyAgreementConnection(
|
||||
byte[] commitment, TransportDescriptor d, long timeout) {
|
||||
byte[] commitment, BdfList descriptor, long timeout) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@ package org.briarproject.api.keyagreement;
|
||||
public interface KeyAgreementConstants {
|
||||
|
||||
/** The current version of the BQP protocol. */
|
||||
byte PROTOCOL_VERSION = 1;
|
||||
byte PROTOCOL_VERSION = 2;
|
||||
|
||||
/** The length of the record header in bytes. */
|
||||
int RECORD_HEADER_LENGTH = 4;
|
||||
@@ -16,4 +16,10 @@ public interface KeyAgreementConstants {
|
||||
int COMMIT_LENGTH = 16;
|
||||
|
||||
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;
|
||||
|
||||
import org.briarproject.api.data.BdfList;
|
||||
|
||||
import java.util.concurrent.Callable;
|
||||
|
||||
/**
|
||||
@@ -7,9 +9,9 @@ import java.util.concurrent.Callable;
|
||||
*/
|
||||
public abstract class KeyAgreementListener {
|
||||
|
||||
private final TransportDescriptor descriptor;
|
||||
private final BdfList descriptor;
|
||||
|
||||
public KeyAgreementListener(TransportDescriptor descriptor) {
|
||||
public KeyAgreementListener(BdfList 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
|
||||
* listener.
|
||||
*/
|
||||
public TransportDescriptor getDescriptor() {
|
||||
public BdfList getDescriptor() {
|
||||
return descriptor;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,29 +1,40 @@
|
||||
package org.briarproject.api.keyagreement;
|
||||
|
||||
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.
|
||||
*/
|
||||
@Immutable
|
||||
@NotNullByDefault
|
||||
public class Payload implements Comparable<Payload> {
|
||||
|
||||
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.descriptors = descriptors;
|
||||
}
|
||||
|
||||
/** Returns the commitment contained in this payload. */
|
||||
/**
|
||||
* Returns the commitment contained in this payload.
|
||||
*/
|
||||
public byte[] getCommitment() {
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,10 @@
|
||||
package org.briarproject.api.keyagreement;
|
||||
|
||||
import org.briarproject.api.nullsafety.NotNullByDefault;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
@NotNullByDefault
|
||||
public interface PayloadParser {
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
@@ -1,21 +1,26 @@
|
||||
package org.briarproject.api.plugins;
|
||||
|
||||
import org.briarproject.api.TransportId;
|
||||
import org.briarproject.api.nullsafety.NotNullByDefault;
|
||||
import org.briarproject.api.plugins.duplex.DuplexPlugin;
|
||||
import org.briarproject.api.plugins.simplex.SimplexPlugin;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
/**
|
||||
* Responsible for starting transport plugins at startup and stopping them at
|
||||
* shutdown.
|
||||
*/
|
||||
@NotNullByDefault
|
||||
public interface PluginManager {
|
||||
|
||||
/**
|
||||
* Returns the plugin for the given transport, or null if no such plugin
|
||||
* has been created.
|
||||
*/
|
||||
@Nullable
|
||||
Plugin getPlugin(TransportId t);
|
||||
|
||||
/**
|
||||
|
||||
@@ -2,8 +2,8 @@ package org.briarproject.api.plugins.duplex;
|
||||
|
||||
import org.briarproject.api.contact.ContactId;
|
||||
import org.briarproject.api.crypto.PseudoRandom;
|
||||
import org.briarproject.api.data.BdfList;
|
||||
import org.briarproject.api.keyagreement.KeyAgreementListener;
|
||||
import org.briarproject.api.keyagreement.TransportDescriptor;
|
||||
import org.briarproject.api.plugins.Plugin;
|
||||
|
||||
/** An interface for transport plugins that support duplex communication. */
|
||||
@@ -40,5 +40,5 @@ public interface DuplexPlugin extends Plugin {
|
||||
* Returns null if no connection can be established within the given time.
|
||||
*/
|
||||
DuplexTransportConnection createKeyAgreementConnection(
|
||||
byte[] remoteCommitment, TransportDescriptor d, long timeout);
|
||||
byte[] remoteCommitment, BdfList descriptor, long timeout);
|
||||
}
|
||||
|
||||
@@ -1,11 +1,13 @@
|
||||
package org.briarproject.keyagreement;
|
||||
|
||||
import org.briarproject.api.TransportId;
|
||||
import org.briarproject.api.crypto.CryptoComponent;
|
||||
import org.briarproject.api.crypto.KeyPair;
|
||||
import org.briarproject.api.data.BdfList;
|
||||
import org.briarproject.api.keyagreement.KeyAgreementConnection;
|
||||
import org.briarproject.api.keyagreement.KeyAgreementListener;
|
||||
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.duplex.DuplexPlugin;
|
||||
import org.briarproject.api.plugins.duplex.DuplexTransportConnection;
|
||||
@@ -14,7 +16,10 @@ import org.briarproject.api.system.Clock;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.concurrent.CompletionService;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
@@ -68,14 +73,13 @@ class KeyAgreementConnector {
|
||||
byte[] commitment = crypto.deriveKeyCommitment(
|
||||
localKeyPair.getPublic().getEncoded());
|
||||
// Start all listeners and collect their descriptors
|
||||
List<TransportDescriptor> descriptors =
|
||||
new ArrayList<TransportDescriptor>();
|
||||
Map<TransportId, BdfList> descriptors =
|
||||
new HashMap<TransportId, BdfList>();
|
||||
for (DuplexPlugin plugin : pluginManager.getKeyAgreementPlugins()) {
|
||||
KeyAgreementListener l = plugin.createKeyAgreementListener(
|
||||
commitment);
|
||||
KeyAgreementListener l =
|
||||
plugin.createKeyAgreementListener(commitment);
|
||||
if (l != null) {
|
||||
TransportDescriptor d = l.getDescriptor();
|
||||
descriptors.add(d);
|
||||
descriptors.put(plugin.getId(), l.getDescriptor());
|
||||
pending.add(connect.submit(new ReadableTask(l.listen())));
|
||||
listeners.add(l);
|
||||
}
|
||||
@@ -100,13 +104,16 @@ class KeyAgreementConnector {
|
||||
|
||||
// Start connecting over supported transports
|
||||
LOG.info("Starting outgoing BQP connections");
|
||||
for (TransportDescriptor d : remotePayload.getTransportDescriptors()) {
|
||||
DuplexPlugin plugin = (DuplexPlugin) pluginManager.getPlugin(
|
||||
d.getIdentifier());
|
||||
if (plugin != null)
|
||||
Map<TransportId, BdfList> descriptors =
|
||||
remotePayload.getTransportDescriptors();
|
||||
for (Entry<TransportId, BdfList> e : descriptors.entrySet()) {
|
||||
Plugin p = pluginManager.getPlugin(e.getKey());
|
||||
if (p instanceof DuplexPlugin) {
|
||||
DuplexPlugin plugin = (DuplexPlugin) p;
|
||||
pending.add(connect.submit(new ReadableTask(
|
||||
new ConnectorTask(plugin, remotePayload.getCommitment(),
|
||||
d, end))));
|
||||
e.getValue(), end))));
|
||||
}
|
||||
}
|
||||
|
||||
// Get chosen connection
|
||||
@@ -170,12 +177,12 @@ class KeyAgreementConnector {
|
||||
private class ConnectorTask implements Callable<KeyAgreementConnection> {
|
||||
|
||||
private final byte[] commitment;
|
||||
private final TransportDescriptor descriptor;
|
||||
private final BdfList descriptor;
|
||||
private final long end;
|
||||
private final DuplexPlugin plugin;
|
||||
|
||||
private ConnectorTask(DuplexPlugin plugin, byte[] commitment,
|
||||
TransportDescriptor descriptor, long end) {
|
||||
BdfList descriptor, long end) {
|
||||
this.plugin = plugin;
|
||||
this.commitment = commitment;
|
||||
this.descriptor = descriptor;
|
||||
|
||||
@@ -1,24 +1,30 @@
|
||||
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.BdfWriterFactory;
|
||||
import org.briarproject.api.keyagreement.Payload;
|
||||
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.IOException;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.annotation.concurrent.Immutable;
|
||||
import javax.inject.Inject;
|
||||
|
||||
import static org.briarproject.api.keyagreement.KeyAgreementConstants.PROTOCOL_VERSION;
|
||||
|
||||
@Immutable
|
||||
@NotNullByDefault
|
||||
class PayloadEncoderImpl implements PayloadEncoder {
|
||||
|
||||
private final BdfWriterFactory bdfWriterFactory;
|
||||
|
||||
@Inject
|
||||
public PayloadEncoderImpl(BdfWriterFactory bdfWriterFactory) {
|
||||
PayloadEncoderImpl(BdfWriterFactory bdfWriterFactory) {
|
||||
this.bdfWriterFactory = bdfWriterFactory;
|
||||
}
|
||||
|
||||
@@ -30,18 +36,13 @@ class PayloadEncoderImpl implements PayloadEncoder {
|
||||
w.writeListStart(); // Payload start
|
||||
w.writeLong(PROTOCOL_VERSION);
|
||||
w.writeRaw(p.getCommitment());
|
||||
w.writeListStart(); // Descriptors start
|
||||
for (TransportDescriptor d : p.getTransportDescriptors()) {
|
||||
w.writeListStart();
|
||||
w.writeString(d.getIdentifier().getString());
|
||||
w.writeDictionary(d.getProperties());
|
||||
w.writeListEnd();
|
||||
}
|
||||
w.writeListEnd(); // Descriptors end
|
||||
Map<TransportId, BdfList> descriptors = p.getTransportDescriptors();
|
||||
for (BdfList descriptor : descriptors.values())
|
||||
w.writeList(descriptor);
|
||||
w.writeListEnd(); // Payload end
|
||||
} catch (IOException e) {
|
||||
// Shouldn't happen with ByteArrayOutputStream
|
||||
throw new RuntimeException(e);
|
||||
throw new AssertionError(e);
|
||||
}
|
||||
return out.toByteArray();
|
||||
}
|
||||
|
||||
@@ -2,30 +2,34 @@ package org.briarproject.keyagreement;
|
||||
|
||||
import org.briarproject.api.FormatException;
|
||||
import org.briarproject.api.TransportId;
|
||||
import org.briarproject.api.data.BdfList;
|
||||
import org.briarproject.api.data.BdfReader;
|
||||
import org.briarproject.api.data.BdfReaderFactory;
|
||||
import org.briarproject.api.keyagreement.Payload;
|
||||
import org.briarproject.api.keyagreement.PayloadParser;
|
||||
import org.briarproject.api.keyagreement.TransportDescriptor;
|
||||
import org.briarproject.api.properties.TransportProperties;
|
||||
import org.briarproject.api.nullsafety.NotNullByDefault;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.annotation.concurrent.Immutable;
|
||||
import javax.inject.Inject;
|
||||
|
||||
import static org.briarproject.api.keyagreement.KeyAgreementConstants.COMMIT_LENGTH;
|
||||
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 {
|
||||
|
||||
private final BdfReaderFactory bdfReaderFactory;
|
||||
|
||||
@Inject
|
||||
public PayloadParserImpl(BdfReaderFactory bdfReaderFactory) {
|
||||
PayloadParserImpl(BdfReaderFactory bdfReaderFactory) {
|
||||
this.bdfReaderFactory = bdfReaderFactory;
|
||||
}
|
||||
|
||||
@@ -33,36 +37,28 @@ class PayloadParserImpl implements PayloadParser {
|
||||
public Payload parse(byte[] raw) throws IOException {
|
||||
ByteArrayInputStream in = new ByteArrayInputStream(raw);
|
||||
BdfReader r = bdfReaderFactory.createReader(in);
|
||||
r.readListStart(); // Payload start
|
||||
int proto = (int) r.readLong();
|
||||
if (proto != PROTOCOL_VERSION)
|
||||
throw new FormatException();
|
||||
byte[] commitment = r.readRaw(COMMIT_LENGTH);
|
||||
if (commitment.length != COMMIT_LENGTH)
|
||||
throw new FormatException();
|
||||
List<TransportDescriptor> descriptors = new ArrayList<TransportDescriptor>();
|
||||
r.readListStart(); // Descriptors start
|
||||
while (r.hasList()) {
|
||||
r.readListStart();
|
||||
while (!r.hasListEnd()) {
|
||||
TransportId id =
|
||||
new TransportId(r.readString(MAX_PROPERTY_LENGTH));
|
||||
TransportProperties p = new TransportProperties();
|
||||
r.readDictionaryStart();
|
||||
while (!r.hasDictionaryEnd()) {
|
||||
String key = r.readString(MAX_PROPERTY_LENGTH);
|
||||
String value = r.readString(MAX_PROPERTY_LENGTH);
|
||||
p.put(key, value);
|
||||
}
|
||||
r.readDictionaryEnd();
|
||||
descriptors.add(new TransportDescriptor(id, p));
|
||||
// The payload is a BDF list with two or more elements
|
||||
BdfList payload = r.readList();
|
||||
if (payload.size() < 2) throw new FormatException();
|
||||
if (!r.eof()) throw new FormatException();
|
||||
// First element: the protocol version
|
||||
long protocolVersion = payload.getLong(0);
|
||||
if (protocolVersion != PROTOCOL_VERSION) throw new FormatException();
|
||||
// Second element: the public key commitment
|
||||
byte[] commitment = payload.getRaw(1);
|
||||
if (commitment.length != COMMIT_LENGTH) throw new FormatException();
|
||||
// Remaining elements: transport descriptors
|
||||
Map<TransportId, BdfList> recognised =
|
||||
new HashMap<TransportId, BdfList>();
|
||||
for (int i = 2; i < payload.size(); i++) {
|
||||
BdfList descriptor = payload.getList(i);
|
||||
long transportId = descriptor.getLong(0);
|
||||
if (transportId == TRANSPORT_ID_BLUETOOTH) {
|
||||
recognised.put(new TransportId("bt"), descriptor);
|
||||
} else if (transportId == TRANSPORT_ID_LAN) {
|
||||
recognised.put(new TransportId("lan"), descriptor);
|
||||
}
|
||||
r.readListEnd();
|
||||
}
|
||||
r.readListEnd(); // Descriptors end
|
||||
r.readListEnd(); // Payload end
|
||||
if (!r.eof())
|
||||
throw new FormatException();
|
||||
return new Payload(commitment, descriptors);
|
||||
return new Payload(commitment, recognised);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,6 +9,7 @@ import org.briarproject.api.event.TransportEnabledEvent;
|
||||
import org.briarproject.api.lifecycle.IoExecutor;
|
||||
import org.briarproject.api.lifecycle.Service;
|
||||
import org.briarproject.api.lifecycle.ServiceException;
|
||||
import org.briarproject.api.nullsafety.NotNullByDefault;
|
||||
import org.briarproject.api.plugins.ConnectionManager;
|
||||
import org.briarproject.api.plugins.Plugin;
|
||||
import org.briarproject.api.plugins.PluginCallback;
|
||||
@@ -42,11 +43,14 @@ import java.util.concurrent.Executor;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import javax.annotation.concurrent.ThreadSafe;
|
||||
import javax.inject.Inject;
|
||||
|
||||
import static java.util.logging.Level.INFO;
|
||||
import static java.util.logging.Level.WARNING;
|
||||
|
||||
@ThreadSafe
|
||||
@NotNullByDefault
|
||||
class PluginManagerImpl implements PluginManager, Service {
|
||||
|
||||
private static final Logger LOG =
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
package org.briarproject.plugins.tcp;
|
||||
|
||||
import org.briarproject.api.FormatException;
|
||||
import org.briarproject.api.TransportId;
|
||||
import org.briarproject.api.contact.ContactId;
|
||||
import org.briarproject.api.data.BdfList;
|
||||
import org.briarproject.api.keyagreement.KeyAgreementConnection;
|
||||
import org.briarproject.api.keyagreement.KeyAgreementListener;
|
||||
import org.briarproject.api.keyagreement.TransportDescriptor;
|
||||
import org.briarproject.api.plugins.Backoff;
|
||||
import org.briarproject.api.plugins.duplex.DuplexPluginCallback;
|
||||
import org.briarproject.api.plugins.duplex.DuplexTransportConnection;
|
||||
@@ -19,6 +20,7 @@ import java.net.InetSocketAddress;
|
||||
import java.net.ServerSocket;
|
||||
import java.net.Socket;
|
||||
import java.net.SocketAddress;
|
||||
import java.net.UnknownHostException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.LinkedList;
|
||||
@@ -27,8 +29,12 @@ import java.util.concurrent.Callable;
|
||||
import java.util.concurrent.Executor;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import static java.util.logging.Level.INFO;
|
||||
import static java.util.logging.Level.WARNING;
|
||||
import static org.briarproject.api.keyagreement.KeyAgreementConstants.TRANSPORT_ID_LAN;
|
||||
import static org.briarproject.util.ByteUtils.MAX_16_BIT_UNSIGNED;
|
||||
import static org.briarproject.util.PrivacyUtils.scrubSocketAddress;
|
||||
|
||||
class LanTcpPlugin extends TcpPlugin {
|
||||
@@ -40,7 +46,6 @@ class LanTcpPlugin extends TcpPlugin {
|
||||
|
||||
private static final int MAX_ADDRESSES = 5;
|
||||
private static final String PROP_IP_PORTS = "ipPorts";
|
||||
private static final String PROP_IP_PORT = "ipPort";
|
||||
private static final String SEPARATOR = ",";
|
||||
|
||||
LanTcpPlugin(Executor ioExecutor, Backoff backoff,
|
||||
@@ -186,22 +191,26 @@ class LanTcpPlugin extends TcpPlugin {
|
||||
LOG.info("Could not bind server socket for key agreement");
|
||||
return null;
|
||||
}
|
||||
TransportProperties p = new TransportProperties();
|
||||
SocketAddress local = ss.getLocalSocketAddress();
|
||||
p.put(PROP_IP_PORT, getIpPortString((InetSocketAddress) local));
|
||||
TransportDescriptor d = new TransportDescriptor(ID, p);
|
||||
return new LanKeyAgreementListener(d, ss);
|
||||
BdfList descriptor = new BdfList();
|
||||
descriptor.add(TRANSPORT_ID_LAN);
|
||||
InetSocketAddress local =
|
||||
(InetSocketAddress) ss.getLocalSocketAddress();
|
||||
descriptor.add(local.getAddress().getAddress());
|
||||
descriptor.add(local.getPort());
|
||||
return new LanKeyAgreementListener(descriptor, ss);
|
||||
}
|
||||
|
||||
@Override
|
||||
public DuplexTransportConnection createKeyAgreementConnection(
|
||||
byte[] commitment, TransportDescriptor d, long timeout) {
|
||||
byte[] commitment, BdfList descriptor, long timeout) {
|
||||
if (!isRunning()) return null;
|
||||
if (!ID.equals(d.getIdentifier())) return null;
|
||||
TransportProperties p = d.getProperties();
|
||||
if (p == null) return null;
|
||||
String ipPort = p.get(PROP_IP_PORT);
|
||||
InetSocketAddress remote = parseSocketAddress(ipPort);
|
||||
InetSocketAddress remote;
|
||||
try {
|
||||
remote = parseSocketAddress(descriptor);
|
||||
} catch (FormatException e) {
|
||||
LOG.info("Invalid IP/port in key agreement descriptor");
|
||||
return null;
|
||||
}
|
||||
if (remote == null) return null;
|
||||
if (!isConnectable(remote)) {
|
||||
if (LOG.isLoggable(INFO)) {
|
||||
@@ -228,11 +237,27 @@ class LanTcpPlugin extends TcpPlugin {
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private InetSocketAddress parseSocketAddress(BdfList descriptor)
|
||||
throws FormatException {
|
||||
if (descriptor.size() < 3) return null;
|
||||
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 final ServerSocket ss;
|
||||
|
||||
public LanKeyAgreementListener(TransportDescriptor descriptor,
|
||||
private LanKeyAgreementListener(BdfList descriptor,
|
||||
ServerSocket ss) {
|
||||
super(descriptor);
|
||||
this.ss = ss;
|
||||
|
||||
@@ -2,8 +2,8 @@ package org.briarproject.plugins.tcp;
|
||||
|
||||
import org.briarproject.api.contact.ContactId;
|
||||
import org.briarproject.api.crypto.PseudoRandom;
|
||||
import org.briarproject.api.data.BdfList;
|
||||
import org.briarproject.api.keyagreement.KeyAgreementListener;
|
||||
import org.briarproject.api.keyagreement.TransportDescriptor;
|
||||
import org.briarproject.api.plugins.Backoff;
|
||||
import org.briarproject.api.plugins.duplex.DuplexPlugin;
|
||||
import org.briarproject.api.plugins.duplex.DuplexPluginCallback;
|
||||
@@ -298,7 +298,7 @@ abstract class TcpPlugin implements DuplexPlugin {
|
||||
|
||||
@Override
|
||||
public DuplexTransportConnection createKeyAgreementConnection(
|
||||
byte[] commitment, TransportDescriptor d, long timeout) {
|
||||
byte[] commitment, BdfList descriptor, long timeout) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
|
||||
@@ -1,24 +1,34 @@
|
||||
package org.briarproject.util;
|
||||
|
||||
import org.briarproject.api.nullsafety.NotNullByDefault;
|
||||
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.charset.CharacterCodingException;
|
||||
import java.nio.charset.Charset;
|
||||
import java.nio.charset.CharsetDecoder;
|
||||
import java.util.Collection;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import static java.nio.charset.CodingErrorAction.IGNORE;
|
||||
import static java.util.regex.Pattern.CASE_INSENSITIVE;
|
||||
|
||||
@NotNullByDefault
|
||||
public class StringUtils {
|
||||
|
||||
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[] {
|
||||
'0', '1', '2', '3', '4', '5', '6', '7',
|
||||
'8', '9', 'A', 'B', 'C', 'D', 'E', 'F'
|
||||
'0', '1', '2', '3', '4', '5', '6', '7',
|
||||
'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;
|
||||
}
|
||||
|
||||
@@ -61,7 +71,9 @@ public class StringUtils {
|
||||
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) {
|
||||
char[] hex = new char[bytes.length * 2];
|
||||
for (int i = 0, j = 0; i < bytes.length; i++) {
|
||||
@@ -71,12 +83,16 @@ public class StringUtils {
|
||||
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) {
|
||||
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) {
|
||||
int len = hex.length();
|
||||
if (len % 2 != 0)
|
||||
@@ -107,4 +123,20 @@ public class StringUtils {
|
||||
public static boolean utf8IsTooLong(String s, int 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,12 @@
|
||||
package org.briarproject.plugins.bluetooth;
|
||||
|
||||
import org.briarproject.api.FormatException;
|
||||
import org.briarproject.api.TransportId;
|
||||
import org.briarproject.api.contact.ContactId;
|
||||
import org.briarproject.api.crypto.PseudoRandom;
|
||||
import org.briarproject.api.data.BdfList;
|
||||
import org.briarproject.api.keyagreement.KeyAgreementConnection;
|
||||
import org.briarproject.api.keyagreement.KeyAgreementListener;
|
||||
import org.briarproject.api.keyagreement.TransportDescriptor;
|
||||
import org.briarproject.api.plugins.Backoff;
|
||||
import org.briarproject.api.plugins.duplex.DuplexPlugin;
|
||||
import org.briarproject.api.plugins.duplex.DuplexPluginCallback;
|
||||
@@ -33,6 +34,7 @@ import java.util.concurrent.Semaphore;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import javax.bluetooth.BluetoothStateException;
|
||||
import javax.bluetooth.DiscoveryAgent;
|
||||
import javax.bluetooth.LocalDevice;
|
||||
@@ -44,6 +46,7 @@ import static java.util.concurrent.TimeUnit.MILLISECONDS;
|
||||
import static java.util.logging.Level.INFO;
|
||||
import static java.util.logging.Level.WARNING;
|
||||
import static javax.bluetooth.DiscoveryAgent.GIAC;
|
||||
import static org.briarproject.api.keyagreement.KeyAgreementConstants.TRANSPORT_ID_BLUETOOTH;
|
||||
|
||||
class BluetoothPlugin implements DuplexPlugin {
|
||||
|
||||
@@ -382,21 +385,25 @@ class BluetoothPlugin implements DuplexPlugin {
|
||||
tryToClose(ss);
|
||||
return null;
|
||||
}
|
||||
TransportProperties p = new TransportProperties();
|
||||
p.put(PROP_ADDRESS, localDevice.getBluetoothAddress());
|
||||
TransportDescriptor d = new TransportDescriptor(ID, p);
|
||||
return new BluetoothKeyAgreementListener(d, ss);
|
||||
BdfList descriptor = new BdfList();
|
||||
descriptor.add(TRANSPORT_ID_BLUETOOTH);
|
||||
String address = localDevice.getBluetoothAddress();
|
||||
if (!address.isEmpty()) descriptor.add(StringUtils.macToBytes(address));
|
||||
return new BluetoothKeyAgreementListener(descriptor, ss);
|
||||
}
|
||||
|
||||
@Override
|
||||
public DuplexTransportConnection createKeyAgreementConnection(
|
||||
byte[] commitment, TransportDescriptor d, long timeout) {
|
||||
byte[] commitment, BdfList descriptor, long timeout) {
|
||||
if (!isRunning()) return null;
|
||||
if (!ID.equals(d.getIdentifier())) return null;
|
||||
TransportProperties p = d.getProperties();
|
||||
if (p == null) return null;
|
||||
String address = p.get(PROP_ADDRESS);
|
||||
if (StringUtils.isNullOrEmpty(address)) return null;
|
||||
String address;
|
||||
try {
|
||||
address = parseAddress(descriptor);
|
||||
} catch (FormatException e) {
|
||||
LOG.info("Invalid address in key agreement descriptor");
|
||||
return null;
|
||||
}
|
||||
if (address == null) return null;
|
||||
// No truncation necessary because COMMIT_LENGTH = 16
|
||||
String uuid = UUID.nameUUIDFromBytes(commitment).toString();
|
||||
if (LOG.isLoggable(INFO))
|
||||
@@ -407,6 +414,14 @@ class BluetoothPlugin implements DuplexPlugin {
|
||||
return new BluetoothTransportConnection(this, s);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private String parseAddress(BdfList descriptor) throws FormatException {
|
||||
if (descriptor.size() < 2) return null;
|
||||
byte[] mac = descriptor.getRaw(1);
|
||||
if (mac.length != 6) throw new FormatException();
|
||||
return StringUtils.macToString(mac);
|
||||
}
|
||||
|
||||
private void makeDeviceDiscoverable() {
|
||||
// Try to make the device discoverable (requires root on Linux)
|
||||
try {
|
||||
@@ -491,7 +506,7 @@ class BluetoothPlugin implements DuplexPlugin {
|
||||
|
||||
private final StreamConnectionNotifier ss;
|
||||
|
||||
BluetoothKeyAgreementListener(TransportDescriptor descriptor,
|
||||
BluetoothKeyAgreementListener(BdfList descriptor,
|
||||
StreamConnectionNotifier ss) {
|
||||
super(descriptor);
|
||||
this.ss = ss;
|
||||
|
||||
@@ -3,8 +3,8 @@ package org.briarproject.plugins.modem;
|
||||
import org.briarproject.api.TransportId;
|
||||
import org.briarproject.api.contact.ContactId;
|
||||
import org.briarproject.api.crypto.PseudoRandom;
|
||||
import org.briarproject.api.data.BdfList;
|
||||
import org.briarproject.api.keyagreement.KeyAgreementListener;
|
||||
import org.briarproject.api.keyagreement.TransportDescriptor;
|
||||
import org.briarproject.api.plugins.duplex.AbstractDuplexTransportConnection;
|
||||
import org.briarproject.api.plugins.duplex.DuplexPlugin;
|
||||
import org.briarproject.api.plugins.duplex.DuplexPluginCallback;
|
||||
@@ -114,7 +114,7 @@ class ModemPlugin implements DuplexPlugin, Modem.Callback {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
boolean resetModem() {
|
||||
private boolean resetModem() {
|
||||
if (!running) return false;
|
||||
for (String portName : serialPortList.getPortNames()) {
|
||||
if (LOG.isLoggable(INFO))
|
||||
@@ -184,7 +184,7 @@ class ModemPlugin implements DuplexPlugin, Modem.Callback {
|
||||
|
||||
@Override
|
||||
public DuplexTransportConnection createKeyAgreementConnection(
|
||||
byte[] commitment, TransportDescriptor d, long timeout) {
|
||||
byte[] commitment, BdfList descriptor, long timeout) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
|
||||
@@ -2,9 +2,9 @@ package org.briarproject.plugins.tcp;
|
||||
|
||||
import org.briarproject.BriarTestCase;
|
||||
import org.briarproject.api.contact.ContactId;
|
||||
import org.briarproject.api.data.BdfList;
|
||||
import org.briarproject.api.keyagreement.KeyAgreementConnection;
|
||||
import org.briarproject.api.keyagreement.KeyAgreementListener;
|
||||
import org.briarproject.api.keyagreement.TransportDescriptor;
|
||||
import org.briarproject.api.plugins.Backoff;
|
||||
import org.briarproject.api.plugins.duplex.DuplexPlugin;
|
||||
import org.briarproject.api.plugins.duplex.DuplexPluginCallback;
|
||||
@@ -27,11 +27,11 @@ import java.util.concurrent.Callable;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.concurrent.Executor;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.concurrent.FutureTask;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
|
||||
import static java.util.concurrent.TimeUnit.SECONDS;
|
||||
import static org.briarproject.api.keyagreement.KeyAgreementConstants.TRANSPORT_ID_LAN;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
@@ -193,18 +193,15 @@ public class LanTcpPluginTest extends BriarTestCase {
|
||||
FutureTask<KeyAgreementConnection> f = new FutureTask<>(c);
|
||||
new Thread(f).start();
|
||||
// The plugin should have bound a socket and stored the port number
|
||||
TransportDescriptor d = kal.getDescriptor();
|
||||
TransportProperties p = d.getProperties();
|
||||
String ipPort = p.get("ipPort");
|
||||
assertNotNull(ipPort);
|
||||
String[] split = ipPort.split(":");
|
||||
assertEquals(2, split.length);
|
||||
String addrString = split[0], portString = split[1];
|
||||
InetAddress addr = InetAddress.getByName(addrString);
|
||||
BdfList descriptor = kal.getDescriptor();
|
||||
assertEquals(3, descriptor.size());
|
||||
assertEquals(TRANSPORT_ID_LAN, descriptor.getLong(0).longValue());
|
||||
byte[] address = descriptor.getRaw(1);
|
||||
InetAddress addr = InetAddress.getByAddress(address);
|
||||
assertTrue(addr instanceof Inet4Address);
|
||||
assertFalse(addr.isLoopbackAddress());
|
||||
assertTrue(addr.isLinkLocalAddress() || addr.isSiteLocalAddress());
|
||||
int port = Integer.parseInt(portString);
|
||||
int port = descriptor.getLong(2).intValue();
|
||||
assertTrue(port > 0 && port < 65536);
|
||||
// The plugin should be listening on the port
|
||||
InetSocketAddress socketAddr = new InetSocketAddress(addr, port);
|
||||
@@ -240,7 +237,6 @@ public class LanTcpPluginTest extends BriarTestCase {
|
||||
// Listen on the same interface as the plugin
|
||||
final ServerSocket ss = new ServerSocket();
|
||||
ss.bind(new InetSocketAddress(addrString, 0), 10);
|
||||
int port = ss.getLocalPort();
|
||||
final CountDownLatch latch = new CountDownLatch(1);
|
||||
final AtomicBoolean error = new AtomicBoolean(false);
|
||||
new Thread() {
|
||||
@@ -255,12 +251,15 @@ public class LanTcpPluginTest extends BriarTestCase {
|
||||
}
|
||||
}.start();
|
||||
// Tell the plugin about the port
|
||||
TransportProperties p = new TransportProperties();
|
||||
p.put("ipPort", addrString + ":" + port);
|
||||
TransportDescriptor desc = new TransportDescriptor(plugin.getId(), p);
|
||||
BdfList descriptor = new BdfList();
|
||||
descriptor.add(TRANSPORT_ID_LAN);
|
||||
InetSocketAddress local =
|
||||
(InetSocketAddress) ss.getLocalSocketAddress();
|
||||
descriptor.add(local.getAddress().getAddress());
|
||||
descriptor.add(local.getPort());
|
||||
// Connect to the port
|
||||
DuplexTransportConnection d =
|
||||
plugin.createKeyAgreementConnection(null, desc, 5000);
|
||||
plugin.createKeyAgreementConnection(null, descriptor, 5000);
|
||||
assertNotNull(d);
|
||||
// Check that the connection was accepted
|
||||
assertTrue(latch.await(5, SECONDS));
|
||||
@@ -291,61 +290,76 @@ public class LanTcpPluginTest extends BriarTestCase {
|
||||
private final CountDownLatch connectionsLatch = new CountDownLatch(1);
|
||||
private final TransportProperties local = new TransportProperties();
|
||||
|
||||
@Override
|
||||
public Settings getSettings() {
|
||||
return new Settings();
|
||||
}
|
||||
|
||||
@Override
|
||||
public TransportProperties getLocalProperties() {
|
||||
return local;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<ContactId, TransportProperties> getRemoteProperties() {
|
||||
return remote;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void mergeSettings(Settings s) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void mergeLocalProperties(TransportProperties p) {
|
||||
local.putAll(p);
|
||||
propertiesLatch.countDown();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int showChoice(String[] options, String... message) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean showConfirmationMessage(String... message) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void showMessage(String... message) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void incomingConnectionCreated(DuplexTransportConnection d) {
|
||||
connectionsLatch.countDown();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void outgoingConnectionCreated(ContactId c,
|
||||
DuplexTransportConnection d) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void transportEnabled() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void transportDisabled() {
|
||||
}
|
||||
}
|
||||
|
||||
private static class TestBackoff implements Backoff {
|
||||
|
||||
@Override
|
||||
public int getPollingInterval() {
|
||||
return 60 * 1000;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void increment() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reset() {
|
||||
}
|
||||
}
|
||||
|
||||
@@ -173,4 +173,55 @@ public class StringUtilsTest extends BriarTestCase {
|
||||
public void testTruncateUtf8EmptyInput() {
|
||||
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