diff --git a/briar-core/src/main/java/org/briarproject/briar/client/BdfIncomingMessageHook.java b/bramble-api/src/main/java/org/briarproject/bramble/api/client/BdfIncomingMessageHook.java similarity index 98% rename from briar-core/src/main/java/org/briarproject/briar/client/BdfIncomingMessageHook.java rename to bramble-api/src/main/java/org/briarproject/bramble/api/client/BdfIncomingMessageHook.java index edc62948dd5681e84bd72f1834b6158f31833d30..30de75695139f7bda1f5bd0687b6234fadd56ab3 100644 --- a/briar-core/src/main/java/org/briarproject/briar/client/BdfIncomingMessageHook.java +++ b/bramble-api/src/main/java/org/briarproject/bramble/api/client/BdfIncomingMessageHook.java @@ -1,4 +1,4 @@ -package org.briarproject.briar.client; +package org.briarproject.bramble.api.client; import org.briarproject.bramble.api.FormatException; import org.briarproject.bramble.api.client.ClientHelper; diff --git a/briar-api/src/main/java/org/briarproject/briar/api/client/ProtocolStateException.java b/bramble-api/src/main/java/org/briarproject/bramble/api/client/ProtocolStateException.java similarity index 89% rename from briar-api/src/main/java/org/briarproject/briar/api/client/ProtocolStateException.java rename to bramble-api/src/main/java/org/briarproject/bramble/api/client/ProtocolStateException.java index a879e912d8ede480ba1a37127e59f3b1713ded66..3672e091fab75b27d8f7f019a763e8275fcc6327 100644 --- a/briar-api/src/main/java/org/briarproject/briar/api/client/ProtocolStateException.java +++ b/bramble-api/src/main/java/org/briarproject/bramble/api/client/ProtocolStateException.java @@ -1,4 +1,4 @@ -package org.briarproject.briar.api.client; +package org.briarproject.bramble.api.client; import org.briarproject.bramble.api.db.DbException; diff --git a/briar-api/src/main/java/org/briarproject/briar/api/client/SessionId.java b/bramble-api/src/main/java/org/briarproject/bramble/api/client/SessionId.java similarity index 91% rename from briar-api/src/main/java/org/briarproject/briar/api/client/SessionId.java rename to bramble-api/src/main/java/org/briarproject/bramble/api/client/SessionId.java index d569bdfec8c2e8d941fdf92b41df9c58df8b903b..e350327d833194667335c476bcd012c2966eeae2 100644 --- a/briar-api/src/main/java/org/briarproject/briar/api/client/SessionId.java +++ b/bramble-api/src/main/java/org/briarproject/bramble/api/client/SessionId.java @@ -1,4 +1,4 @@ -package org.briarproject.briar.api.client; +package org.briarproject.bramble.api.client; import org.briarproject.bramble.api.UniqueId; import org.briarproject.bramble.api.nullsafety.NotNullByDefault; diff --git a/bramble-api/src/main/java/org/briarproject/bramble/api/contact/ContactFactory.java b/bramble-api/src/main/java/org/briarproject/bramble/api/contact/ContactFactory.java index b12c19c9927b4ff4b00668daaa047cde8d0a9e4f..ab3eb6eaeb29cb95f7ae4036c9f758bf3849e0e9 100644 --- a/bramble-api/src/main/java/org/briarproject/bramble/api/contact/ContactFactory.java +++ b/bramble-api/src/main/java/org/briarproject/bramble/api/contact/ContactFactory.java @@ -19,6 +19,9 @@ public interface ContactFactory { case MAILBOX_OWNER: return new MailboxOwner(c, author, localAuthorId, verified, active); + case CONTACT_MAILBOX: + return new ContactMailbox(c, author, localAuthorId, verified, + active); default: throw new IllegalArgumentException("Unknown contact type"); } diff --git a/bramble-api/src/main/java/org/briarproject/bramble/api/contact/ContactMailbox.java b/bramble-api/src/main/java/org/briarproject/bramble/api/contact/ContactMailbox.java new file mode 100644 index 0000000000000000000000000000000000000000..6a044b94b79f3ce1648ab62ff91064308832176c --- /dev/null +++ b/bramble-api/src/main/java/org/briarproject/bramble/api/contact/ContactMailbox.java @@ -0,0 +1,26 @@ +package org.briarproject.bramble.api.contact; + +import org.briarproject.bramble.api.identity.Author; +import org.briarproject.bramble.api.identity.AuthorId; +import org.briarproject.bramble.api.nullsafety.NotNullByDefault; + +import javax.annotation.concurrent.Immutable; + +import static org.briarproject.bramble.api.contact.ContactType.CONTACT_MAILBOX; + +@Immutable +@NotNullByDefault +public class ContactMailbox extends Contact { + + public ContactMailbox(ContactId id, + Author author, + AuthorId localAuthorId, + boolean verified, boolean active) { + super(id, author, localAuthorId, verified, active); + } + + @Override + public ContactType getType() { + return CONTACT_MAILBOX; + } +} diff --git a/bramble-api/src/main/java/org/briarproject/bramble/api/contact/ContactManager.java b/bramble-api/src/main/java/org/briarproject/bramble/api/contact/ContactManager.java index d8693d79fd046ef5acb5ca8329885427b80b7512..5b87dc30395021783f424233bf9eabc924980892 100644 --- a/bramble-api/src/main/java/org/briarproject/bramble/api/contact/ContactManager.java +++ b/bramble-api/src/main/java/org/briarproject/bramble/api/contact/ContactManager.java @@ -49,6 +49,10 @@ public interface ContactManager { long timestamp, boolean alice, boolean verified, boolean active) throws DbException; + ContactId addPrivateMailbox(Author remote, AuthorId local, SecretKey master, + long timestamp, boolean alice) + throws DbException; + /** * Add a private Mailbox */ @@ -58,6 +62,14 @@ public interface ContactManager { ContactId addMailboxOwner(Transaction txn, Author remote, AuthorId local, SecretKey master, long timestamp, boolean alice) throws DbException; + ContactId addMailboxOwner(Author remote, AuthorId local, + SecretKey secretKey, long currentTimeMillis, boolean alice) + throws DbException; + + ContactId addContactMailbox(Transaction txn, Author remote, + AuthorId local, SecretKey master, long timestamp, boolean alice) + throws DbException; + /** * Returns the contact with the given ID. */ @@ -96,6 +108,8 @@ public interface ContactManager { */ PrivateMailbox getPrivateMailbox() throws DbException; + PrivateMailbox getPrivateMailbox(Transaction txn) throws DbException; + /** * Removes a contact and all associated state. */ @@ -124,7 +138,6 @@ public interface ContactManager { boolean contactExists(AuthorId remoteAuthorId, AuthorId localAuthorId) throws DbException; - interface ContactHook { Collection<ContactType> getApplicableContactTypes(); diff --git a/bramble-api/src/main/java/org/briarproject/bramble/api/db/DatabaseConfig.java b/bramble-api/src/main/java/org/briarproject/bramble/api/db/DatabaseConfig.java index f096f1fec8e99185d0679846e536613525e38ec0..0df7b80a7dfdbafd3c082d620b6b1e65abbe0983 100644 --- a/bramble-api/src/main/java/org/briarproject/bramble/api/db/DatabaseConfig.java +++ b/bramble-api/src/main/java/org/briarproject/bramble/api/db/DatabaseConfig.java @@ -12,4 +12,5 @@ public interface DatabaseConfig { File getDatabaseKeyDirectory(); long getMaxSize(); + } diff --git a/bramble-api/src/main/java/org/briarproject/bramble/api/mailbox/IntroductionConstants.java b/bramble-api/src/main/java/org/briarproject/bramble/api/mailbox/IntroductionConstants.java new file mode 100644 index 0000000000000000000000000000000000000000..6513098827cf9b4a9a256f868712200323d3e392 --- /dev/null +++ b/bramble-api/src/main/java/org/briarproject/bramble/api/mailbox/IntroductionConstants.java @@ -0,0 +1,24 @@ +package org.briarproject.bramble.api.mailbox; + +public interface IntroductionConstants { + + String LABEL_SESSION_ID = "org.briarproject.briar.introduction/SESSION_ID"; + + String LABEL_MASTER_KEY = "org.briarproject.briar.introduction/MASTER_KEY"; + + String LABEL_ALICE_MAC_KEY = + "org.briarproject.briar.introduction/ALICE_MAC_KEY"; + + String LABEL_BOB_MAC_KEY = + "org.briarproject.briar.introduction/BOB_MAC_KEY"; + + String LABEL_AUTH_MAC = "org.briarproject.briar.introduction/AUTH_MAC"; + + String LABEL_AUTH_SIGN = "org.briarproject.briar.introduction/AUTH_SIGN"; + + String LABEL_AUTH_NONCE = "org.briarproject.briar.introduction/AUTH_NONCE"; + + String LABEL_ACTIVATE_MAC = + "org.briarproject.briar.introduction/ACTIVATE_MAC"; + +} diff --git a/bramble-api/src/main/java/org/briarproject/bramble/api/mailbox/MailboxIntroductionManager.java b/bramble-api/src/main/java/org/briarproject/bramble/api/mailbox/MailboxIntroductionManager.java new file mode 100644 index 0000000000000000000000000000000000000000..ca912d551dba6ca781a548ab57d9acea114d9192 --- /dev/null +++ b/bramble-api/src/main/java/org/briarproject/bramble/api/mailbox/MailboxIntroductionManager.java @@ -0,0 +1,40 @@ +package org.briarproject.bramble.api.mailbox; + +import org.briarproject.bramble.api.contact.Contact; +import org.briarproject.bramble.api.contact.PrivateMailbox; +import org.briarproject.bramble.api.db.DbException; +import org.briarproject.bramble.api.db.Transaction; +import org.briarproject.bramble.api.sync.ClientId; +import org.briarproject.bramble.api.sync.Group; + +public interface MailboxIntroductionManager { + /** + * The unique ID of the introduction client. + */ + ClientId CLIENT_ID = + new ClientId("org.briarproject.briar.mailbox.introduction"); + + /** + * The current major version of the introduction client. + */ + int MAJOR_VERSION = 1; + + /** + * The current minor version of the introduction client. + */ + int MINOR_VERSION = 0; + + void contactAdded(Transaction txn, Contact contact) throws DbException; + + void privateMailboxAdded(Transaction txn, PrivateMailbox privateMailbox) + throws DbException; + + /** + * Sends two initial introduction messages. + */ + void makeIntroduction(PrivateMailbox privateMailbox, Contact contact, long timestamp) + throws DbException; + + + Group getContactGroup(Contact c); +} diff --git a/bramble-api/src/main/java/org/briarproject/bramble/api/mailbox/Role.java b/bramble-api/src/main/java/org/briarproject/bramble/api/mailbox/Role.java new file mode 100644 index 0000000000000000000000000000000000000000..df8655b9a109d7c737a3a87c821b0cc7ac85b23e --- /dev/null +++ b/bramble-api/src/main/java/org/briarproject/bramble/api/mailbox/Role.java @@ -0,0 +1,29 @@ +package org.briarproject.bramble.api.mailbox; + +import org.briarproject.bramble.api.FormatException; +import org.briarproject.bramble.api.nullsafety.NotNullByDefault; + +import javax.annotation.concurrent.Immutable; + +@Immutable +@NotNullByDefault +public enum Role { + + OWNER(0), MAILBOX(1), INTRODUCEE(2); + + private final int value; + + Role(int value) { + this.value = value; + } + + public int getValue() { + return value; + } + + public static Role fromValue(int value) throws FormatException { + for (Role r : values()) if (r.value == value) return r; + throw new FormatException(); + } + +} diff --git a/bramble-api/src/main/java/org/briarproject/bramble/api/mailbox/event/MailboxIntroductionAbortedEvent.java b/bramble-api/src/main/java/org/briarproject/bramble/api/mailbox/event/MailboxIntroductionAbortedEvent.java new file mode 100644 index 0000000000000000000000000000000000000000..38e36fa4628f5c1237459f0cebb32302308155f7 --- /dev/null +++ b/bramble-api/src/main/java/org/briarproject/bramble/api/mailbox/event/MailboxIntroductionAbortedEvent.java @@ -0,0 +1,22 @@ +package org.briarproject.bramble.api.mailbox.event; + +import org.briarproject.bramble.api.event.Event; +import org.briarproject.bramble.api.nullsafety.NotNullByDefault; +import org.briarproject.bramble.api.client.SessionId; + +import javax.annotation.concurrent.Immutable; + +@Immutable +@NotNullByDefault +public class MailboxIntroductionAbortedEvent extends Event { + + private SessionId sessionId; + + public MailboxIntroductionAbortedEvent(SessionId sessionId) { + this.sessionId = sessionId; + } + + public SessionId getSessionId() { + return sessionId; + } +} diff --git a/bramble-api/src/main/java/org/briarproject/bramble/api/mailbox/event/MailboxIntroductionRequestReceivedEvent.java b/bramble-api/src/main/java/org/briarproject/bramble/api/mailbox/event/MailboxIntroductionRequestReceivedEvent.java new file mode 100644 index 0000000000000000000000000000000000000000..a690247f77de8a4aca896dae54c40c91cdb79307 --- /dev/null +++ b/bramble-api/src/main/java/org/briarproject/bramble/api/mailbox/event/MailboxIntroductionRequestReceivedEvent.java @@ -0,0 +1,24 @@ +package org.briarproject.bramble.api.mailbox.event; + +import org.briarproject.bramble.api.event.Event; +import org.briarproject.bramble.api.identity.AuthorId; +import org.briarproject.bramble.api.nullsafety.NotNullByDefault; + +import javax.annotation.concurrent.Immutable; + +@Immutable +@NotNullByDefault +public class MailboxIntroductionRequestReceivedEvent extends Event { + + private final AuthorId contactId; + + public MailboxIntroductionRequestReceivedEvent(AuthorId contactId) { + this.contactId = contactId; + + } + + public AuthorId getAuthorId() { + return contactId; + } + +} diff --git a/bramble-api/src/main/java/org/briarproject/bramble/api/mailbox/event/MailboxIntroductionResponseReceivedEvent.java b/bramble-api/src/main/java/org/briarproject/bramble/api/mailbox/event/MailboxIntroductionResponseReceivedEvent.java new file mode 100644 index 0000000000000000000000000000000000000000..3f655215ed6d103580a7199a59e7bc0b72f30ba6 --- /dev/null +++ b/bramble-api/src/main/java/org/briarproject/bramble/api/mailbox/event/MailboxIntroductionResponseReceivedEvent.java @@ -0,0 +1,29 @@ +package org.briarproject.bramble.api.mailbox.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.concurrent.Immutable; + +@Immutable +@NotNullByDefault +public class MailboxIntroductionResponseReceivedEvent extends Event { + + private final Author from; + private final Author to; + + public MailboxIntroductionResponseReceivedEvent(Author from, Author to) { + this.from = from; + this.to = to; + } + + + public Author getFrom() { + return from; + } + + public Author getTo() { + return to; + } +} diff --git a/bramble-api/src/main/java/org/briarproject/bramble/api/mailbox/event/MailboxIntroductionSucceededEvent.java b/bramble-api/src/main/java/org/briarproject/bramble/api/mailbox/event/MailboxIntroductionSucceededEvent.java new file mode 100644 index 0000000000000000000000000000000000000000..df6cb7b8b4e52de7c114a7c02522cef59c4106f9 --- /dev/null +++ b/bramble-api/src/main/java/org/briarproject/bramble/api/mailbox/event/MailboxIntroductionSucceededEvent.java @@ -0,0 +1,22 @@ +package org.briarproject.bramble.api.mailbox.event; + +import org.briarproject.bramble.api.contact.Contact; +import org.briarproject.bramble.api.event.Event; +import org.briarproject.bramble.api.nullsafety.NotNullByDefault; + +import javax.annotation.concurrent.Immutable; + +@Immutable +@NotNullByDefault +public class MailboxIntroductionSucceededEvent extends Event { + + private final Contact contact; + + public MailboxIntroductionSucceededEvent(Contact contact) { + this.contact = contact; + } + + public Contact getContact() { + return contact; + } +} diff --git a/bramble-api/src/main/java/org/briarproject/bramble/api/properties/TransportPropertyManager.java b/bramble-api/src/main/java/org/briarproject/bramble/api/properties/TransportPropertyManager.java index 1c64f5b6d957d62e389206715d48253ff965de30..164d1f5a2900abd9a70ed2dbacd2e4397830b5c7 100644 --- a/bramble-api/src/main/java/org/briarproject/bramble/api/properties/TransportPropertyManager.java +++ b/bramble-api/src/main/java/org/briarproject/bramble/api/properties/TransportPropertyManager.java @@ -35,6 +35,10 @@ public interface TransportPropertyManager { void addRemoteProperties(Transaction txn, ContactId c, Map<TransportId, TransportProperties> props) throws DbException; + Map<TransportId, TransportProperties> getLocalAnonymizedProperties( + Transaction txn) + throws DbException; + /** * Returns the local transport properties for all transports. */ diff --git a/bramble-core/build.gradle b/bramble-core/build.gradle index eec6c43879d0f21c83332d5764d8bf182360a6da..e0e54ac4f01978ee6e920484e87b88b21d5dcc0b 100644 --- a/bramble-core/build.gradle +++ b/bramble-core/build.gradle @@ -22,6 +22,7 @@ dependencies { testImplementation project(path: ':bramble-api', configuration: 'testOutput') testImplementation 'org.hsqldb:hsqldb:2.3.5' // The last version that supports Java 1.6 testImplementation 'junit:junit:4.12' + testImplementation 'net.jodah:concurrentunit:0.4.2' testImplementation "org.jmock:jmock:2.8.2" testImplementation "org.jmock:jmock-junit4:2.8.2" testImplementation "org.jmock:jmock-legacy:2.8.2" diff --git a/bramble-core/src/main/java/org/briarproject/bramble/contact/ContactManagerImpl.java b/bramble-core/src/main/java/org/briarproject/bramble/contact/ContactManagerImpl.java index 976f270f8d2baca22ebb103722fbd16b96da03ec..c600e3a21fdbbe93223abfe0541f11743ed78993 100644 --- a/bramble-core/src/main/java/org/briarproject/bramble/contact/ContactManagerImpl.java +++ b/bramble-core/src/main/java/org/briarproject/bramble/contact/ContactManagerImpl.java @@ -24,6 +24,7 @@ import javax.annotation.concurrent.ThreadSafe; import javax.inject.Inject; import static org.briarproject.bramble.api.contact.ContactType.CONTACT; +import static org.briarproject.bramble.api.contact.ContactType.CONTACT_MAILBOX; import static org.briarproject.bramble.api.contact.ContactType.MAILBOX_OWNER; import static org.briarproject.bramble.api.contact.ContactType.PRIVATE_MAILBOX; @@ -91,6 +92,22 @@ class ContactManagerImpl implements ContactManager { return c; } + @Override + public ContactId addPrivateMailbox(Author remote, AuthorId local, + SecretKey master, + long timestamp, boolean alice) + throws DbException { + ContactId c; + Transaction txn = db.startTransaction(false); + try { + c = addPrivateMailbox(txn, remote, local, master, timestamp, alice); + db.commitTransaction(txn); + } finally { + db.endTransaction(txn); + } + return c; + } + @Override public ContactId addPrivateMailbox(Transaction txn, Author remote, AuthorId local, SecretKey master, long timestamp, boolean alice) @@ -106,6 +123,22 @@ class ContactManagerImpl implements ContactManager { return c; } + + @Override + public ContactId addMailboxOwner(Author remote, AuthorId local, + SecretKey master, long timestamp, boolean alice) + throws DbException { + ContactId c; + Transaction txn = db.startTransaction(false); + try { + c = addMailboxOwner(txn, remote, local, master, timestamp, alice); + db.commitTransaction(txn); + } finally { + db.endTransaction(txn); + } + return c; + } + @Override public ContactId addMailboxOwner(Transaction txn, Author remote, AuthorId local, SecretKey master, long timestamp, boolean alice) @@ -121,6 +154,21 @@ class ContactManagerImpl implements ContactManager { return c; } + @Override + public ContactId addContactMailbox(Transaction txn, Author remote, + AuthorId local, SecretKey master, long timestamp, boolean alice) + throws DbException { + ContactId c = db.addContact(txn, remote, local, false, true, + CONTACT_MAILBOX); + //keyManager.addContact(txn, c, master, timestamp, alice, true); + Contact contact = db.getContact(txn, c); + for (ContactHook hook : hooks) { + if (hook.getApplicableContactTypes().contains(contact.getType())) + hook.addingContact(txn, contact); + } + return c; + } + @Override public Contact getContact(ContactId c) throws DbException { Contact contact; @@ -181,7 +229,7 @@ class ContactManagerImpl implements ContactManager { Collection<Contact> contacts; Transaction txn = db.startTransaction(true); try { - contacts = db.getContactsByType(txn, type); + contacts = getContactsByType(txn, type); db.commitTransaction(txn); } finally { db.endTransaction(txn); @@ -189,6 +237,11 @@ class ContactManagerImpl implements ContactManager { return contacts; } + private Collection<Contact> getContactsByType(Transaction txn, + ContactType type) throws DbException { + return db.getContactsByType(txn, type); + } + @Override public PrivateMailbox getPrivateMailbox() throws DbException { Collection<Contact> privateMailbox = getContactsByType(PRIVATE_MAILBOX); @@ -197,6 +250,16 @@ class ContactManagerImpl implements ContactManager { return (PrivateMailbox) privateMailbox.iterator().next(); } + @Override + public PrivateMailbox getPrivateMailbox(Transaction txn) + throws DbException { + Collection<Contact> privateMailbox = + getContactsByType(txn, PRIVATE_MAILBOX); + if (privateMailbox.isEmpty()) + return null; + return (PrivateMailbox) privateMailbox.iterator().next(); + } + @Override public void removeContact(ContactId c) throws DbException { Transaction txn = db.startTransaction(false); diff --git a/bramble-core/src/main/java/org/briarproject/bramble/db/JdbcDatabase.java b/bramble-core/src/main/java/org/briarproject/bramble/db/JdbcDatabase.java index 132f3b8de0c1a42aaad7f4257d26643236c9027f..a185633c75f8b76bc800050846075aab4f022122 100644 --- a/bramble-core/src/main/java/org/briarproject/bramble/db/JdbcDatabase.java +++ b/bramble-core/src/main/java/org/briarproject/bramble/db/JdbcDatabase.java @@ -996,7 +996,7 @@ abstract class JdbcDatabase implements Database<Connection> { ps = txn.prepareStatement(sql); ps.setInt(1, contactId.getInt()); if (mailboxId == null) ps.setNull(2, INTEGER); - else ps.setInt(1, mailboxId.getInt()); + else ps.setInt(2, mailboxId.getInt()); if (aliasId == null) ps.setNull(3, INTEGER); else ps.setInt(3, aliasId.getInt()); int affected = ps.executeUpdate(); diff --git a/bramble-core/src/main/java/org/briarproject/bramble/mailbox/introduction/AbortMessage.java b/bramble-core/src/main/java/org/briarproject/bramble/mailbox/introduction/AbortMessage.java new file mode 100644 index 0000000000000000000000000000000000000000..02bd625a5599f738c5d752e2838da56b21338888 --- /dev/null +++ b/bramble-core/src/main/java/org/briarproject/bramble/mailbox/introduction/AbortMessage.java @@ -0,0 +1,27 @@ +package org.briarproject.bramble.mailbox.introduction; + +import org.briarproject.bramble.api.client.SessionId; +import org.briarproject.bramble.api.nullsafety.NotNullByDefault; +import org.briarproject.bramble.api.sync.GroupId; +import org.briarproject.bramble.api.sync.MessageId; + +import javax.annotation.Nullable; +import javax.annotation.concurrent.Immutable; + +@Immutable +@NotNullByDefault +class AbortMessage extends AbstractMailboxIntroductionMessage { + + private final SessionId sessionId; + + protected AbortMessage(MessageId messageId, GroupId groupId, long timestamp, + @Nullable MessageId previousMessageId, SessionId sessionId) { + super(messageId, groupId, timestamp, previousMessageId); + this.sessionId = sessionId; + } + + public SessionId getSessionId() { + return sessionId; + } + +} diff --git a/bramble-core/src/main/java/org/briarproject/bramble/mailbox/introduction/AbstractIntroduceeSession.java b/bramble-core/src/main/java/org/briarproject/bramble/mailbox/introduction/AbstractIntroduceeSession.java new file mode 100644 index 0000000000000000000000000000000000000000..438bc62cbc9a375e488106fb070827a908728355 --- /dev/null +++ b/bramble-core/src/main/java/org/briarproject/bramble/mailbox/introduction/AbstractIntroduceeSession.java @@ -0,0 +1,156 @@ +package org.briarproject.bramble.mailbox.introduction; + +import org.briarproject.bramble.api.client.SessionId; +import org.briarproject.bramble.api.identity.Author; +import org.briarproject.bramble.api.nullsafety.NotNullByDefault; +import org.briarproject.bramble.api.plugin.TransportId; +import org.briarproject.bramble.api.properties.TransportProperties; +import org.briarproject.bramble.api.sync.GroupId; +import org.briarproject.bramble.api.sync.MessageId; +import org.briarproject.bramble.api.transport.KeySetId; + +import java.util.Map; + +import javax.annotation.Nullable; +import javax.annotation.concurrent.Immutable; + +@Immutable +@NotNullByDefault +abstract class AbstractIntroduceeSession<S extends State> extends Session<S> + implements PeerSession { + + final GroupId contactGroupId; + final Author introducer; + final Local local; + final Remote remote; + @Nullable + final byte[] masterKey; + @Nullable + final Map<TransportId, KeySetId> transportKeys; + + AbstractIntroduceeSession(SessionId sessionId, S state, + long requestTimestamp, GroupId contactGroupId, Author introducer, + Local local, Remote remote, @Nullable byte[] masterKey, + @Nullable Map<TransportId, KeySetId> transportKeys, + long abortCounter) { + super(sessionId, state, requestTimestamp, abortCounter); + this.contactGroupId = contactGroupId; + this.introducer = introducer; + this.local = local; + this.remote = remote; + this.masterKey = masterKey; + this.transportKeys = transportKeys; + } + + @Override + public GroupId getContactGroupId() { + return contactGroupId; + } + + @Override + public long getLocalTimestamp() { + return local.lastMessageTimestamp; + } + + @Nullable + @Override + public MessageId getLastLocalMessageId() { + return local.lastMessageId; + } + + Author getIntroducer() { + return introducer; + } + + Local getLocal() { + return local; + } + + Remote getRemote() { + return remote; + } + + @Nullable + byte[] getMasterKey() { + return masterKey; + } + + @Nullable + Map<TransportId, KeySetId> getTransportKeys() { + return transportKeys; + } + + @Nullable + @Override + public MessageId getLastRemoteMessageId() { + return remote.lastMessageId; + } + + abstract static class Common { + final boolean alice; + @Nullable + final MessageId lastMessageId; + @Nullable + final byte[] ephemeralPublicKey; + + final long acceptTimestamp; + @Nullable + final byte[] macKey; + + private Common(boolean alice, @Nullable MessageId lastMessageId, + @Nullable byte[] ephemeralPublicKey, + @Nullable long acceptTimestamp, @Nullable byte[] macKey) { + this.alice = alice; + this.lastMessageId = lastMessageId; + this.ephemeralPublicKey = ephemeralPublicKey; + this.acceptTimestamp = acceptTimestamp; + this.macKey = macKey; + } + } + + static class Local extends Common { + final long lastMessageTimestamp; + @Nullable + final byte[] ephemeralPrivateKey; + + Local(Local s, @Nullable MessageId lastMessageId, + long lastMessageTimestamp) { + this(s.alice, lastMessageId, lastMessageTimestamp, + s.ephemeralPublicKey, s.ephemeralPrivateKey, + s.acceptTimestamp, s.macKey); + } + + Local(boolean alice, @Nullable MessageId lastMessageId, + long lastMessageTimestamp, @Nullable byte[] ephemeralPublicKey, + @Nullable byte[] ephemeralPrivateKey, long acceptTimestamp, + @Nullable byte[] macKey) { + super(alice, lastMessageId, ephemeralPublicKey, acceptTimestamp, + macKey); + this.lastMessageTimestamp = lastMessageTimestamp; + this.ephemeralPrivateKey = ephemeralPrivateKey; + } + } + + static class Remote extends Common { + final Author author; + @Nullable + final Map<TransportId, TransportProperties> transportProperties; + + Remote(Remote s, @Nullable MessageId lastMessageId) { + this(s.alice, s.author, lastMessageId, s.ephemeralPublicKey, + s.transportProperties, s.acceptTimestamp, s.macKey); + } + + Remote(boolean alice, Author author, @Nullable MessageId lastMessageId, + @Nullable byte[] ephemeralPublicKey, @Nullable + Map<TransportId, TransportProperties> transportProperties, + long acceptTimestamp, @Nullable byte[] macKey) { + super(alice, lastMessageId, ephemeralPublicKey, acceptTimestamp, + macKey); + this.author = author; + this.transportProperties = transportProperties; + } + + } + +} diff --git a/bramble-core/src/main/java/org/briarproject/bramble/mailbox/introduction/AbstractMailboxIntroductionMessage.java b/bramble-core/src/main/java/org/briarproject/bramble/mailbox/introduction/AbstractMailboxIntroductionMessage.java new file mode 100644 index 0000000000000000000000000000000000000000..f498ce7667cc3f0b49e673be8f1290cc8b9df775 --- /dev/null +++ b/bramble-core/src/main/java/org/briarproject/bramble/mailbox/introduction/AbstractMailboxIntroductionMessage.java @@ -0,0 +1,45 @@ +package org.briarproject.bramble.mailbox.introduction; + +import org.briarproject.bramble.api.nullsafety.NotNullByDefault; +import org.briarproject.bramble.api.sync.GroupId; +import org.briarproject.bramble.api.sync.MessageId; + +import javax.annotation.Nullable; +import javax.annotation.concurrent.Immutable; + +@Immutable +@NotNullByDefault +abstract class AbstractMailboxIntroductionMessage { + + private final MessageId messageId; + private final GroupId groupId; + private final long timestamp; + @Nullable + private final MessageId previousMessageId; + + AbstractMailboxIntroductionMessage(MessageId messageId, GroupId groupId, + long timestamp, @Nullable MessageId previousMessageId) { + this.messageId = messageId; + this.groupId = groupId; + this.timestamp = timestamp; + this.previousMessageId = previousMessageId; + } + + MessageId getMessageId() { + return messageId; + } + + GroupId getGroupId() { + return groupId; + } + + long getTimestamp() { + return timestamp; + } + + @Nullable + MessageId getPreviousMessageId() { + return previousMessageId; + } + +} diff --git a/bramble-core/src/main/java/org/briarproject/bramble/mailbox/introduction/AbstractProtocolEngine.java b/bramble-core/src/main/java/org/briarproject/bramble/mailbox/introduction/AbstractProtocolEngine.java new file mode 100644 index 0000000000000000000000000000000000000000..8a998aa5eeb5c643951f7b168c9eba87d71378eb --- /dev/null +++ b/bramble-core/src/main/java/org/briarproject/bramble/mailbox/introduction/AbstractProtocolEngine.java @@ -0,0 +1,168 @@ +package org.briarproject.bramble.mailbox.introduction; + +import org.briarproject.bramble.api.FormatException; +import org.briarproject.bramble.api.client.ClientHelper; +import org.briarproject.bramble.api.client.ContactGroupFactory; +import org.briarproject.bramble.api.client.SessionId; +import org.briarproject.bramble.api.contact.ContactManager; +import org.briarproject.bramble.api.data.BdfDictionary; +import org.briarproject.bramble.api.db.DatabaseComponent; +import org.briarproject.bramble.api.db.DbException; +import org.briarproject.bramble.api.db.Transaction; +import org.briarproject.bramble.api.identity.Author; +import org.briarproject.bramble.api.identity.IdentityManager; +import org.briarproject.bramble.api.nullsafety.NotNullByDefault; +import org.briarproject.bramble.api.plugin.TransportId; +import org.briarproject.bramble.api.properties.TransportProperties; +import org.briarproject.bramble.api.properties.TransportPropertyManager; +import org.briarproject.bramble.api.sync.Message; +import org.briarproject.bramble.api.sync.MessageId; +import org.briarproject.bramble.api.system.Clock; +import org.briarproject.bramble.api.transport.KeyManager; + +import java.util.Map; + +import javax.annotation.Nullable; +import javax.annotation.concurrent.Immutable; + +import static org.briarproject.bramble.mailbox.introduction.MessageType.ABORT; +import static org.briarproject.bramble.mailbox.introduction.MessageType.DECLINE; +import static org.briarproject.bramble.mailbox.introduction.MessageType.INTRODUCEE_ACCEPT; +import static org.briarproject.bramble.mailbox.introduction.MessageType.MAILBOX_ACCEPT; +import static org.briarproject.bramble.mailbox.introduction.MessageType.MAILBOX_AUTH; +import static org.briarproject.bramble.mailbox.introduction.MessageType.MAILBOX_REQUEST; + +@Immutable +@NotNullByDefault +abstract class AbstractProtocolEngine<S extends Session> + implements ProtocolEngine<S> { + + protected final DatabaseComponent db; + protected final ClientHelper clientHelper; + protected final ContactManager contactManager; + protected final ContactGroupFactory contactGroupFactory; + protected final IdentityManager identityManager; + protected final MailboxMessageParser messageParser; + protected final MailboxMessageEncoder messageEncoder; + protected final Clock clock; + protected final MailboxIntroductionCrypto crypto; + protected final KeyManager keyManager; + protected final TransportPropertyManager transportPropertyManager; + + AbstractProtocolEngine(DatabaseComponent db, ClientHelper clientHelper, + ContactManager contactManager, + ContactGroupFactory contactGroupFactory, + IdentityManager identityManager, MailboxMessageParser messageParser, + MailboxMessageEncoder messageEncoder, Clock clock, + MailboxIntroductionCrypto crypto, KeyManager keyManager, + TransportPropertyManager transportPropertyManager) { + this.db = db; + this.clientHelper = clientHelper; + this.contactManager = contactManager; + this.contactGroupFactory = contactGroupFactory; + this.identityManager = identityManager; + this.messageParser = messageParser; + this.messageEncoder = messageEncoder; + this.clock = clock; + this.crypto = crypto; + this.keyManager = keyManager; + this.transportPropertyManager = transportPropertyManager; + } + + Message sendMailboxRequestMessage(Transaction txn, PeerSession s, + long timestamp, Author introduceeAuthor) throws DbException { + Message m = messageEncoder + .encodeRequestMessage(s.getContactGroupId(), timestamp, + s.getLastLocalMessageId(), introduceeAuthor, + s.getAbortCounter()); + sendMessage(txn, MAILBOX_REQUEST, s.getSessionId(), m, + s.getAbortCounter()); + return m; + } + + Message sendMailboxAcceptMessage(Transaction txn, PeerSession s, + long timestamp, Author author, byte[] ephemeralPublicKey, + long acceptTimestamp) throws DbException { + Message m = messageEncoder + .encodeMailboxAcceptMessage(s.getContactGroupId(), timestamp, + s.getLastLocalMessageId(), s.getSessionId(), + MAILBOX_ACCEPT, author, ephemeralPublicKey, + acceptTimestamp, s.getAbortCounter()); + sendMessage(txn, MAILBOX_ACCEPT, s.getSessionId(), m, + s.getAbortCounter()); + return m; + } + + Message sendIntroduceeResponseMessage(Transaction txn, PeerSession s, + MessageId previousMessage, long timestamp, + byte[] ephemeralPublicKey, byte[] mac, byte[] signature, + long acceptTimestamp) throws DbException { + Message m = messageEncoder + .encodeIntroduceeAcceptMessage(s.getContactGroupId(), timestamp, + previousMessage, s.getSessionId(), ephemeralPublicKey, + mac, signature, acceptTimestamp, s.getAbortCounter()); + sendMessage(txn, INTRODUCEE_ACCEPT, s.getSessionId(), m, + s.getAbortCounter()); + return m; + } + + Message sendMailboxAuthMessage(Transaction txn, PeerSession s, + long timestamp, + Map<TransportId, TransportProperties> transportProperties, + byte[] mac, byte[] signature) throws DbException { + Message m = messageEncoder + .encodeMailboxAuthMessage(s.getContactGroupId(), timestamp, + s.getLastRemoteMessageId(), s.getSessionId(), + transportProperties, mac, signature, + s.getAbortCounter()); + sendMessage(txn, MAILBOX_AUTH, s.getSessionId(), m, + s.getAbortCounter()); + return m; + } + + Message sendDeclineMessage(Transaction txn, PeerSession s, long timestamp) + throws DbException { + Message m = messageEncoder + .encodeDeclineMessage(s.getContactGroupId(), timestamp, + s.getLastLocalMessageId(), s.getSessionId(), + s.getAbortCounter()); + sendMessage(txn, DECLINE, s.getSessionId(), m, s.getAbortCounter()); + return m; + } + + Message sendAbortMessage(Transaction txn, PeerSession s, long timestamp) + throws DbException { + Message m = messageEncoder + .encodeAbortMessage(s.getContactGroupId(), timestamp, + s.getLastLocalMessageId(), s.getSessionId(), + s.getAbortCounter()); + sendMessage(txn, ABORT, s.getSessionId(), m, s.getAbortCounter()); + return m; + } + + private void sendMessage(Transaction txn, MessageType type, + SessionId sessionId, Message m, long abortCounter) + throws DbException { + BdfDictionary meta = messageEncoder + .encodeMetadata(type, sessionId, m.getTimestamp(), true, + abortCounter); + try { + clientHelper.addLocalMessage(txn, m, meta, true); + } catch (FormatException e) { + throw new AssertionError(e); + } + } + + boolean isInvalidDependency(@Nullable MessageId lastRemoteMessageId, + @Nullable MessageId dependency) { + if (dependency == null) return lastRemoteMessageId != null; + return lastRemoteMessageId == null || + !dependency.equals(lastRemoteMessageId); + } + + long getLocalTimestamp(long localTimestamp, long requestTimestamp) { + return Math.max(clock.currentTimeMillis(), + Math.max(localTimestamp, requestTimestamp) + 1); + } + +} diff --git a/bramble-core/src/main/java/org/briarproject/bramble/mailbox/introduction/DeclineMessage.java b/bramble-core/src/main/java/org/briarproject/bramble/mailbox/introduction/DeclineMessage.java new file mode 100644 index 0000000000000000000000000000000000000000..d7367c467d6db28cb18f147c20b4560ac144ed7d --- /dev/null +++ b/bramble-core/src/main/java/org/briarproject/bramble/mailbox/introduction/DeclineMessage.java @@ -0,0 +1,28 @@ +package org.briarproject.bramble.mailbox.introduction; + +import org.briarproject.bramble.api.client.SessionId; +import org.briarproject.bramble.api.nullsafety.NotNullByDefault; +import org.briarproject.bramble.api.sync.GroupId; +import org.briarproject.bramble.api.sync.MessageId; + +import javax.annotation.Nullable; +import javax.annotation.concurrent.Immutable; + +@Immutable +@NotNullByDefault +class DeclineMessage extends AbstractMailboxIntroductionMessage { + + private final SessionId sessionId; + + protected DeclineMessage(MessageId messageId, GroupId groupId, + long timestamp, @Nullable MessageId previousMessageId, + SessionId sessionId) { + super(messageId, groupId, timestamp, previousMessageId); + this.sessionId = sessionId; + } + + public SessionId getSessionId() { + return sessionId; + } + +} diff --git a/bramble-core/src/main/java/org/briarproject/bramble/mailbox/introduction/Introducee.java b/bramble-core/src/main/java/org/briarproject/bramble/mailbox/introduction/Introducee.java new file mode 100644 index 0000000000000000000000000000000000000000..8494cfdcb8d81c6ae46653ad402b2a4539e9cca1 --- /dev/null +++ b/bramble-core/src/main/java/org/briarproject/bramble/mailbox/introduction/Introducee.java @@ -0,0 +1,83 @@ +package org.briarproject.bramble.mailbox.introduction; + +import org.briarproject.bramble.api.client.SessionId; +import org.briarproject.bramble.api.identity.Author; +import org.briarproject.bramble.api.nullsafety.NotNullByDefault; +import org.briarproject.bramble.api.sync.GroupId; +import org.briarproject.bramble.api.sync.Message; +import org.briarproject.bramble.api.sync.MessageId; + +import javax.annotation.Nullable; +import javax.annotation.concurrent.Immutable; + +@Immutable +@NotNullByDefault +final class Introducee implements PeerSession { + final SessionId sessionId; + final GroupId groupId; + final Author author; + final long localTimestamp; + @Nullable + final MessageId lastLocalMessageId, lastRemoteMessageId; + final long abortCounter; + + Introducee(SessionId sessionId, GroupId groupId, Author author, + long localTimestamp, @Nullable MessageId lastLocalMessageId, + @Nullable MessageId lastRemoteMessageId, long abortCounter) { + this.sessionId = sessionId; + this.groupId = groupId; + this.localTimestamp = localTimestamp; + this.author = author; + this.lastLocalMessageId = lastLocalMessageId; + this.lastRemoteMessageId = lastRemoteMessageId; + this.abortCounter = abortCounter; + } + + Introducee(Introducee i, Message sent, long abortCounter) { + this(i.sessionId, i.groupId, i.author, sent.getTimestamp(), + sent.getId(), i.lastRemoteMessageId, abortCounter); + } + + Introducee(Introducee i, MessageId remoteMessageId, long abortCounter) { + this(i.sessionId, i.groupId, i.author, i.localTimestamp, + i.lastLocalMessageId, remoteMessageId, abortCounter); + } + + Introducee(SessionId sessionId, GroupId groupId, Author author, + long abortCounter) { + this(sessionId, groupId, author, -1, null, null, abortCounter); + } + + public SessionId getSessionId() { + return sessionId; + } + + @Override + public GroupId getContactGroupId() { + return groupId; + } + + @Override + public long getLocalTimestamp() { + return localTimestamp; + } + + @Nullable + @Override + public MessageId getLastLocalMessageId() { + return lastLocalMessageId; + } + + @Nullable + @Override + public MessageId getLastRemoteMessageId() { + return lastRemoteMessageId; + } + + @Override + public long getAbortCounter() { + return abortCounter; + } + +} + diff --git a/bramble-core/src/main/java/org/briarproject/bramble/mailbox/introduction/IntroduceeAcceptMessage.java b/bramble-core/src/main/java/org/briarproject/bramble/mailbox/introduction/IntroduceeAcceptMessage.java new file mode 100644 index 0000000000000000000000000000000000000000..fc34dddc1e2df839c9084a0b37fd1a805461b8e0 --- /dev/null +++ b/bramble-core/src/main/java/org/briarproject/bramble/mailbox/introduction/IntroduceeAcceptMessage.java @@ -0,0 +1,52 @@ +package org.briarproject.bramble.mailbox.introduction; + +import org.briarproject.bramble.api.client.SessionId; +import org.briarproject.bramble.api.nullsafety.NotNullByDefault; +import org.briarproject.bramble.api.sync.GroupId; +import org.briarproject.bramble.api.sync.MessageId; + +import javax.annotation.Nullable; +import javax.annotation.concurrent.Immutable; + +@Immutable +@NotNullByDefault +class IntroduceeAcceptMessage extends AbstractMailboxIntroductionMessage { + + private final SessionId sessionId; + private final byte[] ephemeralPublicKey; + private final long acceptTimestamp; + private final byte[] mac; + private final byte[] signature; + + protected IntroduceeAcceptMessage(MessageId messageId, GroupId groupId, + long timestamp, @Nullable MessageId previousMessageId, + SessionId sessionId, byte[] ephemeralPublicKey, byte[] mac, + byte[] signature, long acceptTimestamp) { + super(messageId, groupId, timestamp, previousMessageId); + this.sessionId = sessionId; + this.ephemeralPublicKey = ephemeralPublicKey; + this.acceptTimestamp = acceptTimestamp; + this.mac = mac; + this.signature = signature; + } + + public SessionId getSessionId() { + return sessionId; + } + + public byte[] getEphemeralPublicKey() { + return ephemeralPublicKey; + } + + public long getAcceptTimestamp() { + return acceptTimestamp; + } + + public byte[] getMac() { + return mac; + } + + public byte[] getSignature() { + return signature; + } +} diff --git a/bramble-core/src/main/java/org/briarproject/bramble/mailbox/introduction/IntroduceeProtocolEngine.java b/bramble-core/src/main/java/org/briarproject/bramble/mailbox/introduction/IntroduceeProtocolEngine.java new file mode 100644 index 0000000000000000000000000000000000000000..83fe29e7c739bb301aed9657fe54b540ec0e802b --- /dev/null +++ b/bramble-core/src/main/java/org/briarproject/bramble/mailbox/introduction/IntroduceeProtocolEngine.java @@ -0,0 +1,230 @@ +package org.briarproject.bramble.mailbox.introduction; + +import org.briarproject.bramble.api.FormatException; +import org.briarproject.bramble.api.client.ClientHelper; +import org.briarproject.bramble.api.client.ContactGroupFactory; +import org.briarproject.bramble.api.contact.Contact; +import org.briarproject.bramble.api.contact.ContactManager; +import org.briarproject.bramble.api.crypto.KeyPair; +import org.briarproject.bramble.api.crypto.SecretKey; +import org.briarproject.bramble.api.db.DatabaseComponent; +import org.briarproject.bramble.api.db.DbException; +import org.briarproject.bramble.api.db.Transaction; +import org.briarproject.bramble.api.identity.IdentityManager; +import org.briarproject.bramble.api.identity.LocalAuthor; +import org.briarproject.bramble.api.mailbox.event.MailboxIntroductionAbortedEvent; +import org.briarproject.bramble.api.mailbox.event.MailboxIntroductionRequestReceivedEvent; +import org.briarproject.bramble.api.mailbox.event.MailboxIntroductionSucceededEvent; +import org.briarproject.bramble.api.plugin.TransportId; +import org.briarproject.bramble.api.properties.TransportPropertyManager; +import org.briarproject.bramble.api.sync.Message; +import org.briarproject.bramble.api.sync.MessageId; +import org.briarproject.bramble.api.system.Clock; +import org.briarproject.bramble.api.transport.KeyManager; +import org.briarproject.bramble.api.transport.KeySetId; + +import java.security.GeneralSecurityException; +import java.util.Map; +import java.util.logging.Logger; + +import javax.annotation.Nullable; +import javax.inject.Inject; + +import static java.util.logging.Level.WARNING; +import static org.briarproject.bramble.mailbox.introduction.IntroduceeState.AWAIT_AUTH; +import static org.briarproject.bramble.mailbox.introduction.IntroduceeState.MAILBOX_ADDED; +import static org.briarproject.bramble.mailbox.introduction.IntroduceeState.START; +import static org.briarproject.bramble.util.LogUtils.logException; + +class IntroduceeProtocolEngine + extends AbstractProtocolEngine<IntroduceeSession> { + + private final static Logger LOG = + Logger.getLogger(IntroduceeProtocolEngine.class.getName()); + + @Inject + IntroduceeProtocolEngine(DatabaseComponent db, ClientHelper clientHelper, + ContactManager contactManager, + ContactGroupFactory contactGroupFactory, + IdentityManager identityManager, MailboxMessageParser messageParser, + MailboxMessageEncoder messageEncoder, Clock clock, + MailboxIntroductionCrypto crypto, KeyManager keyManager, + TransportPropertyManager transportPropertyManager) { + super(db, clientHelper, contactManager, contactGroupFactory, + identityManager, messageParser, messageEncoder, clock, crypto, + keyManager, transportPropertyManager); + } + + @Override + public IntroduceeSession onRequestMessage(Transaction txn, + IntroduceeSession session, RequestMessage m) + throws DbException, FormatException { + throw new UnsupportedOperationException(); + } + + @Override + public IntroduceeSession onMailboxAcceptMessage(Transaction txn, + IntroduceeSession s, MailboxAcceptMessage m) + throws DbException, FormatException { + switch (s.getState()) { + case START: + return onRemoteRequest(txn, s, m); + case LOCAL_DECLINED: + case MAILBOX_ADDED: + return abort(txn, s); + default: + throw new AssertionError(); + } + } + + @Override + public IntroduceeSession onIntroduceeAcceptMessage(Transaction txn, + IntroduceeSession session, IntroduceeAcceptMessage acceptMessage) { + throw new UnsupportedOperationException(); + } + + @Override + public IntroduceeSession onDeclineMessage(Transaction txn, + IntroduceeSession s, DeclineMessage m) + throws DbException, FormatException { + throw new UnsupportedOperationException(); + } + + @Override + public IntroduceeSession onAuthMessage(Transaction txn, IntroduceeSession s, + MailboxAuthMessage m) throws DbException, FormatException { + switch (s.getState()) { + case AWAIT_AUTH: + return handleAuthMessage(txn, s, m); + case START: + case LOCAL_DECLINED: + case MAILBOX_ADDED: + return abort(txn, s); + default: + throw new AssertionError(); + } + } + + @Override + public IntroduceeSession onAbortMessage(Transaction txn, + IntroduceeSession s, AbortMessage m) { + // Broadcast abort event for testing + txn.attach(new MailboxIntroductionAbortedEvent(s.getSessionId())); + // Reset the session back to initial state + return IntroduceeSession.clear(s, START, s.getLastLocalMessageId(), + s.getLocalTimestamp(), m.getMessageId(), + s.getAbortCounter() + 1); + } + + private IntroduceeSession handleAuthMessage(Transaction txn, + IntroduceeSession s, MailboxAuthMessage m) throws DbException { + // The dependency, if any, must be the last remote message + if (isInvalidDependency(s.getLastLocalMessageId(), + m.getPreviousMessageId())) return abort(txn, s); + LocalAuthor localAuthor = identityManager.getLocalAuthor(txn); + try { + crypto.verifyAuthMac(m.getMac(), s, localAuthor.getId()); + crypto.verifySignature(m.getSignature(), s); + long timestamp = Math.min(s.getLocal().acceptTimestamp, + s.getRemote().acceptTimestamp); + if (timestamp == -1) throw new AssertionError(); + contactManager.addContactMailbox(txn, s.getRemote().author, + localAuthor.getId(), new SecretKey(s.masterKey), timestamp, + false); + Contact c = contactManager + .getContact(txn, s.getRemote().author.getId(), + localAuthor.getId()); + // add the keys to the new mailbox + //noinspection ConstantConditions + Map<TransportId, KeySetId> keys = keyManager + .addContact(txn, c.getId(), new SecretKey(s.masterKey), + timestamp, false, true); + // add signed transport properties for the mailbox + //noinspection ConstantConditions + transportPropertyManager.addRemoteProperties(txn, c.getId(), + m.getTransportProperties()); + Contact owner = contactManager + .getContact(txn, s.getIntroducer().getId(), + localAuthor.getId()); + // Mark the mailbox as usable for the owner + db.setMailboxForContact(txn, owner.getId(), c.getId(), null); + MailboxIntroductionSucceededEvent e = + new MailboxIntroductionSucceededEvent(c); + txn.attach(e); + } catch (GeneralSecurityException e) { + logException(LOG, WARNING, e); + return abort(txn, s); + } + return IntroduceeSession + .clear(s, MAILBOX_ADDED, s.getLastLocalMessageId(), + clock.currentTimeMillis(), m.getMessageId(), + s.getAbortCounter()); + } + + private IntroduceeSession abort(Transaction txn, IntroduceeSession s) + throws DbException { + // Send an ABORT message + Message sent = sendAbortMessage(txn, s, getLocalTimestamp(s)); + // Broadcast abort event for testing + txn.attach(new MailboxIntroductionAbortedEvent(s.getSessionId())); + // Reset the session back to initial state + return IntroduceeSession + .clear(s, START, sent.getId(), sent.getTimestamp(), + s.getLastRemoteMessageId(), s.getAbortCounter() + 1); + } + + private long getLocalTimestamp(AbstractIntroduceeSession s) { + return getLocalTimestamp(s.getLocalTimestamp(), + s.getRequestTimestamp()); + } + + private IntroduceeSession onRemoteRequest(Transaction txn, + IntroduceeSession s, MailboxAcceptMessage m) + throws DbException, FormatException { + // The dependency, if any, must be the last remote message + if (isInvalidDependency(s, m.getPreviousMessageId())) + return abort(txn, s); + // Broadcast IntroductionRequestReceivedEvent + LocalAuthor localAuthor = identityManager.getLocalAuthor(txn); + txn.attach(new MailboxIntroductionRequestReceivedEvent( + localAuthor.getId())); + if (m.getAuthor() == null) throw new FormatException(); + // Create ephemeral key pair and get local transport properties + KeyPair keyPair = crypto.generateKeyPair(); + byte[] publicKey = keyPair.getPublic().getEncoded(); + byte[] privateKey = keyPair.getPrivate().getEncoded(); + long localTimestamp = clock.currentTimeMillis(); + try { + SecretKey secretKey = crypto.deriveMasterKey(publicKey, privateKey, + m.getEphemeralPublicKey(), false); + SecretKey mailboxMacKey = crypto.deriveMacKey(secretKey, true); + SecretKey introduceeMacKey = crypto.deriveMacKey(secretKey, false); + // Add the keys to the session + s = IntroduceeSession + .addLocalAccept(s, s.getState(), m, publicKey, privateKey, + localTimestamp, secretKey.getBytes(), + mailboxMacKey.getBytes(), + introduceeMacKey.getBytes()); + byte[] mac = + crypto.authMac(introduceeMacKey, s, localAuthor.getId()); + byte[] signature = + crypto.sign(introduceeMacKey, localAuthor.getPrivateKey()); + // Send ephemeral public key, mac and accept timestamp back + Message reply = + sendIntroduceeResponseMessage(txn, s, m.getMessageId(), + localTimestamp, publicKey, mac, signature, + localTimestamp); + //TODO: Check for reasons to decline and if any, move to LOCAL_DECLINE + // Move to the AWAIT_REMOTE_RESPONSE state + return IntroduceeSession.addLocalAuth(s, AWAIT_AUTH, reply); + } catch (GeneralSecurityException e) { + logException(LOG, WARNING, e); + return abort(txn, s); + } + } + + private boolean isInvalidDependency(AbstractIntroduceeSession s, + @Nullable MessageId dependency) { + return isInvalidDependency(s.getLastRemoteMessageId(), dependency); + } +} diff --git a/bramble-core/src/main/java/org/briarproject/bramble/mailbox/introduction/IntroduceeSession.java b/bramble-core/src/main/java/org/briarproject/bramble/mailbox/introduction/IntroduceeSession.java new file mode 100644 index 0000000000000000000000000000000000000000..9ffd984ed1c418ff59094a0dc18746ea83798a1d --- /dev/null +++ b/bramble-core/src/main/java/org/briarproject/bramble/mailbox/introduction/IntroduceeSession.java @@ -0,0 +1,147 @@ +package org.briarproject.bramble.mailbox.introduction; + +import org.briarproject.bramble.api.client.SessionId; +import org.briarproject.bramble.api.identity.Author; +import org.briarproject.bramble.api.mailbox.Role; +import org.briarproject.bramble.api.nullsafety.NotNullByDefault; +import org.briarproject.bramble.api.plugin.TransportId; +import org.briarproject.bramble.api.sync.GroupId; +import org.briarproject.bramble.api.sync.Message; +import org.briarproject.bramble.api.sync.MessageId; +import org.briarproject.bramble.api.transport.KeySetId; + +import java.util.Map; + +import javax.annotation.Nullable; +import javax.annotation.concurrent.Immutable; + +import static org.briarproject.bramble.api.mailbox.Role.INTRODUCEE; +import static org.briarproject.bramble.mailbox.introduction.IntroduceeState.AWAIT_AUTH; +import static org.briarproject.bramble.mailbox.introduction.IntroduceeState.START; + +@Immutable +@NotNullByDefault +class IntroduceeSession extends AbstractIntroduceeSession<IntroduceeState> { + + IntroduceeSession(SessionId sessionId, IntroduceeState state, + long requestTimestamp, GroupId contactGroupId, Author introducer, + Local local, Remote remote, @Nullable byte[] masterKey, + @Nullable Map<TransportId, KeySetId> transportKeys, + long sessionCounter) { + super(sessionId, state, requestTimestamp, contactGroupId, introducer, + local, remote, masterKey, transportKeys, sessionCounter); + } + + static IntroduceeSession getInitial(GroupId contactGroupId, + SessionId sessionId, Author introducer, boolean localIsAlice, + Author remoteAuthor) { + Local local = new Local(localIsAlice, null, -1, null, null, -1, null); + Remote remote = + new Remote(!localIsAlice, remoteAuthor, null, null, null, -1, + null); + return new IntroduceeSession(sessionId, START, -1, contactGroupId, + introducer, local, remote, null, null, 0); + } + + static IntroduceeSession addLocalAccept(IntroduceeSession s, + IntroduceeState state, MailboxAcceptMessage m, + byte[] ephemeralPublicKey, byte[] ephemeralPrivateKey, + long acceptTimestamp, byte[] masterKey, byte[] aliceMackey, + byte[] bobMacKey) { + Local local = new Local(false, s.local.lastMessageId, + s.local.lastMessageTimestamp, ephemeralPublicKey, + ephemeralPrivateKey, acceptTimestamp, bobMacKey); + Remote remote = new Remote(true, m.getAuthor(), m.getMessageId(), + m.getEphemeralPublicKey(), null, m.getAcceptTimestamp(), + aliceMackey); + return new IntroduceeSession(s.getSessionId(), state, m.getTimestamp(), + s.contactGroupId, s.introducer, local, remote, masterKey, + s.transportKeys, s.getAbortCounter()); + } + + static IntroduceeSession addLocalAuth(IntroduceeSession s, + IntroduceeState state, Message m) { + // add mac key and sent message + Local local = new Local(false, m.getId(), m.getTimestamp(), + s.local.ephemeralPublicKey, s.local.ephemeralPrivateKey, + s.local.acceptTimestamp, s.local.macKey); + + return new IntroduceeSession(s.getSessionId(), state, + s.getRequestTimestamp(), s.contactGroupId, s.introducer, local, + s.remote, s.masterKey, s.transportKeys, s.getAbortCounter()); + } + + static IntroduceeSession awaitAuth(IntroduceeSession s, + MailboxAuthMessage m, Message sent, + @Nullable Map<TransportId, KeySetId> transportKeys) { + Local local = new Local(s.local, sent.getId(), sent.getTimestamp()); + Remote remote = new Remote(s.remote, m.getMessageId()); + return new IntroduceeSession(s.getSessionId(), AWAIT_AUTH, + s.getRequestTimestamp(), s.contactGroupId, s.introducer, local, + remote, null, transportKeys, s.getAbortCounter()); + } + + static IntroduceeSession clear(IntroduceeSession s, IntroduceeState state, + @Nullable MessageId lastLocalMessageId, long localTimestamp, + @Nullable MessageId lastRemoteMessageId, long abortCounter) { + Local local = + new Local(s.local.alice, lastLocalMessageId, localTimestamp, + null, null, -1, null); + Remote remote = + new Remote(s.remote.alice, s.remote.author, lastRemoteMessageId, + null, null, -1, null); + return new IntroduceeSession(s.getSessionId(), state, + s.getRequestTimestamp(), s.contactGroupId, s.introducer, local, + remote, null, null, abortCounter); + } + + @Override + Role getRole() { + return INTRODUCEE; + } + + @Override + public GroupId getContactGroupId() { + return contactGroupId; + } + + @Override + public long getLocalTimestamp() { + return local.lastMessageTimestamp; + } + + @Nullable + @Override + public MessageId getLastLocalMessageId() { + return local.lastMessageId; + } + + @Nullable + @Override + public MessageId getLastRemoteMessageId() { + return remote.lastMessageId; + } + + Author getIntroducer() { + return introducer; + } + + public Local getLocal() { + return local; + } + + public Remote getRemote() { + return remote; + } + + @Nullable + byte[] getMasterKey() { + return masterKey; + } + + @Nullable + Map<TransportId, KeySetId> getTransportKeys() { + return transportKeys; + } + +} diff --git a/bramble-core/src/main/java/org/briarproject/bramble/mailbox/introduction/IntroduceeState.java b/bramble-core/src/main/java/org/briarproject/bramble/mailbox/introduction/IntroduceeState.java new file mode 100644 index 0000000000000000000000000000000000000000..e0bad4558a647688ec384726670f5522debba2ba --- /dev/null +++ b/bramble-core/src/main/java/org/briarproject/bramble/mailbox/introduction/IntroduceeState.java @@ -0,0 +1,33 @@ +package org.briarproject.bramble.mailbox.introduction; + +import org.briarproject.bramble.api.FormatException; +import org.briarproject.bramble.api.nullsafety.NotNullByDefault; + +import javax.annotation.concurrent.Immutable; + +@Immutable +@NotNullByDefault +enum IntroduceeState implements State { + + START(0), + LOCAL_DECLINED(1), + AWAIT_AUTH(2), + MAILBOX_ADDED(3); + + private final int value; + + IntroduceeState(int value) { + this.value = value; + } + + @Override + public int getValue() { + return value; + } + + static IntroduceeState fromValue(int value) throws FormatException { + for (IntroduceeState s : values()) if (s.value == value) return s; + throw new FormatException(); + } + +} diff --git a/bramble-core/src/main/java/org/briarproject/bramble/mailbox/introduction/IntroductionConstants.java b/bramble-core/src/main/java/org/briarproject/bramble/mailbox/introduction/IntroductionConstants.java new file mode 100644 index 0000000000000000000000000000000000000000..adc5223cdb6ad5658fb76f5541e7d958896a58fc --- /dev/null +++ b/bramble-core/src/main/java/org/briarproject/bramble/mailbox/introduction/IntroductionConstants.java @@ -0,0 +1,49 @@ +package org.briarproject.bramble.mailbox.introduction; + +interface IntroductionConstants { + + // Group metadata keys + String GROUP_KEY_CONTACT_ID = "contactId"; + + // Message metadata keys + String MSG_KEY_MESSAGE_TYPE = "messageType"; + String MSG_KEY_SESSION_ID = "sessionId"; + String MSG_KEY_TIMESTAMP = "timestamp"; + String MSG_KEY_LOCAL = "local"; + String MSG_KEY_COUNTER = "counter"; + String MSG_KEY_AVAILABLE_TO_ANSWER = "availableToAnswer"; + + // Session Keys + String SESSION_KEY_SESSION_ID = "sessionId"; + String SESSION_KEY_COUNTER = "counter"; + String SESSION_KEY_ROLE = "role"; + String SESSION_KEY_STATE = "state"; + String SESSION_KEY_REQUEST_TIMESTAMP = "requestTimestamp"; + String SESSION_KEY_LOCAL_TIMESTAMP = "localTimestamp"; + String SESSION_KEY_LAST_LOCAL_MESSAGE_ID = "lastLocalMessageId"; + String SESSION_KEY_LAST_REMOTE_MESSAGE_ID = "lastRemoteMessageId"; + + // Session Keys Introducer + String SESSION_KEY_INTRODUCEE_A = "introduceeA"; + String SESSION_KEY_INTRODUCEE_B = "introduceeB"; + String SESSION_KEY_GROUP_ID = "groupId"; + String SESSION_KEY_AUTHOR = "author"; + + // Session Keys Introducee + String SESSION_KEY_INTRODUCER = "introducer"; + String SESSION_KEY_LOCAL = "local"; + String SESSION_KEY_REMOTE = "remote"; + + String SESSION_KEY_MASTER_KEY = "masterKey"; + String SESSION_KEY_TRANSPORT_KEYS = "transportKeys"; + + String SESSION_KEY_ALICE = "alice"; + String SESSION_KEY_EPHEMERAL_PUBLIC_KEY = "ephemeralPublicKey"; + String SESSION_KEY_EPHEMERAL_PRIVATE_KEY = "ephemeralPrivateKey"; + String SESSION_KEY_TRANSPORT_PROPERTIES = "transportProperties"; + String SESSION_KEY_ACCEPT_TIMESTAMP = "acceptTimestamp"; + String SESSION_KEY_MAC_KEY = "macKey"; + + String SESSION_KEY_REMOTE_AUTHOR = "remoteAuthor"; + +} diff --git a/bramble-core/src/main/java/org/briarproject/bramble/mailbox/introduction/MailboxAcceptMessage.java b/bramble-core/src/main/java/org/briarproject/bramble/mailbox/introduction/MailboxAcceptMessage.java new file mode 100644 index 0000000000000000000000000000000000000000..bec6267bdebf2a93ab6ba71e9f4246282b33b743 --- /dev/null +++ b/bramble-core/src/main/java/org/briarproject/bramble/mailbox/introduction/MailboxAcceptMessage.java @@ -0,0 +1,48 @@ +package org.briarproject.bramble.mailbox.introduction; + +import org.briarproject.bramble.api.client.SessionId; +import org.briarproject.bramble.api.identity.Author; +import org.briarproject.bramble.api.nullsafety.NotNullByDefault; +import org.briarproject.bramble.api.sync.GroupId; +import org.briarproject.bramble.api.sync.MessageId; + +import javax.annotation.Nullable; +import javax.annotation.concurrent.Immutable; + +@Immutable +@NotNullByDefault +class MailboxAcceptMessage extends AbstractMailboxIntroductionMessage { + + private final SessionId sessionId; + private final Author author; + private final byte[] ephemeralPublicKey; + private final long acceptTimestamp; + + protected MailboxAcceptMessage(MessageId messageId, GroupId groupId, + long timestamp, @Nullable MessageId previousMessageId, + SessionId sessionId, Author author, byte[] ephemeralPublicKey, + long acceptTimestamp) { + super(messageId, groupId, timestamp, previousMessageId); + this.sessionId = sessionId; + this.author = author; + this.ephemeralPublicKey = ephemeralPublicKey; + this.acceptTimestamp = acceptTimestamp; + } + + public SessionId getSessionId() { + return sessionId; + } + + public Author getAuthor() { + return author; + } + + public byte[] getEphemeralPublicKey() { + return ephemeralPublicKey; + } + + public long getAcceptTimestamp() { + return acceptTimestamp; + } + +} diff --git a/bramble-core/src/main/java/org/briarproject/bramble/mailbox/introduction/MailboxAuthMessage.java b/bramble-core/src/main/java/org/briarproject/bramble/mailbox/introduction/MailboxAuthMessage.java new file mode 100644 index 0000000000000000000000000000000000000000..8f7871be9dc69f481530a1974fda875482679e29 --- /dev/null +++ b/bramble-core/src/main/java/org/briarproject/bramble/mailbox/introduction/MailboxAuthMessage.java @@ -0,0 +1,51 @@ +package org.briarproject.bramble.mailbox.introduction; + +import org.briarproject.bramble.api.client.SessionId; +import org.briarproject.bramble.api.nullsafety.NotNullByDefault; +import org.briarproject.bramble.api.plugin.TransportId; +import org.briarproject.bramble.api.properties.TransportProperties; +import org.briarproject.bramble.api.sync.GroupId; +import org.briarproject.bramble.api.sync.MessageId; + +import java.util.Map; + +import javax.annotation.Nullable; +import javax.annotation.concurrent.Immutable; + +@Immutable +@NotNullByDefault +class MailboxAuthMessage extends AbstractMailboxIntroductionMessage { + + private final SessionId sessionId; + private final Map<TransportId, TransportProperties> transportProperties; + private final byte[] mac; + private final byte[] signature; + + protected MailboxAuthMessage(MessageId messageId, GroupId groupId, + long timestamp, @Nullable MessageId previousMessageId, + SessionId sessionId, + Map<TransportId, TransportProperties> transportProperties, + byte[] mac, byte[] signature) { + super(messageId, groupId, timestamp, previousMessageId); + this.sessionId = sessionId; + this.transportProperties = transportProperties; + this.mac = mac; + this.signature = signature; + } + + public SessionId getSessionId() { + return sessionId; + } + + public byte[] getMac() { + return mac; + } + + public byte[] getSignature() { + return signature; + } + + public Map<TransportId, TransportProperties> getTransportProperties() { + return transportProperties; + } +} diff --git a/bramble-core/src/main/java/org/briarproject/bramble/mailbox/introduction/MailboxIntroductionCrypto.java b/bramble-core/src/main/java/org/briarproject/bramble/mailbox/introduction/MailboxIntroductionCrypto.java new file mode 100644 index 0000000000000000000000000000000000000000..46f8736cd9fec290ec0d0d4f62e1a80a0d991a3b --- /dev/null +++ b/bramble-core/src/main/java/org/briarproject/bramble/mailbox/introduction/MailboxIntroductionCrypto.java @@ -0,0 +1,95 @@ +package org.briarproject.bramble.mailbox.introduction; + +import org.briarproject.bramble.api.client.SessionId; +import org.briarproject.bramble.api.crypto.KeyPair; +import org.briarproject.bramble.api.crypto.SecretKey; +import org.briarproject.bramble.api.identity.Author; +import org.briarproject.bramble.api.identity.AuthorId; +import org.briarproject.bramble.api.identity.LocalAuthor; + +import java.security.GeneralSecurityException; + +public interface MailboxIntroductionCrypto { + + /** + * Returns the {@link SessionId} based on the introducer + * and the two introducees. + */ + SessionId getSessionId(Author introducer, Author local, Author remote, + boolean isAlice); + + /** + * Generates an agreement key pair. + */ + KeyPair generateKeyPair(); + + /** + * Derives a session master key for Alice or Bob. + * + * @return The secret master key + */ + @SuppressWarnings("ConstantConditions") + SecretKey deriveMasterKey(byte[] ephemeralPublicKey, + byte[] ephemeralPrivateKey, byte[] remoteEphemeralPublicKey, + boolean alice) throws GeneralSecurityException; + + /** + * Derives a MAC key from the session's master key for Alice or Bob. + * + * @param masterKey The key returned by {@link #deriveMasterKey(byte[], byte[], byte[], boolean)} + * @param alice true for Alice's MAC key, false for Bob's + * @return The MAC key + */ + SecretKey deriveMacKey(SecretKey masterKey, boolean alice); + + /** + * Generates a MAC that covers both introducee's ephemeral public keys, + * transport properties, Author IDs and timestamps of the accept message. + */ + byte[] authMac(SecretKey macKey, AbstractIntroduceeSession s, + AuthorId localAuthorId); + + /** + * Verifies a received MAC + * + * @param mac The MAC to verify + * as returned by {@link #deriveMasterKey#deriveMasterKey(byte[], byte[], byte[], boolean)} + * @throws GeneralSecurityException if the verification fails + */ + void verifyAuthMac(byte[] mac, AbstractIntroduceeSession s, + AuthorId localAuthorId) throws GeneralSecurityException; + + /** + * Signs a nonce derived from the macKey + * with the local introducee's identity private key. + * + * @param macKey The corresponding MAC key for the signer's role + * @param privateKey The identity private key + * (from {@link LocalAuthor#getPrivateKey()}) + * @return The signature as a byte array + */ + byte[] sign(SecretKey macKey, byte[] privateKey) + throws GeneralSecurityException; + + /** + * Verifies the signature on a nonce derived from the MAC key. + * + * @throws GeneralSecurityException if the signature is invalid + */ + void verifySignature(byte[] signature, AbstractIntroduceeSession s) + throws GeneralSecurityException; + + /** + * Generates a MAC using the local MAC key. + */ + byte[] activateMac(AbstractIntroduceeSession s); + + /** + * Verifies a MAC from an ACTIVATE message. + * + * @throws GeneralSecurityException if the verification fails + */ + void verifyActivateMac(byte[] mac, AbstractIntroduceeSession s) + throws GeneralSecurityException; + +} diff --git a/bramble-core/src/main/java/org/briarproject/bramble/mailbox/introduction/MailboxIntroductionCryptoImpl.java b/bramble-core/src/main/java/org/briarproject/bramble/mailbox/introduction/MailboxIntroductionCryptoImpl.java new file mode 100644 index 0000000000000000000000000000000000000000..79d7f6d0754684783ed1abef85ae2b9be77931b4 --- /dev/null +++ b/bramble-core/src/main/java/org/briarproject/bramble/mailbox/introduction/MailboxIntroductionCryptoImpl.java @@ -0,0 +1,190 @@ +package org.briarproject.bramble.mailbox.introduction; + +import org.briarproject.bramble.api.FormatException; +import org.briarproject.bramble.api.client.ClientHelper; +import org.briarproject.bramble.api.client.SessionId; +import org.briarproject.bramble.api.crypto.CryptoComponent; +import org.briarproject.bramble.api.crypto.KeyPair; +import org.briarproject.bramble.api.crypto.KeyParser; +import org.briarproject.bramble.api.crypto.PrivateKey; +import org.briarproject.bramble.api.crypto.PublicKey; +import org.briarproject.bramble.api.crypto.SecretKey; +import org.briarproject.bramble.api.data.BdfList; +import org.briarproject.bramble.api.identity.Author; +import org.briarproject.bramble.api.identity.AuthorId; +import org.briarproject.bramble.api.nullsafety.NotNullByDefault; + +import java.security.GeneralSecurityException; + +import javax.annotation.concurrent.Immutable; +import javax.inject.Inject; + +import static org.briarproject.bramble.api.mailbox.IntroductionConstants.LABEL_ACTIVATE_MAC; +import static org.briarproject.bramble.api.mailbox.IntroductionConstants.LABEL_ALICE_MAC_KEY; +import static org.briarproject.bramble.api.mailbox.IntroductionConstants.LABEL_AUTH_MAC; +import static org.briarproject.bramble.api.mailbox.IntroductionConstants.LABEL_AUTH_NONCE; +import static org.briarproject.bramble.api.mailbox.IntroductionConstants.LABEL_AUTH_SIGN; +import static org.briarproject.bramble.api.mailbox.IntroductionConstants.LABEL_BOB_MAC_KEY; +import static org.briarproject.bramble.api.mailbox.IntroductionConstants.LABEL_MASTER_KEY; +import static org.briarproject.bramble.api.mailbox.IntroductionConstants.LABEL_SESSION_ID; +import static org.briarproject.bramble.api.mailbox.MailboxIntroductionManager.MAJOR_VERSION; +import static org.briarproject.bramble.mailbox.introduction.AbstractIntroduceeSession.Common; +import static org.briarproject.bramble.mailbox.introduction.AbstractIntroduceeSession.Local; +import static org.briarproject.bramble.mailbox.introduction.AbstractIntroduceeSession.Remote; + +@Immutable +@NotNullByDefault +class MailboxIntroductionCryptoImpl implements MailboxIntroductionCrypto { + + private final CryptoComponent crypto; + private final ClientHelper clientHelper; + + @Inject + MailboxIntroductionCryptoImpl(CryptoComponent crypto, + ClientHelper clientHelper) { + this.crypto = crypto; + this.clientHelper = clientHelper; + } + + @Override + public SessionId getSessionId(Author owner, Author local, Author remote, + boolean isAlice) { + byte[] hash = crypto.hash(LABEL_SESSION_ID, owner.getId().getBytes(), + isAlice ? local.getId().getBytes() : remote.getId().getBytes(), + isAlice ? remote.getId().getBytes() : local.getId().getBytes()); + return new SessionId(hash); + } + + @Override + public KeyPair generateKeyPair() { + return crypto.generateAgreementKeyPair(); + } + + @Override + public SecretKey deriveMasterKey(byte[] publicKey, byte[] privateKey, + byte[] remotePublicKey, boolean alice) + throws GeneralSecurityException { + KeyParser kp = crypto.getAgreementKeyParser(); + PublicKey remoteEphemeralPublicKey = kp.parsePublicKey(remotePublicKey); + PublicKey ephemeralPublicKey = kp.parsePublicKey(publicKey); + PrivateKey ephemeralPrivateKey = kp.parsePrivateKey(privateKey); + KeyPair keyPair = new KeyPair(ephemeralPublicKey, ephemeralPrivateKey); + return crypto + .deriveSharedSecret(LABEL_MASTER_KEY, remoteEphemeralPublicKey, + keyPair, new byte[] {MAJOR_VERSION}, + alice ? publicKey : remotePublicKey, + alice ? remotePublicKey : publicKey); + } + + @Override + public SecretKey deriveMacKey(SecretKey masterKey, boolean alice) { + return crypto.deriveKey(alice ? LABEL_ALICE_MAC_KEY : LABEL_BOB_MAC_KEY, + masterKey); + } + + @Override + @SuppressWarnings("ConstantConditions") + public byte[] authMac(SecretKey macKey, AbstractIntroduceeSession s, + AuthorId localAuthorId) { + // the macKey is not yet available in the session at this point + return authMac(macKey, s.getIntroducer().getId(), localAuthorId, + s.getLocal(), s.getRemote()); + } + + byte[] authMac(SecretKey macKey, AuthorId introducerId, + AuthorId localAuthorId, Local local, Remote remote) { + byte[] inputs = getAuthMacInputs(introducerId, localAuthorId, local, + remote.author.getId(), remote); + return crypto.mac(LABEL_AUTH_MAC, macKey, inputs); + } + + @SuppressWarnings("ConstantConditions") + private byte[] getAuthMacInputs(AuthorId introducerId, + AuthorId localAuthorId, Common local, AuthorId remoteAuthorId, + Common remote) { + BdfList localInfo = BdfList.of(localAuthorId, local.acceptTimestamp, + local.ephemeralPublicKey); + BdfList remoteInfo = BdfList.of(remoteAuthorId, remote.acceptTimestamp, + remote.ephemeralPublicKey); + BdfList macList = BdfList.of(introducerId, localInfo, remoteInfo); + try { + return clientHelper.toByteArray(macList); + } catch (FormatException e) { + throw new AssertionError(); + } + } + + @Override + @SuppressWarnings("ConstantConditions") + public void verifyAuthMac(byte[] mac, AbstractIntroduceeSession s, + AuthorId localAuthorId) throws GeneralSecurityException { + verifyAuthMac(mac, new SecretKey(s.getRemote().macKey), + s.getIntroducer().getId(), localAuthorId, s.getLocal(), + s.getRemote().author.getId(), s.getRemote()); + } + + void verifyAuthMac(byte[] mac, SecretKey macKey, AuthorId introducerId, + AuthorId localAuthorId, Common local, AuthorId remoteAuthorId, + Common remote) throws GeneralSecurityException { + // switch input for verification + byte[] inputs = getAuthMacInputs(introducerId, remoteAuthorId, remote, + localAuthorId, local); + if (!crypto.verifyMac(mac, LABEL_AUTH_MAC, macKey, inputs)) { + throw new GeneralSecurityException(); + } + } + + @Override + public byte[] sign(SecretKey macKey, byte[] privateKey) + throws GeneralSecurityException { + return crypto.sign(LABEL_AUTH_SIGN, getNonce(macKey), privateKey); + } + + private byte[] getNonce(SecretKey macKey) { + return crypto.mac(LABEL_AUTH_NONCE, macKey); + } + + @Override + @SuppressWarnings("ConstantConditions") + public void verifySignature(byte[] signature, AbstractIntroduceeSession s) + throws GeneralSecurityException { + SecretKey macKey = new SecretKey(s.getRemote().macKey); + verifySignature(macKey, s.getRemote().author.getPublicKey(), signature); + } + + void verifySignature(SecretKey macKey, byte[] publicKey, byte[] signature) + throws GeneralSecurityException { + byte[] nonce = getNonce(macKey); + if (!crypto.verifySignature(signature, LABEL_AUTH_SIGN, nonce, + publicKey)) { + throw new GeneralSecurityException(); + } + } + + @Override + public byte[] activateMac(AbstractIntroduceeSession s) { + if (s.getLocal().macKey == null) + throw new AssertionError("Local MAC key is null"); + return activateMac(new SecretKey(s.getLocal().macKey)); + } + + byte[] activateMac(SecretKey macKey) { + return crypto.mac(LABEL_ACTIVATE_MAC, macKey); + } + + @Override + public void verifyActivateMac(byte[] mac, AbstractIntroduceeSession s) + throws GeneralSecurityException { + if (s.getRemote().macKey == null) + throw new AssertionError("Remote MAC key is null"); + verifyActivateMac(mac, new SecretKey(s.getRemote().macKey)); + } + + void verifyActivateMac(byte[] mac, SecretKey macKey) + throws GeneralSecurityException { + if (!crypto.verifyMac(mac, LABEL_ACTIVATE_MAC, macKey)) { + throw new GeneralSecurityException(); + } + } + +} diff --git a/bramble-core/src/main/java/org/briarproject/bramble/mailbox/introduction/MailboxIntroductionManagerImpl.java b/bramble-core/src/main/java/org/briarproject/bramble/mailbox/introduction/MailboxIntroductionManagerImpl.java new file mode 100644 index 0000000000000000000000000000000000000000..c10a7bfcef71fea378795d6e209213802a9f5ed8 --- /dev/null +++ b/bramble-core/src/main/java/org/briarproject/bramble/mailbox/introduction/MailboxIntroductionManagerImpl.java @@ -0,0 +1,486 @@ +package org.briarproject.bramble.mailbox.introduction; + +import org.briarproject.bramble.api.FormatException; +import org.briarproject.bramble.api.client.BdfIncomingMessageHook; +import org.briarproject.bramble.api.client.ClientHelper; +import org.briarproject.bramble.api.client.ContactGroupFactory; +import org.briarproject.bramble.api.client.SessionId; +import org.briarproject.bramble.api.contact.Contact; +import org.briarproject.bramble.api.contact.ContactId; +import org.briarproject.bramble.api.contact.ContactManager; +import org.briarproject.bramble.api.contact.ContactType; +import org.briarproject.bramble.api.contact.PrivateMailbox; +import org.briarproject.bramble.api.data.BdfDictionary; +import org.briarproject.bramble.api.data.BdfList; +import org.briarproject.bramble.api.data.MetadataParser; +import org.briarproject.bramble.api.db.DatabaseComponent; +import org.briarproject.bramble.api.db.DbException; +import org.briarproject.bramble.api.db.Metadata; +import org.briarproject.bramble.api.db.Transaction; +import org.briarproject.bramble.api.identity.Author; +import org.briarproject.bramble.api.identity.IdentityManager; +import org.briarproject.bramble.api.identity.LocalAuthor; +import org.briarproject.bramble.api.lifecycle.IoExecutor; +import org.briarproject.bramble.api.mailbox.MailboxIntroductionManager; +import org.briarproject.bramble.api.mailbox.Role; +import org.briarproject.bramble.api.sync.Client; +import org.briarproject.bramble.api.sync.Group; +import org.briarproject.bramble.api.sync.GroupId; +import org.briarproject.bramble.api.sync.Message; +import org.briarproject.bramble.api.sync.MessageId; +import org.briarproject.bramble.api.system.Clock; +import org.briarproject.bramble.api.versioning.ClientVersioningManager; + +import java.util.Arrays; +import java.util.Collection; +import java.util.Map; +import java.util.concurrent.Executor; +import java.util.logging.Logger; + +import javax.annotation.Nullable; +import javax.inject.Inject; + +import static org.briarproject.bramble.api.contact.ContactManager.ContactHook; +import static org.briarproject.bramble.api.contact.ContactType.values; +import static org.briarproject.bramble.api.mailbox.Role.INTRODUCEE; +import static org.briarproject.bramble.api.mailbox.Role.MAILBOX; +import static org.briarproject.bramble.api.mailbox.Role.OWNER; +import static org.briarproject.bramble.api.versioning.ClientVersioningManager.ClientVersioningHook; +import static org.briarproject.bramble.mailbox.introduction.IntroductionConstants.GROUP_KEY_CONTACT_ID; +import static org.briarproject.bramble.mailbox.introduction.MessageType.MAILBOX_ACCEPT; +import static org.briarproject.bramble.mailbox.introduction.MessageType.MAILBOX_REQUEST; + +class MailboxIntroductionManagerImpl extends BdfIncomingMessageHook + implements MailboxIntroductionManager, Client, ClientVersioningHook, + ContactHook { + + private static final Logger LOG = + Logger.getLogger(MailboxIntroductionManagerImpl.class.getName()); + private final Executor ioExecutor; + private final ClientVersioningManager clientVersioningManager; + private final ContactGroupFactory contactGroupFactory; + private final ContactManager contactManager; + private final MailboxMessageParser messageParser; + private final MailboxSessionEncoder sessionEncoder; + private final MailboxSessionParser sessionParser; + private final OwnerProtocolEngine ownerProtocolEngine; + private final IntroduceeProtocolEngine introduceeProtocolEngine; + private final MailboxIntroductionCrypto crypto; + private final MailboxProtocolEngine mailboxProtocolEngine; + private final IdentityManager identityManager; + private final Clock clock; + private final Group localGroup; + + @Inject + MailboxIntroductionManagerImpl(@IoExecutor Executor ioExecutor, + DatabaseComponent db, ClientHelper clientHelper, + ClientVersioningManager clientVersioningManager, + MetadataParser metadataParser, + ContactGroupFactory contactGroupFactory, + ContactManager contactManager, MailboxMessageParser messageParser, + MailboxSessionParser sessionParser, + OwnerProtocolEngine ownerProtocolEngine, + IntroduceeProtocolEngine introduceeProtocolEngine, + MailboxSessionEncoder sessionEncoder, + MailboxIntroductionCrypto crypto, + MailboxProtocolEngine mailboxProtocolEngine, + IdentityManager identityManager, Clock clock) { + super(db, clientHelper, metadataParser); + this.ioExecutor = ioExecutor; + this.clientVersioningManager = clientVersioningManager; + this.contactGroupFactory = contactGroupFactory; + this.contactManager = contactManager; + this.messageParser = messageParser; + this.sessionParser = sessionParser; + this.ownerProtocolEngine = ownerProtocolEngine; + this.introduceeProtocolEngine = introduceeProtocolEngine; + this.sessionEncoder = sessionEncoder; + this.crypto = crypto; + this.mailboxProtocolEngine = mailboxProtocolEngine; + this.identityManager = identityManager; + this.localGroup = + contactGroupFactory.createLocalGroup(CLIENT_ID, MAJOR_VERSION); + this.clock = clock; + } + + @Override + public void createLocalState(Transaction txn) throws DbException { + // Create a local group to store protocol sessions + if (db.containsGroup(txn, localGroup.getId())) return; + db.addGroup(txn, localGroup); + // Set up groups for communication with any pre-existing contacts + for (Contact c : db.getAllContacts(txn)) addingContact(txn, c); + } + + @Override + public Collection<ContactType> getApplicableContactTypes() { + return Arrays.asList(values()); + } + + @Override + public void addingContact(Transaction txn, Contact c) throws DbException { + switch (c.getType()) { + case PRIVATE_MAILBOX: + privateMailboxAdded(txn, (PrivateMailbox) c); + break; + case CONTACT: + contactAdded(txn, c); + break; + default: + setupNewContact(txn, c); + } + } + + private void setupNewContact(Transaction txn, Contact c) + throws DbException { + // Create a group to share with the contact + Group g = getContactGroup(c); + db.addGroup(txn, g); + // Apply the client's visibility to the contact group + Group.Visibility client = clientVersioningManager + .getClientVisibility(txn, c.getId(), CLIENT_ID, MAJOR_VERSION); + db.setGroupVisibility(txn, c.getId(), g.getId(), client); + // Attach the contact ID to the group + BdfDictionary meta = new BdfDictionary(); + meta.put(GROUP_KEY_CONTACT_ID, c.getId().getInt()); + try { + clientHelper.mergeGroupMetadata(txn, g.getId(), meta); + } catch (FormatException e) { + throw new AssertionError(e); + } + } + + @Override + public void contactAdded(Transaction txn, Contact c) throws DbException { + setupNewContact(txn, c); + PrivateMailbox privateMailbox = contactManager.getPrivateMailbox(txn); + if (privateMailbox == null) return; + ioExecutor.execute(() -> { + try { + makeIntroduction(privateMailbox, c, clock.currentTimeMillis()); + } catch (DbException e) { + LOG.warning("Mailbox introduction failed: " + e.toString()); + } + }); + } + + @Override + public void privateMailboxAdded(Transaction txn, + PrivateMailbox privateMailbox) throws DbException { + setupNewContact(txn, privateMailbox); + ioExecutor.execute(() -> { + try { + for (Contact c : db.getContacts(txn)) { + makeIntroduction(privateMailbox, c, + clock.currentTimeMillis()); + } + } catch (DbException e) { + LOG.warning("Mailbox introduction failed: " + e.toString()); + } + }); + } + + @Override + protected boolean incomingMessage(Transaction txn, Message m, BdfList body, + BdfDictionary bdfMeta) throws DbException, FormatException { + MessageMetadata meta = messageParser.parseMetadata(bdfMeta); + // Look up the session, if there is one + SessionId sessionId = meta.getSessionId(); + Session session = null; + if (sessionId == null) { + if (meta.getMessageType() != MAILBOX_REQUEST) + throw new AssertionError(); + session = createMailboxSession(txn, m, body); + sessionId = session.getSessionId(); + } + StoredSession ss = getSession(txn, sessionId); + // Handle the message + MessageId storageId; + if (ss == null) { + ProtocolEngine engine; + if (meta.getMessageType() == MAILBOX_REQUEST) + engine = mailboxProtocolEngine; + else if (meta.getMessageType() == MAILBOX_ACCEPT) { + session = createIntroduceeSession(txn, m, body); + engine = introduceeProtocolEngine; + } else throw new FormatException(); + if (session == null) throw new AssertionError(); + session = handleMessage(txn, m, body, meta, session, engine); + storageId = createStorageId(txn); + } else { + storageId = ss.storageId; + Role role = sessionParser.getRole(ss.bdfSession); + switch (role) { + case OWNER: + session = handleMessage(txn, m, body, meta, + sessionParser.parseOwnerSession(ss.bdfSession), + ownerProtocolEngine); + break; + case MAILBOX: + session = handleMessage(txn, m, body, meta, sessionParser + .parseMailboxSession(m.getGroupId(), ss.bdfSession), + mailboxProtocolEngine); + break; + case INTRODUCEE: + session = handleMessage(txn, m, body, meta, sessionParser + .parseIntroduceeSession(m.getGroupId(), + ss.bdfSession), introduceeProtocolEngine); + break; + default: + throw new AssertionError(); + } + } + // Store the updated session + storeSession(txn, storageId, session); + return false; + } + + private MailboxSession createMailboxSession(Transaction txn, Message m, + BdfList body) throws DbException, FormatException { + ContactId ownerId = getContactId(txn, m.getGroupId()); + Author owner = db.getContact(txn, ownerId).getAuthor(); + Author local = identityManager.getLocalAuthor(txn); + Author remote = messageParser.parseRequestMessage(m, body).getAuthor(); + if (local.equals(remote)) throw new FormatException(); + SessionId sessionId = crypto.getSessionId(owner, local, remote, true); + return MailboxSession + .getInitial(m.getGroupId(), sessionId, owner, true, remote); + } + + private IntroduceeSession createIntroduceeSession(Transaction txn, + Message m, BdfList body) throws DbException, FormatException { + ContactId ownerId = getContactId(txn, m.getGroupId()); + Author owner = db.getContact(txn, ownerId).getAuthor(); + Author local = identityManager.getLocalAuthor(txn); + Author remote = + messageParser.parseMailboxAcceptMessage(m, body).getAuthor(); + if (local.equals(remote)) throw new FormatException(); + SessionId sessionId = crypto.getSessionId(owner, local, remote, false); + return IntroduceeSession + .getInitial(m.getGroupId(), sessionId, owner, false, remote); + } + + private <S extends Session> S handleMessage(Transaction txn, Message m, + BdfList body, MessageMetadata meta, S session, + ProtocolEngine<S> engine) throws DbException, FormatException { + if (meta.getCounter() < session.getAbortCounter()) { + LOG.warning("Ignoring old client message"); + throw new FormatException(); + } + switch (meta.getMessageType()) { + case MAILBOX_REQUEST: { + RequestMessage request = + messageParser.parseRequestMessage(m, body); + return engine.onRequestMessage(txn, session, request); + } + case DECLINE: + DeclineMessage declineMessage = + messageParser.parseDeclineMessage(m, body); + return engine.onDeclineMessage(txn, session, declineMessage); + case MAILBOX_ACCEPT: { + MailboxAcceptMessage acceptMessage = + messageParser.parseMailboxAcceptMessage(m, body); + return engine + .onMailboxAcceptMessage(txn, session, acceptMessage); + } + case INTRODUCEE_ACCEPT: { + IntroduceeAcceptMessage acceptMessage = + messageParser.parseIntroduceeAcceptMessage(m, body); + return engine + .onIntroduceeAcceptMessage(txn, session, acceptMessage); + } + case MAILBOX_AUTH: + MailboxAuthMessage authMessage = + messageParser.parseMailboxAuthMessage(m, body); + return engine.onAuthMessage(txn, session, authMessage); + case ABORT: { + AbortMessage abort = messageParser.parseAbortMessage(m, body); + return engine.onAbortMessage(txn, session, abort); + } + default: + throw new AssertionError(); + } + } + + @Nullable + private StoredSession getSession(Transaction txn, + @Nullable SessionId sessionId) throws DbException, FormatException { + if (sessionId == null) return null; + BdfDictionary query = sessionParser.getSessionQuery(sessionId); + Map<MessageId, BdfDictionary> results = clientHelper + .getMessageMetadataAsDictionary(txn, localGroup.getId(), query); + if (results.size() > 1) throw new DbException(); + if (results.isEmpty()) return null; + return new StoredSession(results.keySet().iterator().next(), + results.values().iterator().next()); + } + + @Override + public void makeIntroduction(PrivateMailbox privateMailbox, Contact contact, + long timestamp) throws DbException { + Transaction txn = db.startTransaction(false); + try { + // Look up the session, if there is one + Author introducer = identityManager.getLocalAuthor(txn); + SessionId sessionId = + crypto.getSessionId(introducer, privateMailbox.getAuthor(), + contact.getAuthor(), true); + StoredSession ss = getSession(txn, sessionId); + // Create or parse the session + OwnerSession session; + MessageId storageId; + if (ss == null) { + // This is the first request - create a new session + GroupId groupId1 = getContactGroup(privateMailbox).getId(); + GroupId groupId2 = getContactGroup(contact).getId(); + // use fixed deterministic roles for the introducees + session = new OwnerSession(sessionId, groupId1, + privateMailbox.getAuthor(), groupId2, + contact.getAuthor(), 0); + storageId = createStorageId(txn); + } else { + // An earlier request exists, so we already have a session + session = sessionParser.parseOwnerSession(ss.bdfSession); + storageId = ss.storageId; + } + // Handle the request action + session = ownerProtocolEngine + .onStartStartIntroduction(txn, session, timestamp); + // Store the updated session + storeSession(txn, storageId, session); + db.commitTransaction(txn); + } catch (FormatException e) { + throw new DbException(e); + } finally { + db.endTransaction(txn); + } + } + + private void storeSession(Transaction txn, MessageId storageId, + Session session) throws DbException { + BdfDictionary d; + if (session.getRole() == OWNER) { + d = sessionEncoder.encodeIntroducerSession((OwnerSession) session); + } else if (session.getRole() == MAILBOX || + session.getRole() == INTRODUCEE) { + d = sessionEncoder.encodeIntroduceeSession( + (AbstractIntroduceeSession) session); + } else { + throw new AssertionError(); + } + try { + clientHelper.mergeMessageMetadata(txn, storageId, d); + } catch (FormatException e) { + throw new AssertionError(); + } + } + + private ContactId getContactId(Transaction txn, GroupId contactGroupId) + throws DbException, FormatException { + BdfDictionary meta = + clientHelper.getGroupMetadataAsDictionary(txn, contactGroupId); + return new ContactId(meta.getLong(GROUP_KEY_CONTACT_ID).intValue()); + } + + @Override + public Group getContactGroup(Contact c) { + return contactGroupFactory + .createContactGroup(CLIENT_ID, MAJOR_VERSION, c); + } + + private MessageId createStorageId(Transaction txn) throws DbException { + Message m = clientHelper + .createMessageForStoringMetadata(localGroup.getId()); + db.addLocalMessage(txn, m, new Metadata(), false); + return m.getId(); + } + + @Override + public void removingContact(Transaction txn, Contact c) throws DbException { + removeSessionWithIntroducer(txn, c); + abortOrRemoveSessionWithIntroducee(txn, c); + + // Remove the contact group (all messages will be removed with it) + db.removeGroup(txn, getContactGroup(c)); + } + + private void removeSessionWithIntroducer(Transaction txn, + Contact introducer) throws DbException { + BdfDictionary query = sessionEncoder + .getIntroduceeSessionsByIntroducerQuery(introducer.getAuthor()); + Map<MessageId, BdfDictionary> sessions; + try { + sessions = clientHelper + .getMessageMetadataAsDictionary(txn, localGroup.getId(), + query); + } catch (FormatException e) { + throw new DbException(e); + } + for (MessageId id : sessions.keySet()) { + db.removeMessage(txn, id); + } + } + + private void abortOrRemoveSessionWithIntroducee(Transaction txn, Contact c) + throws DbException { + BdfDictionary query = sessionEncoder.getIntroducerSessionsQuery(); + Map<MessageId, BdfDictionary> sessions; + try { + sessions = clientHelper + .getMessageMetadataAsDictionary(txn, localGroup.getId(), + query); + } catch (FormatException e) { + throw new DbException(); + } + LocalAuthor localAuthor = identityManager.getLocalAuthor(txn); + for (Map.Entry<MessageId, BdfDictionary> session : sessions + .entrySet()) { + OwnerSession s; + try { + s = sessionParser.parseOwnerSession(session.getValue()); + } catch (FormatException e) { + throw new DbException(); + } + if (s.getMailbox().author.equals(c.getAuthor())) { + abortOrRemoveSessionWithIntroducee(txn, s, session.getKey(), + s.getIntroducee(), localAuthor); + } else if (s.getIntroducee().author.equals(c.getAuthor())) { + abortOrRemoveSessionWithIntroducee(txn, s, session.getKey(), + s.getMailbox(), localAuthor); + } + } + } + + private void abortOrRemoveSessionWithIntroducee(Transaction txn, + OwnerSession s, MessageId storageId, Introducee i, + LocalAuthor localAuthor) throws DbException { + if (db.containsContact(txn, i.author.getId(), localAuthor.getId())) { + OwnerSession session = + ownerProtocolEngine.onIntroduceeRemoved(txn, i, s); + storeSession(txn, storageId, session); + } else { + db.removeMessage(txn, storageId); + } + } + + + @Override + public void onClientVisibilityChanging(Transaction txn, Contact c, + Group.Visibility v) throws DbException { + if (!getApplicableContactTypes().contains(c.getType())) return; + // Apply the client's visibility to the contact group + Group g = getContactGroup(c); + db.setGroupVisibility(txn, c.getId(), g.getId(), v); + } + + private static class StoredSession { + + private final MessageId storageId; + private final BdfDictionary bdfSession; + + private StoredSession(MessageId storageId, BdfDictionary bdfSession) { + this.storageId = storageId; + this.bdfSession = bdfSession; + } + } +} diff --git a/bramble-core/src/main/java/org/briarproject/bramble/mailbox/introduction/MailboxIntroductionModule.java b/bramble-core/src/main/java/org/briarproject/bramble/mailbox/introduction/MailboxIntroductionModule.java new file mode 100644 index 0000000000000000000000000000000000000000..409a0149c73dd8ef6377a21756e93b42db6da901 --- /dev/null +++ b/bramble-core/src/main/java/org/briarproject/bramble/mailbox/introduction/MailboxIntroductionModule.java @@ -0,0 +1,95 @@ +package org.briarproject.bramble.mailbox.introduction; + +import org.briarproject.bramble.api.client.ClientHelper; +import org.briarproject.bramble.api.contact.ContactManager; +import org.briarproject.bramble.api.data.MetadataEncoder; +import org.briarproject.bramble.api.lifecycle.LifecycleManager; +import org.briarproject.bramble.api.mailbox.MailboxIntroductionManager; +import org.briarproject.bramble.api.sync.ValidationManager; +import org.briarproject.bramble.api.system.Clock; +import org.briarproject.bramble.api.versioning.ClientVersioningManager; + +import javax.inject.Inject; +import javax.inject.Singleton; + +import dagger.Module; +import dagger.Provides; + +import static org.briarproject.bramble.api.mailbox.MailboxIntroductionManager.CLIENT_ID; +import static org.briarproject.bramble.api.mailbox.MailboxIntroductionManager.MAJOR_VERSION; +import static org.briarproject.bramble.api.mailbox.MailboxIntroductionManager.MINOR_VERSION; + +@Module +public class MailboxIntroductionModule { + + public static class EagerSingletons { + @Inject + MailboxIntroductionValidator mailboxIntroductionValidator; + @Inject + MailboxIntroductionManager mailboxIntroductionManager; + } + + + @Provides + @Singleton + MailboxIntroductionValidator provideMailboxValidator( + ValidationManager validationManager, + MailboxMessageEncoder messageEncoder, + MetadataEncoder metadataEncoder, ClientHelper clientHelper, + Clock clock) { + MailboxIntroductionValidator mailboxIntroductionValidator = + new MailboxIntroductionValidator(messageEncoder, clientHelper, + metadataEncoder, clock); + validationManager.registerMessageValidator(CLIENT_ID, + MailboxIntroductionManager.MAJOR_VERSION, + mailboxIntroductionValidator); + return mailboxIntroductionValidator; + } + + @Provides + @Singleton + MailboxIntroductionManager provideMailboxIntroductionManager( + LifecycleManager lifecycleManager, ContactManager contactManager, + ValidationManager validationManager, + ClientVersioningManager clientVersioningManager, + MailboxIntroductionManagerImpl mailboxIntroductionManager) { + lifecycleManager.registerClient(mailboxIntroductionManager); + contactManager.registerContactHook(mailboxIntroductionManager); + validationManager.registerIncomingMessageHook(CLIENT_ID, MAJOR_VERSION, + mailboxIntroductionManager); + clientVersioningManager + .registerClient(CLIENT_ID, MAJOR_VERSION, MINOR_VERSION, + mailboxIntroductionManager); + return mailboxIntroductionManager; + } + + @Provides + MailboxMessageParser provideMailboxMessageParser( + MailboxMessageParserImpl messageParser) { + return messageParser; + } + + @Provides + MailboxMessageEncoder provideMailboxMessageEncoder( + MailboxMessageEncoderImpl messageEncoder) { + return messageEncoder; + } + + @Provides + MailboxSessionParser provideMailboxSessionParser( + MailboxSessionParserImpl sessionParser) { + return sessionParser; + } + + @Provides + MailboxSessionEncoder provideMailboxSessionEncoder( + MailboxSessionEncoderImpl sessionEncoder) { + return sessionEncoder; + } + + @Provides + MailboxIntroductionCrypto provideMailboxIntroductionCrypto( + MailboxIntroductionCryptoImpl mailboxIntroductionCrypto) { + return mailboxIntroductionCrypto; + } +} diff --git a/bramble-core/src/main/java/org/briarproject/bramble/mailbox/introduction/MailboxIntroductionValidator.java b/bramble-core/src/main/java/org/briarproject/bramble/mailbox/introduction/MailboxIntroductionValidator.java new file mode 100644 index 0000000000000000000000000000000000000000..f6a2e23627fb92a23504298b106cab3355cdb245 --- /dev/null +++ b/bramble-core/src/main/java/org/briarproject/bramble/mailbox/introduction/MailboxIntroductionValidator.java @@ -0,0 +1,216 @@ +package org.briarproject.bramble.mailbox.introduction; + +import org.briarproject.bramble.api.FormatException; +import org.briarproject.bramble.api.UniqueId; +import org.briarproject.bramble.api.client.BdfMessageContext; +import org.briarproject.bramble.api.client.BdfMessageValidator; +import org.briarproject.bramble.api.client.ClientHelper; +import org.briarproject.bramble.api.client.SessionId; +import org.briarproject.bramble.api.data.BdfDictionary; +import org.briarproject.bramble.api.data.BdfList; +import org.briarproject.bramble.api.data.MetadataEncoder; +import org.briarproject.bramble.api.nullsafety.NotNullByDefault; +import org.briarproject.bramble.api.sync.Group; +import org.briarproject.bramble.api.sync.Message; +import org.briarproject.bramble.api.sync.MessageId; +import org.briarproject.bramble.api.system.Clock; + +import java.util.Collections; + +import javax.annotation.concurrent.Immutable; + +import static org.briarproject.bramble.api.crypto.CryptoConstants.MAC_BYTES; +import static org.briarproject.bramble.api.crypto.CryptoConstants.MAX_SIGNATURE_BYTES; +import static org.briarproject.bramble.api.identity.AuthorConstants.MAX_PUBLIC_KEY_LENGTH; +import static org.briarproject.bramble.api.identity.AuthorConstants.MAX_SIGNATURE_LENGTH; +import static org.briarproject.bramble.mailbox.introduction.MessageType.INTRODUCEE_ACCEPT; +import static org.briarproject.bramble.mailbox.introduction.MessageType.MAILBOX_ACCEPT; +import static org.briarproject.bramble.mailbox.introduction.MessageType.MAILBOX_AUTH; +import static org.briarproject.bramble.util.ValidationUtils.checkLength; +import static org.briarproject.bramble.util.ValidationUtils.checkSize; + + +@Immutable +@NotNullByDefault +class MailboxIntroductionValidator extends BdfMessageValidator { + + private final MailboxMessageEncoder messageEncoder; + + MailboxIntroductionValidator(MailboxMessageEncoder messageEncoder, + ClientHelper clientHelper, MetadataEncoder metadataEncoder, + Clock clock) { + super(clientHelper, metadataEncoder, clock); + this.messageEncoder = messageEncoder; + } + + @Override + protected BdfMessageContext validateMessage(Message m, Group g, + BdfList body) throws FormatException { + MessageType type = MessageType.fromValue(body.getLong(0).intValue()); + + switch (type) { + case MAILBOX_REQUEST: + return validateRequestMessage(m, body); + case MAILBOX_ACCEPT: + return validateMailboxAcceptMessage(m, body); + case MAILBOX_AUTH: + return validateAuthMessage(m, body); + case INTRODUCEE_ACCEPT: + return validateIntroduceeAcceptMessage(m, body); + case DECLINE: + case ABORT: + return validateOtherMessage(type, m, body); + default: + throw new FormatException(); + } + } + + private BdfMessageContext validateRequestMessage(Message m, BdfList body) + throws FormatException { + checkSize(body, 4); + byte[] previousMessageId = body.getOptionalRaw(1); + checkLength(previousMessageId, UniqueId.LENGTH); + BdfList authorList = body.getList(2); + if (authorList != null) clientHelper.parseAndValidateAuthor(authorList); + long messageCounter = body.getLong(3); + BdfDictionary meta = messageEncoder + .encodeRequestMetadata(m.getTimestamp(), messageCounter); + if (previousMessageId == null) { + return new BdfMessageContext(meta); + } else { + MessageId dependency = new MessageId(previousMessageId); + return new BdfMessageContext(meta, + Collections.singletonList(dependency)); + } + } + + private BdfMessageContext validateMailboxAcceptMessage(Message m, + BdfList body) throws FormatException { + checkSize(body, 7); + + byte[] sessionIdBytes = body.getRaw(1); + checkLength(sessionIdBytes, UniqueId.LENGTH); + + byte[] previousMessageId = body.getOptionalRaw(2); + checkLength(previousMessageId, UniqueId.LENGTH); + + Object author = body.get(3); + if (author instanceof BdfList) + clientHelper.parseAndValidateAuthor((BdfList) author); + + byte[] ephemeralPublicKey = body.getRaw(4); + checkLength(ephemeralPublicKey, 0, MAX_PUBLIC_KEY_LENGTH); + + long timestamp = body.getLong(5); + if (timestamp < 0) throw new FormatException(); + + long messageCounter = body.getLong(6); + + SessionId sessionId = new SessionId(sessionIdBytes); + BdfDictionary meta = messageEncoder + .encodeMetadata(MAILBOX_ACCEPT, sessionId, m.getTimestamp(), + false, messageCounter); + if (previousMessageId == null) { + return new BdfMessageContext(meta); + } else { + MessageId dependency = new MessageId(previousMessageId); + return new BdfMessageContext(meta, + Collections.singletonList(dependency)); + } + } + + private BdfMessageContext validateIntroduceeAcceptMessage(Message m, + BdfList body) throws FormatException { + checkSize(body, 8); + + byte[] sessionIdBytes = body.getRaw(1); + checkLength(sessionIdBytes, UniqueId.LENGTH); + + byte[] previousMessageId = body.getOptionalRaw(2); + checkLength(previousMessageId, UniqueId.LENGTH); + + byte[] ephemeralPublicKey = body.getRaw(3); + checkLength(ephemeralPublicKey, 0, MAX_PUBLIC_KEY_LENGTH); + + byte[] mac = body.getRaw(4); + checkLength(mac, MAC_BYTES); + + byte[] signature = body.getRaw(5); + checkLength(signature, 1, MAX_SIGNATURE_LENGTH); + + long timestamp = body.getLong(6); + if (timestamp < 0) throw new FormatException(); + + long messageCounter = body.getLong(7); + + SessionId sessionId = new SessionId(sessionIdBytes); + BdfDictionary meta = messageEncoder + .encodeMetadata(INTRODUCEE_ACCEPT, sessionId, m.getTimestamp(), + false, messageCounter); + if (previousMessageId == null) { + return new BdfMessageContext(meta); + } else { + MessageId dependency = new MessageId(previousMessageId); + return new BdfMessageContext(meta, + Collections.singletonList(dependency)); + } + } + + private BdfMessageContext validateAuthMessage(Message m, BdfList body) + throws FormatException { + checkSize(body, 7); + + byte[] sessionIdBytes = body.getRaw(1); + checkLength(sessionIdBytes, UniqueId.LENGTH); + + byte[] previousMessageId = body.getRaw(2); + checkLength(previousMessageId, UniqueId.LENGTH); + + BdfDictionary transportProperties = body.getDictionary(3); + if (transportProperties.size() < 1) throw new FormatException(); + clientHelper + .parseAndValidateTransportPropertiesMap(transportProperties); + + byte[] mac = body.getRaw(4); + checkLength(mac, MAC_BYTES); + + byte[] signature = body.getRaw(5); + checkLength(signature, 1, MAX_SIGNATURE_BYTES); + + long messageCounter = body.getLong(6); + + SessionId sessionId = new SessionId(sessionIdBytes); + BdfDictionary meta = messageEncoder + .encodeMetadata(MAILBOX_AUTH, sessionId, m.getTimestamp(), + false, messageCounter); + MessageId dependency = new MessageId(previousMessageId); + return new BdfMessageContext(meta, + Collections.singletonList(dependency)); + } + + private BdfMessageContext validateOtherMessage(MessageType type, Message m, + BdfList body) throws FormatException { + checkSize(body, 4); + + byte[] sessionIdBytes = body.getRaw(1); + checkLength(sessionIdBytes, UniqueId.LENGTH); + + byte[] previousMessageId = body.getOptionalRaw(2); + checkLength(previousMessageId, UniqueId.LENGTH); + + long messageCounter = body.getLong(3); + + SessionId sessionId = new SessionId(sessionIdBytes); + BdfDictionary meta = messageEncoder + .encodeMetadata(type, sessionId, m.getTimestamp(), false, + messageCounter); + if (previousMessageId == null) { + return new BdfMessageContext(meta); + } else { + MessageId dependency = new MessageId(previousMessageId); + return new BdfMessageContext(meta, + Collections.singletonList(dependency)); + } + } + +} diff --git a/bramble-core/src/main/java/org/briarproject/bramble/mailbox/introduction/MailboxMessageEncoder.java b/bramble-core/src/main/java/org/briarproject/bramble/mailbox/introduction/MailboxMessageEncoder.java new file mode 100644 index 0000000000000000000000000000000000000000..f1ead80fad69969589b6149b121478118c9a3566 --- /dev/null +++ b/bramble-core/src/main/java/org/briarproject/bramble/mailbox/introduction/MailboxMessageEncoder.java @@ -0,0 +1,57 @@ +package org.briarproject.bramble.mailbox.introduction; + +import org.briarproject.bramble.api.client.SessionId; +import org.briarproject.bramble.api.data.BdfDictionary; +import org.briarproject.bramble.api.identity.Author; +import org.briarproject.bramble.api.nullsafety.NotNullByDefault; +import org.briarproject.bramble.api.plugin.TransportId; +import org.briarproject.bramble.api.properties.TransportProperties; +import org.briarproject.bramble.api.sync.GroupId; +import org.briarproject.bramble.api.sync.Message; +import org.briarproject.bramble.api.sync.MessageId; + +import java.util.Map; + +import javax.annotation.Nullable; + +@NotNullByDefault +public interface MailboxMessageEncoder { + + BdfDictionary encodeRequestMetadata(long timestamp, long messageCounter); + + BdfDictionary encodeMetadata(MessageType type, + @Nullable SessionId sessionId, long timestamp, boolean local, + long messsageCounter); + + void addSessionId(BdfDictionary meta, SessionId sessionId); + + void setAvailableToAnswer(BdfDictionary meta, boolean available); + + Message encodeRequestMessage(GroupId contactGroupId, long timestamp, + @Nullable MessageId previousMessageId, Author introduceeAuthor, + long messageCounter); + + Message encodeIntroduceeAcceptMessage(GroupId contactGroupId, + long timestamp, @Nullable MessageId previousMessageId, + SessionId sessionId, byte[] ephemeralPublicKey, byte[] mac, + byte[] signature, long acceptTimestamp, long messageCounter); + + Message encodeMailboxAcceptMessage(GroupId contactGroupId, long timestamp, + @Nullable MessageId previousMessageId, SessionId sessionId, + MessageType type, Author author, byte[] ephemeralPublicKey, + long acceptTimestamp, long messageCounter); + + Message encodeMailboxAuthMessage(GroupId contactGroupId, long timestamp, + @Nullable MessageId previousMessageId, SessionId sessionId, + Map<TransportId, TransportProperties> transportProperties, + byte[] mac, byte[] signature, long messageCounter); + + Message encodeDeclineMessage(GroupId contactGroupId, long timestamp, + @Nullable MessageId previousMessageId, SessionId sessionId, + long abortCounter); + + Message encodeAbortMessage(GroupId contactGroupId, long timestamp, + @Nullable MessageId previousMessageId, SessionId sessionId, + long abortCounter); + +} diff --git a/bramble-core/src/main/java/org/briarproject/bramble/mailbox/introduction/MailboxMessageEncoderImpl.java b/bramble-core/src/main/java/org/briarproject/bramble/mailbox/introduction/MailboxMessageEncoderImpl.java new file mode 100644 index 0000000000000000000000000000000000000000..8e438ada95b234204a10dc290ec32fac96c73344 --- /dev/null +++ b/bramble-core/src/main/java/org/briarproject/bramble/mailbox/introduction/MailboxMessageEncoderImpl.java @@ -0,0 +1,160 @@ +package org.briarproject.bramble.mailbox.introduction; + +import org.briarproject.bramble.api.FormatException; +import org.briarproject.bramble.api.client.ClientHelper; +import org.briarproject.bramble.api.client.SessionId; +import org.briarproject.bramble.api.data.BdfDictionary; +import org.briarproject.bramble.api.data.BdfList; +import org.briarproject.bramble.api.identity.Author; +import org.briarproject.bramble.api.nullsafety.NotNullByDefault; +import org.briarproject.bramble.api.plugin.TransportId; +import org.briarproject.bramble.api.properties.TransportProperties; +import org.briarproject.bramble.api.sync.GroupId; +import org.briarproject.bramble.api.sync.Message; +import org.briarproject.bramble.api.sync.MessageFactory; +import org.briarproject.bramble.api.sync.MessageId; + +import java.util.Map; + +import javax.annotation.Nullable; +import javax.inject.Inject; + +import static org.briarproject.bramble.mailbox.introduction.IntroductionConstants.MSG_KEY_AVAILABLE_TO_ANSWER; +import static org.briarproject.bramble.mailbox.introduction.IntroductionConstants.MSG_KEY_COUNTER; +import static org.briarproject.bramble.mailbox.introduction.IntroductionConstants.MSG_KEY_LOCAL; +import static org.briarproject.bramble.mailbox.introduction.IntroductionConstants.MSG_KEY_MESSAGE_TYPE; +import static org.briarproject.bramble.mailbox.introduction.IntroductionConstants.MSG_KEY_SESSION_ID; +import static org.briarproject.bramble.mailbox.introduction.IntroductionConstants.MSG_KEY_TIMESTAMP; +import static org.briarproject.bramble.mailbox.introduction.MessageType.ABORT; +import static org.briarproject.bramble.mailbox.introduction.MessageType.DECLINE; +import static org.briarproject.bramble.mailbox.introduction.MessageType.INTRODUCEE_ACCEPT; +import static org.briarproject.bramble.mailbox.introduction.MessageType.MAILBOX_AUTH; +import static org.briarproject.bramble.mailbox.introduction.MessageType.MAILBOX_REQUEST; + +@NotNullByDefault +class MailboxMessageEncoderImpl implements MailboxMessageEncoder { + + private final ClientHelper clientHelper; + private final MessageFactory messageFactory; + + @Inject + MailboxMessageEncoderImpl(ClientHelper clientHelper, + MessageFactory messageFactory) { + this.clientHelper = clientHelper; + this.messageFactory = messageFactory; + } + + @Override + public BdfDictionary encodeRequestMetadata(long timestamp, + long messageCounter) { + BdfDictionary meta = + encodeMetadata(MAILBOX_REQUEST, null, timestamp, false, + messageCounter); + meta.put(MSG_KEY_AVAILABLE_TO_ANSWER, false); + return meta; + } + + @Override + public BdfDictionary encodeMetadata(MessageType type, + @Nullable SessionId sessionId, long timestamp, boolean local, + long messageCounter) { + BdfDictionary meta = new BdfDictionary(); + meta.put(MSG_KEY_MESSAGE_TYPE, type.getValue()); + if (sessionId != null) meta.put(MSG_KEY_SESSION_ID, sessionId); + else if (type != MAILBOX_REQUEST) throw new IllegalArgumentException(); + meta.put(MSG_KEY_TIMESTAMP, timestamp); + meta.put(MSG_KEY_LOCAL, local); + meta.put(MSG_KEY_COUNTER, messageCounter); + return meta; + } + + @Override + public void addSessionId(BdfDictionary meta, SessionId sessionId) { + meta.put(MSG_KEY_SESSION_ID, sessionId); + } + + @Override + public void setAvailableToAnswer(BdfDictionary meta, boolean available) { + meta.put(MSG_KEY_AVAILABLE_TO_ANSWER, available); + } + + @Override + public Message encodeRequestMessage(GroupId contactGroupId, long timestamp, + @Nullable MessageId previousMessageId, Author introduceeAuthor, + long messageCounter) { + BdfList body = BdfList.of(MAILBOX_REQUEST.getValue(), previousMessageId, + clientHelper.toList(introduceeAuthor), messageCounter); + return createMessage(contactGroupId, timestamp, body); + } + + @Override + public Message encodeMailboxAcceptMessage(GroupId contactGroupId, + long timestamp, @Nullable MessageId previousMessageId, + SessionId sessionId, MessageType type, Author author, + byte[] ephemeralPublicKey, long acceptTimestamp, + long messageCounter) { + BdfList body = BdfList.of(type.getValue(), sessionId, previousMessageId, + author == null ? null : clientHelper.toList(author), + ephemeralPublicKey, acceptTimestamp, messageCounter); + return createMessage(contactGroupId, timestamp, body); + } + + @Override + public Message encodeIntroduceeAcceptMessage(GroupId contactGroupId, + long timestamp, @Nullable MessageId previousMessageId, + SessionId sessionId, byte[] ephemeralPublicKey, byte[] mac, + byte[] signature, long acceptTimestamp, long messageCounter) { + BdfList body = BdfList.of(INTRODUCEE_ACCEPT.getValue(), sessionId, + previousMessageId, ephemeralPublicKey, mac, signature, + acceptTimestamp, messageCounter); + return createMessage(contactGroupId, timestamp, body); + } + + @Override + public Message encodeMailboxAuthMessage(GroupId contactGroupId, + long timestamp, @Nullable MessageId previousMessageId, + SessionId sessionId, + Map<TransportId, TransportProperties> transportProperties, + byte[] mac, byte[] signature, long messageCounter) { + BdfList body = BdfList.of(MAILBOX_AUTH.getValue(), sessionId, + previousMessageId, + clientHelper.toDictionary(transportProperties), mac, signature, + messageCounter); + return createMessage(contactGroupId, timestamp, body); + } + + @Override + public Message encodeDeclineMessage(GroupId contactGroupId, long timestamp, + @Nullable MessageId previousMessageId, SessionId sessionId, + long abortCounter) { + return encodeMessage(DECLINE, contactGroupId, sessionId, timestamp, + previousMessageId, abortCounter); + } + + @Override + public Message encodeAbortMessage(GroupId contactGroupId, long timestamp, + @Nullable MessageId previousMessageId, SessionId sessionId, + long abortCounter) { + return encodeMessage(ABORT, contactGroupId, sessionId, timestamp, + previousMessageId, abortCounter); + } + + private Message encodeMessage(MessageType type, GroupId contactGroupId, + SessionId sessionId, long timestamp, + @Nullable MessageId previousMessageId, long abortCounter) { + BdfList body = BdfList.of(type.getValue(), sessionId, previousMessageId, + abortCounter); + return createMessage(contactGroupId, timestamp, body); + } + + private Message createMessage(GroupId contactGroupId, long timestamp, + BdfList body) { + try { + return messageFactory.createMessage(contactGroupId, timestamp, + clientHelper.toByteArray(body)); + } catch (FormatException e) { + throw new AssertionError(e); + } + } + +} diff --git a/bramble-core/src/main/java/org/briarproject/bramble/mailbox/introduction/MailboxMessageParser.java b/bramble-core/src/main/java/org/briarproject/bramble/mailbox/introduction/MailboxMessageParser.java new file mode 100644 index 0000000000000000000000000000000000000000..8ca36bda90b2d957a83e750794c0c545ef4828b6 --- /dev/null +++ b/bramble-core/src/main/java/org/briarproject/bramble/mailbox/introduction/MailboxMessageParser.java @@ -0,0 +1,33 @@ +package org.briarproject.bramble.mailbox.introduction; + +import org.briarproject.bramble.api.FormatException; +import org.briarproject.bramble.api.client.SessionId; +import org.briarproject.bramble.api.data.BdfDictionary; +import org.briarproject.bramble.api.data.BdfList; +import org.briarproject.bramble.api.nullsafety.NotNullByDefault; +import org.briarproject.bramble.api.sync.Message; + +@NotNullByDefault +public interface MailboxMessageParser { + + MessageMetadata parseMetadata(BdfDictionary meta) throws FormatException; + + RequestMessage parseRequestMessage(Message m, BdfList body) + throws FormatException; + + MailboxAcceptMessage parseMailboxAcceptMessage(Message m, BdfList body) + throws FormatException; + + IntroduceeAcceptMessage parseIntroduceeAcceptMessage(Message m, + BdfList body) throws FormatException; + + DeclineMessage parseDeclineMessage(Message m, BdfList body) + throws FormatException; + + MailboxAuthMessage parseMailboxAuthMessage(Message m, BdfList body) + throws FormatException; + + AbortMessage parseAbortMessage(Message m, BdfList body) + throws FormatException; + +} diff --git a/bramble-core/src/main/java/org/briarproject/bramble/mailbox/introduction/MailboxMessageParserImpl.java b/bramble-core/src/main/java/org/briarproject/bramble/mailbox/introduction/MailboxMessageParserImpl.java new file mode 100644 index 0000000000000000000000000000000000000000..778e76e820df55da1e071c2824b3d68a60ac2705 --- /dev/null +++ b/bramble-core/src/main/java/org/briarproject/bramble/mailbox/introduction/MailboxMessageParserImpl.java @@ -0,0 +1,134 @@ +package org.briarproject.bramble.mailbox.introduction; + +import org.briarproject.bramble.api.FormatException; +import org.briarproject.bramble.api.client.ClientHelper; +import org.briarproject.bramble.api.client.SessionId; +import org.briarproject.bramble.api.data.BdfDictionary; +import org.briarproject.bramble.api.data.BdfList; +import org.briarproject.bramble.api.identity.Author; +import org.briarproject.bramble.api.nullsafety.NotNullByDefault; +import org.briarproject.bramble.api.plugin.TransportId; +import org.briarproject.bramble.api.properties.TransportProperties; +import org.briarproject.bramble.api.sync.Message; +import org.briarproject.bramble.api.sync.MessageId; + +import java.util.Map; + +import javax.inject.Inject; + +import static org.briarproject.bramble.mailbox.introduction.IntroductionConstants.MSG_KEY_AVAILABLE_TO_ANSWER; +import static org.briarproject.bramble.mailbox.introduction.IntroductionConstants.MSG_KEY_COUNTER; +import static org.briarproject.bramble.mailbox.introduction.IntroductionConstants.MSG_KEY_LOCAL; +import static org.briarproject.bramble.mailbox.introduction.IntroductionConstants.MSG_KEY_MESSAGE_TYPE; +import static org.briarproject.bramble.mailbox.introduction.IntroductionConstants.MSG_KEY_SESSION_ID; +import static org.briarproject.bramble.mailbox.introduction.IntroductionConstants.MSG_KEY_TIMESTAMP; + +@NotNullByDefault +class MailboxMessageParserImpl implements MailboxMessageParser { + + private final ClientHelper clientHelper; + + @Inject + MailboxMessageParserImpl(ClientHelper clientHelper) { + this.clientHelper = clientHelper; + } + + @Override + public MessageMetadata parseMetadata(BdfDictionary d) + throws FormatException { + MessageType type = MessageType + .fromValue(d.getLong(MSG_KEY_MESSAGE_TYPE).intValue()); + byte[] sessionIdBytes = d.getOptionalRaw(MSG_KEY_SESSION_ID); + SessionId sessionId = + sessionIdBytes == null ? null : new SessionId(sessionIdBytes); + long timestamp = d.getLong(MSG_KEY_TIMESTAMP); + boolean local = d.getBoolean(MSG_KEY_LOCAL); + long counter = d.getLong(MSG_KEY_COUNTER); + boolean available = d.getBoolean(MSG_KEY_AVAILABLE_TO_ANSWER, false); + return new MessageMetadata(type, sessionId, timestamp, local, counter, + available); + } + + @Override + public RequestMessage parseRequestMessage(Message m, BdfList body) + throws FormatException { + byte[] previousMsgBytes = body.getOptionalRaw(1); + MessageId previousMessageId = (previousMsgBytes == null ? null : + new MessageId(previousMsgBytes)); + Author author = clientHelper.parseAndValidateAuthor(body.getList(2)); + return new RequestMessage(m.getId(), m.getGroupId(), m.getTimestamp(), + previousMessageId, author); + } + + @Override + public MailboxAcceptMessage parseMailboxAcceptMessage(Message m, + BdfList body) throws FormatException { + SessionId sessionId = new SessionId(body.getRaw(1)); + byte[] previousMsgBytes = body.getOptionalRaw(2); + MessageId previousMessageId = (previousMsgBytes == null ? null : + new MessageId(previousMsgBytes)); + Author author = null; + Object authorList = body.get(3); + if (authorList instanceof BdfList) + author = clientHelper.parseAndValidateAuthor((BdfList) authorList); + byte[] ephemeralPublicKey = body.getRaw(4); + long acceptTimestamp = body.getLong(5); + return new MailboxAcceptMessage(m.getId(), m.getGroupId(), + m.getTimestamp(), previousMessageId, sessionId, author, + ephemeralPublicKey, acceptTimestamp); + } + + @Override + public IntroduceeAcceptMessage parseIntroduceeAcceptMessage(Message m, + BdfList body) throws FormatException { + SessionId sessionId = new SessionId(body.getRaw(1)); + byte[] previousMsgBytes = body.getOptionalRaw(2); + MessageId previousMessageId = (previousMsgBytes == null ? null : + new MessageId(previousMsgBytes)); + byte[] ephemeralPublicKey = body.getRaw(3); + byte[] mac = body.getRaw(4); + byte[] signature = body.getRaw(5); + long acceptTimestamp = body.getLong(6); + return new IntroduceeAcceptMessage(m.getId(), m.getGroupId(), + m.getTimestamp(), previousMessageId, sessionId, + ephemeralPublicKey, mac, signature, acceptTimestamp); + } + + @Override + public DeclineMessage parseDeclineMessage(Message m, BdfList body) + throws FormatException { + SessionId sessionId = new SessionId(body.getRaw(1)); + byte[] previousMsgBytes = body.getOptionalRaw(2); + MessageId previousMessageId = (previousMsgBytes == null ? null : + new MessageId(previousMsgBytes)); + return new DeclineMessage(m.getId(), m.getGroupId(), m.getTimestamp(), + previousMessageId, sessionId); + } + + @Override + public MailboxAuthMessage parseMailboxAuthMessage(Message m, BdfList body) + throws FormatException { + SessionId sessionId = new SessionId(body.getRaw(1)); + byte[] previousMsgBytes = body.getRaw(2); + MessageId previousMessageId = new MessageId(previousMsgBytes); + Map<TransportId, TransportProperties> transportProperties = clientHelper + .parseAndValidateTransportPropertiesMap(body.getDictionary(3)); + byte[] mac = body.getRaw(4); + byte[] signature = body.getRaw(5); + return new MailboxAuthMessage(m.getId(), m.getGroupId(), + m.getTimestamp(), previousMessageId, sessionId, + transportProperties, mac, signature); + } + + @Override + public AbortMessage parseAbortMessage(Message m, BdfList body) + throws FormatException { + SessionId sessionId = new SessionId(body.getRaw(1)); + byte[] previousMsgBytes = body.getOptionalRaw(2); + MessageId previousMessageId = (previousMsgBytes == null ? null : + new MessageId(previousMsgBytes)); + return new AbortMessage(m.getId(), m.getGroupId(), m.getTimestamp(), + previousMessageId, sessionId); + } + +} diff --git a/bramble-core/src/main/java/org/briarproject/bramble/mailbox/introduction/MailboxProtocolEngine.java b/bramble-core/src/main/java/org/briarproject/bramble/mailbox/introduction/MailboxProtocolEngine.java new file mode 100644 index 0000000000000000000000000000000000000000..9f19e23ac0d2f92cf15ea1e63355855665c636a3 --- /dev/null +++ b/bramble-core/src/main/java/org/briarproject/bramble/mailbox/introduction/MailboxProtocolEngine.java @@ -0,0 +1,263 @@ +package org.briarproject.bramble.mailbox.introduction; + +import org.briarproject.bramble.api.FormatException; +import org.briarproject.bramble.api.client.ClientHelper; +import org.briarproject.bramble.api.client.ContactGroupFactory; +import org.briarproject.bramble.api.client.SessionId; +import org.briarproject.bramble.api.contact.Contact; +import org.briarproject.bramble.api.contact.ContactManager; +import org.briarproject.bramble.api.crypto.KeyPair; +import org.briarproject.bramble.api.crypto.SecretKey; +import org.briarproject.bramble.api.data.BdfDictionary; +import org.briarproject.bramble.api.db.DatabaseComponent; +import org.briarproject.bramble.api.db.DbException; +import org.briarproject.bramble.api.db.Transaction; +import org.briarproject.bramble.api.identity.IdentityManager; +import org.briarproject.bramble.api.identity.LocalAuthor; +import org.briarproject.bramble.api.mailbox.event.MailboxIntroductionAbortedEvent; +import org.briarproject.bramble.api.mailbox.event.MailboxIntroductionRequestReceivedEvent; +import org.briarproject.bramble.api.mailbox.event.MailboxIntroductionSucceededEvent; +import org.briarproject.bramble.api.plugin.TransportId; +import org.briarproject.bramble.api.properties.TransportProperties; +import org.briarproject.bramble.api.properties.TransportPropertyManager; +import org.briarproject.bramble.api.sync.Message; +import org.briarproject.bramble.api.sync.MessageId; +import org.briarproject.bramble.api.system.Clock; +import org.briarproject.bramble.api.transport.KeyManager; +import org.briarproject.bramble.api.transport.KeySetId; + +import java.security.GeneralSecurityException; +import java.util.Map; +import java.util.logging.Logger; + +import javax.annotation.Nullable; +import javax.inject.Inject; + +import static java.util.logging.Level.WARNING; +import static org.briarproject.bramble.mailbox.introduction.MailboxState.AWAIT_INTRODUCEE_RESPONSE; +import static org.briarproject.bramble.mailbox.introduction.MailboxState.CONTACT_ADDED; +import static org.briarproject.bramble.mailbox.introduction.MailboxState.INTRODUCEE_DECLINED; +import static org.briarproject.bramble.mailbox.introduction.MailboxState.START; +import static org.briarproject.bramble.util.LogUtils.logException; + +class MailboxProtocolEngine extends AbstractProtocolEngine<MailboxSession> { + + private final static Logger LOG = + Logger.getLogger(MailboxProtocolEngine.class.getName()); + + @Inject + MailboxProtocolEngine(DatabaseComponent db, ClientHelper clientHelper, + ContactManager contactManager, + ContactGroupFactory contactGroupFactory, + IdentityManager identityManager, MailboxMessageParser messageParser, + MailboxMessageEncoder messageEncoder, Clock clock, + MailboxIntroductionCrypto crypto, KeyManager keyManager, + TransportPropertyManager transportPropertyManager) { + super(db, clientHelper, contactManager, contactGroupFactory, + identityManager, messageParser, messageEncoder, clock, crypto, + keyManager, transportPropertyManager); + } + + @Override + public MailboxSession onRequestMessage(Transaction txn, MailboxSession s, + RequestMessage m) throws DbException, FormatException { + switch (s.getState()) { + case START: + return onRemoteRequest(txn, s, m); + case LOCAL_DECLINED: + case INTRODUCEE_DECLINED: + case AWAIT_INTRODUCEE_RESPONSE: + case CONTACT_ADDED: + return abort(txn, s); + default: + throw new AssertionError(); + } + } + + @Override + public MailboxSession onMailboxAcceptMessage(Transaction txn, + MailboxSession session, MailboxAcceptMessage m) + throws DbException, FormatException { + throw new UnsupportedOperationException(); + } + + @Override + public MailboxSession onIntroduceeAcceptMessage(Transaction txn, + MailboxSession s, IntroduceeAcceptMessage m) throws DbException { + switch (s.getState()) { + case AWAIT_INTRODUCEE_RESPONSE: + return handleIntroduceeAccept(txn, s, m); + case START: + case INTRODUCEE_DECLINED: + case CONTACT_ADDED: + return abort(txn, s); + default: + throw new AssertionError(); + } + } + + private MailboxSession handleIntroduceeAccept(Transaction txn, + MailboxSession s, IntroduceeAcceptMessage m) throws DbException { + // The dependency, if any, must be the last remote message + if (isInvalidDependency(s.getLastLocalMessageId(), + m.getPreviousMessageId())) return abort(txn, s); + // Broadcast IntroductionRequestReceivedEvent + LocalAuthor localAuthor = identityManager.getLocalAuthor(txn); + try { + SecretKey secretKey = + crypto.deriveMasterKey(s.local.ephemeralPublicKey, + s.local.ephemeralPrivateKey, + m.getEphemeralPublicKey(), true); + SecretKey aliceMacKey = crypto.deriveMacKey(secretKey, true); + SecretKey bobMacKey = crypto.deriveMacKey(secretKey, false); + + s = MailboxSession.addIntroduceeAccept(s, m.getMessageId(), + m.getEphemeralPublicKey(), secretKey, aliceMacKey, + bobMacKey, m.getAcceptTimestamp()); + crypto.verifyAuthMac(m.getMac(), s, localAuthor.getId()); + crypto.verifySignature(m.getSignature(), s); + long timestamp = Math.min(s.getLocal().acceptTimestamp, + s.getRemote().acceptTimestamp); + if (timestamp == -1) throw new AssertionError(); + byte[] mac = crypto.authMac(aliceMacKey, s, localAuthor.getId()); + byte[] signature = + crypto.sign(aliceMacKey, localAuthor.getPrivateKey()); + + contactManager + .addContact(txn, s.getRemote().author, localAuthor.getId(), + false, true); + // Only add transport properties and keys when the contact was added + // This will be changed once we have a way to reset state for peers + // that were contacts already at some point in the past. + Contact c = contactManager + .getContact(txn, s.getRemote().author.getId(), + localAuthor.getId()); + // add the keys to the new contact + //noinspection ConstantConditions + Map<TransportId, KeySetId> keys = keyManager + .addContact(txn, c.getId(), secretKey, timestamp, + s.getLocal().alice, true); + // add signed transport properties for the contact + //noinspection ConstantConditions + transportPropertyManager.addRemoteProperties(txn, c.getId(), + transportPropertyManager.getLocalAnonymizedProperties(txn)); + // Broadcast MailboxIntroductionSucceededEvent, because contact got added + MailboxIntroductionSucceededEvent e = + new MailboxIntroductionSucceededEvent(c); + txn.attach(e); + Map<TransportId, TransportProperties> transportProperties = + transportPropertyManager.getLocalProperties(txn); + Message reply = + sendMailboxAuthMessage(txn, s, clock.currentTimeMillis(), + transportProperties, mac, signature); + LOG.info("Contact from owner added"); + //TODO: Check for reasons to decline and if any, move to LOCAL_DECLINE + return MailboxSession.clear(s, CONTACT_ADDED, reply.getId(), + s.getLocalTimestamp(), m.getMessageId(), + s.getAbortCounter() + 1); + } catch (GeneralSecurityException e) { + logException(LOG, WARNING, e); + return abort(txn, s); + } + + } + + private MailboxSession abort(Transaction txn, MailboxSession s) + throws DbException { + // Send an ABORT message + Message sent = sendAbortMessage(txn, s, getLocalTimestamp(s)); + // Broadcast abort event for testing + txn.attach(new MailboxIntroductionAbortedEvent(s.getSessionId())); + // Reset the session back to initial state + return MailboxSession.clear(s, START, sent.getId(), sent.getTimestamp(), + s.getLastRemoteMessageId(), s.getAbortCounter() + 1); + } + + private long getLocalTimestamp(AbstractIntroduceeSession s) { + return getLocalTimestamp(s.getLocalTimestamp(), + s.getRequestTimestamp()); + } + + @Override + public MailboxSession onDeclineMessage(Transaction txn, + MailboxSession session, DeclineMessage m) + throws DbException, FormatException { + switch (session.getState()) { + case AWAIT_INTRODUCEE_RESPONSE: + break; + case START: + case LOCAL_DECLINED: + case INTRODUCEE_DECLINED: + case CONTACT_ADDED: + return abort(txn, session); + default: + throw new AssertionError(); + } + return MailboxSession.clear(session, INTRODUCEE_DECLINED, + session.getLastLocalMessageId(), m.getTimestamp(), + m.getMessageId(), session.getAbortCounter()); + } + + @Override + public MailboxSession onAuthMessage(Transaction txn, MailboxSession session, + MailboxAuthMessage m) throws DbException, FormatException { + throw new UnsupportedOperationException(); + } + + @Override + public MailboxSession onAbortMessage(Transaction txn, MailboxSession s, + AbortMessage m) throws DbException, FormatException { + // Broadcast abort event for testing + txn.attach(new MailboxIntroductionAbortedEvent(s.getSessionId())); + // Reset the session back to initial state + return MailboxSession.clear(s, START, s.getLastLocalMessageId(), + s.getLocalTimestamp(), m.getMessageId(), + s.getAbortCounter() + 1); + } + + private MailboxSession onRemoteRequest(Transaction txn, MailboxSession s, + RequestMessage m) throws DbException { + // The dependency, if any, must be the last remote message + if (isInvalidDependency(s, m.getPreviousMessageId())) + return abort(txn, s); + + // Add SessionId to message metadata + addSessionId(txn, m.getMessageId(), s.getSessionId()); + + // Broadcast IntroductionRequestReceivedEvent + LocalAuthor localAuthor = identityManager.getLocalAuthor(txn); + txn.attach(new MailboxIntroductionRequestReceivedEvent( + localAuthor.getId())); + + // Create ephemeral key pair and get local transport properties + KeyPair keyPair = crypto.generateKeyPair(); + byte[] publicKey = keyPair.getPublic().getEncoded(); + byte[] privateKey = keyPair.getPrivate().getEncoded(); + long localTimestamp = clock.currentTimeMillis(); + // Send ephemeral public key and timestamp back + Message reply = sendMailboxAcceptMessage(txn, s, localTimestamp, null, + publicKey, localTimestamp); + + //TODO: Check for reasons to decline and if any, move to LOCAL_DECLINE + // Move to the AWAIT_REMOTE_RESPONSE state + return MailboxSession + .addLocalAccept(s, AWAIT_INTRODUCEE_RESPONSE, reply, publicKey, + privateKey, localTimestamp); + } + + private boolean isInvalidDependency(AbstractIntroduceeSession s, + @Nullable MessageId dependency) { + return isInvalidDependency(s.getLastRemoteMessageId(), dependency); + } + + private void addSessionId(Transaction txn, MessageId m, SessionId sessionId) + throws DbException { + BdfDictionary meta = new BdfDictionary(); + messageEncoder.addSessionId(meta, sessionId); + try { + clientHelper.mergeMessageMetadata(txn, m, meta); + } catch (FormatException e) { + throw new AssertionError(e); + } + } +} diff --git a/bramble-core/src/main/java/org/briarproject/bramble/mailbox/introduction/MailboxSession.java b/bramble-core/src/main/java/org/briarproject/bramble/mailbox/introduction/MailboxSession.java new file mode 100644 index 0000000000000000000000000000000000000000..e9b7fe6e8c59a90190953d1cd34f7159a2d3826a --- /dev/null +++ b/bramble-core/src/main/java/org/briarproject/bramble/mailbox/introduction/MailboxSession.java @@ -0,0 +1,136 @@ +package org.briarproject.bramble.mailbox.introduction; + +import org.briarproject.bramble.api.client.SessionId; +import org.briarproject.bramble.api.crypto.SecretKey; +import org.briarproject.bramble.api.identity.Author; +import org.briarproject.bramble.api.mailbox.Role; +import org.briarproject.bramble.api.nullsafety.NotNullByDefault; +import org.briarproject.bramble.api.plugin.TransportId; +import org.briarproject.bramble.api.sync.GroupId; +import org.briarproject.bramble.api.sync.Message; +import org.briarproject.bramble.api.sync.MessageId; +import org.briarproject.bramble.api.transport.KeySetId; + +import java.util.Map; + +import javax.annotation.Nullable; +import javax.annotation.concurrent.Immutable; + +import static org.briarproject.bramble.api.mailbox.Role.MAILBOX; +import static org.briarproject.bramble.mailbox.introduction.MailboxState.START; + +@Immutable +@NotNullByDefault +class MailboxSession extends AbstractIntroduceeSession<MailboxState> { + + + MailboxSession(SessionId sessionId, MailboxState state, + long requestTimestamp, GroupId contactGroupId, Author introducer, + Local local, Remote remote, @Nullable byte[] masterKey, + @Nullable Map<TransportId, KeySetId> transportKeys, + long sessionCounter) { + super(sessionId, state, requestTimestamp, contactGroupId, introducer, + local, remote, masterKey, transportKeys, sessionCounter); + } + + static MailboxSession getInitial(GroupId contactGroupId, + SessionId sessionId, Author introducer, boolean localIsAlice, + Author remoteAuthor) { + Local local = new Local(localIsAlice, null, -1, null, null, -1, null); + Remote remote = + new Remote(!localIsAlice, remoteAuthor, null, null, null, -1, + null); + return new MailboxSession(sessionId, START, -1, contactGroupId, + introducer, local, remote, null, null, 0); + } + + static MailboxSession addLocalAccept(MailboxSession s, MailboxState state, + Message m, byte[] ephemeralPublicKey, byte[] ephemeralPrivateKey, + long acceptTimestamp) { + Local local = new Local(s.local.alice, m.getId(), m.getTimestamp(), + ephemeralPublicKey, ephemeralPrivateKey, acceptTimestamp, null); + return new MailboxSession(s.getSessionId(), state, m.getTimestamp(), + s.contactGroupId, s.introducer, local, s.remote, s.masterKey, + s.transportKeys, s.getAbortCounter()); + } + + static MailboxSession clear(MailboxSession s, MailboxState state, + @Nullable MessageId lastLocalMessageId, long localTimestamp, + @Nullable MessageId lastRemoteMessageId, long abortCounter) { + Local local = + new Local(s.local.alice, lastLocalMessageId, localTimestamp, + null, null, -1, null); + Remote remote = + new Remote(s.remote.alice, s.remote.author, lastRemoteMessageId, + null, null, -1, null); + return new MailboxSession(s.getSessionId(), state, + s.getRequestTimestamp(), s.contactGroupId, s.introducer, local, + remote, null, null, abortCounter); + } + + static MailboxSession addIntroduceeAccept(MailboxSession s, + MessageId lastMessageId, byte[] ephemeralPublicKey, + SecretKey masterKey, SecretKey aliceMacKey, SecretKey bobMacKey, + long acceptTimestamp) { + Local local = new Local(s.local.alice, s.local.lastMessageId, + s.local.lastMessageTimestamp, s.local.ephemeralPublicKey, + s.local.ephemeralPrivateKey, s.local.acceptTimestamp, + aliceMacKey.getBytes()); + Remote remote = new Remote(false, s.remote.author, lastMessageId, + ephemeralPublicKey, null, acceptTimestamp, + bobMacKey.getBytes()); + return new MailboxSession(s.getSessionId(), s.getState(), + s.getRequestTimestamp(), s.contactGroupId, s.introducer, local, + remote, masterKey.getBytes(), null, s.getAbortCounter()); + } + + @Override + Role getRole() { + return MAILBOX; + } + + @Override + public GroupId getContactGroupId() { + return contactGroupId; + } + + @Override + public long getLocalTimestamp() { + return local.lastMessageTimestamp; + } + + @Nullable + @Override + public MessageId getLastLocalMessageId() { + return local.lastMessageId; + } + + @Nullable + @Override + public MessageId getLastRemoteMessageId() { + return remote.lastMessageId; + } + + Author getIntroducer() { + return introducer; + } + + public Local getLocal() { + return local; + } + + public Remote getRemote() { + return remote; + } + + @Nullable + byte[] getMasterKey() { + return masterKey; + } + + @Nullable + Map<TransportId, KeySetId> getTransportKeys() { + return transportKeys; + } + +} diff --git a/bramble-core/src/main/java/org/briarproject/bramble/mailbox/introduction/MailboxSessionEncoder.java b/bramble-core/src/main/java/org/briarproject/bramble/mailbox/introduction/MailboxSessionEncoder.java new file mode 100644 index 0000000000000000000000000000000000000000..22bd220e475b5e04ea3cb496ac0d26e2cb67c1a9 --- /dev/null +++ b/bramble-core/src/main/java/org/briarproject/bramble/mailbox/introduction/MailboxSessionEncoder.java @@ -0,0 +1,18 @@ +package org.briarproject.bramble.mailbox.introduction; + +import org.briarproject.bramble.api.data.BdfDictionary; +import org.briarproject.bramble.api.identity.Author; +import org.briarproject.bramble.api.nullsafety.NotNullByDefault; + +@NotNullByDefault +interface MailboxSessionEncoder { + + BdfDictionary getIntroduceeSessionsByIntroducerQuery(Author introducer); + + BdfDictionary getIntroducerSessionsQuery(); + + BdfDictionary encodeIntroducerSession(OwnerSession s); + + BdfDictionary encodeIntroduceeSession(AbstractIntroduceeSession s); + +} diff --git a/bramble-core/src/main/java/org/briarproject/bramble/mailbox/introduction/MailboxSessionEncoderImpl.java b/bramble-core/src/main/java/org/briarproject/bramble/mailbox/introduction/MailboxSessionEncoderImpl.java new file mode 100644 index 0000000000000000000000000000000000000000..cb87e76defa03c491e93c60dbd27c7791bd0dcfc --- /dev/null +++ b/bramble-core/src/main/java/org/briarproject/bramble/mailbox/introduction/MailboxSessionEncoderImpl.java @@ -0,0 +1,155 @@ +package org.briarproject.bramble.mailbox.introduction; + +import org.briarproject.bramble.api.client.ClientHelper; +import org.briarproject.bramble.api.data.BdfDictionary; +import org.briarproject.bramble.api.data.BdfEntry; +import org.briarproject.bramble.api.identity.Author; +import org.briarproject.bramble.api.nullsafety.NotNullByDefault; +import org.briarproject.bramble.api.plugin.TransportId; +import org.briarproject.bramble.api.transport.KeySetId; + +import java.util.Map; + +import javax.annotation.Nullable; +import javax.annotation.concurrent.Immutable; +import javax.inject.Inject; + +import static org.briarproject.bramble.api.data.BdfDictionary.NULL_VALUE; +import static org.briarproject.bramble.api.mailbox.Role.INTRODUCEE; +import static org.briarproject.bramble.api.mailbox.Role.OWNER; +import static org.briarproject.bramble.mailbox.introduction.AbstractIntroduceeSession.Common; +import static org.briarproject.bramble.mailbox.introduction.AbstractIntroduceeSession.Local; +import static org.briarproject.bramble.mailbox.introduction.AbstractIntroduceeSession.Remote; +import static org.briarproject.bramble.mailbox.introduction.IntroductionConstants.SESSION_KEY_ACCEPT_TIMESTAMP; +import static org.briarproject.bramble.mailbox.introduction.IntroductionConstants.SESSION_KEY_ALICE; +import static org.briarproject.bramble.mailbox.introduction.IntroductionConstants.SESSION_KEY_AUTHOR; +import static org.briarproject.bramble.mailbox.introduction.IntroductionConstants.SESSION_KEY_COUNTER; +import static org.briarproject.bramble.mailbox.introduction.IntroductionConstants.SESSION_KEY_EPHEMERAL_PRIVATE_KEY; +import static org.briarproject.bramble.mailbox.introduction.IntroductionConstants.SESSION_KEY_EPHEMERAL_PUBLIC_KEY; +import static org.briarproject.bramble.mailbox.introduction.IntroductionConstants.SESSION_KEY_GROUP_ID; +import static org.briarproject.bramble.mailbox.introduction.IntroductionConstants.SESSION_KEY_INTRODUCEE_A; +import static org.briarproject.bramble.mailbox.introduction.IntroductionConstants.SESSION_KEY_INTRODUCEE_B; +import static org.briarproject.bramble.mailbox.introduction.IntroductionConstants.SESSION_KEY_INTRODUCER; +import static org.briarproject.bramble.mailbox.introduction.IntroductionConstants.SESSION_KEY_LAST_LOCAL_MESSAGE_ID; +import static org.briarproject.bramble.mailbox.introduction.IntroductionConstants.SESSION_KEY_LAST_REMOTE_MESSAGE_ID; +import static org.briarproject.bramble.mailbox.introduction.IntroductionConstants.SESSION_KEY_LOCAL; +import static org.briarproject.bramble.mailbox.introduction.IntroductionConstants.SESSION_KEY_LOCAL_TIMESTAMP; +import static org.briarproject.bramble.mailbox.introduction.IntroductionConstants.SESSION_KEY_MAC_KEY; +import static org.briarproject.bramble.mailbox.introduction.IntroductionConstants.SESSION_KEY_MASTER_KEY; +import static org.briarproject.bramble.mailbox.introduction.IntroductionConstants.SESSION_KEY_REMOTE; +import static org.briarproject.bramble.mailbox.introduction.IntroductionConstants.SESSION_KEY_REMOTE_AUTHOR; +import static org.briarproject.bramble.mailbox.introduction.IntroductionConstants.SESSION_KEY_REQUEST_TIMESTAMP; +import static org.briarproject.bramble.mailbox.introduction.IntroductionConstants.SESSION_KEY_ROLE; +import static org.briarproject.bramble.mailbox.introduction.IntroductionConstants.SESSION_KEY_SESSION_ID; +import static org.briarproject.bramble.mailbox.introduction.IntroductionConstants.SESSION_KEY_STATE; +import static org.briarproject.bramble.mailbox.introduction.IntroductionConstants.SESSION_KEY_TRANSPORT_KEYS; + +@Immutable +@NotNullByDefault +class MailboxSessionEncoderImpl implements MailboxSessionEncoder { + + private final ClientHelper clientHelper; + + @Inject + MailboxSessionEncoderImpl(ClientHelper clientHelper) { + this.clientHelper = clientHelper; + } + + @Override + public BdfDictionary getIntroduceeSessionsByIntroducerQuery( + Author introducer) { + return BdfDictionary + .of(new BdfEntry(SESSION_KEY_ROLE, INTRODUCEE.getValue()), + new BdfEntry(SESSION_KEY_INTRODUCER, + clientHelper.toList(introducer))); + } + + @Override + public BdfDictionary getIntroducerSessionsQuery() { + return BdfDictionary + .of(new BdfEntry(SESSION_KEY_ROLE, OWNER.getValue())); + } + + @Override + public BdfDictionary encodeIntroducerSession(OwnerSession s) { + BdfDictionary d = encodeSession(s); + d.put(SESSION_KEY_INTRODUCEE_A, encodeIntroducee(s.getMailbox())); + d.put(SESSION_KEY_INTRODUCEE_B, encodeIntroducee(s.getIntroducee())); + return d; + } + + private BdfDictionary encodeIntroducee(Introducee i) { + BdfDictionary d = new BdfDictionary(); + putNullable(d, SESSION_KEY_LAST_LOCAL_MESSAGE_ID, i.lastLocalMessageId); + putNullable(d, SESSION_KEY_LAST_REMOTE_MESSAGE_ID, + i.lastRemoteMessageId); + d.put(SESSION_KEY_LOCAL_TIMESTAMP, i.localTimestamp); + d.put(SESSION_KEY_GROUP_ID, i.groupId); + d.put(SESSION_KEY_AUTHOR, clientHelper.toList(i.author)); + d.put(SESSION_KEY_COUNTER, i.abortCounter); + return d; + } + + @Override + public BdfDictionary encodeIntroduceeSession(AbstractIntroduceeSession s) { + BdfDictionary d = encodeSession(s); + d.put(SESSION_KEY_INTRODUCER, clientHelper.toList(s.getIntroducer())); + d.put(SESSION_KEY_LOCAL, encodeLocal(s.getLocal())); + d.put(SESSION_KEY_REMOTE, encodeRemote(s.getRemote())); + putNullable(d, SESSION_KEY_MASTER_KEY, s.getMasterKey()); + putNullable(d, SESSION_KEY_TRANSPORT_KEYS, + encodeTransportKeys(s.getTransportKeys())); + return d; + } + + private BdfDictionary encodeCommon(Common s) { + BdfDictionary d = new BdfDictionary(); + d.put(SESSION_KEY_ALICE, s.alice); + putNullable(d, SESSION_KEY_EPHEMERAL_PUBLIC_KEY, s.ephemeralPublicKey); + d.put(SESSION_KEY_ACCEPT_TIMESTAMP, s.acceptTimestamp); + putNullable(d, SESSION_KEY_MAC_KEY, s.macKey); + return d; + } + + private BdfDictionary encodeLocal(Local s) { + BdfDictionary d = encodeCommon(s); + d.put(SESSION_KEY_LOCAL_TIMESTAMP, s.lastMessageTimestamp); + putNullable(d, SESSION_KEY_LAST_LOCAL_MESSAGE_ID, s.lastMessageId); + putNullable(d, SESSION_KEY_EPHEMERAL_PRIVATE_KEY, + s.ephemeralPrivateKey); + return d; + } + + private BdfDictionary encodeRemote(Remote s) { + BdfDictionary d = encodeCommon(s); + d.put(SESSION_KEY_REMOTE_AUTHOR, clientHelper.toList(s.author)); + putNullable(d, SESSION_KEY_LAST_REMOTE_MESSAGE_ID, s.lastMessageId); + return d; + } + + private BdfDictionary encodeSession(Session s) { + BdfDictionary d = new BdfDictionary(); + d.put(SESSION_KEY_SESSION_ID, s.getSessionId()); + d.put(SESSION_KEY_ROLE, s.getRole().getValue()); + d.put(SESSION_KEY_STATE, s.getState().getValue()); + d.put(SESSION_KEY_REQUEST_TIMESTAMP, s.getRequestTimestamp()); + d.put(SESSION_KEY_COUNTER, s.getAbortCounter()); + return d; + } + + @Nullable + private BdfDictionary encodeTransportKeys( + @Nullable Map<TransportId, KeySetId> keys) { + if (keys == null) return null; + BdfDictionary d = new BdfDictionary(); + for (Map.Entry<TransportId, KeySetId> e : keys.entrySet()) { + d.put(e.getKey().getString(), e.getValue().getInt()); + } + return d; + } + + private void putNullable(BdfDictionary d, String key, @Nullable Object o) { + d.put(key, o == null ? NULL_VALUE : o); + } + +} diff --git a/bramble-core/src/main/java/org/briarproject/bramble/mailbox/introduction/MailboxSessionParser.java b/bramble-core/src/main/java/org/briarproject/bramble/mailbox/introduction/MailboxSessionParser.java new file mode 100644 index 0000000000000000000000000000000000000000..a77b3c6018abb78fcc0e9741d2639d9323551b31 --- /dev/null +++ b/bramble-core/src/main/java/org/briarproject/bramble/mailbox/introduction/MailboxSessionParser.java @@ -0,0 +1,27 @@ +package org.briarproject.bramble.mailbox.introduction; + +import org.briarproject.bramble.api.FormatException; +import org.briarproject.bramble.api.client.SessionId; +import org.briarproject.bramble.api.data.BdfDictionary; +import org.briarproject.bramble.api.mailbox.Role; +import org.briarproject.bramble.api.nullsafety.NotNullByDefault; +import org.briarproject.bramble.api.sync.GroupId; + +@NotNullByDefault +public interface MailboxSessionParser { + + BdfDictionary getSessionQuery(SessionId s); + + Role getRole(BdfDictionary d) throws FormatException; + + long getMessageCounter(BdfDictionary d) throws FormatException; + + OwnerSession parseOwnerSession(BdfDictionary d) throws FormatException; + + MailboxSession parseMailboxSession(GroupId introducerGroupId, + BdfDictionary d) throws FormatException; + + IntroduceeSession parseIntroduceeSession(GroupId introducerGroupId, + BdfDictionary d) throws FormatException; + +} diff --git a/bramble-core/src/main/java/org/briarproject/bramble/mailbox/introduction/MailboxSessionParserImpl.java b/bramble-core/src/main/java/org/briarproject/bramble/mailbox/introduction/MailboxSessionParserImpl.java new file mode 100644 index 0000000000000000000000000000000000000000..a714fe929a7eeb8410fdbb96ae531858d748e4b4 --- /dev/null +++ b/bramble-core/src/main/java/org/briarproject/bramble/mailbox/introduction/MailboxSessionParserImpl.java @@ -0,0 +1,231 @@ +package org.briarproject.bramble.mailbox.introduction; + +import org.briarproject.bramble.api.FormatException; +import org.briarproject.bramble.api.client.ClientHelper; +import org.briarproject.bramble.api.client.SessionId; +import org.briarproject.bramble.api.data.BdfDictionary; +import org.briarproject.bramble.api.data.BdfEntry; +import org.briarproject.bramble.api.identity.Author; +import org.briarproject.bramble.api.mailbox.Role; +import org.briarproject.bramble.api.nullsafety.NotNullByDefault; +import org.briarproject.bramble.api.plugin.TransportId; +import org.briarproject.bramble.api.properties.TransportProperties; +import org.briarproject.bramble.api.sync.GroupId; +import org.briarproject.bramble.api.sync.MessageId; +import org.briarproject.bramble.api.transport.KeySetId; + +import java.util.HashMap; +import java.util.Map; + +import javax.annotation.Nullable; +import javax.annotation.concurrent.Immutable; +import javax.inject.Inject; + +import static org.briarproject.bramble.api.mailbox.Role.INTRODUCEE; +import static org.briarproject.bramble.api.mailbox.Role.MAILBOX; +import static org.briarproject.bramble.api.mailbox.Role.OWNER; +import static org.briarproject.bramble.api.mailbox.Role.fromValue; +import static org.briarproject.bramble.mailbox.introduction.AbstractIntroduceeSession.Local; +import static org.briarproject.bramble.mailbox.introduction.AbstractIntroduceeSession.Remote; +import static org.briarproject.bramble.mailbox.introduction.IntroductionConstants.SESSION_KEY_ACCEPT_TIMESTAMP; +import static org.briarproject.bramble.mailbox.introduction.IntroductionConstants.SESSION_KEY_ALICE; +import static org.briarproject.bramble.mailbox.introduction.IntroductionConstants.SESSION_KEY_AUTHOR; +import static org.briarproject.bramble.mailbox.introduction.IntroductionConstants.SESSION_KEY_COUNTER; +import static org.briarproject.bramble.mailbox.introduction.IntroductionConstants.SESSION_KEY_EPHEMERAL_PRIVATE_KEY; +import static org.briarproject.bramble.mailbox.introduction.IntroductionConstants.SESSION_KEY_EPHEMERAL_PUBLIC_KEY; +import static org.briarproject.bramble.mailbox.introduction.IntroductionConstants.SESSION_KEY_GROUP_ID; +import static org.briarproject.bramble.mailbox.introduction.IntroductionConstants.SESSION_KEY_INTRODUCEE_A; +import static org.briarproject.bramble.mailbox.introduction.IntroductionConstants.SESSION_KEY_INTRODUCEE_B; +import static org.briarproject.bramble.mailbox.introduction.IntroductionConstants.SESSION_KEY_INTRODUCER; +import static org.briarproject.bramble.mailbox.introduction.IntroductionConstants.SESSION_KEY_LAST_LOCAL_MESSAGE_ID; +import static org.briarproject.bramble.mailbox.introduction.IntroductionConstants.SESSION_KEY_LAST_REMOTE_MESSAGE_ID; +import static org.briarproject.bramble.mailbox.introduction.IntroductionConstants.SESSION_KEY_LOCAL; +import static org.briarproject.bramble.mailbox.introduction.IntroductionConstants.SESSION_KEY_LOCAL_TIMESTAMP; +import static org.briarproject.bramble.mailbox.introduction.IntroductionConstants.SESSION_KEY_MAC_KEY; +import static org.briarproject.bramble.mailbox.introduction.IntroductionConstants.SESSION_KEY_MASTER_KEY; +import static org.briarproject.bramble.mailbox.introduction.IntroductionConstants.SESSION_KEY_REMOTE; +import static org.briarproject.bramble.mailbox.introduction.IntroductionConstants.SESSION_KEY_REMOTE_AUTHOR; +import static org.briarproject.bramble.mailbox.introduction.IntroductionConstants.SESSION_KEY_REQUEST_TIMESTAMP; +import static org.briarproject.bramble.mailbox.introduction.IntroductionConstants.SESSION_KEY_ROLE; +import static org.briarproject.bramble.mailbox.introduction.IntroductionConstants.SESSION_KEY_SESSION_ID; +import static org.briarproject.bramble.mailbox.introduction.IntroductionConstants.SESSION_KEY_STATE; +import static org.briarproject.bramble.mailbox.introduction.IntroductionConstants.SESSION_KEY_TRANSPORT_KEYS; +import static org.briarproject.bramble.mailbox.introduction.IntroductionConstants.SESSION_KEY_TRANSPORT_PROPERTIES; + +@Immutable +@NotNullByDefault +class MailboxSessionParserImpl implements MailboxSessionParser { + + private final ClientHelper clientHelper; + + @Inject + MailboxSessionParserImpl(ClientHelper clientHelper) { + this.clientHelper = clientHelper; + } + + @Override + public BdfDictionary getSessionQuery(SessionId s) { + return BdfDictionary.of(new BdfEntry(SESSION_KEY_SESSION_ID, s)); + } + + @Override + public Role getRole(BdfDictionary d) throws FormatException { + return fromValue(d.getLong(SESSION_KEY_ROLE).intValue()); + } + + @Override + public long getMessageCounter(BdfDictionary d) throws FormatException { + return d.getLong(SESSION_KEY_COUNTER); + } + + @Override + public OwnerSession parseOwnerSession(BdfDictionary d) + throws FormatException { + if (getRole(d) != OWNER) throw new IllegalArgumentException(); + SessionId sessionId = getSessionId(d); + long sessionCounter = getSessionCounter(d); + OwnerState state = OwnerState.fromValue(getState(d)); + long requestTimestamp = d.getLong(SESSION_KEY_REQUEST_TIMESTAMP); + Introducee introduceeA = parseIntroducee(sessionId, + d.getDictionary(SESSION_KEY_INTRODUCEE_A)); + Introducee introduceeB = parseIntroducee(sessionId, + d.getDictionary(SESSION_KEY_INTRODUCEE_B)); + return new OwnerSession(sessionId, state, requestTimestamp, introduceeA, + introduceeB, sessionCounter); + } + + private Introducee parseIntroducee(SessionId sessionId, BdfDictionary d) + throws FormatException { + MessageId lastLocalMessageId = + getMessageId(d, SESSION_KEY_LAST_LOCAL_MESSAGE_ID); + MessageId lastRemoteMessageId = + getMessageId(d, SESSION_KEY_LAST_REMOTE_MESSAGE_ID); + long localTimestamp = d.getLong(SESSION_KEY_LOCAL_TIMESTAMP); + GroupId groupId = getGroupId(d, SESSION_KEY_GROUP_ID); + Author author = getAuthor(d, SESSION_KEY_AUTHOR); + long abortCounter = d.getLong(SESSION_KEY_COUNTER); + return new Introducee(sessionId, groupId, author, localTimestamp, + lastLocalMessageId, lastRemoteMessageId, abortCounter); + } + + @Override + public MailboxSession parseMailboxSession(GroupId introducerGroupId, + BdfDictionary d) throws FormatException { + if (getRole(d) != MAILBOX) throw new IllegalArgumentException(); + SessionId sessionId = getSessionId(d); + long sessionCounter = getSessionCounter(d); + MailboxState state = MailboxState.fromValue(getState(d)); + long requestTimestamp = d.getLong(SESSION_KEY_REQUEST_TIMESTAMP); + Author introducer = getAuthor(d, SESSION_KEY_INTRODUCER); + Local local = parseLocal(d.getDictionary(SESSION_KEY_LOCAL)); + Remote remote = parseRemote(d.getDictionary(SESSION_KEY_REMOTE)); + byte[] masterKey = d.getOptionalRaw(SESSION_KEY_MASTER_KEY); + Map<TransportId, KeySetId> transportKeys = parseTransportKeys( + d.getOptionalDictionary(SESSION_KEY_TRANSPORT_KEYS)); + return new MailboxSession(sessionId, state, requestTimestamp, + introducerGroupId, introducer, local, remote, masterKey, + transportKeys, sessionCounter); + } + + @Override + public IntroduceeSession parseIntroduceeSession(GroupId introducerGroupId, + BdfDictionary d) throws FormatException { + if (getRole(d) != INTRODUCEE) throw new IllegalArgumentException(); + SessionId sessionId = getSessionId(d); + long sessionCounter = getSessionCounter(d); + IntroduceeState state = IntroduceeState.fromValue(getState(d)); + long requestTimestamp = d.getLong(SESSION_KEY_REQUEST_TIMESTAMP); + Author introducer = getAuthor(d, SESSION_KEY_INTRODUCER); + Local local = parseLocal(d.getDictionary(SESSION_KEY_LOCAL)); + Remote remote = parseRemote(d.getDictionary(SESSION_KEY_REMOTE)); + byte[] masterKey = d.getOptionalRaw(SESSION_KEY_MASTER_KEY); + Map<TransportId, KeySetId> transportKeys = parseTransportKeys( + d.getOptionalDictionary(SESSION_KEY_TRANSPORT_KEYS)); + return new IntroduceeSession(sessionId, state, requestTimestamp, + introducerGroupId, introducer, local, remote, masterKey, + transportKeys, sessionCounter); + } + + private Local parseLocal(BdfDictionary d) throws FormatException { + boolean alice = d.getBoolean(SESSION_KEY_ALICE); + MessageId lastLocalMessageId = + getMessageId(d, SESSION_KEY_LAST_LOCAL_MESSAGE_ID); + long localTimestamp = d.getLong(SESSION_KEY_LOCAL_TIMESTAMP); + byte[] ephemeralPublicKey = + d.getOptionalRaw(SESSION_KEY_EPHEMERAL_PUBLIC_KEY); + BdfDictionary tpDict = + d.getOptionalDictionary(SESSION_KEY_TRANSPORT_PROPERTIES); + byte[] ephemeralPrivateKey = + d.getOptionalRaw(SESSION_KEY_EPHEMERAL_PRIVATE_KEY); + Map<TransportId, TransportProperties> transportProperties = + tpDict == null ? null : clientHelper + .parseAndValidateTransportPropertiesMap(tpDict); + long acceptTimestamp = d.getLong(SESSION_KEY_ACCEPT_TIMESTAMP); + byte[] macKey = d.getOptionalRaw(SESSION_KEY_MAC_KEY); + return new Local(alice, lastLocalMessageId, localTimestamp, + ephemeralPublicKey, ephemeralPrivateKey, acceptTimestamp, + macKey); + } + + private Remote parseRemote(BdfDictionary d) throws FormatException { + boolean alice = d.getBoolean(SESSION_KEY_ALICE); + Author remoteAuthor = getAuthor(d, SESSION_KEY_REMOTE_AUTHOR); + MessageId lastRemoteMessageId = + getMessageId(d, SESSION_KEY_LAST_REMOTE_MESSAGE_ID); + byte[] ephemeralPublicKey = + d.getOptionalRaw(SESSION_KEY_EPHEMERAL_PUBLIC_KEY); + BdfDictionary tpDict = + d.getOptionalDictionary(SESSION_KEY_TRANSPORT_PROPERTIES); + Map<TransportId, TransportProperties> transportProperties = + tpDict == null ? null : clientHelper + .parseAndValidateTransportPropertiesMap(tpDict); + long acceptTimestamp = d.getLong(SESSION_KEY_ACCEPT_TIMESTAMP); + byte[] macKey = d.getOptionalRaw(SESSION_KEY_MAC_KEY); + return new Remote(alice, remoteAuthor, lastRemoteMessageId, + ephemeralPublicKey, transportProperties, acceptTimestamp, + macKey); + } + + private int getState(BdfDictionary d) throws FormatException { + return d.getLong(SESSION_KEY_STATE).intValue(); + } + + private long getSessionCounter(BdfDictionary d) throws FormatException { + return d.getLong(SESSION_KEY_COUNTER); + } + + private SessionId getSessionId(BdfDictionary d) throws FormatException { + byte[] b = d.getRaw(SESSION_KEY_SESSION_ID); + return new SessionId(b); + } + + @Nullable + private MessageId getMessageId(BdfDictionary d, String key) + throws FormatException { + byte[] b = d.getOptionalRaw(key); + return b == null ? null : new MessageId(b); + } + + private GroupId getGroupId(BdfDictionary d, String key) + throws FormatException { + return new GroupId(d.getRaw(key)); + } + + private Author getAuthor(BdfDictionary d, String key) + throws FormatException { + return clientHelper.parseAndValidateAuthor(d.getList(key)); + } + + @Nullable + private Map<TransportId, KeySetId> parseTransportKeys( + @Nullable BdfDictionary d) throws FormatException { + if (d == null) return null; + Map<TransportId, KeySetId> map = new HashMap<>(d.size()); + for (String key : d.keySet()) { + map.put(new TransportId(key), + new KeySetId(d.getLong(key).intValue())); + } + return map; + } + +} diff --git a/bramble-core/src/main/java/org/briarproject/bramble/mailbox/introduction/MailboxState.java b/bramble-core/src/main/java/org/briarproject/bramble/mailbox/introduction/MailboxState.java new file mode 100644 index 0000000000000000000000000000000000000000..9a00c0584be99f19061342777315526e583d7c6b --- /dev/null +++ b/bramble-core/src/main/java/org/briarproject/bramble/mailbox/introduction/MailboxState.java @@ -0,0 +1,34 @@ +package org.briarproject.bramble.mailbox.introduction; + +import org.briarproject.bramble.api.FormatException; +import org.briarproject.bramble.api.nullsafety.NotNullByDefault; + +import javax.annotation.concurrent.Immutable; + +@Immutable +@NotNullByDefault +enum MailboxState implements State { + + START(0), + LOCAL_DECLINED(1), + AWAIT_INTRODUCEE_RESPONSE(2), + INTRODUCEE_DECLINED(3), + CONTACT_ADDED(4); + + private final int value; + + MailboxState(int value) { + this.value = value; + } + + @Override + public int getValue() { + return value; + } + + static MailboxState fromValue(int value) throws FormatException { + for (MailboxState s : values()) if (s.value == value) return s; + throw new FormatException(); + } + +} diff --git a/bramble-core/src/main/java/org/briarproject/bramble/mailbox/introduction/MessageMetadata.java b/bramble-core/src/main/java/org/briarproject/bramble/mailbox/introduction/MessageMetadata.java new file mode 100644 index 0000000000000000000000000000000000000000..2acc677119e45d63d8678d89b0797c6d6c8f4e1a --- /dev/null +++ b/bramble-core/src/main/java/org/briarproject/bramble/mailbox/introduction/MessageMetadata.java @@ -0,0 +1,55 @@ +package org.briarproject.bramble.mailbox.introduction; + +import org.briarproject.bramble.api.client.SessionId; +import org.briarproject.bramble.api.nullsafety.NotNullByDefault; + +import javax.annotation.Nullable; +import javax.annotation.concurrent.Immutable; + +@Immutable +@NotNullByDefault +class MessageMetadata { + + private final MessageType type; + @Nullable + private final SessionId sessionId; + private final long timestamp, counter; + private final boolean local; + private final boolean available; + + MessageMetadata(MessageType type, @Nullable SessionId sessionId, + long timestamp, boolean local, long counter, boolean available) { + this.type = type; + this.sessionId = sessionId; + this.timestamp = timestamp; + this.local = local; + this.counter = counter; + this.available = available; + } + + MessageType getMessageType() { + return type; + } + + @Nullable + public SessionId getSessionId() { + return sessionId; + } + + long getTimestamp() { + return timestamp; + } + + boolean isLocal() { + return local; + } + + long getCounter() { + return counter; + } + + boolean isAvailableToAnswer() { + return available; + } + +} diff --git a/bramble-core/src/main/java/org/briarproject/bramble/mailbox/introduction/MessageType.java b/bramble-core/src/main/java/org/briarproject/bramble/mailbox/introduction/MessageType.java new file mode 100644 index 0000000000000000000000000000000000000000..10a6efd804f4ad0aa17b75ecdff3d9c20d610457 --- /dev/null +++ b/bramble-core/src/main/java/org/briarproject/bramble/mailbox/introduction/MessageType.java @@ -0,0 +1,35 @@ +package org.briarproject.bramble.mailbox.introduction; + +import org.briarproject.bramble.api.FormatException; +import org.briarproject.bramble.api.nullsafety.NotNullByDefault; + +import javax.annotation.concurrent.Immutable; + +@Immutable +@NotNullByDefault +enum MessageType { + + MAILBOX_REQUEST(0), + MAILBOX_ACCEPT(1), + INTRODUCEE_ACCEPT(3), + CONTACT_INFO(4), + MAILBOX_AUTH(5), + DECLINE(6), + ABORT(7); + + private final int value; + + MessageType(int value) { + this.value = value; + } + + int getValue() { + return value; + } + + static MessageType fromValue(int value) throws FormatException { + for (MessageType m : values()) if (m.value == value) return m; + throw new FormatException(); + } + +} diff --git a/bramble-core/src/main/java/org/briarproject/bramble/mailbox/introduction/OwnerProtocolEngine.java b/bramble-core/src/main/java/org/briarproject/bramble/mailbox/introduction/OwnerProtocolEngine.java new file mode 100644 index 0000000000000000000000000000000000000000..50be2b64befd32113684b0bcd306c1be98c89023 --- /dev/null +++ b/bramble-core/src/main/java/org/briarproject/bramble/mailbox/introduction/OwnerProtocolEngine.java @@ -0,0 +1,262 @@ +package org.briarproject.bramble.mailbox.introduction; + +import org.briarproject.bramble.api.FormatException; +import org.briarproject.bramble.api.client.ClientHelper; +import org.briarproject.bramble.api.client.ContactGroupFactory; +import org.briarproject.bramble.api.client.ProtocolStateException; +import org.briarproject.bramble.api.contact.Contact; +import org.briarproject.bramble.api.contact.ContactManager; +import org.briarproject.bramble.api.db.DatabaseComponent; +import org.briarproject.bramble.api.db.DbException; +import org.briarproject.bramble.api.db.Transaction; +import org.briarproject.bramble.api.identity.Author; +import org.briarproject.bramble.api.identity.IdentityManager; +import org.briarproject.bramble.api.mailbox.event.MailboxIntroductionAbortedEvent; +import org.briarproject.bramble.api.mailbox.event.MailboxIntroductionResponseReceivedEvent; +import org.briarproject.bramble.api.mailbox.event.MailboxIntroductionSucceededEvent; +import org.briarproject.bramble.api.properties.TransportPropertyManager; +import org.briarproject.bramble.api.sync.GroupId; +import org.briarproject.bramble.api.sync.Message; +import org.briarproject.bramble.api.system.Clock; +import org.briarproject.bramble.api.transport.KeyManager; + +import java.util.logging.Logger; + +import javax.inject.Inject; + +import static org.briarproject.bramble.mailbox.introduction.OwnerState.ADDED; +import static org.briarproject.bramble.mailbox.introduction.OwnerState.AWAIT_AUTH_M; +import static org.briarproject.bramble.mailbox.introduction.OwnerState.AWAIT_RESPONSE_B; +import static org.briarproject.bramble.mailbox.introduction.OwnerState.AWAIT_RESPONSE_M; +import static org.briarproject.bramble.mailbox.introduction.OwnerState.START; + +class OwnerProtocolEngine extends AbstractProtocolEngine<OwnerSession> { + + private static final Logger LOG = + Logger.getLogger(OwnerProtocolEngine.class.getName()); + + @Inject + OwnerProtocolEngine(DatabaseComponent db, ClientHelper clientHelper, + ContactManager contactManager, + ContactGroupFactory contactGroupFactory, + IdentityManager identityManager, MailboxMessageParser messageParser, + MailboxMessageEncoder messageEncoder, Clock clock, + MailboxIntroductionCrypto crypto, KeyManager keyManager, + TransportPropertyManager transportPropertyManager) { + super(db, clientHelper, contactManager, contactGroupFactory, + identityManager, messageParser, messageEncoder, clock, crypto, + keyManager, transportPropertyManager); + } + + OwnerSession onStartStartIntroduction(Transaction txn, OwnerSession s, + long timestamp) throws DbException { + switch (s.getState()) { + case START: + return onLocalRequest(txn, s, timestamp); + case AWAIT_RESPONSE_M: + case M_DECLINED: + case AWAIT_RESPONSE_B: + case B_DECLINED: + case AWAIT_AUTH_M: + case ADDED: + throw new ProtocolStateException(); // Invalid in these states + default: + throw new AssertionError(); + } + } + + @Override + public OwnerSession onRequestMessage(Transaction txn, OwnerSession session, + RequestMessage m) throws DbException, FormatException { + // return abort(txn, session); + throw new UnsupportedOperationException(); + } + + @Override + public OwnerSession onMailboxAcceptMessage(Transaction txn, OwnerSession s, + MailboxAcceptMessage m) throws DbException, FormatException { + switch (s.getState()) { + case START: + case AWAIT_RESPONSE_M: + return onMailboxAccept(txn, s, m); + case M_DECLINED: + case AWAIT_RESPONSE_B: + case B_DECLINED: + case AWAIT_AUTH_M: + case ADDED: + throw new ProtocolStateException(); // Invalid in these states + default: + throw new AssertionError(); + } + } + + private OwnerSession onMailboxAccept(Transaction txn, OwnerSession s, + MailboxAcceptMessage m) throws DbException { + // The dependency, if any, must be the last remote message + if (isInvalidDependency(s.getMailbox().lastRemoteMessageId, + m.getPreviousMessageId())) return abort(txn, s); + Message forward = sendMailboxAcceptMessage(txn, s.getIntroducee(), + clock.currentTimeMillis(), s.getMailbox().author, + m.getEphemeralPublicKey(), m.getAcceptTimestamp()); + broadcastMailboxIntroductionResponseReceived(txn, s.getMailbox().author, + s.getIntroducee().author); + return new OwnerSession(s.getSessionId(), AWAIT_RESPONSE_B, + s.getRequestTimestamp(), + new Introducee(s.getMailbox(), m.getMessageId(), + s.getAbortCounter()), + new Introducee(s.getIntroducee(), forward, s.getAbortCounter()), + s.getAbortCounter()); + } + + @Override + public OwnerSession onDeclineMessage(Transaction txn, OwnerSession session, + DeclineMessage m) throws DbException, FormatException { + return null; + } + + @Override + public OwnerSession onAuthMessage(Transaction txn, OwnerSession s, + MailboxAuthMessage m) throws DbException, FormatException { + // The dependency, if any, must be the last remote message + if (isInvalidDependency(s.getMailbox().getLastLocalMessageId(), + m.getPreviousMessageId())) return abort(txn, s); + Message forward = sendMailboxAuthMessage(txn, s.getIntroducee(), + clock.currentTimeMillis(), m.getTransportProperties(), + m.getMac(), m.getSignature()); + Contact c = contactManager + .getContact(txn, s.getIntroducee().author.getId(), + identityManager.getLocalAuthor().getId()); + db.setMailboxForContact(txn, c.getId(), null, c.getId()); + txn.attach(new MailboxIntroductionSucceededEvent(c)); + return new OwnerSession(s.getSessionId(), ADDED, + s.getRequestTimestamp(), + new Introducee(s.getMailbox(), m.getMessageId(), + s.getAbortCounter()), + new Introducee(s.getIntroducee(), forward, s.getAbortCounter()), + s.getAbortCounter()); + } + + @Override + public OwnerSession onAbortMessage(Transaction txn, OwnerSession s, + AbortMessage m) throws DbException { + // Forward ABORT message + Introducee i = getOtherIntroducee(s, m.getGroupId()); + long timestamp = getLocalTimestamp(s, i); + Message sent = sendAbortMessage(txn, i, timestamp); + + // Broadcast abort event for testing + txn.attach(new MailboxIntroductionAbortedEvent(s.getSessionId())); + + // Reset the session back to initial state + Introducee mailbox, introduceeB; + long abortCounter = s.getAbortCounter() + 1; + if (i.equals(s.getMailbox())) { + mailbox = new Introducee(s.getMailbox(), sent, abortCounter); + introduceeB = new Introducee(s.getIntroducee(), m.getMessageId(), + abortCounter); + } else if (i.equals(s.getIntroducee())) { + mailbox = new Introducee(s.getMailbox(), m.getMessageId(), + abortCounter); + introduceeB = new Introducee(s.getIntroducee(), sent, abortCounter); + } else throw new AssertionError(); + return new OwnerSession(s.getSessionId(), START, + s.getRequestTimestamp(), mailbox, introduceeB, abortCounter); + } + + @Override + public OwnerSession onIntroduceeAcceptMessage(Transaction txn, + OwnerSession s, IntroduceeAcceptMessage m) throws DbException { + // The dependency, if any, must be the last remote message + if (isInvalidDependency(s.getIntroducee().getLastLocalMessageId(), + m.getPreviousMessageId())) return abort(txn, s); + Message forward = sendIntroduceeResponseMessage(txn, s.getMailbox(), + s.getMailbox().lastRemoteMessageId, clock.currentTimeMillis(), + m.getEphemeralPublicKey(), m.getMac(), m.getSignature(), + m.getAcceptTimestamp()); + return new OwnerSession(s.getSessionId(), AWAIT_AUTH_M, + s.getRequestTimestamp(), + new Introducee(s.getMailbox(), forward, s.getAbortCounter()), + new Introducee(s.getIntroducee(), m.getMessageId(), + s.getAbortCounter()), s.getAbortCounter()); + } + + private OwnerSession onLocalRequest(Transaction txn, OwnerSession s, + long timestamp) throws DbException { + // Send REQUEST messages + long maxIntroduceeTimestamp = + Math.max(getLocalTimestamp(s, s.getMailbox()), + getLocalTimestamp(s, s.getIntroducee())); + long localTimestamp = Math.max(timestamp, maxIntroduceeTimestamp); + Message sentMailbox = + sendMailboxRequestMessage(txn, s.getMailbox(), localTimestamp, + s.getIntroducee().author); + // Move to the AWAIT_RESPONSES state + Introducee mailbox = new Introducee(s.getMailbox(), sentMailbox, + s.getAbortCounter()); + Introducee b = new Introducee(s.getIntroducee().sessionId, + s.getIntroducee().groupId, s.getIntroducee().author, + s.getAbortCounter()); + return new OwnerSession(s.getSessionId(), AWAIT_RESPONSE_M, + localTimestamp, mailbox, b, s.getAbortCounter()); + } + + OwnerSession onIntroduceeRemoved(Transaction txn, + Introducee remainingIntroducee, OwnerSession session) + throws DbException { + // abort session + OwnerSession s = abort(txn, session); + // reset information for introducee that was removed + Introducee mailbox, introduceeB; + if (remainingIntroducee.author.equals(s.getMailbox().author)) { + mailbox = s.getMailbox(); + introduceeB = + new Introducee(s.getSessionId(), s.getIntroducee().groupId, + s.getIntroducee().author, s.getAbortCounter()); + } else if (remainingIntroducee.author + .equals(s.getIntroducee().author)) { + mailbox = new Introducee(s.getSessionId(), s.getMailbox().groupId, + s.getMailbox().author, s.getAbortCounter()); + introduceeB = s.getIntroducee(); + } else throw new DbException(); + return new OwnerSession(s.getSessionId(), s.getState(), + s.getRequestTimestamp(), mailbox, introduceeB, 0); + } + + private long getLocalTimestamp(OwnerSession s, PeerSession p) { + return getLocalTimestamp(p.getLocalTimestamp(), + s.getRequestTimestamp()); + } + + private OwnerSession abort(Transaction txn, OwnerSession s) + throws DbException { + // Broadcast abort event for testing + txn.attach(new MailboxIntroductionAbortedEvent(s.getSessionId())); + // Send an ABORT message to both introducees + long timestampMailbox = getLocalTimestamp(s, s.getMailbox()); + Message sentMailbox = + sendAbortMessage(txn, s.getMailbox(), timestampMailbox); + long timestampB = getLocalTimestamp(s, s.getIntroducee()); + Message sentB = sendAbortMessage(txn, s.getIntroducee(), timestampB); + long abortCounter = s.getAbortCounter() + 1; + // Reset the session back to initial state + Introducee mailbox = + new Introducee(s.getMailbox(), sentMailbox, abortCounter); + Introducee introducee = + new Introducee(s.getIntroducee(), sentB, abortCounter); + return new OwnerSession(s.getSessionId(), START, + s.getRequestTimestamp(), mailbox, introducee, abortCounter); + } + + private Introducee getOtherIntroducee(OwnerSession s, GroupId g) { + if (s.getMailbox().groupId.equals(g)) return s.getIntroducee(); + else if (s.getIntroducee().groupId.equals(g)) return s.getMailbox(); + else throw new AssertionError(); + } + + void broadcastMailboxIntroductionResponseReceived(Transaction txn, + Author from, Author to) { + MailboxIntroductionResponseReceivedEvent e = + new MailboxIntroductionResponseReceivedEvent(from, to); + txn.attach(e); + } +} diff --git a/bramble-core/src/main/java/org/briarproject/bramble/mailbox/introduction/OwnerSession.java b/bramble-core/src/main/java/org/briarproject/bramble/mailbox/introduction/OwnerSession.java new file mode 100644 index 0000000000000000000000000000000000000000..e883892158e1c9fa58c591aebd57a7bd74bb38fd --- /dev/null +++ b/bramble-core/src/main/java/org/briarproject/bramble/mailbox/introduction/OwnerSession.java @@ -0,0 +1,52 @@ +package org.briarproject.bramble.mailbox.introduction; + +import org.briarproject.bramble.api.client.SessionId; +import org.briarproject.bramble.api.identity.Author; +import org.briarproject.bramble.api.mailbox.Role; +import org.briarproject.bramble.api.nullsafety.NotNullByDefault; +import org.briarproject.bramble.api.sync.GroupId; + +import javax.annotation.concurrent.Immutable; + +import static org.briarproject.bramble.api.mailbox.Role.OWNER; + +@Immutable +@NotNullByDefault +class OwnerSession extends Session<OwnerState> { + + private final Introducee mailbox, introducee; + + OwnerSession(SessionId sessionId, OwnerState state, long requestTimestamp, + Introducee mailbox, Introducee introducee, long sessionCounter) { + super(sessionId, state, requestTimestamp, sessionCounter); + this.mailbox = mailbox; + this.introducee = introducee; + } + + OwnerSession(SessionId sessionId, GroupId groupIdA, Author authorA, + GroupId groupIdB, Author authorB, long abortCounter) { + this(sessionId, OwnerState.START, -1, + new Introducee(sessionId, groupIdA, authorA, abortCounter), + new Introducee(sessionId, groupIdB, authorB, abortCounter), + abortCounter); + } + + public static OwnerSession finished(OwnerSession s) { + return null; + } + + @Override + Role getRole() { + return OWNER; + } + + Introducee getMailbox() { + return mailbox; + } + + Introducee getIntroducee() { + return introducee; + } + + +} diff --git a/bramble-core/src/main/java/org/briarproject/bramble/mailbox/introduction/OwnerState.java b/bramble-core/src/main/java/org/briarproject/bramble/mailbox/introduction/OwnerState.java new file mode 100644 index 0000000000000000000000000000000000000000..bf77ef7c72f97d51c1d56518ba0af486c05c6f14 --- /dev/null +++ b/bramble-core/src/main/java/org/briarproject/bramble/mailbox/introduction/OwnerState.java @@ -0,0 +1,36 @@ +package org.briarproject.bramble.mailbox.introduction; + +import org.briarproject.bramble.api.FormatException; +import org.briarproject.bramble.api.nullsafety.NotNullByDefault; + +import javax.annotation.concurrent.Immutable; + +@Immutable +@NotNullByDefault +enum OwnerState implements State { + + START(0), + AWAIT_RESPONSE_M(1), + M_DECLINED(2), + AWAIT_RESPONSE_B(3), + B_DECLINED(4), + AWAIT_AUTH_M(5), + ADDED(6); + + private final int value; + + OwnerState(int value) { + this.value = value; + } + + @Override + public int getValue() { + return value; + } + + static OwnerState fromValue(int value) throws FormatException { + for (OwnerState s : values()) if (s.value == value) return s; + throw new FormatException(); + } + +} diff --git a/bramble-core/src/main/java/org/briarproject/bramble/mailbox/introduction/PeerSession.java b/bramble-core/src/main/java/org/briarproject/bramble/mailbox/introduction/PeerSession.java new file mode 100644 index 0000000000000000000000000000000000000000..b832a5f57a46868227cca8b1005d8645c2bf8e05 --- /dev/null +++ b/bramble-core/src/main/java/org/briarproject/bramble/mailbox/introduction/PeerSession.java @@ -0,0 +1,27 @@ +package org.briarproject.bramble.mailbox.introduction; + +import org.briarproject.bramble.api.client.SessionId; +import org.briarproject.bramble.api.nullsafety.NotNullByDefault; +import org.briarproject.bramble.api.sync.GroupId; +import org.briarproject.bramble.api.sync.MessageId; + +import javax.annotation.Nullable; + +@NotNullByDefault +interface PeerSession { + + SessionId getSessionId(); + + GroupId getContactGroupId(); + + long getLocalTimestamp(); + + @Nullable + MessageId getLastLocalMessageId(); + + @Nullable + MessageId getLastRemoteMessageId(); + + long getAbortCounter(); + +} diff --git a/bramble-core/src/main/java/org/briarproject/bramble/mailbox/introduction/ProtocolEngine.java b/bramble-core/src/main/java/org/briarproject/bramble/mailbox/introduction/ProtocolEngine.java new file mode 100644 index 0000000000000000000000000000000000000000..c0b18de6bd7b7b42c8ca053ebd1a413806d9b847 --- /dev/null +++ b/bramble-core/src/main/java/org/briarproject/bramble/mailbox/introduction/ProtocolEngine.java @@ -0,0 +1,30 @@ +package org.briarproject.bramble.mailbox.introduction; + +import org.briarproject.bramble.api.FormatException; +import org.briarproject.bramble.api.db.DbException; +import org.briarproject.bramble.api.db.Transaction; +import org.briarproject.bramble.api.nullsafety.NotNullByDefault; + +@NotNullByDefault +interface ProtocolEngine<S extends Session> { + + S onRequestMessage(Transaction txn, S session, RequestMessage m) + throws DbException, FormatException; + + S onMailboxAcceptMessage(Transaction txn, S session, MailboxAcceptMessage m) + throws DbException, FormatException; + + S onIntroduceeAcceptMessage(Transaction txn, S session, + IntroduceeAcceptMessage acceptMessage) throws DbException; + + S onDeclineMessage(Transaction txn, S session, DeclineMessage m) + throws DbException, FormatException; + + S onAuthMessage(Transaction txn, S session, MailboxAuthMessage m) + throws DbException, FormatException; + + S onAbortMessage(Transaction txn, S session, AbortMessage m) + throws DbException, FormatException; + + +} diff --git a/bramble-core/src/main/java/org/briarproject/bramble/mailbox/introduction/RequestMessage.java b/bramble-core/src/main/java/org/briarproject/bramble/mailbox/introduction/RequestMessage.java new file mode 100644 index 0000000000000000000000000000000000000000..d490ef2ac512644f9e4cb5f215b98a3bdd8087cb --- /dev/null +++ b/bramble-core/src/main/java/org/briarproject/bramble/mailbox/introduction/RequestMessage.java @@ -0,0 +1,28 @@ +package org.briarproject.bramble.mailbox.introduction; + +import org.briarproject.bramble.api.identity.Author; +import org.briarproject.bramble.api.nullsafety.NotNullByDefault; +import org.briarproject.bramble.api.sync.GroupId; +import org.briarproject.bramble.api.sync.MessageId; + +import javax.annotation.Nullable; +import javax.annotation.concurrent.Immutable; + +@Immutable +@NotNullByDefault +class RequestMessage extends AbstractMailboxIntroductionMessage { + + + private final Author author; + + protected RequestMessage(MessageId messageId, GroupId groupId, + long timestamp, @Nullable MessageId previousMessageId, + Author author) { + super(messageId, groupId, timestamp, previousMessageId); + this.author = author; + } + + public Author getAuthor() { + return author; + } +} diff --git a/bramble-core/src/main/java/org/briarproject/bramble/mailbox/introduction/Session.java b/bramble-core/src/main/java/org/briarproject/bramble/mailbox/introduction/Session.java new file mode 100644 index 0000000000000000000000000000000000000000..6039a5a694590bd835be59eb3236996e37c83ce4 --- /dev/null +++ b/bramble-core/src/main/java/org/briarproject/bramble/mailbox/introduction/Session.java @@ -0,0 +1,44 @@ +package org.briarproject.bramble.mailbox.introduction; + +import org.briarproject.bramble.api.client.SessionId; +import org.briarproject.bramble.api.mailbox.Role; +import org.briarproject.bramble.api.nullsafety.NotNullByDefault; + +import javax.annotation.concurrent.Immutable; + +@Immutable +@NotNullByDefault +abstract class Session<S extends State> { + + private final SessionId sessionId; + private final S state; + private final long requestTimestamp; + private final long abortCounter; + + Session(SessionId sessionId, S state, long requestTimestamp, + long abortCounter) { + this.sessionId = sessionId; + this.state = state; + this.requestTimestamp = requestTimestamp; + this.abortCounter = abortCounter; + } + + abstract Role getRole(); + + public SessionId getSessionId() { + return sessionId; + } + + S getState() { + return state; + } + + long getRequestTimestamp() { + return requestTimestamp; + } + + public long getAbortCounter() { + return abortCounter; + } + +} diff --git a/bramble-core/src/main/java/org/briarproject/bramble/mailbox/introduction/State.java b/bramble-core/src/main/java/org/briarproject/bramble/mailbox/introduction/State.java new file mode 100644 index 0000000000000000000000000000000000000000..1e794cd8388ca51a04ae6db69fd96561fe821c5b --- /dev/null +++ b/bramble-core/src/main/java/org/briarproject/bramble/mailbox/introduction/State.java @@ -0,0 +1,7 @@ +package org.briarproject.bramble.mailbox.introduction; + +interface State { + + int getValue(); + +} diff --git a/bramble-core/src/main/java/org/briarproject/bramble/properties/TransportPropertyManagerImpl.java b/bramble-core/src/main/java/org/briarproject/bramble/properties/TransportPropertyManagerImpl.java index 98822d8b028944fe9c0d207eede6dca1abcd87c0..7851663bca18df38d692d3aa2b5790c1fbbc9d66 100644 --- a/bramble-core/src/main/java/org/briarproject/bramble/properties/TransportPropertyManagerImpl.java +++ b/bramble-core/src/main/java/org/briarproject/bramble/properties/TransportPropertyManagerImpl.java @@ -108,6 +108,7 @@ class TransportPropertyManagerImpl implements TransportPropertyManager, @Override public void onClientVisibilityChanging(Transaction txn, Contact c, Visibility v) throws DbException { + if (!getApplicableContactTypes().contains(c.getType())) return; // Apply the client's visibility to the contact group Group g = getContactGroup(c); db.setGroupVisibility(txn, c.getId(), g.getId(), v); @@ -153,7 +154,19 @@ class TransportPropertyManagerImpl implements TransportPropertyManager, throws DbException { Map<TransportId, TransportProperties> properties = getLocalProperties(); for (Entry e : properties.entrySet()) { - e.setValue(Collections.EMPTY_MAP); + e.setValue(new TransportProperties(Collections.EMPTY_MAP)); + } + return properties; + } + + @Override + public Map<TransportId, TransportProperties> getLocalAnonymizedProperties( + Transaction txn) + throws DbException { + Map<TransportId, TransportProperties> properties = + getLocalProperties(txn); + for (Entry e : properties.entrySet()) { + e.setValue(new TransportProperties(Collections.EMPTY_MAP)); } return properties; } diff --git a/bramble-core/src/test/java/org/briarproject/bramble/integration/BrambleIntegrationTest.java b/bramble-core/src/test/java/org/briarproject/bramble/integration/BrambleIntegrationTest.java new file mode 100644 index 0000000000000000000000000000000000000000..8c73d11101911f6dbb5f5765085538a7c8b6fbd7 --- /dev/null +++ b/bramble-core/src/test/java/org/briarproject/bramble/integration/BrambleIntegrationTest.java @@ -0,0 +1,404 @@ +package org.briarproject.bramble.integration; + +import net.jodah.concurrentunit.Waiter; + +import org.briarproject.bramble.api.client.ClientHelper; +import org.briarproject.bramble.api.client.ContactGroupFactory; +import org.briarproject.bramble.api.contact.Contact; +import org.briarproject.bramble.api.contact.ContactId; +import org.briarproject.bramble.api.contact.ContactManager; +import org.briarproject.bramble.api.contact.PrivateMailbox; +import org.briarproject.bramble.api.crypto.CryptoComponent; +import org.briarproject.bramble.api.db.DatabaseComponent; +import org.briarproject.bramble.api.db.DbException; +import org.briarproject.bramble.api.event.Event; +import org.briarproject.bramble.api.event.EventListener; +import org.briarproject.bramble.api.identity.AuthorFactory; +import org.briarproject.bramble.api.identity.IdentityManager; +import org.briarproject.bramble.api.identity.LocalAuthor; +import org.briarproject.bramble.api.lifecycle.LifecycleManager; +import org.briarproject.bramble.api.nullsafety.MethodsNotNullByDefault; +import org.briarproject.bramble.api.nullsafety.ParametersNotNullByDefault; +import org.briarproject.bramble.api.sync.MessageFactory; +import org.briarproject.bramble.api.sync.SyncSession; +import org.briarproject.bramble.api.sync.SyncSessionFactory; +import org.briarproject.bramble.api.sync.event.MessageStateChangedEvent; +import org.briarproject.bramble.api.system.Clock; +import org.briarproject.bramble.api.transport.StreamWriter; +import org.briarproject.bramble.contact.ContactModule; +import org.briarproject.bramble.crypto.CryptoExecutorModule; +import org.briarproject.bramble.identity.IdentityModule; +import org.briarproject.bramble.lifecycle.LifecycleModule; +import org.briarproject.bramble.mailbox.introduction.MailboxIntroductionModule; +import org.briarproject.bramble.properties.PropertiesModule; +import org.briarproject.bramble.sync.SyncModule; +import org.briarproject.bramble.system.SystemModule; +import org.briarproject.bramble.test.BrambleTestCase; +import org.briarproject.bramble.test.TestUtils; +import org.briarproject.bramble.transport.TransportModule; +import org.briarproject.bramble.versioning.VersioningModule; +import org.junit.After; +import org.junit.Before; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.File; +import java.io.IOException; +import java.util.concurrent.TimeoutException; +import java.util.logging.Logger; + +import javax.annotation.Nullable; +import javax.inject.Inject; + +import static junit.framework.Assert.assertNotNull; +import static org.briarproject.bramble.api.sync.ValidationManager.State.DELIVERED; +import static org.briarproject.bramble.api.sync.ValidationManager.State.INVALID; +import static org.briarproject.bramble.api.sync.ValidationManager.State.PENDING; +import static org.briarproject.bramble.test.TestPluginConfigModule.MAX_LATENCY; +import static org.briarproject.bramble.test.TestUtils.getSecretKey; +import static org.junit.Assert.assertTrue; + +@MethodsNotNullByDefault +@ParametersNotNullByDefault +public abstract class BrambleIntegrationTest<C extends BrambleIntegrationTestComponent> + extends BrambleTestCase { + + private static final Logger LOG = + Logger.getLogger(BrambleIntegrationTest.class.getName()); + + @Nullable + protected ContactId contactId1From2, contactId2From1; + protected ContactId contactId0From1, contactId0From2, contactId1From0, + contactId2From0, privateMailboxIdFrom0, contactId0FromMailbox; + protected Contact contact0From1, contact0From2, contact1From0, + contact2From0, contact0FromMailbox; + protected PrivateMailbox privateMailboxFrom0; + protected LocalAuthor author0, author1, author2, authorMailbox; + protected ContactManager contactManager0, contactManager1, contactManager2, + contactManagerMailbox; + protected IdentityManager identityManager0, identityManager1, + identityManager2, identityManagerMailbox; + protected DatabaseComponent db0, db1, db2, dbMailbox; + + private LifecycleManager lifecycleManager0, lifecycleManager1, + lifecycleManager2, lifecycleManagerMailbox; + private SyncSessionFactory sync0, sync1, sync2, syncMailbox; + + @Inject + protected Clock clock; + @Inject + protected CryptoComponent crypto; + @Inject + protected ClientHelper clientHelper; + @Inject + protected AuthorFactory authorFactory; + @Inject + protected MessageFactory messageFactory; + @Inject + protected ContactGroupFactory contactGroupFactory; + + // objects accessed from background threads need to be volatile + private volatile Waiter validationWaiter; + private volatile Waiter deliveryWaiter; + + protected final static int TIMEOUT = 600000; + protected C c0, c1, c2, cMailbox; + + private final File testDir = TestUtils.getTestDirectory(); + private final String AUTHOR0 = "Author 0"; + private final String AUTHOR1 = "Author 1"; + private final String AUTHOR2 = "Author 2"; + private final String AUTHOR_MAILBOX = "Author MB"; + + protected File t0Dir = new File(testDir, AUTHOR0); + protected File t1Dir = new File(testDir, AUTHOR1); + protected File t2Dir = new File(testDir, AUTHOR2); + protected File t3Dir = new File(testDir, AUTHOR_MAILBOX); + + @Before + public void setUp() throws Exception { + assertTrue(testDir.mkdirs()); + createComponents(); + + identityManager0 = c0.getIdentityManager(); + identityManager1 = c1.getIdentityManager(); + identityManager2 = c2.getIdentityManager(); + identityManagerMailbox = cMailbox.getIdentityManager(); + contactManager0 = c0.getContactManager(); + contactManager1 = c1.getContactManager(); + contactManager2 = c2.getContactManager(); + contactManagerMailbox = cMailbox.getContactManager(); + db0 = c0.getDatabaseComponent(); + db1 = c1.getDatabaseComponent(); + db2 = c2.getDatabaseComponent(); + dbMailbox = cMailbox.getDatabaseComponent(); + sync0 = c0.getSyncSessionFactory(); + sync1 = c1.getSyncSessionFactory(); + sync2 = c2.getSyncSessionFactory(); + syncMailbox = cMailbox.getSyncSessionFactory(); + + // initialize waiters fresh for each test + validationWaiter = new Waiter(); + deliveryWaiter = new Waiter(); + + createAndRegisterIdentities(); + startLifecycles(); + listenToEvents(); + addDefaultContacts(); + } + + abstract protected void createComponents(); + + protected void injectEagerSingletons( + BrambleIntegrationTestComponent component) { + component.inject(new ContactModule.EagerSingletons()); + component.inject(new CryptoExecutorModule.EagerSingletons()); + component.inject(new IdentityModule.EagerSingletons()); + component.inject(new LifecycleModule.EagerSingletons()); + component.inject(new MailboxIntroductionModule.EagerSingletons()); + component.inject(new PropertiesModule.EagerSingletons()); + component.inject(new SyncModule.EagerSingletons()); + component.inject(new SystemModule.EagerSingletons()); + component.inject(new TransportModule.EagerSingletons()); + component.inject(new VersioningModule.EagerSingletons()); + } + + private void startLifecycles() throws InterruptedException { + // Start the lifecycle manager and wait for it to finish starting + lifecycleManager0 = c0.getLifecycleManager(); + lifecycleManager1 = c1.getLifecycleManager(); + lifecycleManager2 = c2.getLifecycleManager(); + lifecycleManagerMailbox = cMailbox.getLifecycleManager(); + lifecycleManager0.startServices(getSecretKey()); + lifecycleManager1.startServices(getSecretKey()); + lifecycleManager2.startServices(getSecretKey()); + lifecycleManagerMailbox.startServices(getSecretKey()); + lifecycleManager0.waitForStartup(); + lifecycleManager1.waitForStartup(); + lifecycleManager2.waitForStartup(); + lifecycleManagerMailbox.waitForStartup(); + } + + private void listenToEvents() { + Listener listener0 = new Listener(); + c0.getEventBus().addListener(listener0); + Listener listener1 = new Listener(); + c1.getEventBus().addListener(listener1); + Listener listener2 = new Listener(); + c2.getEventBus().addListener(listener2); + Listener listenerMailbox = new Listener(); + cMailbox.getEventBus().addListener(listenerMailbox); + } + + private class Listener implements EventListener { + @Override + public void eventOccurred(Event e) { + if (e instanceof MessageStateChangedEvent) { + MessageStateChangedEvent event = (MessageStateChangedEvent) e; + if (!event.isLocal()) { + if (event.getState() == DELIVERED) { + LOG.info("Delivered new message"); + deliveryWaiter.resume(); + } else if (event.getState() == INVALID || + event.getState() == PENDING) { + LOG.info("Validated new " + event.getState().name() + + " message"); + validationWaiter.resume(); + } + } + } + } + } + + private void createAndRegisterIdentities() { + author0 = identityManager0.createLocalAuthor(AUTHOR0); + identityManager0.registerLocalAuthor(author0); + author1 = identityManager1.createLocalAuthor(AUTHOR1); + identityManager1.registerLocalAuthor(author1); + author2 = identityManager2.createLocalAuthor(AUTHOR2); + identityManager2.registerLocalAuthor(author2); + authorMailbox = + identityManagerMailbox.createLocalAuthor(AUTHOR_MAILBOX); + identityManagerMailbox.registerLocalAuthor(authorMailbox); + } + + protected void addDefaultContacts() throws Exception { + contactId1From0 = contactManager0 + .addContact(author1, author0.getId(), getSecretKey(), + clock.currentTimeMillis(), true, true, true); + contact1From0 = contactManager0.getContact(contactId1From0); + contactId0From1 = contactManager1 + .addContact(author0, author1.getId(), getSecretKey(), + clock.currentTimeMillis(), true, true, true); + contact0From1 = contactManager1.getContact(contactId0From1); + contactId2From0 = contactManager0 + .addContact(author2, author0.getId(), getSecretKey(), + clock.currentTimeMillis(), true, true, true); + contact2From0 = contactManager0.getContact(contactId2From0); + contactId0From2 = contactManager2 + .addContact(author0, author2.getId(), getSecretKey(), + clock.currentTimeMillis(), true, true, true); + contact0From2 = contactManager2.getContact(contactId0From2); + privateMailboxIdFrom0 = contactManager0 + .addPrivateMailbox(authorMailbox, author0.getId(), + getSecretKey(), clock.currentTimeMillis(), true); + privateMailboxFrom0 = + (PrivateMailbox) contactManager0 + .getContact(privateMailboxIdFrom0); + contactId0FromMailbox = contactManagerMailbox + .addMailboxOwner(author0, authorMailbox.getId(), + getSecretKey(), + clock.currentTimeMillis(), false); + contact0FromMailbox = + contactManagerMailbox.getContact(contactId0FromMailbox); + + // Sync initial client versioning updates + sync0To1(1, true); + sync0To2(1, true); + sync0ToMailbox(1, true); + sync1To0(1, true); + sync2To0(1, true); + syncMailboxTo0(1, true); + sync0To1(1, true); + sync0To2(1, true); + sync0ToMailbox(1, true); + } + + protected void addContacts1And2() throws Exception { + contactId2From1 = contactManager1 + .addContact(author2, author1.getId(), getSecretKey(), + clock.currentTimeMillis(), true, true, true); + contactId1From2 = contactManager2 + .addContact(author1, author2.getId(), getSecretKey(), + clock.currentTimeMillis(), true, true, true); + + // Sync initial client versioning updates + sync1To2(1, true); + sync2To1(1, true); + sync1To2(1, true); + } + + @After + public void tearDown() throws Exception { + stopLifecycles(); + TestUtils.deleteTestDirectory(testDir); + } + + private void stopLifecycles() throws InterruptedException { + // Clean up + lifecycleManager0.stopServices(); + lifecycleManager1.stopServices(); + lifecycleManager2.stopServices(); + lifecycleManagerMailbox.stopServices(); + lifecycleManager0.waitForShutdown(); + lifecycleManager1.waitForShutdown(); + lifecycleManager2.waitForShutdown(); + lifecycleManagerMailbox.waitForShutdown(); + } + + protected void sync0To1(int num, boolean valid) + throws IOException, TimeoutException { + syncMessage(sync0, contactId0From1, sync1, contactId1From0, num, + valid); + } + + protected void sync0To2(int num, boolean valid) + throws IOException, TimeoutException { + syncMessage(sync0, contactId0From2, sync2, contactId2From0, num, + valid); + } + + protected void sync0ToMailbox(int num, boolean valid) + throws IOException, TimeoutException { + syncMessage(sync0, contactId0FromMailbox, syncMailbox, + privateMailboxIdFrom0, num, + valid); + } + + protected void sync1To0(int num, boolean valid) + throws IOException, TimeoutException { + syncMessage(sync1, contactId1From0, sync0, contactId0From1, num, + valid); + } + + protected void sync2To0(int num, boolean valid) + throws IOException, TimeoutException { + syncMessage(sync2, contactId2From0, sync0, contactId0From2, num, + valid); + } + + protected void syncMailboxTo0(int num, boolean valid) + throws IOException, TimeoutException { + syncMessage(syncMailbox, privateMailboxIdFrom0, sync0, + contactId0FromMailbox, + num, valid); + } + + protected void sync2To1(int num, boolean valid) + throws IOException, TimeoutException { + assertNotNull(contactId2From1); + assertNotNull(contactId1From2); + syncMessage(sync2, contactId2From1, sync1, contactId1From2, num, + valid); + } + + protected void sync1To2(int num, boolean valid) + throws IOException, TimeoutException { + assertNotNull(contactId2From1); + assertNotNull(contactId1From2); + syncMessage(sync1, contactId1From2, sync2, contactId2From1, num, + valid); + } + + private void syncMessage(SyncSessionFactory fromSync, ContactId fromId, + SyncSessionFactory toSync, ContactId toId, int num, boolean valid) + throws IOException, TimeoutException { + + // Debug output + String from = "0"; + if (fromSync == sync1) from = "1"; + else if (fromSync == sync2) from = "2"; + else if (fromSync == syncMailbox) from = "Mailbox"; + String to = "0"; + if (toSync == sync1) to = "1"; + else if (toSync == sync2) to = "2"; + else if (toSync == syncMailbox) to = "Mailbox"; + LOG.info("TEST: Sending message from " + from + " to " + to); + + ByteArrayOutputStream out = new ByteArrayOutputStream(); + StreamWriter streamWriter = new TestStreamWriter(out); + // Create an outgoing sync session + SyncSession sessionFrom = + fromSync.createSimplexOutgoingSession(toId, + MAX_LATENCY, streamWriter); + // Write whatever needs to be written + sessionFrom.run(); + out.close(); + + ByteArrayInputStream in = + new ByteArrayInputStream(out.toByteArray()); + // Create an incoming sync session + SyncSession sessionTo = toSync.createIncomingSession(fromId, in); + // Read whatever needs to be read + sessionTo.run(); + in.close(); + + if (valid) { + deliveryWaiter.await(TIMEOUT, num); + } else { + validationWaiter.await(TIMEOUT, num); + } + } + + protected void removeAllContacts() throws DbException { + contactManager0.removeContact(contactId1From0); + contactManager0.removeContact(contactId2From0); + contactManager1.removeContact(contactId0From1); + contactManager2.removeContact(contactId0From2); + contactManagerMailbox.removeContact(contactId0FromMailbox); + assertNotNull(contactId2From1); + contactManager1.removeContact(contactId2From1); + assertNotNull(contactId1From2); + contactManager2.removeContact(contactId1From2); + } +} diff --git a/bramble-core/src/test/java/org/briarproject/bramble/integration/BrambleIntegrationTestComponent.java b/bramble-core/src/test/java/org/briarproject/bramble/integration/BrambleIntegrationTestComponent.java new file mode 100644 index 0000000000000000000000000000000000000000..2a0e2033406546565f2dae24cbe6923b8417e8d6 --- /dev/null +++ b/bramble-core/src/test/java/org/briarproject/bramble/integration/BrambleIntegrationTestComponent.java @@ -0,0 +1,102 @@ +package org.briarproject.bramble.integration; + +import org.briarproject.bramble.api.client.ClientHelper; +import org.briarproject.bramble.api.contact.ContactManager; +import org.briarproject.bramble.api.db.DatabaseComponent; +import org.briarproject.bramble.api.event.EventBus; +import org.briarproject.bramble.api.identity.AuthorFactory; +import org.briarproject.bramble.api.identity.IdentityManager; +import org.briarproject.bramble.api.lifecycle.LifecycleManager; +import org.briarproject.bramble.api.properties.TransportPropertyManager; +import org.briarproject.bramble.api.sync.SyncSessionFactory; +import org.briarproject.bramble.client.ClientModule; +import org.briarproject.bramble.contact.ContactModule; +import org.briarproject.bramble.crypto.CryptoExecutorModule; +import org.briarproject.bramble.crypto.CryptoModule; +import org.briarproject.bramble.data.DataModule; +import org.briarproject.bramble.db.DatabaseModule; +import org.briarproject.bramble.event.EventModule; +import org.briarproject.bramble.identity.IdentityModule; +import org.briarproject.bramble.lifecycle.LifecycleModule; +import org.briarproject.bramble.api.mailbox.MailboxIntroductionManager; +import org.briarproject.bramble.mailbox.introduction.MailboxIntroductionModule; +import org.briarproject.bramble.properties.PropertiesModule; +import org.briarproject.bramble.record.RecordModule; +import org.briarproject.bramble.sync.SyncModule; +import org.briarproject.bramble.system.SystemModule; +import org.briarproject.bramble.test.TestDatabaseModule; +import org.briarproject.bramble.test.TestPluginConfigModule; +import org.briarproject.bramble.test.TestSecureRandomModule; +import org.briarproject.bramble.transport.TransportModule; +import org.briarproject.bramble.versioning.VersioningModule; + +import javax.inject.Singleton; + +import dagger.Component; + +@Singleton +@Component(modules = { + TestDatabaseModule.class, + TestPluginConfigModule.class, + TestSecureRandomModule.class, + ClientModule.class, + ContactModule.class, + CryptoModule.class, + CryptoExecutorModule.class, + DataModule.class, + DatabaseModule.class, + EventModule.class, + IdentityModule.class, + LifecycleModule.class, + MailboxIntroductionModule.class, + PropertiesModule.class, + RecordModule.class, + SyncModule.class, + SystemModule.class, + TransportModule.class, + VersioningModule.class +}) +public interface BrambleIntegrationTestComponent { + + void inject(BrambleIntegrationTest<BrambleIntegrationTestComponent> init); + + void inject(ContactModule.EagerSingletons init); + + void inject(CryptoExecutorModule.EagerSingletons init); + + void inject(IdentityModule.EagerSingletons init); + + void inject(LifecycleModule.EagerSingletons init); + + void inject(MailboxIntroductionModule.EagerSingletons init); + + void inject(PropertiesModule.EagerSingletons init); + + void inject(SyncModule.EagerSingletons init); + + void inject(SystemModule.EagerSingletons init); + + void inject(TransportModule.EagerSingletons init); + + void inject(VersioningModule.EagerSingletons init); + + LifecycleManager getLifecycleManager(); + + EventBus getEventBus(); + + IdentityManager getIdentityManager(); + + ClientHelper getClientHelper(); + + ContactManager getContactManager(); + + SyncSessionFactory getSyncSessionFactory(); + + DatabaseComponent getDatabaseComponent(); + + TransportPropertyManager getTransportPropertyManager(); + + AuthorFactory getAuthorFactory(); + + MailboxIntroductionManager getMailboxIntroductionManager(); +} diff --git a/bramble-core/src/test/java/org/briarproject/bramble/integration/TestStreamWriter.java b/bramble-core/src/test/java/org/briarproject/bramble/integration/TestStreamWriter.java new file mode 100644 index 0000000000000000000000000000000000000000..6b619169f1f97410ac8ab3b7865744e1a5b65d4d --- /dev/null +++ b/bramble-core/src/test/java/org/briarproject/bramble/integration/TestStreamWriter.java @@ -0,0 +1,25 @@ +package org.briarproject.bramble.integration; + +import org.briarproject.bramble.api.transport.StreamWriter; + +import java.io.IOException; +import java.io.OutputStream; + +class TestStreamWriter implements StreamWriter { + + private final OutputStream out; + + TestStreamWriter(OutputStream out) { + this.out = out; + } + + @Override + public OutputStream getOutputStream() { + return out; + } + + @Override + public void sendEndOfStream() throws IOException { + out.flush(); + } +} diff --git a/bramble-core/src/test/java/org/briarproject/bramble/mailbox/introduction/MailboxIntroductionIntegrationTest.java b/bramble-core/src/test/java/org/briarproject/bramble/mailbox/introduction/MailboxIntroductionIntegrationTest.java new file mode 100644 index 0000000000000000000000000000000000000000..d69b67fc504892e24ae662775f0c910a99cd778a --- /dev/null +++ b/bramble-core/src/test/java/org/briarproject/bramble/mailbox/introduction/MailboxIntroductionIntegrationTest.java @@ -0,0 +1,303 @@ +package org.briarproject.bramble.mailbox.introduction; + +import net.jodah.concurrentunit.Waiter; + +import org.briarproject.bramble.api.contact.Contact; +import org.briarproject.bramble.api.contact.PrivateMailbox; +import org.briarproject.bramble.api.db.DbException; +import org.briarproject.bramble.api.event.Event; +import org.briarproject.bramble.api.event.EventListener; +import org.briarproject.bramble.api.identity.AuthorId; +import org.briarproject.bramble.api.nullsafety.MethodsNotNullByDefault; +import org.briarproject.bramble.api.nullsafety.NotNullByDefault; +import org.briarproject.bramble.api.nullsafety.ParametersNotNullByDefault; +import org.briarproject.bramble.api.properties.TransportPropertyManager; +import org.briarproject.bramble.api.sync.Group; +import org.briarproject.bramble.api.client.SessionId; +import org.briarproject.bramble.integration.BrambleIntegrationTest; +import org.briarproject.bramble.integration.BrambleIntegrationTestComponent; +import org.briarproject.bramble.api.mailbox.MailboxIntroductionManager; +import org.briarproject.bramble.api.mailbox.event.MailboxIntroductionAbortedEvent; +import org.briarproject.bramble.api.mailbox.event.MailboxIntroductionRequestReceivedEvent; +import org.briarproject.bramble.api.mailbox.event.MailboxIntroductionResponseReceivedEvent; +import org.briarproject.bramble.api.mailbox.event.MailboxIntroductionSucceededEvent; +import org.briarproject.bramble.test.TestDatabaseModule; +import org.junit.Before; +import org.junit.Test; + +import java.io.IOException; +import java.util.concurrent.TimeoutException; + +import static org.briarproject.bramble.api.mailbox.MailboxIntroductionManager.CLIENT_ID; +import static org.briarproject.bramble.api.mailbox.MailboxIntroductionManager.MAJOR_VERSION; +import static org.briarproject.bramble.test.TestPluginConfigModule.TRANSPORT_ID; +import static org.briarproject.bramble.test.TestUtils.getTransportProperties; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +public class MailboxIntroductionIntegrationTest extends + BrambleIntegrationTest<MailboxIntroductionIntegrationTestComponent> { + + // objects accessed from background threads need to be volatile + private volatile MailboxIntroductionManager introductionManager0; + private volatile MailboxIntroductionManager introductionManager1; + private volatile MailboxIntroductionManager introductionManager2; + private volatile MailboxIntroductionManager introductionManagerMailbox; + private volatile Waiter eventWaiter; + + private OwnerListener listener0; + private IntroduceeListener listener1; + private IntroduceeListener listener2; + private IntroduceeListener listenerMailbox; + + /* + interface StateVisitor { + AcceptMessage visit(AcceptMessage response); + }*/ + + @Before + @Override + public void setUp() throws Exception { + super.setUp(); + + introductionManager0 = c0.getMailboxIntroductionManager(); + introductionManager1 = c1.getMailboxIntroductionManager(); + introductionManager2 = c2.getMailboxIntroductionManager(); + introductionManagerMailbox = cMailbox.getMailboxIntroductionManager(); + + // initialize waiter fresh for each test + eventWaiter = new Waiter(); + + addTransportProperties(); + } + + @Override + protected void createComponents() { + MailboxIntroductionIntegrationTestComponent component = + DaggerMailboxIntroductionIntegrationTestComponent.builder() + .build(); + component.inject(this); + + c0 = DaggerMailboxIntroductionIntegrationTestComponent.builder() + .testDatabaseModule(new TestDatabaseModule(t0Dir)).build(); + injectEagerSingletons(c0); + + c1 = DaggerMailboxIntroductionIntegrationTestComponent.builder() + .testDatabaseModule(new TestDatabaseModule(t1Dir)).build(); + injectEagerSingletons(c1); + + c2 = DaggerMailboxIntroductionIntegrationTestComponent.builder() + .testDatabaseModule(new TestDatabaseModule(t2Dir)).build(); + injectEagerSingletons(c2); + + cMailbox = DaggerMailboxIntroductionIntegrationTestComponent.builder() + .testDatabaseModule(new TestDatabaseModule(t3Dir)).build(); + injectEagerSingletons(cMailbox); + } + + @Override + protected void injectEagerSingletons( + BrambleIntegrationTestComponent component) { + super.injectEagerSingletons(component); + component.inject(new MailboxIntroductionModule.EagerSingletons()); + } + + @Test + public void testIntroductionSession() throws Exception { + addListeners(true, true, true); + + // make introduction + long time = clock.currentTimeMillis(); + Contact introducee = contact1From0; + PrivateMailbox mailbox = privateMailboxFrom0; + introductionManager0.makeIntroduction(mailbox, introducee, time); + + // sync first REQUEST message + sync0ToMailbox(1, true); + eventWaiter.await(TIMEOUT, 1); + assertTrue(listenerMailbox.requestReceived); + assertEquals(authorMailbox.getId(), listenerMailbox.getRequest()); + // sync RESPONSE message + syncMailboxTo0(1, true); + eventWaiter.await(TIMEOUT, 1); + assertTrue(listener0.response1Received); + assertEquals(authorMailbox.getId(), listener0.getAuthors()[0]); + assertEquals(author1.getId(), listener0.getAuthors()[1]); + // sync/forward RESPONSE message to the contact + sync0To1(1, true); + eventWaiter.await(TIMEOUT, 1); + sync1To0(1, true); + sync0ToMailbox(1, true); + eventWaiter.await(TIMEOUT, 1); + assertTrue(listenerMailbox.succeeded); + assertEquals(contact1From0.getAuthor(), + listenerMailbox.introduceeContact.getAuthor()); + syncMailboxTo0(1, true); + eventWaiter.await(TIMEOUT, 1); + assertTrue(listener0.success); + sync0To1(1, true); + eventWaiter.await(TIMEOUT, 1); + assertTrue(listener1.succeeded); + assertEquals(privateMailboxFrom0.getAuthor(), + listener1.introduceeContact.getAuthor()); + } + + + private void addTransportProperties() + throws DbException, IOException, TimeoutException { + TransportPropertyManager tpm0 = c0.getTransportPropertyManager(); + TransportPropertyManager tpm1 = c1.getTransportPropertyManager(); + TransportPropertyManager tpm2 = c2.getTransportPropertyManager(); + TransportPropertyManager tpmMailbox = + cMailbox.getTransportPropertyManager(); + + tpm0.mergeLocalProperties(TRANSPORT_ID, getTransportProperties(2)); + sync0To1(1, true); + sync0To2(1, true); + sync0ToMailbox(1, true); + + tpm1.mergeLocalProperties(TRANSPORT_ID, getTransportProperties(2)); + sync1To0(1, true); + + tpm2.mergeLocalProperties(TRANSPORT_ID, getTransportProperties(2)); + sync2To0(1, true); + + tpmMailbox + .mergeLocalProperties(TRANSPORT_ID, getTransportProperties(2)); + syncMailboxTo0(1, true); + } + + private void addListeners(boolean accept1, boolean accept2, + boolean accept3) { + // listen to events + listener0 = new OwnerListener(); + c0.getEventBus().addListener(listener0); + listener1 = new IntroduceeListener(1, accept1); + c1.getEventBus().addListener(listener1); + listener2 = new IntroduceeListener(2, accept2); + c2.getEventBus().addListener(listener2); + listenerMailbox = new IntroduceeListener(3, accept3); + cMailbox.getEventBus().addListener(listenerMailbox); + } + + @MethodsNotNullByDefault + @ParametersNotNullByDefault + private abstract class IntroductionListener implements EventListener { + + protected volatile boolean aborted = false; + protected volatile Event latestEvent; + + @SuppressWarnings("WeakerAccess") + AuthorId[] getAuthors() { + assertTrue( + latestEvent instanceof MailboxIntroductionResponseReceivedEvent); + AuthorId[] authors = + {((MailboxIntroductionResponseReceivedEvent) latestEvent) + .getFrom().getId(), + ((MailboxIntroductionResponseReceivedEvent) latestEvent) + .getTo().getId()}; + return authors; + } + } + + @MethodsNotNullByDefault + @ParametersNotNullByDefault + private class IntroduceeListener extends IntroductionListener { + + private volatile boolean requestReceived = false; + private volatile boolean succeeded = false; + private volatile boolean answerRequests = true; + private volatile SessionId sessionId; + private volatile Contact introduceeContact; + + private final int introducee; + private final boolean accept; + + private IntroduceeListener(int introducee, boolean accept) { + this.introducee = introducee; + this.accept = accept; + } + + @Override + public void eventOccurred(Event e) { + if (e instanceof MailboxIntroductionRequestReceivedEvent) { + latestEvent = e; + MailboxIntroductionRequestReceivedEvent introEvent = + (MailboxIntroductionRequestReceivedEvent) e; + requestReceived = true; + long time = clock.currentTimeMillis(); + try { + if (introducee == 1 && answerRequests) { + /* introductionManager1 + .respondToIntroduction(contactId, sessionId, + time, accept);*/ + } else if (introducee == 2 && answerRequests) { +/* introductionManager2 + .respondToIntroduction(contactId, sessionId, + time, accept);*/ + } + // } catch (DbException exception) { + //eventWaiter.rethrow(exception); + } finally { + eventWaiter.resume(); + } + } else if (e instanceof MailboxIntroductionResponseReceivedEvent) { + // only broadcast for DECLINE messages in introducee role + latestEvent = e; + eventWaiter.resume(); + } else if (e instanceof MailboxIntroductionSucceededEvent) { + latestEvent = e; + succeeded = true; + Contact contact = + ((MailboxIntroductionSucceededEvent) e).getContact(); + eventWaiter + .assertFalse(contact.getId().equals(contactId0From1)); + introduceeContact = contact; + eventWaiter.resume(); + } else if (e instanceof MailboxIntroductionAbortedEvent) { + latestEvent = e; + aborted = true; + eventWaiter.resume(); + } + } + + private AuthorId getRequest() { + assertTrue( + latestEvent instanceof MailboxIntroductionRequestReceivedEvent); + return ((MailboxIntroductionRequestReceivedEvent) latestEvent) + .getAuthorId(); + } + } + + @NotNullByDefault + private class OwnerListener extends IntroductionListener { + + private volatile boolean response1Received = false; + private volatile boolean response2Received = false; + private volatile boolean success = false; + + @Override + public void eventOccurred(Event e) { + if (e instanceof MailboxIntroductionResponseReceivedEvent) { + latestEvent = e; + AuthorId from = + ((MailboxIntroductionResponseReceivedEvent) e).getFrom() + .getId(); + if (from.equals(authorMailbox.getId())) { + response1Received = true; + } + eventWaiter.resume(); + } else if (e instanceof MailboxIntroductionSucceededEvent) { + latestEvent = e; + success = true; + eventWaiter.resume(); + } + } + + } + + private Group getLocalGroup() { + return contactGroupFactory.createLocalGroup(CLIENT_ID, MAJOR_VERSION); + } + +} diff --git a/bramble-core/src/test/java/org/briarproject/bramble/mailbox/introduction/MailboxIntroductionIntegrationTestComponent.java b/bramble-core/src/test/java/org/briarproject/bramble/mailbox/introduction/MailboxIntroductionIntegrationTestComponent.java new file mode 100644 index 0000000000000000000000000000000000000000..706b951ea6bfe022d16cf5157ff6834622b4524f --- /dev/null +++ b/bramble-core/src/test/java/org/briarproject/bramble/mailbox/introduction/MailboxIntroductionIntegrationTestComponent.java @@ -0,0 +1,62 @@ +package org.briarproject.bramble.mailbox.introduction; + +import org.briarproject.bramble.client.ClientModule; +import org.briarproject.bramble.contact.ContactModule; +import org.briarproject.bramble.crypto.CryptoExecutorModule; +import org.briarproject.bramble.crypto.CryptoModule; +import org.briarproject.bramble.data.DataModule; +import org.briarproject.bramble.db.DatabaseModule; +import org.briarproject.bramble.event.EventModule; +import org.briarproject.bramble.identity.IdentityModule; +import org.briarproject.bramble.integration.BrambleIntegrationTestComponent; +import org.briarproject.bramble.lifecycle.LifecycleModule; +import org.briarproject.bramble.properties.PropertiesModule; +import org.briarproject.bramble.record.RecordModule; +import org.briarproject.bramble.sync.SyncModule; +import org.briarproject.bramble.system.SystemModule; +import org.briarproject.bramble.test.TestDatabaseModule; +import org.briarproject.bramble.test.TestPluginConfigModule; +import org.briarproject.bramble.test.TestSecureRandomModule; +import org.briarproject.bramble.transport.TransportModule; +import org.briarproject.bramble.versioning.VersioningModule; + +import javax.inject.Singleton; + +import dagger.Component; + +@Singleton +@Component(modules = { + TestDatabaseModule.class, + TestPluginConfigModule.class, + TestSecureRandomModule.class, + ClientModule.class, + ContactModule.class, + CryptoModule.class, + CryptoExecutorModule.class, + DataModule.class, + DatabaseModule.class, + EventModule.class, + IdentityModule.class, + MailboxIntroductionModule.class, + LifecycleModule.class, + PropertiesModule.class, + RecordModule.class, + SyncModule.class, + SystemModule.class, + TransportModule.class, + VersioningModule.class +}) +interface MailboxIntroductionIntegrationTestComponent + extends BrambleIntegrationTestComponent { + + void inject(MailboxIntroductionIntegrationTest init); + + MailboxMessageEncoder getMessageEncoder(); + + MailboxMessageParser getMessageParser(); + + MailboxSessionParser getSessionParser(); + + MailboxIntroductionCrypto getMailboxIntroductionCrypto(); + +} diff --git a/briar-api/src/main/java/org/briarproject/briar/api/blog/BlogInvitationRequest.java b/briar-api/src/main/java/org/briarproject/briar/api/blog/BlogInvitationRequest.java index 77dddbbe034303beb720f3f1475b4c254d3b85d6..cbf36af8fa9256acd7684acffd42c3031709ecd6 100644 --- a/briar-api/src/main/java/org/briarproject/briar/api/blog/BlogInvitationRequest.java +++ b/briar-api/src/main/java/org/briarproject/briar/api/blog/BlogInvitationRequest.java @@ -4,7 +4,7 @@ import org.briarproject.bramble.api.contact.ContactId; import org.briarproject.bramble.api.nullsafety.NotNullByDefault; import org.briarproject.bramble.api.sync.GroupId; import org.briarproject.bramble.api.sync.MessageId; -import org.briarproject.briar.api.client.SessionId; +import org.briarproject.bramble.api.client.SessionId; import org.briarproject.briar.api.sharing.InvitationRequest; import javax.annotation.Nullable; diff --git a/briar-api/src/main/java/org/briarproject/briar/api/blog/BlogInvitationResponse.java b/briar-api/src/main/java/org/briarproject/briar/api/blog/BlogInvitationResponse.java index e4914230020f7543e3a9709c41f698068253c13a..1e9cb9a831bdcb2968423fd056cc9066bb3aee29 100644 --- a/briar-api/src/main/java/org/briarproject/briar/api/blog/BlogInvitationResponse.java +++ b/briar-api/src/main/java/org/briarproject/briar/api/blog/BlogInvitationResponse.java @@ -4,7 +4,7 @@ import org.briarproject.bramble.api.contact.ContactId; import org.briarproject.bramble.api.nullsafety.NotNullByDefault; import org.briarproject.bramble.api.sync.GroupId; import org.briarproject.bramble.api.sync.MessageId; -import org.briarproject.briar.api.client.SessionId; +import org.briarproject.bramble.api.client.SessionId; import org.briarproject.briar.api.sharing.InvitationResponse; @NotNullByDefault diff --git a/briar-api/src/main/java/org/briarproject/briar/api/forum/ForumInvitationRequest.java b/briar-api/src/main/java/org/briarproject/briar/api/forum/ForumInvitationRequest.java index 2d23ab0e8bd768411a0b787dd8721d4076705fd8..cc13e0d8bf64bc63135886c4230e76744abcdee5 100644 --- a/briar-api/src/main/java/org/briarproject/briar/api/forum/ForumInvitationRequest.java +++ b/briar-api/src/main/java/org/briarproject/briar/api/forum/ForumInvitationRequest.java @@ -4,7 +4,7 @@ import org.briarproject.bramble.api.contact.ContactId; import org.briarproject.bramble.api.nullsafety.NotNullByDefault; import org.briarproject.bramble.api.sync.GroupId; import org.briarproject.bramble.api.sync.MessageId; -import org.briarproject.briar.api.client.SessionId; +import org.briarproject.bramble.api.client.SessionId; import org.briarproject.briar.api.sharing.InvitationRequest; import javax.annotation.Nullable; diff --git a/briar-api/src/main/java/org/briarproject/briar/api/forum/ForumInvitationResponse.java b/briar-api/src/main/java/org/briarproject/briar/api/forum/ForumInvitationResponse.java index 48f03ce8593e4874ed550c71400b3d1df299b052..45e8bc1fd9367b72c656eda7ec9b5ac5c569ccc8 100644 --- a/briar-api/src/main/java/org/briarproject/briar/api/forum/ForumInvitationResponse.java +++ b/briar-api/src/main/java/org/briarproject/briar/api/forum/ForumInvitationResponse.java @@ -4,7 +4,7 @@ import org.briarproject.bramble.api.contact.ContactId; import org.briarproject.bramble.api.nullsafety.NotNullByDefault; import org.briarproject.bramble.api.sync.GroupId; import org.briarproject.bramble.api.sync.MessageId; -import org.briarproject.briar.api.client.SessionId; +import org.briarproject.bramble.api.client.SessionId; import org.briarproject.briar.api.sharing.InvitationResponse; import javax.annotation.concurrent.Immutable; diff --git a/briar-api/src/main/java/org/briarproject/briar/api/introduction/IntroductionManager.java b/briar-api/src/main/java/org/briarproject/briar/api/introduction/IntroductionManager.java index 532d633539e3e33b89a386383e9d9cc79122395f..e08b16eefcd92f2fd92dd7e91197cf9c4d8d57b5 100644 --- a/briar-api/src/main/java/org/briarproject/briar/api/introduction/IntroductionManager.java +++ b/briar-api/src/main/java/org/briarproject/briar/api/introduction/IntroductionManager.java @@ -5,7 +5,7 @@ import org.briarproject.bramble.api.contact.ContactId; import org.briarproject.bramble.api.db.DbException; import org.briarproject.bramble.api.nullsafety.NotNullByDefault; import org.briarproject.bramble.api.sync.ClientId; -import org.briarproject.briar.api.client.SessionId; +import org.briarproject.bramble.api.client.SessionId; import org.briarproject.briar.api.messaging.ConversationManager.ConversationClient; import java.util.Collection; diff --git a/briar-api/src/main/java/org/briarproject/briar/api/introduction/IntroductionMessage.java b/briar-api/src/main/java/org/briarproject/briar/api/introduction/IntroductionMessage.java index 009487fa2faf852fc5aa843db4d3aba9a09ba24f..0b72ddd3f6390fdd00b11b75b9837acbb5459298 100644 --- a/briar-api/src/main/java/org/briarproject/briar/api/introduction/IntroductionMessage.java +++ b/briar-api/src/main/java/org/briarproject/briar/api/introduction/IntroductionMessage.java @@ -4,7 +4,7 @@ import org.briarproject.bramble.api.nullsafety.NotNullByDefault; import org.briarproject.bramble.api.sync.GroupId; import org.briarproject.bramble.api.sync.MessageId; import org.briarproject.briar.api.client.BaseMessageHeader; -import org.briarproject.briar.api.client.SessionId; +import org.briarproject.bramble.api.client.SessionId; import javax.annotation.concurrent.Immutable; diff --git a/briar-api/src/main/java/org/briarproject/briar/api/introduction/IntroductionRequest.java b/briar-api/src/main/java/org/briarproject/briar/api/introduction/IntroductionRequest.java index b2a804bd88b8de918546c68e15a3327e4605180f..1201ce516d6aa1bd478ca3f9dde7db5fa137ff18 100644 --- a/briar-api/src/main/java/org/briarproject/briar/api/introduction/IntroductionRequest.java +++ b/briar-api/src/main/java/org/briarproject/briar/api/introduction/IntroductionRequest.java @@ -3,7 +3,7 @@ package org.briarproject.briar.api.introduction; import org.briarproject.bramble.api.nullsafety.NotNullByDefault; import org.briarproject.bramble.api.sync.GroupId; import org.briarproject.bramble.api.sync.MessageId; -import org.briarproject.briar.api.client.SessionId; +import org.briarproject.bramble.api.client.SessionId; import javax.annotation.Nullable; import javax.annotation.concurrent.Immutable; diff --git a/briar-api/src/main/java/org/briarproject/briar/api/introduction/IntroductionResponse.java b/briar-api/src/main/java/org/briarproject/briar/api/introduction/IntroductionResponse.java index 816135d43f59668a4ecfa4baf27e625ba2469462..605e3eb5467d3c423a8f1f8788b5d14c9efaa34a 100644 --- a/briar-api/src/main/java/org/briarproject/briar/api/introduction/IntroductionResponse.java +++ b/briar-api/src/main/java/org/briarproject/briar/api/introduction/IntroductionResponse.java @@ -3,7 +3,7 @@ package org.briarproject.briar.api.introduction; import org.briarproject.bramble.api.nullsafety.NotNullByDefault; import org.briarproject.bramble.api.sync.GroupId; import org.briarproject.bramble.api.sync.MessageId; -import org.briarproject.briar.api.client.SessionId; +import org.briarproject.bramble.api.client.SessionId; import javax.annotation.concurrent.Immutable; diff --git a/briar-api/src/main/java/org/briarproject/briar/api/introduction/event/IntroductionAbortedEvent.java b/briar-api/src/main/java/org/briarproject/briar/api/introduction/event/IntroductionAbortedEvent.java index 113ba400efdebb484b0b41b84d70ccc64443f2b3..08b4f72ffdb9dc7908d9cae49d54b24cc4955aec 100644 --- a/briar-api/src/main/java/org/briarproject/briar/api/introduction/event/IntroductionAbortedEvent.java +++ b/briar-api/src/main/java/org/briarproject/briar/api/introduction/event/IntroductionAbortedEvent.java @@ -2,7 +2,7 @@ package org.briarproject.briar.api.introduction.event; import org.briarproject.bramble.api.event.Event; import org.briarproject.bramble.api.nullsafety.NotNullByDefault; -import org.briarproject.briar.api.client.SessionId; +import org.briarproject.bramble.api.client.SessionId; import javax.annotation.concurrent.Immutable; diff --git a/briar-api/src/main/java/org/briarproject/briar/api/privategroup/invitation/GroupInvitationManager.java b/briar-api/src/main/java/org/briarproject/briar/api/privategroup/invitation/GroupInvitationManager.java index 1062d0ce1127f828425532cb56fd504ea6e89380..cf8498474a60c9c85a853975af3c9b793b8f64c0 100644 --- a/briar-api/src/main/java/org/briarproject/briar/api/privategroup/invitation/GroupInvitationManager.java +++ b/briar-api/src/main/java/org/briarproject/briar/api/privategroup/invitation/GroupInvitationManager.java @@ -6,8 +6,8 @@ import org.briarproject.bramble.api.db.DbException; import org.briarproject.bramble.api.nullsafety.NotNullByDefault; import org.briarproject.bramble.api.sync.ClientId; import org.briarproject.bramble.api.sync.GroupId; -import org.briarproject.briar.api.client.ProtocolStateException; -import org.briarproject.briar.api.client.SessionId; +import org.briarproject.bramble.api.client.ProtocolStateException; +import org.briarproject.bramble.api.client.SessionId; import org.briarproject.briar.api.messaging.ConversationManager.ConversationClient; import org.briarproject.briar.api.privategroup.PrivateGroup; import org.briarproject.briar.api.sharing.InvitationMessage; diff --git a/briar-api/src/main/java/org/briarproject/briar/api/privategroup/invitation/GroupInvitationRequest.java b/briar-api/src/main/java/org/briarproject/briar/api/privategroup/invitation/GroupInvitationRequest.java index d447ae8ef176629db9ed8b25e901fd0ab4c633d2..505a450a76daf54b85a1dd61dde8813f7c03e7d2 100644 --- a/briar-api/src/main/java/org/briarproject/briar/api/privategroup/invitation/GroupInvitationRequest.java +++ b/briar-api/src/main/java/org/briarproject/briar/api/privategroup/invitation/GroupInvitationRequest.java @@ -4,7 +4,7 @@ import org.briarproject.bramble.api.contact.ContactId; import org.briarproject.bramble.api.nullsafety.NotNullByDefault; import org.briarproject.bramble.api.sync.GroupId; import org.briarproject.bramble.api.sync.MessageId; -import org.briarproject.briar.api.client.SessionId; +import org.briarproject.bramble.api.client.SessionId; import org.briarproject.briar.api.privategroup.PrivateGroup; import org.briarproject.briar.api.sharing.InvitationRequest; diff --git a/briar-api/src/main/java/org/briarproject/briar/api/privategroup/invitation/GroupInvitationResponse.java b/briar-api/src/main/java/org/briarproject/briar/api/privategroup/invitation/GroupInvitationResponse.java index b2e7d54b538cc3ba3bb5590e5c834a654280af78..273a39e8e9c3188edbb24b28c279c0b4cbda8f9d 100644 --- a/briar-api/src/main/java/org/briarproject/briar/api/privategroup/invitation/GroupInvitationResponse.java +++ b/briar-api/src/main/java/org/briarproject/briar/api/privategroup/invitation/GroupInvitationResponse.java @@ -4,7 +4,7 @@ import org.briarproject.bramble.api.contact.ContactId; import org.briarproject.bramble.api.nullsafety.NotNullByDefault; import org.briarproject.bramble.api.sync.GroupId; import org.briarproject.bramble.api.sync.MessageId; -import org.briarproject.briar.api.client.SessionId; +import org.briarproject.bramble.api.client.SessionId; import org.briarproject.briar.api.sharing.InvitationResponse; import javax.annotation.concurrent.Immutable; diff --git a/briar-api/src/main/java/org/briarproject/briar/api/sharing/InvitationMessage.java b/briar-api/src/main/java/org/briarproject/briar/api/sharing/InvitationMessage.java index df93ebdfab831f585bf16cac400582ce42ff5264..e6953894e66e36cc16ac92ab7dd9dcf6b3ea946f 100644 --- a/briar-api/src/main/java/org/briarproject/briar/api/sharing/InvitationMessage.java +++ b/briar-api/src/main/java/org/briarproject/briar/api/sharing/InvitationMessage.java @@ -5,7 +5,7 @@ import org.briarproject.bramble.api.nullsafety.NotNullByDefault; import org.briarproject.bramble.api.sync.GroupId; import org.briarproject.bramble.api.sync.MessageId; import org.briarproject.briar.api.client.BaseMessageHeader; -import org.briarproject.briar.api.client.SessionId; +import org.briarproject.bramble.api.client.SessionId; import javax.annotation.concurrent.Immutable; diff --git a/briar-api/src/main/java/org/briarproject/briar/api/sharing/InvitationRequest.java b/briar-api/src/main/java/org/briarproject/briar/api/sharing/InvitationRequest.java index c5239310d467872bc182c8b17c2471d7924506ee..5a1b90c433d247ebc068c9b466a36168e8212e9d 100644 --- a/briar-api/src/main/java/org/briarproject/briar/api/sharing/InvitationRequest.java +++ b/briar-api/src/main/java/org/briarproject/briar/api/sharing/InvitationRequest.java @@ -4,7 +4,7 @@ import org.briarproject.bramble.api.contact.ContactId; import org.briarproject.bramble.api.nullsafety.NotNullByDefault; import org.briarproject.bramble.api.sync.GroupId; import org.briarproject.bramble.api.sync.MessageId; -import org.briarproject.briar.api.client.SessionId; +import org.briarproject.bramble.api.client.SessionId; import javax.annotation.Nullable; import javax.annotation.concurrent.Immutable; diff --git a/briar-api/src/main/java/org/briarproject/briar/api/sharing/InvitationResponse.java b/briar-api/src/main/java/org/briarproject/briar/api/sharing/InvitationResponse.java index 517b6068e96c0bd30aaf62fdae98671a93ff1fab..18a3102a06321414c7a57eb86f272112c55bb9af 100644 --- a/briar-api/src/main/java/org/briarproject/briar/api/sharing/InvitationResponse.java +++ b/briar-api/src/main/java/org/briarproject/briar/api/sharing/InvitationResponse.java @@ -4,7 +4,7 @@ import org.briarproject.bramble.api.contact.ContactId; import org.briarproject.bramble.api.nullsafety.NotNullByDefault; import org.briarproject.bramble.api.sync.GroupId; import org.briarproject.bramble.api.sync.MessageId; -import org.briarproject.briar.api.client.SessionId; +import org.briarproject.bramble.api.client.SessionId; import javax.annotation.concurrent.Immutable; diff --git a/briar-api/src/main/java/org/briarproject/briar/api/sharing/SharingManager.java b/briar-api/src/main/java/org/briarproject/briar/api/sharing/SharingManager.java index b593d2fdf74207abe5be1f1f7216b67cfaae7154..656fa623b5f43848478eaa952f098e7ffdfc8fb1 100644 --- a/briar-api/src/main/java/org/briarproject/briar/api/sharing/SharingManager.java +++ b/briar-api/src/main/java/org/briarproject/briar/api/sharing/SharingManager.java @@ -5,7 +5,7 @@ import org.briarproject.bramble.api.contact.ContactId; import org.briarproject.bramble.api.db.DbException; import org.briarproject.bramble.api.nullsafety.NotNullByDefault; import org.briarproject.bramble.api.sync.GroupId; -import org.briarproject.briar.api.client.SessionId; +import org.briarproject.bramble.api.client.SessionId; import org.briarproject.briar.api.messaging.ConversationManager.ConversationClient; import java.util.Collection; diff --git a/briar-core/src/main/java/org/briarproject/briar/blog/BlogManagerImpl.java b/briar-core/src/main/java/org/briarproject/briar/blog/BlogManagerImpl.java index 7f6e581f588e7715c5db84f8e2a41f4d60266e56..e4584245b5c76cb6dd05921b8d32d11b3292600e 100644 --- a/briar-core/src/main/java/org/briarproject/briar/blog/BlogManagerImpl.java +++ b/briar-core/src/main/java/org/briarproject/briar/blog/BlogManagerImpl.java @@ -23,6 +23,7 @@ import org.briarproject.bramble.api.sync.Group; import org.briarproject.bramble.api.sync.GroupId; import org.briarproject.bramble.api.sync.Message; import org.briarproject.bramble.api.sync.MessageId; +import org.briarproject.bramble.api.client.BdfIncomingMessageHook; import org.briarproject.briar.api.blog.Blog; import org.briarproject.briar.api.blog.BlogCommentHeader; import org.briarproject.briar.api.blog.BlogFactory; @@ -32,7 +33,6 @@ import org.briarproject.briar.api.blog.BlogPostFactory; import org.briarproject.briar.api.blog.BlogPostHeader; import org.briarproject.briar.api.blog.MessageType; import org.briarproject.briar.api.blog.event.BlogPostAddedEvent; -import org.briarproject.briar.client.BdfIncomingMessageHook; import java.security.GeneralSecurityException; import java.util.ArrayList; diff --git a/briar-core/src/main/java/org/briarproject/briar/client/ConversationClientImpl.java b/briar-core/src/main/java/org/briarproject/briar/client/ConversationClientImpl.java index 9e47fa3a3fd786b077ed382bcb662f15a5abe01e..cb8a280b2850d662c8e98d20bcf23d94701afa24 100644 --- a/briar-core/src/main/java/org/briarproject/briar/client/ConversationClientImpl.java +++ b/briar-core/src/main/java/org/briarproject/briar/client/ConversationClientImpl.java @@ -10,6 +10,7 @@ import org.briarproject.bramble.api.db.Transaction; import org.briarproject.bramble.api.nullsafety.NotNullByDefault; import org.briarproject.bramble.api.sync.GroupId; import org.briarproject.bramble.api.sync.MessageId; +import org.briarproject.bramble.api.client.BdfIncomingMessageHook; import org.briarproject.briar.api.client.MessageTracker; import org.briarproject.briar.api.client.MessageTracker.GroupCount; import org.briarproject.briar.api.messaging.ConversationManager.ConversationClient; diff --git a/briar-core/src/main/java/org/briarproject/briar/forum/ForumManagerImpl.java b/briar-core/src/main/java/org/briarproject/briar/forum/ForumManagerImpl.java index 58b35ea6560cfe4b9c4671ddbea861e0dc5bd2cc..1c410c9130a0d53e2e7d3c3b99d0a9348bdd5361 100644 --- a/briar-core/src/main/java/org/briarproject/briar/forum/ForumManagerImpl.java +++ b/briar-core/src/main/java/org/briarproject/briar/forum/ForumManagerImpl.java @@ -27,7 +27,7 @@ import org.briarproject.briar.api.forum.ForumPost; import org.briarproject.briar.api.forum.ForumPostFactory; import org.briarproject.briar.api.forum.ForumPostHeader; import org.briarproject.briar.api.forum.event.ForumPostReceivedEvent; -import org.briarproject.briar.client.BdfIncomingMessageHook; +import org.briarproject.bramble.api.client.BdfIncomingMessageHook; import java.security.GeneralSecurityException; import java.util.ArrayList; diff --git a/briar-core/src/main/java/org/briarproject/briar/introduction/AbortMessage.java b/briar-core/src/main/java/org/briarproject/briar/introduction/AbortMessage.java index e9a2d1233489716140048f80642ca2687c3a33de..cdcacb7b65581cdc286d356e612f672916bef696 100644 --- a/briar-core/src/main/java/org/briarproject/briar/introduction/AbortMessage.java +++ b/briar-core/src/main/java/org/briarproject/briar/introduction/AbortMessage.java @@ -3,7 +3,7 @@ package org.briarproject.briar.introduction; import org.briarproject.bramble.api.nullsafety.NotNullByDefault; import org.briarproject.bramble.api.sync.GroupId; import org.briarproject.bramble.api.sync.MessageId; -import org.briarproject.briar.api.client.SessionId; +import org.briarproject.bramble.api.client.SessionId; import javax.annotation.Nullable; import javax.annotation.concurrent.Immutable; diff --git a/briar-core/src/main/java/org/briarproject/briar/introduction/AbstractProtocolEngine.java b/briar-core/src/main/java/org/briarproject/briar/introduction/AbstractProtocolEngine.java index 03b3486ada568e39f8ad457fb2b6c45159dff2ea..b56aa0c1cc0b80be74950b0c29fc7369c2c5981b 100644 --- a/briar-core/src/main/java/org/briarproject/briar/introduction/AbstractProtocolEngine.java +++ b/briar-core/src/main/java/org/briarproject/briar/introduction/AbstractProtocolEngine.java @@ -19,7 +19,7 @@ import org.briarproject.bramble.api.sync.Message; import org.briarproject.bramble.api.sync.MessageId; import org.briarproject.bramble.api.system.Clock; import org.briarproject.briar.api.client.MessageTracker; -import org.briarproject.briar.api.client.SessionId; +import org.briarproject.bramble.api.client.SessionId; import org.briarproject.briar.api.introduction.IntroductionResponse; import org.briarproject.briar.api.introduction.event.IntroductionResponseReceivedEvent; diff --git a/briar-core/src/main/java/org/briarproject/briar/introduction/AcceptMessage.java b/briar-core/src/main/java/org/briarproject/briar/introduction/AcceptMessage.java index 6cadae73b6257bbe76c67d5904a47dba286838c3..dfc6e33ea8d4f9b6191bb871000fe7db69770328 100644 --- a/briar-core/src/main/java/org/briarproject/briar/introduction/AcceptMessage.java +++ b/briar-core/src/main/java/org/briarproject/briar/introduction/AcceptMessage.java @@ -5,7 +5,7 @@ import org.briarproject.bramble.api.plugin.TransportId; import org.briarproject.bramble.api.properties.TransportProperties; import org.briarproject.bramble.api.sync.GroupId; import org.briarproject.bramble.api.sync.MessageId; -import org.briarproject.briar.api.client.SessionId; +import org.briarproject.bramble.api.client.SessionId; import java.util.Map; diff --git a/briar-core/src/main/java/org/briarproject/briar/introduction/ActivateMessage.java b/briar-core/src/main/java/org/briarproject/briar/introduction/ActivateMessage.java index 5f767737d90fe68029f80e2e0ab4d87932df13ce..c9c535667a00ff8cc5a13da176fe971f1a39990c 100644 --- a/briar-core/src/main/java/org/briarproject/briar/introduction/ActivateMessage.java +++ b/briar-core/src/main/java/org/briarproject/briar/introduction/ActivateMessage.java @@ -3,7 +3,7 @@ package org.briarproject.briar.introduction; import org.briarproject.bramble.api.nullsafety.NotNullByDefault; import org.briarproject.bramble.api.sync.GroupId; import org.briarproject.bramble.api.sync.MessageId; -import org.briarproject.briar.api.client.SessionId; +import org.briarproject.bramble.api.client.SessionId; import javax.annotation.concurrent.Immutable; diff --git a/briar-core/src/main/java/org/briarproject/briar/introduction/AuthMessage.java b/briar-core/src/main/java/org/briarproject/briar/introduction/AuthMessage.java index 1de1a4eb5803cbbfef2fb82c6fbc99e88ea09f5d..f64ae616ea97471a79b65714da6c6f25f121e05f 100644 --- a/briar-core/src/main/java/org/briarproject/briar/introduction/AuthMessage.java +++ b/briar-core/src/main/java/org/briarproject/briar/introduction/AuthMessage.java @@ -3,7 +3,7 @@ package org.briarproject.briar.introduction; import org.briarproject.bramble.api.nullsafety.NotNullByDefault; import org.briarproject.bramble.api.sync.GroupId; import org.briarproject.bramble.api.sync.MessageId; -import org.briarproject.briar.api.client.SessionId; +import org.briarproject.bramble.api.client.SessionId; import javax.annotation.concurrent.Immutable; diff --git a/briar-core/src/main/java/org/briarproject/briar/introduction/DeclineMessage.java b/briar-core/src/main/java/org/briarproject/briar/introduction/DeclineMessage.java index 27386b90587a7297174ffbbf27e2ef82544b2444..b4b1acd3a656f5af722dbb0acc0f64eaaeeb1bdf 100644 --- a/briar-core/src/main/java/org/briarproject/briar/introduction/DeclineMessage.java +++ b/briar-core/src/main/java/org/briarproject/briar/introduction/DeclineMessage.java @@ -3,7 +3,7 @@ package org.briarproject.briar.introduction; import org.briarproject.bramble.api.nullsafety.NotNullByDefault; import org.briarproject.bramble.api.sync.GroupId; import org.briarproject.bramble.api.sync.MessageId; -import org.briarproject.briar.api.client.SessionId; +import org.briarproject.bramble.api.client.SessionId; import javax.annotation.Nullable; import javax.annotation.concurrent.Immutable; diff --git a/briar-core/src/main/java/org/briarproject/briar/introduction/IntroduceeProtocolEngine.java b/briar-core/src/main/java/org/briarproject/briar/introduction/IntroduceeProtocolEngine.java index 6bdaea9d28f78fc4d7120d0af39d7e25a308d234..5857c3aa4e7e7b84faca3fa15b5543c342144756 100644 --- a/briar-core/src/main/java/org/briarproject/briar/introduction/IntroduceeProtocolEngine.java +++ b/briar-core/src/main/java/org/briarproject/briar/introduction/IntroduceeProtocolEngine.java @@ -24,8 +24,8 @@ import org.briarproject.bramble.api.system.Clock; import org.briarproject.bramble.api.transport.KeyManager; import org.briarproject.bramble.api.transport.KeySetId; import org.briarproject.briar.api.client.MessageTracker; -import org.briarproject.briar.api.client.ProtocolStateException; -import org.briarproject.briar.api.client.SessionId; +import org.briarproject.bramble.api.client.ProtocolStateException; +import org.briarproject.bramble.api.client.SessionId; import org.briarproject.briar.api.introduction.IntroductionRequest; import org.briarproject.briar.api.introduction.event.IntroductionAbortedEvent; import org.briarproject.briar.api.introduction.event.IntroductionRequestReceivedEvent; diff --git a/briar-core/src/main/java/org/briarproject/briar/introduction/IntroduceeSession.java b/briar-core/src/main/java/org/briarproject/briar/introduction/IntroduceeSession.java index b952b3dc52e9c64a5c8900cb6e5c27131e309cc5..203275b0faffea661b10273af51ed7275dd26304 100644 --- a/briar-core/src/main/java/org/briarproject/briar/introduction/IntroduceeSession.java +++ b/briar-core/src/main/java/org/briarproject/briar/introduction/IntroduceeSession.java @@ -9,7 +9,7 @@ import org.briarproject.bramble.api.sync.GroupId; import org.briarproject.bramble.api.sync.Message; import org.briarproject.bramble.api.sync.MessageId; import org.briarproject.bramble.api.transport.KeySetId; -import org.briarproject.briar.api.client.SessionId; +import org.briarproject.bramble.api.client.SessionId; import org.briarproject.briar.api.introduction.Role; import java.util.Map; diff --git a/briar-core/src/main/java/org/briarproject/briar/introduction/IntroducerProtocolEngine.java b/briar-core/src/main/java/org/briarproject/briar/introduction/IntroducerProtocolEngine.java index c159697adc5253a64ca77866052291980b087a93..d2d57016ea4981d74f555fbc6649ad0f99655873 100644 --- a/briar-core/src/main/java/org/briarproject/briar/introduction/IntroducerProtocolEngine.java +++ b/briar-core/src/main/java/org/briarproject/briar/introduction/IntroducerProtocolEngine.java @@ -14,7 +14,7 @@ import org.briarproject.bramble.api.sync.Message; import org.briarproject.bramble.api.sync.MessageId; import org.briarproject.bramble.api.system.Clock; import org.briarproject.briar.api.client.MessageTracker; -import org.briarproject.briar.api.client.ProtocolStateException; +import org.briarproject.bramble.api.client.ProtocolStateException; import org.briarproject.briar.api.introduction.event.IntroductionAbortedEvent; import org.briarproject.briar.introduction.IntroducerSession.Introducee; @@ -556,6 +556,7 @@ class IntroducerProtocolEngine private IntroducerSession abort(Transaction txn, IntroducerSession s) throws DbException { // Broadcast abort event for testing + txn.attach(new IntroductionAbortedEvent(s.getSessionId())); // Send an ABORT message to both introducees diff --git a/briar-core/src/main/java/org/briarproject/briar/introduction/IntroducerSession.java b/briar-core/src/main/java/org/briarproject/briar/introduction/IntroducerSession.java index 3c50621eb77e284fd1c4b50f4433eb292e9e4f56..b48595d70ad0aa5f6c48800601435a647ccea7ca 100644 --- a/briar-core/src/main/java/org/briarproject/briar/introduction/IntroducerSession.java +++ b/briar-core/src/main/java/org/briarproject/briar/introduction/IntroducerSession.java @@ -5,7 +5,7 @@ import org.briarproject.bramble.api.nullsafety.NotNullByDefault; import org.briarproject.bramble.api.sync.GroupId; import org.briarproject.bramble.api.sync.Message; import org.briarproject.bramble.api.sync.MessageId; -import org.briarproject.briar.api.client.SessionId; +import org.briarproject.bramble.api.client.SessionId; import org.briarproject.briar.api.introduction.Role; import javax.annotation.Nullable; diff --git a/briar-core/src/main/java/org/briarproject/briar/introduction/IntroductionCrypto.java b/briar-core/src/main/java/org/briarproject/briar/introduction/IntroductionCrypto.java index 37f7aa10f63ffb9e25514d3d557139c408dd3433..bef20f1d2c39ee14806a5b47a0e9c9b5d39ad189 100644 --- a/briar-core/src/main/java/org/briarproject/briar/introduction/IntroductionCrypto.java +++ b/briar-core/src/main/java/org/briarproject/briar/introduction/IntroductionCrypto.java @@ -5,7 +5,7 @@ import org.briarproject.bramble.api.crypto.SecretKey; import org.briarproject.bramble.api.identity.Author; import org.briarproject.bramble.api.identity.AuthorId; import org.briarproject.bramble.api.identity.LocalAuthor; -import org.briarproject.briar.api.client.SessionId; +import org.briarproject.bramble.api.client.SessionId; import java.security.GeneralSecurityException; diff --git a/briar-core/src/main/java/org/briarproject/briar/introduction/IntroductionCryptoImpl.java b/briar-core/src/main/java/org/briarproject/briar/introduction/IntroductionCryptoImpl.java index d892c58b3cac4376c0586b0b8f6f4facb6c844c4..045772589e8556dba20266069333b92675821082 100644 --- a/briar-core/src/main/java/org/briarproject/briar/introduction/IntroductionCryptoImpl.java +++ b/briar-core/src/main/java/org/briarproject/briar/introduction/IntroductionCryptoImpl.java @@ -12,7 +12,7 @@ import org.briarproject.bramble.api.data.BdfList; import org.briarproject.bramble.api.identity.Author; import org.briarproject.bramble.api.identity.AuthorId; import org.briarproject.bramble.api.nullsafety.NotNullByDefault; -import org.briarproject.briar.api.client.SessionId; +import org.briarproject.bramble.api.client.SessionId; import org.briarproject.briar.introduction.IntroduceeSession.Common; import org.briarproject.briar.introduction.IntroduceeSession.Remote; diff --git a/briar-core/src/main/java/org/briarproject/briar/introduction/IntroductionManagerImpl.java b/briar-core/src/main/java/org/briarproject/briar/introduction/IntroductionManagerImpl.java index 19021d1135f22a1cab964214ae0565c80dea4993..b2c2d06336ac270007eb78532989c61a7f913eb2 100644 --- a/briar-core/src/main/java/org/briarproject/briar/introduction/IntroductionManagerImpl.java +++ b/briar-core/src/main/java/org/briarproject/briar/introduction/IntroductionManagerImpl.java @@ -29,7 +29,7 @@ import org.briarproject.bramble.api.sync.MessageStatus; import org.briarproject.bramble.api.versioning.ClientVersioningManager; import org.briarproject.bramble.api.versioning.ClientVersioningManager.ClientVersioningHook; import org.briarproject.briar.api.client.MessageTracker; -import org.briarproject.briar.api.client.SessionId; +import org.briarproject.bramble.api.client.SessionId; import org.briarproject.briar.api.introduction.IntroductionManager; import org.briarproject.briar.api.introduction.IntroductionMessage; import org.briarproject.briar.api.introduction.IntroductionRequest; @@ -155,6 +155,7 @@ class IntroductionManagerImpl extends ConversationClientImpl @Override public void onClientVisibilityChanging(Transaction txn, Contact c, Visibility v) throws DbException { + if(!getApplicableContactTypes().contains(c.getType())) return; // Apply the client's visibility to the contact group Group g = getContactGroup(c); db.setGroupVisibility(txn, c.getId(), g.getId(), v); diff --git a/briar-core/src/main/java/org/briarproject/briar/introduction/IntroductionValidator.java b/briar-core/src/main/java/org/briarproject/briar/introduction/IntroductionValidator.java index 929c8bddf91798d3ca284ed9a42308edaa0a5e60..570f76c682d2e615d4339444dafeef14f57a18ca 100644 --- a/briar-core/src/main/java/org/briarproject/briar/introduction/IntroductionValidator.java +++ b/briar-core/src/main/java/org/briarproject/briar/introduction/IntroductionValidator.java @@ -13,7 +13,7 @@ import org.briarproject.bramble.api.sync.Group; import org.briarproject.bramble.api.sync.Message; import org.briarproject.bramble.api.sync.MessageId; import org.briarproject.bramble.api.system.Clock; -import org.briarproject.briar.api.client.SessionId; +import org.briarproject.bramble.api.client.SessionId; import java.util.Collections; diff --git a/briar-core/src/main/java/org/briarproject/briar/introduction/MessageEncoder.java b/briar-core/src/main/java/org/briarproject/briar/introduction/MessageEncoder.java index 1327b54a938150a5c14019ae5db11a9dab162934..9ffad1a64dda936bcd9aaa06458d04d39776dec8 100644 --- a/briar-core/src/main/java/org/briarproject/briar/introduction/MessageEncoder.java +++ b/briar-core/src/main/java/org/briarproject/briar/introduction/MessageEncoder.java @@ -8,7 +8,7 @@ import org.briarproject.bramble.api.properties.TransportProperties; import org.briarproject.bramble.api.sync.GroupId; import org.briarproject.bramble.api.sync.Message; import org.briarproject.bramble.api.sync.MessageId; -import org.briarproject.briar.api.client.SessionId; +import org.briarproject.bramble.api.client.SessionId; import java.util.Map; diff --git a/briar-core/src/main/java/org/briarproject/briar/introduction/MessageEncoderImpl.java b/briar-core/src/main/java/org/briarproject/briar/introduction/MessageEncoderImpl.java index fb3d66f38012129401d21453d63b9ab431be13d1..7dde270348cf4e661825bfa7e00c7c4472cfd491 100644 --- a/briar-core/src/main/java/org/briarproject/briar/introduction/MessageEncoderImpl.java +++ b/briar-core/src/main/java/org/briarproject/briar/introduction/MessageEncoderImpl.java @@ -12,7 +12,7 @@ import org.briarproject.bramble.api.sync.GroupId; import org.briarproject.bramble.api.sync.Message; import org.briarproject.bramble.api.sync.MessageFactory; import org.briarproject.bramble.api.sync.MessageId; -import org.briarproject.briar.api.client.SessionId; +import org.briarproject.bramble.api.client.SessionId; import java.util.Map; diff --git a/briar-core/src/main/java/org/briarproject/briar/introduction/MessageMetadata.java b/briar-core/src/main/java/org/briarproject/briar/introduction/MessageMetadata.java index 102d72bfc3fc0634c39a915f41c9efc2cfa1cd7b..6186c50d59ca99a870b4036e239a71827062492a 100644 --- a/briar-core/src/main/java/org/briarproject/briar/introduction/MessageMetadata.java +++ b/briar-core/src/main/java/org/briarproject/briar/introduction/MessageMetadata.java @@ -1,7 +1,7 @@ package org.briarproject.briar.introduction; import org.briarproject.bramble.api.nullsafety.NotNullByDefault; -import org.briarproject.briar.api.client.SessionId; +import org.briarproject.bramble.api.client.SessionId; import javax.annotation.Nullable; import javax.annotation.concurrent.Immutable; diff --git a/briar-core/src/main/java/org/briarproject/briar/introduction/MessageParser.java b/briar-core/src/main/java/org/briarproject/briar/introduction/MessageParser.java index 503dd4cc66077228053a147ac1e5dc92b546cfee..8403f20c27e0f52792004e600983eced19ec4253 100644 --- a/briar-core/src/main/java/org/briarproject/briar/introduction/MessageParser.java +++ b/briar-core/src/main/java/org/briarproject/briar/introduction/MessageParser.java @@ -5,7 +5,7 @@ import org.briarproject.bramble.api.data.BdfDictionary; import org.briarproject.bramble.api.data.BdfList; import org.briarproject.bramble.api.nullsafety.NotNullByDefault; import org.briarproject.bramble.api.sync.Message; -import org.briarproject.briar.api.client.SessionId; +import org.briarproject.bramble.api.client.SessionId; @NotNullByDefault interface MessageParser { diff --git a/briar-core/src/main/java/org/briarproject/briar/introduction/MessageParserImpl.java b/briar-core/src/main/java/org/briarproject/briar/introduction/MessageParserImpl.java index 69ddd242d1cab3137d7e312905d16388362a629f..13224d612fd7fa8609c1d45e58b2648cc8a4cf03 100644 --- a/briar-core/src/main/java/org/briarproject/briar/introduction/MessageParserImpl.java +++ b/briar-core/src/main/java/org/briarproject/briar/introduction/MessageParserImpl.java @@ -11,7 +11,7 @@ import org.briarproject.bramble.api.plugin.TransportId; import org.briarproject.bramble.api.properties.TransportProperties; import org.briarproject.bramble.api.sync.Message; import org.briarproject.bramble.api.sync.MessageId; -import org.briarproject.briar.api.client.SessionId; +import org.briarproject.bramble.api.client.SessionId; import java.util.Map; diff --git a/briar-core/src/main/java/org/briarproject/briar/introduction/PeerSession.java b/briar-core/src/main/java/org/briarproject/briar/introduction/PeerSession.java index 3c453d2fa9e8cc311623768c48362f65b197a2ad..d8504db14cb41f327de84f1af1d697438a134433 100644 --- a/briar-core/src/main/java/org/briarproject/briar/introduction/PeerSession.java +++ b/briar-core/src/main/java/org/briarproject/briar/introduction/PeerSession.java @@ -3,7 +3,7 @@ package org.briarproject.briar.introduction; import org.briarproject.bramble.api.nullsafety.NotNullByDefault; import org.briarproject.bramble.api.sync.GroupId; import org.briarproject.bramble.api.sync.MessageId; -import org.briarproject.briar.api.client.SessionId; +import org.briarproject.bramble.api.client.SessionId; import javax.annotation.Nullable; diff --git a/briar-core/src/main/java/org/briarproject/briar/introduction/Session.java b/briar-core/src/main/java/org/briarproject/briar/introduction/Session.java index 086dfb1a2975defaf177206dbce5cb65cac7edcb..6e8bcff17fed366effd80d54b9d7cafe55429f1d 100644 --- a/briar-core/src/main/java/org/briarproject/briar/introduction/Session.java +++ b/briar-core/src/main/java/org/briarproject/briar/introduction/Session.java @@ -1,7 +1,7 @@ package org.briarproject.briar.introduction; import org.briarproject.bramble.api.nullsafety.NotNullByDefault; -import org.briarproject.briar.api.client.SessionId; +import org.briarproject.bramble.api.client.SessionId; import org.briarproject.briar.api.introduction.Role; import javax.annotation.concurrent.Immutable; diff --git a/briar-core/src/main/java/org/briarproject/briar/introduction/SessionParser.java b/briar-core/src/main/java/org/briarproject/briar/introduction/SessionParser.java index c58cac3d951012cbd1298f2283b97e2747f13681..82dfa092ac3fbbf63b334da88c7ef06079108975 100644 --- a/briar-core/src/main/java/org/briarproject/briar/introduction/SessionParser.java +++ b/briar-core/src/main/java/org/briarproject/briar/introduction/SessionParser.java @@ -4,7 +4,7 @@ import org.briarproject.bramble.api.FormatException; import org.briarproject.bramble.api.data.BdfDictionary; import org.briarproject.bramble.api.nullsafety.NotNullByDefault; import org.briarproject.bramble.api.sync.GroupId; -import org.briarproject.briar.api.client.SessionId; +import org.briarproject.bramble.api.client.SessionId; import org.briarproject.briar.api.introduction.Role; @NotNullByDefault diff --git a/briar-core/src/main/java/org/briarproject/briar/introduction/SessionParserImpl.java b/briar-core/src/main/java/org/briarproject/briar/introduction/SessionParserImpl.java index 52c12e5477ae040cc77be6193eeed5108d600662..5c86e7ed242542273d1ed44080b278336dbd0838 100644 --- a/briar-core/src/main/java/org/briarproject/briar/introduction/SessionParserImpl.java +++ b/briar-core/src/main/java/org/briarproject/briar/introduction/SessionParserImpl.java @@ -11,7 +11,7 @@ import org.briarproject.bramble.api.properties.TransportProperties; import org.briarproject.bramble.api.sync.GroupId; import org.briarproject.bramble.api.sync.MessageId; import org.briarproject.bramble.api.transport.KeySetId; -import org.briarproject.briar.api.client.SessionId; +import org.briarproject.bramble.api.client.SessionId; import org.briarproject.briar.api.introduction.Role; import org.briarproject.briar.introduction.IntroduceeSession.Local; import org.briarproject.briar.introduction.IntroduceeSession.Remote; diff --git a/briar-core/src/main/java/org/briarproject/briar/messaging/MessagingManagerImpl.java b/briar-core/src/main/java/org/briarproject/briar/messaging/MessagingManagerImpl.java index af46561a3ae006295aa10000db8782d0a1c87ef0..f70c239edd37467d7c5b1cb179fe36d25bbd44be 100644 --- a/briar-core/src/main/java/org/briarproject/briar/messaging/MessagingManagerImpl.java +++ b/briar-core/src/main/java/org/briarproject/briar/messaging/MessagingManagerImpl.java @@ -107,6 +107,7 @@ class MessagingManagerImpl extends ConversationClientImpl @Override public void onClientVisibilityChanging(Transaction txn, Contact c, Visibility v) throws DbException { + if(!getApplicableContactTypes().contains(c.getType())) return; // Apply the client's visibility to the contact group Group g = getContactGroup(c); db.setGroupVisibility(txn, c.getId(), g.getId(), v); diff --git a/briar-core/src/main/java/org/briarproject/briar/privategroup/PrivateGroupManagerImpl.java b/briar-core/src/main/java/org/briarproject/briar/privategroup/PrivateGroupManagerImpl.java index 4a615fe3430323e138187802c0fb223e42eb28a5..50e08acf8e9ed108b94db04152d4acbb349beefe 100644 --- a/briar-core/src/main/java/org/briarproject/briar/privategroup/PrivateGroupManagerImpl.java +++ b/briar-core/src/main/java/org/briarproject/briar/privategroup/PrivateGroupManagerImpl.java @@ -24,7 +24,7 @@ import org.briarproject.bramble.api.sync.Message; import org.briarproject.bramble.api.sync.MessageId; import org.briarproject.briar.api.client.MessageTracker; import org.briarproject.briar.api.client.MessageTracker.GroupCount; -import org.briarproject.briar.api.client.ProtocolStateException; +import org.briarproject.bramble.api.client.ProtocolStateException; import org.briarproject.briar.api.privategroup.GroupMember; import org.briarproject.briar.api.privategroup.GroupMessage; import org.briarproject.briar.api.privategroup.GroupMessageHeader; @@ -37,7 +37,7 @@ import org.briarproject.briar.api.privategroup.Visibility; import org.briarproject.briar.api.privategroup.event.ContactRelationshipRevealedEvent; import org.briarproject.briar.api.privategroup.event.GroupDissolvedEvent; import org.briarproject.briar.api.privategroup.event.GroupMessageAddedEvent; -import org.briarproject.briar.client.BdfIncomingMessageHook; +import org.briarproject.bramble.api.client.BdfIncomingMessageHook; import java.util.ArrayList; import java.util.Collection; diff --git a/briar-core/src/main/java/org/briarproject/briar/privategroup/invitation/CreatorProtocolEngine.java b/briar-core/src/main/java/org/briarproject/briar/privategroup/invitation/CreatorProtocolEngine.java index d043fbad260f7e00ce42c7d2172d68773b6ba54f..551b2d762efa2dbaaf33eed5fd635767897b9b55 100644 --- a/briar-core/src/main/java/org/briarproject/briar/privategroup/invitation/CreatorProtocolEngine.java +++ b/briar-core/src/main/java/org/briarproject/briar/privategroup/invitation/CreatorProtocolEngine.java @@ -12,8 +12,8 @@ import org.briarproject.bramble.api.sync.Message; import org.briarproject.bramble.api.system.Clock; import org.briarproject.bramble.api.versioning.ClientVersioningManager; import org.briarproject.briar.api.client.MessageTracker; -import org.briarproject.briar.api.client.ProtocolStateException; -import org.briarproject.briar.api.client.SessionId; +import org.briarproject.bramble.api.client.ProtocolStateException; +import org.briarproject.bramble.api.client.SessionId; import org.briarproject.briar.api.privategroup.GroupMessageFactory; import org.briarproject.briar.api.privategroup.PrivateGroupFactory; import org.briarproject.briar.api.privategroup.PrivateGroupManager; diff --git a/briar-core/src/main/java/org/briarproject/briar/privategroup/invitation/GroupInvitationManagerImpl.java b/briar-core/src/main/java/org/briarproject/briar/privategroup/invitation/GroupInvitationManagerImpl.java index b5a771970aef2f5249aa42b0167972cfea2f2d04..c0205049d9bd8da6ca40b82a42fafe3f91b08f89 100644 --- a/briar-core/src/main/java/org/briarproject/briar/privategroup/invitation/GroupInvitationManagerImpl.java +++ b/briar-core/src/main/java/org/briarproject/briar/privategroup/invitation/GroupInvitationManagerImpl.java @@ -26,7 +26,7 @@ import org.briarproject.bramble.api.sync.MessageStatus; import org.briarproject.bramble.api.versioning.ClientVersioningManager; import org.briarproject.bramble.api.versioning.ClientVersioningManager.ClientVersioningHook; import org.briarproject.briar.api.client.MessageTracker; -import org.briarproject.briar.api.client.SessionId; +import org.briarproject.bramble.api.client.SessionId; import org.briarproject.briar.api.privategroup.PrivateGroup; import org.briarproject.briar.api.privategroup.PrivateGroupFactory; import org.briarproject.briar.api.privategroup.PrivateGroupManager; @@ -588,6 +588,7 @@ class GroupInvitationManagerImpl extends ConversationClientImpl @Override public void onClientVisibilityChanging(Transaction txn, Contact c, Visibility v) throws DbException { + if(!getApplicableContactTypes().contains(c.getType())) return; // Apply the client's visibility to the contact group Group g = getContactGroup(c); db.setGroupVisibility(txn, c.getId(), g.getId(), v); @@ -600,6 +601,7 @@ class GroupInvitationManagerImpl extends ConversationClientImpl private void onPrivateGroupClientVisibilityChanging(Transaction txn, Contact c, Visibility client) throws DbException { try { + if(!getApplicableContactTypes().contains(c.getType())) return; Collection<Group> shareables = db.getGroups(txn, PrivateGroupManager.CLIENT_ID, PrivateGroupManager.MAJOR_VERSION); diff --git a/briar-core/src/main/java/org/briarproject/briar/privategroup/invitation/InviteeProtocolEngine.java b/briar-core/src/main/java/org/briarproject/briar/privategroup/invitation/InviteeProtocolEngine.java index a0e73d9b05d43f7a8f3ec227b03b37b6c5ef7b4c..efb98f7f5ac25d446ac270aa6a43a91d8590d28a 100644 --- a/briar-core/src/main/java/org/briarproject/briar/privategroup/invitation/InviteeProtocolEngine.java +++ b/briar-core/src/main/java/org/briarproject/briar/privategroup/invitation/InviteeProtocolEngine.java @@ -14,8 +14,8 @@ import org.briarproject.bramble.api.sync.MessageId; import org.briarproject.bramble.api.system.Clock; import org.briarproject.bramble.api.versioning.ClientVersioningManager; import org.briarproject.briar.api.client.MessageTracker; -import org.briarproject.briar.api.client.ProtocolStateException; -import org.briarproject.briar.api.client.SessionId; +import org.briarproject.bramble.api.client.ProtocolStateException; +import org.briarproject.bramble.api.client.SessionId; import org.briarproject.briar.api.privategroup.GroupMessageFactory; import org.briarproject.briar.api.privategroup.PrivateGroup; import org.briarproject.briar.api.privategroup.PrivateGroupFactory; diff --git a/briar-core/src/main/java/org/briarproject/briar/privategroup/invitation/PeerProtocolEngine.java b/briar-core/src/main/java/org/briarproject/briar/privategroup/invitation/PeerProtocolEngine.java index 9b7096b63b7ac48f2eea99fb5b1522b095f46f06..f70f8b3ecd9db714fd1d501a7884df67a6be47eb 100644 --- a/briar-core/src/main/java/org/briarproject/briar/privategroup/invitation/PeerProtocolEngine.java +++ b/briar-core/src/main/java/org/briarproject/briar/privategroup/invitation/PeerProtocolEngine.java @@ -13,7 +13,7 @@ import org.briarproject.bramble.api.sync.Message; import org.briarproject.bramble.api.system.Clock; import org.briarproject.bramble.api.versioning.ClientVersioningManager; import org.briarproject.briar.api.client.MessageTracker; -import org.briarproject.briar.api.client.ProtocolStateException; +import org.briarproject.bramble.api.client.ProtocolStateException; import org.briarproject.briar.api.privategroup.GroupMessageFactory; import org.briarproject.briar.api.privategroup.PrivateGroupFactory; import org.briarproject.briar.api.privategroup.PrivateGroupManager; diff --git a/briar-core/src/main/java/org/briarproject/briar/privategroup/invitation/SessionParser.java b/briar-core/src/main/java/org/briarproject/briar/privategroup/invitation/SessionParser.java index 152ed067e32c879d111df13e7f5c2442d6fe7e65..1c2dbe607510e4afc84bfb14461fcc1a02b50e5d 100644 --- a/briar-core/src/main/java/org/briarproject/briar/privategroup/invitation/SessionParser.java +++ b/briar-core/src/main/java/org/briarproject/briar/privategroup/invitation/SessionParser.java @@ -4,7 +4,7 @@ import org.briarproject.bramble.api.FormatException; import org.briarproject.bramble.api.data.BdfDictionary; import org.briarproject.bramble.api.nullsafety.NotNullByDefault; import org.briarproject.bramble.api.sync.GroupId; -import org.briarproject.briar.api.client.SessionId; +import org.briarproject.bramble.api.client.SessionId; @NotNullByDefault interface SessionParser { diff --git a/briar-core/src/main/java/org/briarproject/briar/privategroup/invitation/SessionParserImpl.java b/briar-core/src/main/java/org/briarproject/briar/privategroup/invitation/SessionParserImpl.java index 19a424d707e460cf8f023e42d1cb7a4dab028543..e58224cd0b1cd69cdfe6a66e94f3b596c844b23b 100644 --- a/briar-core/src/main/java/org/briarproject/briar/privategroup/invitation/SessionParserImpl.java +++ b/briar-core/src/main/java/org/briarproject/briar/privategroup/invitation/SessionParserImpl.java @@ -6,7 +6,7 @@ import org.briarproject.bramble.api.data.BdfEntry; import org.briarproject.bramble.api.nullsafety.NotNullByDefault; import org.briarproject.bramble.api.sync.GroupId; import org.briarproject.bramble.api.sync.MessageId; -import org.briarproject.briar.api.client.SessionId; +import org.briarproject.bramble.api.client.SessionId; import javax.annotation.Nullable; import javax.annotation.concurrent.Immutable; diff --git a/briar-core/src/main/java/org/briarproject/briar/sharing/BlogInvitationFactoryImpl.java b/briar-core/src/main/java/org/briarproject/briar/sharing/BlogInvitationFactoryImpl.java index 0162f08decd3c553c0722aa1ba4a052e74b21300..efeca4ac1bd01959d19e70bbb3c72fcf21a4a2a4 100644 --- a/briar-core/src/main/java/org/briarproject/briar/sharing/BlogInvitationFactoryImpl.java +++ b/briar-core/src/main/java/org/briarproject/briar/sharing/BlogInvitationFactoryImpl.java @@ -6,7 +6,7 @@ import org.briarproject.bramble.api.sync.MessageId; import org.briarproject.briar.api.blog.Blog; import org.briarproject.briar.api.blog.BlogInvitationRequest; import org.briarproject.briar.api.blog.BlogInvitationResponse; -import org.briarproject.briar.api.client.SessionId; +import org.briarproject.bramble.api.client.SessionId; import javax.inject.Inject; diff --git a/briar-core/src/main/java/org/briarproject/briar/sharing/ForumInvitationFactoryImpl.java b/briar-core/src/main/java/org/briarproject/briar/sharing/ForumInvitationFactoryImpl.java index c59acfd00677e9d225cc0346ef07058adb0d5c5c..d98bd6c0cd657318bc278155a2e9b3bacba7420f 100644 --- a/briar-core/src/main/java/org/briarproject/briar/sharing/ForumInvitationFactoryImpl.java +++ b/briar-core/src/main/java/org/briarproject/briar/sharing/ForumInvitationFactoryImpl.java @@ -3,7 +3,7 @@ package org.briarproject.briar.sharing; import org.briarproject.bramble.api.contact.ContactId; import org.briarproject.bramble.api.sync.GroupId; import org.briarproject.bramble.api.sync.MessageId; -import org.briarproject.briar.api.client.SessionId; +import org.briarproject.bramble.api.client.SessionId; import org.briarproject.briar.api.forum.Forum; import org.briarproject.briar.api.forum.ForumInvitationRequest; import org.briarproject.briar.api.forum.ForumInvitationResponse; diff --git a/briar-core/src/main/java/org/briarproject/briar/sharing/ProtocolEngineImpl.java b/briar-core/src/main/java/org/briarproject/briar/sharing/ProtocolEngineImpl.java index 0a672f57810a031537abae10dfc11c7a7db9b20a..9a0bf53ec24c03b5c4529e983c0a687dbda43659 100644 --- a/briar-core/src/main/java/org/briarproject/briar/sharing/ProtocolEngineImpl.java +++ b/briar-core/src/main/java/org/briarproject/briar/sharing/ProtocolEngineImpl.java @@ -19,7 +19,7 @@ import org.briarproject.bramble.api.sync.MessageId; import org.briarproject.bramble.api.system.Clock; import org.briarproject.bramble.api.versioning.ClientVersioningManager; import org.briarproject.briar.api.client.MessageTracker; -import org.briarproject.briar.api.client.ProtocolStateException; +import org.briarproject.bramble.api.client.ProtocolStateException; import org.briarproject.briar.api.sharing.Shareable; import org.briarproject.briar.api.sharing.event.ContactLeftShareableEvent; diff --git a/briar-core/src/main/java/org/briarproject/briar/sharing/SessionParser.java b/briar-core/src/main/java/org/briarproject/briar/sharing/SessionParser.java index eec97355f4db745ea8fb54712cd73717698de051..768ba339d17611bb7146d259a1b506354c2f5e8d 100644 --- a/briar-core/src/main/java/org/briarproject/briar/sharing/SessionParser.java +++ b/briar-core/src/main/java/org/briarproject/briar/sharing/SessionParser.java @@ -4,7 +4,7 @@ import org.briarproject.bramble.api.FormatException; import org.briarproject.bramble.api.data.BdfDictionary; import org.briarproject.bramble.api.nullsafety.NotNullByDefault; import org.briarproject.bramble.api.sync.GroupId; -import org.briarproject.briar.api.client.SessionId; +import org.briarproject.bramble.api.client.SessionId; @NotNullByDefault interface SessionParser { diff --git a/briar-core/src/main/java/org/briarproject/briar/sharing/SessionParserImpl.java b/briar-core/src/main/java/org/briarproject/briar/sharing/SessionParserImpl.java index ee0c06f61f32d6acb9149d6664b927cde30eb14f..d59a23ca00f3df82521896ed502113165cbd23a4 100644 --- a/briar-core/src/main/java/org/briarproject/briar/sharing/SessionParserImpl.java +++ b/briar-core/src/main/java/org/briarproject/briar/sharing/SessionParserImpl.java @@ -6,7 +6,7 @@ import org.briarproject.bramble.api.data.BdfEntry; import org.briarproject.bramble.api.nullsafety.NotNullByDefault; import org.briarproject.bramble.api.sync.GroupId; import org.briarproject.bramble.api.sync.MessageId; -import org.briarproject.briar.api.client.SessionId; +import org.briarproject.bramble.api.client.SessionId; import javax.annotation.Nullable; import javax.annotation.concurrent.Immutable; diff --git a/briar-core/src/main/java/org/briarproject/briar/sharing/SharingManagerImpl.java b/briar-core/src/main/java/org/briarproject/briar/sharing/SharingManagerImpl.java index 7b9c81867503c79356b8d12126c9df79270ba862..1ef808825414d39c05865c5b2c7a5593dcfe2341 100644 --- a/briar-core/src/main/java/org/briarproject/briar/sharing/SharingManagerImpl.java +++ b/briar-core/src/main/java/org/briarproject/briar/sharing/SharingManagerImpl.java @@ -26,7 +26,7 @@ import org.briarproject.bramble.api.sync.MessageStatus; import org.briarproject.bramble.api.versioning.ClientVersioningManager; import org.briarproject.bramble.api.versioning.ClientVersioningManager.ClientVersioningHook; import org.briarproject.briar.api.client.MessageTracker; -import org.briarproject.briar.api.client.SessionId; +import org.briarproject.bramble.api.client.SessionId; import org.briarproject.briar.api.sharing.InvitationMessage; import org.briarproject.briar.api.sharing.InvitationRequest; import org.briarproject.briar.api.sharing.InvitationResponse; @@ -510,6 +510,7 @@ abstract class SharingManagerImpl<S extends Shareable> @Override public void onClientVisibilityChanging(Transaction txn, Contact c, Visibility v) throws DbException { + if(!getApplicableContactTypes().contains(c.getType())) return; // Apply the client's visibility to the contact group Group g = getContactGroup(c); db.setGroupVisibility(txn, c.getId(), g.getId(), v); @@ -523,6 +524,7 @@ abstract class SharingManagerImpl<S extends Shareable> private void onShareableClientVisibilityChanging(Transaction txn, Contact c, Visibility client) throws DbException { try { + if(!getApplicableContactTypes().contains(c.getType())) return; Collection<Group> shareables = db.getGroups(txn, getShareableClientId(), getShareableMajorVersion()); Map<GroupId, Visibility> m = getPreferredVisibilities(txn, c); diff --git a/briar-core/src/test/java/org/briarproject/briar/introduction/IntroductionCryptoIntegrationTest.java b/briar-core/src/test/java/org/briarproject/briar/introduction/IntroductionCryptoIntegrationTest.java index 81c2ae01c3c6a80389b5bc793615006f4a6df1a2..d894866aa4edadad81155088d47219850fad4349 100644 --- a/briar-core/src/test/java/org/briarproject/briar/introduction/IntroductionCryptoIntegrationTest.java +++ b/briar-core/src/test/java/org/briarproject/briar/introduction/IntroductionCryptoIntegrationTest.java @@ -10,7 +10,7 @@ import org.briarproject.bramble.api.identity.LocalAuthor; import org.briarproject.bramble.api.plugin.TransportId; import org.briarproject.bramble.api.properties.TransportProperties; import org.briarproject.bramble.test.BrambleTestCase; -import org.briarproject.briar.api.client.SessionId; +import org.briarproject.bramble.api.client.SessionId; import org.junit.Test; import java.util.Map; diff --git a/briar-core/src/test/java/org/briarproject/briar/introduction/IntroductionCryptoTest.java b/briar-core/src/test/java/org/briarproject/briar/introduction/IntroductionCryptoTest.java index f966aa2cb06531c1c3b241bdd112c10d23620f0b..7f13a6311b16df9192f331c4f2f1442effa55c0f 100644 --- a/briar-core/src/test/java/org/briarproject/briar/introduction/IntroductionCryptoTest.java +++ b/briar-core/src/test/java/org/briarproject/briar/introduction/IntroductionCryptoTest.java @@ -4,7 +4,7 @@ import org.briarproject.bramble.api.client.ClientHelper; import org.briarproject.bramble.api.crypto.CryptoComponent; import org.briarproject.bramble.api.identity.Author; import org.briarproject.bramble.test.BrambleMockTestCase; -import org.briarproject.briar.api.client.SessionId; +import org.briarproject.bramble.api.client.SessionId; import org.jmock.Expectations; import org.junit.Test; diff --git a/briar-core/src/test/java/org/briarproject/briar/introduction/IntroductionIntegrationTest.java b/briar-core/src/test/java/org/briarproject/briar/introduction/IntroductionIntegrationTest.java index b3161af64dce727a64b1fafa8dba50879ce68094..51953b6164512e577bb10020460960aa47f99a99 100644 --- a/briar-core/src/test/java/org/briarproject/briar/introduction/IntroductionIntegrationTest.java +++ b/briar-core/src/test/java/org/briarproject/briar/introduction/IntroductionIntegrationTest.java @@ -4,6 +4,8 @@ import net.jodah.concurrentunit.Waiter; import org.briarproject.bramble.api.FormatException; import org.briarproject.bramble.api.client.ClientHelper; +import org.briarproject.bramble.api.client.ProtocolStateException; +import org.briarproject.bramble.api.client.SessionId; import org.briarproject.bramble.api.contact.Contact; import org.briarproject.bramble.api.contact.ContactId; import org.briarproject.bramble.api.data.BdfDictionary; @@ -22,8 +24,6 @@ import org.briarproject.bramble.api.sync.Group; import org.briarproject.bramble.api.sync.Message; import org.briarproject.bramble.api.sync.MessageId; import org.briarproject.bramble.test.TestDatabaseModule; -import org.briarproject.briar.api.client.ProtocolStateException; -import org.briarproject.briar.api.client.SessionId; import org.briarproject.briar.api.introduction.IntroductionManager; import org.briarproject.briar.api.introduction.IntroductionMessage; import org.briarproject.briar.api.introduction.IntroductionRequest; diff --git a/briar-core/src/test/java/org/briarproject/briar/introduction/IntroductionValidatorTest.java b/briar-core/src/test/java/org/briarproject/briar/introduction/IntroductionValidatorTest.java index 4f52aa4de9f83d9df7cb4e5b735bf3557e82c524..743946de812ba5885c678a6b2563542ed5339715 100644 --- a/briar-core/src/test/java/org/briarproject/briar/introduction/IntroductionValidatorTest.java +++ b/briar-core/src/test/java/org/briarproject/briar/introduction/IntroductionValidatorTest.java @@ -7,7 +7,7 @@ import org.briarproject.bramble.api.data.BdfEntry; import org.briarproject.bramble.api.data.BdfList; import org.briarproject.bramble.api.sync.MessageId; import org.briarproject.bramble.test.ValidatorTestCase; -import org.briarproject.briar.api.client.SessionId; +import org.briarproject.bramble.api.client.SessionId; import org.jmock.Expectations; import org.junit.Test; diff --git a/briar-core/src/test/java/org/briarproject/briar/introduction/MessageEncoderParserIntegrationTest.java b/briar-core/src/test/java/org/briarproject/briar/introduction/MessageEncoderParserIntegrationTest.java index a29f7944577f3b494ba3eb50a6ea44dcf26290c1..3dc0588b5bad1a0c934bf0e1ca4bce71a3b473cf 100644 --- a/briar-core/src/test/java/org/briarproject/briar/introduction/MessageEncoderParserIntegrationTest.java +++ b/briar-core/src/test/java/org/briarproject/briar/introduction/MessageEncoderParserIntegrationTest.java @@ -15,7 +15,7 @@ import org.briarproject.bramble.api.sync.MessageFactory; import org.briarproject.bramble.api.sync.MessageId; import org.briarproject.bramble.api.system.Clock; import org.briarproject.bramble.test.BrambleTestCase; -import org.briarproject.briar.api.client.SessionId; +import org.briarproject.bramble.api.client.SessionId; import org.junit.Test; import java.util.Map; diff --git a/briar-core/src/test/java/org/briarproject/briar/introduction/SessionEncoderParserIntegrationTest.java b/briar-core/src/test/java/org/briarproject/briar/introduction/SessionEncoderParserIntegrationTest.java index 9ddb006323c4f5f28c9c36a59a80c53b9d1015fb..9a6f616ea72d8b587c7917d5d6cb4a413b811589 100644 --- a/briar-core/src/test/java/org/briarproject/briar/introduction/SessionEncoderParserIntegrationTest.java +++ b/briar-core/src/test/java/org/briarproject/briar/introduction/SessionEncoderParserIntegrationTest.java @@ -12,7 +12,7 @@ import org.briarproject.bramble.api.sync.GroupId; import org.briarproject.bramble.api.sync.MessageId; import org.briarproject.bramble.api.transport.KeySetId; import org.briarproject.bramble.test.BrambleTestCase; -import org.briarproject.briar.api.client.SessionId; +import org.briarproject.bramble.api.client.SessionId; import org.briarproject.briar.introduction.IntroducerSession.Introducee; import org.junit.Test; diff --git a/briar-core/src/test/java/org/briarproject/briar/privategroup/invitation/CreatorProtocolEngineTest.java b/briar-core/src/test/java/org/briarproject/briar/privategroup/invitation/CreatorProtocolEngineTest.java index 19e996e43d0ce80c7dbd7551e373cfc3e5ea58cb..062695da12b5ba9e6143107c6041b3c498d4d08c 100644 --- a/briar-core/src/test/java/org/briarproject/briar/privategroup/invitation/CreatorProtocolEngineTest.java +++ b/briar-core/src/test/java/org/briarproject/briar/privategroup/invitation/CreatorProtocolEngineTest.java @@ -1,7 +1,7 @@ package org.briarproject.briar.privategroup.invitation; import org.briarproject.bramble.api.sync.MessageId; -import org.briarproject.briar.api.client.ProtocolStateException; +import org.briarproject.bramble.api.client.ProtocolStateException; import org.jmock.Expectations; import org.junit.Test; diff --git a/briar-core/src/test/java/org/briarproject/briar/privategroup/invitation/GroupInvitationIntegrationTest.java b/briar-core/src/test/java/org/briarproject/briar/privategroup/invitation/GroupInvitationIntegrationTest.java index 66a0bdb0329ff4efdad0ebcf71c8cd0a6fcc4c50..35660c9715cf801f1d46d2d4fa61615bdd795966 100644 --- a/briar-core/src/test/java/org/briarproject/briar/privategroup/invitation/GroupInvitationIntegrationTest.java +++ b/briar-core/src/test/java/org/briarproject/briar/privategroup/invitation/GroupInvitationIntegrationTest.java @@ -3,7 +3,7 @@ package org.briarproject.briar.privategroup.invitation; import org.briarproject.bramble.api.db.DbException; import org.briarproject.bramble.api.sync.Group; import org.briarproject.bramble.test.TestDatabaseModule; -import org.briarproject.briar.api.client.ProtocolStateException; +import org.briarproject.bramble.api.client.ProtocolStateException; import org.briarproject.briar.api.privategroup.GroupMessage; import org.briarproject.briar.api.privategroup.PrivateGroup; import org.briarproject.briar.api.privategroup.PrivateGroupManager; diff --git a/briar-core/src/test/java/org/briarproject/briar/privategroup/invitation/GroupInvitationManagerImplTest.java b/briar-core/src/test/java/org/briarproject/briar/privategroup/invitation/GroupInvitationManagerImplTest.java index 328347b4dcb8055bea780e6b1bad27221738a243..fa6d228e5f90fc426da626c37de4436fab272d38 100644 --- a/briar-core/src/test/java/org/briarproject/briar/privategroup/invitation/GroupInvitationManagerImplTest.java +++ b/briar-core/src/test/java/org/briarproject/briar/privategroup/invitation/GroupInvitationManagerImplTest.java @@ -23,7 +23,7 @@ import org.briarproject.bramble.api.versioning.ClientVersioningManager; import org.briarproject.bramble.test.BrambleMockTestCase; import org.briarproject.bramble.test.TestUtils; import org.briarproject.briar.api.client.MessageTracker; -import org.briarproject.briar.api.client.SessionId; +import org.briarproject.bramble.api.client.SessionId; import org.briarproject.briar.api.privategroup.PrivateGroup; import org.briarproject.briar.api.privategroup.PrivateGroupFactory; import org.briarproject.briar.api.privategroup.PrivateGroupManager; diff --git a/briar-core/src/test/java/org/briarproject/briar/privategroup/invitation/InviteeProtocolEngineTest.java b/briar-core/src/test/java/org/briarproject/briar/privategroup/invitation/InviteeProtocolEngineTest.java index abbb912deb7cd0c10c7729a8d075548c67f895f7..70d604f5d390d6feeae4e83f498eae928b00fd7f 100644 --- a/briar-core/src/test/java/org/briarproject/briar/privategroup/invitation/InviteeProtocolEngineTest.java +++ b/briar-core/src/test/java/org/briarproject/briar/privategroup/invitation/InviteeProtocolEngineTest.java @@ -6,7 +6,7 @@ import org.briarproject.bramble.api.data.BdfEntry; import org.briarproject.bramble.api.identity.Author; import org.briarproject.bramble.api.identity.LocalAuthor; import org.briarproject.bramble.api.sync.MessageId; -import org.briarproject.briar.api.client.ProtocolStateException; +import org.briarproject.bramble.api.client.ProtocolStateException; import org.briarproject.briar.api.privategroup.GroupMessage; import org.jmock.Expectations; import org.junit.Test; diff --git a/briar-core/src/test/java/org/briarproject/briar/privategroup/invitation/PeerProtocolEngineTest.java b/briar-core/src/test/java/org/briarproject/briar/privategroup/invitation/PeerProtocolEngineTest.java index 05c0920c545c3b97c83f9553ab2034cee77a8774..d45930a71abb284fb1e47291e566471fe169434d 100644 --- a/briar-core/src/test/java/org/briarproject/briar/privategroup/invitation/PeerProtocolEngineTest.java +++ b/briar-core/src/test/java/org/briarproject/briar/privategroup/invitation/PeerProtocolEngineTest.java @@ -1,7 +1,7 @@ package org.briarproject.briar.privategroup.invitation; import org.briarproject.bramble.api.sync.MessageId; -import org.briarproject.briar.api.client.ProtocolStateException; +import org.briarproject.bramble.api.client.ProtocolStateException; import org.jmock.Expectations; import org.junit.Test; diff --git a/briar-core/src/test/java/org/briarproject/briar/sharing/BlogSharingManagerImplTest.java b/briar-core/src/test/java/org/briarproject/briar/sharing/BlogSharingManagerImplTest.java index c44c1e23f11f765e49b274683ca709d99f6d1d29..c85618b9abe37af6aa95b9b384a00b4f7c2d1129 100644 --- a/briar-core/src/test/java/org/briarproject/briar/sharing/BlogSharingManagerImplTest.java +++ b/briar-core/src/test/java/org/briarproject/briar/sharing/BlogSharingManagerImplTest.java @@ -23,7 +23,7 @@ import org.briarproject.briar.api.blog.Blog; import org.briarproject.briar.api.blog.BlogInvitationResponse; import org.briarproject.briar.api.blog.BlogManager; import org.briarproject.briar.api.client.MessageTracker; -import org.briarproject.briar.api.client.SessionId; +import org.briarproject.bramble.api.client.SessionId; import org.jmock.Expectations; import org.junit.Test;