From 15ea91a9bd9b2d1b44aa9c110fba3e2149a1e15a Mon Sep 17 00:00:00 2001 From: Julian Dehm <goapunk@riseup.net> Date: Sat, 29 Sep 2018 12:11:27 +0200 Subject: [PATCH] wipper --- .../api}/client/BdfIncomingMessageHook.java | 2 +- .../api/client/ProtocolStateException.java | 2 +- .../bramble}/api/client/SessionId.java | 2 +- .../bramble/api/contact/ContactFactory.java | 3 + .../bramble/api/contact/ContactMailbox.java | 26 + .../bramble/api/contact/ContactManager.java | 15 +- .../bramble/api/db/DatabaseConfig.java | 1 + .../api/mailbox/IntroductionConstants.java | 24 + .../mailbox/MailboxIntroductionManager.java | 40 ++ .../bramble/api/mailbox/Role.java | 29 ++ .../MailboxIntroductionAbortedEvent.java | 22 + ...ilboxIntroductionRequestReceivedEvent.java | 24 + ...lboxIntroductionResponseReceivedEvent.java | 29 ++ .../MailboxIntroductionSucceededEvent.java | 22 + .../properties/TransportPropertyManager.java | 4 + bramble-core/build.gradle | 1 + .../bramble/contact/ContactManagerImpl.java | 65 ++- .../briarproject/bramble/db/JdbcDatabase.java | 2 +- .../mailbox/introduction/AbortMessage.java | 27 + .../AbstractIntroduceeSession.java | 156 ++++++ .../AbstractMailboxIntroductionMessage.java | 45 ++ .../introduction/AbstractProtocolEngine.java | 168 ++++++ .../mailbox/introduction/DeclineMessage.java | 28 + .../mailbox/introduction/Introducee.java | 83 +++ .../introduction/IntroduceeAcceptMessage.java | 52 ++ .../IntroduceeProtocolEngine.java | 230 +++++++++ .../introduction/IntroduceeSession.java | 147 ++++++ .../mailbox/introduction/IntroduceeState.java | 33 ++ .../introduction/IntroductionConstants.java | 49 ++ .../introduction/MailboxAcceptMessage.java | 48 ++ .../introduction/MailboxAuthMessage.java | 51 ++ .../MailboxIntroductionCrypto.java | 95 ++++ .../MailboxIntroductionCryptoImpl.java | 190 +++++++ .../MailboxIntroductionManagerImpl.java | 486 ++++++++++++++++++ .../MailboxIntroductionModule.java | 95 ++++ .../MailboxIntroductionValidator.java | 216 ++++++++ .../introduction/MailboxMessageEncoder.java | 57 ++ .../MailboxMessageEncoderImpl.java | 160 ++++++ .../introduction/MailboxMessageParser.java | 33 ++ .../MailboxMessageParserImpl.java | 134 +++++ .../introduction/MailboxProtocolEngine.java | 263 ++++++++++ .../mailbox/introduction/MailboxSession.java | 136 +++++ .../introduction/MailboxSessionEncoder.java | 18 + .../MailboxSessionEncoderImpl.java | 155 ++++++ .../introduction/MailboxSessionParser.java | 27 + .../MailboxSessionParserImpl.java | 231 +++++++++ .../mailbox/introduction/MailboxState.java | 34 ++ .../mailbox/introduction/MessageMetadata.java | 55 ++ .../mailbox/introduction/MessageType.java | 35 ++ .../introduction/OwnerProtocolEngine.java | 262 ++++++++++ .../mailbox/introduction/OwnerSession.java | 52 ++ .../mailbox/introduction/OwnerState.java | 36 ++ .../mailbox/introduction/PeerSession.java | 27 + .../mailbox/introduction/ProtocolEngine.java | 30 ++ .../mailbox/introduction/RequestMessage.java | 28 + .../bramble/mailbox/introduction/Session.java | 44 ++ .../bramble/mailbox/introduction/State.java | 7 + .../TransportPropertyManagerImpl.java | 15 +- .../integration/BrambleIntegrationTest.java | 404 +++++++++++++++ .../BrambleIntegrationTestComponent.java | 102 ++++ .../bramble/integration/TestStreamWriter.java | 25 + .../MailboxIntroductionIntegrationTest.java | 303 +++++++++++ ...xIntroductionIntegrationTestComponent.java | 62 +++ .../briar/api/blog/BlogInvitationRequest.java | 2 +- .../api/blog/BlogInvitationResponse.java | 2 +- .../api/forum/ForumInvitationRequest.java | 2 +- .../api/forum/ForumInvitationResponse.java | 2 +- .../api/introduction/IntroductionManager.java | 2 +- .../api/introduction/IntroductionMessage.java | 2 +- .../api/introduction/IntroductionRequest.java | 2 +- .../introduction/IntroductionResponse.java | 2 +- .../event/IntroductionAbortedEvent.java | 2 +- .../invitation/GroupInvitationManager.java | 4 +- .../invitation/GroupInvitationRequest.java | 2 +- .../invitation/GroupInvitationResponse.java | 2 +- .../briar/api/sharing/InvitationMessage.java | 2 +- .../briar/api/sharing/InvitationRequest.java | 2 +- .../briar/api/sharing/InvitationResponse.java | 2 +- .../briar/api/sharing/SharingManager.java | 2 +- .../briar/blog/BlogManagerImpl.java | 2 +- .../briar/client/ConversationClientImpl.java | 1 + .../briar/forum/ForumManagerImpl.java | 2 +- .../briar/introduction/AbortMessage.java | 2 +- .../introduction/AbstractProtocolEngine.java | 2 +- .../briar/introduction/AcceptMessage.java | 2 +- .../briar/introduction/ActivateMessage.java | 2 +- .../briar/introduction/AuthMessage.java | 2 +- .../briar/introduction/DeclineMessage.java | 2 +- .../IntroduceeProtocolEngine.java | 4 +- .../briar/introduction/IntroduceeSession.java | 2 +- .../IntroducerProtocolEngine.java | 3 +- .../briar/introduction/IntroducerSession.java | 2 +- .../introduction/IntroductionCrypto.java | 2 +- .../introduction/IntroductionCryptoImpl.java | 2 +- .../introduction/IntroductionManagerImpl.java | 3 +- .../introduction/IntroductionValidator.java | 2 +- .../briar/introduction/MessageEncoder.java | 2 +- .../introduction/MessageEncoderImpl.java | 2 +- .../briar/introduction/MessageMetadata.java | 2 +- .../briar/introduction/MessageParser.java | 2 +- .../briar/introduction/MessageParserImpl.java | 2 +- .../briar/introduction/PeerSession.java | 2 +- .../briar/introduction/Session.java | 2 +- .../briar/introduction/SessionParser.java | 2 +- .../briar/introduction/SessionParserImpl.java | 2 +- .../briar/messaging/MessagingManagerImpl.java | 1 + .../privategroup/PrivateGroupManagerImpl.java | 4 +- .../invitation/CreatorProtocolEngine.java | 4 +- .../GroupInvitationManagerImpl.java | 4 +- .../invitation/InviteeProtocolEngine.java | 4 +- .../invitation/PeerProtocolEngine.java | 2 +- .../invitation/SessionParser.java | 2 +- .../invitation/SessionParserImpl.java | 2 +- .../sharing/BlogInvitationFactoryImpl.java | 2 +- .../sharing/ForumInvitationFactoryImpl.java | 2 +- .../briar/sharing/ProtocolEngineImpl.java | 2 +- .../briar/sharing/SessionParser.java | 2 +- .../briar/sharing/SessionParserImpl.java | 2 +- .../briar/sharing/SharingManagerImpl.java | 4 +- .../IntroductionCryptoIntegrationTest.java | 2 +- .../introduction/IntroductionCryptoTest.java | 2 +- .../IntroductionIntegrationTest.java | 4 +- .../IntroductionValidatorTest.java | 2 +- .../MessageEncoderParserIntegrationTest.java | 2 +- .../SessionEncoderParserIntegrationTest.java | 2 +- .../invitation/CreatorProtocolEngineTest.java | 2 +- .../GroupInvitationIntegrationTest.java | 2 +- .../GroupInvitationManagerImplTest.java | 2 +- .../invitation/InviteeProtocolEngineTest.java | 2 +- .../invitation/PeerProtocolEngineTest.java | 2 +- .../sharing/BlogSharingManagerImplTest.java | 2 +- 131 files changed, 5320 insertions(+), 79 deletions(-) rename {briar-core/src/main/java/org/briarproject/briar => bramble-api/src/main/java/org/briarproject/bramble/api}/client/BdfIncomingMessageHook.java (98%) rename {briar-api/src/main/java/org/briarproject/briar => bramble-api/src/main/java/org/briarproject/bramble}/api/client/ProtocolStateException.java (89%) rename {briar-api/src/main/java/org/briarproject/briar => bramble-api/src/main/java/org/briarproject/bramble}/api/client/SessionId.java (91%) create mode 100644 bramble-api/src/main/java/org/briarproject/bramble/api/contact/ContactMailbox.java create mode 100644 bramble-api/src/main/java/org/briarproject/bramble/api/mailbox/IntroductionConstants.java create mode 100644 bramble-api/src/main/java/org/briarproject/bramble/api/mailbox/MailboxIntroductionManager.java create mode 100644 bramble-api/src/main/java/org/briarproject/bramble/api/mailbox/Role.java create mode 100644 bramble-api/src/main/java/org/briarproject/bramble/api/mailbox/event/MailboxIntroductionAbortedEvent.java create mode 100644 bramble-api/src/main/java/org/briarproject/bramble/api/mailbox/event/MailboxIntroductionRequestReceivedEvent.java create mode 100644 bramble-api/src/main/java/org/briarproject/bramble/api/mailbox/event/MailboxIntroductionResponseReceivedEvent.java create mode 100644 bramble-api/src/main/java/org/briarproject/bramble/api/mailbox/event/MailboxIntroductionSucceededEvent.java create mode 100644 bramble-core/src/main/java/org/briarproject/bramble/mailbox/introduction/AbortMessage.java create mode 100644 bramble-core/src/main/java/org/briarproject/bramble/mailbox/introduction/AbstractIntroduceeSession.java create mode 100644 bramble-core/src/main/java/org/briarproject/bramble/mailbox/introduction/AbstractMailboxIntroductionMessage.java create mode 100644 bramble-core/src/main/java/org/briarproject/bramble/mailbox/introduction/AbstractProtocolEngine.java create mode 100644 bramble-core/src/main/java/org/briarproject/bramble/mailbox/introduction/DeclineMessage.java create mode 100644 bramble-core/src/main/java/org/briarproject/bramble/mailbox/introduction/Introducee.java create mode 100644 bramble-core/src/main/java/org/briarproject/bramble/mailbox/introduction/IntroduceeAcceptMessage.java create mode 100644 bramble-core/src/main/java/org/briarproject/bramble/mailbox/introduction/IntroduceeProtocolEngine.java create mode 100644 bramble-core/src/main/java/org/briarproject/bramble/mailbox/introduction/IntroduceeSession.java create mode 100644 bramble-core/src/main/java/org/briarproject/bramble/mailbox/introduction/IntroduceeState.java create mode 100644 bramble-core/src/main/java/org/briarproject/bramble/mailbox/introduction/IntroductionConstants.java create mode 100644 bramble-core/src/main/java/org/briarproject/bramble/mailbox/introduction/MailboxAcceptMessage.java create mode 100644 bramble-core/src/main/java/org/briarproject/bramble/mailbox/introduction/MailboxAuthMessage.java create mode 100644 bramble-core/src/main/java/org/briarproject/bramble/mailbox/introduction/MailboxIntroductionCrypto.java create mode 100644 bramble-core/src/main/java/org/briarproject/bramble/mailbox/introduction/MailboxIntroductionCryptoImpl.java create mode 100644 bramble-core/src/main/java/org/briarproject/bramble/mailbox/introduction/MailboxIntroductionManagerImpl.java create mode 100644 bramble-core/src/main/java/org/briarproject/bramble/mailbox/introduction/MailboxIntroductionModule.java create mode 100644 bramble-core/src/main/java/org/briarproject/bramble/mailbox/introduction/MailboxIntroductionValidator.java create mode 100644 bramble-core/src/main/java/org/briarproject/bramble/mailbox/introduction/MailboxMessageEncoder.java create mode 100644 bramble-core/src/main/java/org/briarproject/bramble/mailbox/introduction/MailboxMessageEncoderImpl.java create mode 100644 bramble-core/src/main/java/org/briarproject/bramble/mailbox/introduction/MailboxMessageParser.java create mode 100644 bramble-core/src/main/java/org/briarproject/bramble/mailbox/introduction/MailboxMessageParserImpl.java create mode 100644 bramble-core/src/main/java/org/briarproject/bramble/mailbox/introduction/MailboxProtocolEngine.java create mode 100644 bramble-core/src/main/java/org/briarproject/bramble/mailbox/introduction/MailboxSession.java create mode 100644 bramble-core/src/main/java/org/briarproject/bramble/mailbox/introduction/MailboxSessionEncoder.java create mode 100644 bramble-core/src/main/java/org/briarproject/bramble/mailbox/introduction/MailboxSessionEncoderImpl.java create mode 100644 bramble-core/src/main/java/org/briarproject/bramble/mailbox/introduction/MailboxSessionParser.java create mode 100644 bramble-core/src/main/java/org/briarproject/bramble/mailbox/introduction/MailboxSessionParserImpl.java create mode 100644 bramble-core/src/main/java/org/briarproject/bramble/mailbox/introduction/MailboxState.java create mode 100644 bramble-core/src/main/java/org/briarproject/bramble/mailbox/introduction/MessageMetadata.java create mode 100644 bramble-core/src/main/java/org/briarproject/bramble/mailbox/introduction/MessageType.java create mode 100644 bramble-core/src/main/java/org/briarproject/bramble/mailbox/introduction/OwnerProtocolEngine.java create mode 100644 bramble-core/src/main/java/org/briarproject/bramble/mailbox/introduction/OwnerSession.java create mode 100644 bramble-core/src/main/java/org/briarproject/bramble/mailbox/introduction/OwnerState.java create mode 100644 bramble-core/src/main/java/org/briarproject/bramble/mailbox/introduction/PeerSession.java create mode 100644 bramble-core/src/main/java/org/briarproject/bramble/mailbox/introduction/ProtocolEngine.java create mode 100644 bramble-core/src/main/java/org/briarproject/bramble/mailbox/introduction/RequestMessage.java create mode 100644 bramble-core/src/main/java/org/briarproject/bramble/mailbox/introduction/Session.java create mode 100644 bramble-core/src/main/java/org/briarproject/bramble/mailbox/introduction/State.java create mode 100644 bramble-core/src/test/java/org/briarproject/bramble/integration/BrambleIntegrationTest.java create mode 100644 bramble-core/src/test/java/org/briarproject/bramble/integration/BrambleIntegrationTestComponent.java create mode 100644 bramble-core/src/test/java/org/briarproject/bramble/integration/TestStreamWriter.java create mode 100644 bramble-core/src/test/java/org/briarproject/bramble/mailbox/introduction/MailboxIntroductionIntegrationTest.java create mode 100644 bramble-core/src/test/java/org/briarproject/bramble/mailbox/introduction/MailboxIntroductionIntegrationTestComponent.java 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 edc62948d..30de75695 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 a879e912d..3672e091f 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 d569bdfec..e350327d8 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 b12c19c99..ab3eb6eae 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 000000000..6a044b94b --- /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 d8693d79f..5b87dc303 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 f096f1fec..0df7b80a7 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 000000000..651309882 --- /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 000000000..ca912d551 --- /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 000000000..df8655b9a --- /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 000000000..38e36fa46 --- /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 000000000..a690247f7 --- /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 000000000..3f655215e --- /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 000000000..df6cb7b8b --- /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 1c64f5b6d..164d1f5a2 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 eec6c4387..e0e54ac4f 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 976f270f8..c600e3a21 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 132f3b8de..a185633c7 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 000000000..02bd625a5 --- /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 000000000..438bc62cb --- /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 000000000..f498ce766 --- /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 000000000..8a998aa5e --- /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 000000000..d7367c467 --- /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 000000000..8494cfdcb --- /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 000000000..fc34dddc1 --- /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 000000000..83fe29e7c --- /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 000000000..9ffd984ed --- /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 000000000..e0bad4558 --- /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 000000000..adc5223cd --- /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 000000000..bec6267bd --- /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 000000000..8f7871be9 --- /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 000000000..46f8736cd --- /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 000000000..79d7f6d07 --- /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 000000000..c10a7bfce --- /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 000000000..409a0149c --- /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 000000000..f6a2e2362 --- /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 000000000..f1ead80fa --- /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 000000000..8e438ada9 --- /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 000000000..8ca36bda9 --- /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 000000000..778e76e82 --- /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 000000000..9f19e23ac --- /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 000000000..e9b7fe6e8 --- /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 000000000..22bd220e4 --- /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 000000000..cb87e76de --- /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 000000000..a77b3c601 --- /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 000000000..a714fe929 --- /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 000000000..9a00c0584 --- /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 000000000..2acc67711 --- /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 000000000..10a6efd80 --- /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 000000000..50be2b64b --- /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 000000000..e88389215 --- /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 000000000..bf77ef7c7 --- /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 000000000..b832a5f57 --- /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 000000000..c0b18de6b --- /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 000000000..d490ef2ac --- /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 000000000..6039a5a69 --- /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 000000000..1e794cd83 --- /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 98822d8b0..7851663bc 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 000000000..8c73d1110 --- /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 000000000..2a0e20334 --- /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 000000000..6b619169f --- /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 000000000..d69b67fc5 --- /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 000000000..706b951ea --- /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 77dddbbe0..cbf36af8f 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 e49142300..1e9cb9a83 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 2d23ab0e8..cc13e0d8b 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 48f03ce85..45e8bc1fd 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 532d63353..e08b16eef 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 009487fa2..0b72ddd3f 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 b2a804bd8..1201ce516 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 816135d43..605e3eb54 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 113ba400e..08b4f72ff 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 1062d0ce1..cf8498474 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 d447ae8ef..505a450a7 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 b2e7d54b5..273a39e8e 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 df93ebdfa..e6953894e 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 c5239310d..5a1b90c43 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 517b6068e..18a3102a0 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 b593d2fdf..656fa623b 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 7f6e581f5..e4584245b 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 9e47fa3a3..cb8a280b2 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 58b35ea65..1c410c913 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 e9a2d1233..cdcacb7b6 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 03b3486ad..b56aa0c1c 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 6cadae73b..dfc6e33ea 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 5f767737d..c9c535667 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 1de1a4eb5..f64ae616e 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 27386b905..b4b1acd3a 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 6bdaea9d2..5857c3aa4 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 b952b3dc5..203275b0f 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 c159697ad..d2d57016e 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 3c50621eb..b48595d70 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 37f7aa10f..bef20f1d2 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 d892c58b3..045772589 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 19021d113..b2c2d0633 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 929c8bddf..570f76c68 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 1327b54a9..9ffad1a64 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 fb3d66f38..7dde27034 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 102d72bfc..6186c50d5 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 503dd4cc6..8403f20c2 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 69ddd242d..13224d612 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 3c453d2fa..d8504db14 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 086dfb1a2..6e8bcff17 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 c58cac3d9..82dfa092a 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 52c12e547..5c86e7ed2 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 af46561a3..f70c239ed 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 4a615fe34..50e08acf8 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 d043fbad2..551b2d762 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 b5a771970..c0205049d 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 a0e73d9b0..efb98f7f5 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 9b7096b63..f70f8b3ec 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 152ed067e..1c2dbe607 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 19a424d70..e58224cd0 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 0162f08de..efeca4ac1 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 c59acfd00..d98bd6c0c 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 0a672f578..9a0bf53ec 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 eec97355f..768ba339d 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 ee0c06f61..d59a23ca0 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 7b9c81867..1ef808825 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 81c2ae01c..d894866aa 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 f966aa2cb..7f13a6311 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 b3161af64..51953b616 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 4f52aa4de..743946de8 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 a29f79445..3dc0588b5 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 9ddb00632..9a6f616ea 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 19e996e43..062695da1 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 66a0bdb03..35660c971 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 328347b4d..fa6d228e5 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 abbb912de..70d604f5d 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 05c0920c5..d45930a71 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 c44c1e23f..c85618b9a 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; -- GitLab