Replace events with return value and exceptions.

This commit is contained in:
akwizgran
2019-05-24 10:50:03 +01:00
parent bcc899eebf
commit 5be0e928c4
5 changed files with 66 additions and 174 deletions

View File

@@ -1,16 +1,24 @@
package org.briarproject.bramble.api.contact; package org.briarproject.bramble.api.contact;
import org.briarproject.bramble.api.crypto.SecretKey; import org.briarproject.bramble.api.crypto.SecretKey;
import org.briarproject.bramble.api.db.ContactExistsException;
import org.briarproject.bramble.api.db.DbException;
import org.briarproject.bramble.api.identity.Author;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault; import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import org.briarproject.bramble.api.plugin.TransportId; import org.briarproject.bramble.api.plugin.TransportId;
import org.briarproject.bramble.api.plugin.duplex.DuplexTransportConnection; import org.briarproject.bramble.api.plugin.duplex.DuplexTransportConnection;
import java.io.IOException;
@NotNullByDefault @NotNullByDefault
public interface ContactExchangeManager { public interface ContactExchangeManager {
/** /**
* Exchanges contact information with a remote peer. * Exchanges contact information with a remote peer.
*
* @return The contact's pseudonym
* @throws ContactExistsException If the contact already exists
*/ */
void exchangeContacts(TransportId t, DuplexTransportConnection conn, Author exchangeContacts(TransportId t, DuplexTransportConnection conn,
SecretKey masterKey, boolean alice); SecretKey masterKey, boolean alice) throws IOException, DbException;
} }

View File

@@ -1,32 +0,0 @@
package org.briarproject.bramble.api.contact.event;
import org.briarproject.bramble.api.event.Event;
import org.briarproject.bramble.api.identity.Author;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import javax.annotation.Nullable;
@NotNullByDefault
public class ContactExchangeFailedEvent extends Event {
@Nullable
private final Author duplicateRemoteAuthor;
public ContactExchangeFailedEvent(@Nullable Author duplicateRemoteAuthor) {
this.duplicateRemoteAuthor = duplicateRemoteAuthor;
}
public ContactExchangeFailedEvent() {
this(null);
}
@Nullable
public Author getDuplicateRemoteAuthor() {
return duplicateRemoteAuthor;
}
public boolean wasDuplicateContact() {
return duplicateRemoteAuthor != null;
}
}

View File

@@ -1,20 +0,0 @@
package org.briarproject.bramble.api.contact.event;
import org.briarproject.bramble.api.event.Event;
import org.briarproject.bramble.api.identity.Author;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
@NotNullByDefault
public class ContactExchangeSucceededEvent extends Event {
private final Author remoteAuthor;
public ContactExchangeSucceededEvent(Author remoteAuthor) {
this.remoteAuthor = remoteAuthor;
}
public Author getRemoteAuthor() {
return remoteAuthor;
}
}

View File

@@ -6,16 +6,12 @@ import org.briarproject.bramble.api.client.ClientHelper;
import org.briarproject.bramble.api.contact.ContactExchangeManager; import org.briarproject.bramble.api.contact.ContactExchangeManager;
import org.briarproject.bramble.api.contact.ContactId; import org.briarproject.bramble.api.contact.ContactId;
import org.briarproject.bramble.api.contact.ContactManager; import org.briarproject.bramble.api.contact.ContactManager;
import org.briarproject.bramble.api.contact.event.ContactExchangeFailedEvent;
import org.briarproject.bramble.api.contact.event.ContactExchangeSucceededEvent;
import org.briarproject.bramble.api.crypto.CryptoComponent; import org.briarproject.bramble.api.crypto.CryptoComponent;
import org.briarproject.bramble.api.crypto.SecretKey; import org.briarproject.bramble.api.crypto.SecretKey;
import org.briarproject.bramble.api.data.BdfDictionary; import org.briarproject.bramble.api.data.BdfDictionary;
import org.briarproject.bramble.api.data.BdfList; import org.briarproject.bramble.api.data.BdfList;
import org.briarproject.bramble.api.db.ContactExistsException;
import org.briarproject.bramble.api.db.DatabaseComponent; import org.briarproject.bramble.api.db.DatabaseComponent;
import org.briarproject.bramble.api.db.DbException; import org.briarproject.bramble.api.db.DbException;
import org.briarproject.bramble.api.event.EventBus;
import org.briarproject.bramble.api.identity.Author; import org.briarproject.bramble.api.identity.Author;
import org.briarproject.bramble.api.identity.IdentityManager; import org.briarproject.bramble.api.identity.IdentityManager;
import org.briarproject.bramble.api.identity.LocalAuthor; import org.briarproject.bramble.api.identity.LocalAuthor;
@@ -46,7 +42,6 @@ import java.util.logging.Logger;
import javax.inject.Inject; import javax.inject.Inject;
import static java.util.logging.Level.WARNING;
import static java.util.logging.Logger.getLogger; import static java.util.logging.Logger.getLogger;
import static org.briarproject.bramble.api.contact.RecordTypes.CONTACT_INFO; import static org.briarproject.bramble.api.contact.RecordTypes.CONTACT_INFO;
import static org.briarproject.bramble.api.identity.AuthorConstants.MAX_SIGNATURE_LENGTH; import static org.briarproject.bramble.api.identity.AuthorConstants.MAX_SIGNATURE_LENGTH;
@@ -56,7 +51,6 @@ import static org.briarproject.bramble.contact.ContactExchangeConstants.BOB_KEY_
import static org.briarproject.bramble.contact.ContactExchangeConstants.BOB_NONCE_LABEL; import static org.briarproject.bramble.contact.ContactExchangeConstants.BOB_NONCE_LABEL;
import static org.briarproject.bramble.contact.ContactExchangeConstants.PROTOCOL_VERSION; import static org.briarproject.bramble.contact.ContactExchangeConstants.PROTOCOL_VERSION;
import static org.briarproject.bramble.contact.ContactExchangeConstants.SIGNING_LABEL; import static org.briarproject.bramble.contact.ContactExchangeConstants.SIGNING_LABEL;
import static org.briarproject.bramble.util.LogUtils.logException;
import static org.briarproject.bramble.util.ValidationUtils.checkLength; import static org.briarproject.bramble.util.ValidationUtils.checkLength;
import static org.briarproject.bramble.util.ValidationUtils.checkSize; import static org.briarproject.bramble.util.ValidationUtils.checkSize;
@@ -85,7 +79,6 @@ class ContactExchangeManagerImpl implements ContactExchangeManager {
private final ClientHelper clientHelper; private final ClientHelper clientHelper;
private final RecordReaderFactory recordReaderFactory; private final RecordReaderFactory recordReaderFactory;
private final RecordWriterFactory recordWriterFactory; private final RecordWriterFactory recordWriterFactory;
private final EventBus eventBus;
private final Clock clock; private final Clock clock;
private final ConnectionManager connectionManager; private final ConnectionManager connectionManager;
private final ContactManager contactManager; private final ContactManager contactManager;
@@ -98,7 +91,7 @@ class ContactExchangeManagerImpl implements ContactExchangeManager {
@Inject @Inject
ContactExchangeManagerImpl(DatabaseComponent db, ClientHelper clientHelper, ContactExchangeManagerImpl(DatabaseComponent db, ClientHelper clientHelper,
RecordReaderFactory recordReaderFactory, RecordReaderFactory recordReaderFactory,
RecordWriterFactory recordWriterFactory, EventBus eventBus, RecordWriterFactory recordWriterFactory,
Clock clock, ConnectionManager connectionManager, Clock clock, ConnectionManager connectionManager,
ContactManager contactManager, IdentityManager identityManager, ContactManager contactManager, IdentityManager identityManager,
TransportPropertyManager transportPropertyManager, TransportPropertyManager transportPropertyManager,
@@ -108,7 +101,6 @@ class ContactExchangeManagerImpl implements ContactExchangeManager {
this.clientHelper = clientHelper; this.clientHelper = clientHelper;
this.recordReaderFactory = recordReaderFactory; this.recordReaderFactory = recordReaderFactory;
this.recordWriterFactory = recordWriterFactory; this.recordWriterFactory = recordWriterFactory;
this.eventBus = eventBus;
this.clock = clock; this.clock = clock;
this.connectionManager = connectionManager; this.connectionManager = connectionManager;
this.contactManager = contactManager; this.contactManager = contactManager;
@@ -120,33 +112,17 @@ class ContactExchangeManagerImpl implements ContactExchangeManager {
} }
@Override @Override
public void exchangeContacts(TransportId t, DuplexTransportConnection conn, public Author exchangeContacts(TransportId t,
SecretKey masterKey, boolean alice) { DuplexTransportConnection conn, SecretKey masterKey, boolean alice)
throws IOException, DbException {
// Get the transport connection's input and output streams // Get the transport connection's input and output streams
InputStream in; InputStream in = conn.getReader().getInputStream();
OutputStream out; OutputStream out = conn.getWriter().getOutputStream();
try {
in = conn.getReader().getInputStream();
out = conn.getWriter().getOutputStream();
} catch (IOException e) {
logException(LOG, WARNING, e);
tryToClose(conn);
eventBus.broadcast(new ContactExchangeFailedEvent());
return;
}
// Get the local author and transport properties // Get the local author and transport properties
LocalAuthor localAuthor; LocalAuthor localAuthor = identityManager.getLocalAuthor();
Map<TransportId, TransportProperties> localProperties; Map<TransportId, TransportProperties> localProperties =
try { transportPropertyManager.getLocalProperties();
localAuthor = identityManager.getLocalAuthor();
localProperties = transportPropertyManager.getLocalProperties();
} catch (DbException e) {
logException(LOG, WARNING, e);
eventBus.broadcast(new ContactExchangeFailedEvent());
tryToClose(conn);
return;
}
// Derive the header keys for the transport streams // Derive the header keys for the transport streams
SecretKey aliceHeaderKey = crypto.deriveKey(ALICE_KEY_LABEL, masterKey, SecretKey aliceHeaderKey = crypto.deriveKey(ALICE_KEY_LABEL, masterKey,
@@ -183,58 +159,37 @@ class ContactExchangeManagerImpl implements ContactExchangeManager {
// Exchange contact info // Exchange contact info
long localTimestamp = clock.currentTimeMillis(); long localTimestamp = clock.currentTimeMillis();
ContactInfo remoteInfo; ContactInfo remoteInfo;
try { if (alice) {
if (alice) { sendContactInfo(recordWriter, localAuthor, localProperties,
sendContactInfo(recordWriter, localAuthor, localProperties, localSignature, localTimestamp);
localSignature, localTimestamp); remoteInfo = receiveContactInfo(recordReader);
remoteInfo = receiveContactInfo(recordReader); } else {
} else { remoteInfo = receiveContactInfo(recordReader);
remoteInfo = receiveContactInfo(recordReader); sendContactInfo(recordWriter, localAuthor, localProperties,
sendContactInfo(recordWriter, localAuthor, localProperties, localSignature, localTimestamp);
localSignature, localTimestamp);
}
// Send EOF on the outgoing stream
streamWriter.sendEndOfStream();
// Skip any remaining records from the incoming stream
recordReader.readRecord(r -> false, IGNORE);
} catch (IOException e) {
logException(LOG, WARNING, e);
eventBus.broadcast(new ContactExchangeFailedEvent());
tryToClose(conn);
return;
} }
// Send EOF on the outgoing stream
streamWriter.sendEndOfStream();
// Skip any remaining records from the incoming stream
recordReader.readRecord(r -> false, IGNORE);
// Verify the contact's signature // Verify the contact's signature
if (!verify(remoteInfo.author, remoteNonce, remoteInfo.signature)) { if (!verify(remoteInfo.author, remoteNonce, remoteInfo.signature)) {
LOG.warning("Invalid signature"); LOG.warning("Invalid signature");
eventBus.broadcast(new ContactExchangeFailedEvent()); throw new FormatException();
tryToClose(conn);
return;
} }
// The agreed timestamp is the minimum of the peers' timestamps // The agreed timestamp is the minimum of the peers' timestamps
long timestamp = Math.min(localTimestamp, remoteInfo.timestamp); long timestamp = Math.min(localTimestamp, remoteInfo.timestamp);
try { // Add the contact
// Add the contact ContactId contactId = addContact(remoteInfo.author, localAuthor,
ContactId contactId = addContact(remoteInfo.author, localAuthor, masterKey, timestamp, alice, remoteInfo.properties);
masterKey, timestamp, alice, remoteInfo.properties); // Reuse the connection as a transport connection
// Reuse the connection as a transport connection connectionManager.manageOutgoingConnection(contactId, t, conn);
connectionManager.manageOutgoingConnection(contactId, t, conn); // Pseudonym exchange succeeded
// Pseudonym exchange succeeded LOG.info("Pseudonym exchange succeeded");
LOG.info("Pseudonym exchange succeeded"); return remoteInfo.author;
eventBus.broadcast(
new ContactExchangeSucceededEvent(remoteInfo.author));
} catch (ContactExistsException e) {
logException(LOG, WARNING, e);
tryToClose(conn);
eventBus.broadcast(
new ContactExchangeFailedEvent(e.getRemoteAuthor()));
} catch (DbException e) {
logException(LOG, WARNING, e);
tryToClose(conn);
eventBus.broadcast(new ContactExchangeFailedEvent());
}
} }
private byte[] sign(LocalAuthor author, byte[] nonce) { private byte[] sign(LocalAuthor author, byte[] nonce) {
@@ -298,16 +253,6 @@ class ContactExchangeManagerImpl implements ContactExchangeManager {
}); });
} }
private void tryToClose(DuplexTransportConnection conn) {
try {
LOG.info("Closing connection");
conn.getReader().dispose(true, true);
conn.getWriter().dispose(true);
} catch (IOException e) {
logException(LOG, WARNING, e);
}
}
private static class ContactInfo { private static class ContactInfo {
private final Author author; private final Author author;

View File

@@ -7,58 +7,63 @@ import android.arch.lifecycle.MutableLiveData;
import android.support.annotation.UiThread; import android.support.annotation.UiThread;
import org.briarproject.bramble.api.contact.ContactExchangeManager; import org.briarproject.bramble.api.contact.ContactExchangeManager;
import org.briarproject.bramble.api.contact.event.ContactExchangeFailedEvent;
import org.briarproject.bramble.api.contact.event.ContactExchangeSucceededEvent;
import org.briarproject.bramble.api.crypto.SecretKey; import org.briarproject.bramble.api.crypto.SecretKey;
import org.briarproject.bramble.api.event.Event; import org.briarproject.bramble.api.db.ContactExistsException;
import org.briarproject.bramble.api.event.EventBus; import org.briarproject.bramble.api.db.DbException;
import org.briarproject.bramble.api.event.EventListener;
import org.briarproject.bramble.api.identity.Author; import org.briarproject.bramble.api.identity.Author;
import org.briarproject.bramble.api.lifecycle.IoExecutor; import org.briarproject.bramble.api.lifecycle.IoExecutor;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault; import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import org.briarproject.bramble.api.plugin.TransportId; import org.briarproject.bramble.api.plugin.TransportId;
import org.briarproject.bramble.api.plugin.duplex.DuplexTransportConnection; import org.briarproject.bramble.api.plugin.duplex.DuplexTransportConnection;
import java.io.IOException;
import java.util.concurrent.Executor; import java.util.concurrent.Executor;
import java.util.logging.Logger;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import javax.inject.Inject; import javax.inject.Inject;
import static java.util.Objects.requireNonNull; import static java.util.logging.Level.WARNING;
import static java.util.logging.Logger.getLogger;
import static org.briarproject.bramble.util.LogUtils.logException;
@NotNullByDefault @NotNullByDefault
class ContactExchangeViewModel extends AndroidViewModel class ContactExchangeViewModel extends AndroidViewModel {
implements EventListener {
private static final Logger LOG =
getLogger(ContactExchangeViewModel.class.getName());
private final Executor ioExecutor; private final Executor ioExecutor;
private final ContactExchangeManager contactExchangeManager; private final ContactExchangeManager contactExchangeManager;
private final EventBus eventBus;
private final MutableLiveData<Boolean> succeeded = new MutableLiveData<>(); private final MutableLiveData<Boolean> succeeded = new MutableLiveData<>();
@Nullable @Nullable
private Author remoteAuthor, duplicateAuthor; private volatile Author remoteAuthor, duplicateAuthor;
@Inject @Inject
ContactExchangeViewModel(Application app, @IoExecutor Executor ioExecutor, ContactExchangeViewModel(Application app, @IoExecutor Executor ioExecutor,
ContactExchangeManager contactExchangeManager, EventBus eventBus) { ContactExchangeManager contactExchangeManager) {
super(app); super(app);
this.ioExecutor = ioExecutor; this.ioExecutor = ioExecutor;
this.contactExchangeManager = contactExchangeManager; this.contactExchangeManager = contactExchangeManager;
this.eventBus = eventBus;
eventBus.addListener(this);
}
@Override
protected void onCleared() {
super.onCleared();
eventBus.removeListener(this);
} }
@UiThread @UiThread
void startContactExchange(TransportId t, DuplexTransportConnection conn, void startContactExchange(TransportId t, DuplexTransportConnection conn,
SecretKey masterKey, boolean alice) { SecretKey masterKey, boolean alice) {
ioExecutor.execute(() -> contactExchangeManager.exchangeContacts(t, ioExecutor.execute(() -> {
conn, masterKey, alice)); try {
remoteAuthor = contactExchangeManager.exchangeContacts(t, conn,
masterKey, alice);
succeeded.postValue(true);
} catch (ContactExistsException e) {
duplicateAuthor = e.getRemoteAuthor();
succeeded.postValue(false);
} catch (DbException | IOException e) {
logException(LOG, WARNING, e);
succeeded.postValue(false);
}
});
} }
@UiThread @UiThread
@@ -76,18 +81,4 @@ class ContactExchangeViewModel extends AndroidViewModel
LiveData<Boolean> getSucceeded() { LiveData<Boolean> getSucceeded() {
return succeeded; return succeeded;
} }
@Override
public void eventOccurred(Event e) {
if (e instanceof ContactExchangeSucceededEvent) {
ContactExchangeSucceededEvent c = (ContactExchangeSucceededEvent) e;
remoteAuthor = c.getRemoteAuthor();
succeeded.setValue(true);
} else if (e instanceof ContactExchangeFailedEvent) {
ContactExchangeFailedEvent c = (ContactExchangeFailedEvent) e;
if (c.wasDuplicateContact())
duplicateAuthor = requireNonNull(c.getDuplicateRemoteAuthor());
succeeded.setValue(false);
}
}
} }