From 7327029fca83ecdfebb547020cf04f48b377692a Mon Sep 17 00:00:00 2001 From: akwizgran Date: Mon, 7 Nov 2016 16:04:07 +0000 Subject: [PATCH 1/3] Log the QR code payload length. --- .../android/keyagreement/ShowQrCodeFragment.java | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/briar-android/src/org/briarproject/android/keyagreement/ShowQrCodeFragment.java b/briar-android/src/org/briarproject/android/keyagreement/ShowQrCodeFragment.java index 0f4704ca9..aa38dde97 100644 --- a/briar-android/src/org/briarproject/android/keyagreement/ShowQrCodeFragment.java +++ b/briar-android/src/org/briarproject/android/keyagreement/ShowQrCodeFragment.java @@ -57,6 +57,7 @@ import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_NOSENSOR; import static android.view.View.INVISIBLE; import static android.view.View.VISIBLE; import static android.widget.Toast.LENGTH_LONG; +import static java.util.logging.Level.INFO; import static java.util.logging.Level.WARNING; public class ShowQrCodeFragment extends BaseEventFragment @@ -244,8 +245,10 @@ public class ShowQrCodeFragment extends BaseEventFragment @UiThread private void qrCodeScanned(String content) { try { - Payload remotePayload = payloadParser.parse( - Base64.decode(content, 0)); + byte[] encoded = Base64.decode(content, 0); + if (LOG.isLoggable(INFO)) + LOG.info("Remote payload is " + encoded.length + " bytes"); + Payload remotePayload = payloadParser.parse(encoded); cameraView.setVisibility(INVISIBLE); statusView.setVisibility(VISIBLE); status.setText(R.string.connecting_to_device); @@ -293,9 +296,10 @@ public class ShowQrCodeFragment extends BaseEventFragment @Override protected Bitmap doInBackground(Void... params) { - String input = - Base64.encodeToString(payloadEncoder.encode(payload), - 0); + byte[] encoded = payloadEncoder.encode(payload); + if (LOG.isLoggable(INFO)) + LOG.info("Local payload is " + encoded.length + " bytes"); + String input = Base64.encodeToString(encoded, 0); return QrCodeUtils.createQrCode(dm, input); } From 04d4ecad05dc7625e13a8e562d15f21945d5d92c Mon Sep 17 00:00:00 2001 From: akwizgran Date: Mon, 7 Nov 2016 16:25:30 +0000 Subject: [PATCH 2/3] Encode transport properties more compactly in QR codes. --- .../plugins/droidtooth/DroidtoothPlugin.java | 40 +++++++---- .../briarproject/plugins/tor/TorPlugin.java | 4 +- .../keyagreement/KeyAgreementConstants.java | 8 ++- .../keyagreement/KeyAgreementListener.java | 8 ++- .../api/keyagreement/Payload.java | 23 +++++-- .../api/keyagreement/PayloadParser.java | 3 + .../api/keyagreement/TransportDescriptor.java | 28 -------- .../api/plugins/PluginManager.java | 5 ++ .../api/plugins/duplex/DuplexPlugin.java | 4 +- .../keyagreement/KeyAgreementConnector.java | 35 ++++++---- .../keyagreement/PayloadEncoderImpl.java | 23 +++---- .../keyagreement/PayloadParserImpl.java | 66 +++++++++---------- .../plugins/PluginManagerImpl.java | 4 ++ .../plugins/tcp/LanTcpPlugin.java | 53 +++++++++++---- .../briarproject/plugins/tcp/TcpPlugin.java | 4 +- .../org/briarproject/util/StringUtils.java | 44 +++++++++++-- .../plugins/bluetooth/BluetoothPlugin.java | 39 +++++++---- .../plugins/modem/ModemPlugin.java | 6 +- .../plugins/tcp/LanTcpPluginTest.java | 46 ++++++++----- .../briarproject/util/StringUtilsTest.java | 51 ++++++++++++++ 20 files changed, 326 insertions(+), 168 deletions(-) delete mode 100644 briar-api/src/org/briarproject/api/keyagreement/TransportDescriptor.java diff --git a/briar-android/src/org/briarproject/plugins/droidtooth/DroidtoothPlugin.java b/briar-android/src/org/briarproject/plugins/droidtooth/DroidtoothPlugin.java index 686d15b61..c5841d76e 100644 --- a/briar-android/src/org/briarproject/plugins/droidtooth/DroidtoothPlugin.java +++ b/briar-android/src/org/briarproject/plugins/droidtooth/DroidtoothPlugin.java @@ -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; diff --git a/briar-android/src/org/briarproject/plugins/tor/TorPlugin.java b/briar-android/src/org/briarproject/plugins/tor/TorPlugin.java index e66e0a658..ee62791d2 100644 --- a/briar-android/src/org/briarproject/plugins/tor/TorPlugin.java +++ b/briar-android/src/org/briarproject/plugins/tor/TorPlugin.java @@ -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(); } diff --git a/briar-api/src/org/briarproject/api/keyagreement/KeyAgreementConstants.java b/briar-api/src/org/briarproject/api/keyagreement/KeyAgreementConstants.java index f23911126..9961a2b99 100644 --- a/briar-api/src/org/briarproject/api/keyagreement/KeyAgreementConstants.java +++ b/briar-api/src/org/briarproject/api/keyagreement/KeyAgreementConstants.java @@ -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; } diff --git a/briar-api/src/org/briarproject/api/keyagreement/KeyAgreementListener.java b/briar-api/src/org/briarproject/api/keyagreement/KeyAgreementListener.java index 05163614c..41b18a7de 100644 --- a/briar-api/src/org/briarproject/api/keyagreement/KeyAgreementListener.java +++ b/briar-api/src/org/briarproject/api/keyagreement/KeyAgreementListener.java @@ -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; } diff --git a/briar-api/src/org/briarproject/api/keyagreement/Payload.java b/briar-api/src/org/briarproject/api/keyagreement/Payload.java index 0c749da53..60cbb45a3 100644 --- a/briar-api/src/org/briarproject/api/keyagreement/Payload.java +++ b/briar-api/src/org/briarproject/api/keyagreement/Payload.java @@ -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 { private final Bytes commitment; - private final List descriptors; + private final Map descriptors; - public Payload(byte[] commitment, List descriptors) { + public Payload(byte[] commitment, Map 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 getTransportDescriptors() { + /** + * Returns the transport descriptors contained in this payload. + */ + public Map getTransportDescriptors() { return descriptors; } diff --git a/briar-api/src/org/briarproject/api/keyagreement/PayloadParser.java b/briar-api/src/org/briarproject/api/keyagreement/PayloadParser.java index 0df9c653d..0ada113f3 100644 --- a/briar-api/src/org/briarproject/api/keyagreement/PayloadParser.java +++ b/briar-api/src/org/briarproject/api/keyagreement/PayloadParser.java @@ -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; diff --git a/briar-api/src/org/briarproject/api/keyagreement/TransportDescriptor.java b/briar-api/src/org/briarproject/api/keyagreement/TransportDescriptor.java deleted file mode 100644 index cdaa5a579..000000000 --- a/briar-api/src/org/briarproject/api/keyagreement/TransportDescriptor.java +++ /dev/null @@ -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; - } -} diff --git a/briar-api/src/org/briarproject/api/plugins/PluginManager.java b/briar-api/src/org/briarproject/api/plugins/PluginManager.java index 18e71c2ec..3f1fcf31a 100644 --- a/briar-api/src/org/briarproject/api/plugins/PluginManager.java +++ b/briar-api/src/org/briarproject/api/plugins/PluginManager.java @@ -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); /** diff --git a/briar-api/src/org/briarproject/api/plugins/duplex/DuplexPlugin.java b/briar-api/src/org/briarproject/api/plugins/duplex/DuplexPlugin.java index ff7db3b51..a77bd090e 100644 --- a/briar-api/src/org/briarproject/api/plugins/duplex/DuplexPlugin.java +++ b/briar-api/src/org/briarproject/api/plugins/duplex/DuplexPlugin.java @@ -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); } diff --git a/briar-core/src/org/briarproject/keyagreement/KeyAgreementConnector.java b/briar-core/src/org/briarproject/keyagreement/KeyAgreementConnector.java index 190a13850..44636b31d 100644 --- a/briar-core/src/org/briarproject/keyagreement/KeyAgreementConnector.java +++ b/briar-core/src/org/briarproject/keyagreement/KeyAgreementConnector.java @@ -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 descriptors = - new ArrayList(); + Map descriptors = + new HashMap(); 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 descriptors = + remotePayload.getTransportDescriptors(); + for (Entry 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 { 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; diff --git a/briar-core/src/org/briarproject/keyagreement/PayloadEncoderImpl.java b/briar-core/src/org/briarproject/keyagreement/PayloadEncoderImpl.java index 8a26f9405..32342993c 100644 --- a/briar-core/src/org/briarproject/keyagreement/PayloadEncoderImpl.java +++ b/briar-core/src/org/briarproject/keyagreement/PayloadEncoderImpl.java @@ -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 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(); } diff --git a/briar-core/src/org/briarproject/keyagreement/PayloadParserImpl.java b/briar-core/src/org/briarproject/keyagreement/PayloadParserImpl.java index d13f9ff73..105311811 100644 --- a/briar-core/src/org/briarproject/keyagreement/PayloadParserImpl.java +++ b/briar-core/src/org/briarproject/keyagreement/PayloadParserImpl.java @@ -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 descriptors = new ArrayList(); - 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 recognised = + new HashMap(); + 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); } } diff --git a/briar-core/src/org/briarproject/plugins/PluginManagerImpl.java b/briar-core/src/org/briarproject/plugins/PluginManagerImpl.java index eaefc8e5f..f9aa0ec17 100644 --- a/briar-core/src/org/briarproject/plugins/PluginManagerImpl.java +++ b/briar-core/src/org/briarproject/plugins/PluginManagerImpl.java @@ -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 = diff --git a/briar-core/src/org/briarproject/plugins/tcp/LanTcpPlugin.java b/briar-core/src/org/briarproject/plugins/tcp/LanTcpPlugin.java index 87ba78fab..01928d373 100644 --- a/briar-core/src/org/briarproject/plugins/tcp/LanTcpPlugin.java +++ b/briar-core/src/org/briarproject/plugins/tcp/LanTcpPlugin.java @@ -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; diff --git a/briar-core/src/org/briarproject/plugins/tcp/TcpPlugin.java b/briar-core/src/org/briarproject/plugins/tcp/TcpPlugin.java index 9ba84875b..7227e1a0f 100644 --- a/briar-core/src/org/briarproject/plugins/tcp/TcpPlugin.java +++ b/briar-core/src/org/briarproject/plugins/tcp/TcpPlugin.java @@ -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(); } diff --git a/briar-core/src/org/briarproject/util/StringUtils.java b/briar-core/src/org/briarproject/util/StringUtils.java index 5acedc34e..af622cc27 100644 --- a/briar-core/src/org/briarproject/util/StringUtils.java +++ b/briar-core/src/org/briarproject/util/StringUtils.java @@ -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(); + } } diff --git a/briar-desktop/src/org/briarproject/plugins/bluetooth/BluetoothPlugin.java b/briar-desktop/src/org/briarproject/plugins/bluetooth/BluetoothPlugin.java index f7b639bba..c6b607d32 100644 --- a/briar-desktop/src/org/briarproject/plugins/bluetooth/BluetoothPlugin.java +++ b/briar-desktop/src/org/briarproject/plugins/bluetooth/BluetoothPlugin.java @@ -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; diff --git a/briar-desktop/src/org/briarproject/plugins/modem/ModemPlugin.java b/briar-desktop/src/org/briarproject/plugins/modem/ModemPlugin.java index ce2d2d57e..4a32bf461 100644 --- a/briar-desktop/src/org/briarproject/plugins/modem/ModemPlugin.java +++ b/briar-desktop/src/org/briarproject/plugins/modem/ModemPlugin.java @@ -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(); } diff --git a/briar-tests/src/org/briarproject/plugins/tcp/LanTcpPluginTest.java b/briar-tests/src/org/briarproject/plugins/tcp/LanTcpPluginTest.java index 622bb59aa..33f8d3a90 100644 --- a/briar-tests/src/org/briarproject/plugins/tcp/LanTcpPluginTest.java +++ b/briar-tests/src/org/briarproject/plugins/tcp/LanTcpPluginTest.java @@ -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 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 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() { } } diff --git a/briar-tests/src/org/briarproject/util/StringUtilsTest.java b/briar-tests/src/org/briarproject/util/StringUtilsTest.java index 76f830df3..92aeaf54c 100644 --- a/briar-tests/src/org/briarproject/util/StringUtilsTest.java +++ b/briar-tests/src/org/briarproject/util/StringUtilsTest.java @@ -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)); + } } From d2a3804cfe2c02a197928b79faf4c9d65e4d3646 Mon Sep 17 00:00:00 2001 From: akwizgran Date: Tue, 8 Nov 2016 16:59:56 +0000 Subject: [PATCH 3/3] Added null safety annotations to plugin interfaces. --- .../plugins/droidtooth/DroidtoothPlugin.java | 22 +++++++++------- .../plugins/tcp/AndroidLanTcpPlugin.java | 5 ++++ .../briarproject/plugins/tor/TorPlugin.java | 13 +++++++--- .../org/briarproject/api/plugins/Plugin.java | 26 ++++++++++++++----- .../api/plugins/duplex/DuplexPlugin.java | 25 ++++++++++++++---- .../api/plugins/simplex/SimplexPlugin.java | 14 +++++++--- .../briarproject/plugins/file/FilePlugin.java | 8 +++++- .../plugins/tcp/LanTcpPlugin.java | 7 ++--- .../briarproject/plugins/tcp/TcpPlugin.java | 9 ++++++- .../plugins/tcp/WanTcpPlugin.java | 4 +++ .../plugins/bluetooth/BluetoothPlugin.java | 13 +++++----- .../plugins/file/RemovableDrivePlugin.java | 2 ++ .../plugins/modem/ModemPlugin.java | 4 +++ .../plugins/tcp/LanTcpPluginTest.java | 9 ++++--- 14 files changed, 119 insertions(+), 42 deletions(-) diff --git a/briar-android/src/org/briarproject/plugins/droidtooth/DroidtoothPlugin.java b/briar-android/src/org/briarproject/plugins/droidtooth/DroidtoothPlugin.java index c5841d76e..d1ba7d858 100644 --- a/briar-android/src/org/briarproject/plugins/droidtooth/DroidtoothPlugin.java +++ b/briar-android/src/org/briarproject/plugins/droidtooth/DroidtoothPlugin.java @@ -18,6 +18,8 @@ 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.nullsafety.MethodsNotNullByDefault; +import org.briarproject.api.nullsafety.ParametersNotNullByDefault; import org.briarproject.api.plugins.Backoff; import org.briarproject.api.plugins.duplex.DuplexPlugin; import org.briarproject.api.plugins.duplex.DuplexPluginCallback; @@ -25,6 +27,7 @@ import org.briarproject.api.plugins.duplex.DuplexTransportConnection; import org.briarproject.api.properties.TransportProperties; import org.briarproject.util.StringUtils; +import java.io.Closeable; import java.io.IOException; import java.io.InputStream; import java.security.SecureRandom; @@ -63,6 +66,8 @@ import static java.util.logging.Level.WARNING; import static org.briarproject.api.keyagreement.KeyAgreementConstants.TRANSPORT_ID_BLUETOOTH; import static org.briarproject.util.PrivacyUtils.scrubMacAddress; +@MethodsNotNullByDefault +@ParametersNotNullByDefault class DroidtoothPlugin implements DuplexPlugin { // Share an ID with the J2SE Bluetooth plugin @@ -221,7 +226,7 @@ class DroidtoothPlugin implements DuplexPlugin { return UUID.fromString(uuid); } - private void tryToClose(BluetoothServerSocket ss) { + private void tryToClose(@Nullable BluetoothServerSocket ss) { try { if (ss != null) ss.close(); } catch (IOException e) { @@ -344,9 +349,9 @@ class DroidtoothPlugin implements DuplexPlugin { } } - private void tryToClose(BluetoothSocket s) { + private void tryToClose(@Nullable Closeable c) { try { - if (s != null) s.close(); + if (c != null) c.close(); } catch (IOException e) { if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e); } @@ -424,7 +429,7 @@ class DroidtoothPlugin implements DuplexPlugin { } private void closeSockets(final List> futures, - final BluetoothSocket chosen) { + @Nullable final BluetoothSocket chosen) { ioExecutor.execute(new Runnable() { @Override public void run() { @@ -458,6 +463,9 @@ class DroidtoothPlugin implements DuplexPlugin { @Override public KeyAgreementListener createKeyAgreementListener(byte[] commitment) { 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 UUID uuid = UUID.nameUUIDFromBytes(commitment); if (LOG.isLoggable(INFO)) LOG.info("Key agreement UUID " + uuid); @@ -472,8 +480,7 @@ class DroidtoothPlugin implements DuplexPlugin { } BdfList descriptor = new BdfList(); descriptor.add(TRANSPORT_ID_BLUETOOTH); - String address = AndroidUtils.getBluetoothAddress(appContext, adapter); - if (!address.isEmpty()) descriptor.add(StringUtils.macToBytes(address)); + descriptor.add(StringUtils.macToBytes(address)); return new BluetoothKeyAgreementListener(descriptor, ss); } @@ -488,7 +495,6 @@ class DroidtoothPlugin implements DuplexPlugin { 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)) @@ -498,9 +504,7 @@ 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); diff --git a/briar-android/src/org/briarproject/plugins/tcp/AndroidLanTcpPlugin.java b/briar-android/src/org/briarproject/plugins/tcp/AndroidLanTcpPlugin.java index 598e914b6..b96aefa08 100644 --- a/briar-android/src/org/briarproject/plugins/tcp/AndroidLanTcpPlugin.java +++ b/briar-android/src/org/briarproject/plugins/tcp/AndroidLanTcpPlugin.java @@ -7,16 +7,20 @@ import android.content.IntentFilter; import android.net.ConnectivityManager; import android.net.NetworkInfo; +import org.briarproject.api.nullsafety.NotNullByDefault; import org.briarproject.api.plugins.Backoff; import org.briarproject.api.plugins.duplex.DuplexPluginCallback; import java.util.concurrent.Executor; import java.util.logging.Logger; +import javax.annotation.Nullable; + import static android.content.Context.CONNECTIVITY_SERVICE; import static android.net.ConnectivityManager.CONNECTIVITY_ACTION; import static android.net.ConnectivityManager.TYPE_WIFI; +@NotNullByDefault class AndroidLanTcpPlugin extends LanTcpPlugin { private static final Logger LOG = @@ -24,6 +28,7 @@ class AndroidLanTcpPlugin extends LanTcpPlugin { private final Context appContext; + @Nullable private volatile BroadcastReceiver networkStateReceiver = null; AndroidLanTcpPlugin(Executor ioExecutor, Backoff backoff, diff --git a/briar-android/src/org/briarproject/plugins/tor/TorPlugin.java b/briar-android/src/org/briarproject/plugins/tor/TorPlugin.java index ee62791d2..2a8b58991 100644 --- a/briar-android/src/org/briarproject/plugins/tor/TorPlugin.java +++ b/briar-android/src/org/briarproject/plugins/tor/TorPlugin.java @@ -24,6 +24,7 @@ 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.nullsafety.NotNullByDefault; import org.briarproject.api.plugins.Backoff; import org.briarproject.api.plugins.TorConstants; import org.briarproject.api.plugins.duplex.DuplexPlugin; @@ -60,6 +61,7 @@ import java.util.logging.Logger; import java.util.regex.Pattern; import java.util.zip.ZipInputStream; +import javax.annotation.Nullable; import javax.net.SocketFactory; 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.util.PrivacyUtils.scrubOnion; +@NotNullByDefault class TorPlugin implements DuplexPlugin, EventHandler, EventListener { 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 volatile boolean running = false; + @Nullable private volatile ServerSocket socket = null; + @Nullable private volatile Socket controlSocket = null; + @Nullable private volatile TorControlConnection controlConnection = null; + @Nullable private volatile BroadcastReceiver networkStateReceiver = null; TorPlugin(Executor ioExecutor, Context appContext, @@ -289,7 +296,7 @@ class TorPlugin implements DuplexPlugin, EventHandler, EventListener { return appContext.getResources().getAssets().open("torrc"); } - private void tryToClose(Closeable c) { + private void tryToClose(@Nullable Closeable c) { try { if (c != null) c.close(); } 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 { if (s != null) s.close(); } 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 { if (ss != null) ss.close(); } catch (IOException e) { diff --git a/briar-api/src/org/briarproject/api/plugins/Plugin.java b/briar-api/src/org/briarproject/api/plugins/Plugin.java index 393fa27ea..e54822cce 100644 --- a/briar-api/src/org/briarproject/api/plugins/Plugin.java +++ b/briar-api/src/org/briarproject/api/plugins/Plugin.java @@ -2,28 +2,42 @@ package org.briarproject.api.plugins; import org.briarproject.api.TransportId; import org.briarproject.api.contact.ContactId; +import org.briarproject.api.nullsafety.NotNullByDefault; import java.io.IOException; import java.util.Collection; +@NotNullByDefault public interface Plugin { - /** Returns the plugin's transport identifier. */ + /** + * Returns the plugin's transport identifier. + */ TransportId getId(); - /** Returns the transport's maximum latency in milliseconds. */ + /** + * Returns the transport's maximum latency in milliseconds. + */ int getMaxLatency(); - /** Returns the transport's maximum idle time in milliseconds. */ + /** + * Returns the transport's maximum idle time in milliseconds. + */ 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; - /** Stops the plugin. */ + /** + * Stops the plugin. + */ void stop() throws IOException; - /** Returns true if the plugin is running. */ + /** + * Returns true if the plugin is running. + */ boolean isRunning(); /** diff --git a/briar-api/src/org/briarproject/api/plugins/duplex/DuplexPlugin.java b/briar-api/src/org/briarproject/api/plugins/duplex/DuplexPlugin.java index a77bd090e..c45d5bab3 100644 --- a/briar-api/src/org/briarproject/api/plugins/duplex/DuplexPlugin.java +++ b/briar-api/src/org/briarproject/api/plugins/duplex/DuplexPlugin.java @@ -4,19 +4,28 @@ 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.nullsafety.NotNullByDefault; 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 { /** * Attempts to create and return a connection to the given contact using * the current transport and configuration properties. Returns null if a - * connection could not be created. + * connection cannot be created. */ + @Nullable DuplexTransportConnection createConnection(ContactId c); - /** Returns true if the plugin supports exchanging invitations. */ + /** + * Returns true if the plugin supports exchanging invitations. + */ boolean supportsInvitations(); /** @@ -24,21 +33,27 @@ public interface DuplexPlugin extends Plugin { * peer. Returns null if no connection can be established within the given * time. */ + @Nullable DuplexTransportConnection createInvitationConnection(PseudoRandom r, long timeout, boolean alice); - /** Returns true if the plugin supports short-range key agreement. */ + /** + * Returns true if the plugin supports short-range key agreement. + */ 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); /** * Attempts to connect to the remote peer specified in the given descriptor. * Returns null if no connection can be established within the given time. */ + @Nullable DuplexTransportConnection createKeyAgreementConnection( byte[] remoteCommitment, BdfList descriptor, long timeout); } diff --git a/briar-api/src/org/briarproject/api/plugins/simplex/SimplexPlugin.java b/briar-api/src/org/briarproject/api/plugins/simplex/SimplexPlugin.java index 36e2ed438..cf9f5ebec 100644 --- a/briar-api/src/org/briarproject/api/plugins/simplex/SimplexPlugin.java +++ b/briar-api/src/org/briarproject/api/plugins/simplex/SimplexPlugin.java @@ -1,24 +1,32 @@ package org.briarproject.api.plugins.simplex; import org.briarproject.api.contact.ContactId; +import org.briarproject.api.nullsafety.NotNullByDefault; import org.briarproject.api.plugins.Plugin; import org.briarproject.api.plugins.TransportConnectionReader; 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 { /** * Attempts to create and return a reader for the given contact using the * current transport and configuration properties. Returns null if a reader - * could not be created. + * cannot be created. */ + @Nullable TransportConnectionReader createReader(ContactId c); /** * Attempts to create and return a writer for the given contact using the * current transport and configuration properties. Returns null if a writer - * could not be created. + * cannot be created. */ + @Nullable TransportConnectionWriter createWriter(ContactId c); } diff --git a/briar-core/src/org/briarproject/plugins/file/FilePlugin.java b/briar-core/src/org/briarproject/plugins/file/FilePlugin.java index 981923553..108db3c7b 100644 --- a/briar-core/src/org/briarproject/plugins/file/FilePlugin.java +++ b/briar-core/src/org/briarproject/plugins/file/FilePlugin.java @@ -1,6 +1,7 @@ package org.briarproject.plugins.file; import org.briarproject.api.contact.ContactId; +import org.briarproject.api.nullsafety.NotNullByDefault; import org.briarproject.api.plugins.TransportConnectionReader; import org.briarproject.api.plugins.TransportConnectionWriter; 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.logging.Logger; +import javax.annotation.Nullable; + import static java.util.logging.Level.WARNING; 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 = Logger.getLogger(FilePlugin.class.getName()); @@ -32,6 +36,7 @@ public abstract class FilePlugin implements SimplexPlugin { protected volatile boolean running = false; + @Nullable protected abstract File chooseOutputDirectory(); protected abstract Collection findFilesByName(String filename); 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"); } + @Nullable private TransportConnectionWriter createWriter(String filename) { if (!running) return null; File dir = chooseOutputDirectory(); diff --git a/briar-core/src/org/briarproject/plugins/tcp/LanTcpPlugin.java b/briar-core/src/org/briarproject/plugins/tcp/LanTcpPlugin.java index 01928d373..e3527f74d 100644 --- a/briar-core/src/org/briarproject/plugins/tcp/LanTcpPlugin.java +++ b/briar-core/src/org/briarproject/plugins/tcp/LanTcpPlugin.java @@ -6,6 +6,7 @@ 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.nullsafety.NotNullByDefault; import org.briarproject.api.plugins.Backoff; import org.briarproject.api.plugins.duplex.DuplexPluginCallback; import org.briarproject.api.plugins.duplex.DuplexTransportConnection; @@ -29,14 +30,13 @@ 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; +@NotNullByDefault class LanTcpPlugin extends TcpPlugin { static final TransportId ID = new TransportId("lan"); @@ -211,7 +211,6 @@ class LanTcpPlugin extends TcpPlugin { LOG.info("Invalid IP/port in key agreement descriptor"); return null; } - if (remote == null) return null; if (!isConnectable(remote)) { if (LOG.isLoggable(INFO)) { SocketAddress local = socket.getLocalSocketAddress(); @@ -237,10 +236,8 @@ 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(); diff --git a/briar-core/src/org/briarproject/plugins/tcp/TcpPlugin.java b/briar-core/src/org/briarproject/plugins/tcp/TcpPlugin.java index 7227e1a0f..76da5bf7d 100644 --- a/briar-core/src/org/briarproject/plugins/tcp/TcpPlugin.java +++ b/briar-core/src/org/briarproject/plugins/tcp/TcpPlugin.java @@ -4,6 +4,8 @@ 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.nullsafety.MethodsNotNullByDefault; +import org.briarproject.api.nullsafety.ParametersNotNullByDefault; import org.briarproject.api.plugins.Backoff; import org.briarproject.api.plugins.duplex.DuplexPlugin; 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.regex.Pattern; +import javax.annotation.Nullable; + import static java.util.logging.Level.INFO; import static java.util.logging.Level.WARNING; import static org.briarproject.util.PrivacyUtils.scrubSocketAddress; +@MethodsNotNullByDefault +@ParametersNotNullByDefault abstract class TcpPlugin implements DuplexPlugin { 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 { if (ss != null) ss.close(); } catch (IOException e) { @@ -252,6 +258,7 @@ abstract class TcpPlugin implements DuplexPlugin { return null; } + @Nullable protected InetSocketAddress parseSocketAddress(String ipPort) { if (StringUtils.isNullOrEmpty(ipPort)) return null; String[] split = ipPort.split(":"); diff --git a/briar-core/src/org/briarproject/plugins/tcp/WanTcpPlugin.java b/briar-core/src/org/briarproject/plugins/tcp/WanTcpPlugin.java index 82c3221a5..3f297d148 100644 --- a/briar-core/src/org/briarproject/plugins/tcp/WanTcpPlugin.java +++ b/briar-core/src/org/briarproject/plugins/tcp/WanTcpPlugin.java @@ -2,6 +2,8 @@ package org.briarproject.plugins.tcp; import org.briarproject.api.TransportId; 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.duplex.DuplexPluginCallback; import org.briarproject.api.properties.TransportProperties; @@ -14,6 +16,8 @@ import java.util.LinkedList; import java.util.List; import java.util.concurrent.Executor; +@MethodsNotNullByDefault +@ParametersNotNullByDefault class WanTcpPlugin extends TcpPlugin { static final TransportId ID = new TransportId("wan"); diff --git a/briar-desktop/src/org/briarproject/plugins/bluetooth/BluetoothPlugin.java b/briar-desktop/src/org/briarproject/plugins/bluetooth/BluetoothPlugin.java index c6b607d32..c945ca815 100644 --- a/briar-desktop/src/org/briarproject/plugins/bluetooth/BluetoothPlugin.java +++ b/briar-desktop/src/org/briarproject/plugins/bluetooth/BluetoothPlugin.java @@ -7,6 +7,8 @@ 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.nullsafety.MethodsNotNullByDefault; +import org.briarproject.api.nullsafety.ParametersNotNullByDefault; import org.briarproject.api.plugins.Backoff; import org.briarproject.api.plugins.duplex.DuplexPlugin; import org.briarproject.api.plugins.duplex.DuplexPluginCallback; @@ -48,6 +50,8 @@ import static java.util.logging.Level.WARNING; import static javax.bluetooth.DiscoveryAgent.GIAC; import static org.briarproject.api.keyagreement.KeyAgreementConstants.TRANSPORT_ID_BLUETOOTH; +@MethodsNotNullByDefault +@ParametersNotNullByDefault class BluetoothPlugin implements DuplexPlugin { // Share an ID with the Android Bluetooth plugin @@ -164,7 +168,7 @@ class BluetoothPlugin implements DuplexPlugin { return uuid; } - private void tryToClose(StreamConnectionNotifier ss) { + private void tryToClose(@Nullable StreamConnectionNotifier ss) { try { if (ss != null) ss.close(); } catch (IOException e) { @@ -333,7 +337,7 @@ class BluetoothPlugin implements DuplexPlugin { } private void closeSockets(final List> futures, - final StreamConnection chosen) { + @Nullable final StreamConnection chosen) { ioExecutor.execute(new Runnable() { @Override public void run() { @@ -388,7 +392,7 @@ class BluetoothPlugin implements DuplexPlugin { BdfList descriptor = new BdfList(); descriptor.add(TRANSPORT_ID_BLUETOOTH); String address = localDevice.getBluetoothAddress(); - if (!address.isEmpty()) descriptor.add(StringUtils.macToBytes(address)); + descriptor.add(StringUtils.macToBytes(address)); return new BluetoothKeyAgreementListener(descriptor, ss); } @@ -403,7 +407,6 @@ class BluetoothPlugin implements DuplexPlugin { 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)) @@ -414,9 +417,7 @@ 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); diff --git a/briar-desktop/src/org/briarproject/plugins/file/RemovableDrivePlugin.java b/briar-desktop/src/org/briarproject/plugins/file/RemovableDrivePlugin.java index 926f8d314..4a463eb3e 100644 --- a/briar-desktop/src/org/briarproject/plugins/file/RemovableDrivePlugin.java +++ b/briar-desktop/src/org/briarproject/plugins/file/RemovableDrivePlugin.java @@ -2,6 +2,7 @@ package org.briarproject.plugins.file; import org.briarproject.api.TransportId; import org.briarproject.api.contact.ContactId; +import org.briarproject.api.nullsafety.NotNullByDefault; import org.briarproject.api.plugins.simplex.SimplexPluginCallback; import java.io.File; @@ -15,6 +16,7 @@ import java.util.logging.Logger; import static java.util.logging.Level.WARNING; +@NotNullByDefault class RemovableDrivePlugin extends FilePlugin implements RemovableDriveMonitor.Callback { diff --git a/briar-desktop/src/org/briarproject/plugins/modem/ModemPlugin.java b/briar-desktop/src/org/briarproject/plugins/modem/ModemPlugin.java index 4a32bf461..fe3b89e2c 100644 --- a/briar-desktop/src/org/briarproject/plugins/modem/ModemPlugin.java +++ b/briar-desktop/src/org/briarproject/plugins/modem/ModemPlugin.java @@ -5,6 +5,8 @@ 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.nullsafety.MethodsNotNullByDefault; +import org.briarproject.api.nullsafety.ParametersNotNullByDefault; import org.briarproject.api.plugins.duplex.AbstractDuplexTransportConnection; import org.briarproject.api.plugins.duplex.DuplexPlugin; 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.WARNING; +@MethodsNotNullByDefault +@ParametersNotNullByDefault class ModemPlugin implements DuplexPlugin, Modem.Callback { static final TransportId ID = new TransportId("modem"); diff --git a/briar-tests/src/org/briarproject/plugins/tcp/LanTcpPluginTest.java b/briar-tests/src/org/briarproject/plugins/tcp/LanTcpPluginTest.java index 33f8d3a90..2f8e349c4 100644 --- a/briar-tests/src/org/briarproject/plugins/tcp/LanTcpPluginTest.java +++ b/briar-tests/src/org/briarproject/plugins/tcp/LanTcpPluginTest.java @@ -31,6 +31,7 @@ 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.COMMIT_LENGTH; import static org.briarproject.api.keyagreement.KeyAgreementConstants.TRANSPORT_ID_LAN; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; @@ -188,7 +189,9 @@ public class LanTcpPluginTest extends BriarTestCase { 0, 0); plugin.start(); assertTrue(callback.propertiesLatch.await(5, SECONDS)); - KeyAgreementListener kal = plugin.createKeyAgreementListener(null); + KeyAgreementListener kal = + plugin.createKeyAgreementListener(new byte[COMMIT_LENGTH]); + assertNotNull(kal); Callable c = kal.listen(); FutureTask f = new FutureTask<>(c); new Thread(f).start(); @@ -258,8 +261,8 @@ public class LanTcpPluginTest extends BriarTestCase { descriptor.add(local.getAddress().getAddress()); descriptor.add(local.getPort()); // Connect to the port - DuplexTransportConnection d = - plugin.createKeyAgreementConnection(null, descriptor, 5000); + DuplexTransportConnection d = plugin.createKeyAgreementConnection( + new byte[COMMIT_LENGTH], descriptor, 5000); assertNotNull(d); // Check that the connection was accepted assertTrue(latch.await(5, SECONDS));