diff --git a/briar-android/src/main/java/org/briarproject/briar/android/introduction/IntroductionMessageFragment.java b/briar-android/src/main/java/org/briarproject/briar/android/introduction/IntroductionMessageFragment.java index 3a76421b375e9c8f9b51ac4fa6976a923cd56582..a052e7393423b772b928f17bf217c9b2b6c50b96 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/introduction/IntroductionMessageFragment.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/introduction/IntroductionMessageFragment.java @@ -11,7 +11,6 @@ import android.widget.ProgressBar; import android.widget.TextView; import android.widget.Toast; -import org.briarproject.bramble.api.FormatException; import org.briarproject.bramble.api.contact.Contact; import org.briarproject.bramble.api.contact.ContactId; import org.briarproject.bramble.api.contact.ContactManager; @@ -35,7 +34,7 @@ import static android.app.Activity.RESULT_OK; import static android.view.View.GONE; import static android.widget.Toast.LENGTH_SHORT; import static java.util.logging.Level.WARNING; -import static org.briarproject.briar.api.introduction.IntroductionConstants.MAX_INTRODUCTION_MESSAGE_LENGTH; +import static org.briarproject.briar.api.introduction.IntroductionConstants.MAX_REQUEST_MESSAGE_LENGTH; public class IntroductionMessageFragment extends BaseFragment implements TextInputListener { @@ -175,7 +174,7 @@ public class IntroductionMessageFragment extends BaseFragment ui.message.setSendButtonEnabled(false); String msg = ui.message.getText().toString(); - msg = StringUtils.truncateUtf8(msg, MAX_INTRODUCTION_MESSAGE_LENGTH); + msg = StringUtils.truncateUtf8(msg, MAX_REQUEST_MESSAGE_LENGTH); makeIntroduction(contact1, contact2, msg); // don't wait for the introduction to be made before finishing activity @@ -190,7 +189,7 @@ public class IntroductionMessageFragment extends BaseFragment try { long timestamp = System.currentTimeMillis(); introductionManager.makeIntroduction(c1, c2, msg, timestamp); - } catch (DbException | FormatException e) { + } catch (DbException e) { if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e); introductionError(); } diff --git a/briar-api/src/main/java/org/briarproject/briar/api/introduction/IntroduceeAction.java b/briar-api/src/main/java/org/briarproject/briar/api/introduction/IntroduceeAction.java deleted file mode 100644 index 68881b9dc0d57e5993afb38e35943652141629a5..0000000000000000000000000000000000000000 --- a/briar-api/src/main/java/org/briarproject/briar/api/introduction/IntroduceeAction.java +++ /dev/null @@ -1,53 +0,0 @@ -package org.briarproject.briar.api.introduction; - -import org.briarproject.bramble.api.nullsafety.NotNullByDefault; - -import javax.annotation.Nullable; - -import static org.briarproject.briar.api.introduction.IntroductionConstants.TYPE_ABORT; -import static org.briarproject.briar.api.introduction.IntroductionConstants.TYPE_ACK; -import static org.briarproject.briar.api.introduction.IntroductionConstants.TYPE_REQUEST; -import static org.briarproject.briar.api.introduction.IntroductionConstants.TYPE_RESPONSE; - -@NotNullByDefault -public enum IntroduceeAction { - - LOCAL_ACCEPT, - LOCAL_DECLINE, - LOCAL_ABORT, - REMOTE_REQUEST, - REMOTE_ACCEPT, - REMOTE_DECLINE, - REMOTE_ABORT, - ACK; - - @Nullable - public static IntroduceeAction getRemote(int type, boolean accept) { - if (type == TYPE_REQUEST) return REMOTE_REQUEST; - if (type == TYPE_RESPONSE && accept) return REMOTE_ACCEPT; - if (type == TYPE_RESPONSE) return REMOTE_DECLINE; - if (type == TYPE_ACK) return ACK; - if (type == TYPE_ABORT) return REMOTE_ABORT; - return null; - } - - @Nullable - public static IntroduceeAction getRemote(int type) { - return getRemote(type, true); - } - - @Nullable - public static IntroduceeAction getLocal(int type, boolean accept) { - if (type == TYPE_RESPONSE && accept) return LOCAL_ACCEPT; - if (type == TYPE_RESPONSE) return LOCAL_DECLINE; - if (type == TYPE_ACK) return ACK; - if (type == TYPE_ABORT) return LOCAL_ABORT; - return null; - } - - @Nullable - public static IntroduceeAction getLocal(int type) { - return getLocal(type, true); - } - -} diff --git a/briar-api/src/main/java/org/briarproject/briar/api/introduction/IntroduceeProtocolState.java b/briar-api/src/main/java/org/briarproject/briar/api/introduction/IntroduceeProtocolState.java deleted file mode 100644 index e696181a01715261bd2d58b697ce03ff61907d67..0000000000000000000000000000000000000000 --- a/briar-api/src/main/java/org/briarproject/briar/api/introduction/IntroduceeProtocolState.java +++ /dev/null @@ -1,82 +0,0 @@ -package org.briarproject.briar.api.introduction; - -import org.briarproject.bramble.api.nullsafety.NotNullByDefault; - -import javax.annotation.concurrent.Immutable; - -import static org.briarproject.briar.api.introduction.IntroduceeAction.ACK; -import static org.briarproject.briar.api.introduction.IntroduceeAction.LOCAL_ACCEPT; -import static org.briarproject.briar.api.introduction.IntroduceeAction.LOCAL_DECLINE; -import static org.briarproject.briar.api.introduction.IntroduceeAction.REMOTE_ACCEPT; -import static org.briarproject.briar.api.introduction.IntroduceeAction.REMOTE_DECLINE; -import static org.briarproject.briar.api.introduction.IntroduceeAction.REMOTE_REQUEST; - -@Immutable -@NotNullByDefault -public enum IntroduceeProtocolState { - - ERROR(0), - AWAIT_REQUEST(1) { - @Override - public IntroduceeProtocolState next(IntroduceeAction a) { - if (a == REMOTE_REQUEST) return AWAIT_RESPONSES; - return ERROR; - } - }, - AWAIT_RESPONSES(2) { - @Override - public IntroduceeProtocolState next(IntroduceeAction a) { - if (a == REMOTE_ACCEPT) return AWAIT_LOCAL_RESPONSE; - if (a == REMOTE_DECLINE) return FINISHED; - if (a == LOCAL_ACCEPT) return AWAIT_REMOTE_RESPONSE; - if (a == LOCAL_DECLINE) return FINISHED; - return ERROR; - } - }, - AWAIT_REMOTE_RESPONSE(3) { - @Override - public IntroduceeProtocolState next(IntroduceeAction a) { - if (a == REMOTE_ACCEPT) return AWAIT_ACK; - if (a == REMOTE_DECLINE) return FINISHED; - return ERROR; - } - }, - AWAIT_LOCAL_RESPONSE(4) { - @Override - public IntroduceeProtocolState next(IntroduceeAction a) { - if (a == LOCAL_ACCEPT) return AWAIT_ACK; - if (a == LOCAL_DECLINE) return FINISHED; - return ERROR; - } - }, - AWAIT_ACK(5) { - @Override - public IntroduceeProtocolState next(IntroduceeAction a) { - if (a == ACK) return FINISHED; - return ERROR; - } - }, - FINISHED(6); - - private final int value; - - IntroduceeProtocolState(int value) { - this.value = value; - } - - public int getValue() { - return value; - } - - public static IntroduceeProtocolState fromValue(int value) { - for (IntroduceeProtocolState s : values()) { - if (s.value == value) return s; - } - throw new IllegalArgumentException(); - } - - public IntroduceeProtocolState next(IntroduceeAction a) { - return this; - } - -} diff --git a/briar-api/src/main/java/org/briarproject/briar/api/introduction/IntroducerAction.java b/briar-api/src/main/java/org/briarproject/briar/api/introduction/IntroducerAction.java deleted file mode 100644 index 7123c7eb26f8abf6f9c455307253aaaf04f59c75..0000000000000000000000000000000000000000 --- a/briar-api/src/main/java/org/briarproject/briar/api/introduction/IntroducerAction.java +++ /dev/null @@ -1,54 +0,0 @@ -package org.briarproject.briar.api.introduction; - -import org.briarproject.bramble.api.nullsafety.NotNullByDefault; - -import javax.annotation.Nullable; - -import static org.briarproject.briar.api.introduction.IntroductionConstants.TYPE_ABORT; -import static org.briarproject.briar.api.introduction.IntroductionConstants.TYPE_ACK; -import static org.briarproject.briar.api.introduction.IntroductionConstants.TYPE_REQUEST; -import static org.briarproject.briar.api.introduction.IntroductionConstants.TYPE_RESPONSE; - -@NotNullByDefault -public enum IntroducerAction { - - LOCAL_REQUEST, - LOCAL_ABORT, - REMOTE_ACCEPT_1, - REMOTE_ACCEPT_2, - REMOTE_DECLINE_1, - REMOTE_DECLINE_2, - REMOTE_ABORT, - ACK_1, - ACK_2; - - @Nullable - public static IntroducerAction getLocal(int type) { - if (type == TYPE_REQUEST) return LOCAL_REQUEST; - if (type == TYPE_ABORT) return LOCAL_ABORT; - return null; - } - - @Nullable - public static IntroducerAction getRemote(int type, boolean one, - boolean accept) { - - if (one) { - if (type == TYPE_RESPONSE && accept) return REMOTE_ACCEPT_1; - if (type == TYPE_RESPONSE) return REMOTE_DECLINE_1; - if (type == TYPE_ACK) return ACK_1; - } else { - if (type == TYPE_RESPONSE && accept) return REMOTE_ACCEPT_2; - if (type == TYPE_RESPONSE) return REMOTE_DECLINE_2; - if (type == TYPE_ACK) return ACK_2; - } - if (type == TYPE_ABORT) return REMOTE_ABORT; - return null; - } - - @Nullable - public static IntroducerAction getRemote(int type, boolean one) { - return getRemote(type, one, true); - } - -} diff --git a/briar-api/src/main/java/org/briarproject/briar/api/introduction/IntroducerProtocolState.java b/briar-api/src/main/java/org/briarproject/briar/api/introduction/IntroducerProtocolState.java deleted file mode 100644 index b3d89864e421b60853111c67e43fdbe9a2c6a6f3..0000000000000000000000000000000000000000 --- a/briar-api/src/main/java/org/briarproject/briar/api/introduction/IntroducerProtocolState.java +++ /dev/null @@ -1,108 +0,0 @@ -package org.briarproject.briar.api.introduction; - -import org.briarproject.bramble.api.nullsafety.NotNullByDefault; - -import javax.annotation.concurrent.Immutable; - -import static org.briarproject.briar.api.introduction.IntroducerAction.ACK_1; -import static org.briarproject.briar.api.introduction.IntroducerAction.ACK_2; -import static org.briarproject.briar.api.introduction.IntroducerAction.LOCAL_REQUEST; -import static org.briarproject.briar.api.introduction.IntroducerAction.REMOTE_ABORT; -import static org.briarproject.briar.api.introduction.IntroducerAction.REMOTE_ACCEPT_1; -import static org.briarproject.briar.api.introduction.IntroducerAction.REMOTE_ACCEPT_2; -import static org.briarproject.briar.api.introduction.IntroducerAction.REMOTE_DECLINE_1; -import static org.briarproject.briar.api.introduction.IntroducerAction.REMOTE_DECLINE_2; - -@Immutable -@NotNullByDefault -public enum IntroducerProtocolState { - - ERROR(0), - PREPARE_REQUESTS(1) { - @Override - public IntroducerProtocolState next(IntroducerAction a) { - if (a == LOCAL_REQUEST) return AWAIT_RESPONSES; - return ERROR; - } - }, - AWAIT_RESPONSES(2) { - @Override - public IntroducerProtocolState next(IntroducerAction a) { - if (a == REMOTE_ACCEPT_1) return AWAIT_RESPONSE_2; - if (a == REMOTE_ACCEPT_2) return AWAIT_RESPONSE_1; - if (a == REMOTE_DECLINE_1) return FINISHED; - if (a == REMOTE_DECLINE_2) return FINISHED; - return ERROR; - } - }, - AWAIT_RESPONSE_1(3) { - @Override - public IntroducerProtocolState next(IntroducerAction a) { - if (a == REMOTE_ACCEPT_1) return AWAIT_ACKS; - if (a == REMOTE_DECLINE_1) return FINISHED; - return ERROR; - } - }, - AWAIT_RESPONSE_2(4) { - @Override - public IntroducerProtocolState next(IntroducerAction a) { - if (a == REMOTE_ACCEPT_2) return AWAIT_ACKS; - if (a == REMOTE_DECLINE_2) return FINISHED; - return ERROR; - } - }, - AWAIT_ACKS(5) { - @Override - public IntroducerProtocolState next(IntroducerAction a) { - if (a == ACK_1) return AWAIT_ACK_2; - if (a == ACK_2) return AWAIT_ACK_1; - return ERROR; - } - }, - AWAIT_ACK_1(6) { - @Override - public IntroducerProtocolState next(IntroducerAction a) { - if (a == ACK_1) return FINISHED; - return ERROR; - } - }, - AWAIT_ACK_2(7) { - @Override - public IntroducerProtocolState next(IntroducerAction a) { - if (a == ACK_2) return FINISHED; - return ERROR; - } - }, - FINISHED(8) { - @Override - public IntroducerProtocolState next(IntroducerAction a) { - if (a == REMOTE_ABORT) return ERROR; - return FINISHED; - } - }; - - private final int value; - - IntroducerProtocolState(int value) { - this.value = value; - } - - public int getValue() { - return value; - } - - public static IntroducerProtocolState fromValue(int value) { - for (IntroducerProtocolState s : values()) { - if (s.value == value) return s; - } - throw new IllegalArgumentException(); - } - - public static boolean isOngoing(IntroducerProtocolState state) { - return state != FINISHED && state != ERROR; - } - - public IntroducerProtocolState next(IntroducerAction a) { - return this; - } -} diff --git a/briar-api/src/main/java/org/briarproject/briar/api/introduction/IntroductionConstants.java b/briar-api/src/main/java/org/briarproject/briar/api/introduction/IntroductionConstants.java index 72e6030b10b207a179abf99be29e7897af2777cb..9b454218d5e736f5d17546e4bbe67775e40684f1 100644 --- a/briar-api/src/main/java/org/briarproject/briar/api/introduction/IntroductionConstants.java +++ b/briar-api/src/main/java/org/briarproject/briar/api/introduction/IntroductionConstants.java @@ -4,126 +4,26 @@ import static org.briarproject.bramble.api.sync.SyncConstants.MAX_MESSAGE_BODY_L public interface IntroductionConstants { - /* Protocol roles */ - int ROLE_INTRODUCER = 0; - int ROLE_INTRODUCEE = 1; - - /* Message types */ - int TYPE_REQUEST = 1; - int TYPE_RESPONSE = 2; - int TYPE_ACK = 3; - int TYPE_ABORT = 4; - - /* Message Constants */ - String TYPE = "type"; - String GROUP_ID = "groupId"; - String SESSION_ID = "sessionId"; - String CONTACT = "contactId"; - String NAME = "name"; - String PUBLIC_KEY = "publicKey"; - String E_PUBLIC_KEY = "ephemeralPublicKey"; - String MSG = "msg"; - String ACCEPT = "accept"; - String TIME = "time"; - String TRANSPORT = "transport"; - String MESSAGE_ID = "messageId"; - String MESSAGE_TIME = "timestamp"; - String MAC = "mac"; - String SIGNATURE = "signature"; - - /* Validation Constants */ - - /** - * The length of the message authentication code in bytes. - */ - int MAC_LENGTH = 32; - /** * The maximum length of the introducer's optional message to the * introducees in UTF-8 bytes. */ - int MAX_INTRODUCTION_MESSAGE_LENGTH = MAX_MESSAGE_BODY_LENGTH - 1024; - - /* Introducer Local State Metadata */ - String STATE = "state"; - String ROLE = "role"; - String GROUP_ID_1 = "groupId1"; - String GROUP_ID_2 = "groupId2"; - String CONTACT_1 = "contact1"; - String CONTACT_2 = "contact2"; - String AUTHOR_ID_1 = "authorId1"; - String AUTHOR_ID_2 = "authorId2"; - String CONTACT_ID_1 = "contactId1"; - String CONTACT_ID_2 = "contactId2"; - String RESPONSE_1 = "response1"; - String RESPONSE_2 = "response2"; - - /* Introduction Request Action */ - String PUBLIC_KEY1 = "publicKey1"; - String PUBLIC_KEY2 = "publicKey2"; - - /* Introducee Local State Metadata (without those already defined) */ - String STORAGE_ID = "storageId"; - String INTRODUCER = "introducer"; - String LOCAL_AUTHOR_ID = "localAuthorId"; - String REMOTE_AUTHOR_ID = "remoteAuthorId"; - String OUR_PUBLIC_KEY = "ourEphemeralPublicKey"; - String OUR_PRIVATE_KEY = "ourEphemeralPrivateKey"; - String OUR_TIME = "ourTime"; - String ADDED_CONTACT_ID = "addedContactId"; - String NOT_OUR_RESPONSE = "notOurResponse"; - String EXISTS = "contactExists"; - String REMOTE_AUTHOR_IS_US = "remoteAuthorIsUs"; - String ANSWERED = "answered"; - String NONCE = "nonce"; - String MAC_KEY = "macKey"; - String OUR_TRANSPORT = "ourTransport"; - String OUR_MAC = "ourMac"; - String OUR_SIGNATURE = "ourSignature"; - - String TASK = "task"; - int TASK_ADD_CONTACT = 0; - int TASK_ACTIVATE_CONTACT = 1; - int TASK_ABORT = 2; - - /** - * Label for deriving the shared secret. - */ - String SHARED_SECRET_LABEL = - "org.briarproject.briar.introduction/SHARED_SECRET"; + int MAX_REQUEST_MESSAGE_LENGTH = MAX_MESSAGE_BODY_LENGTH - 1024; - /** - * Label for deriving Alice's key binding nonce from the shared secret. - */ - String ALICE_NONCE_LABEL = - "org.briarproject.briar.introduction/ALICE_NONCE"; + String LABEL_SESSION_ID = "org.briarproject.briar.introduction/SESSION_ID"; - /** - * Label for deriving Bob's key binding nonce from the shared secret. - */ - String BOB_NONCE_LABEL = - "org.briarproject.briar.introduction/BOB_NONCE"; + String LABEL_MASTER_KEY = "org.briarproject.briar.introduction/MASTER_KEY"; - /** - * Label for deriving Alice's MAC key from the shared secret. - */ - String ALICE_MAC_KEY_LABEL = + String LABEL_ALICE_MAC_KEY = "org.briarproject.briar.introduction/ALICE_MAC_KEY"; - /** - * Label for deriving Bob's MAC key from the shared secret. - */ - String BOB_MAC_KEY_LABEL = + String LABEL_BOB_MAC_KEY = "org.briarproject.briar.introduction/BOB_MAC_KEY"; - /** - * Label for signing the introduction response. - */ - String SIGNING_LABEL = - "org.briarproject.briar.introduction/RESPONSE_SIGNATURE"; + 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"; - /** - * Label for MACing the introduction response. - */ - String MAC_LABEL = "org.briarproject.briar.introduction/RESPONSE_MAC"; } 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 ce9d067277fabd9aed94a254f3c86f2b47ee3775..15936e8ad84f9fad746902d0ac88293a01b0495f 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 @@ -1,6 +1,5 @@ package org.briarproject.briar.api.introduction; -import org.briarproject.bramble.api.FormatException; import org.briarproject.bramble.api.contact.Contact; import org.briarproject.bramble.api.contact.ContactId; import org.briarproject.bramble.api.db.DbException; @@ -24,25 +23,25 @@ public interface IntroductionManager extends ConversationClient { /** * The current version of the introduction client. */ - int CLIENT_VERSION = 0; + int CLIENT_VERSION = 1; /** * Sends two initial introduction messages. */ void makeIntroduction(Contact c1, Contact c2, @Nullable String msg, - long timestamp) throws DbException, FormatException; + long timestamp) throws DbException; /** * Accepts an introduction. */ void acceptIntroduction(ContactId contactId, SessionId sessionId, - long timestamp) throws DbException, FormatException; + long timestamp) throws DbException; /** * Declines an introduction. */ void declineIntroduction(ContactId contactId, SessionId sessionId, - long timestamp) throws DbException, FormatException; + long timestamp) throws DbException; /** * Returns all introduction messages for the given contact. 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 861469a3a4d0c8eb6b9f34b5c6e5247db98fe995..009487fa2faf852fc5aa843db4d3aba9a09ba24f 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 @@ -8,7 +8,7 @@ import org.briarproject.briar.api.client.SessionId; import javax.annotation.concurrent.Immutable; -import static org.briarproject.briar.api.introduction.IntroductionConstants.ROLE_INTRODUCER; +import static org.briarproject.briar.api.introduction.Role.INTRODUCER; @Immutable @NotNullByDefault @@ -16,10 +16,10 @@ public class IntroductionMessage extends BaseMessageHeader { private final SessionId sessionId; private final MessageId messageId; - private final int role; + private final Role role; IntroductionMessage(SessionId sessionId, MessageId messageId, - GroupId groupId, int role, long time, boolean local, boolean sent, + GroupId groupId, Role role, long time, boolean local, boolean sent, boolean seen, boolean read) { super(messageId, groupId, time, local, sent, seen, read); @@ -37,7 +37,7 @@ public class IntroductionMessage extends BaseMessageHeader { } public boolean isIntroducer() { - return role == ROLE_INTRODUCER; + return role == INTRODUCER; } } 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 428528260c6a4f11dbd88983e78f55183f9b1614..b2a804bd88b8de918546c68e15a3327e4605180f 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 @@ -1,6 +1,5 @@ package org.briarproject.briar.api.introduction; -import org.briarproject.bramble.api.identity.AuthorId; import org.briarproject.bramble.api.nullsafety.NotNullByDefault; import org.briarproject.bramble.api.sync.GroupId; import org.briarproject.bramble.api.sync.MessageId; @@ -15,21 +14,19 @@ public class IntroductionRequest extends IntroductionResponse { @Nullable private final String message; - private final boolean answered, exists, introducesOtherIdentity; + private final boolean answered, exists; public IntroductionRequest(SessionId sessionId, MessageId messageId, - GroupId groupId, int role, long time, boolean local, boolean sent, - boolean seen, boolean read, AuthorId authorId, String name, - boolean accepted, @Nullable String message, boolean answered, - boolean exists, boolean introducesOtherIdentity) { + GroupId groupId, Role role, long time, boolean local, boolean sent, + boolean seen, boolean read, String name, boolean accepted, + @Nullable String message, boolean answered, boolean exists) { super(sessionId, messageId, groupId, role, time, local, sent, seen, - read, authorId, name, accepted); + read, name, accepted); this.message = message; this.answered = answered; this.exists = exists; - this.introducesOtherIdentity = introducesOtherIdentity; } @Nullable @@ -44,8 +41,4 @@ public class IntroductionRequest extends IntroductionResponse { public boolean contactExists() { return exists; } - - public boolean doesIntroduceOtherIdentity() { - return introducesOtherIdentity; - } } 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 22df6eba89e2e44d38fb15cdd94bd75dfacd3cb4..816135d43f59668a4ecfa4baf27e625ba2469462 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 @@ -1,6 +1,5 @@ package org.briarproject.briar.api.introduction; -import org.briarproject.bramble.api.identity.AuthorId; import org.briarproject.bramble.api.nullsafety.NotNullByDefault; import org.briarproject.bramble.api.sync.GroupId; import org.briarproject.bramble.api.sync.MessageId; @@ -12,19 +11,15 @@ import javax.annotation.concurrent.Immutable; @NotNullByDefault public class IntroductionResponse extends IntroductionMessage { - private final AuthorId remoteAuthorId; private final String name; private final boolean accepted; public IntroductionResponse(SessionId sessionId, MessageId messageId, - GroupId groupId, int role, long time, boolean local, boolean sent, - boolean seen, boolean read, AuthorId remoteAuthorId, String name, - boolean accepted) { - + GroupId groupId, Role role, long time, boolean local, boolean sent, + boolean seen, boolean read, String name, boolean accepted) { super(sessionId, messageId, groupId, role, time, local, sent, seen, read); - this.remoteAuthorId = remoteAuthorId; this.name = name; this.accepted = accepted; } @@ -37,7 +32,4 @@ public class IntroductionResponse extends IntroductionMessage { return accepted; } - public AuthorId getRemoteAuthorId() { - return remoteAuthorId; - } } diff --git a/briar-api/src/main/java/org/briarproject/briar/api/introduction2/Role.java b/briar-api/src/main/java/org/briarproject/briar/api/introduction/Role.java similarity index 91% rename from briar-api/src/main/java/org/briarproject/briar/api/introduction2/Role.java rename to briar-api/src/main/java/org/briarproject/briar/api/introduction/Role.java index bc7e4e3d907b92ca717e59519ea509c1a38222fb..38f0bd44cf85fb804fcff9f49e520474423e4a19 100644 --- a/briar-api/src/main/java/org/briarproject/briar/api/introduction2/Role.java +++ b/briar-api/src/main/java/org/briarproject/briar/api/introduction/Role.java @@ -1,4 +1,4 @@ -package org.briarproject.briar.api.introduction2; +package org.briarproject.briar.api.introduction; import org.briarproject.bramble.api.FormatException; import org.briarproject.bramble.api.nullsafety.NotNullByDefault; 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 5855275918a6001dbabf6211183d5aad40d4b9a5..113ba400efdebb484b0b41b84d70ccc64443f2b3 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 @@ -1,6 +1,5 @@ package org.briarproject.briar.api.introduction.event; -import org.briarproject.bramble.api.contact.ContactId; import org.briarproject.bramble.api.event.Event; import org.briarproject.bramble.api.nullsafety.NotNullByDefault; import org.briarproject.briar.api.client.SessionId; @@ -11,19 +10,14 @@ import javax.annotation.concurrent.Immutable; @NotNullByDefault public class IntroductionAbortedEvent extends Event { - private final ContactId contactId; private final SessionId sessionId; - public IntroductionAbortedEvent(ContactId contactId, SessionId sessionId) { - this.contactId = contactId; + public IntroductionAbortedEvent(SessionId sessionId) { this.sessionId = sessionId; } - public ContactId getContactId() { - return contactId; - } - public SessionId getSessionId() { return sessionId; } + } diff --git a/briar-api/src/main/java/org/briarproject/briar/api/introduction/event/IntroductionSucceededEvent.java b/briar-api/src/main/java/org/briarproject/briar/api/introduction/event/IntroductionSucceededEvent.java index 88998789c201b3ea1a5d4a788d3651904f91b4aa..44d166863ea1094b72358c7fb7eb4c514e347d00 100644 --- a/briar-api/src/main/java/org/briarproject/briar/api/introduction/event/IntroductionSucceededEvent.java +++ b/briar-api/src/main/java/org/briarproject/briar/api/introduction/event/IntroductionSucceededEvent.java @@ -8,6 +8,7 @@ import javax.annotation.concurrent.Immutable; @Immutable @NotNullByDefault +// TODO still needed? public class IntroductionSucceededEvent extends Event { private final Contact contact; diff --git a/briar-api/src/main/java/org/briarproject/briar/api/introduction2/IntroductionConstants.java b/briar-api/src/main/java/org/briarproject/briar/api/introduction2/IntroductionConstants.java deleted file mode 100644 index 962bd0a52b723f6089f70a74a26f7a3654321e8b..0000000000000000000000000000000000000000 --- a/briar-api/src/main/java/org/briarproject/briar/api/introduction2/IntroductionConstants.java +++ /dev/null @@ -1,29 +0,0 @@ -package org.briarproject.briar.api.introduction2; - -import static org.briarproject.bramble.api.sync.SyncConstants.MAX_MESSAGE_BODY_LENGTH; - -public interface IntroductionConstants { - - /** - * The maximum length of the introducer's optional message to the - * introducees in UTF-8 bytes. - */ - int MAX_REQUEST_MESSAGE_LENGTH = MAX_MESSAGE_BODY_LENGTH - 1024; - - 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"; - -} diff --git a/briar-api/src/main/java/org/briarproject/briar/api/introduction2/IntroductionManager.java b/briar-api/src/main/java/org/briarproject/briar/api/introduction2/IntroductionManager.java deleted file mode 100644 index f3d5c40fa4f6a03736060492e6defea4c8258e4d..0000000000000000000000000000000000000000 --- a/briar-api/src/main/java/org/briarproject/briar/api/introduction2/IntroductionManager.java +++ /dev/null @@ -1,52 +0,0 @@ -package org.briarproject.briar.api.introduction2; - -import org.briarproject.bramble.api.contact.Contact; -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.briar.api.messaging.ConversationManager.ConversationClient; - -import java.util.Collection; - -import javax.annotation.Nullable; - -@NotNullByDefault -public interface IntroductionManager extends ConversationClient { - - /** - * The unique ID of the introduction client. - */ - ClientId CLIENT_ID = new ClientId("org.briarproject.briar.introduction"); - - /** - * The current version of the introduction client. - */ - int CLIENT_VERSION = 1; - - /** - * Sends two initial introduction messages. - */ - void makeIntroduction(Contact c1, Contact c2, @Nullable String msg, - long timestamp) throws DbException; - - /** - * Accepts an introduction. - */ - void acceptIntroduction(ContactId contactId, SessionId sessionId, - long timestamp) throws DbException; - - /** - * Declines an introduction. - */ - void declineIntroduction(ContactId contactId, SessionId sessionId, - long timestamp) throws DbException; - - /** - * Returns all introduction messages for the given contact. - */ - Collection<IntroductionMessage> getIntroductionMessages(ContactId contactId) - throws DbException; - -} diff --git a/briar-api/src/main/java/org/briarproject/briar/api/introduction2/IntroductionMessage.java b/briar-api/src/main/java/org/briarproject/briar/api/introduction2/IntroductionMessage.java deleted file mode 100644 index a4b3999d1602dd109f5505f9c331ebcda5869875..0000000000000000000000000000000000000000 --- a/briar-api/src/main/java/org/briarproject/briar/api/introduction2/IntroductionMessage.java +++ /dev/null @@ -1,43 +0,0 @@ -package org.briarproject.briar.api.introduction2; - -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 javax.annotation.concurrent.Immutable; - -import static org.briarproject.briar.api.introduction2.Role.INTRODUCER; - -@Immutable -@NotNullByDefault -public class IntroductionMessage extends BaseMessageHeader { - - private final SessionId sessionId; - private final MessageId messageId; - private final Role role; - - IntroductionMessage(SessionId sessionId, MessageId messageId, - GroupId groupId, Role role, long time, boolean local, boolean sent, - boolean seen, boolean read) { - - super(messageId, groupId, time, local, sent, seen, read); - this.sessionId = sessionId; - this.messageId = messageId; - this.role = role; - } - - public SessionId getSessionId() { - return sessionId; - } - - public MessageId getMessageId() { - return messageId; - } - - public boolean isIntroducer() { - return role == INTRODUCER; - } - -} diff --git a/briar-api/src/main/java/org/briarproject/briar/api/introduction2/IntroductionRequest.java b/briar-api/src/main/java/org/briarproject/briar/api/introduction2/IntroductionRequest.java deleted file mode 100644 index 4494fa123d42a2b162a993429b5ffbebf1938323..0000000000000000000000000000000000000000 --- a/briar-api/src/main/java/org/briarproject/briar/api/introduction2/IntroductionRequest.java +++ /dev/null @@ -1,44 +0,0 @@ -package org.briarproject.briar.api.introduction2; - -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 javax.annotation.Nullable; -import javax.annotation.concurrent.Immutable; - -@Immutable -@NotNullByDefault -public class IntroductionRequest extends IntroductionResponse { - - @Nullable - private final String message; - private final boolean answered, exists; - - public IntroductionRequest(SessionId sessionId, MessageId messageId, - GroupId groupId, Role role, long time, boolean local, boolean sent, - boolean seen, boolean read, String name, boolean accepted, - @Nullable String message, boolean answered, boolean exists) { - - super(sessionId, messageId, groupId, role, time, local, sent, seen, - read, name, accepted); - - this.message = message; - this.answered = answered; - this.exists = exists; - } - - @Nullable - public String getMessage() { - return message; - } - - public boolean wasAnswered() { - return answered; - } - - public boolean contactExists() { - return exists; - } -} diff --git a/briar-api/src/main/java/org/briarproject/briar/api/introduction2/IntroductionResponse.java b/briar-api/src/main/java/org/briarproject/briar/api/introduction2/IntroductionResponse.java deleted file mode 100644 index b9d2bd99367a6b63656c42ade5bb4a3d59d01546..0000000000000000000000000000000000000000 --- a/briar-api/src/main/java/org/briarproject/briar/api/introduction2/IntroductionResponse.java +++ /dev/null @@ -1,35 +0,0 @@ -package org.briarproject.briar.api.introduction2; - -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 javax.annotation.concurrent.Immutable; - -@Immutable -@NotNullByDefault -public class IntroductionResponse extends IntroductionMessage { - - private final String name; - private final boolean accepted; - - public IntroductionResponse(SessionId sessionId, MessageId messageId, - GroupId groupId, Role role, long time, boolean local, boolean sent, - boolean seen, boolean read, String name, boolean accepted) { - super(sessionId, messageId, groupId, role, time, local, sent, seen, - read); - - this.name = name; - this.accepted = accepted; - } - - public String getName() { - return name; - } - - public boolean wasAccepted() { - return accepted; - } - -} diff --git a/briar-api/src/main/java/org/briarproject/briar/api/introduction2/event/IntroductionAbortedEvent.java b/briar-api/src/main/java/org/briarproject/briar/api/introduction2/event/IntroductionAbortedEvent.java deleted file mode 100644 index 610db397054b9c0b984ac275f2d8663ba6462283..0000000000000000000000000000000000000000 --- a/briar-api/src/main/java/org/briarproject/briar/api/introduction2/event/IntroductionAbortedEvent.java +++ /dev/null @@ -1,32 +0,0 @@ -package org.briarproject.briar.api.introduction2.event; - -import org.briarproject.bramble.api.event.Event; -import org.briarproject.bramble.api.identity.AuthorId; -import org.briarproject.bramble.api.nullsafety.NotNullByDefault; -import org.briarproject.briar.api.client.SessionId; - -import javax.annotation.concurrent.Immutable; - -@Immutable -@NotNullByDefault -// TODO still needed? -public class IntroductionAbortedEvent extends Event { - - private final AuthorId remoteAuthorId; - private final SessionId sessionId; - - public IntroductionAbortedEvent(AuthorId remoteAuthorId, - SessionId sessionId) { - this.remoteAuthorId = remoteAuthorId; - this.sessionId = sessionId; - } - - public AuthorId getRemoteAuthorId() { - return remoteAuthorId; - } - - public SessionId getSessionId() { - return sessionId; - } - -} diff --git a/briar-api/src/main/java/org/briarproject/briar/api/introduction2/event/IntroductionRequestReceivedEvent.java b/briar-api/src/main/java/org/briarproject/briar/api/introduction2/event/IntroductionRequestReceivedEvent.java deleted file mode 100644 index 0798ac356fc88ed78136448712e2607a548fe0fd..0000000000000000000000000000000000000000 --- a/briar-api/src/main/java/org/briarproject/briar/api/introduction2/event/IntroductionRequestReceivedEvent.java +++ /dev/null @@ -1,32 +0,0 @@ -package org.briarproject.briar.api.introduction2.event; - -import org.briarproject.bramble.api.contact.ContactId; -import org.briarproject.bramble.api.event.Event; -import org.briarproject.bramble.api.nullsafety.NotNullByDefault; -import org.briarproject.briar.api.introduction2.IntroductionRequest; - -import javax.annotation.concurrent.Immutable; - -@Immutable -@NotNullByDefault -public class IntroductionRequestReceivedEvent extends Event { - - private final ContactId contactId; - private final IntroductionRequest introductionRequest; - - public IntroductionRequestReceivedEvent(ContactId contactId, - IntroductionRequest introductionRequest) { - - this.contactId = contactId; - this.introductionRequest = introductionRequest; - } - - public ContactId getContactId() { - return contactId; - } - - public IntroductionRequest getIntroductionRequest() { - return introductionRequest; - } - -} diff --git a/briar-api/src/main/java/org/briarproject/briar/api/introduction2/event/IntroductionResponseReceivedEvent.java b/briar-api/src/main/java/org/briarproject/briar/api/introduction2/event/IntroductionResponseReceivedEvent.java deleted file mode 100644 index a05731b5996f620c6f7d296c6efc108408a50185..0000000000000000000000000000000000000000 --- a/briar-api/src/main/java/org/briarproject/briar/api/introduction2/event/IntroductionResponseReceivedEvent.java +++ /dev/null @@ -1,31 +0,0 @@ -package org.briarproject.briar.api.introduction2.event; - -import org.briarproject.bramble.api.contact.ContactId; -import org.briarproject.bramble.api.event.Event; -import org.briarproject.bramble.api.nullsafety.NotNullByDefault; -import org.briarproject.briar.api.introduction2.IntroductionResponse; - -import javax.annotation.concurrent.Immutable; - -@Immutable -@NotNullByDefault -public class IntroductionResponseReceivedEvent extends Event { - - private final ContactId contactId; - private final IntroductionResponse introductionResponse; - - public IntroductionResponseReceivedEvent(ContactId contactId, - IntroductionResponse introductionResponse) { - - this.contactId = contactId; - this.introductionResponse = introductionResponse; - } - - public ContactId getContactId() { - return contactId; - } - - public IntroductionResponse getIntroductionResponse() { - return introductionResponse; - } -} diff --git a/briar-api/src/main/java/org/briarproject/briar/api/introduction2/event/IntroductionSucceededEvent.java b/briar-api/src/main/java/org/briarproject/briar/api/introduction2/event/IntroductionSucceededEvent.java deleted file mode 100644 index 11f85c2ce83b114a5c83cbbb09fecc1a9b9c339f..0000000000000000000000000000000000000000 --- a/briar-api/src/main/java/org/briarproject/briar/api/introduction2/event/IntroductionSucceededEvent.java +++ /dev/null @@ -1,23 +0,0 @@ -package org.briarproject.briar.api.introduction2.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 -// TODO still needed? -public class IntroductionSucceededEvent extends Event { - - private final Contact contact; - - public IntroductionSucceededEvent(Contact contact) { - this.contact = contact; - } - - public Contact getContact() { - return contact; - } -} diff --git a/briar-core/src/main/java/org/briarproject/briar/introduction2/AbortMessage.java b/briar-core/src/main/java/org/briarproject/briar/introduction/AbortMessage.java similarity index 86% rename from briar-core/src/main/java/org/briarproject/briar/introduction2/AbortMessage.java rename to briar-core/src/main/java/org/briarproject/briar/introduction/AbortMessage.java index 9d7112407614ec456ce65647174fe272cc09f1c8..e9a2d1233489716140048f80642ca2687c3a33de 100644 --- a/briar-core/src/main/java/org/briarproject/briar/introduction2/AbortMessage.java +++ b/briar-core/src/main/java/org/briarproject/briar/introduction/AbortMessage.java @@ -1,4 +1,4 @@ -package org.briarproject.briar.introduction2; +package org.briarproject.briar.introduction; import org.briarproject.bramble.api.nullsafety.NotNullByDefault; import org.briarproject.bramble.api.sync.GroupId; @@ -10,7 +10,7 @@ import javax.annotation.concurrent.Immutable; @Immutable @NotNullByDefault -class AbortMessage extends IntroductionMessage { +class AbortMessage extends AbstractIntroductionMessage { private final SessionId sessionId; diff --git a/briar-core/src/main/java/org/briarproject/briar/introduction2/IntroductionMessage.java b/briar-core/src/main/java/org/briarproject/briar/introduction/AbstractIntroductionMessage.java similarity index 84% rename from briar-core/src/main/java/org/briarproject/briar/introduction2/IntroductionMessage.java rename to briar-core/src/main/java/org/briarproject/briar/introduction/AbstractIntroductionMessage.java index 24a252f5ef31170a37415c851dee3c2d152c435c..240b5ddecf2e7915041da47b0b7df0e0bc59a7e9 100644 --- a/briar-core/src/main/java/org/briarproject/briar/introduction2/IntroductionMessage.java +++ b/briar-core/src/main/java/org/briarproject/briar/introduction/AbstractIntroductionMessage.java @@ -1,4 +1,4 @@ -package org.briarproject.briar.introduction2; +package org.briarproject.briar.introduction; import org.briarproject.bramble.api.nullsafety.NotNullByDefault; import org.briarproject.bramble.api.sync.GroupId; @@ -9,7 +9,7 @@ import javax.annotation.concurrent.Immutable; @Immutable @NotNullByDefault -abstract class IntroductionMessage { +abstract class AbstractIntroductionMessage { private final MessageId messageId; private final GroupId groupId; @@ -17,7 +17,7 @@ abstract class IntroductionMessage { @Nullable private final MessageId previousMessageId; - IntroductionMessage(MessageId messageId, GroupId groupId, + AbstractIntroductionMessage(MessageId messageId, GroupId groupId, long timestamp, @Nullable MessageId previousMessageId) { this.messageId = messageId; this.groupId = groupId; diff --git a/briar-core/src/main/java/org/briarproject/briar/introduction2/AbstractProtocolEngine.java b/briar-core/src/main/java/org/briarproject/briar/introduction/AbstractProtocolEngine.java similarity index 90% rename from briar-core/src/main/java/org/briarproject/briar/introduction2/AbstractProtocolEngine.java rename to briar-core/src/main/java/org/briarproject/briar/introduction/AbstractProtocolEngine.java index d2c9f227098617991291ad63b2b6a81de614c523..20ac59307842b7edc02296a42fbdca5ce095c453 100644 --- a/briar-core/src/main/java/org/briarproject/briar/introduction2/AbstractProtocolEngine.java +++ b/briar-core/src/main/java/org/briarproject/briar/introduction/AbstractProtocolEngine.java @@ -1,4 +1,4 @@ -package org.briarproject.briar.introduction2; +package org.briarproject.briar.introduction; import org.briarproject.bramble.api.FormatException; import org.briarproject.bramble.api.client.ClientHelper; @@ -25,14 +25,14 @@ import java.util.Map; import javax.annotation.Nullable; import javax.annotation.concurrent.Immutable; -import static org.briarproject.briar.api.introduction2.IntroductionManager.CLIENT_ID; -import static org.briarproject.briar.api.introduction2.IntroductionManager.CLIENT_VERSION; -import static org.briarproject.briar.introduction2.MessageType.ABORT; -import static org.briarproject.briar.introduction2.MessageType.ACCEPT; -import static org.briarproject.briar.introduction2.MessageType.ACTIVATE; -import static org.briarproject.briar.introduction2.MessageType.AUTH; -import static org.briarproject.briar.introduction2.MessageType.DECLINE; -import static org.briarproject.briar.introduction2.MessageType.REQUEST; +import static org.briarproject.briar.api.introduction.IntroductionManager.CLIENT_ID; +import static org.briarproject.briar.api.introduction.IntroductionManager.CLIENT_VERSION; +import static org.briarproject.briar.introduction.MessageType.ABORT; +import static org.briarproject.briar.introduction.MessageType.ACCEPT; +import static org.briarproject.briar.introduction.MessageType.ACTIVATE; +import static org.briarproject.briar.introduction.MessageType.AUTH; +import static org.briarproject.briar.introduction.MessageType.DECLINE; +import static org.briarproject.briar.introduction.MessageType.REQUEST; @Immutable @NotNullByDefault diff --git a/briar-core/src/main/java/org/briarproject/briar/introduction2/AcceptMessage.java b/briar-core/src/main/java/org/briarproject/briar/introduction/AcceptMessage.java similarity index 93% rename from briar-core/src/main/java/org/briarproject/briar/introduction2/AcceptMessage.java rename to briar-core/src/main/java/org/briarproject/briar/introduction/AcceptMessage.java index 77d09c74ac33cf3a5d6df2a3c958a02a3e5f20bd..6cadae73b6257bbe76c67d5904a47dba286838c3 100644 --- a/briar-core/src/main/java/org/briarproject/briar/introduction2/AcceptMessage.java +++ b/briar-core/src/main/java/org/briarproject/briar/introduction/AcceptMessage.java @@ -1,4 +1,4 @@ -package org.briarproject.briar.introduction2; +package org.briarproject.briar.introduction; import org.briarproject.bramble.api.nullsafety.NotNullByDefault; import org.briarproject.bramble.api.plugin.TransportId; @@ -14,7 +14,7 @@ import javax.annotation.concurrent.Immutable; @Immutable @NotNullByDefault -class AcceptMessage extends IntroductionMessage { +class AcceptMessage extends AbstractIntroductionMessage { private final SessionId sessionId; private final byte[] ephemeralPublicKey; diff --git a/briar-core/src/main/java/org/briarproject/briar/introduction2/ActivateMessage.java b/briar-core/src/main/java/org/briarproject/briar/introduction/ActivateMessage.java similarity index 85% rename from briar-core/src/main/java/org/briarproject/briar/introduction2/ActivateMessage.java rename to briar-core/src/main/java/org/briarproject/briar/introduction/ActivateMessage.java index 0d5e935b489ff703998ceecea70c13fa07557a91..e7498dec2781c0ed36f8bebd8077ebabb47d2f5e 100644 --- a/briar-core/src/main/java/org/briarproject/briar/introduction2/ActivateMessage.java +++ b/briar-core/src/main/java/org/briarproject/briar/introduction/ActivateMessage.java @@ -1,4 +1,4 @@ -package org.briarproject.briar.introduction2; +package org.briarproject.briar.introduction; import org.briarproject.bramble.api.nullsafety.NotNullByDefault; import org.briarproject.bramble.api.sync.GroupId; @@ -9,7 +9,7 @@ import javax.annotation.concurrent.Immutable; @Immutable @NotNullByDefault -class ActivateMessage extends IntroductionMessage { +class ActivateMessage extends AbstractIntroductionMessage { private final SessionId sessionId; diff --git a/briar-core/src/main/java/org/briarproject/briar/introduction2/AuthMessage.java b/briar-core/src/main/java/org/briarproject/briar/introduction/AuthMessage.java similarity index 89% rename from briar-core/src/main/java/org/briarproject/briar/introduction2/AuthMessage.java rename to briar-core/src/main/java/org/briarproject/briar/introduction/AuthMessage.java index 5833a64d689e540fb0b53b1d37e5199055d8192e..1de1a4eb5803cbbfef2fb82c6fbc99e88ea09f5d 100644 --- a/briar-core/src/main/java/org/briarproject/briar/introduction2/AuthMessage.java +++ b/briar-core/src/main/java/org/briarproject/briar/introduction/AuthMessage.java @@ -1,4 +1,4 @@ -package org.briarproject.briar.introduction2; +package org.briarproject.briar.introduction; import org.briarproject.bramble.api.nullsafety.NotNullByDefault; import org.briarproject.bramble.api.sync.GroupId; @@ -9,7 +9,7 @@ import javax.annotation.concurrent.Immutable; @Immutable @NotNullByDefault -class AuthMessage extends IntroductionMessage { +class AuthMessage extends AbstractIntroductionMessage { private final SessionId sessionId; private final byte[] mac, signature; diff --git a/briar-core/src/main/java/org/briarproject/briar/introduction2/DeclineMessage.java b/briar-core/src/main/java/org/briarproject/briar/introduction/DeclineMessage.java similarity index 86% rename from briar-core/src/main/java/org/briarproject/briar/introduction2/DeclineMessage.java rename to briar-core/src/main/java/org/briarproject/briar/introduction/DeclineMessage.java index c419704c5c72e2e3aed1438f893a57ea372e2302..27386b90587a7297174ffbbf27e2ef82544b2444 100644 --- a/briar-core/src/main/java/org/briarproject/briar/introduction2/DeclineMessage.java +++ b/briar-core/src/main/java/org/briarproject/briar/introduction/DeclineMessage.java @@ -1,4 +1,4 @@ -package org.briarproject.briar.introduction2; +package org.briarproject.briar.introduction; import org.briarproject.bramble.api.nullsafety.NotNullByDefault; import org.briarproject.bramble.api.sync.GroupId; @@ -10,7 +10,7 @@ import javax.annotation.concurrent.Immutable; @Immutable @NotNullByDefault -class DeclineMessage extends IntroductionMessage { +class DeclineMessage extends AbstractIntroductionMessage { private final SessionId sessionId; diff --git a/briar-core/src/main/java/org/briarproject/briar/introduction/IntroduceeEngine.java b/briar-core/src/main/java/org/briarproject/briar/introduction/IntroduceeEngine.java deleted file mode 100644 index 2d5bb95c3ad591c57b5aabb0889f48c4803d93ab..0000000000000000000000000000000000000000 --- a/briar-core/src/main/java/org/briarproject/briar/introduction/IntroduceeEngine.java +++ /dev/null @@ -1,372 +0,0 @@ -package org.briarproject.briar.introduction; - -import org.briarproject.bramble.api.FormatException; -import org.briarproject.bramble.api.contact.ContactId; -import org.briarproject.bramble.api.data.BdfDictionary; -import org.briarproject.bramble.api.event.Event; -import org.briarproject.bramble.api.identity.AuthorId; -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.ProtocolEngine; -import org.briarproject.briar.api.client.SessionId; -import org.briarproject.briar.api.introduction.IntroduceeAction; -import org.briarproject.briar.api.introduction.IntroduceeProtocolState; -import org.briarproject.briar.api.introduction.IntroductionRequest; -import org.briarproject.briar.api.introduction.event.IntroductionAbortedEvent; -import org.briarproject.briar.api.introduction.event.IntroductionRequestReceivedEvent; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; -import java.util.logging.Logger; - -import javax.annotation.concurrent.Immutable; - -import static java.util.logging.Level.INFO; -import static java.util.logging.Level.WARNING; -import static org.briarproject.briar.api.introduction.IntroduceeAction.ACK; -import static org.briarproject.briar.api.introduction.IntroduceeAction.LOCAL_ABORT; -import static org.briarproject.briar.api.introduction.IntroduceeAction.LOCAL_ACCEPT; -import static org.briarproject.briar.api.introduction.IntroduceeAction.LOCAL_DECLINE; -import static org.briarproject.briar.api.introduction.IntroduceeAction.REMOTE_ABORT; -import static org.briarproject.briar.api.introduction.IntroduceeProtocolState.AWAIT_ACK; -import static org.briarproject.briar.api.introduction.IntroduceeProtocolState.AWAIT_REMOTE_RESPONSE; -import static org.briarproject.briar.api.introduction.IntroduceeProtocolState.AWAIT_REQUEST; -import static org.briarproject.briar.api.introduction.IntroduceeProtocolState.AWAIT_RESPONSES; -import static org.briarproject.briar.api.introduction.IntroduceeProtocolState.ERROR; -import static org.briarproject.briar.api.introduction.IntroduceeProtocolState.FINISHED; -import static org.briarproject.briar.api.introduction.IntroductionConstants.ACCEPT; -import static org.briarproject.briar.api.introduction.IntroductionConstants.ANSWERED; -import static org.briarproject.briar.api.introduction.IntroductionConstants.CONTACT_ID_1; -import static org.briarproject.briar.api.introduction.IntroductionConstants.EXISTS; -import static org.briarproject.briar.api.introduction.IntroductionConstants.E_PUBLIC_KEY; -import static org.briarproject.briar.api.introduction.IntroductionConstants.GROUP_ID; -import static org.briarproject.briar.api.introduction.IntroductionConstants.MAC; -import static org.briarproject.briar.api.introduction.IntroductionConstants.MESSAGE_ID; -import static org.briarproject.briar.api.introduction.IntroductionConstants.MESSAGE_TIME; -import static org.briarproject.briar.api.introduction.IntroductionConstants.MSG; -import static org.briarproject.briar.api.introduction.IntroductionConstants.NAME; -import static org.briarproject.briar.api.introduction.IntroductionConstants.NOT_OUR_RESPONSE; -import static org.briarproject.briar.api.introduction.IntroductionConstants.OUR_MAC; -import static org.briarproject.briar.api.introduction.IntroductionConstants.OUR_PUBLIC_KEY; -import static org.briarproject.briar.api.introduction.IntroductionConstants.OUR_SIGNATURE; -import static org.briarproject.briar.api.introduction.IntroductionConstants.OUR_TIME; -import static org.briarproject.briar.api.introduction.IntroductionConstants.PUBLIC_KEY; -import static org.briarproject.briar.api.introduction.IntroductionConstants.REMOTE_AUTHOR_ID; -import static org.briarproject.briar.api.introduction.IntroductionConstants.REMOTE_AUTHOR_IS_US; -import static org.briarproject.briar.api.introduction.IntroductionConstants.ROLE_INTRODUCEE; -import static org.briarproject.briar.api.introduction.IntroductionConstants.SESSION_ID; -import static org.briarproject.briar.api.introduction.IntroductionConstants.SIGNATURE; -import static org.briarproject.briar.api.introduction.IntroductionConstants.STATE; -import static org.briarproject.briar.api.introduction.IntroductionConstants.TASK; -import static org.briarproject.briar.api.introduction.IntroductionConstants.TASK_ABORT; -import static org.briarproject.briar.api.introduction.IntroductionConstants.TASK_ACTIVATE_CONTACT; -import static org.briarproject.briar.api.introduction.IntroductionConstants.TASK_ADD_CONTACT; -import static org.briarproject.briar.api.introduction.IntroductionConstants.TIME; -import static org.briarproject.briar.api.introduction.IntroductionConstants.TRANSPORT; -import static org.briarproject.briar.api.introduction.IntroductionConstants.TYPE; -import static org.briarproject.briar.api.introduction.IntroductionConstants.TYPE_ABORT; -import static org.briarproject.briar.api.introduction.IntroductionConstants.TYPE_ACK; -import static org.briarproject.briar.api.introduction.IntroductionConstants.TYPE_REQUEST; -import static org.briarproject.briar.api.introduction.IntroductionConstants.TYPE_RESPONSE; - -@Immutable -@NotNullByDefault -class IntroduceeEngine - implements ProtocolEngine<BdfDictionary, BdfDictionary, BdfDictionary> { - - private static final Logger LOG = - Logger.getLogger(IntroduceeEngine.class.getName()); - - @Override - public StateUpdate<BdfDictionary, BdfDictionary> onLocalAction( - BdfDictionary localState, BdfDictionary localAction) { - - try { - IntroduceeProtocolState currentState = - getState(localState.getLong(STATE)); - int type = localAction.getLong(TYPE).intValue(); - IntroduceeAction action; - if (localState.containsKey(ACCEPT)) action = IntroduceeAction - .getLocal(type, localState.getBoolean(ACCEPT)); - else action = IntroduceeAction.getLocal(type); - IntroduceeProtocolState nextState = currentState.next(action); - - if (action == LOCAL_ABORT && currentState != ERROR) { - return abortSession(currentState, localState); - } - - if (nextState == ERROR) { - if (LOG.isLoggable(WARNING)) { - LOG.warning("Error: Invalid action in state " + - currentState.name()); - } - if (currentState == ERROR) return noUpdate(localState); - else return abortSession(currentState, localState); - } - - List<BdfDictionary> messages = new ArrayList<>(1); - if (action == LOCAL_ACCEPT || action == LOCAL_DECLINE) { - localState.put(STATE, nextState.getValue()); - localState.put(ANSWERED, true); - // create the introduction response message - BdfDictionary msg = new BdfDictionary(); - msg.put(TYPE, TYPE_RESPONSE); - msg.put(GROUP_ID, localState.getRaw(GROUP_ID)); - msg.put(SESSION_ID, localState.getRaw(SESSION_ID)); - msg.put(ACCEPT, localState.getBoolean(ACCEPT)); - if (localState.getBoolean(ACCEPT)) { - msg.put(TIME, localState.getLong(OUR_TIME)); - msg.put(E_PUBLIC_KEY, localState.getRaw(OUR_PUBLIC_KEY)); - msg.put(TRANSPORT, localAction.getDictionary(TRANSPORT)); - } - msg.put(MESSAGE_TIME, localAction.getLong(MESSAGE_TIME)); - messages.add(msg); - logAction(currentState, localState, msg); - - if (nextState == AWAIT_ACK) { - localState.put(TASK, TASK_ADD_CONTACT); - } - } else if (action == ACK) { - // just send ACK, don't update local state again - BdfDictionary ack = getAckMessage(localState); - messages.add(ack); - } else { - throw new IllegalArgumentException(); - } - List<Event> events = Collections.emptyList(); - return new StateUpdate<>(false, false, - localState, messages, events); - } catch (FormatException e) { - throw new IllegalArgumentException(e); - } - } - - @Override - public StateUpdate<BdfDictionary, BdfDictionary> onMessageReceived( - BdfDictionary localState, BdfDictionary msg) { - - try { - IntroduceeProtocolState currentState = - getState(localState.getLong(STATE)); - int type = msg.getLong(TYPE).intValue(); - IntroduceeAction action = IntroduceeAction.getRemote(type); - IntroduceeProtocolState nextState = currentState.next(action); - - logMessageReceived(currentState, nextState, localState, type, msg); - - if (nextState == ERROR) { - if (currentState != ERROR && action != REMOTE_ABORT) { - return abortSession(currentState, localState); - } else { - return noUpdate(localState); - } - } - - // update local session state with next protocol state - localState.put(STATE, nextState.getValue()); - List<BdfDictionary> messages; - List<Event> events; - // we received the introduction request - if (currentState == AWAIT_REQUEST) { - // remember the session ID used by the introducer - localState.put(SESSION_ID, msg.getRaw(SESSION_ID)); - - addRequestData(localState, msg); - messages = Collections.emptyList(); - events = Collections.singletonList(getEvent(localState, msg)); - } - // we had the request and now one response came in _OR_ - // we had sent our response already and now received the other one - else if (currentState == AWAIT_RESPONSES || - currentState == AWAIT_REMOTE_RESPONSE) { - // update next state based on message content - action = IntroduceeAction - .getRemote(type, msg.getBoolean(ACCEPT)); - nextState = currentState.next(action); - localState.put(STATE, nextState.getValue()); - - addResponseData(localState, msg); - if (nextState == AWAIT_ACK) { - localState.put(TASK, TASK_ADD_CONTACT); - } - messages = Collections.emptyList(); - events = Collections.emptyList(); - } - // we already sent our ACK and now received the other one - else if (currentState == AWAIT_ACK) { - localState.put(TASK, TASK_ACTIVATE_CONTACT); - addAckData(localState, msg); - messages = Collections.emptyList(); - events = Collections.emptyList(); - } - // we are done (probably declined response), ignore & delete message - else if (currentState == FINISHED) { - return new StateUpdate<>(true, false, localState, - Collections.<BdfDictionary>emptyList(), - Collections.emptyList()); - } - // this should not happen - else { - throw new IllegalArgumentException(); - } - return new StateUpdate<>(false, false, - localState, messages, events); - } catch (FormatException e) { - throw new IllegalArgumentException(e); - } - } - - private void addRequestData(BdfDictionary localState, BdfDictionary msg) - throws FormatException { - - localState.put(NAME, msg.getString(NAME)); - localState.put(PUBLIC_KEY, msg.getRaw(PUBLIC_KEY)); - if (msg.containsKey(MSG)) { - localState.put(MSG, msg.getString(MSG)); - } - } - - private void addResponseData(BdfDictionary localState, BdfDictionary msg) - throws FormatException { - - if (localState.containsKey(ACCEPT)) { - localState.put(ACCEPT, - localState.getBoolean(ACCEPT) && msg.getBoolean(ACCEPT)); - } else { - localState.put(ACCEPT, msg.getBoolean(ACCEPT)); - } - localState.put(NOT_OUR_RESPONSE, msg.getRaw(MESSAGE_ID)); - - if (msg.getBoolean(ACCEPT)) { - localState.put(TIME, msg.getLong(TIME)); - localState.put(E_PUBLIC_KEY, msg.getRaw(E_PUBLIC_KEY)); - localState.put(TRANSPORT, msg.getDictionary(TRANSPORT)); - } - } - - private void addAckData(BdfDictionary localState, BdfDictionary msg) - throws FormatException { - - localState.put(MAC, msg.getRaw(MAC)); - localState.put(SIGNATURE, msg.getRaw(SIGNATURE)); - } - - private BdfDictionary getAckMessage(BdfDictionary localState) - throws FormatException { - - BdfDictionary m = new BdfDictionary(); - m.put(TYPE, TYPE_ACK); - m.put(GROUP_ID, localState.getRaw(GROUP_ID)); - m.put(SESSION_ID, localState.getRaw(SESSION_ID)); - m.put(MAC, localState.getRaw(OUR_MAC)); - m.put(SIGNATURE, localState.getRaw(OUR_SIGNATURE)); - return m; - } - - private void logAction(IntroduceeProtocolState state, - BdfDictionary localState, BdfDictionary msg) { - - if (!LOG.isLoggable(INFO)) return; - - try { - LOG.info("Sending " + - (localState.getBoolean(ACCEPT) ? "accept " : "decline ") + - "response in state " + state.name()); - LOG.info("Moving on to state " + - getState(localState.getLong(STATE)).name()); - } catch (FormatException e) { - if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e); - } - } - - private void logMessageReceived(IntroduceeProtocolState currentState, - IntroduceeProtocolState nextState, BdfDictionary localState, - int type, BdfDictionary msg) { - - if (!LOG.isLoggable(INFO)) return; - - String t = "unknown"; - if (type == TYPE_REQUEST) t = "Introduction"; - else if (type == TYPE_RESPONSE) t = "Response"; - else if (type == TYPE_ACK) t = "ACK"; - else if (type == TYPE_ABORT) t = "Abort"; - - LOG.info("Received " + t + " in state " + currentState.name()); - LOG.info("Moving on to state " + nextState.name()); - } - - @Override - public StateUpdate<BdfDictionary, BdfDictionary> onMessageDelivered( - BdfDictionary localState, BdfDictionary delivered) { - try { - return noUpdate(localState); - } catch (FormatException e) { - if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e); - return null; - } - } - - private IntroduceeProtocolState getState(Long state) { - return IntroduceeProtocolState.fromValue(state.intValue()); - } - - private Event getEvent(BdfDictionary localState, BdfDictionary msg) - throws FormatException { - - ContactId contactId = - new ContactId(localState.getLong(CONTACT_ID_1).intValue()); - AuthorId authorId = new AuthorId(localState.getRaw(REMOTE_AUTHOR_ID)); - - SessionId sessionId = new SessionId(localState.getRaw(SESSION_ID)); - MessageId messageId = new MessageId(msg.getRaw(MESSAGE_ID)); - GroupId groupId = new GroupId(msg.getRaw(GROUP_ID)); - long time = msg.getLong(MESSAGE_TIME); - String name = msg.getString(NAME); - String message = msg.getOptionalString(MSG); - boolean exists = localState.getBoolean(EXISTS); - boolean introducesOtherIdentity = - localState.getBoolean(REMOTE_AUTHOR_IS_US); - - IntroductionRequest ir = new IntroductionRequest(sessionId, messageId, - groupId, ROLE_INTRODUCEE, time, false, false, false, false, - authorId, name, false, message, false, exists, - introducesOtherIdentity); - return new IntroductionRequestReceivedEvent(contactId, ir); - } - - private StateUpdate<BdfDictionary, BdfDictionary> abortSession( - IntroduceeProtocolState currentState, BdfDictionary localState) - throws FormatException { - - if (LOG.isLoggable(WARNING)) - LOG.warning("Aborting protocol session in state " + - currentState.name()); - - localState.put(STATE, ERROR.getValue()); - localState.put(TASK, TASK_ABORT); - BdfDictionary msg = new BdfDictionary(); - msg.put(TYPE, TYPE_ABORT); - msg.put(GROUP_ID, localState.getRaw(GROUP_ID)); - msg.put(SESSION_ID, localState.getRaw(SESSION_ID)); - List<BdfDictionary> messages = Collections.singletonList(msg); - - // send abort event - ContactId contactId = - new ContactId(localState.getLong(CONTACT_ID_1).intValue()); - SessionId sessionId = new SessionId(localState.getRaw(SESSION_ID)); - Event event = new IntroductionAbortedEvent(contactId, sessionId); - List<Event> events = Collections.singletonList(event); - - return new StateUpdate<>(false, false, localState, messages, events); - } - - private StateUpdate<BdfDictionary, BdfDictionary> noUpdate( - BdfDictionary localState) throws FormatException { - - return new StateUpdate<>(false, false, localState, - Collections.<BdfDictionary>emptyList(), - Collections.emptyList()); - } -} diff --git a/briar-core/src/main/java/org/briarproject/briar/introduction/IntroduceeManager.java b/briar-core/src/main/java/org/briarproject/briar/introduction/IntroduceeManager.java deleted file mode 100644 index 4666ac92e68bdf30621f35fa33e3801c221ef23f..0000000000000000000000000000000000000000 --- a/briar-core/src/main/java/org/briarproject/briar/introduction/IntroduceeManager.java +++ /dev/null @@ -1,569 +0,0 @@ -package org.briarproject.briar.introduction; - -import org.briarproject.bramble.api.Bytes; -import org.briarproject.bramble.api.FormatException; -import org.briarproject.bramble.api.client.ClientHelper; -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.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.BdfDictionary; -import org.briarproject.bramble.api.data.BdfList; -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.event.Event; -import org.briarproject.bramble.api.identity.Author; -import org.briarproject.bramble.api.identity.AuthorFactory; -import org.briarproject.bramble.api.identity.AuthorId; -import org.briarproject.bramble.api.identity.IdentityManager; -import org.briarproject.bramble.api.identity.LocalAuthor; -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.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.briar.api.introduction.event.IntroductionSucceededEvent; - -import java.io.IOException; -import java.security.GeneralSecurityException; -import java.util.Arrays; -import java.util.HashMap; -import java.util.Map; -import java.util.logging.Logger; - -import javax.annotation.Nullable; -import javax.annotation.concurrent.Immutable; -import javax.inject.Inject; - -import static java.util.logging.Level.INFO; -import static java.util.logging.Level.WARNING; -import static org.briarproject.bramble.api.data.BdfDictionary.NULL_VALUE; -import static org.briarproject.briar.api.introduction.IntroduceeProtocolState.AWAIT_REQUEST; -import static org.briarproject.briar.api.introduction.IntroductionConstants.ACCEPT; -import static org.briarproject.briar.api.introduction.IntroductionConstants.ADDED_CONTACT_ID; -import static org.briarproject.briar.api.introduction.IntroductionConstants.ALICE_MAC_KEY_LABEL; -import static org.briarproject.briar.api.introduction.IntroductionConstants.ALICE_NONCE_LABEL; -import static org.briarproject.briar.api.introduction.IntroductionConstants.ANSWERED; -import static org.briarproject.briar.api.introduction.IntroductionConstants.BOB_MAC_KEY_LABEL; -import static org.briarproject.briar.api.introduction.IntroductionConstants.BOB_NONCE_LABEL; -import static org.briarproject.briar.api.introduction.IntroductionConstants.CONTACT; -import static org.briarproject.briar.api.introduction.IntroductionConstants.CONTACT_ID_1; -import static org.briarproject.briar.api.introduction.IntroductionConstants.EXISTS; -import static org.briarproject.briar.api.introduction.IntroductionConstants.E_PUBLIC_KEY; -import static org.briarproject.briar.api.introduction.IntroductionConstants.GROUP_ID; -import static org.briarproject.briar.api.introduction.IntroductionConstants.INTRODUCER; -import static org.briarproject.briar.api.introduction.IntroductionConstants.LOCAL_AUTHOR_ID; -import static org.briarproject.briar.api.introduction.IntroductionConstants.MAC; -import static org.briarproject.briar.api.introduction.IntroductionConstants.MAC_KEY; -import static org.briarproject.briar.api.introduction.IntroductionConstants.MAC_LABEL; -import static org.briarproject.briar.api.introduction.IntroductionConstants.MESSAGE_ID; -import static org.briarproject.briar.api.introduction.IntroductionConstants.MESSAGE_TIME; -import static org.briarproject.briar.api.introduction.IntroductionConstants.NAME; -import static org.briarproject.briar.api.introduction.IntroductionConstants.NONCE; -import static org.briarproject.briar.api.introduction.IntroductionConstants.NOT_OUR_RESPONSE; -import static org.briarproject.briar.api.introduction.IntroductionConstants.OUR_MAC; -import static org.briarproject.briar.api.introduction.IntroductionConstants.OUR_PRIVATE_KEY; -import static org.briarproject.briar.api.introduction.IntroductionConstants.OUR_PUBLIC_KEY; -import static org.briarproject.briar.api.introduction.IntroductionConstants.OUR_SIGNATURE; -import static org.briarproject.briar.api.introduction.IntroductionConstants.OUR_TIME; -import static org.briarproject.briar.api.introduction.IntroductionConstants.OUR_TRANSPORT; -import static org.briarproject.briar.api.introduction.IntroductionConstants.PUBLIC_KEY; -import static org.briarproject.briar.api.introduction.IntroductionConstants.REMOTE_AUTHOR_ID; -import static org.briarproject.briar.api.introduction.IntroductionConstants.REMOTE_AUTHOR_IS_US; -import static org.briarproject.briar.api.introduction.IntroductionConstants.ROLE; -import static org.briarproject.briar.api.introduction.IntroductionConstants.ROLE_INTRODUCEE; -import static org.briarproject.briar.api.introduction.IntroductionConstants.SHARED_SECRET_LABEL; -import static org.briarproject.briar.api.introduction.IntroductionConstants.SIGNATURE; -import static org.briarproject.briar.api.introduction.IntroductionConstants.SIGNING_LABEL; -import static org.briarproject.briar.api.introduction.IntroductionConstants.STATE; -import static org.briarproject.briar.api.introduction.IntroductionConstants.STORAGE_ID; -import static org.briarproject.briar.api.introduction.IntroductionConstants.TASK; -import static org.briarproject.briar.api.introduction.IntroductionConstants.TASK_ABORT; -import static org.briarproject.briar.api.introduction.IntroductionConstants.TASK_ACTIVATE_CONTACT; -import static org.briarproject.briar.api.introduction.IntroductionConstants.TASK_ADD_CONTACT; -import static org.briarproject.briar.api.introduction.IntroductionConstants.TIME; -import static org.briarproject.briar.api.introduction.IntroductionConstants.TRANSPORT; -import static org.briarproject.briar.api.introduction.IntroductionConstants.TYPE; -import static org.briarproject.briar.api.introduction.IntroductionConstants.TYPE_ABORT; -import static org.briarproject.briar.api.introduction.IntroductionConstants.TYPE_ACK; -import static org.briarproject.briar.api.introduction.IntroductionConstants.TYPE_RESPONSE; -import static org.briarproject.briar.api.introduction.IntroductionManager.CLIENT_VERSION; - -@Immutable -@NotNullByDefault -class IntroduceeManager { - - private static final Logger LOG = - Logger.getLogger(IntroduceeManager.class.getName()); - - private final MessageSender messageSender; - private final DatabaseComponent db; - private final ClientHelper clientHelper; - private final Clock clock; - private final CryptoComponent cryptoComponent; - private final TransportPropertyManager transportPropertyManager; - private final AuthorFactory authorFactory; - private final ContactManager contactManager; - private final IdentityManager identityManager; - private final IntroductionGroupFactory introductionGroupFactory; - - @Inject - IntroduceeManager(MessageSender messageSender, DatabaseComponent db, - ClientHelper clientHelper, Clock clock, - CryptoComponent cryptoComponent, - TransportPropertyManager transportPropertyManager, - AuthorFactory authorFactory, ContactManager contactManager, - IdentityManager identityManager, - IntroductionGroupFactory introductionGroupFactory) { - - this.messageSender = messageSender; - this.db = db; - this.clientHelper = clientHelper; - this.clock = clock; - this.cryptoComponent = cryptoComponent; - this.transportPropertyManager = transportPropertyManager; - this.authorFactory = authorFactory; - this.contactManager = contactManager; - this.identityManager = identityManager; - this.introductionGroupFactory = introductionGroupFactory; - } - - public BdfDictionary initialize(Transaction txn, GroupId groupId, - BdfDictionary message) throws DbException, FormatException { - - // create local message to keep engine state - long now = clock.currentTimeMillis(); - Bytes salt = new Bytes(new byte[64]); - cryptoComponent.getSecureRandom().nextBytes(salt.getBytes()); - - Message localMsg = clientHelper.createMessage( - introductionGroupFactory.createLocalGroup().getId(), now, - BdfList.of(salt)); - MessageId storageId = localMsg.getId(); - - // find out who is introducing us - BdfDictionary gd = - clientHelper.getGroupMetadataAsDictionary(txn, groupId); - ContactId introducerId = - new ContactId(gd.getLong(CONTACT).intValue()); - Contact introducer = db.getContact(txn, introducerId); - - BdfDictionary d = new BdfDictionary(); - d.put(STORAGE_ID, storageId); - d.put(STATE, AWAIT_REQUEST.getValue()); - d.put(ROLE, ROLE_INTRODUCEE); - d.put(GROUP_ID, groupId); - d.put(INTRODUCER, introducer.getAuthor().getName()); - d.put(CONTACT_ID_1, introducer.getId().getInt()); - d.put(LOCAL_AUTHOR_ID, introducer.getLocalAuthorId().getBytes()); - d.put(NOT_OUR_RESPONSE, storageId); - d.put(ANSWERED, false); - - // check if the contact we are introduced to does already exist - // TODO: Exchange author format version - AuthorId remoteAuthorId = authorFactory - .createAuthor(message.getString(NAME), - message.getRaw(PUBLIC_KEY)).getId(); - boolean exists = contactManager.contactExists(txn, remoteAuthorId, - introducer.getLocalAuthorId()); - d.put(EXISTS, exists); - d.put(REMOTE_AUTHOR_ID, remoteAuthorId); - - // check if someone is trying to introduce us to ourselves - if (remoteAuthorId.equals(introducer.getLocalAuthorId())) { - LOG.warning("Received Introduction Request to Ourselves"); - throw new FormatException(); - } - - // check if remote author is actually one of our other identities - boolean introducesOtherIdentity = - db.containsLocalAuthor(txn, remoteAuthorId); - d.put(REMOTE_AUTHOR_IS_US, introducesOtherIdentity); - - // save local state to database - clientHelper.addLocalMessage(txn, localMsg, d, false); - - return d; - } - - public void incomingMessage(Transaction txn, BdfDictionary state, - BdfDictionary message) throws DbException, FormatException { - - IntroduceeEngine engine = new IntroduceeEngine(); - processStateUpdate(txn, message, - engine.onMessageReceived(state, message)); - } - - void acceptIntroduction(Transaction txn, BdfDictionary state, - long timestamp) throws DbException, FormatException { - - // get data to connect and derive a shared secret later - long now = clock.currentTimeMillis(); - KeyPair keyPair = cryptoComponent.generateAgreementKeyPair(); - byte[] publicKey = keyPair.getPublic().getEncoded(); - byte[] privateKey = keyPair.getPrivate().getEncoded(); - Map<TransportId, TransportProperties> transportProperties = - transportPropertyManager.getLocalProperties(txn); - BdfDictionary tp = encodeTransportProperties(transportProperties); - - // update session state for later - state.put(ACCEPT, true); - state.put(OUR_TIME, now); - state.put(OUR_PUBLIC_KEY, publicKey); - state.put(OUR_PRIVATE_KEY, privateKey); - state.put(OUR_TRANSPORT, tp); - - // define action - BdfDictionary localAction = new BdfDictionary(); - localAction.put(TYPE, TYPE_RESPONSE); - localAction.put(TRANSPORT, tp); - localAction.put(MESSAGE_TIME, timestamp); - - // start engine and process its state update - IntroduceeEngine engine = new IntroduceeEngine(); - processStateUpdate(txn, null, engine.onLocalAction(state, localAction)); - } - - void declineIntroduction(Transaction txn, BdfDictionary state, - long timestamp) throws DbException, FormatException { - - // update session state - state.put(ACCEPT, false); - - // define action - BdfDictionary localAction = new BdfDictionary(); - localAction.put(TYPE, TYPE_RESPONSE); - localAction.put(MESSAGE_TIME, timestamp); - - // start engine and process its state update - IntroduceeEngine engine = new IntroduceeEngine(); - processStateUpdate(txn, null, - engine.onLocalAction(state, localAction)); - } - - private void processStateUpdate(Transaction txn, - @Nullable BdfDictionary msg, - IntroduceeEngine.StateUpdate<BdfDictionary, BdfDictionary> result) - throws DbException, FormatException { - - // perform actions based on new local state - BdfDictionary followUpAction = performTasks(txn, result.localState); - - // save new local state - MessageId storageId = - new MessageId(result.localState.getRaw(STORAGE_ID)); - clientHelper.mergeMessageMetadata(txn, storageId, result.localState); - - // send messages - for (BdfDictionary d : result.toSend) { - messageSender.sendMessage(txn, d); - } - - // broadcast events - for (Event event : result.toBroadcast) { - txn.attach(event); - } - - // delete message - if (result.deleteMessage && msg != null) { - MessageId messageId = new MessageId(msg.getRaw(MESSAGE_ID)); - if (LOG.isLoggable(INFO)) { - LOG.info("Deleting message with id " + messageId.hashCode()); - } - db.deleteMessage(txn, messageId); - db.deleteMessageMetadata(txn, messageId); - } - - // process follow up action at the end if available - if (followUpAction != null) { - IntroduceeEngine engine = new IntroduceeEngine(); - processStateUpdate(txn, null, - engine.onLocalAction(result.localState, followUpAction)); - } - } - - @Nullable - private BdfDictionary performTasks(Transaction txn, - BdfDictionary localState) throws FormatException, DbException { - - if (!localState.containsKey(TASK) || localState.get(TASK) == NULL_VALUE) - return null; - - // remember task and remove it from localState - long task = localState.getLong(TASK); - localState.put(TASK, NULL_VALUE); - - if (task == TASK_ADD_CONTACT) { - if (localState.getBoolean(EXISTS)) { - // we have this contact already, so do not perform actions - LOG.info("We have this contact already, do not add"); - return null; - } - - // figure out who takes which role by comparing public keys - byte[] ourPublicKeyBytes = localState.getRaw(OUR_PUBLIC_KEY); - byte[] theirPublicKeyBytes = localState.getRaw(E_PUBLIC_KEY); - int comp = Bytes.COMPARATOR.compare(new Bytes(ourPublicKeyBytes), - new Bytes(theirPublicKeyBytes)); - boolean alice = comp < 0; - - // get our local author - LocalAuthor author = identityManager.getLocalAuthor(txn); - - SecretKey secretKey; - byte[] ourPrivateKeyBytes = localState.getRaw(OUR_PRIVATE_KEY); - try { - // derive secret master key - secretKey = deriveSecretKey(ourPublicKeyBytes, - ourPrivateKeyBytes, alice, theirPublicKeyBytes); - // derive MAC keys and nonces, sign our nonce and calculate MAC - deriveMacKeysAndNonces(localState, author, secretKey, alice); - } catch (GeneralSecurityException e) { - // we can not continue without the signature - throw new DbException(e); - } - - LOG.info("Adding contact in inactive state"); - - // The agreed timestamp is the minimum of the peers' timestamps - long ourTime = localState.getLong(OUR_TIME); - long theirTime = localState.getLong(TIME); - long timestamp = Math.min(ourTime, theirTime); - - // Add the contact to the database as inactive - // TODO: Exchange author format version - Author remoteAuthor = authorFactory - .createAuthor(localState.getString(NAME), - localState.getRaw(PUBLIC_KEY)); - ContactId contactId = contactManager - .addContact(txn, remoteAuthor, author.getId(), secretKey, - timestamp, alice, false, false); - - // Update local state with ContactId, so we know what to activate - localState.put(ADDED_CONTACT_ID, contactId.getInt()); - - // let the transport manager know how to connect to the contact - Map<TransportId, TransportProperties> transportProperties = - parseTransportProperties(localState); - transportPropertyManager.addRemoteProperties(txn, contactId, - transportProperties); - - // delete the ephemeral private key by overwriting with NULL value - // this ensures future ephemeral keys can not be recovered when - // this device should gets compromised - localState.put(OUR_PRIVATE_KEY, NULL_VALUE); - - // define next action: Send ACK - BdfDictionary localAction = new BdfDictionary(); - localAction.put(TYPE, TYPE_ACK); - - // return follow up action to start engine - // and process its state update again - return localAction; - } - - // we sent and received an ACK, so activate contact - if (task == TASK_ACTIVATE_CONTACT) { - if (!localState.getBoolean(EXISTS) && - localState.containsKey(ADDED_CONTACT_ID)) { - try { - LOG.info("Verifying Signature..."); - verifySignature(localState); - LOG.info("Verifying MAC..."); - verifyMac(localState); - } catch (GeneralSecurityException e) { - throw new DbException(e); - } - - LOG.info("Activating Contact..."); - - ContactId contactId = new ContactId( - localState.getLong(ADDED_CONTACT_ID).intValue()); - - // activate and show contact in contact list - contactManager.setContactActive(txn, contactId, true); - - // broadcast event informing of successful introduction - Contact contact = db.getContact(txn, contactId); - Event event = new IntroductionSucceededEvent(contact); - txn.attach(event); - } else { - LOG.info( - "We must have had this contact already, not activating..."); - } - } - - // we need to abort the protocol, clean up what has been done - if (task == TASK_ABORT) { - if (localState.containsKey(ADDED_CONTACT_ID)) { - LOG.info("Deleting added contact due to abort..."); - ContactId contactId = new ContactId( - localState.getLong(ADDED_CONTACT_ID).intValue()); - contactManager.removeContact(txn, contactId); - } - } - return null; - } - - private SecretKey deriveSecretKey(byte[] ourPublicKeyBytes, - byte[] ourPrivateKeyBytes, boolean alice, - byte[] theirPublicKeyBytes) throws GeneralSecurityException { - // parse the local ephemeral key pair - KeyParser keyParser = cryptoComponent.getAgreementKeyParser(); - PublicKey ourPublicKey; - PrivateKey ourPrivateKey; - try { - ourPublicKey = keyParser.parsePublicKey(ourPublicKeyBytes); - ourPrivateKey = keyParser.parsePrivateKey(ourPrivateKeyBytes); - } catch (GeneralSecurityException e) { - if (LOG.isLoggable(WARNING)) { - LOG.log(WARNING, e.toString(), e); - } - throw new RuntimeException("Our own ephemeral key is invalid"); - } - KeyPair ourKeyPair = new KeyPair(ourPublicKey, ourPrivateKey); - PublicKey theirPublicKey = - keyParser.parsePublicKey(theirPublicKeyBytes); - - // The shared secret is derived from the local ephemeral key pair - // and the remote ephemeral public key - byte[][] inputs = { - new byte[] {CLIENT_VERSION}, - alice ? ourPublicKeyBytes : theirPublicKeyBytes, - alice ? theirPublicKeyBytes : ourPublicKeyBytes - }; - return cryptoComponent.deriveSharedSecret(SHARED_SECRET_LABEL, - theirPublicKey, ourKeyPair, inputs); - } - - /** - * Derives nonces, signs our nonce and calculates MAC - * <p> - * Derives two nonces and two MAC keys from the shared secret key. - * The other introducee's nonce and MAC key are added to the localState. - * <p> - * Our nonce is signed with the local author's long-term private key. - * The signature is added to the localState. - * <p> - * Calculates a MAC and stores it in the localState. - */ - private void deriveMacKeysAndNonces(BdfDictionary localState, - LocalAuthor author, SecretKey secretKey, boolean alice) - throws FormatException, GeneralSecurityException { - // Derive two nonces and two MAC keys from the shared secret key - String ourNonceLabel = alice ? ALICE_NONCE_LABEL : BOB_NONCE_LABEL; - String theirNonceLabel = alice ? BOB_NONCE_LABEL : ALICE_NONCE_LABEL; - byte[] ourNonce = cryptoComponent.mac(ourNonceLabel, secretKey); - byte[] theirNonce = cryptoComponent.mac(theirNonceLabel, secretKey); - String ourKeyLabel = alice ? ALICE_MAC_KEY_LABEL : BOB_MAC_KEY_LABEL; - String theirKeyLabel = alice ? BOB_MAC_KEY_LABEL : ALICE_MAC_KEY_LABEL; - SecretKey ourMacKey = cryptoComponent.deriveKey(ourKeyLabel, secretKey); - SecretKey theirMacKey = - cryptoComponent.deriveKey(theirKeyLabel, secretKey); - - // Save the other nonce and MAC key for the verification - localState.put(NONCE, theirNonce); - localState.put(MAC_KEY, theirMacKey.getBytes()); - - // Sign our nonce with our long-term identity public key - byte[] sig = cryptoComponent.sign(SIGNING_LABEL, ourNonce, - author.getPrivateKey()); - - // Calculate a MAC over identity public key, ephemeral public key, - // transport properties and timestamp. - byte[] publicKeyBytes = localState.getRaw(OUR_PUBLIC_KEY); - BdfDictionary tp = localState.getDictionary(OUR_TRANSPORT); - long ourTime = localState.getLong(OUR_TIME); - BdfList toMacList = BdfList.of(author.getPublicKey(), - publicKeyBytes, tp, ourTime); - byte[] toMac = clientHelper.toByteArray(toMacList); - byte[] mac = cryptoComponent.mac(MAC_LABEL, ourMacKey, toMac); - - // Add MAC and signature to localState, so it can be included in ACK - localState.put(OUR_MAC, mac); - localState.put(OUR_SIGNATURE, sig); - } - - void verifySignature(BdfDictionary localState) - throws FormatException, GeneralSecurityException { - byte[] nonce = localState.getRaw(NONCE); - byte[] sig = localState.getRaw(SIGNATURE); - byte[] key = localState.getRaw(PUBLIC_KEY); - - // Verify the signature - if (!cryptoComponent.verifySignature(sig, SIGNING_LABEL, nonce, key)) { - LOG.warning("Invalid nonce signature in ACK"); - throw new GeneralSecurityException(); - } - } - - void verifyMac(BdfDictionary localState) - throws FormatException, GeneralSecurityException { - // get MAC and MAC key from session state - byte[] mac = localState.getRaw(MAC); - byte[] macKeyBytes = localState.getRaw(MAC_KEY); - SecretKey macKey = new SecretKey(macKeyBytes); - - // get MAC data and calculate a new MAC with stored key - byte[] pubKey = localState.getRaw(PUBLIC_KEY); - byte[] ePubKey = localState.getRaw(E_PUBLIC_KEY); - BdfDictionary tp = localState.getDictionary(TRANSPORT); - long timestamp = localState.getLong(TIME); - BdfList toMacList = BdfList.of(pubKey, ePubKey, tp, timestamp); - byte[] toMac = clientHelper.toByteArray(toMacList); - byte[] calculatedMac = cryptoComponent.mac(MAC_LABEL, macKey, toMac); - if (!Arrays.equals(mac, calculatedMac)) { - LOG.warning("Received ACK with invalid MAC"); - throw new GeneralSecurityException(); - } - } - - public void abort(Transaction txn, BdfDictionary state) { - IntroduceeEngine engine = new IntroduceeEngine(); - BdfDictionary localAction = new BdfDictionary(); - localAction.put(TYPE, TYPE_ABORT); - try { - processStateUpdate(txn, null, - engine.onLocalAction(state, localAction)); - } catch (DbException | IOException e) { - if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e); - } - } - - private BdfDictionary encodeTransportProperties( - Map<TransportId, TransportProperties> map) { - - BdfDictionary d = new BdfDictionary(); - for (Map.Entry<TransportId, TransportProperties> e : map.entrySet()) { - d.put(e.getKey().getString(), e.getValue()); - } - return d; - } - - private Map<TransportId, TransportProperties> parseTransportProperties( - BdfDictionary d) throws FormatException { - - Map<TransportId, TransportProperties> tpMap = new HashMap<>(); - BdfDictionary tpMapDict = d.getDictionary(TRANSPORT); - for (String key : tpMapDict.keySet()) { - TransportId transportId = new TransportId(key); - TransportProperties transportProperties = new TransportProperties(); - BdfDictionary tpDict = tpMapDict.getDictionary(key); - for (String tkey : tpDict.keySet()) { - transportProperties.put(tkey, tpDict.getString(tkey)); - } - tpMap.put(transportId, transportProperties); - } - return tpMap; - } - -} diff --git a/briar-core/src/main/java/org/briarproject/briar/introduction2/IntroduceeProtocolEngine.java b/briar-core/src/main/java/org/briarproject/briar/introduction/IntroduceeProtocolEngine.java similarity index 89% rename from briar-core/src/main/java/org/briarproject/briar/introduction2/IntroduceeProtocolEngine.java rename to briar-core/src/main/java/org/briarproject/briar/introduction/IntroduceeProtocolEngine.java index 1efb6919bb10ed2a4759ef36565fbf61d39a29bd..e463dd39a79626f5e6588bf05a84a9f4f17c8f07 100644 --- a/briar-core/src/main/java/org/briarproject/briar/introduction2/IntroduceeProtocolEngine.java +++ b/briar-core/src/main/java/org/briarproject/briar/introduction/IntroduceeProtocolEngine.java @@ -1,4 +1,4 @@ -package org.briarproject.briar.introduction2; +package org.briarproject.briar.introduction; import org.briarproject.bramble.api.FormatException; import org.briarproject.bramble.api.client.ClientHelper; @@ -28,11 +28,12 @@ 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.briar.api.introduction2.IntroductionRequest; -import org.briarproject.briar.api.introduction2.IntroductionResponse; -import org.briarproject.briar.api.introduction2.event.IntroductionRequestReceivedEvent; -import org.briarproject.briar.api.introduction2.event.IntroductionResponseReceivedEvent; -import org.briarproject.briar.api.introduction2.event.IntroductionSucceededEvent; +import org.briarproject.briar.api.introduction.IntroductionRequest; +import org.briarproject.briar.api.introduction.IntroductionResponse; +import org.briarproject.briar.api.introduction.event.IntroductionAbortedEvent; +import org.briarproject.briar.api.introduction.event.IntroductionRequestReceivedEvent; +import org.briarproject.briar.api.introduction.event.IntroductionResponseReceivedEvent; +import org.briarproject.briar.api.introduction.event.IntroductionSucceededEvent; import java.security.GeneralSecurityException; import java.util.Map; @@ -41,11 +42,11 @@ import javax.annotation.Nullable; import javax.annotation.concurrent.Immutable; import javax.inject.Inject; -import static org.briarproject.briar.api.introduction2.Role.INTRODUCEE; -import static org.briarproject.briar.introduction2.IntroduceeState.AWAIT_AUTH; -import static org.briarproject.briar.introduction2.IntroduceeState.AWAIT_RESPONSES; -import static org.briarproject.briar.introduction2.IntroduceeState.LOCAL_ACCEPTED; -import static org.briarproject.briar.introduction2.IntroduceeState.REMOTE_ACCEPTED; +import static org.briarproject.briar.api.introduction.Role.INTRODUCEE; +import static org.briarproject.briar.introduction.IntroduceeState.AWAIT_AUTH; +import static org.briarproject.briar.introduction.IntroduceeState.AWAIT_RESPONSES; +import static org.briarproject.briar.introduction.IntroduceeState.LOCAL_ACCEPTED; +import static org.briarproject.briar.introduction.IntroduceeState.REMOTE_ACCEPTED; @Immutable @NotNullByDefault @@ -145,10 +146,11 @@ class IntroduceeProtocolEngine IntroduceeSession session, AcceptMessage m) throws DbException, FormatException { switch (session.getState()) { + case START: + return onRemoteResponseInStart(txn, session, m); case AWAIT_RESPONSES: case LOCAL_ACCEPTED: return onRemoteAccept(txn, session, m); - case START: case LOCAL_DECLINED: case REMOTE_ACCEPTED: case AWAIT_AUTH: @@ -165,7 +167,7 @@ class IntroduceeProtocolEngine throws DbException, FormatException { switch (session.getState()) { case START: - return session; // Ignore in the START state + return onRemoteResponseInStart(txn, session, m); case AWAIT_RESPONSES: case LOCAL_DECLINED: case LOCAL_ACCEPTED: @@ -322,18 +324,6 @@ class IntroduceeProtocolEngine if (isInvalidDependency(s, m.getPreviousMessageId())) return abort(txn, s); - // Broadcast IntroductionResponseReceivedEvent - Contact c = contactManager.getContact(s.getIntroducer().getId(), - identityManager.getLocalAuthor(txn).getId()); - IntroductionResponse request = - new IntroductionResponse(s.getSessionId(), m.getMessageId(), - m.getGroupId(), INTRODUCEE, m.getTimestamp(), false, - false, false, false, s.getRemoteAuthor().getName(), - true); - IntroductionResponseReceivedEvent e = - new IntroductionResponseReceivedEvent(c.getId(), request); - txn.attach(e); - // Determine next state IntroduceeState state = s.getState() == AWAIT_RESPONSES ? REMOTE_ACCEPTED : AWAIT_AUTH; @@ -356,12 +346,46 @@ class IntroduceeProtocolEngine if (isInvalidDependency(s, m.getPreviousMessageId())) return abort(txn, s); + // Mark the request visible in the UI + markMessageVisibleInUi(txn, m.getMessageId()); + + // Track the incoming message + messageTracker + .trackMessage(txn, m.getGroupId(), m.getTimestamp(), false); + + // Broadcast IntroductionResponseReceivedEvent + Contact c = contactManager.getContact(txn, s.getIntroducer().getId(), + identityManager.getLocalAuthor(txn).getId()); + IntroductionResponse request = + new IntroductionResponse(s.getSessionId(), m.getMessageId(), + m.getGroupId(), INTRODUCEE, m.getTimestamp(), false, + false, false, false, s.getRemoteAuthor().getName(), + false); + IntroductionResponseReceivedEvent e = + new IntroductionResponseReceivedEvent(c.getId(), request); + txn.attach(e); + // Move back to START state return IntroduceeSession .clear(s, s.getLastLocalMessageId(), s.getLocalTimestamp(), m.getMessageId()); } + private IntroduceeSession onRemoteResponseInStart(Transaction txn, + IntroduceeSession s, AbstractIntroductionMessage m) throws DbException { + // The timestamp must be higher than the last request message + if (m.getTimestamp() <= s.getRequestTimestamp()) + return abort(txn, s); + // The dependency, if any, must be the last remote message + if (isInvalidDependency(s, m.getPreviousMessageId())) + return abort(txn, s); + + // Stay in START state + return IntroduceeSession + .clear(s, s.getLastLocalMessageId(), s.getLocalTimestamp(), + m.getMessageId()); + } + private IntroduceeSession onLocalAuth(Transaction txn, IntroduceeSession s) throws DbException { boolean alice = isAlice(txn, s); @@ -459,6 +483,9 @@ class IntroduceeProtocolEngine if (requestId == null) throw new IllegalStateException(); markRequestUnavailableToAnswer(txn, requestId); + // Broadcast abort event for testing + txn.attach(new IntroductionAbortedEvent(s.getSessionId())); + // Reset the session back to initial state return IntroduceeSession .clear(s, s.getLastLocalMessageId(), s.getLocalTimestamp(), @@ -475,6 +502,9 @@ class IntroduceeProtocolEngine // Send an ABORT message Message sent = sendAbortMessage(txn, s, getLocalTimestamp(s)); + // Broadcast abort event for testing + txn.attach(new IntroductionAbortedEvent(s.getSessionId())); + // Reset the session back to initial state return IntroduceeSession.clear(s, sent.getId(), sent.getTimestamp(), s.getLastRemoteMessageId()); diff --git a/briar-core/src/main/java/org/briarproject/briar/introduction2/IntroduceeSession.java b/briar-core/src/main/java/org/briarproject/briar/introduction/IntroduceeSession.java similarity index 95% rename from briar-core/src/main/java/org/briarproject/briar/introduction2/IntroduceeSession.java rename to briar-core/src/main/java/org/briarproject/briar/introduction/IntroduceeSession.java index 61e3014981034076c1a8cb92573af37f1358664f..1b44452d972b1407591d6c716ff4788f805d771a 100644 --- a/briar-core/src/main/java/org/briarproject/briar/introduction2/IntroduceeSession.java +++ b/briar-core/src/main/java/org/briarproject/briar/introduction/IntroduceeSession.java @@ -1,4 +1,4 @@ -package org.briarproject.briar.introduction2; +package org.briarproject.briar.introduction; import org.briarproject.bramble.api.crypto.SecretKey; import org.briarproject.bramble.api.identity.Author; @@ -10,16 +10,16 @@ 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.briar.api.introduction2.Role; +import org.briarproject.briar.api.introduction.Role; import java.util.Map; import javax.annotation.Nullable; import javax.annotation.concurrent.Immutable; -import static org.briarproject.briar.introduction2.IntroduceeState.AWAIT_ACTIVATE; -import static org.briarproject.briar.introduction2.IntroduceeState.START; -import static org.briarproject.briar.api.introduction2.Role.INTRODUCEE; +import static org.briarproject.briar.introduction.IntroduceeState.AWAIT_ACTIVATE; +import static org.briarproject.briar.introduction.IntroduceeState.START; +import static org.briarproject.briar.api.introduction.Role.INTRODUCEE; @Immutable @NotNullByDefault diff --git a/briar-core/src/main/java/org/briarproject/briar/introduction2/IntroduceeState.java b/briar-core/src/main/java/org/briarproject/briar/introduction/IntroduceeState.java similarity index 93% rename from briar-core/src/main/java/org/briarproject/briar/introduction2/IntroduceeState.java rename to briar-core/src/main/java/org/briarproject/briar/introduction/IntroduceeState.java index 4a901752df07d53d489945ca8a4229869e7ae815..7a54abde8d0938a4201dd307013264431cc2e3ef 100644 --- a/briar-core/src/main/java/org/briarproject/briar/introduction2/IntroduceeState.java +++ b/briar-core/src/main/java/org/briarproject/briar/introduction/IntroduceeState.java @@ -1,4 +1,4 @@ -package org.briarproject.briar.introduction2; +package org.briarproject.briar.introduction; import org.briarproject.bramble.api.FormatException; import org.briarproject.bramble.api.nullsafety.NotNullByDefault; diff --git a/briar-core/src/main/java/org/briarproject/briar/introduction/IntroducerEngine.java b/briar-core/src/main/java/org/briarproject/briar/introduction/IntroducerEngine.java deleted file mode 100644 index df364b34ff0f7cdc39e4c607678ae6cdb1e64398..0000000000000000000000000000000000000000 --- a/briar-core/src/main/java/org/briarproject/briar/introduction/IntroducerEngine.java +++ /dev/null @@ -1,370 +0,0 @@ -package org.briarproject.briar.introduction; - -import org.briarproject.bramble.api.FormatException; -import org.briarproject.bramble.api.contact.ContactId; -import org.briarproject.bramble.api.data.BdfDictionary; -import org.briarproject.bramble.api.event.Event; -import org.briarproject.bramble.api.identity.AuthorId; -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.ProtocolEngine; -import org.briarproject.briar.api.client.SessionId; -import org.briarproject.briar.api.introduction.IntroducerAction; -import org.briarproject.briar.api.introduction.IntroducerProtocolState; -import org.briarproject.briar.api.introduction.IntroductionResponse; -import org.briarproject.briar.api.introduction.event.IntroductionAbortedEvent; -import org.briarproject.briar.api.introduction.event.IntroductionResponseReceivedEvent; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; -import java.util.List; -import java.util.logging.Logger; - -import javax.annotation.concurrent.Immutable; - -import static java.util.logging.Level.INFO; -import static java.util.logging.Level.WARNING; -import static org.briarproject.briar.api.introduction.IntroducerAction.LOCAL_ABORT; -import static org.briarproject.briar.api.introduction.IntroducerAction.LOCAL_REQUEST; -import static org.briarproject.briar.api.introduction.IntroducerAction.REMOTE_ACCEPT_1; -import static org.briarproject.briar.api.introduction.IntroducerAction.REMOTE_ACCEPT_2; -import static org.briarproject.briar.api.introduction.IntroducerAction.REMOTE_DECLINE_1; -import static org.briarproject.briar.api.introduction.IntroducerAction.REMOTE_DECLINE_2; -import static org.briarproject.briar.api.introduction.IntroducerProtocolState.AWAIT_ACKS; -import static org.briarproject.briar.api.introduction.IntroducerProtocolState.AWAIT_ACK_1; -import static org.briarproject.briar.api.introduction.IntroducerProtocolState.AWAIT_ACK_2; -import static org.briarproject.briar.api.introduction.IntroducerProtocolState.AWAIT_RESPONSES; -import static org.briarproject.briar.api.introduction.IntroducerProtocolState.AWAIT_RESPONSE_1; -import static org.briarproject.briar.api.introduction.IntroducerProtocolState.AWAIT_RESPONSE_2; -import static org.briarproject.briar.api.introduction.IntroducerProtocolState.ERROR; -import static org.briarproject.briar.api.introduction.IntroducerProtocolState.FINISHED; -import static org.briarproject.briar.api.introduction.IntroductionConstants.ACCEPT; -import static org.briarproject.briar.api.introduction.IntroductionConstants.AUTHOR_ID_1; -import static org.briarproject.briar.api.introduction.IntroductionConstants.AUTHOR_ID_2; -import static org.briarproject.briar.api.introduction.IntroductionConstants.CONTACT_1; -import static org.briarproject.briar.api.introduction.IntroductionConstants.CONTACT_2; -import static org.briarproject.briar.api.introduction.IntroductionConstants.CONTACT_ID_1; -import static org.briarproject.briar.api.introduction.IntroductionConstants.CONTACT_ID_2; -import static org.briarproject.briar.api.introduction.IntroductionConstants.GROUP_ID; -import static org.briarproject.briar.api.introduction.IntroductionConstants.GROUP_ID_1; -import static org.briarproject.briar.api.introduction.IntroductionConstants.GROUP_ID_2; -import static org.briarproject.briar.api.introduction.IntroductionConstants.MESSAGE_ID; -import static org.briarproject.briar.api.introduction.IntroductionConstants.MESSAGE_TIME; -import static org.briarproject.briar.api.introduction.IntroductionConstants.MSG; -import static org.briarproject.briar.api.introduction.IntroductionConstants.NAME; -import static org.briarproject.briar.api.introduction.IntroductionConstants.PUBLIC_KEY; -import static org.briarproject.briar.api.introduction.IntroductionConstants.PUBLIC_KEY1; -import static org.briarproject.briar.api.introduction.IntroductionConstants.PUBLIC_KEY2; -import static org.briarproject.briar.api.introduction.IntroductionConstants.RESPONSE_1; -import static org.briarproject.briar.api.introduction.IntroductionConstants.RESPONSE_2; -import static org.briarproject.briar.api.introduction.IntroductionConstants.ROLE_INTRODUCER; -import static org.briarproject.briar.api.introduction.IntroductionConstants.SESSION_ID; -import static org.briarproject.briar.api.introduction.IntroductionConstants.STATE; -import static org.briarproject.briar.api.introduction.IntroductionConstants.TYPE; -import static org.briarproject.briar.api.introduction.IntroductionConstants.TYPE_ABORT; -import static org.briarproject.briar.api.introduction.IntroductionConstants.TYPE_ACK; -import static org.briarproject.briar.api.introduction.IntroductionConstants.TYPE_REQUEST; -import static org.briarproject.briar.api.introduction.IntroductionConstants.TYPE_RESPONSE; - -@Immutable -@NotNullByDefault -class IntroducerEngine - implements ProtocolEngine<BdfDictionary, BdfDictionary, BdfDictionary> { - - private static final Logger LOG = - Logger.getLogger(IntroducerEngine.class.getName()); - - @Override - public StateUpdate<BdfDictionary, BdfDictionary> onLocalAction( - BdfDictionary localState, BdfDictionary localAction) { - - try { - IntroducerProtocolState currentState = - getState(localState.getLong(STATE)); - int type = localAction.getLong(TYPE).intValue(); - IntroducerAction action = IntroducerAction.getLocal(type); - IntroducerProtocolState nextState = currentState.next(action); - - if (action == LOCAL_ABORT && currentState != ERROR) { - return abortSession(currentState, localState); - } - - if (nextState == ERROR) { - if (LOG.isLoggable(WARNING)) { - LOG.warning("Error: Invalid action in state " + - currentState.name()); - } - return noUpdate(localState); - } - - localState.put(STATE, nextState.getValue()); - if (action == LOCAL_REQUEST) { - // create the introduction requests for both contacts - List<BdfDictionary> messages = new ArrayList<>(2); - BdfDictionary msg1 = new BdfDictionary(); - msg1.put(TYPE, TYPE_REQUEST); - msg1.put(SESSION_ID, localState.getRaw(SESSION_ID)); - msg1.put(GROUP_ID, localState.getRaw(GROUP_ID_1)); - msg1.put(NAME, localState.getString(CONTACT_2)); - msg1.put(PUBLIC_KEY, localAction.getRaw(PUBLIC_KEY2)); - if (localAction.containsKey(MSG)) { - msg1.put(MSG, localAction.getString(MSG)); - } - msg1.put(MESSAGE_TIME, localAction.getLong(MESSAGE_TIME)); - messages.add(msg1); - logLocalAction(currentState, localState); - BdfDictionary msg2 = new BdfDictionary(); - msg2.put(TYPE, TYPE_REQUEST); - msg2.put(SESSION_ID, localState.getRaw(SESSION_ID)); - msg2.put(GROUP_ID, localState.getRaw(GROUP_ID_2)); - msg2.put(NAME, localState.getString(CONTACT_1)); - msg2.put(PUBLIC_KEY, localAction.getRaw(PUBLIC_KEY1)); - if (localAction.containsKey(MSG)) { - msg2.put(MSG, localAction.getString(MSG)); - } - msg2.put(MESSAGE_TIME, localAction.getLong(MESSAGE_TIME)); - messages.add(msg2); - logLocalAction(currentState, localState); - - List<Event> events = Collections.emptyList(); - return new StateUpdate<>(false, false, - localState, messages, events); - } else { - throw new IllegalArgumentException("Unknown Local Action"); - } - } catch (FormatException e) { - throw new IllegalArgumentException(e); - } - } - - @Override - public StateUpdate<BdfDictionary, BdfDictionary> onMessageReceived( - BdfDictionary localState, BdfDictionary msg) { - - try { - IntroducerProtocolState currentState = - getState(localState.getLong(STATE)); - int type = msg.getLong(TYPE).intValue(); - boolean one = isContact1(localState, msg); - IntroducerAction action = IntroducerAction.getRemote(type, one); - IntroducerProtocolState nextState = currentState.next(action); - - logMessageReceived(currentState, nextState, localState, type, msg); - - if (nextState == ERROR) { - if (currentState != ERROR) { - return abortSession(currentState, localState); - } else { - return noUpdate(localState); - } - } - - List<BdfDictionary> messages; - List<Event> events; - - // we have sent our requests and just got the 1st or 2nd response - if (currentState == AWAIT_RESPONSES || - currentState == AWAIT_RESPONSE_1 || - currentState == AWAIT_RESPONSE_2) { - // update next state based on message content - action = IntroducerAction - .getRemote(type, one, msg.getBoolean(ACCEPT)); - nextState = currentState.next(action); - localState.put(STATE, nextState.getValue()); - if (one) localState.put(RESPONSE_1, msg.getRaw(MESSAGE_ID)); - else localState.put(RESPONSE_2, msg.getRaw(MESSAGE_ID)); - - messages = forwardMessage(localState, msg); - events = Collections.singletonList(getEvent(localState, msg)); - } - // we have forwarded both responses and now received the 1st or 2nd ACK - else if (currentState == AWAIT_ACKS || - currentState == AWAIT_ACK_1 || - currentState == AWAIT_ACK_2) { - localState.put(STATE, nextState.getValue()); - messages = forwardMessage(localState, msg); - events = Collections.emptyList(); - } - // we probably received a response while already being FINISHED - else if (currentState == FINISHED) { - // if it was a response store it to be found later - if (action == REMOTE_ACCEPT_1 || action == REMOTE_DECLINE_1) { - localState.put(RESPONSE_1, msg.getRaw(MESSAGE_ID)); - messages = Collections.emptyList(); - events = Collections - .singletonList(getEvent(localState, msg)); - } else if (action == REMOTE_ACCEPT_2 || - action == REMOTE_DECLINE_2) { - localState.put(RESPONSE_2, msg.getRaw(MESSAGE_ID)); - messages = Collections.emptyList(); - events = Collections - .singletonList(getEvent(localState, msg)); - } else return noUpdate(localState); - } else { - throw new IllegalArgumentException("Bad state"); - } - return new StateUpdate<>(false, false, - localState, messages, events); - } catch (FormatException e) { - throw new IllegalArgumentException(e); - } - } - - private void logLocalAction(IntroducerProtocolState state, - BdfDictionary localState) { - - if (!LOG.isLoggable(INFO)) return; - try { - LOG.info("Sending introduction request in state " + state.name()); - LOG.info("Moving on to state " + - getState(localState.getLong(STATE)).name()); - } catch (FormatException e) { - if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e); - } - } - - private void logMessageReceived(IntroducerProtocolState currentState, - IntroducerProtocolState nextState, - BdfDictionary localState, int type, BdfDictionary msg) { - - if (!LOG.isLoggable(INFO)) return; - - String t = "unknown"; - if (type == TYPE_REQUEST) t = "Introduction"; - else if (type == TYPE_RESPONSE) t = "Response"; - else if (type == TYPE_ACK) t = "ACK"; - else if (type == TYPE_ABORT) t = "Abort"; - - LOG.info("Received " + t + " in state " + currentState.name()); - LOG.info("Moving on to state " + nextState.name()); - } - - private List<BdfDictionary> forwardMessage(BdfDictionary localState, - BdfDictionary message) throws FormatException { - - // clone the message here, because we still need the original - BdfDictionary msg = (BdfDictionary) message.clone(); - if (isContact1(localState, msg)) { - msg.put(GROUP_ID, localState.getRaw(GROUP_ID_2)); - } else { - msg.put(GROUP_ID, localState.getRaw(GROUP_ID_1)); - } - - return Collections.singletonList(msg); - } - - @Override - public StateUpdate<BdfDictionary, BdfDictionary> onMessageDelivered( - BdfDictionary localState, BdfDictionary delivered) { - try { - return noUpdate(localState); - } catch (FormatException e) { - if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e); - return null; - } - } - - private IntroducerProtocolState getState(Long state) { - return IntroducerProtocolState.fromValue(state.intValue()); - } - - private Event getEvent(BdfDictionary localState, BdfDictionary msg) - throws FormatException { - - ContactId contactId = - new ContactId(localState.getLong(CONTACT_ID_1).intValue()); - AuthorId authorId = new AuthorId(localState.getRaw(AUTHOR_ID_1)); - if (Arrays - .equals(msg.getRaw(GROUP_ID), localState.getRaw(GROUP_ID_2))) { - contactId = - new ContactId(localState.getLong(CONTACT_ID_2).intValue()); - authorId = new AuthorId(localState.getRaw(AUTHOR_ID_2)); - } - - SessionId sessionId = new SessionId(localState.getRaw(SESSION_ID)); - MessageId messageId = new MessageId(msg.getRaw(MESSAGE_ID)); - GroupId groupId = new GroupId(msg.getRaw(GROUP_ID)); - long time = msg.getLong(MESSAGE_TIME); - String name = getOtherContact(localState, msg); - boolean accept = msg.getBoolean(ACCEPT); - - IntroductionResponse ir = - new IntroductionResponse(sessionId, messageId, groupId, - ROLE_INTRODUCER, time, false, false, false, false, - authorId, name, accept); - return new IntroductionResponseReceivedEvent(contactId, ir); - } - - private boolean isContact1(BdfDictionary localState, BdfDictionary msg) - throws FormatException { - - byte[] group = msg.getRaw(GROUP_ID); - byte[] group1 = localState.getRaw(GROUP_ID_1); - byte[] group2 = localState.getRaw(GROUP_ID_2); - - if (Arrays.equals(group, group1)) { - return true; - } else if (Arrays.equals(group, group2)) { - return false; - } else { - throw new FormatException(); - } - } - - private String getOtherContact(BdfDictionary localState, BdfDictionary msg) - throws FormatException { - - String to = localState.getString(CONTACT_2); - if (Arrays - .equals(msg.getRaw(GROUP_ID), localState.getRaw(GROUP_ID_2))) { - to = localState.getString(CONTACT_1); - } - return to; - } - - private StateUpdate<BdfDictionary, BdfDictionary> abortSession( - IntroducerProtocolState currentState, BdfDictionary localState) - throws FormatException { - - if (LOG.isLoggable(WARNING)) - LOG.warning("Aborting protocol session in state " + - currentState.name()); - - localState.put(STATE, ERROR.getValue()); - List<BdfDictionary> messages = new ArrayList<>(2); - BdfDictionary msg1 = new BdfDictionary(); - msg1.put(TYPE, TYPE_ABORT); - msg1.put(SESSION_ID, localState.getRaw(SESSION_ID)); - msg1.put(GROUP_ID, localState.getRaw(GROUP_ID_1)); - messages.add(msg1); - BdfDictionary msg2 = new BdfDictionary(); - msg2.put(TYPE, TYPE_ABORT); - msg2.put(SESSION_ID, localState.getRaw(SESSION_ID)); - msg2.put(GROUP_ID, localState.getRaw(GROUP_ID_2)); - messages.add(msg2); - - // send one abort event per contact - List<Event> events = new ArrayList<>(2); - SessionId sessionId = new SessionId(localState.getRaw(SESSION_ID)); - ContactId contactId1 = - new ContactId(localState.getLong(CONTACT_ID_1).intValue()); - ContactId contactId2 = - new ContactId(localState.getLong(CONTACT_ID_2).intValue()); - Event event1 = new IntroductionAbortedEvent(contactId1, sessionId); - events.add(event1); - Event event2 = new IntroductionAbortedEvent(contactId2, sessionId); - events.add(event2); - - return new StateUpdate<>(false, false, localState, messages, events); - } - - private StateUpdate<BdfDictionary, BdfDictionary> noUpdate( - BdfDictionary localState) throws FormatException { - - return new StateUpdate<>(false, false, localState, - Collections.<BdfDictionary>emptyList(), - Collections.emptyList()); - } -} diff --git a/briar-core/src/main/java/org/briarproject/briar/introduction/IntroducerManager.java b/briar-core/src/main/java/org/briarproject/briar/introduction/IntroducerManager.java deleted file mode 100644 index b24109396c7f634c8668ff9aea64dca16750cca8..0000000000000000000000000000000000000000 --- a/briar-core/src/main/java/org/briarproject/briar/introduction/IntroducerManager.java +++ /dev/null @@ -1,181 +0,0 @@ -package org.briarproject.briar.introduction; - -import org.briarproject.bramble.api.Bytes; -import org.briarproject.bramble.api.FormatException; -import org.briarproject.bramble.api.client.ClientHelper; -import org.briarproject.bramble.api.contact.Contact; -import org.briarproject.bramble.api.crypto.CryptoComponent; -import org.briarproject.bramble.api.data.BdfDictionary; -import org.briarproject.bramble.api.data.BdfList; -import org.briarproject.bramble.api.db.DbException; -import org.briarproject.bramble.api.db.Transaction; -import org.briarproject.bramble.api.event.Event; -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 org.briarproject.bramble.util.StringUtils; - -import java.io.IOException; -import java.util.logging.Logger; - -import javax.annotation.Nullable; -import javax.annotation.concurrent.Immutable; -import javax.inject.Inject; - -import static java.util.logging.Level.WARNING; -import static org.briarproject.briar.api.introduction.IntroducerProtocolState.PREPARE_REQUESTS; -import static org.briarproject.briar.api.introduction.IntroductionConstants.AUTHOR_ID_1; -import static org.briarproject.briar.api.introduction.IntroductionConstants.AUTHOR_ID_2; -import static org.briarproject.briar.api.introduction.IntroductionConstants.CONTACT_1; -import static org.briarproject.briar.api.introduction.IntroductionConstants.CONTACT_2; -import static org.briarproject.briar.api.introduction.IntroductionConstants.CONTACT_ID_1; -import static org.briarproject.briar.api.introduction.IntroductionConstants.CONTACT_ID_2; -import static org.briarproject.briar.api.introduction.IntroductionConstants.GROUP_ID_1; -import static org.briarproject.briar.api.introduction.IntroductionConstants.GROUP_ID_2; -import static org.briarproject.briar.api.introduction.IntroductionConstants.MAX_INTRODUCTION_MESSAGE_LENGTH; -import static org.briarproject.briar.api.introduction.IntroductionConstants.MESSAGE_TIME; -import static org.briarproject.briar.api.introduction.IntroductionConstants.MSG; -import static org.briarproject.briar.api.introduction.IntroductionConstants.PUBLIC_KEY1; -import static org.briarproject.briar.api.introduction.IntroductionConstants.PUBLIC_KEY2; -import static org.briarproject.briar.api.introduction.IntroductionConstants.ROLE; -import static org.briarproject.briar.api.introduction.IntroductionConstants.ROLE_INTRODUCER; -import static org.briarproject.briar.api.introduction.IntroductionConstants.SESSION_ID; -import static org.briarproject.briar.api.introduction.IntroductionConstants.STATE; -import static org.briarproject.briar.api.introduction.IntroductionConstants.STORAGE_ID; -import static org.briarproject.briar.api.introduction.IntroductionConstants.TYPE; -import static org.briarproject.briar.api.introduction.IntroductionConstants.TYPE_ABORT; -import static org.briarproject.briar.api.introduction.IntroductionConstants.TYPE_REQUEST; - -@Immutable -@NotNullByDefault -class IntroducerManager { - - private static final Logger LOG = - Logger.getLogger(IntroducerManager.class.getName()); - - private final MessageSender messageSender; - private final ClientHelper clientHelper; - private final Clock clock; - private final CryptoComponent cryptoComponent; - private final IntroductionGroupFactory introductionGroupFactory; - - @Inject - IntroducerManager(MessageSender messageSender, ClientHelper clientHelper, - Clock clock, CryptoComponent cryptoComponent, - IntroductionGroupFactory introductionGroupFactory) { - - this.messageSender = messageSender; - this.clientHelper = clientHelper; - this.clock = clock; - this.cryptoComponent = cryptoComponent; - this.introductionGroupFactory = introductionGroupFactory; - } - - public BdfDictionary initialize(Transaction txn, Contact c1, Contact c2) - throws FormatException, DbException { - - // create local message to keep engine state - long now = clock.currentTimeMillis(); - Bytes salt = new Bytes(new byte[64]); - cryptoComponent.getSecureRandom().nextBytes(salt.getBytes()); - - Message m = clientHelper.createMessage( - introductionGroupFactory.createLocalGroup().getId(), now, - BdfList.of(salt)); - MessageId sessionId = m.getId(); - - Group g1 = introductionGroupFactory.createIntroductionGroup(c1); - Group g2 = introductionGroupFactory.createIntroductionGroup(c2); - - BdfDictionary d = new BdfDictionary(); - d.put(SESSION_ID, sessionId); - d.put(STORAGE_ID, sessionId); - d.put(STATE, PREPARE_REQUESTS.getValue()); - d.put(ROLE, ROLE_INTRODUCER); - d.put(GROUP_ID_1, g1.getId()); - d.put(GROUP_ID_2, g2.getId()); - d.put(CONTACT_1, c1.getAuthor().getName()); - d.put(CONTACT_2, c2.getAuthor().getName()); - d.put(CONTACT_ID_1, c1.getId().getInt()); - d.put(CONTACT_ID_2, c2.getId().getInt()); - d.put(AUTHOR_ID_1, c1.getAuthor().getId()); - d.put(AUTHOR_ID_2, c2.getAuthor().getId()); - - // save local state to database - clientHelper.addLocalMessage(txn, m, d, false); - - return d; - } - - void makeIntroduction(Transaction txn, Contact c1, Contact c2, - @Nullable String msg, long timestamp) - throws DbException, FormatException { - - // TODO check for existing session with those contacts? - // deny new introduction under which conditions? - - // initialize engine state - BdfDictionary localState = initialize(txn, c1, c2); - - // define action - BdfDictionary localAction = new BdfDictionary(); - localAction.put(TYPE, TYPE_REQUEST); - if (!StringUtils.isNullOrEmpty(msg)) { - int msgLength = StringUtils.toUtf8(msg).length; - if (msgLength > MAX_INTRODUCTION_MESSAGE_LENGTH) - throw new IllegalArgumentException(); - localAction.put(MSG, msg); - } - localAction.put(PUBLIC_KEY1, c1.getAuthor().getPublicKey()); - localAction.put(PUBLIC_KEY2, c2.getAuthor().getPublicKey()); - localAction.put(MESSAGE_TIME, timestamp); - - // start engine and process its state update - IntroducerEngine engine = new IntroducerEngine(); - processStateUpdate(txn, - engine.onLocalAction(localState, localAction)); - } - - public void incomingMessage(Transaction txn, BdfDictionary state, - BdfDictionary message) throws DbException, FormatException { - - IntroducerEngine engine = new IntroducerEngine(); - processStateUpdate(txn, - engine.onMessageReceived(state, message)); - } - - private void processStateUpdate(Transaction txn, - IntroducerEngine.StateUpdate<BdfDictionary, BdfDictionary> - result) throws DbException, FormatException { - - // save new local state - MessageId storageId = - new MessageId(result.localState.getRaw(STORAGE_ID)); - clientHelper.mergeMessageMetadata(txn, storageId, result.localState); - - // send messages - for (BdfDictionary d : result.toSend) { - messageSender.sendMessage(txn, d); - } - - // broadcast events - for (Event event : result.toBroadcast) { - txn.attach(event); - } - } - - public void abort(Transaction txn, BdfDictionary state) { - IntroducerEngine engine = new IntroducerEngine(); - BdfDictionary localAction = new BdfDictionary(); - localAction.put(TYPE, TYPE_ABORT); - try { - processStateUpdate(txn, - engine.onLocalAction(state, localAction)); - } catch (DbException | IOException e) { - if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e); - } - } - -} diff --git a/briar-core/src/main/java/org/briarproject/briar/introduction2/IntroducerProtocolEngine.java b/briar-core/src/main/java/org/briarproject/briar/introduction/IntroducerProtocolEngine.java similarity index 78% rename from briar-core/src/main/java/org/briarproject/briar/introduction2/IntroducerProtocolEngine.java rename to briar-core/src/main/java/org/briarproject/briar/introduction/IntroducerProtocolEngine.java index a65f18301a0a31c072f793ccace5de91f9e81645..044b7ccd2cfd46927b951f44d8254dfeb71eab00 100644 --- a/briar-core/src/main/java/org/briarproject/briar/introduction2/IntroducerProtocolEngine.java +++ b/briar-core/src/main/java/org/briarproject/briar/introduction/IntroducerProtocolEngine.java @@ -1,4 +1,4 @@ -package org.briarproject.briar.introduction2; +package org.briarproject.briar.introduction; import org.briarproject.bramble.api.FormatException; import org.briarproject.bramble.api.client.ClientHelper; @@ -9,6 +9,7 @@ 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.AuthorId; import org.briarproject.bramble.api.identity.IdentityManager; import org.briarproject.bramble.api.nullsafety.NotNullByDefault; import org.briarproject.bramble.api.sync.GroupId; @@ -17,9 +18,10 @@ 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.briar.api.introduction2.IntroductionResponse; -import org.briarproject.briar.api.introduction2.event.IntroductionResponseReceivedEvent; -import org.briarproject.briar.introduction2.IntroducerSession.Introducee; +import org.briarproject.briar.api.introduction.IntroductionResponse; +import org.briarproject.briar.api.introduction.event.IntroductionAbortedEvent; +import org.briarproject.briar.api.introduction.event.IntroductionResponseReceivedEvent; +import org.briarproject.briar.introduction.IntroducerSession.Introducee; import java.util.Map; @@ -27,17 +29,17 @@ import javax.annotation.Nullable; import javax.annotation.concurrent.Immutable; import javax.inject.Inject; -import static org.briarproject.briar.api.introduction2.Role.INTRODUCER; -import static org.briarproject.briar.introduction2.IntroducerState.AWAIT_ACTIVATES; -import static org.briarproject.briar.introduction2.IntroducerState.AWAIT_ACTIVATE_A; -import static org.briarproject.briar.introduction2.IntroducerState.AWAIT_ACTIVATE_B; -import static org.briarproject.briar.introduction2.IntroducerState.AWAIT_AUTHS; -import static org.briarproject.briar.introduction2.IntroducerState.AWAIT_AUTH_A; -import static org.briarproject.briar.introduction2.IntroducerState.AWAIT_AUTH_B; -import static org.briarproject.briar.introduction2.IntroducerState.AWAIT_RESPONSES; -import static org.briarproject.briar.introduction2.IntroducerState.AWAIT_RESPONSE_A; -import static org.briarproject.briar.introduction2.IntroducerState.AWAIT_RESPONSE_B; -import static org.briarproject.briar.introduction2.IntroducerState.START; +import static org.briarproject.briar.api.introduction.Role.INTRODUCER; +import static org.briarproject.briar.introduction.IntroducerState.AWAIT_ACTIVATES; +import static org.briarproject.briar.introduction.IntroducerState.AWAIT_ACTIVATE_A; +import static org.briarproject.briar.introduction.IntroducerState.AWAIT_ACTIVATE_B; +import static org.briarproject.briar.introduction.IntroducerState.AWAIT_AUTHS; +import static org.briarproject.briar.introduction.IntroducerState.AWAIT_AUTH_A; +import static org.briarproject.briar.introduction.IntroducerState.AWAIT_AUTH_B; +import static org.briarproject.briar.introduction.IntroducerState.AWAIT_RESPONSES; +import static org.briarproject.briar.introduction.IntroducerState.AWAIT_RESPONSE_A; +import static org.briarproject.briar.introduction.IntroducerState.AWAIT_RESPONSE_B; +import static org.briarproject.briar.introduction.IntroducerState.START; @Immutable @NotNullByDefault @@ -94,6 +96,11 @@ class IntroducerProtocolEngine throw new UnsupportedOperationException(); // Invalid in this role } + IntroducerSession onAbortAction(Transaction txn, IntroducerSession s) + throws DbException, FormatException { + return abort(txn, s); + } + @Override public IntroducerSession onRequestMessage(Transaction txn, IntroducerSession s, RequestMessage m) @@ -111,8 +118,7 @@ class IntroducerProtocolEngine case AWAIT_RESPONSE_B: return onRemoteAccept(txn, s, m); case START: - // TODO check and update lastRemoteMsgId? - return s; // Ignored in this state + return onRemoteResponseInStart(txn, s, m); case AWAIT_AUTHS: case AWAIT_AUTH_A: case AWAIT_AUTH_B: @@ -135,8 +141,7 @@ class IntroducerProtocolEngine case AWAIT_RESPONSE_B: return onRemoteDecline(txn, s, m); case START: - // TODO check and update lastRemoteMsgId? - return s; // Ignored in this state + return onRemoteResponseInStart(txn, s, m); case AWAIT_AUTHS: case AWAIT_AUTH_A: case AWAIT_AUTH_B: @@ -253,14 +258,16 @@ class IntroducerProtocolEngine if (s.getState() == AWAIT_RESPONSES) state = AWAIT_RESPONSE_A; introducee1 = new Introducee(s.getIntroducee1(), sent); introducee2 = new Introducee(s.getIntroducee2(), m.getMessageId()); - c = contactManager.getContact(s.getIntroducee2().author.getId(), - identityManager.getLocalAuthor(txn).getId()); + c = contactManager + .getContact(txn, s.getIntroducee2().author.getId(), + identityManager.getLocalAuthor(txn).getId()); } else if (i.equals(s.getIntroducee2())) { if (s.getState() == AWAIT_RESPONSES) state = AWAIT_RESPONSE_B; introducee1 = new Introducee(s.getIntroducee1(), m.getMessageId()); introducee2 = new Introducee(s.getIntroducee2(), sent); - c = contactManager.getContact(s.getIntroducee1().author.getId(), - identityManager.getLocalAuthor(txn).getId()); + c = contactManager + .getContact(txn, s.getIntroducee1().author.getId(), + identityManager.getLocalAuthor(txn).getId()); } else throw new AssertionError(); // Broadcast IntroductionResponseReceivedEvent @@ -296,22 +303,23 @@ class IntroducerProtocolEngine Introducee i = getOtherIntroducee(s, m.getGroupId()); long timestamp = getLocalTimestamp(s, i); Message sent = sendDeclineMessage(txn, i, timestamp, false); - // Track the message - messageTracker.trackOutgoingMessage(txn, sent); // Move to the START state Introducee introducee1, introducee2; + AuthorId localAuthorId =identityManager.getLocalAuthor(txn).getId(); Contact c; if (i.equals(s.getIntroducee1())) { introducee1 = new Introducee(s.getIntroducee1(), sent); introducee2 = new Introducee(s.getIntroducee2(), m.getMessageId()); - c = contactManager.getContact(s.getIntroducee2().author.getId(), - identityManager.getLocalAuthor(txn).getId()); + c = contactManager + .getContact(txn, s.getIntroducee2().author.getId(), + localAuthorId); } else if (i.equals(s.getIntroducee2())) { introducee1 = new Introducee(s.getIntroducee1(), m.getMessageId()); introducee2 = new Introducee(s.getIntroducee2(), sent); - c = contactManager.getContact(s.getIntroducee2().author.getId(), - identityManager.getLocalAuthor(txn).getId()); + c = contactManager + .getContact(txn, s.getIntroducee1().author.getId(), + localAuthorId); } else throw new AssertionError(); // Broadcast IntroductionResponseReceivedEvent @@ -327,6 +335,54 @@ class IntroducerProtocolEngine s.getRequestTimestamp(), introducee1, introducee2); } + private IntroducerSession onRemoteResponseInStart(Transaction txn, + IntroducerSession s, AbstractIntroductionMessage m) + throws DbException, FormatException { + // The timestamp must be higher than the last request message + if (m.getTimestamp() <= s.getRequestTimestamp()) + return abort(txn, s); + // The dependency, if any, must be the last remote message + if (isInvalidDependency(s, m.getGroupId(), m.getPreviousMessageId())) + return abort(txn, s); + + // Mark the response visible in the UI + markMessageVisibleInUi(txn, m.getMessageId()); + // Track the incoming message + messageTracker + .trackMessage(txn, m.getGroupId(), m.getTimestamp(), false); + + Introducee i = getIntroducee(s, m.getGroupId()); + Introducee introducee1, introducee2; + AuthorId localAuthorId = identityManager.getLocalAuthor(txn).getId(); + Contact c; + if (i.equals(s.getIntroducee1())) { + introducee1 = new Introducee(s.getIntroducee1(), m.getMessageId()); + introducee2 = s.getIntroducee2(); + c = contactManager + .getContact(txn, s.getIntroducee1().author.getId(), + localAuthorId); + } else if (i.equals(s.getIntroducee2())) { + introducee1 = s.getIntroducee1(); + introducee2 = new Introducee(s.getIntroducee2(), m.getMessageId()); + c = contactManager + .getContact(txn, s.getIntroducee2().author.getId(), + localAuthorId); + } else throw new AssertionError(); + + // Broadcast IntroductionResponseReceivedEvent + IntroductionResponse request = + new IntroductionResponse(s.getSessionId(), m.getMessageId(), + m.getGroupId(), INTRODUCER, m.getTimestamp(), false, + false, false, false, c.getAuthor().getName(), + m instanceof AcceptMessage); + IntroductionResponseReceivedEvent e = + new IntroductionResponseReceivedEvent(c.getId(), request); + txn.attach(e); + + return new IntroducerSession(s.getSessionId(), START, + s.getRequestTimestamp(), introducee1, introducee2); + } + private IntroducerSession onRemoteAuth(Transaction txn, IntroducerSession s, AuthMessage m) throws DbException, FormatException { @@ -395,6 +451,9 @@ class IntroducerProtocolEngine long timestamp = getLocalTimestamp(s, i); Message sent = sendAbortMessage(txn, i, timestamp); + // Broadcast abort event for testing + txn.attach(new IntroductionAbortedEvent(s.getSessionId())); + // Reset the session back to initial state Introducee introducee1, introducee2; if (i.equals(s.getIntroducee1())) { @@ -412,6 +471,10 @@ class IntroducerProtocolEngine IntroducerSession s) throws DbException, FormatException { // Mark any REQUEST messages in the session unavailable to answer markRequestsUnavailableToAnswer(txn, s); + + // Broadcast abort event for testing + txn.attach(new IntroductionAbortedEvent(s.getSessionId())); + // Send an ABORT message to both introducees long timestamp1 = getLocalTimestamp(s, s.getIntroducee1()); Message sent1 = sendAbortMessage(txn, s.getIntroducee1(), timestamp1); diff --git a/briar-core/src/main/java/org/briarproject/briar/introduction2/IntroducerSession.java b/briar-core/src/main/java/org/briarproject/briar/introduction/IntroducerSession.java similarity index 94% rename from briar-core/src/main/java/org/briarproject/briar/introduction2/IntroducerSession.java rename to briar-core/src/main/java/org/briarproject/briar/introduction/IntroducerSession.java index cbfc53923e47f22b4000f46c273b6a1fb4e88f36..906947969224f19ab084dfc52bec5f52da333e22 100644 --- a/briar-core/src/main/java/org/briarproject/briar/introduction2/IntroducerSession.java +++ b/briar-core/src/main/java/org/briarproject/briar/introduction/IntroducerSession.java @@ -1,4 +1,4 @@ -package org.briarproject.briar.introduction2; +package org.briarproject.briar.introduction; import org.briarproject.bramble.api.identity.Author; import org.briarproject.bramble.api.nullsafety.NotNullByDefault; @@ -6,12 +6,12 @@ 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.briar.api.introduction2.Role; +import org.briarproject.briar.api.introduction.Role; import javax.annotation.Nullable; import javax.annotation.concurrent.Immutable; -import static org.briarproject.briar.api.introduction2.Role.INTRODUCER; +import static org.briarproject.briar.api.introduction.Role.INTRODUCER; @Immutable @NotNullByDefault diff --git a/briar-core/src/main/java/org/briarproject/briar/introduction2/IntroducerState.java b/briar-core/src/main/java/org/briarproject/briar/introduction/IntroducerState.java similarity index 94% rename from briar-core/src/main/java/org/briarproject/briar/introduction2/IntroducerState.java rename to briar-core/src/main/java/org/briarproject/briar/introduction/IntroducerState.java index 43e51d96af8e2b77abb57d92951f07f0cc2247f3..99c3fbf86c755ed80104ab6e2748a187342ccec5 100644 --- a/briar-core/src/main/java/org/briarproject/briar/introduction2/IntroducerState.java +++ b/briar-core/src/main/java/org/briarproject/briar/introduction/IntroducerState.java @@ -1,4 +1,4 @@ -package org.briarproject.briar.introduction2; +package org.briarproject.briar.introduction; import org.briarproject.bramble.api.FormatException; import org.briarproject.bramble.api.nullsafety.NotNullByDefault; diff --git a/briar-core/src/main/java/org/briarproject/briar/introduction2/IntroductionConstants.java b/briar-core/src/main/java/org/briarproject/briar/introduction/IntroductionConstants.java similarity index 97% rename from briar-core/src/main/java/org/briarproject/briar/introduction2/IntroductionConstants.java rename to briar-core/src/main/java/org/briarproject/briar/introduction/IntroductionConstants.java index 634c0fff1ea320eeb97a49ba89709263813dc059..bda50f47b98250fe247285cfb5303050a34514fe 100644 --- a/briar-core/src/main/java/org/briarproject/briar/introduction2/IntroductionConstants.java +++ b/briar-core/src/main/java/org/briarproject/briar/introduction/IntroductionConstants.java @@ -1,4 +1,4 @@ -package org.briarproject.briar.introduction2; +package org.briarproject.briar.introduction; interface IntroductionConstants { diff --git a/briar-core/src/main/java/org/briarproject/briar/introduction2/IntroductionCrypto.java b/briar-core/src/main/java/org/briarproject/briar/introduction/IntroductionCrypto.java similarity index 98% rename from briar-core/src/main/java/org/briarproject/briar/introduction2/IntroductionCrypto.java rename to briar-core/src/main/java/org/briarproject/briar/introduction/IntroductionCrypto.java index a91184db2a60c1f032272a3c99125f40ce43f4d0..a563e3c753de524bb6da390ea4a1446fa7868df6 100644 --- a/briar-core/src/main/java/org/briarproject/briar/introduction2/IntroductionCrypto.java +++ b/briar-core/src/main/java/org/briarproject/briar/introduction/IntroductionCrypto.java @@ -1,4 +1,4 @@ -package org.briarproject.briar.introduction2; +package org.briarproject.briar.introduction; import org.briarproject.bramble.api.FormatException; import org.briarproject.bramble.api.crypto.KeyPair; diff --git a/briar-core/src/main/java/org/briarproject/briar/introduction2/IntroductionCryptoImpl.java b/briar-core/src/main/java/org/briarproject/briar/introduction/IntroductionCryptoImpl.java similarity index 89% rename from briar-core/src/main/java/org/briarproject/briar/introduction2/IntroductionCryptoImpl.java rename to briar-core/src/main/java/org/briarproject/briar/introduction/IntroductionCryptoImpl.java index 93ff9b33e30b5fddc06dec4c24421bf555f7a085..9bf4e46c2be23ad933f874777359811317e85269 100644 --- a/briar-core/src/main/java/org/briarproject/briar/introduction2/IntroductionCryptoImpl.java +++ b/briar-core/src/main/java/org/briarproject/briar/introduction/IntroductionCryptoImpl.java @@ -1,4 +1,4 @@ -package org.briarproject.briar.introduction2; +package org.briarproject.briar.introduction; import org.briarproject.bramble.api.Bytes; import org.briarproject.bramble.api.FormatException; @@ -24,14 +24,14 @@ import java.util.Map; import javax.annotation.concurrent.Immutable; import javax.inject.Inject; -import static org.briarproject.briar.api.introduction2.IntroductionConstants.LABEL_ALICE_MAC_KEY; -import static org.briarproject.briar.api.introduction2.IntroductionConstants.LABEL_AUTH_MAC; -import static org.briarproject.briar.api.introduction2.IntroductionConstants.LABEL_AUTH_NONCE; -import static org.briarproject.briar.api.introduction2.IntroductionConstants.LABEL_AUTH_SIGN; -import static org.briarproject.briar.api.introduction2.IntroductionConstants.LABEL_BOB_MAC_KEY; -import static org.briarproject.briar.api.introduction2.IntroductionConstants.LABEL_MASTER_KEY; -import static org.briarproject.briar.api.introduction2.IntroductionConstants.LABEL_SESSION_ID; -import static org.briarproject.briar.api.introduction2.IntroductionManager.CLIENT_VERSION; +import static org.briarproject.briar.api.introduction.IntroductionConstants.LABEL_ALICE_MAC_KEY; +import static org.briarproject.briar.api.introduction.IntroductionConstants.LABEL_AUTH_MAC; +import static org.briarproject.briar.api.introduction.IntroductionConstants.LABEL_AUTH_NONCE; +import static org.briarproject.briar.api.introduction.IntroductionConstants.LABEL_AUTH_SIGN; +import static org.briarproject.briar.api.introduction.IntroductionConstants.LABEL_BOB_MAC_KEY; +import static org.briarproject.briar.api.introduction.IntroductionConstants.LABEL_MASTER_KEY; +import static org.briarproject.briar.api.introduction.IntroductionConstants.LABEL_SESSION_ID; +import static org.briarproject.briar.api.introduction.IntroductionManager.CLIENT_VERSION; @Immutable @NotNullByDefault diff --git a/briar-core/src/main/java/org/briarproject/briar/introduction/IntroductionGroupFactory.java b/briar-core/src/main/java/org/briarproject/briar/introduction/IntroductionGroupFactory.java deleted file mode 100644 index 050d2b9f4430bcf38f950ea6c3dd941d0ac44cd2..0000000000000000000000000000000000000000 --- a/briar-core/src/main/java/org/briarproject/briar/introduction/IntroductionGroupFactory.java +++ /dev/null @@ -1,33 +0,0 @@ -package org.briarproject.briar.introduction; - -import org.briarproject.bramble.api.client.ContactGroupFactory; -import org.briarproject.bramble.api.contact.Contact; -import org.briarproject.bramble.api.sync.Group; - -import javax.inject.Inject; - -import static org.briarproject.briar.api.introduction.IntroductionManager.CLIENT_ID; -import static org.briarproject.briar.api.introduction.IntroductionManager.CLIENT_VERSION; - -class IntroductionGroupFactory { - - private final ContactGroupFactory contactGroupFactory; - private final Group localGroup; - - @Inject - IntroductionGroupFactory(ContactGroupFactory contactGroupFactory) { - this.contactGroupFactory = contactGroupFactory; - localGroup = contactGroupFactory.createLocalGroup(CLIENT_ID, - CLIENT_VERSION); - } - - Group createIntroductionGroup(Contact c) { - return contactGroupFactory.createContactGroup(CLIENT_ID, - CLIENT_VERSION, c); - } - - Group createLocalGroup() { - return localGroup; - } - -} 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 9ccf06b6796fdf869500d8e7233042950c9a84ec..7b7f9cd9b32b0571365ee53a5126ee4e85e8ae94 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 @@ -2,19 +2,20 @@ package org.briarproject.briar.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.ContactId; import org.briarproject.bramble.api.contact.ContactManager.ContactHook; import org.briarproject.bramble.api.data.BdfDictionary; -import org.briarproject.bramble.api.data.BdfEntry; 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.NoSuchContactException; -import org.briarproject.bramble.api.db.NoSuchMessageException; +import org.briarproject.bramble.api.db.Metadata; import org.briarproject.bramble.api.db.Transaction; -import org.briarproject.bramble.api.identity.AuthorId; +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.nullsafety.NotNullByDefault; import org.briarproject.bramble.api.sync.Client; import org.briarproject.bramble.api.sync.Group; @@ -24,264 +25,278 @@ import org.briarproject.bramble.api.sync.MessageId; import org.briarproject.bramble.api.sync.MessageStatus; import org.briarproject.briar.api.client.MessageTracker; import org.briarproject.briar.api.client.SessionId; -import org.briarproject.briar.api.introduction.IntroducerProtocolState; import org.briarproject.briar.api.introduction.IntroductionManager; import org.briarproject.briar.api.introduction.IntroductionMessage; import org.briarproject.briar.api.introduction.IntroductionRequest; import org.briarproject.briar.api.introduction.IntroductionResponse; +import org.briarproject.briar.api.introduction.Role; import org.briarproject.briar.client.ConversationClientImpl; +import org.briarproject.briar.introduction.IntroducerSession.Introducee; import java.util.ArrayList; -import java.util.Arrays; import java.util.Collection; +import java.util.List; import java.util.Map; -import java.util.logging.Logger; import javax.annotation.Nullable; import javax.annotation.concurrent.Immutable; import javax.inject.Inject; -import static java.util.logging.Level.WARNING; import static org.briarproject.bramble.api.sync.Group.Visibility.SHARED; -import static org.briarproject.briar.api.introduction.IntroduceeProtocolState.FINISHED; -import static org.briarproject.briar.api.introduction.IntroductionConstants.ACCEPT; -import static org.briarproject.briar.api.introduction.IntroductionConstants.ANSWERED; -import static org.briarproject.briar.api.introduction.IntroductionConstants.AUTHOR_ID_1; -import static org.briarproject.briar.api.introduction.IntroductionConstants.AUTHOR_ID_2; -import static org.briarproject.briar.api.introduction.IntroductionConstants.CONTACT; -import static org.briarproject.briar.api.introduction.IntroductionConstants.CONTACT_1; -import static org.briarproject.briar.api.introduction.IntroductionConstants.CONTACT_2; -import static org.briarproject.briar.api.introduction.IntroductionConstants.CONTACT_ID_1; -import static org.briarproject.briar.api.introduction.IntroductionConstants.CONTACT_ID_2; -import static org.briarproject.briar.api.introduction.IntroductionConstants.EXISTS; -import static org.briarproject.briar.api.introduction.IntroductionConstants.GROUP_ID; -import static org.briarproject.briar.api.introduction.IntroductionConstants.GROUP_ID_1; -import static org.briarproject.briar.api.introduction.IntroductionConstants.GROUP_ID_2; -import static org.briarproject.briar.api.introduction.IntroductionConstants.MESSAGE_TIME; -import static org.briarproject.briar.api.introduction.IntroductionConstants.MSG; -import static org.briarproject.briar.api.introduction.IntroductionConstants.NAME; -import static org.briarproject.briar.api.introduction.IntroductionConstants.NOT_OUR_RESPONSE; -import static org.briarproject.briar.api.introduction.IntroductionConstants.REMOTE_AUTHOR_ID; -import static org.briarproject.briar.api.introduction.IntroductionConstants.REMOTE_AUTHOR_IS_US; -import static org.briarproject.briar.api.introduction.IntroductionConstants.RESPONSE_1; -import static org.briarproject.briar.api.introduction.IntroductionConstants.RESPONSE_2; -import static org.briarproject.briar.api.introduction.IntroductionConstants.ROLE; -import static org.briarproject.briar.api.introduction.IntroductionConstants.ROLE_INTRODUCEE; -import static org.briarproject.briar.api.introduction.IntroductionConstants.ROLE_INTRODUCER; -import static org.briarproject.briar.api.introduction.IntroductionConstants.SESSION_ID; -import static org.briarproject.briar.api.introduction.IntroductionConstants.STATE; -import static org.briarproject.briar.api.introduction.IntroductionConstants.TYPE; -import static org.briarproject.briar.api.introduction.IntroductionConstants.TYPE_ABORT; -import static org.briarproject.briar.api.introduction.IntroductionConstants.TYPE_ACK; -import static org.briarproject.briar.api.introduction.IntroductionConstants.TYPE_REQUEST; -import static org.briarproject.briar.api.introduction.IntroductionConstants.TYPE_RESPONSE; -import static org.briarproject.briar.client.MessageTrackerConstants.MSG_KEY_READ; +import static org.briarproject.briar.api.introduction.Role.INTRODUCEE; +import static org.briarproject.briar.api.introduction.Role.INTRODUCER; +import static org.briarproject.briar.introduction.IntroductionConstants.GROUP_KEY_CONTACT_ID; +import static org.briarproject.briar.introduction.MessageType.ABORT; +import static org.briarproject.briar.introduction.MessageType.ACCEPT; +import static org.briarproject.briar.introduction.MessageType.ACTIVATE; +import static org.briarproject.briar.introduction.MessageType.AUTH; +import static org.briarproject.briar.introduction.MessageType.DECLINE; +import static org.briarproject.briar.introduction.MessageType.REQUEST; @Immutable @NotNullByDefault class IntroductionManagerImpl extends ConversationClientImpl implements IntroductionManager, Client, ContactHook { - private static final Logger LOG = - Logger.getLogger(IntroductionManagerImpl.class.getName()); - - private final IntroducerManager introducerManager; - private final IntroduceeManager introduceeManager; - private final IntroductionGroupFactory introductionGroupFactory; + private final ContactGroupFactory contactGroupFactory; + private final MessageParser messageParser; + private final SessionEncoder sessionEncoder; + private final SessionParser sessionParser; + private final IntroducerProtocolEngine introducerEngine; + private final IntroduceeProtocolEngine introduceeEngine; + private final IntroductionCrypto crypto; + private final IdentityManager identityManager; @Inject - IntroductionManagerImpl(DatabaseComponent db, ClientHelper clientHelper, - MetadataParser metadataParser, MessageTracker messageTracker, - IntroducerManager introducerManager, - IntroduceeManager introduceeManager, - IntroductionGroupFactory introductionGroupFactory) { - + IntroductionManagerImpl( + DatabaseComponent db, + ClientHelper clientHelper, + MetadataParser metadataParser, + MessageTracker messageTracker, + ContactGroupFactory contactGroupFactory, + MessageParser messageParser, + SessionEncoder sessionEncoder, + SessionParser sessionParser, + IntroducerProtocolEngine introducerEngine, + IntroduceeProtocolEngine introduceeEngine, + IntroductionCrypto crypto, + IdentityManager identityManager) { super(db, clientHelper, metadataParser, messageTracker); - this.introducerManager = introducerManager; - this.introduceeManager = introduceeManager; - this.introductionGroupFactory = introductionGroupFactory; + this.contactGroupFactory = contactGroupFactory; + this.messageParser = messageParser; + this.sessionEncoder = sessionEncoder; + this.sessionParser = sessionParser; + this.introducerEngine = introducerEngine; + this.introduceeEngine = introduceeEngine; + this.crypto = crypto; + this.identityManager = identityManager; } @Override public void createLocalState(Transaction txn) throws DbException { - Group localGroup = introductionGroupFactory.createLocalGroup(); + // Create a local group to store protocol sessions + Group localGroup = getLocalGroup(); if (db.containsGroup(txn, localGroup.getId())) return; db.addGroup(txn, localGroup); - // Ensure we've set things up for any pre-existing contacts + // Set up groups for communication with any pre-existing contacts for (Contact c : db.getContacts(txn)) addingContact(txn, c); } @Override + // TODO adapt to use upcoming ClientVersioning client public void addingContact(Transaction txn, Contact c) throws DbException { + // Create a group to share with the contact + Group g = getContactGroup(c); + // Return if we've already set things up for this contact + if (db.containsGroup(txn, g.getId())) return; + // Store the group and share it with the contact + db.addGroup(txn, g); + db.setGroupVisibility(txn, c.getId(), g.getId(), SHARED); + // Attach the contact ID to the group + BdfDictionary meta = new BdfDictionary(); + meta.put(GROUP_KEY_CONTACT_ID, c.getId().getInt()); try { - // Create an introduction group for sending introduction messages - Group g = getContactGroup(c); - // Return if we've already set things up for this contact - if (db.containsGroup(txn, g.getId())) return; - // Store the group and share it with the contact - db.addGroup(txn, g); - db.setGroupVisibility(txn, c.getId(), g.getId(), SHARED); - // Attach the contact ID to the group - BdfDictionary gm = new BdfDictionary(); - gm.put(CONTACT, c.getId().getInt()); - clientHelper.mergeGroupMetadata(txn, g.getId(), gm); + clientHelper.mergeGroupMetadata(txn, g.getId(), meta); } catch (FormatException e) { - throw new RuntimeException(e); + throw new AssertionError(e); } } @Override public void removingContact(Transaction txn, Contact c) throws DbException { - GroupId gId = introductionGroupFactory.createLocalGroup().getId(); - - // search for session states where c introduced us - BdfDictionary query = BdfDictionary.of( - new BdfEntry(ROLE, ROLE_INTRODUCEE), - new BdfEntry(CONTACT_ID_1, c.getId().getInt()) - ); - try { - Map<MessageId, BdfDictionary> map = clientHelper - .getMessageMetadataAsDictionary(txn, gId, query); - for (Map.Entry<MessageId, BdfDictionary> entry : map.entrySet()) { - // delete states if introducee removes introducer - deleteMessage(txn, entry.getKey()); - } - } catch (FormatException e) { - if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e); - } - - // check for open sessions with c and abort those, - // so the other introducee knows - query = BdfDictionary.of( - new BdfEntry(ROLE, ROLE_INTRODUCER) - ); try { - Map<MessageId, BdfDictionary> map = clientHelper - .getMessageMetadataAsDictionary(txn, gId, query); - for (Map.Entry<MessageId, BdfDictionary> entry : map.entrySet()) { - BdfDictionary d = entry.getValue(); - ContactId c1 = new ContactId(d.getLong(CONTACT_ID_1).intValue()); - ContactId c2 = new ContactId(d.getLong(CONTACT_ID_2).intValue()); - - if (c1.equals(c.getId()) || c2.equals(c.getId())) { - IntroducerProtocolState state = IntroducerProtocolState - .fromValue(d.getLong(STATE).intValue()); - // abort protocol if still ongoing - if (IntroducerProtocolState.isOngoing(state)) { - introducerManager.abort(txn, d); - } - // also delete state if both contacts have been deleted - if (c1.equals(c.getId())) { - try { - db.getContact(txn, c2); - } catch (NoSuchContactException e) { - deleteMessage(txn, entry.getKey()); - } - } else if (c2.equals(c.getId())) { - try { - db.getContact(txn, c1); - } catch (NoSuchContactException e) { - deleteMessage(txn, entry.getKey()); - } - } - } - } + removeSessionWithIntroducer(txn, c); + abortOrRemoveSessionWithIntroducee(txn, c); } catch (FormatException e) { - if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e); + throw new AssertionError(); } - - // remove the group (all messages will be removed with it) - // this contact won't get our abort message, but the other will + // Remove the contact group (all messages will be removed with it) db.removeGroup(txn, getContactGroup(c)); } - /** - * This is called when a new message arrived and is being validated. - * It is the central method where we determine which role we play - * in the introduction protocol and which engine we need to start. - */ + @Override + public Group getContactGroup(Contact c) { + return contactGroupFactory + .createContactGroup(CLIENT_ID, CLIENT_VERSION, c); + } + @Override protected boolean incomingMessage(Transaction txn, Message m, BdfList body, - BdfDictionary message) throws DbException, FormatException { - - // Get message data and type - GroupId groupId = m.getGroupId(); - long type = message.getLong(TYPE, -1L); - - // we are an introducee, need to initialize new state - if (type == TYPE_REQUEST) { - boolean stateExists = true; - try { - getSessionState(txn, groupId, message.getRaw(SESSION_ID), false); - } catch (FormatException e) { - stateExists = false; - } - if (stateExists) throw new FormatException(); - BdfDictionary state = - introduceeManager.initialize(txn, groupId, message); - try { - introduceeManager.incomingMessage(txn, state, message); - messageTracker.trackIncomingMessage(txn, m); - } catch (DbException e) { - if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e); - introduceeManager.abort(txn, state); - } catch (FormatException e) { - // FIXME necessary? - if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e); - introduceeManager.abort(txn, state); - } + BdfDictionary bdfMeta) throws DbException, FormatException { + // Parse the metadata + MessageMetadata meta = messageParser.parseMetadata(bdfMeta); + // Look up the session, if there is one + SessionId sessionId = meta.getSessionId(); + IntroduceeSession newIntroduceeSession = null; + if (sessionId == null) { + if (meta.getMessageType() != REQUEST) throw new AssertionError(); + newIntroduceeSession = createNewIntroduceeSession(txn, m, body); + sessionId = newIntroduceeSession.getSessionId(); } - // our role can be anything - else if (type == TYPE_RESPONSE || type == TYPE_ACK || type == TYPE_ABORT) { - BdfDictionary state = - getSessionState(txn, groupId, message.getRaw(SESSION_ID)); - - long role = state.getLong(ROLE, -1L); - try { - if (role == ROLE_INTRODUCER) { - introducerManager.incomingMessage(txn, state, message); - if (type == TYPE_RESPONSE) - messageTracker.trackIncomingMessage(txn, m); - } else if (role == ROLE_INTRODUCEE) { - introduceeManager.incomingMessage(txn, state, message); - if (type == TYPE_RESPONSE && !message.getBoolean(ACCEPT)) - messageTracker.trackIncomingMessage(txn, m); - } else { - if (LOG.isLoggable(WARNING)) - LOG.warning("Unknown role '" + role + "'"); - throw new DbException(); - } - } catch (DbException | FormatException e) { - if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e); - if (role == ROLE_INTRODUCER) introducerManager.abort(txn, state); - else introduceeManager.abort(txn, state); - } + StoredSession ss = getSession(txn, sessionId); + // Handle the message + Session session; + MessageId storageId; + if (ss == null) { + if (meta.getMessageType() != REQUEST) throw new FormatException(); + if (newIntroduceeSession == null) throw new AssertionError(); + storageId = createStorageId(txn); + session = handleMessage(txn, m, body, meta.getMessageType(), + newIntroduceeSession, introduceeEngine); } else { - // the message has been validated, so this should not happen - if(LOG.isLoggable(WARNING)) { - LOG.warning("Unknown message type '" + type + "', deleting..."); - } + storageId = ss.storageId; + Role role = sessionParser.getRole(ss.bdfSession); + if (role == INTRODUCER) { + session = handleMessage(txn, m, body, meta.getMessageType(), + sessionParser.parseIntroducerSession(ss.bdfSession), + introducerEngine); + } else if (role == INTRODUCEE) { + session = handleMessage(txn, m, body, meta.getMessageType(), + sessionParser.parseIntroduceeSession(m.getGroupId(), + ss.bdfSession), introduceeEngine); + } else throw new AssertionError(); } + // Store the updated session + storeSession(txn, storageId, session); return false; } - @Override - public Group getContactGroup(Contact contact) { - return introductionGroupFactory.createIntroductionGroup(contact); + private IntroduceeSession createNewIntroduceeSession(Transaction txn, + Message m, BdfList body) throws DbException, FormatException { + ContactId introducerId = getContactId(txn, m.getGroupId()); + Author introducer = db.getContact(txn, introducerId).getAuthor(); + Author alice = identityManager.getLocalAuthor(txn); + Author bob = messageParser.parseRequestMessage(m, body).getAuthor(); + if (alice.equals(bob)) throw new FormatException(); + SessionId sessionId = crypto.getSessionId(introducer, alice, bob); + return IntroduceeSession + .getInitial(m.getGroupId(), sessionId, introducer, bob); + } + + private <S extends Session> S handleMessage(Transaction txn, Message m, + BdfList body, MessageType type, S session, ProtocolEngine<S> engine) + throws DbException, FormatException { + if (type == REQUEST) { + RequestMessage request = messageParser.parseRequestMessage(m, body); + return engine.onRequestMessage(txn, session, request); + } else if (type == ACCEPT) { + AcceptMessage accept = messageParser.parseAcceptMessage(m, body); + return engine.onAcceptMessage(txn, session, accept); + } else if (type == DECLINE) { + DeclineMessage decline = messageParser.parseDeclineMessage(m, body); + return engine.onDeclineMessage(txn, session, decline); + } else if (type == AUTH) { + AuthMessage auth = messageParser.parseAuthMessage(m, body); + return engine.onAuthMessage(txn, session, auth); + } else if (type == ACTIVATE) { + ActivateMessage activate = + messageParser.parseActivateMessage(m, body); + return engine.onActivateMessage(txn, session, activate); + } else if (type == ABORT) { + AbortMessage abort = messageParser.parseAbortMessage(m, body); + return engine.onAbortMessage(txn, session, abort); + } else { + 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, getLocalGroup().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()); + } + + 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()); + } + + private MessageId createStorageId(Transaction txn) throws DbException { + Message m = clientHelper + .createMessageForStoringMetadata(getLocalGroup().getId()); + db.addLocalMessage(txn, m, new Metadata(), false); + return m.getId(); + } + + private void storeSession(Transaction txn, MessageId storageId, + Session session) throws DbException, FormatException { + BdfDictionary d; + if (session.getRole() == INTRODUCER) { + d = sessionEncoder + .encodeIntroducerSession((IntroducerSession) session); + } else if (session.getRole() == INTRODUCEE) { + d = sessionEncoder + .encodeIntroduceeSession((IntroduceeSession) session); + } else { + throw new AssertionError(); + } + clientHelper.mergeMessageMetadata(txn, storageId, d); } @Override public void makeIntroduction(Contact c1, Contact c2, @Nullable String msg, - long timestamp) throws DbException, FormatException { - + long timestamp) throws DbException { Transaction txn = db.startTransaction(false); try { - introducerManager.makeIntroduction(txn, c1, c2, msg, timestamp); - Group g1 = getContactGroup(c1); - Group g2 = getContactGroup(c2); - messageTracker.trackMessage(txn, g1.getId(), timestamp, true); - messageTracker.trackMessage(txn, g2.getId(), timestamp, true); + // Look up the session, if there is one + Author introducer = identityManager.getLocalAuthor(txn); + SessionId sessionId = + crypto.getSessionId(introducer, c1.getAuthor(), + c2.getAuthor()); + StoredSession ss = getSession(txn, sessionId); + // Create or parse the session + IntroducerSession session; + MessageId storageId; + if (ss == null) { + // This is the first request - create a new session + GroupId groupId1 = getContactGroup(c1).getId(); + GroupId groupId2 = getContactGroup(c2).getId(); + session = new IntroducerSession(sessionId, groupId1, + c1.getAuthor(), groupId2, c2.getAuthor()); + storageId = createStorageId(txn); + } else { + // An earlier request exists, so we already have a session + session = sessionParser.parseIntroducerSession(ss.bdfSession); + storageId = ss.storageId; + } + // Handle the request action + session = introducerEngine + .onRequestAction(txn, session, msg, timestamp); + // Store the updated session + storeSession(txn, storageId, session); db.commitTransaction(txn); + } catch (FormatException e) { + throw new DbException(e); } finally { db.endTransaction(txn); } @@ -289,147 +304,78 @@ class IntroductionManagerImpl extends ConversationClientImpl @Override public void acceptIntroduction(ContactId contactId, SessionId sessionId, - long timestamp) throws DbException, FormatException { - - Transaction txn = db.startTransaction(false); - try { - Contact c = db.getContact(txn, contactId); - Group g = getContactGroup(c); - BdfDictionary state = - getSessionState(txn, g.getId(), sessionId.getBytes()); - - introduceeManager.acceptIntroduction(txn, state, timestamp); - messageTracker.trackMessage(txn, g.getId(), timestamp, true); - db.commitTransaction(txn); - } finally { - db.endTransaction(txn); - } + long timestamp) throws DbException { + respondToRequest(contactId, sessionId, timestamp, true); } @Override public void declineIntroduction(ContactId contactId, SessionId sessionId, - long timestamp) throws DbException, FormatException { + long timestamp) throws DbException { + respondToRequest(contactId, sessionId, timestamp, false); + } + private void respondToRequest(ContactId contactId, SessionId sessionId, + long timestamp, boolean accept) throws DbException { Transaction txn = db.startTransaction(false); try { - Contact c = db.getContact(txn, contactId); - Group g = getContactGroup(c); - BdfDictionary state = - getSessionState(txn, g.getId(), sessionId.getBytes()); - - introduceeManager.declineIntroduction(txn, state, timestamp); - messageTracker.trackMessage(txn, g.getId(), timestamp, true); + // Look up the session + StoredSession ss = getSession(txn, sessionId); + if (ss == null) throw new IllegalArgumentException(); + // Parse the session + Contact contact = db.getContact(txn, contactId); + GroupId contactGroupId = getContactGroup(contact).getId(); + IntroduceeSession session = sessionParser + .parseIntroduceeSession(contactGroupId, ss.bdfSession); + // Handle the join or leave action + if (accept) { + session = introduceeEngine + .onAcceptAction(txn, session, timestamp); + } else { + session = introduceeEngine + .onDeclineAction(txn, session, timestamp); + } + // Store the updated session + storeSession(txn, ss.storageId, session); db.commitTransaction(txn); + } catch (FormatException e) { + throw new DbException(e); } finally { db.endTransaction(txn); } } @Override - public Collection<IntroductionMessage> getIntroductionMessages( - ContactId contactId) throws DbException { - - Collection<IntroductionMessage> list = new ArrayList<>(); - - Map<MessageId, BdfDictionary> metadata; - Collection<MessageStatus> statuses; + public Collection<IntroductionMessage> getIntroductionMessages(ContactId c) + throws DbException { + List<IntroductionMessage> messages; Transaction txn = db.startTransaction(true); try { - // get messages and their status - GroupId g = getContactGroup(db.getContact(txn, contactId)).getId(); - metadata = clientHelper.getMessageMetadataAsDictionary(txn, g); - statuses = db.getMessageStatus(txn, contactId, g); - - // turn messages into classes for the UI - for (MessageStatus s : statuses) { - MessageId messageId = s.getMessageId(); - BdfDictionary msg = metadata.get(messageId); - if (msg == null) continue; - - try { - long type = msg.getLong(TYPE); - if (type == TYPE_ACK || type == TYPE_ABORT) continue; - - // get session state - SessionId sessionId = new SessionId(msg.getRaw(SESSION_ID)); - BdfDictionary state = - getSessionState(txn, g, sessionId.getBytes()); - - int role = state.getLong(ROLE).intValue(); - boolean local; - long time = msg.getLong(MESSAGE_TIME); - boolean accepted = msg.getBoolean(ACCEPT, false); - boolean read = msg.getBoolean(MSG_KEY_READ, false); - AuthorId authorId; - String name; - if (type == TYPE_RESPONSE) { - if (role == ROLE_INTRODUCER) { - if (!concernsThisContact(contactId, messageId, state)) { - // this response is not from contactId - continue; - } - local = false; - authorId = - getAuthorIdForIntroducer(contactId, state); - name = getNameForIntroducer(contactId, state); - } else { - if (Arrays.equals(state.getRaw(NOT_OUR_RESPONSE), - messageId.getBytes())) { - // this response is not ours, - // check if it was a decline - if (!accepted) { - local = false; - } else { - // don't include positive responses - continue; - } - } else { - local = true; - } - authorId = new AuthorId( - state.getRaw(REMOTE_AUTHOR_ID)); - name = state.getString(NAME); - } - IntroductionResponse ir = new IntroductionResponse( - sessionId, messageId, g, role, time, local, - s.isSent(), s.isSeen(), read, authorId, name, - accepted); - list.add(ir); - } else if (type == TYPE_REQUEST) { - String message; - boolean answered, exists, introducesOtherIdentity; - if (role == ROLE_INTRODUCER) { - local = true; - authorId = - getAuthorIdForIntroducer(contactId, state); - name = getNameForIntroducer(contactId, state); - message = msg.getOptionalString(MSG); - answered = false; - exists = false; - introducesOtherIdentity = false; - } else { - local = false; - authorId = new AuthorId( - state.getRaw(REMOTE_AUTHOR_ID)); - name = state.getString(NAME); - message = state.getOptionalString(MSG); - boolean finished = state.getLong(STATE) == - FINISHED.getValue(); - answered = finished || state.getBoolean(ANSWERED); - exists = state.getBoolean(EXISTS); - introducesOtherIdentity = - state.getBoolean(REMOTE_AUTHOR_IS_US); - } - IntroductionRequest ir = new IntroductionRequest( - sessionId, messageId, g, role, time, local, - s.isSent(), s.isSeen(), read, authorId, name, - accepted, message, answered, exists, - introducesOtherIdentity); - list.add(ir); - } - } catch (FormatException e) { - if (LOG.isLoggable(WARNING)) - LOG.log(WARNING, e.toString(), e); + Contact contact = db.getContact(txn, c); + GroupId contactGroupId = getContactGroup(contact).getId(); + BdfDictionary query = messageParser.getMessagesVisibleInUiQuery(); + Map<MessageId, BdfDictionary> results = clientHelper + .getMessageMetadataAsDictionary(txn, contactGroupId, query); + messages = new ArrayList<>(results.size()); + for (Map.Entry<MessageId, BdfDictionary> e : results.entrySet()) { + MessageId m = e.getKey(); + MessageMetadata meta = + messageParser.parseMetadata(e.getValue()); + MessageStatus status = db.getMessageStatus(txn, c, m); + StoredSession ss = getSession(txn, meta.getSessionId()); + if (ss == null) throw new AssertionError(); + MessageType type = meta.getMessageType(); + if (type == REQUEST) { + messages.add( + parseInvitationRequest(txn, contactGroupId, m, + meta, status, ss.bdfSession)); + } else if (type == ACCEPT) { + messages.add( + parseInvitationResponse(txn, contactGroupId, m, + meta, status, ss.bdfSession, true)); + } else if (type == DECLINE) { + messages.add( + parseInvitationResponse(txn, contactGroupId, m, + meta, status, ss.bdfSession, false)); } } db.commitTransaction(txn); @@ -438,88 +384,129 @@ class IntroductionManagerImpl extends ConversationClientImpl } finally { db.endTransaction(txn); } - return list; + return messages; } - private String getNameForIntroducer(ContactId contactId, - BdfDictionary state) throws FormatException { - - if (contactId.getInt() == state.getLong(CONTACT_ID_1).intValue()) - return state.getString(CONTACT_2); - if (contactId.getInt() == state.getLong(CONTACT_ID_2).intValue()) - return state.getString(CONTACT_1); - throw new RuntimeException( - "Contact not part of this introduction session"); + private IntroductionRequest parseInvitationRequest(Transaction txn, + GroupId contactGroupId, MessageId m, MessageMetadata meta, + MessageStatus status, BdfDictionary bdfSession) + throws DbException, FormatException { + Role role = sessionParser.getRole(bdfSession); + SessionId sessionId; + Author author; + if (role == INTRODUCER) { + IntroducerSession session = + sessionParser.parseIntroducerSession(bdfSession); + sessionId = session.getSessionId(); + LocalAuthor localAuthor = identityManager.getLocalAuthor(txn); + if (localAuthor.equals(session.getIntroducee1().author)) { + author = session.getIntroducee2().author; + } else { + author = session.getIntroducee1().author; + } + } else if (role == INTRODUCEE) { + IntroduceeSession session = sessionParser + .parseIntroduceeSession(contactGroupId, bdfSession); + sessionId = session.getSessionId(); + author = session.getRemoteAuthor(); + } else throw new AssertionError(); + String message = ""; // TODO + boolean contactExists = false; // TODO + + return new IntroductionRequest(sessionId, m, contactGroupId, + role, meta.getTimestamp(), meta.isLocal(), + status.isSent(), status.isSeen(), meta.isRead(), + author.getName(), false, message, !meta.isAvailableToAnswer(), + contactExists); } - private AuthorId getAuthorIdForIntroducer(ContactId contactId, - BdfDictionary state) throws FormatException { - - if (contactId.getInt() == state.getLong(CONTACT_ID_1).intValue()) - return new AuthorId(state.getRaw(AUTHOR_ID_2)); - if (contactId.getInt() == state.getLong(CONTACT_ID_2).intValue()) - return new AuthorId(state.getRaw(AUTHOR_ID_1)); - throw new RuntimeException( - "Contact not part of this introduction session"); + private IntroductionResponse parseInvitationResponse(Transaction txn, + GroupId contactGroupId, MessageId m, MessageMetadata meta, + MessageStatus status, BdfDictionary bdfSession, boolean accept) + throws FormatException, DbException { + Role role = sessionParser.getRole(bdfSession); + SessionId sessionId; + Author author; + if (role == INTRODUCER) { + IntroducerSession session = + sessionParser.parseIntroducerSession(bdfSession); + sessionId = session.getSessionId(); + LocalAuthor localAuthor = identityManager.getLocalAuthor(txn); + if (localAuthor.equals(session.getIntroducee1().author)) { + author = session.getIntroducee2().author; + } else { + author = session.getIntroducee1().author; + } + } else if (role == INTRODUCEE) { + IntroduceeSession session = sessionParser + .parseIntroduceeSession(contactGroupId, bdfSession); + sessionId = session.getSessionId(); + author = session.getRemoteAuthor(); + } else throw new AssertionError(); + return new IntroductionResponse(sessionId, m, contactGroupId, + role, meta.getTimestamp(), meta.isLocal(), status.isSent(), + status.isSeen(), meta.isRead(), author.getName(), accept); } - private boolean concernsThisContact(ContactId contactId, MessageId messageId, - BdfDictionary state) throws FormatException { - - if (contactId.getInt() == state.getLong(CONTACT_ID_1).intValue()) { - return Arrays.equals(state.getRaw(RESPONSE_1, new byte[0]), - messageId.getBytes()); - } else { - return Arrays.equals(state.getRaw(RESPONSE_2, new byte[0]), - messageId.getBytes()); + private void removeSessionWithIntroducer(Transaction txn, + Contact introducer) throws DbException, FormatException { + BdfDictionary query = sessionEncoder + .getIntroduceeSessionsByIntroducerQuery(introducer.getAuthor()); + Map<MessageId, BdfDictionary> sessions = clientHelper + .getMessageMetadataAsDictionary(txn, getLocalGroup().getId(), + query); + for (MessageId id : sessions.keySet()) { + db.deleteMessageMetadata(txn, id); // TODO needed? + db.removeMessage(txn, id); } } - private BdfDictionary getSessionState(Transaction txn, GroupId groupId, - byte[] sessionId, boolean warn) - throws DbException, FormatException { - - try { - // See if we can find the state directly for the introducer - BdfDictionary state = clientHelper - .getMessageMetadataAsDictionary(txn, - new MessageId(sessionId)); - GroupId g1 = new GroupId(state.getRaw(GROUP_ID_1)); - GroupId g2 = new GroupId(state.getRaw(GROUP_ID_2)); - if (!g1.equals(groupId) && !g2.equals(groupId)) { - throw new NoSuchMessageException(); - } - return state; - } catch (NoSuchMessageException e) { - // State not found directly, so iterate over all states - // to find state for introducee - Map<MessageId, BdfDictionary> map = clientHelper - .getMessageMetadataAsDictionary(txn, - introductionGroupFactory.createLocalGroup().getId()); - for (Map.Entry<MessageId, BdfDictionary> m : map.entrySet()) { - if (Arrays.equals(m.getValue().getRaw(SESSION_ID), sessionId)) { - BdfDictionary state = m.getValue(); - GroupId g = new GroupId(state.getRaw(GROUP_ID)); - if (g.equals(groupId)) return state; - } + private void abortOrRemoveSessionWithIntroducee(Transaction txn, + Contact c) throws DbException, FormatException { + BdfDictionary query = sessionEncoder.getIntroducerSessionsQuery(); + Map<MessageId, BdfDictionary> sessions = clientHelper + .getMessageMetadataAsDictionary(txn, getLocalGroup().getId(), + query); + LocalAuthor localAuthor = identityManager.getLocalAuthor(txn); + for (Map.Entry<MessageId, BdfDictionary> session : sessions + .entrySet()) { + IntroducerSession s = + sessionParser.parseIntroducerSession(session.getValue()); + if (s.getIntroducee1().author.equals(c.getAuthor())) { + abortOrRemoveSessionWithIntroducee(txn, s, session.getKey(), + s.getIntroducee2(), localAuthor); + } else if (s.getIntroducee2().author.equals(c.getAuthor())) { + abortOrRemoveSessionWithIntroducee(txn, s, session.getKey(), + s.getIntroducee1(), localAuthor); } - if (warn && LOG.isLoggable(WARNING)) - LOG.warning("No session state found"); - throw new FormatException(); } } - private BdfDictionary getSessionState(Transaction txn, GroupId groupId, - byte[] sessionId) throws DbException, FormatException { + private void abortOrRemoveSessionWithIntroducee(Transaction txn, + IntroducerSession s, MessageId storageId, Introducee i, + LocalAuthor localAuthor) throws DbException, FormatException { + if (db.containsContact(txn, i.author.getId(), localAuthor.getId())) { + IntroducerSession session = introducerEngine.onAbortAction(txn, s); + storeSession(txn, storageId, session); + } else { + db.deleteMessageMetadata(txn, storageId); // TODO needed? + db.removeMessage(txn, storageId); + } + } - return getSessionState(txn, groupId, sessionId, true); + private Group getLocalGroup() { + return contactGroupFactory.createLocalGroup(CLIENT_ID, CLIENT_VERSION); } - private void deleteMessage(Transaction txn, MessageId messageId) - throws DbException { + private static class StoredSession { - db.deleteMessage(txn, messageId); - db.deleteMessageMetadata(txn, messageId); + private final MessageId storageId; + private final BdfDictionary bdfSession; + + private StoredSession(MessageId storageId, BdfDictionary bdfSession) { + this.storageId = storageId; + this.bdfSession = bdfSession; + } } } diff --git a/briar-core/src/main/java/org/briarproject/briar/introduction/IntroductionModule.java b/briar-core/src/main/java/org/briarproject/briar/introduction/IntroductionModule.java index e0122faa9d315af728599a43220b89c4afdec756..24c649c5fd6cbb0e4a1fe7ad838af2ff13ac4d20 100644 --- a/briar-core/src/main/java/org/briarproject/briar/introduction/IntroductionModule.java +++ b/briar-core/src/main/java/org/briarproject/briar/introduction/IntroductionModule.java @@ -4,8 +4,8 @@ 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.sync.ValidationManager; import org.briarproject.bramble.api.system.Clock; -import org.briarproject.briar.api.client.MessageQueueManager; import org.briarproject.briar.api.introduction.IntroductionManager; import org.briarproject.briar.api.messaging.ConversationManager; @@ -21,22 +21,22 @@ import static org.briarproject.briar.api.introduction.IntroductionManager.CLIENT public class IntroductionModule { public static class EagerSingletons { - @Inject - IntroductionManager introductionManager; @Inject IntroductionValidator introductionValidator; + @Inject + IntroductionManager introductionManager; } @Provides @Singleton - IntroductionValidator provideValidator( - MessageQueueManager messageQueueManager, - MetadataEncoder metadataEncoder, ClientHelper clientHelper, - Clock clock) { - - IntroductionValidator introductionValidator = new IntroductionValidator( - clientHelper, metadataEncoder, clock); - messageQueueManager.registerMessageValidator(CLIENT_ID, + IntroductionValidator provideValidator(ValidationManager validationManager, + MessageEncoder messageEncoder, MetadataEncoder metadataEncoder, + ClientHelper clientHelper, Clock clock) { + + IntroductionValidator introductionValidator = + new IntroductionValidator(messageEncoder, clientHelper, + metadataEncoder, clock); + validationManager.registerMessageValidator(CLIENT_ID, introductionValidator); return introductionValidator; @@ -46,16 +46,42 @@ public class IntroductionModule { @Singleton IntroductionManager provideIntroductionManager( LifecycleManager lifecycleManager, ContactManager contactManager, - MessageQueueManager messageQueueManager, + ValidationManager validationManager, ConversationManager conversationManager, IntroductionManagerImpl introductionManager) { - lifecycleManager.registerClient(introductionManager); contactManager.registerContactHook(introductionManager); - messageQueueManager.registerIncomingMessageHook(CLIENT_ID, + validationManager.registerIncomingMessageHook(CLIENT_ID, introductionManager); conversationManager.registerConversationClient(introductionManager); return introductionManager; } + + @Provides + MessageParser provideMessageParser(MessageParserImpl messageParser) { + return messageParser; + } + + @Provides + MessageEncoder provideMessageEncoder(MessageEncoderImpl messageEncoder) { + return messageEncoder; + } + + @Provides + SessionParser provideSessionParser(SessionParserImpl sessionParser) { + return sessionParser; + } + + @Provides + SessionEncoder provideSessionEncoder(SessionEncoderImpl sessionEncoder) { + return sessionEncoder; + } + + @Provides + IntroductionCrypto provideIntroductionCrypto( + IntroductionCryptoImpl introductionCrypto) { + return introductionCrypto; + } + } 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 9fc526e49c24a709cc2a43d9abaea0b5973c944d..16d26afdf38da22645c7ffedf9a89406628d0ea0 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 @@ -1,7 +1,9 @@ package org.briarproject.briar.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.data.BdfDictionary; import org.briarproject.bramble.api.data.BdfList; @@ -9,183 +11,166 @@ 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 org.briarproject.briar.api.client.SessionId; -import org.briarproject.briar.client.BdfQueueMessageValidator; + +import java.util.Collections; import javax.annotation.concurrent.Immutable; -import static org.briarproject.bramble.api.crypto.CryptoConstants.MAX_AGREEMENT_PUBLIC_KEY_BYTES; -import static org.briarproject.bramble.api.identity.AuthorConstants.MAX_AUTHOR_NAME_LENGTH; +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.api.plugin.TransportId.MAX_TRANSPORT_ID_LENGTH; -import static org.briarproject.bramble.api.properties.TransportPropertyConstants.MAX_PROPERTIES_PER_TRANSPORT; -import static org.briarproject.bramble.api.properties.TransportPropertyConstants.MAX_PROPERTY_LENGTH; import static org.briarproject.bramble.util.ValidationUtils.checkLength; import static org.briarproject.bramble.util.ValidationUtils.checkSize; -import static org.briarproject.briar.api.introduction.IntroductionConstants.ACCEPT; -import static org.briarproject.briar.api.introduction.IntroductionConstants.E_PUBLIC_KEY; -import static org.briarproject.briar.api.introduction.IntroductionConstants.GROUP_ID; -import static org.briarproject.briar.api.introduction.IntroductionConstants.MAC; -import static org.briarproject.briar.api.introduction.IntroductionConstants.MAC_LENGTH; -import static org.briarproject.briar.api.introduction.IntroductionConstants.MAX_INTRODUCTION_MESSAGE_LENGTH; -import static org.briarproject.briar.api.introduction.IntroductionConstants.MESSAGE_ID; -import static org.briarproject.briar.api.introduction.IntroductionConstants.MESSAGE_TIME; -import static org.briarproject.briar.api.introduction.IntroductionConstants.MSG; -import static org.briarproject.briar.api.introduction.IntroductionConstants.NAME; -import static org.briarproject.briar.api.introduction.IntroductionConstants.PUBLIC_KEY; -import static org.briarproject.briar.api.introduction.IntroductionConstants.SESSION_ID; -import static org.briarproject.briar.api.introduction.IntroductionConstants.SIGNATURE; -import static org.briarproject.briar.api.introduction.IntroductionConstants.TIME; -import static org.briarproject.briar.api.introduction.IntroductionConstants.TRANSPORT; -import static org.briarproject.briar.api.introduction.IntroductionConstants.TYPE; -import static org.briarproject.briar.api.introduction.IntroductionConstants.TYPE_ABORT; -import static org.briarproject.briar.api.introduction.IntroductionConstants.TYPE_ACK; -import static org.briarproject.briar.api.introduction.IntroductionConstants.TYPE_REQUEST; -import static org.briarproject.briar.api.introduction.IntroductionConstants.TYPE_RESPONSE; +import static org.briarproject.briar.api.introduction.IntroductionConstants.MAX_REQUEST_MESSAGE_LENGTH; +import static org.briarproject.briar.introduction.MessageType.ACCEPT; +import static org.briarproject.briar.introduction.MessageType.AUTH; + @Immutable @NotNullByDefault -class IntroductionValidator extends BdfQueueMessageValidator { +class IntroductionValidator extends BdfMessageValidator { + + private final MessageEncoder messageEncoder; - IntroductionValidator(ClientHelper clientHelper, - MetadataEncoder metadataEncoder, Clock clock) { + IntroductionValidator(MessageEncoder 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 REQUEST: + return validateRequestMessage(m, body); + case ACCEPT: + return validateAcceptMessage(m, body); + case AUTH: + return validateAuthMessage(m, body); + case DECLINE: + case ACTIVATE: + case ABORT: + return validateOtherMessage(type, m, body); + default: + throw new FormatException(); + } + } - BdfDictionary d; - long type = body.getLong(0); - byte[] id = body.getRaw(1); - checkLength(id, SessionId.LENGTH); - - if (type == TYPE_REQUEST) { - d = validateRequest(body); - } else if (type == TYPE_RESPONSE) { - d = validateResponse(body); - } else if (type == TYPE_ACK) { - d = validateAck(body); - } else if (type == TYPE_ABORT) { - d = validateAbort(body); + 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); + clientHelper.parseAndValidateAuthor(authorList); + + String msg = body.getOptionalString(3); + checkLength(msg, 1, MAX_REQUEST_MESSAGE_LENGTH); + + BdfDictionary meta = messageEncoder + .encodeRequestMetadata(m.getTimestamp(), false, false, + false, false); + if (previousMessageId == null) { + return new BdfMessageContext(meta); } else { - throw new FormatException(); + MessageId dependency = new MessageId(previousMessageId); + return new BdfMessageContext(meta, + Collections.singletonList(dependency)); } - - d.put(TYPE, type); - d.put(SESSION_ID, id); - d.put(GROUP_ID, m.getGroupId()); - d.put(MESSAGE_ID, m.getId()); - d.put(MESSAGE_TIME, m.getTimestamp()); - return new BdfMessageContext(d); } - private BdfDictionary validateRequest(BdfList message) + private BdfMessageContext validateAcceptMessage(Message m, BdfList body) throws FormatException { + checkSize(body, 6); - checkSize(message, 4, 5); + byte[] sessionIdBytes = body.getRaw(1); + checkLength(sessionIdBytes, UniqueId.LENGTH); - // TODO: Exchange author format version + byte[] previousMessageId = body.getOptionalRaw(2); + checkLength(previousMessageId, UniqueId.LENGTH); - // parse contact name - String name = message.getString(2); - checkLength(name, 1, MAX_AUTHOR_NAME_LENGTH); + byte[] ephemeralPublicKey = body.getRaw(3); + checkLength(ephemeralPublicKey, 0, MAX_PUBLIC_KEY_LENGTH); - // parse contact's public key - byte[] key = message.getRaw(3); - checkLength(key, 0, MAX_PUBLIC_KEY_LENGTH); + body.getLong(4); - // parse (optional) message - String msg = null; - if (message.size() == 5) { - msg = message.getString(4); - checkLength(msg, 0, MAX_INTRODUCTION_MESSAGE_LENGTH); + BdfDictionary transportProperties = body.getDictionary(5); + if (transportProperties.size() < 1) throw new FormatException(); + for (String tId : transportProperties.keySet()) { + checkLength(tId, 1, MAX_TRANSPORT_ID_LENGTH); + BdfDictionary tProps = transportProperties.getDictionary(tId); + clientHelper.parseAndValidateTransportProperties(tProps); } - // Return the metadata - BdfDictionary d = new BdfDictionary(); - d.put(NAME, name); - d.put(PUBLIC_KEY, key); - if (msg != null) { - d.put(MSG, msg); + SessionId sessionId = new SessionId(sessionIdBytes); + BdfDictionary meta = messageEncoder + .encodeMetadata(ACCEPT, sessionId, m.getTimestamp(), false, + false, false); + if (previousMessageId == null) { + return new BdfMessageContext(meta); + } else { + MessageId dependency = new MessageId(previousMessageId); + return new BdfMessageContext(meta, + Collections.singletonList(dependency)); } - return d; } - private BdfDictionary validateResponse(BdfList message) + private BdfMessageContext validateAuthMessage(Message m, BdfList body) throws FormatException { + checkSize(body, 5); - checkSize(message, 3, 6); - - // parse accept/decline - boolean accept = message.getBoolean(2); - - long time = 0; - byte[] pubkey = null; - BdfDictionary tp = new BdfDictionary(); - if (accept) { - checkSize(message, 6); - - // parse timestamp - time = message.getLong(3); - - // parse ephemeral public key - pubkey = message.getRaw(4); - checkLength(pubkey, 1, MAX_AGREEMENT_PUBLIC_KEY_BYTES); - - // parse transport properties - tp = message.getDictionary(5); - if (tp.size() < 1) throw new FormatException(); - for (String tId : tp.keySet()) { - checkLength(tId, 1, MAX_TRANSPORT_ID_LENGTH); - BdfDictionary tProps = tp.getDictionary(tId); - checkSize(tProps, 0, MAX_PROPERTIES_PER_TRANSPORT); - for (String propId : tProps.keySet()) { - checkLength(propId, 0, MAX_PROPERTY_LENGTH); - String prop = tProps.getString(propId); - checkLength(prop, 0, MAX_PROPERTY_LENGTH); - } - } - } else { - checkSize(message, 3); - } - - // Return the metadata - BdfDictionary d = new BdfDictionary(); - d.put(ACCEPT, accept); - if (accept) { - d.put(TIME, time); - d.put(E_PUBLIC_KEY, pubkey); - d.put(TRANSPORT, tp); - } - return d; - } + byte[] sessionIdBytes = body.getRaw(1); + checkLength(sessionIdBytes, UniqueId.LENGTH); - private BdfDictionary validateAck(BdfList message) throws FormatException { - checkSize(message, 4); + byte[] previousMessageId = body.getRaw(2); + checkLength(previousMessageId, UniqueId.LENGTH); - byte[] mac = message.getRaw(2); - checkLength(mac, 1, MAC_LENGTH); + byte[] mac = body.getRaw(3); + checkLength(mac, MAC_BYTES); - byte[] sig = message.getRaw(3); - checkLength(sig, 1, MAX_SIGNATURE_LENGTH); + byte[] signature = body.getRaw(4); + checkLength(signature, 1, MAX_SIGNATURE_BYTES); - // Return the metadata - BdfDictionary d = new BdfDictionary(); - d.put(MAC, mac); - d.put(SIGNATURE, sig); - return d; + SessionId sessionId = new SessionId(sessionIdBytes); + BdfDictionary meta = messageEncoder + .encodeMetadata(AUTH, sessionId, m.getTimestamp(), false, false, + false); + MessageId dependency = new MessageId(previousMessageId); + return new BdfMessageContext(meta, + Collections.singletonList(dependency)); } - private BdfDictionary validateAbort(BdfList message) - throws FormatException { + private BdfMessageContext validateOtherMessage(MessageType type, + Message m, BdfList body) throws FormatException { + checkSize(body, 3); + + byte[] sessionIdBytes = body.getRaw(1); + checkLength(sessionIdBytes, UniqueId.LENGTH); - checkSize(message, 2); + byte[] previousMessageId = body.getOptionalRaw(2); + checkLength(previousMessageId, UniqueId.LENGTH); - // Return the metadata - return new BdfDictionary(); + SessionId sessionId = new SessionId(sessionIdBytes); + BdfDictionary meta = messageEncoder + .encodeMetadata(type, sessionId, m.getTimestamp(), false, false, + false); + if (previousMessageId == null) { + return new BdfMessageContext(meta); + } else { + MessageId dependency = new MessageId(previousMessageId); + return new BdfMessageContext(meta, + Collections.singletonList(dependency)); + } } + } diff --git a/briar-core/src/main/java/org/briarproject/briar/introduction2/MessageEncoder.java b/briar-core/src/main/java/org/briarproject/briar/introduction/MessageEncoder.java similarity index 97% rename from briar-core/src/main/java/org/briarproject/briar/introduction2/MessageEncoder.java rename to briar-core/src/main/java/org/briarproject/briar/introduction/MessageEncoder.java index 390ea9b0fbb83c1c1161e3d95be1e38c06948ee3..d619e3d76eb2f26ce4b417ce82245b743cf02f81 100644 --- a/briar-core/src/main/java/org/briarproject/briar/introduction2/MessageEncoder.java +++ b/briar-core/src/main/java/org/briarproject/briar/introduction/MessageEncoder.java @@ -1,4 +1,4 @@ -package org.briarproject.briar.introduction2; +package org.briarproject.briar.introduction; import org.briarproject.bramble.api.data.BdfDictionary; import org.briarproject.bramble.api.identity.Author; diff --git a/briar-core/src/main/java/org/briarproject/briar/introduction2/MessageEncoderImpl.java b/briar-core/src/main/java/org/briarproject/briar/introduction/MessageEncoderImpl.java similarity index 83% rename from briar-core/src/main/java/org/briarproject/briar/introduction2/MessageEncoderImpl.java rename to briar-core/src/main/java/org/briarproject/briar/introduction/MessageEncoderImpl.java index 7f44671e0c73960f105fb90b5173cc582a09ede0..5bade9d86f338b30bd2badb1dacad9a7fec9f9af 100644 --- a/briar-core/src/main/java/org/briarproject/briar/introduction2/MessageEncoderImpl.java +++ b/briar-core/src/main/java/org/briarproject/briar/introduction/MessageEncoderImpl.java @@ -1,4 +1,4 @@ -package org.briarproject.briar.introduction2; +package org.briarproject.briar.introduction; import org.briarproject.bramble.api.FormatException; import org.briarproject.bramble.api.client.ClientHelper; @@ -20,19 +20,19 @@ import javax.annotation.Nullable; import javax.inject.Inject; import static org.briarproject.briar.client.MessageTrackerConstants.MSG_KEY_READ; -import static org.briarproject.briar.introduction2.IntroductionConstants.MSG_KEY_AVAILABLE_TO_ANSWER; -import static org.briarproject.briar.introduction2.IntroductionConstants.MSG_KEY_INVITATION_ACCEPTED; -import static org.briarproject.briar.introduction2.IntroductionConstants.MSG_KEY_LOCAL; -import static org.briarproject.briar.introduction2.IntroductionConstants.MSG_KEY_MESSAGE_TYPE; -import static org.briarproject.briar.introduction2.IntroductionConstants.MSG_KEY_SESSION_ID; -import static org.briarproject.briar.introduction2.IntroductionConstants.MSG_KEY_TIMESTAMP; -import static org.briarproject.briar.introduction2.IntroductionConstants.MSG_KEY_VISIBLE_IN_UI; -import static org.briarproject.briar.introduction2.MessageType.ABORT; -import static org.briarproject.briar.introduction2.MessageType.ACCEPT; -import static org.briarproject.briar.introduction2.MessageType.ACTIVATE; -import static org.briarproject.briar.introduction2.MessageType.AUTH; -import static org.briarproject.briar.introduction2.MessageType.DECLINE; -import static org.briarproject.briar.introduction2.MessageType.REQUEST; +import static org.briarproject.briar.introduction.IntroductionConstants.MSG_KEY_AVAILABLE_TO_ANSWER; +import static org.briarproject.briar.introduction.IntroductionConstants.MSG_KEY_INVITATION_ACCEPTED; +import static org.briarproject.briar.introduction.IntroductionConstants.MSG_KEY_LOCAL; +import static org.briarproject.briar.introduction.IntroductionConstants.MSG_KEY_MESSAGE_TYPE; +import static org.briarproject.briar.introduction.IntroductionConstants.MSG_KEY_SESSION_ID; +import static org.briarproject.briar.introduction.IntroductionConstants.MSG_KEY_TIMESTAMP; +import static org.briarproject.briar.introduction.IntroductionConstants.MSG_KEY_VISIBLE_IN_UI; +import static org.briarproject.briar.introduction.MessageType.ABORT; +import static org.briarproject.briar.introduction.MessageType.ACCEPT; +import static org.briarproject.briar.introduction.MessageType.ACTIVATE; +import static org.briarproject.briar.introduction.MessageType.AUTH; +import static org.briarproject.briar.introduction.MessageType.DECLINE; +import static org.briarproject.briar.introduction.MessageType.REQUEST; @NotNullByDefault class MessageEncoderImpl implements MessageEncoder { diff --git a/briar-core/src/main/java/org/briarproject/briar/introduction2/MessageMetadata.java b/briar-core/src/main/java/org/briarproject/briar/introduction/MessageMetadata.java similarity index 96% rename from briar-core/src/main/java/org/briarproject/briar/introduction2/MessageMetadata.java rename to briar-core/src/main/java/org/briarproject/briar/introduction/MessageMetadata.java index 67ba5b031992617fc41d73df1233e2139a088e1e..9b3ea54b53066b95852eca4f7d420fb9da36bad4 100644 --- a/briar-core/src/main/java/org/briarproject/briar/introduction2/MessageMetadata.java +++ b/briar-core/src/main/java/org/briarproject/briar/introduction/MessageMetadata.java @@ -1,4 +1,4 @@ -package org.briarproject.briar.introduction2; +package org.briarproject.briar.introduction; import org.briarproject.bramble.api.nullsafety.NotNullByDefault; import org.briarproject.briar.api.client.SessionId; diff --git a/briar-core/src/main/java/org/briarproject/briar/introduction2/MessageParser.java b/briar-core/src/main/java/org/briarproject/briar/introduction/MessageParser.java similarity index 95% rename from briar-core/src/main/java/org/briarproject/briar/introduction2/MessageParser.java rename to briar-core/src/main/java/org/briarproject/briar/introduction/MessageParser.java index 45526a09192977aa6a86f587f7c91b802438e01c..58f9dbfabd93f64b4c925af5df6dda3b0834e0a7 100644 --- a/briar-core/src/main/java/org/briarproject/briar/introduction2/MessageParser.java +++ b/briar-core/src/main/java/org/briarproject/briar/introduction/MessageParser.java @@ -1,4 +1,4 @@ -package org.briarproject.briar.introduction2; +package org.briarproject.briar.introduction; import org.briarproject.bramble.api.FormatException; import org.briarproject.bramble.api.data.BdfDictionary; diff --git a/briar-core/src/main/java/org/briarproject/briar/introduction2/MessageParserImpl.java b/briar-core/src/main/java/org/briarproject/briar/introduction/MessageParserImpl.java similarity index 86% rename from briar-core/src/main/java/org/briarproject/briar/introduction2/MessageParserImpl.java rename to briar-core/src/main/java/org/briarproject/briar/introduction/MessageParserImpl.java index 1c55be11d4f5f8b399b4974b875a299dd6f4fd9f..263af78442ec8cfb35f8832760054c303d9382d0 100644 --- a/briar-core/src/main/java/org/briarproject/briar/introduction2/MessageParserImpl.java +++ b/briar-core/src/main/java/org/briarproject/briar/introduction/MessageParserImpl.java @@ -1,4 +1,4 @@ -package org.briarproject.briar.introduction2; +package org.briarproject.briar.introduction; import org.briarproject.bramble.api.FormatException; import org.briarproject.bramble.api.client.ClientHelper; @@ -18,14 +18,14 @@ import java.util.Map; import javax.inject.Inject; import static org.briarproject.briar.client.MessageTrackerConstants.MSG_KEY_READ; -import static org.briarproject.briar.introduction2.IntroductionConstants.MSG_KEY_AVAILABLE_TO_ANSWER; -import static org.briarproject.briar.introduction2.IntroductionConstants.MSG_KEY_INVITATION_ACCEPTED; -import static org.briarproject.briar.introduction2.IntroductionConstants.MSG_KEY_LOCAL; -import static org.briarproject.briar.introduction2.IntroductionConstants.MSG_KEY_MESSAGE_TYPE; -import static org.briarproject.briar.introduction2.IntroductionConstants.MSG_KEY_SESSION_ID; -import static org.briarproject.briar.introduction2.IntroductionConstants.MSG_KEY_TIMESTAMP; -import static org.briarproject.briar.introduction2.IntroductionConstants.MSG_KEY_VISIBLE_IN_UI; -import static org.briarproject.briar.introduction2.MessageType.REQUEST; +import static org.briarproject.briar.introduction.IntroductionConstants.MSG_KEY_AVAILABLE_TO_ANSWER; +import static org.briarproject.briar.introduction.IntroductionConstants.MSG_KEY_INVITATION_ACCEPTED; +import static org.briarproject.briar.introduction.IntroductionConstants.MSG_KEY_LOCAL; +import static org.briarproject.briar.introduction.IntroductionConstants.MSG_KEY_MESSAGE_TYPE; +import static org.briarproject.briar.introduction.IntroductionConstants.MSG_KEY_SESSION_ID; +import static org.briarproject.briar.introduction.IntroductionConstants.MSG_KEY_TIMESTAMP; +import static org.briarproject.briar.introduction.IntroductionConstants.MSG_KEY_VISIBLE_IN_UI; +import static org.briarproject.briar.introduction.MessageType.REQUEST; @NotNullByDefault class MessageParserImpl implements MessageParser { diff --git a/briar-core/src/main/java/org/briarproject/briar/introduction/MessageSender.java b/briar-core/src/main/java/org/briarproject/briar/introduction/MessageSender.java deleted file mode 100644 index 7848aaf3dcd4fadba978f7cf576e763873c174d5..0000000000000000000000000000000000000000 --- a/briar-core/src/main/java/org/briarproject/briar/introduction/MessageSender.java +++ /dev/null @@ -1,125 +0,0 @@ -package org.briarproject.briar.introduction; - -import org.briarproject.bramble.api.FormatException; -import org.briarproject.bramble.api.client.ClientHelper; -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.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.nullsafety.NotNullByDefault; -import org.briarproject.bramble.api.sync.Group; -import org.briarproject.bramble.api.sync.GroupId; -import org.briarproject.bramble.api.system.Clock; -import org.briarproject.briar.api.client.MessageQueueManager; - -import javax.annotation.concurrent.Immutable; -import javax.inject.Inject; - -import static org.briarproject.briar.api.introduction.IntroductionConstants.ACCEPT; -import static org.briarproject.briar.api.introduction.IntroductionConstants.E_PUBLIC_KEY; -import static org.briarproject.briar.api.introduction.IntroductionConstants.GROUP_ID; -import static org.briarproject.briar.api.introduction.IntroductionConstants.MAC; -import static org.briarproject.briar.api.introduction.IntroductionConstants.MESSAGE_TIME; -import static org.briarproject.briar.api.introduction.IntroductionConstants.MSG; -import static org.briarproject.briar.api.introduction.IntroductionConstants.NAME; -import static org.briarproject.briar.api.introduction.IntroductionConstants.PUBLIC_KEY; -import static org.briarproject.briar.api.introduction.IntroductionConstants.SESSION_ID; -import static org.briarproject.briar.api.introduction.IntroductionConstants.SIGNATURE; -import static org.briarproject.briar.api.introduction.IntroductionConstants.TIME; -import static org.briarproject.briar.api.introduction.IntroductionConstants.TRANSPORT; -import static org.briarproject.briar.api.introduction.IntroductionConstants.TYPE; -import static org.briarproject.briar.api.introduction.IntroductionConstants.TYPE_ABORT; -import static org.briarproject.briar.api.introduction.IntroductionConstants.TYPE_ACK; -import static org.briarproject.briar.api.introduction.IntroductionConstants.TYPE_REQUEST; -import static org.briarproject.briar.api.introduction.IntroductionConstants.TYPE_RESPONSE; - -@Immutable -@NotNullByDefault -class MessageSender { - - private final DatabaseComponent db; - private final ClientHelper clientHelper; - private final Clock clock; - private final MetadataEncoder metadataEncoder; - private final MessageQueueManager messageQueueManager; - - @Inject - MessageSender(DatabaseComponent db, ClientHelper clientHelper, Clock clock, - MetadataEncoder metadataEncoder, - MessageQueueManager messageQueueManager) { - - this.db = db; - this.clientHelper = clientHelper; - this.clock = clock; - this.metadataEncoder = metadataEncoder; - this.messageQueueManager = messageQueueManager; - } - - void sendMessage(Transaction txn, BdfDictionary message) - throws DbException, FormatException { - - BdfList bdfList = encodeMessage(message); - byte[] body = clientHelper.toByteArray(bdfList); - GroupId groupId = new GroupId(message.getRaw(GROUP_ID)); - Group group = db.getGroup(txn, groupId); - long timestamp = clock.currentTimeMillis(); - - message.put(MESSAGE_TIME, timestamp); - Metadata metadata = metadataEncoder.encode(message); - - messageQueueManager.sendMessage(txn, group, timestamp, body, metadata); - } - - private BdfList encodeMessage(BdfDictionary d) throws FormatException { - - BdfList body; - long type = d.getLong(TYPE); - if (type == TYPE_REQUEST) { - body = encodeRequest(d); - } else if (type == TYPE_RESPONSE) { - body = encodeResponse(d); - } else if (type == TYPE_ACK) { - body = encodeAck(d); - } else if (type == TYPE_ABORT) { - body = encodeAbort(d); - } else { - throw new FormatException(); - } - return body; - } - - private BdfList encodeRequest(BdfDictionary d) throws FormatException { - BdfList list = BdfList.of(TYPE_REQUEST, d.getRaw(SESSION_ID), - d.getString(NAME), d.getRaw(PUBLIC_KEY)); - - if (d.containsKey(MSG)) { - list.add(d.getString(MSG)); - } - return list; - } - - private BdfList encodeResponse(BdfDictionary d) throws FormatException { - BdfList list = BdfList.of(TYPE_RESPONSE, d.getRaw(SESSION_ID), - d.getBoolean(ACCEPT)); - - if (d.getBoolean(ACCEPT)) { - list.add(d.getLong(TIME)); - list.add(d.getRaw(E_PUBLIC_KEY)); - list.add(d.getDictionary(TRANSPORT)); - } - return list; - } - - private BdfList encodeAck(BdfDictionary d) throws FormatException { - return BdfList.of(TYPE_ACK, d.getRaw(SESSION_ID), d.getRaw(MAC), - d.getRaw(SIGNATURE)); - } - - private BdfList encodeAbort(BdfDictionary d) throws FormatException { - return BdfList.of(TYPE_ABORT, d.getRaw(SESSION_ID)); - } - -} diff --git a/briar-core/src/main/java/org/briarproject/briar/introduction2/MessageType.java b/briar-core/src/main/java/org/briarproject/briar/introduction/MessageType.java similarity index 92% rename from briar-core/src/main/java/org/briarproject/briar/introduction2/MessageType.java rename to briar-core/src/main/java/org/briarproject/briar/introduction/MessageType.java index bb34b7da3e8040c979ded40546b423dd46172dc1..67365399b0bc22a8627bdf6bba31355116be22ab 100644 --- a/briar-core/src/main/java/org/briarproject/briar/introduction2/MessageType.java +++ b/briar-core/src/main/java/org/briarproject/briar/introduction/MessageType.java @@ -1,4 +1,4 @@ -package org.briarproject.briar.introduction2; +package org.briarproject.briar.introduction; import org.briarproject.bramble.api.FormatException; import org.briarproject.bramble.api.nullsafety.NotNullByDefault; diff --git a/briar-core/src/main/java/org/briarproject/briar/introduction2/PeerSession.java b/briar-core/src/main/java/org/briarproject/briar/introduction/PeerSession.java similarity index 91% rename from briar-core/src/main/java/org/briarproject/briar/introduction2/PeerSession.java rename to briar-core/src/main/java/org/briarproject/briar/introduction/PeerSession.java index e2f8b7c46fbb42f413a35c8a182a3de4e26c29c2..3c453d2fa9e8cc311623768c48362f65b197a2ad 100644 --- a/briar-core/src/main/java/org/briarproject/briar/introduction2/PeerSession.java +++ b/briar-core/src/main/java/org/briarproject/briar/introduction/PeerSession.java @@ -1,4 +1,4 @@ -package org.briarproject.briar.introduction2; +package org.briarproject.briar.introduction; import org.briarproject.bramble.api.nullsafety.NotNullByDefault; import org.briarproject.bramble.api.sync.GroupId; diff --git a/briar-core/src/main/java/org/briarproject/briar/introduction2/ProtocolEngine.java b/briar-core/src/main/java/org/briarproject/briar/introduction/ProtocolEngine.java similarity index 96% rename from briar-core/src/main/java/org/briarproject/briar/introduction2/ProtocolEngine.java rename to briar-core/src/main/java/org/briarproject/briar/introduction/ProtocolEngine.java index 083296ca0cb00cc8e160ed36c12c821dc63e6c92..e3766c91a4556b3bde9e40c2371079a229ef4da7 100644 --- a/briar-core/src/main/java/org/briarproject/briar/introduction2/ProtocolEngine.java +++ b/briar-core/src/main/java/org/briarproject/briar/introduction/ProtocolEngine.java @@ -1,4 +1,4 @@ -package org.briarproject.briar.introduction2; +package org.briarproject.briar.introduction; import org.briarproject.bramble.api.FormatException; import org.briarproject.bramble.api.db.DbException; diff --git a/briar-core/src/main/java/org/briarproject/briar/introduction2/RequestMessage.java b/briar-core/src/main/java/org/briarproject/briar/introduction/RequestMessage.java similarity index 88% rename from briar-core/src/main/java/org/briarproject/briar/introduction2/RequestMessage.java rename to briar-core/src/main/java/org/briarproject/briar/introduction/RequestMessage.java index 470fb39662e3cce6f24d2c21bc3d7402f6657d7a..743e87af872d898f8535b9311d60eb9650622562 100644 --- a/briar-core/src/main/java/org/briarproject/briar/introduction2/RequestMessage.java +++ b/briar-core/src/main/java/org/briarproject/briar/introduction/RequestMessage.java @@ -1,4 +1,4 @@ -package org.briarproject.briar.introduction2; +package org.briarproject.briar.introduction; import org.briarproject.bramble.api.identity.Author; import org.briarproject.bramble.api.nullsafety.NotNullByDefault; @@ -10,7 +10,7 @@ import javax.annotation.concurrent.Immutable; @Immutable @NotNullByDefault -class RequestMessage extends IntroductionMessage { +class RequestMessage extends AbstractIntroductionMessage { private final Author author; @Nullable diff --git a/briar-core/src/main/java/org/briarproject/briar/introduction2/Session.java b/briar-core/src/main/java/org/briarproject/briar/introduction/Session.java similarity index 87% rename from briar-core/src/main/java/org/briarproject/briar/introduction2/Session.java rename to briar-core/src/main/java/org/briarproject/briar/introduction/Session.java index ca2a89c190119dc9aae058d900318abc00b7a259..ddf04d044eb9e95522686d0c2113745a556ed91d 100644 --- a/briar-core/src/main/java/org/briarproject/briar/introduction2/Session.java +++ b/briar-core/src/main/java/org/briarproject/briar/introduction/Session.java @@ -1,8 +1,8 @@ -package org.briarproject.briar.introduction2; +package org.briarproject.briar.introduction; import org.briarproject.bramble.api.nullsafety.NotNullByDefault; import org.briarproject.briar.api.client.SessionId; -import org.briarproject.briar.api.introduction2.Role; +import org.briarproject.briar.api.introduction.Role; import javax.annotation.concurrent.Immutable; diff --git a/briar-core/src/main/java/org/briarproject/briar/introduction2/SessionEncoder.java b/briar-core/src/main/java/org/briarproject/briar/introduction/SessionEncoder.java similarity index 57% rename from briar-core/src/main/java/org/briarproject/briar/introduction2/SessionEncoder.java rename to briar-core/src/main/java/org/briarproject/briar/introduction/SessionEncoder.java index 4b45c39ca29b77057ac116e7bcc4aaee34a5f434..70cfff1bba1077426bc4e087cf60a6627829ae3b 100644 --- a/briar-core/src/main/java/org/briarproject/briar/introduction2/SessionEncoder.java +++ b/briar-core/src/main/java/org/briarproject/briar/introduction/SessionEncoder.java @@ -1,11 +1,16 @@ -package org.briarproject.briar.introduction2; +package org.briarproject.briar.introduction; import org.briarproject.bramble.api.data.BdfDictionary; +import org.briarproject.bramble.api.identity.Author; import org.briarproject.bramble.api.nullsafety.NotNullByDefault; @NotNullByDefault interface SessionEncoder { + BdfDictionary getIntroduceeSessionsByIntroducerQuery(Author introducer); + + BdfDictionary getIntroducerSessionsQuery(); + BdfDictionary encodeIntroducerSession(IntroducerSession s); BdfDictionary encodeIntroduceeSession(IntroduceeSession s); diff --git a/briar-core/src/main/java/org/briarproject/briar/introduction2/SessionEncoderImpl.java b/briar-core/src/main/java/org/briarproject/briar/introduction/SessionEncoderImpl.java similarity index 54% rename from briar-core/src/main/java/org/briarproject/briar/introduction2/SessionEncoderImpl.java rename to briar-core/src/main/java/org/briarproject/briar/introduction/SessionEncoderImpl.java index 3bce33d853d6cf57c8fc9cd7ade56e4718a2d501..9cf17a2d0fcb7dd181a438847ce23133eb2ca680 100644 --- a/briar-core/src/main/java/org/briarproject/briar/introduction2/SessionEncoderImpl.java +++ b/briar-core/src/main/java/org/briarproject/briar/introduction/SessionEncoderImpl.java @@ -1,11 +1,13 @@ -package org.briarproject.briar.introduction2; +package org.briarproject.briar.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 org.briarproject.briar.introduction2.IntroducerSession.Introducee; +import org.briarproject.briar.introduction.IntroducerSession.Introducee; import java.util.Map; @@ -14,28 +16,30 @@ import javax.annotation.concurrent.Immutable; import javax.inject.Inject; import static org.briarproject.bramble.api.data.BdfDictionary.NULL_VALUE; -import static org.briarproject.briar.introduction2.IntroductionConstants.SESSION_KEY_ACCEPT_TIMESTAMP; -import static org.briarproject.briar.introduction2.IntroductionConstants.SESSION_KEY_AUTHOR; -import static org.briarproject.briar.introduction2.IntroductionConstants.SESSION_KEY_EPHEMERAL_PRIVATE_KEY; -import static org.briarproject.briar.introduction2.IntroductionConstants.SESSION_KEY_EPHEMERAL_PUBLIC_KEY; -import static org.briarproject.briar.introduction2.IntroductionConstants.SESSION_KEY_GROUP_ID; -import static org.briarproject.briar.introduction2.IntroductionConstants.SESSION_KEY_INTRODUCEE_1; -import static org.briarproject.briar.introduction2.IntroductionConstants.SESSION_KEY_INTRODUCEE_2; -import static org.briarproject.briar.introduction2.IntroductionConstants.SESSION_KEY_INTRODUCER; -import static org.briarproject.briar.introduction2.IntroductionConstants.SESSION_KEY_LAST_LOCAL_MESSAGE_ID; -import static org.briarproject.briar.introduction2.IntroductionConstants.SESSION_KEY_LAST_REMOTE_MESSAGE_ID; -import static org.briarproject.briar.introduction2.IntroductionConstants.SESSION_KEY_LOCAL_TIMESTAMP; -import static org.briarproject.briar.introduction2.IntroductionConstants.SESSION_KEY_MASTER_KEY; -import static org.briarproject.briar.introduction2.IntroductionConstants.SESSION_KEY_REMOTE_ACCEPT_TIMESTAMP; -import static org.briarproject.briar.introduction2.IntroductionConstants.SESSION_KEY_REMOTE_AUTHOR; -import static org.briarproject.briar.introduction2.IntroductionConstants.SESSION_KEY_REMOTE_EPHEMERAL_PUBLIC_KEY; -import static org.briarproject.briar.introduction2.IntroductionConstants.SESSION_KEY_REMOTE_TRANSPORT_PROPERTIES; -import static org.briarproject.briar.introduction2.IntroductionConstants.SESSION_KEY_REQUEST_TIMESTAMP; -import static org.briarproject.briar.introduction2.IntroductionConstants.SESSION_KEY_ROLE; -import static org.briarproject.briar.introduction2.IntroductionConstants.SESSION_KEY_SESSION_ID; -import static org.briarproject.briar.introduction2.IntroductionConstants.SESSION_KEY_STATE; -import static org.briarproject.briar.introduction2.IntroductionConstants.SESSION_KEY_TRANSPORT_KEYS; -import static org.briarproject.briar.introduction2.IntroductionConstants.SESSION_KEY_TRANSPORT_PROPERTIES; +import static org.briarproject.briar.api.introduction.Role.INTRODUCEE; +import static org.briarproject.briar.api.introduction.Role.INTRODUCER; +import static org.briarproject.briar.introduction.IntroductionConstants.SESSION_KEY_ACCEPT_TIMESTAMP; +import static org.briarproject.briar.introduction.IntroductionConstants.SESSION_KEY_AUTHOR; +import static org.briarproject.briar.introduction.IntroductionConstants.SESSION_KEY_EPHEMERAL_PRIVATE_KEY; +import static org.briarproject.briar.introduction.IntroductionConstants.SESSION_KEY_EPHEMERAL_PUBLIC_KEY; +import static org.briarproject.briar.introduction.IntroductionConstants.SESSION_KEY_GROUP_ID; +import static org.briarproject.briar.introduction.IntroductionConstants.SESSION_KEY_INTRODUCEE_1; +import static org.briarproject.briar.introduction.IntroductionConstants.SESSION_KEY_INTRODUCEE_2; +import static org.briarproject.briar.introduction.IntroductionConstants.SESSION_KEY_INTRODUCER; +import static org.briarproject.briar.introduction.IntroductionConstants.SESSION_KEY_LAST_LOCAL_MESSAGE_ID; +import static org.briarproject.briar.introduction.IntroductionConstants.SESSION_KEY_LAST_REMOTE_MESSAGE_ID; +import static org.briarproject.briar.introduction.IntroductionConstants.SESSION_KEY_LOCAL_TIMESTAMP; +import static org.briarproject.briar.introduction.IntroductionConstants.SESSION_KEY_MASTER_KEY; +import static org.briarproject.briar.introduction.IntroductionConstants.SESSION_KEY_REMOTE_ACCEPT_TIMESTAMP; +import static org.briarproject.briar.introduction.IntroductionConstants.SESSION_KEY_REMOTE_AUTHOR; +import static org.briarproject.briar.introduction.IntroductionConstants.SESSION_KEY_REMOTE_EPHEMERAL_PUBLIC_KEY; +import static org.briarproject.briar.introduction.IntroductionConstants.SESSION_KEY_REMOTE_TRANSPORT_PROPERTIES; +import static org.briarproject.briar.introduction.IntroductionConstants.SESSION_KEY_REQUEST_TIMESTAMP; +import static org.briarproject.briar.introduction.IntroductionConstants.SESSION_KEY_ROLE; +import static org.briarproject.briar.introduction.IntroductionConstants.SESSION_KEY_SESSION_ID; +import static org.briarproject.briar.introduction.IntroductionConstants.SESSION_KEY_STATE; +import static org.briarproject.briar.introduction.IntroductionConstants.SESSION_KEY_TRANSPORT_KEYS; +import static org.briarproject.briar.introduction.IntroductionConstants.SESSION_KEY_TRANSPORT_PROPERTIES; @Immutable @NotNullByDefault @@ -48,6 +52,23 @@ class SessionEncoderImpl implements SessionEncoder { 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, INTRODUCER.getValue()) + ); + } + @Override public BdfDictionary encodeIntroducerSession(IntroducerSession s) { BdfDictionary d = encodeSession(s); diff --git a/briar-core/src/main/java/org/briarproject/briar/introduction2/SessionParser.java b/briar-core/src/main/java/org/briarproject/briar/introduction/SessionParser.java similarity index 86% rename from briar-core/src/main/java/org/briarproject/briar/introduction2/SessionParser.java rename to briar-core/src/main/java/org/briarproject/briar/introduction/SessionParser.java index dd3fba09cb69c17d94a0e04ec94ad921541471ae..c58cac3d951012cbd1298f2283b97e2747f13681 100644 --- a/briar-core/src/main/java/org/briarproject/briar/introduction2/SessionParser.java +++ b/briar-core/src/main/java/org/briarproject/briar/introduction/SessionParser.java @@ -1,11 +1,11 @@ -package org.briarproject.briar.introduction2; +package org.briarproject.briar.introduction; 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.briar.api.introduction2.Role; +import org.briarproject.briar.api.introduction.Role; @NotNullByDefault interface SessionParser { diff --git a/briar-core/src/main/java/org/briarproject/briar/introduction2/SessionParserImpl.java b/briar-core/src/main/java/org/briarproject/briar/introduction/SessionParserImpl.java similarity index 69% rename from briar-core/src/main/java/org/briarproject/briar/introduction2/SessionParserImpl.java rename to briar-core/src/main/java/org/briarproject/briar/introduction/SessionParserImpl.java index dbb609fc1a49ec362630a08282b3a7857db8a7f1..f269b497301ce261335edcfbeb5170aa95f45c8b 100644 --- a/briar-core/src/main/java/org/briarproject/briar/introduction2/SessionParserImpl.java +++ b/briar-core/src/main/java/org/briarproject/briar/introduction/SessionParserImpl.java @@ -1,4 +1,4 @@ -package org.briarproject.briar.introduction2; +package org.briarproject.briar.introduction; import org.briarproject.bramble.api.FormatException; import org.briarproject.bramble.api.client.ClientHelper; @@ -12,8 +12,8 @@ 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.briar.api.introduction2.Role; -import org.briarproject.briar.introduction2.IntroducerSession.Introducee; +import org.briarproject.briar.api.introduction.Role; +import org.briarproject.briar.introduction.IntroducerSession.Introducee; import java.util.HashMap; import java.util.Map; @@ -22,30 +22,30 @@ import javax.annotation.Nullable; import javax.annotation.concurrent.Immutable; import javax.inject.Inject; -import static org.briarproject.briar.introduction2.IntroductionConstants.SESSION_KEY_ACCEPT_TIMESTAMP; -import static org.briarproject.briar.introduction2.IntroductionConstants.SESSION_KEY_AUTHOR; -import static org.briarproject.briar.introduction2.IntroductionConstants.SESSION_KEY_EPHEMERAL_PRIVATE_KEY; -import static org.briarproject.briar.introduction2.IntroductionConstants.SESSION_KEY_EPHEMERAL_PUBLIC_KEY; -import static org.briarproject.briar.introduction2.IntroductionConstants.SESSION_KEY_GROUP_ID; -import static org.briarproject.briar.introduction2.IntroductionConstants.SESSION_KEY_INTRODUCEE_1; -import static org.briarproject.briar.introduction2.IntroductionConstants.SESSION_KEY_INTRODUCEE_2; -import static org.briarproject.briar.introduction2.IntroductionConstants.SESSION_KEY_INTRODUCER; -import static org.briarproject.briar.introduction2.IntroductionConstants.SESSION_KEY_LAST_LOCAL_MESSAGE_ID; -import static org.briarproject.briar.introduction2.IntroductionConstants.SESSION_KEY_LAST_REMOTE_MESSAGE_ID; -import static org.briarproject.briar.introduction2.IntroductionConstants.SESSION_KEY_LOCAL_TIMESTAMP; -import static org.briarproject.briar.introduction2.IntroductionConstants.SESSION_KEY_MASTER_KEY; -import static org.briarproject.briar.introduction2.IntroductionConstants.SESSION_KEY_REMOTE_ACCEPT_TIMESTAMP; -import static org.briarproject.briar.introduction2.IntroductionConstants.SESSION_KEY_REMOTE_AUTHOR; -import static org.briarproject.briar.introduction2.IntroductionConstants.SESSION_KEY_REMOTE_EPHEMERAL_PUBLIC_KEY; -import static org.briarproject.briar.introduction2.IntroductionConstants.SESSION_KEY_REMOTE_TRANSPORT_PROPERTIES; -import static org.briarproject.briar.introduction2.IntroductionConstants.SESSION_KEY_REQUEST_TIMESTAMP; -import static org.briarproject.briar.introduction2.IntroductionConstants.SESSION_KEY_ROLE; -import static org.briarproject.briar.introduction2.IntroductionConstants.SESSION_KEY_SESSION_ID; -import static org.briarproject.briar.introduction2.IntroductionConstants.SESSION_KEY_STATE; -import static org.briarproject.briar.introduction2.IntroductionConstants.SESSION_KEY_TRANSPORT_KEYS; -import static org.briarproject.briar.introduction2.IntroductionConstants.SESSION_KEY_TRANSPORT_PROPERTIES; -import static org.briarproject.briar.api.introduction2.Role.INTRODUCEE; -import static org.briarproject.briar.api.introduction2.Role.INTRODUCER; +import static org.briarproject.briar.introduction.IntroductionConstants.SESSION_KEY_ACCEPT_TIMESTAMP; +import static org.briarproject.briar.introduction.IntroductionConstants.SESSION_KEY_AUTHOR; +import static org.briarproject.briar.introduction.IntroductionConstants.SESSION_KEY_EPHEMERAL_PRIVATE_KEY; +import static org.briarproject.briar.introduction.IntroductionConstants.SESSION_KEY_EPHEMERAL_PUBLIC_KEY; +import static org.briarproject.briar.introduction.IntroductionConstants.SESSION_KEY_GROUP_ID; +import static org.briarproject.briar.introduction.IntroductionConstants.SESSION_KEY_INTRODUCEE_1; +import static org.briarproject.briar.introduction.IntroductionConstants.SESSION_KEY_INTRODUCEE_2; +import static org.briarproject.briar.introduction.IntroductionConstants.SESSION_KEY_INTRODUCER; +import static org.briarproject.briar.introduction.IntroductionConstants.SESSION_KEY_LAST_LOCAL_MESSAGE_ID; +import static org.briarproject.briar.introduction.IntroductionConstants.SESSION_KEY_LAST_REMOTE_MESSAGE_ID; +import static org.briarproject.briar.introduction.IntroductionConstants.SESSION_KEY_LOCAL_TIMESTAMP; +import static org.briarproject.briar.introduction.IntroductionConstants.SESSION_KEY_MASTER_KEY; +import static org.briarproject.briar.introduction.IntroductionConstants.SESSION_KEY_REMOTE_ACCEPT_TIMESTAMP; +import static org.briarproject.briar.introduction.IntroductionConstants.SESSION_KEY_REMOTE_AUTHOR; +import static org.briarproject.briar.introduction.IntroductionConstants.SESSION_KEY_REMOTE_EPHEMERAL_PUBLIC_KEY; +import static org.briarproject.briar.introduction.IntroductionConstants.SESSION_KEY_REMOTE_TRANSPORT_PROPERTIES; +import static org.briarproject.briar.introduction.IntroductionConstants.SESSION_KEY_REQUEST_TIMESTAMP; +import static org.briarproject.briar.introduction.IntroductionConstants.SESSION_KEY_ROLE; +import static org.briarproject.briar.introduction.IntroductionConstants.SESSION_KEY_SESSION_ID; +import static org.briarproject.briar.introduction.IntroductionConstants.SESSION_KEY_STATE; +import static org.briarproject.briar.introduction.IntroductionConstants.SESSION_KEY_TRANSPORT_KEYS; +import static org.briarproject.briar.introduction.IntroductionConstants.SESSION_KEY_TRANSPORT_PROPERTIES; +import static org.briarproject.briar.api.introduction.Role.INTRODUCEE; +import static org.briarproject.briar.api.introduction.Role.INTRODUCER; @Immutable @NotNullByDefault diff --git a/briar-core/src/main/java/org/briarproject/briar/introduction/State.java b/briar-core/src/main/java/org/briarproject/briar/introduction/State.java new file mode 100644 index 0000000000000000000000000000000000000000..3063f9bd83d1761fc6c4b5446a482b00f0329f80 --- /dev/null +++ b/briar-core/src/main/java/org/briarproject/briar/introduction/State.java @@ -0,0 +1,7 @@ +package org.briarproject.briar.introduction; + +interface State { + + int getValue(); + +} diff --git a/briar-core/src/main/java/org/briarproject/briar/introduction2/IntroductionManagerImpl.java b/briar-core/src/main/java/org/briarproject/briar/introduction2/IntroductionManagerImpl.java deleted file mode 100644 index 55a6e552a5f3c672a754c99e3de09d4058dab631..0000000000000000000000000000000000000000 --- a/briar-core/src/main/java/org/briarproject/briar/introduction2/IntroductionManagerImpl.java +++ /dev/null @@ -1,459 +0,0 @@ -package org.briarproject.briar.introduction2; - -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.ContactId; -import org.briarproject.bramble.api.contact.ContactManager.ContactHook; -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.nullsafety.NotNullByDefault; -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.sync.MessageStatus; -import org.briarproject.briar.api.client.MessageTracker; -import org.briarproject.briar.api.client.SessionId; -import org.briarproject.briar.api.introduction2.IntroductionManager; -import org.briarproject.briar.api.introduction2.IntroductionMessage; -import org.briarproject.briar.api.introduction2.IntroductionRequest; -import org.briarproject.briar.api.introduction2.IntroductionResponse; -import org.briarproject.briar.api.introduction2.Role; -import org.briarproject.briar.client.ConversationClientImpl; - -import java.util.ArrayList; -import java.util.Collection; -import java.util.List; -import java.util.Map; - -import javax.annotation.Nullable; -import javax.annotation.concurrent.Immutable; -import javax.inject.Inject; - -import static org.briarproject.bramble.api.sync.Group.Visibility.SHARED; -import static org.briarproject.briar.api.introduction2.Role.INTRODUCEE; -import static org.briarproject.briar.api.introduction2.Role.INTRODUCER; -import static org.briarproject.briar.introduction2.IntroductionConstants.GROUP_KEY_CONTACT_ID; -import static org.briarproject.briar.introduction2.MessageType.ABORT; -import static org.briarproject.briar.introduction2.MessageType.ACCEPT; -import static org.briarproject.briar.introduction2.MessageType.ACTIVATE; -import static org.briarproject.briar.introduction2.MessageType.AUTH; -import static org.briarproject.briar.introduction2.MessageType.DECLINE; -import static org.briarproject.briar.introduction2.MessageType.REQUEST; - -@Immutable -@NotNullByDefault -class IntroductionManagerImpl extends ConversationClientImpl - implements IntroductionManager, Client, ContactHook { - - private final ContactGroupFactory contactGroupFactory; - private final MessageParser messageParser; - private final SessionEncoder sessionEncoder; - private final SessionParser sessionParser; - private final IntroducerProtocolEngine introducerEngine; - private final IntroduceeProtocolEngine introduceeEngine; - private final IntroductionCrypto crypto; - private final IdentityManager identityManager; - - @Inject - IntroductionManagerImpl( - DatabaseComponent db, - ClientHelper clientHelper, - MetadataParser metadataParser, - MessageTracker messageTracker, - ContactGroupFactory contactGroupFactory, - MessageParser messageParser, - SessionEncoder sessionEncoder, - SessionParser sessionParser, - IntroducerProtocolEngine introducerEngine, - IntroduceeProtocolEngine introduceeEngine, - IntroductionCrypto crypto, - IdentityManager identityManager) { - super(db, clientHelper, metadataParser, messageTracker); - this.contactGroupFactory = contactGroupFactory; - this.messageParser = messageParser; - this.sessionEncoder = sessionEncoder; - this.sessionParser = sessionParser; - this.introducerEngine = introducerEngine; - this.introduceeEngine = introduceeEngine; - this.crypto = crypto; - this.identityManager = identityManager; - } - - @Override - public void createLocalState(Transaction txn) throws DbException { - // Create a local group to store protocol sessions - Group localGroup = getLocalGroup(); - 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.getContacts(txn)) addingContact(txn, c); - } - - @Override - // TODO adapt to use upcoming ClientVersioning client - public void addingContact(Transaction txn, Contact c) throws DbException { - // Create a group to share with the contact - Group g = getContactGroup(c); - // Return if we've already set things up for this contact - if (db.containsGroup(txn, g.getId())) return; - // Store the group and share it with the contact - db.addGroup(txn, g); - db.setGroupVisibility(txn, c.getId(), g.getId(), SHARED); - // 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 removingContact(Transaction txn, Contact c) throws DbException { - // Remove the contact group (all messages will be removed with it) - db.removeGroup(txn, getContactGroup(c)); - // TODO abort other sessions the contact is involved in - } - - @Override - public Group getContactGroup(Contact c) { - return contactGroupFactory - .createContactGroup(CLIENT_ID, CLIENT_VERSION, c); - } - - @Override - protected boolean incomingMessage(Transaction txn, Message m, BdfList body, - BdfDictionary bdfMeta) throws DbException, FormatException { - // Parse the metadata - MessageMetadata meta = messageParser.parseMetadata(bdfMeta); - // Look up the session, if there is one - SessionId sessionId = meta.getSessionId(); - IntroduceeSession newIntroduceeSession = null; - if (sessionId == null) { - if (meta.getMessageType() != REQUEST) throw new AssertionError(); - newIntroduceeSession = createNewIntroduceeSession(txn, m, body); - sessionId = newIntroduceeSession.getSessionId(); - } - StoredSession ss = getSession(txn, sessionId); - // Handle the message - Session session; - MessageId storageId; - if (ss == null) { - if (meta.getMessageType() != REQUEST) throw new FormatException(); - if (newIntroduceeSession == null) throw new AssertionError(); - storageId = createStorageId(txn); - session = handleMessage(txn, m, body, meta.getMessageType(), - newIntroduceeSession, introduceeEngine); - } else { - storageId = ss.storageId; - Role role = sessionParser.getRole(ss.bdfSession); - if (role == INTRODUCER) { - session = handleMessage(txn, m, body, meta.getMessageType(), - sessionParser.parseIntroducerSession(ss.bdfSession), - introducerEngine); - } else if (role == INTRODUCEE) { - session = handleMessage(txn, m, body, meta.getMessageType(), - sessionParser.parseIntroduceeSession(m.getGroupId(), - ss.bdfSession), introduceeEngine); - } else throw new AssertionError(); - } - // Store the updated session - storeSession(txn, storageId, session); - return false; - } - - private IntroduceeSession createNewIntroduceeSession(Transaction txn, - Message m, BdfList body) throws DbException, FormatException { - ContactId introducerId = getContactId(txn, m.getGroupId()); - Author introducer = db.getContact(txn, introducerId).getAuthor(); - Author alice = identityManager.getLocalAuthor(txn); - Author bob = messageParser.parseRequestMessage(m, body).getAuthor(); - SessionId sessionId = crypto.getSessionId(introducer, alice, bob); - return IntroduceeSession - .getInitial(m.getGroupId(), sessionId, introducer, bob); - } - - private <S extends Session> S handleMessage(Transaction txn, Message m, - BdfList body, MessageType type, S session, ProtocolEngine<S> engine) - throws DbException, FormatException { - if (type == REQUEST) { - RequestMessage request = messageParser.parseRequestMessage(m, body); - return engine.onRequestMessage(txn, session, request); - } else if (type == ACCEPT) { - AcceptMessage accept = messageParser.parseAcceptMessage(m, body); - return engine.onAcceptMessage(txn, session, accept); - } else if (type == DECLINE) { - DeclineMessage decline = messageParser.parseDeclineMessage(m, body); - return engine.onDeclineMessage(txn, session, decline); - } else if (type == AUTH) { - AuthMessage auth = messageParser.parseAuthMessage(m, body); - return engine.onAuthMessage(txn, session, auth); - } else if (type == ACTIVATE) { - ActivateMessage activate = - messageParser.parseActivateMessage(m, body); - return engine.onActivateMessage(txn, session, activate); - } else if (type == ABORT) { - AbortMessage abort = messageParser.parseAbortMessage(m, body); - return engine.onAbortMessage(txn, session, abort); - } else { - 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, getLocalGroup().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()); - } - - 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()); - } - - private MessageId createStorageId(Transaction txn) throws DbException { - Message m = clientHelper - .createMessageForStoringMetadata(getLocalGroup().getId()); - db.addLocalMessage(txn, m, new Metadata(), false); - return m.getId(); - } - - private void storeSession(Transaction txn, MessageId storageId, - Session session) throws DbException, FormatException { - BdfDictionary d; - if (session.getRole() == INTRODUCER) { - d = sessionEncoder - .encodeIntroducerSession((IntroducerSession) session); - } else if (session.getRole() == INTRODUCEE) { - d = sessionEncoder - .encodeIntroduceeSession((IntroduceeSession) session); - } else { - throw new AssertionError(); - } - clientHelper.mergeMessageMetadata(txn, storageId, d); - } - - @Override - public void makeIntroduction(Contact c1, Contact c2, @Nullable String msg, - 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, c1.getAuthor(), - c2.getAuthor()); - StoredSession ss = getSession(txn, sessionId); - // Create or parse the session - IntroducerSession session; - MessageId storageId; - if (ss == null) { - // This is the first request - create a new session - GroupId groupId1 = getContactGroup(c1).getId(); - GroupId groupId2 = getContactGroup(c2).getId(); - session = new IntroducerSession(sessionId, groupId1, - c1.getAuthor(), groupId2, c2.getAuthor()); - storageId = createStorageId(txn); - } else { - // An earlier request exists, so we already have a session - session = sessionParser.parseIntroducerSession(ss.bdfSession); - storageId = ss.storageId; - } - // Handle the request action - session = introducerEngine - .onRequestAction(txn, session, msg, timestamp); - // Store the updated session - storeSession(txn, storageId, session); - db.commitTransaction(txn); - } catch (FormatException e) { - throw new DbException(e); - } finally { - db.endTransaction(txn); - } - } - - @Override - public void acceptIntroduction(ContactId contactId, SessionId sessionId, - long timestamp) throws DbException { - respondToRequest(contactId, sessionId, timestamp, true); - } - - @Override - public void declineIntroduction(ContactId contactId, SessionId sessionId, - long timestamp) throws DbException { - respondToRequest(contactId, sessionId, timestamp, false); - } - - private void respondToRequest(ContactId contactId, SessionId sessionId, - long timestamp, boolean accept) throws DbException { - Transaction txn = db.startTransaction(false); - try { - // Look up the session - StoredSession ss = getSession(txn, sessionId); - if (ss == null) throw new IllegalArgumentException(); - // Parse the session - Contact contact = db.getContact(txn, contactId); - GroupId contactGroupId = getContactGroup(contact).getId(); - IntroduceeSession session = sessionParser - .parseIntroduceeSession(contactGroupId, ss.bdfSession); - // Handle the join or leave action - if (accept) { - session = introduceeEngine - .onAcceptAction(txn, session, timestamp); - } else { - session = introduceeEngine - .onDeclineAction(txn, session, timestamp); - } - // Store the updated session - storeSession(txn, ss.storageId, session); - db.commitTransaction(txn); - } catch (FormatException e) { - throw new DbException(e); - } finally { - db.endTransaction(txn); - } - } - - @Override - public Collection<IntroductionMessage> getIntroductionMessages(ContactId c) - throws DbException { - List<IntroductionMessage> messages; - Transaction txn = db.startTransaction(true); - try { - Contact contact = db.getContact(txn, c); - GroupId contactGroupId = getContactGroup(contact).getId(); - BdfDictionary query = messageParser.getMessagesVisibleInUiQuery(); - Map<MessageId, BdfDictionary> results = clientHelper - .getMessageMetadataAsDictionary(txn, contactGroupId, query); - messages = new ArrayList<>(results.size()); - for (Map.Entry<MessageId, BdfDictionary> e : results.entrySet()) { - MessageId m = e.getKey(); - MessageMetadata meta = - messageParser.parseMetadata(e.getValue()); - MessageStatus status = db.getMessageStatus(txn, c, m); - StoredSession ss = getSession(txn, meta.getSessionId()); - if (ss == null) throw new AssertionError(); - MessageType type = meta.getMessageType(); - if (type == REQUEST) { - messages.add( - parseInvitationRequest(txn, contactGroupId, m, - meta, status, ss.bdfSession)); - } else if (type == ACCEPT) { - messages.add( - parseInvitationResponse(txn, contactGroupId, m, - meta, status, ss.bdfSession, true)); - } else if (type == DECLINE) { - messages.add( - parseInvitationResponse(txn, contactGroupId, m, - meta, status, ss.bdfSession, false)); - } - } - db.commitTransaction(txn); - } catch (FormatException e) { - throw new DbException(e); - } finally { - db.endTransaction(txn); - } - return messages; - } - - private IntroductionRequest parseInvitationRequest(Transaction txn, - GroupId contactGroupId, MessageId m, MessageMetadata meta, - MessageStatus status, BdfDictionary bdfSession) - throws DbException, FormatException { - Role role = sessionParser.getRole(bdfSession); - SessionId sessionId; - Author author; - if (role == INTRODUCER) { - IntroducerSession session = - sessionParser.parseIntroducerSession(bdfSession); - sessionId = session.getSessionId(); - LocalAuthor localAuthor = identityManager.getLocalAuthor(txn); - if (localAuthor.equals(session.getIntroducee1().author)) { - author = session.getIntroducee2().author; - } else { - author = session.getIntroducee1().author; - } - } else if (role == INTRODUCEE) { - IntroduceeSession session = sessionParser - .parseIntroduceeSession(contactGroupId, bdfSession); - sessionId = session.getSessionId(); - author = session.getRemoteAuthor(); - } else throw new AssertionError(); - String message = ""; // TODO - boolean contactExists = false; // TODO - - return new IntroductionRequest(sessionId, m, contactGroupId, - role, meta.getTimestamp(), meta.isLocal(), - status.isSent(), status.isSeen(), meta.isRead(), - author.getName(), false, message, !meta.isAvailableToAnswer(), - contactExists); - } - - private IntroductionResponse parseInvitationResponse(Transaction txn, - GroupId contactGroupId, MessageId m, MessageMetadata meta, - MessageStatus status, BdfDictionary bdfSession, boolean accept) - throws FormatException, DbException { - Role role = sessionParser.getRole(bdfSession); - SessionId sessionId; - Author author; - if (role == INTRODUCER) { - IntroducerSession session = - sessionParser.parseIntroducerSession(bdfSession); - sessionId = session.getSessionId(); - LocalAuthor localAuthor = identityManager.getLocalAuthor(txn); - if (localAuthor.equals(session.getIntroducee1().author)) { - author = session.getIntroducee2().author; - } else { - author = session.getIntroducee1().author; - } - } else if (role == INTRODUCEE) { - IntroduceeSession session = sessionParser - .parseIntroduceeSession(contactGroupId, bdfSession); - sessionId = session.getSessionId(); - author = session.getRemoteAuthor(); - } else throw new AssertionError(); - return new IntroductionResponse(sessionId, m, contactGroupId, - role, meta.getTimestamp(), meta.isLocal(), status.isSent(), - status.isSeen(), meta.isRead(), author.getName(), accept); - } - - private Group getLocalGroup() { - return contactGroupFactory.createLocalGroup(CLIENT_ID, CLIENT_VERSION); - } - - 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/briar-core/src/main/java/org/briarproject/briar/introduction2/IntroductionModule.java b/briar-core/src/main/java/org/briarproject/briar/introduction2/IntroductionModule.java deleted file mode 100644 index 1a64538ea11db9ce614d96a50336a5e1e20007d5..0000000000000000000000000000000000000000 --- a/briar-core/src/main/java/org/briarproject/briar/introduction2/IntroductionModule.java +++ /dev/null @@ -1,39 +0,0 @@ -package org.briarproject.briar.introduction2; - -import org.briarproject.bramble.api.client.ClientHelper; -import org.briarproject.bramble.api.data.MetadataEncoder; -import org.briarproject.bramble.api.sync.ValidationManager; -import org.briarproject.bramble.api.system.Clock; - -import javax.inject.Inject; -import javax.inject.Singleton; - -import dagger.Module; -import dagger.Provides; - -import static org.briarproject.briar.api.introduction.IntroductionManager.CLIENT_ID; - -@Module -public class IntroductionModule { - - public static class EagerSingletons { - @Inject - IntroductionValidator introductionValidator; - } - - @Provides - @Singleton - IntroductionValidator provideValidator(ValidationManager validationManager, - MessageEncoder messageEncoder, MetadataEncoder metadataEncoder, - ClientHelper clientHelper, Clock clock) { - - IntroductionValidator introductionValidator = - new IntroductionValidator(messageEncoder, clientHelper, - metadataEncoder, clock); - validationManager.registerMessageValidator(CLIENT_ID, - introductionValidator); - - return introductionValidator; - } - -} diff --git a/briar-core/src/main/java/org/briarproject/briar/introduction2/IntroductionValidator.java b/briar-core/src/main/java/org/briarproject/briar/introduction2/IntroductionValidator.java deleted file mode 100644 index 1bdf07ff640a0264385d535361aa5862e4238407..0000000000000000000000000000000000000000 --- a/briar-core/src/main/java/org/briarproject/briar/introduction2/IntroductionValidator.java +++ /dev/null @@ -1,168 +0,0 @@ -package org.briarproject.briar.introduction2; - -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.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 org.briarproject.briar.api.client.SessionId; - -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.plugin.TransportId.MAX_TRANSPORT_ID_LENGTH; -import static org.briarproject.bramble.util.ValidationUtils.checkLength; -import static org.briarproject.bramble.util.ValidationUtils.checkSize; -import static org.briarproject.briar.api.introduction2.IntroductionConstants.MAX_REQUEST_MESSAGE_LENGTH; -import static org.briarproject.briar.introduction2.MessageType.ACCEPT; -import static org.briarproject.briar.introduction2.MessageType.AUTH; - - -@Immutable -@NotNullByDefault -class IntroductionValidator extends BdfMessageValidator { - - private final MessageEncoder messageEncoder; - - IntroductionValidator(MessageEncoder 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 REQUEST: - return validateRequestMessage(m, body); - case ACCEPT: - return validateAcceptMessage(m, body); - case AUTH: - return validateAuthMessage(m, body); - case DECLINE: - case ACTIVATE: - 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); - clientHelper.parseAndValidateAuthor(authorList); - - String msg = body.getOptionalString(3); - checkLength(msg, 1, MAX_REQUEST_MESSAGE_LENGTH); - - BdfDictionary meta = messageEncoder - .encodeRequestMetadata(m.getTimestamp(), false, false, - false, false); - if (previousMessageId == null) { - return new BdfMessageContext(meta); - } else { - MessageId dependency = new MessageId(previousMessageId); - return new BdfMessageContext(meta, - Collections.singletonList(dependency)); - } - } - - private BdfMessageContext validateAcceptMessage(Message m, BdfList body) - throws FormatException { - checkSize(body, 6); - - byte[] sessionIdBytes = body.getRaw(1); - checkLength(sessionIdBytes, UniqueId.LENGTH); - - byte[] previousMessageId = body.getRaw(2); - checkLength(previousMessageId, UniqueId.LENGTH); - - byte[] ephemeralPublicKey = body.getRaw(3); - checkLength(ephemeralPublicKey, 0, MAX_PUBLIC_KEY_LENGTH); - - body.getLong(4); - - BdfDictionary transportProperties = body.getDictionary(5); - if (transportProperties.size() < 1) throw new FormatException(); - for (String tId : transportProperties.keySet()) { - checkLength(tId, 1, MAX_TRANSPORT_ID_LENGTH); - BdfDictionary tProps = transportProperties.getDictionary(tId); - clientHelper.parseAndValidateTransportProperties(tProps); - } - - SessionId sessionId = new SessionId(sessionIdBytes); - BdfDictionary meta = messageEncoder - .encodeMetadata(ACCEPT, sessionId, m.getTimestamp(), false, - false, false); - MessageId dependency = new MessageId(previousMessageId); - return new BdfMessageContext(meta, - Collections.singletonList(dependency)); - } - - private BdfMessageContext validateAuthMessage(Message m, BdfList body) - throws FormatException { - checkSize(body, 5); - - byte[] sessionIdBytes = body.getRaw(1); - checkLength(sessionIdBytes, UniqueId.LENGTH); - - byte[] previousMessageId = body.getRaw(2); - checkLength(previousMessageId, UniqueId.LENGTH); - - byte[] mac = body.getRaw(3); - checkLength(mac, MAC_BYTES); - - byte[] signature = body.getRaw(4); - checkLength(signature, 1, MAX_SIGNATURE_BYTES); - - SessionId sessionId = new SessionId(sessionIdBytes); - BdfDictionary meta = messageEncoder - .encodeMetadata(AUTH, sessionId, m.getTimestamp(), false, false, - false); - 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, 3); - - byte[] sessionIdBytes = body.getRaw(1); - checkLength(sessionIdBytes, UniqueId.LENGTH); - - byte[] previousMessageId = body.getRaw(2); - checkLength(previousMessageId, UniqueId.LENGTH); - - SessionId sessionId = new SessionId(sessionIdBytes); - BdfDictionary meta = messageEncoder - .encodeMetadata(type, sessionId, m.getTimestamp(), false, false, - false); - MessageId dependency = new MessageId(previousMessageId); - return new BdfMessageContext(meta, - Collections.singletonList(dependency)); - } - -} diff --git a/briar-core/src/main/java/org/briarproject/briar/introduction2/State.java b/briar-core/src/main/java/org/briarproject/briar/introduction2/State.java deleted file mode 100644 index 1e1d46e0a6a352addf38f7cb524042a3b21fe08e..0000000000000000000000000000000000000000 --- a/briar-core/src/main/java/org/briarproject/briar/introduction2/State.java +++ /dev/null @@ -1,7 +0,0 @@ -package org.briarproject.briar.introduction2; - -interface State { - - int getValue(); - -} diff --git a/briar-core/src/test/java/org/briarproject/briar/introduction/IntroduceeManagerTest.java b/briar-core/src/test/java/org/briarproject/briar/introduction/IntroduceeManagerTest.java deleted file mode 100644 index 5f8391d9b8be793e3c53290c1b6ad3be1d18e3b5..0000000000000000000000000000000000000000 --- a/briar-core/src/test/java/org/briarproject/briar/introduction/IntroduceeManagerTest.java +++ /dev/null @@ -1,424 +0,0 @@ -package org.briarproject.briar.introduction; - -import org.briarproject.bramble.api.Bytes; -import org.briarproject.bramble.api.FormatException; -import org.briarproject.bramble.api.client.ClientHelper; -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.crypto.CryptoComponent; -import org.briarproject.bramble.api.crypto.SecretKey; -import org.briarproject.bramble.api.data.BdfDictionary; -import org.briarproject.bramble.api.data.BdfEntry; -import org.briarproject.bramble.api.data.BdfList; -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.AuthorFactory; -import org.briarproject.bramble.api.identity.AuthorId; -import org.briarproject.bramble.api.identity.IdentityManager; -import org.briarproject.bramble.api.properties.TransportPropertyManager; -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.briar.api.client.SessionId; -import org.briarproject.briar.api.introduction.IntroduceeProtocolState; -import org.briarproject.briar.test.BriarTestCase; -import org.jmock.Expectations; -import org.jmock.Mockery; -import org.jmock.lib.legacy.ClassImposteriser; -import org.junit.Test; - -import java.security.GeneralSecurityException; -import java.security.SecureRandom; - -import static org.briarproject.bramble.api.crypto.CryptoConstants.MAX_AGREEMENT_PUBLIC_KEY_BYTES; -import static org.briarproject.bramble.api.identity.AuthorConstants.MAX_SIGNATURE_LENGTH; -import static org.briarproject.bramble.api.sync.SyncConstants.MESSAGE_HEADER_LENGTH; -import static org.briarproject.bramble.test.TestUtils.getAuthor; -import static org.briarproject.bramble.test.TestUtils.getGroup; -import static org.briarproject.bramble.test.TestUtils.getRandomBytes; -import static org.briarproject.bramble.test.TestUtils.getRandomId; -import static org.briarproject.bramble.test.TestUtils.getSecretKey; -import static org.briarproject.briar.api.introduction.IntroduceeProtocolState.AWAIT_REQUEST; -import static org.briarproject.briar.api.introduction.IntroductionConstants.ACCEPT; -import static org.briarproject.briar.api.introduction.IntroductionConstants.ADDED_CONTACT_ID; -import static org.briarproject.briar.api.introduction.IntroductionConstants.ANSWERED; -import static org.briarproject.briar.api.introduction.IntroductionConstants.CONTACT; -import static org.briarproject.briar.api.introduction.IntroductionConstants.CONTACT_ID_1; -import static org.briarproject.briar.api.introduction.IntroductionConstants.EXISTS; -import static org.briarproject.briar.api.introduction.IntroductionConstants.E_PUBLIC_KEY; -import static org.briarproject.briar.api.introduction.IntroductionConstants.GROUP_ID; -import static org.briarproject.briar.api.introduction.IntroductionConstants.INTRODUCER; -import static org.briarproject.briar.api.introduction.IntroductionConstants.LOCAL_AUTHOR_ID; -import static org.briarproject.briar.api.introduction.IntroductionConstants.MAC; -import static org.briarproject.briar.api.introduction.IntroductionConstants.MAC_KEY; -import static org.briarproject.briar.api.introduction.IntroductionConstants.MAC_LABEL; -import static org.briarproject.briar.api.introduction.IntroductionConstants.MAC_LENGTH; -import static org.briarproject.briar.api.introduction.IntroductionConstants.MESSAGE_ID; -import static org.briarproject.briar.api.introduction.IntroductionConstants.MESSAGE_TIME; -import static org.briarproject.briar.api.introduction.IntroductionConstants.NAME; -import static org.briarproject.briar.api.introduction.IntroductionConstants.NONCE; -import static org.briarproject.briar.api.introduction.IntroductionConstants.NOT_OUR_RESPONSE; -import static org.briarproject.briar.api.introduction.IntroductionConstants.PUBLIC_KEY; -import static org.briarproject.briar.api.introduction.IntroductionConstants.REMOTE_AUTHOR_ID; -import static org.briarproject.briar.api.introduction.IntroductionConstants.REMOTE_AUTHOR_IS_US; -import static org.briarproject.briar.api.introduction.IntroductionConstants.ROLE; -import static org.briarproject.briar.api.introduction.IntroductionConstants.ROLE_INTRODUCEE; -import static org.briarproject.briar.api.introduction.IntroductionConstants.SESSION_ID; -import static org.briarproject.briar.api.introduction.IntroductionConstants.SIGNATURE; -import static org.briarproject.briar.api.introduction.IntroductionConstants.SIGNING_LABEL; -import static org.briarproject.briar.api.introduction.IntroductionConstants.STATE; -import static org.briarproject.briar.api.introduction.IntroductionConstants.STORAGE_ID; -import static org.briarproject.briar.api.introduction.IntroductionConstants.TIME; -import static org.briarproject.briar.api.introduction.IntroductionConstants.TRANSPORT; -import static org.briarproject.briar.api.introduction.IntroductionConstants.TYPE; -import static org.briarproject.briar.api.introduction.IntroductionConstants.TYPE_ACK; -import static org.briarproject.briar.api.introduction.IntroductionConstants.TYPE_REQUEST; -import static org.briarproject.briar.api.introduction.IntroductionConstants.TYPE_RESPONSE; -import static org.briarproject.briar.api.introduction.IntroductionManager.CLIENT_ID; -import static org.hamcrest.Matchers.array; -import static org.hamcrest.Matchers.samePropertyValuesAs; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; - -public class IntroduceeManagerTest extends BriarTestCase { - - private final Mockery context; - private final IntroduceeManager introduceeManager; - private final DatabaseComponent db; - private final CryptoComponent cryptoComponent; - private final ClientHelper clientHelper; - private final IntroductionGroupFactory introductionGroupFactory; - private final AuthorFactory authorFactory; - private final ContactManager contactManager; - private final Clock clock; - private final Contact introducer; - private final Contact introducee1; - private final Contact introducee2; - private final Group localGroup1; - private final Group introductionGroup1; - private final Transaction txn; - private final long time = 42L; - private final Message localStateMessage; - private final SessionId sessionId; - private final Message message1; - - public IntroduceeManagerTest() { - context = new Mockery(); - context.setImposteriser(ClassImposteriser.INSTANCE); - MessageSender messageSender = context.mock(MessageSender.class); - db = context.mock(DatabaseComponent.class); - cryptoComponent = context.mock(CryptoComponent.class); - clientHelper = context.mock(ClientHelper.class); - clock = context.mock(Clock.class); - introductionGroupFactory = - context.mock(IntroductionGroupFactory.class); - TransportPropertyManager transportPropertyManager = - context.mock(TransportPropertyManager.class); - authorFactory = context.mock(AuthorFactory.class); - contactManager = context.mock(ContactManager.class); - IdentityManager identityManager = context.mock(IdentityManager.class); - - introduceeManager = new IntroduceeManager(messageSender, db, - clientHelper, clock, cryptoComponent, transportPropertyManager, - authorFactory, contactManager, identityManager, - introductionGroupFactory); - - Author author0 = getAuthor(); - AuthorId localAuthorId = new AuthorId(getRandomId()); - ContactId contactId0 = new ContactId(234); - introducer = - new Contact(contactId0, author0, localAuthorId, true, true); - - Author author1 = getAuthor(); - AuthorId localAuthorId1 = new AuthorId(getRandomId()); - ContactId contactId1 = new ContactId(234); - introducee1 = - new Contact(contactId1, author1, localAuthorId1, true, true); - - Author author2 = getAuthor(); - ContactId contactId2 = new ContactId(235); - introducee2 = - new Contact(contactId2, author2, localAuthorId, true, true); - - localGroup1 = getGroup(CLIENT_ID); - introductionGroup1 = getGroup(CLIENT_ID); - - sessionId = new SessionId(getRandomId()); - localStateMessage = new Message( - new MessageId(getRandomId()), - localGroup1.getId(), - time, - getRandomBytes(MESSAGE_HEADER_LENGTH + 1) - ); - message1 = new Message( - new MessageId(getRandomId()), - introductionGroup1.getId(), - time, - getRandomBytes(MESSAGE_HEADER_LENGTH + 1) - ); - - txn = new Transaction(null, false); - } - - @Test - public void testIncomingRequestMessage() - throws DbException, FormatException { - - BdfDictionary msg = new BdfDictionary(); - msg.put(TYPE, TYPE_REQUEST); - msg.put(GROUP_ID, introductionGroup1.getId()); - msg.put(SESSION_ID, sessionId); - msg.put(MESSAGE_ID, message1.getId()); - msg.put(MESSAGE_TIME, time); - msg.put(NAME, introducee2.getAuthor().getName()); - msg.put(PUBLIC_KEY, introducee2.getAuthor().getPublicKey()); - - BdfDictionary state = - initializeSessionState(txn, introductionGroup1.getId(), msg); - - context.checking(new Expectations() {{ - oneOf(clientHelper).mergeMessageMetadata(txn, - localStateMessage.getId(), state); - }}); - - introduceeManager.incomingMessage(txn, state, msg); - - context.assertIsSatisfied(); - assertFalse(txn.isCommitted()); - } - - @Test - public void testIncomingResponseMessage() - throws DbException, FormatException { - - BdfDictionary msg = new BdfDictionary(); - msg.put(TYPE, TYPE_RESPONSE); - msg.put(GROUP_ID, introductionGroup1.getId()); - msg.put(SESSION_ID, sessionId); - msg.put(MESSAGE_ID, message1.getId()); - msg.put(MESSAGE_TIME, time); - msg.put(NAME, introducee2.getAuthor().getName()); - msg.put(PUBLIC_KEY, introducee2.getAuthor().getPublicKey()); - - BdfDictionary state = - initializeSessionState(txn, introductionGroup1.getId(), msg); - state.put(STATE, IntroduceeProtocolState.AWAIT_RESPONSES.ordinal()); - - // turn request message into a response - msg.put(ACCEPT, true); - msg.put(TIME, time); - msg.put(E_PUBLIC_KEY, getRandomBytes(MAX_AGREEMENT_PUBLIC_KEY_BYTES)); - msg.put(TRANSPORT, new BdfDictionary()); - - context.checking(new Expectations() {{ - oneOf(clientHelper).mergeMessageMetadata(txn, - localStateMessage.getId(), state); - }}); - - introduceeManager.incomingMessage(txn, state, msg); - - context.assertIsSatisfied(); - assertFalse(txn.isCommitted()); - } - - @Test - public void testDetectReplacedEphemeralPublicKey() - throws DbException, FormatException, GeneralSecurityException { - - // TODO MR !237 should use its new default initialization method here - BdfDictionary msg = new BdfDictionary(); - msg.put(TYPE, TYPE_RESPONSE); - msg.put(GROUP_ID, introductionGroup1.getId()); - msg.put(SESSION_ID, sessionId); - msg.put(MESSAGE_ID, message1.getId()); - msg.put(MESSAGE_TIME, time); - msg.put(NAME, introducee2.getAuthor().getName()); - msg.put(PUBLIC_KEY, introducee2.getAuthor().getPublicKey()); - BdfDictionary state = - initializeSessionState(txn, introductionGroup1.getId(), msg); - - // prepare state for incoming ACK - state.put(STATE, IntroduceeProtocolState.AWAIT_ACK.ordinal()); - state.put(ADDED_CONTACT_ID, 2); - byte[] nonce = getRandomBytes(42); - state.put(NONCE, nonce); - state.put(PUBLIC_KEY, introducee2.getAuthor().getPublicKey()); - - // create incoming ACK message - byte[] mac = getRandomBytes(MAC_LENGTH); - byte[] sig = getRandomBytes(MAX_SIGNATURE_LENGTH); - BdfDictionary ack = BdfDictionary.of( - new BdfEntry(TYPE, TYPE_ACK), - new BdfEntry(SESSION_ID, sessionId), - new BdfEntry(GROUP_ID, introductionGroup1.getId()), - new BdfEntry(MAC, mac), - new BdfEntry(SIGNATURE, sig) - ); - - context.checking(new Expectations() {{ - oneOf(cryptoComponent).verifySignature(sig, SIGNING_LABEL, nonce, - introducee2.getAuthor().getPublicKey()); - will(returnValue(false)); - }}); - - try { - introduceeManager.incomingMessage(txn, state, ack); - fail(); - } catch (DbException e) { - // expected - assertTrue(e.getCause() instanceof GeneralSecurityException); - } - context.assertIsSatisfied(); - assertFalse(txn.isCommitted()); - } - - @Test - public void testSignatureVerification() - throws FormatException, DbException, GeneralSecurityException { - - byte[] publicKeyBytes = introducee2.getAuthor().getPublicKey(); - byte[] nonce = getRandomBytes(MAC_LENGTH); - byte[] sig = getRandomBytes(MAC_LENGTH); - - BdfDictionary state = new BdfDictionary(); - state.put(PUBLIC_KEY, publicKeyBytes); - state.put(NONCE, nonce); - state.put(SIGNATURE, sig); - - context.checking(new Expectations() {{ - oneOf(cryptoComponent).verifySignature(sig, SIGNING_LABEL, nonce, - publicKeyBytes); - will(returnValue(true)); - }}); - introduceeManager.verifySignature(state); - context.assertIsSatisfied(); - } - - @Test - public void testMacVerification() - throws FormatException, DbException, GeneralSecurityException { - - byte[] publicKeyBytes = introducee2.getAuthor().getPublicKey(); - BdfDictionary tp = BdfDictionary.of(new BdfEntry("fake", "fake")); - byte[] ePublicKeyBytes = getRandomBytes(MAX_AGREEMENT_PUBLIC_KEY_BYTES); - byte[] mac = getRandomBytes(MAC_LENGTH); - SecretKey macKey = getSecretKey(); - - // move state to where it would be after an ACK arrived - BdfDictionary state = new BdfDictionary(); - state.put(PUBLIC_KEY, publicKeyBytes); - state.put(TRANSPORT, tp); - state.put(TIME, time); - state.put(E_PUBLIC_KEY, ePublicKeyBytes); - state.put(MAC, mac); - state.put(MAC_KEY, macKey.getBytes()); - - byte[] signBytes = getRandomBytes(42); - context.checking(new Expectations() {{ - oneOf(clientHelper).toByteArray( - BdfList.of(publicKeyBytes, ePublicKeyBytes, tp, time)); - will(returnValue(signBytes)); - //noinspection unchecked - oneOf(cryptoComponent).mac(with(MAC_LABEL), - with(samePropertyValuesAs(macKey)), - with(array(equal(signBytes)))); - will(returnValue(mac)); - }}); - introduceeManager.verifyMac(state); - context.assertIsSatisfied(); - - // now produce wrong MAC - context.checking(new Expectations() {{ - oneOf(clientHelper).toByteArray( - BdfList.of(publicKeyBytes, ePublicKeyBytes, tp, time)); - will(returnValue(signBytes)); - //noinspection unchecked - oneOf(cryptoComponent).mac(with(MAC_LABEL), - with(samePropertyValuesAs(macKey)), - with(array(equal(signBytes)))); - will(returnValue(getRandomBytes(MAC_LENGTH))); - }}); - try { - introduceeManager.verifyMac(state); - fail(); - } catch (GeneralSecurityException e) { - // expected - } - context.assertIsSatisfied(); - } - - private BdfDictionary initializeSessionState(Transaction txn, - GroupId groupId, BdfDictionary msg) - throws DbException, FormatException { - - SecureRandom secureRandom = context.mock(SecureRandom.class); - Bytes salt = new Bytes(new byte[64]); - BdfDictionary groupMetadata = BdfDictionary.of( - new BdfEntry(CONTACT, introducee1.getId().getInt()) - ); - boolean contactExists = false; - BdfDictionary state = new BdfDictionary(); - state.put(STORAGE_ID, localStateMessage.getId()); - state.put(STATE, AWAIT_REQUEST.getValue()); - state.put(ROLE, ROLE_INTRODUCEE); - state.put(GROUP_ID, groupId); - state.put(INTRODUCER, introducer.getAuthor().getName()); - state.put(CONTACT_ID_1, introducer.getId().getInt()); - state.put(LOCAL_AUTHOR_ID, introducer.getLocalAuthorId().getBytes()); - state.put(NOT_OUR_RESPONSE, localStateMessage.getId()); - state.put(ANSWERED, false); - state.put(EXISTS, contactExists); - state.put(REMOTE_AUTHOR_ID, introducee2.getAuthor().getId()); - state.put(REMOTE_AUTHOR_IS_US, false); - - context.checking(new Expectations() {{ - oneOf(clock).currentTimeMillis(); - will(returnValue(time)); - oneOf(cryptoComponent).getSecureRandom(); - will(returnValue(secureRandom)); - oneOf(secureRandom).nextBytes(salt.getBytes()); - oneOf(introductionGroupFactory).createLocalGroup(); - will(returnValue(localGroup1)); - oneOf(clientHelper) - .createMessage(localGroup1.getId(), time, BdfList.of(salt)); - will(returnValue(localStateMessage)); - - // who is making the introduction? who is the introducer? - oneOf(clientHelper).getGroupMetadataAsDictionary(txn, - groupId); - will(returnValue(groupMetadata)); - oneOf(db).getContact(txn, introducer.getId()); - will(returnValue(introducer)); - - // create remote author to check if contact exists - oneOf(authorFactory).createAuthor(introducee2.getAuthor().getName(), - introducee2.getAuthor().getPublicKey()); - will(returnValue(introducee2.getAuthor())); - oneOf(contactManager) - .contactExists(txn, introducee2.getAuthor().getId(), - introducer.getLocalAuthorId()); - will(returnValue(contactExists)); - - // checks if remote author is one of our identities - oneOf(db).containsLocalAuthor(txn, introducee2.getAuthor().getId()); - will(returnValue(false)); - - // store session state - oneOf(clientHelper) - .addLocalMessage(txn, localStateMessage, state, false); - }}); - - BdfDictionary result = introduceeManager.initialize(txn, groupId, msg); - - context.assertIsSatisfied(); - assertFalse(txn.isCommitted()); - return result; - } - -} diff --git a/briar-core/src/test/java/org/briarproject/briar/introduction/IntroducerManagerTest.java b/briar-core/src/test/java/org/briarproject/briar/introduction/IntroducerManagerTest.java deleted file mode 100644 index 558b26ec9b2fdb9452676dc54e4b86ff8bf2418c..0000000000000000000000000000000000000000 --- a/briar-core/src/test/java/org/briarproject/briar/introduction/IntroducerManagerTest.java +++ /dev/null @@ -1,179 +0,0 @@ -package org.briarproject.briar.introduction; - -import org.briarproject.bramble.api.Bytes; -import org.briarproject.bramble.api.FormatException; -import org.briarproject.bramble.api.client.ClientHelper; -import org.briarproject.bramble.api.contact.Contact; -import org.briarproject.bramble.api.contact.ContactId; -import org.briarproject.bramble.api.crypto.CryptoComponent; -import org.briarproject.bramble.api.data.BdfDictionary; -import org.briarproject.bramble.api.data.BdfList; -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.AuthorId; -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.test.BriarTestCase; -import org.jmock.Expectations; -import org.jmock.Mockery; -import org.jmock.lib.legacy.ClassImposteriser; -import org.junit.Test; - -import java.security.SecureRandom; - -import static org.briarproject.bramble.test.TestUtils.getAuthor; -import static org.briarproject.bramble.test.TestUtils.getGroup; -import static org.briarproject.bramble.test.TestUtils.getRandomBytes; -import static org.briarproject.bramble.test.TestUtils.getRandomId; -import static org.briarproject.briar.api.introduction.IntroducerProtocolState.AWAIT_RESPONSES; -import static org.briarproject.briar.api.introduction.IntroducerProtocolState.PREPARE_REQUESTS; -import static org.briarproject.briar.api.introduction.IntroductionConstants.AUTHOR_ID_1; -import static org.briarproject.briar.api.introduction.IntroductionConstants.AUTHOR_ID_2; -import static org.briarproject.briar.api.introduction.IntroductionConstants.CONTACT_1; -import static org.briarproject.briar.api.introduction.IntroductionConstants.CONTACT_2; -import static org.briarproject.briar.api.introduction.IntroductionConstants.CONTACT_ID_1; -import static org.briarproject.briar.api.introduction.IntroductionConstants.CONTACT_ID_2; -import static org.briarproject.briar.api.introduction.IntroductionConstants.GROUP_ID; -import static org.briarproject.briar.api.introduction.IntroductionConstants.GROUP_ID_1; -import static org.briarproject.briar.api.introduction.IntroductionConstants.GROUP_ID_2; -import static org.briarproject.briar.api.introduction.IntroductionConstants.MESSAGE_TIME; -import static org.briarproject.briar.api.introduction.IntroductionConstants.NAME; -import static org.briarproject.briar.api.introduction.IntroductionConstants.PUBLIC_KEY; -import static org.briarproject.briar.api.introduction.IntroductionConstants.ROLE; -import static org.briarproject.briar.api.introduction.IntroductionConstants.ROLE_INTRODUCER; -import static org.briarproject.briar.api.introduction.IntroductionConstants.SESSION_ID; -import static org.briarproject.briar.api.introduction.IntroductionConstants.STATE; -import static org.briarproject.briar.api.introduction.IntroductionConstants.STORAGE_ID; -import static org.briarproject.briar.api.introduction.IntroductionConstants.TYPE; -import static org.briarproject.briar.api.introduction.IntroductionConstants.TYPE_REQUEST; -import static org.briarproject.briar.api.introduction.IntroductionManager.CLIENT_ID; -import static org.junit.Assert.assertFalse; - -public class IntroducerManagerTest extends BriarTestCase { - - private final Mockery context; - private final IntroducerManager introducerManager; - private final CryptoComponent cryptoComponent; - private final ClientHelper clientHelper; - private final IntroductionGroupFactory introductionGroupFactory; - private final MessageSender messageSender; - private final Clock clock; - private final Contact introducee1; - private final Contact introducee2; - private final Group localGroup0; - private final Group introductionGroup1; - private final Group introductionGroup2; - - public IntroducerManagerTest() { - context = new Mockery(); - context.setImposteriser(ClassImposteriser.INSTANCE); - messageSender = context.mock(MessageSender.class); - cryptoComponent = context.mock(CryptoComponent.class); - clientHelper = context.mock(ClientHelper.class); - clock = context.mock(Clock.class); - introductionGroupFactory = - context.mock(IntroductionGroupFactory.class); - - introducerManager = - new IntroducerManager(messageSender, clientHelper, clock, - cryptoComponent, introductionGroupFactory); - - Author author1 = getAuthor(); - AuthorId localAuthorId1 = new AuthorId(getRandomId()); - ContactId contactId1 = new ContactId(234); - introducee1 = - new Contact(contactId1, author1, localAuthorId1, true, true); - - Author author2 = getAuthor(); - AuthorId localAuthorId2 = new AuthorId(getRandomId()); - ContactId contactId2 = new ContactId(235); - introducee2 = - new Contact(contactId2, author2, localAuthorId2, true, true); - - localGroup0 = getGroup(CLIENT_ID); - introductionGroup1 = getGroup(CLIENT_ID); - introductionGroup2 = getGroup(CLIENT_ID); - - context.assertIsSatisfied(); - } - - @Test - public void testMakeIntroduction() throws DbException, FormatException { - Transaction txn = new Transaction(null, false); - long time = 42L; - context.setImposteriser(ClassImposteriser.INSTANCE); - SecureRandom secureRandom = context.mock(SecureRandom.class); - Bytes salt = new Bytes(new byte[64]); - Message msg = new Message(new MessageId(getRandomId()), - localGroup0.getId(), time, getRandomBytes(64)); - BdfDictionary state = new BdfDictionary(); - state.put(SESSION_ID, msg.getId()); - state.put(STORAGE_ID, msg.getId()); - state.put(STATE, PREPARE_REQUESTS.getValue()); - state.put(ROLE, ROLE_INTRODUCER); - state.put(GROUP_ID_1, introductionGroup1.getId()); - state.put(GROUP_ID_2, introductionGroup2.getId()); - state.put(CONTACT_1, introducee1.getAuthor().getName()); - state.put(CONTACT_2, introducee2.getAuthor().getName()); - state.put(CONTACT_ID_1, introducee1.getId().getInt()); - state.put(CONTACT_ID_2, introducee2.getId().getInt()); - state.put(AUTHOR_ID_1, introducee1.getAuthor().getId()); - state.put(AUTHOR_ID_2, introducee2.getAuthor().getId()); - BdfDictionary state2 = (BdfDictionary) state.clone(); - state2.put(STATE, AWAIT_RESPONSES.getValue()); - - BdfDictionary msg1 = new BdfDictionary(); - msg1.put(TYPE, TYPE_REQUEST); - msg1.put(SESSION_ID, state.getRaw(SESSION_ID)); - msg1.put(GROUP_ID, state.getRaw(GROUP_ID_1)); - msg1.put(NAME, state.getString(CONTACT_2)); - msg1.put(PUBLIC_KEY, introducee2.getAuthor().getPublicKey()); - BdfDictionary msg1send = (BdfDictionary) msg1.clone(); - msg1send.put(MESSAGE_TIME, time); - - BdfDictionary msg2 = new BdfDictionary(); - msg2.put(TYPE, TYPE_REQUEST); - msg2.put(SESSION_ID, state.getRaw(SESSION_ID)); - msg2.put(GROUP_ID, state.getRaw(GROUP_ID_2)); - msg2.put(NAME, state.getString(CONTACT_1)); - msg2.put(PUBLIC_KEY, introducee1.getAuthor().getPublicKey()); - BdfDictionary msg2send = (BdfDictionary) msg2.clone(); - msg2send.put(MESSAGE_TIME, time); - - context.checking(new Expectations() {{ - // initialize and store session state - oneOf(clock).currentTimeMillis(); - will(returnValue(time)); - oneOf(cryptoComponent).getSecureRandom(); - will(returnValue(secureRandom)); - oneOf(secureRandom).nextBytes(salt.getBytes()); - oneOf(introductionGroupFactory).createLocalGroup(); - will(returnValue(localGroup0)); - oneOf(clientHelper).createMessage(localGroup0.getId(), time, - BdfList.of(salt)); - will(returnValue(msg)); - oneOf(introductionGroupFactory) - .createIntroductionGroup(introducee1); - will(returnValue(introductionGroup1)); - oneOf(introductionGroupFactory) - .createIntroductionGroup(introducee2); - will(returnValue(introductionGroup2)); - oneOf(clientHelper).addLocalMessage(txn, msg, state, false); - - // send message - oneOf(clientHelper).mergeMessageMetadata(txn, msg.getId(), state2); - oneOf(messageSender).sendMessage(txn, msg1send); - oneOf(messageSender).sendMessage(txn, msg2send); - }}); - - introducerManager - .makeIntroduction(txn, introducee1, introducee2, null, time); - - context.assertIsSatisfied(); - assertFalse(txn.isCommitted()); - } - -} diff --git a/briar-core/src/test/java/org/briarproject/briar/introduction2/IntroductionCryptoImplTest.java b/briar-core/src/test/java/org/briarproject/briar/introduction/IntroductionCryptoImplTest.java similarity index 99% rename from briar-core/src/test/java/org/briarproject/briar/introduction2/IntroductionCryptoImplTest.java rename to briar-core/src/test/java/org/briarproject/briar/introduction/IntroductionCryptoImplTest.java index 57cadce0e267070243ed1e8e4cab363427cca8b5..b8c636400d1ee102312f0fea368315d22728a426 100644 --- a/briar-core/src/test/java/org/briarproject/briar/introduction2/IntroductionCryptoImplTest.java +++ b/briar-core/src/test/java/org/briarproject/briar/introduction/IntroductionCryptoImplTest.java @@ -1,4 +1,4 @@ -package org.briarproject.briar.introduction2; +package org.briarproject.briar.introduction; import org.briarproject.bramble.api.client.ClientHelper; import org.briarproject.bramble.api.crypto.CryptoComponent; diff --git a/briar-core/src/test/java/org/briarproject/briar/introduction2/IntroductionCryptoTest.java b/briar-core/src/test/java/org/briarproject/briar/introduction/IntroductionCryptoTest.java similarity index 91% rename from briar-core/src/test/java/org/briarproject/briar/introduction2/IntroductionCryptoTest.java rename to briar-core/src/test/java/org/briarproject/briar/introduction/IntroductionCryptoTest.java index 139c4ca40847ef5996471dfa9758e73a8be9d7ab..a28e8321e2ae8adf1904a7495f8a7a2b0f28d680 100644 --- a/briar-core/src/test/java/org/briarproject/briar/introduction2/IntroductionCryptoTest.java +++ b/briar-core/src/test/java/org/briarproject/briar/introduction/IntroductionCryptoTest.java @@ -1,4 +1,4 @@ -package org.briarproject.briar.introduction2; +package org.briarproject.briar.introduction; import org.briarproject.bramble.api.UniqueId; import org.briarproject.bramble.api.client.ClientHelper; @@ -11,7 +11,7 @@ import org.junit.Test; import static org.briarproject.bramble.test.TestUtils.getAuthor; import static org.briarproject.bramble.test.TestUtils.getRandomBytes; -import static org.briarproject.briar.api.introduction2.IntroductionConstants.LABEL_SESSION_ID; +import static org.briarproject.briar.api.introduction.IntroductionConstants.LABEL_SESSION_ID; import static org.junit.Assert.assertEquals; public class IntroductionCryptoTest extends BrambleMockTestCase { 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 9b485e5c42b1ce13b9ab9414cb90eb48de20432d..6d13b80f197a56bb9ee04f3920a2bf53355afbad 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 @@ -6,23 +6,21 @@ import org.briarproject.bramble.api.FormatException; import org.briarproject.bramble.api.client.ClientHelper; import org.briarproject.bramble.api.contact.Contact; import org.briarproject.bramble.api.contact.ContactId; -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.data.BdfEntry; import org.briarproject.bramble.api.data.BdfList; 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.event.Event; import org.briarproject.bramble.api.event.EventListener; +import org.briarproject.bramble.api.identity.Author; 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.TransportProperties; import org.briarproject.bramble.api.properties.TransportPropertyManager; 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.test.TestDatabaseModule; import org.briarproject.briar.api.client.SessionId; @@ -38,56 +36,35 @@ import org.junit.Before; import org.junit.Test; import java.io.IOException; -import java.security.GeneralSecurityException; -import java.util.ArrayList; import java.util.Collection; import java.util.Collections; -import java.util.List; import java.util.Map; -import java.util.Map.Entry; import java.util.concurrent.TimeoutException; import java.util.logging.Logger; -import javax.inject.Inject; - import static org.briarproject.bramble.api.identity.AuthorConstants.MAX_PUBLIC_KEY_LENGTH; import static org.briarproject.bramble.test.TestPluginConfigModule.TRANSPORT_ID; import static org.briarproject.bramble.test.TestUtils.getRandomBytes; import static org.briarproject.bramble.test.TestUtils.getTransportId; -import static org.briarproject.bramble.util.StringUtils.getRandomString; -import static org.briarproject.briar.api.client.MessageQueueManager.QUEUE_STATE_KEY; -import static org.briarproject.briar.api.introduction.IntroductionConstants.ALICE_MAC_KEY_LABEL; -import static org.briarproject.briar.api.introduction.IntroductionConstants.ALICE_NONCE_LABEL; -import static org.briarproject.briar.api.introduction.IntroductionConstants.E_PUBLIC_KEY; -import static org.briarproject.briar.api.introduction.IntroductionConstants.GROUP_ID; -import static org.briarproject.briar.api.introduction.IntroductionConstants.MAC; -import static org.briarproject.briar.api.introduction.IntroductionConstants.MAC_KEY; -import static org.briarproject.briar.api.introduction.IntroductionConstants.MAC_LABEL; -import static org.briarproject.briar.api.introduction.IntroductionConstants.NAME; -import static org.briarproject.briar.api.introduction.IntroductionConstants.NONCE; -import static org.briarproject.briar.api.introduction.IntroductionConstants.PUBLIC_KEY; -import static org.briarproject.briar.api.introduction.IntroductionConstants.SESSION_ID; -import static org.briarproject.briar.api.introduction.IntroductionConstants.SHARED_SECRET_LABEL; -import static org.briarproject.briar.api.introduction.IntroductionConstants.SIGNATURE; -import static org.briarproject.briar.api.introduction.IntroductionConstants.SIGNING_LABEL; -import static org.briarproject.briar.api.introduction.IntroductionConstants.TIME; -import static org.briarproject.briar.api.introduction.IntroductionConstants.TRANSPORT; -import static org.briarproject.briar.api.introduction.IntroductionConstants.TYPE; -import static org.briarproject.briar.api.introduction.IntroductionConstants.TYPE_REQUEST; -import static org.briarproject.briar.api.introduction.IntroductionConstants.TYPE_RESPONSE; +import static org.briarproject.bramble.test.TestUtils.getTransportProperties; +import static org.briarproject.bramble.test.TestUtils.getTransportPropertiesMap; +import static org.briarproject.briar.api.introduction.IntroductionManager.CLIENT_ID; import static org.briarproject.briar.api.introduction.IntroductionManager.CLIENT_VERSION; +import static org.briarproject.briar.introduction.IntroductionConstants.MSG_KEY_MESSAGE_TYPE; +import static org.briarproject.briar.introduction.IntroductionConstants.SESSION_KEY_AUTHOR; +import static org.briarproject.briar.introduction.IntroductionConstants.SESSION_KEY_INTRODUCEE_1; +import static org.briarproject.briar.introduction.IntroductionConstants.SESSION_KEY_INTRODUCEE_2; +import static org.briarproject.briar.introduction.IntroductionConstants.SESSION_KEY_LAST_LOCAL_MESSAGE_ID; +import static org.briarproject.briar.introduction.IntroductionConstants.SESSION_KEY_SESSION_ID; +import static org.briarproject.briar.introduction.MessageType.ACCEPT; import static org.briarproject.briar.test.BriarTestUtils.assertGroupCount; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; public class IntroductionIntegrationTest extends BriarIntegrationTest<IntroductionIntegrationTestComponent> { - @Inject - IntroductionGroupFactory introductionGroupFactory; - // objects accessed from background threads need to be volatile private volatile IntroductionManager introductionManager0; private volatile IntroductionManager introductionManager1; @@ -102,7 +79,7 @@ public class IntroductionIntegrationTest Logger.getLogger(IntroductionIntegrationTest.class.getName()); interface StateVisitor { - boolean visit(BdfDictionary response); + AcceptMessage visit(AcceptMessage response); } @Before @@ -151,50 +128,50 @@ public class IntroductionIntegrationTest .makeIntroduction(introducee1, introducee2, "Hi!", time); // check that messages are tracked properly - Group g1 = introductionGroupFactory - .createIntroductionGroup(introducee1); - Group g2 = introductionGroupFactory - .createIntroductionGroup(introducee2); - assertGroupCount(messageTracker0, g1.getId(), 1, 0, time); - assertGroupCount(messageTracker0, g2.getId(), 1, 0, time); + Group g1 = introductionManager0.getContactGroup(introducee1); + Group g2 = introductionManager0.getContactGroup(introducee2); + assertGroupCount(messageTracker0, g1.getId(), 1, 0); + assertGroupCount(messageTracker0, g2.getId(), 1, 0); - // sync first request message + // sync first REQUEST message sync0To1(1, true); eventWaiter.await(TIMEOUT, 1); assertTrue(listener1.requestReceived); assertGroupCount(messageTracker1, g1.getId(), 2, 1); - // sync second request message + // sync second REQUEST message sync0To2(1, true); eventWaiter.await(TIMEOUT, 1); assertTrue(listener2.requestReceived); assertGroupCount(messageTracker2, g2.getId(), 2, 1); - // sync first response + // sync first ACCEPT message sync1To0(1, true); eventWaiter.await(TIMEOUT, 1); assertTrue(listener0.response1Received); assertGroupCount(messageTracker0, g1.getId(), 2, 1); - // sync second response + // sync second ACCEPT message sync2To0(1, true); eventWaiter.await(TIMEOUT, 1); assertTrue(listener0.response2Received); assertGroupCount(messageTracker0, g2.getId(), 2, 1); - // sync forwarded responses to introducees + // sync forwarded ACCEPT messages to introducees sync0To1(1, true); sync0To2(1, true); - assertGroupCount(messageTracker1, g1.getId(), 2, 1); - assertGroupCount(messageTracker2, g2.getId(), 2, 1); - // sync first ACK and its forward + // sync first AUTH and its forward sync1To0(1, true); sync0To2(1, true); - // sync second ACK and its forward - sync2To0(1, true); - sync0To1(1, true); + // sync second AUTH and its forward as well as the following ACTIVATE + sync2To0(2, true); + sync0To1(2, true); + + // sync first ACTIVATE and its forward + sync1To0(1, true); + sync0To2(1, true); // wait for introduction to succeed eventWaiter.await(TIMEOUT, 2); @@ -269,10 +246,8 @@ public class IntroductionIntegrationTest assertFalse(contactManager2 .contactExists(author1.getId(), author2.getId())); - Group g1 = introductionGroupFactory - .createIntroductionGroup(introducee1); - Group g2 = introductionGroupFactory - .createIntroductionGroup(introducee2); + Group g1 = introductionManager0.getContactGroup(introducee1); + Group g2 = introductionManager0.getContactGroup(introducee2); assertEquals(2, introductionManager0.getIntroductionMessages(contactId1From0) .size()); @@ -290,6 +265,10 @@ public class IntroductionIntegrationTest introductionManager2.getIntroductionMessages(contactId0From2) .size()); assertGroupCount(messageTracker2, g2.getId(), 3, 2); + + assertFalse(listener0.aborted); + assertFalse(listener1.aborted); + assertFalse(listener2.aborted); } @Test @@ -342,6 +321,9 @@ public class IntroductionIntegrationTest assertEquals(2, introductionManager2.getIntroductionMessages(contactId0From2) .size()); + assertFalse(listener0.aborted); + assertFalse(listener1.aborted); + assertFalse(listener2.aborted); } @Test @@ -393,6 +375,9 @@ public class IntroductionIntegrationTest // since introducee2 was already in FINISHED state when // introducee1's response arrived, she ignores and deletes it assertDefaultUiMessages(); + assertFalse(listener0.aborted); + assertFalse(listener1.aborted); + assertFalse(listener2.aborted); } @Test @@ -432,6 +417,8 @@ public class IntroductionIntegrationTest eventWaiter.await(TIMEOUT, 1); assertTrue(listener0.response2Received); assertFalse(listener0.aborted); + assertFalse(listener1.aborted); + assertFalse(listener2.aborted); } @Test @@ -452,61 +439,11 @@ public class IntroductionIntegrationTest // make really sure we don't have that request assertTrue(introductionManager1.getIntroductionMessages(contactId0From1) .isEmpty()); - } - @Test - public void testSessionIdReuse() throws Exception { - addListeners(true, true); - - // make introduction - long time = clock.currentTimeMillis(); - introductionManager0 - .makeIntroduction(contact1From0, contact2From0, "Hi!", time); - - // sync first request message - sync0To1(1, true); - eventWaiter.await(TIMEOUT, 1); - assertTrue(listener1.requestReceived); - - // get SessionId - List<IntroductionMessage> list = new ArrayList<>( - introductionManager1.getIntroductionMessages(contactId0From1)); - assertEquals(2, list.size()); - assertTrue(list.get(0) instanceof IntroductionRequest); - IntroductionRequest msg = (IntroductionRequest) list.get(0); - SessionId sessionId = msg.getSessionId(); - - // get contact group - Group group = - introductionGroupFactory.createIntroductionGroup(contact1From0); - - // create new message with same SessionId - BdfDictionary d = BdfDictionary.of( - new BdfEntry(TYPE, TYPE_REQUEST), - new BdfEntry(SESSION_ID, sessionId), - new BdfEntry(GROUP_ID, group.getId()), - new BdfEntry(NAME, getRandomString(42)), - new BdfEntry(PUBLIC_KEY, getRandomBytes(MAX_PUBLIC_KEY_LENGTH)) - ); - - // reset request received state - listener1.requestReceived = false; - - // add the message to the queue - MessageSender sender0 = c0.getMessageSender(); - Transaction txn = db0.startTransaction(false); - try { - sender0.sendMessage(txn, d); - db0.commitTransaction(txn); - } finally { - db0.endTransaction(txn); - } - - // actually send message - sync0To1(1, false); - - // make sure it does not arrive - assertFalse(listener1.requestReceived); + // The message was invalid, so no abort message was sent + assertFalse(listener0.aborted); + assertFalse(listener1.aborted); + assertFalse(listener2.aborted); } @Test @@ -523,34 +460,20 @@ public class IntroductionIntegrationTest eventWaiter.await(TIMEOUT, 1); assertTrue(listener1.requestReceived); - // get database and local group for introducee - Group group1 = introductionGroupFactory.createLocalGroup(); + // get local group for introducee1 + Group group1 = + contactGroupFactory.createLocalGroup(CLIENT_ID, CLIENT_VERSION); - // get local session state messages - Map<MessageId, Metadata> map; - Transaction txn = db1.startTransaction(false); - try { - map = db1.getMessageMetadata(txn, group1.getId()); - db1.commitTransaction(txn); - } finally { - db1.endTransaction(txn); - } // check that we have one session state - assertEquals(1, map.size()); + assertEquals(1, c1.getClientHelper() + .getMessageMetadataAsDictionary(group1.getId()).size()); // introducee1 removes introducer contactManager1.removeContact(contactId0From1); - // get local session state messages again - txn = db1.startTransaction(false); - try { - map = db1.getMessageMetadata(txn, group1.getId()); - db1.commitTransaction(txn); - } finally { - db1.endTransaction(txn); - } // make sure local state got deleted - assertEquals(0, map.size()); + assertEquals(0, c1.getClientHelper() + .getMessageMetadataAsDictionary(group1.getId()).size()); } @Test @@ -567,48 +490,36 @@ public class IntroductionIntegrationTest eventWaiter.await(TIMEOUT, 1); assertTrue(listener1.requestReceived); - // get database and local group for introducee - Group group1 = introductionGroupFactory.createLocalGroup(); + // get local group for introducer + Group group0 = + contactGroupFactory.createLocalGroup(CLIENT_ID, CLIENT_VERSION); - // get local session state messages - Map<MessageId, Metadata> map; - Transaction txn = db0.startTransaction(false); - try { - map = db0.getMessageMetadata(txn, group1.getId()); - db0.commitTransaction(txn); - } finally { - db0.endTransaction(txn); - } // check that we have one session state - assertEquals(1, map.size()); + assertEquals(1, c0.getClientHelper() + .getMessageMetadataAsDictionary(group0.getId()).size()); // introducer removes introducee1 contactManager0.removeContact(contactId1From0); - // get local session state messages again - txn = db0.startTransaction(false); - try { - map = db0.getMessageMetadata(txn, group1.getId()); - db0.commitTransaction(txn); - } finally { - db0.endTransaction(txn); - } // make sure local state is still there - assertEquals(1, map.size()); + assertEquals(1, c0.getClientHelper() + .getMessageMetadataAsDictionary(group0.getId()).size()); + + // ensure introducer has aborted the session + assertTrue(listener0.aborted); + + // sync REQUEST and ABORT message + sync0To2(2, true); + + // ensure introducee2 has aborted the session as well + assertTrue(listener2.aborted); // introducer removes other introducee contactManager0.removeContact(contactId2From0); - // get local session state messages again - txn = db0.startTransaction(false); - try { - map = db0.getMessageMetadata(txn, group1.getId()); - db0.commitTransaction(txn); - } finally { - db0.endTransaction(txn); - } // make sure local state is gone now - assertEquals(0, map.size()); + assertEquals(0, c0.getClientHelper() + .getMessageMetadataAsDictionary(group0.getId()).size()); } private void testModifiedResponse(StateVisitor visitor) @@ -630,26 +541,36 @@ public class IntroductionIntegrationTest eventWaiter.await(TIMEOUT, 1); // get response to be forwarded - ClientHelper ch = c0.getClientHelper(); // need 0's ClientHelper here - Entry<MessageId, BdfDictionary> resp = - getMessageFor(ch, contact2From0, TYPE_RESPONSE); - MessageId responseId = resp.getKey(); - BdfDictionary response = resp.getValue(); - - // adapt outgoing message queue to removed message - Group g2 = introductionGroupFactory - .createIntroductionGroup(contact2From0); - decreaseOutgoingMessageCounter(ch, g2.getId()); + AcceptMessage message = + (AcceptMessage) getMessageFor(c0.getClientHelper(), + contact2From0, ACCEPT); // allow visitor to modify response - boolean earlyAbort = visitor.visit(response); + AcceptMessage m = visitor.visit(message); // replace original response with modified one - MessageSender sender0 = c0.getMessageSender(); Transaction txn = db0.startTransaction(false); try { - db0.deleteMessage(txn, responseId); - sender0.sendMessage(txn, response); + db0.removeMessage(txn, message.getMessageId()); + Message msg = c0.getMessageEncoder() + .encodeAcceptMessage(m.getGroupId(), m.getTimestamp(), + m.getPreviousMessageId(), m.getSessionId(), + m.getEphemeralPublicKey(), m.getAcceptTimestamp(), + m.getTransportProperties()); + c0.getClientHelper() + .addLocalMessage(txn, msg, new BdfDictionary(), true); + Group group0 = contactGroupFactory + .createLocalGroup(CLIENT_ID, CLIENT_VERSION); + BdfDictionary query = BdfDictionary.of( + new BdfEntry(SESSION_KEY_SESSION_ID, m.getSessionId()) + ); + Map.Entry<MessageId, BdfDictionary> session = c0.getClientHelper() + .getMessageMetadataAsDictionary(txn, group0.getId(), query) + .entrySet().iterator().next(); + replacePreviousLocalMessageId(contact2From0.getAuthor(), + session.getValue(), msg.getId()); + c0.getClientHelper().mergeMessageMetadata(txn, session.getKey(), + session.getValue()); db0.commitTransaction(txn); } finally { db0.endTransaction(txn); @@ -663,21 +584,14 @@ public class IntroductionIntegrationTest sync0To1(1, true); sync0To2(1, true); - // sync first ACK and forward it + // sync first AUTH and forward it sync1To0(1, true); sync0To2(1, true); // introducee2 should have detected the fake now - // and deleted introducee1 again - Collection<Contact> contacts2; - txn = db2.startTransaction(true); - try { - contacts2 = db2.getContacts(txn); - db2.commitTransaction(txn); - } finally { - db2.endTransaction(txn); - } - assertEquals(1, contacts2.size()); + assertFalse(listener0.aborted); + assertFalse(listener1.aborted); + assertTrue(listener2.aborted); // sync introducee2's ack and following abort sync2To0(2, true); @@ -687,144 +601,44 @@ public class IntroductionIntegrationTest // sync abort messages to introducees sync0To1(2, true); - sync0To2(1, true); - if (earlyAbort) { - assertTrue(listener1.aborted); - assertTrue(listener2.aborted); - } else { - assertTrue(listener2.aborted); - // when aborted late, introducee1 keeps the contact, - // so introducer can not make contacts disappear by aborting - Collection<Contact> contacts1; - txn = db1.startTransaction(true); - try { - contacts1 = db1.getContacts(txn); - db1.commitTransaction(txn); - } finally { - db1.endTransaction(txn); - } - assertEquals(2, contacts1.size()); - } + // ensure everybody got the abort now + assertTrue(listener0.aborted); + assertTrue(listener1.aborted); + assertTrue(listener2.aborted); } @Test public void testModifiedTransportProperties() throws Exception { - testModifiedResponse(response -> { - BdfDictionary tp = response.getDictionary(TRANSPORT, null); - tp.put("fakeId", BdfDictionary.of(new BdfEntry("fake", "fake"))); - response.put(TRANSPORT, tp); - return false; - }); + testModifiedResponse( + m -> new AcceptMessage(m.getMessageId(), m.getGroupId(), + m.getTimestamp(), m.getPreviousMessageId(), + m.getSessionId(), m.getEphemeralPublicKey(), + m.getAcceptTimestamp(), + getTransportPropertiesMap(2)) + ); } @Test public void testModifiedTimestamp() throws Exception { - testModifiedResponse(response -> { - long timestamp = response.getLong(TIME, 0L); - response.put(TIME, timestamp + 1); - return false; - }); + testModifiedResponse( + m -> new AcceptMessage(m.getMessageId(), m.getGroupId(), + m.getTimestamp(), m.getPreviousMessageId(), + m.getSessionId(), m.getEphemeralPublicKey(), + clock.currentTimeMillis(), + m.getTransportProperties()) + ); } @Test public void testModifiedEphemeralPublicKey() throws Exception { - testModifiedResponse(response -> { - KeyPair keyPair = crypto.generateAgreementKeyPair(); - response.put(E_PUBLIC_KEY, keyPair.getPublic().getEncoded()); - return true; - }); - } - - @Test - public void testModifiedEphemeralPublicKeyWithFakeMac() - throws Exception { - // initialize a real introducee manager - MessageSender messageSender = c2.getMessageSender(); - TransportPropertyManager tpManager = c2.getTransportPropertyManager(); - IntroduceeManager manager2 = - new IntroduceeManager(messageSender, db2, clientHelper, clock, - crypto, tpManager, authorFactory, contactManager2, - identityManager2, introductionGroupFactory); - - // create keys - KeyPair keyPair1 = crypto.generateSignatureKeyPair(); - KeyPair eKeyPair1 = crypto.generateAgreementKeyPair(); - KeyPair eKeyPair2 = crypto.generateAgreementKeyPair(); - - // Nonce 1 - byte[][] inputs = { - new byte[] {CLIENT_VERSION}, - eKeyPair1.getPublic().getEncoded(), - eKeyPair2.getPublic().getEncoded() - }; - SecretKey sharedSecret = crypto.deriveSharedSecret(SHARED_SECRET_LABEL, - eKeyPair2.getPublic(), eKeyPair1, inputs); - byte[] nonce1 = crypto.mac(ALICE_NONCE_LABEL, sharedSecret); - - // Signature 1 - byte[] sig1 = crypto.sign(SIGNING_LABEL, nonce1, - keyPair1.getPrivate().getEncoded()); - - // MAC 1 - SecretKey macKey1 = crypto.deriveKey(ALICE_MAC_KEY_LABEL, sharedSecret); - BdfDictionary tp1 = BdfDictionary.of(new BdfEntry("fake", "fake")); - long time1 = clock.currentTimeMillis(); - BdfList toMacList = BdfList.of(keyPair1.getPublic().getEncoded(), - eKeyPair1.getPublic().getEncoded(), tp1, time1); - byte[] toMac = clientHelper.toByteArray(toMacList); - byte[] mac1 = crypto.mac(MAC_LABEL, macKey1, toMac); - - // create only relevant part of state for introducee2 - BdfDictionary state = new BdfDictionary(); - state.put(PUBLIC_KEY, keyPair1.getPublic().getEncoded()); - state.put(TRANSPORT, tp1); - state.put(TIME, time1); - state.put(E_PUBLIC_KEY, eKeyPair1.getPublic().getEncoded()); - state.put(MAC, mac1); - state.put(MAC_KEY, macKey1.getBytes()); - state.put(NONCE, nonce1); - state.put(SIGNATURE, sig1); - - // MAC and signature verification should pass - manager2.verifyMac(state); - manager2.verifySignature(state); - - // replace ephemeral key pair and recalculate matching keys and nonce - KeyPair eKeyPair1f = crypto.generateAgreementKeyPair(); - byte[][] fakeInputs = { - new byte[] {CLIENT_VERSION}, - eKeyPair1f.getPublic().getEncoded(), - eKeyPair2.getPublic().getEncoded() - }; - sharedSecret = crypto.deriveSharedSecret(SHARED_SECRET_LABEL, - eKeyPair2.getPublic(), eKeyPair1f, fakeInputs); - nonce1 = crypto.mac(ALICE_NONCE_LABEL, sharedSecret); - - // recalculate MAC - macKey1 = crypto.deriveKey(ALICE_MAC_KEY_LABEL, sharedSecret); - toMacList = BdfList.of(keyPair1.getPublic().getEncoded(), - eKeyPair1f.getPublic().getEncoded(), tp1, time1); - toMac = clientHelper.toByteArray(toMacList); - mac1 = crypto.mac(MAC_LABEL, macKey1, toMac); - - // update state with faked information - state.put(E_PUBLIC_KEY, eKeyPair1f.getPublic().getEncoded()); - state.put(MAC, mac1); - state.put(MAC_KEY, macKey1.getBytes()); - state.put(NONCE, nonce1); - - // MAC verification should still pass - manager2.verifyMac(state); - - // Signature can not be verified, because we don't have private - // long-term key to fake it - try { - manager2.verifySignature(state); - fail(); - } catch (GeneralSecurityException e) { - // expected - } + testModifiedResponse( + m -> new AcceptMessage(m.getMessageId(), m.getGroupId(), + m.getTimestamp(), m.getPreviousMessageId(), + m.getSessionId(), + getRandomBytes(MAX_PUBLIC_KEY_LENGTH), + m.getAcceptTimestamp(), m.getTransportProperties()) + ); } private void addTransportProperties() @@ -832,17 +646,15 @@ public class IntroductionIntegrationTest TransportPropertyManager tpm0 = c0.getTransportPropertyManager(); TransportPropertyManager tpm1 = c1.getTransportPropertyManager(); TransportPropertyManager tpm2 = c2.getTransportPropertyManager(); - TransportProperties tp = new TransportProperties( - Collections.singletonMap("key", "value")); - tpm0.mergeLocalProperties(TRANSPORT_ID, tp); + tpm0.mergeLocalProperties(TRANSPORT_ID, getTransportProperties(2)); sync0To1(1, true); sync0To2(1, true); - tpm1.mergeLocalProperties(TRANSPORT_ID, tp); + tpm1.mergeLocalProperties(TRANSPORT_ID, getTransportProperties(2)); sync1To0(1, true); - tpm2.mergeLocalProperties(TRANSPORT_ID, tp); + tpm2.mergeLocalProperties(TRANSPORT_ID, getTransportProperties(2)); sync2To0(1, true); } @@ -935,7 +747,7 @@ public class IntroductionIntegrationTest time); } } - } catch (DbException | FormatException exception) { + } catch (DbException exception) { eventWaiter.rethrow(exception); } finally { eventWaiter.resume(); @@ -945,7 +757,6 @@ public class IntroductionIntegrationTest Contact contact = ((IntroductionSucceededEvent) e).getContact(); eventWaiter .assertFalse(contact.getId().equals(contactId0From1)); - eventWaiter.assertTrue(contact.isActive()); eventWaiter.resume(); } else if (e instanceof IntroductionAbortedEvent) { aborted = true; @@ -981,30 +792,41 @@ public class IntroductionIntegrationTest } - private void decreaseOutgoingMessageCounter(ClientHelper ch, GroupId g) - throws FormatException, DbException { - BdfDictionary gD = ch.getGroupMetadataAsDictionary(g); - LOG.warning(gD.toString()); - BdfDictionary queue = gD.getDictionary(QUEUE_STATE_KEY); - queue.put("nextOut", queue.getLong("nextOut") - 1); - gD.put(QUEUE_STATE_KEY, queue); - ch.mergeGroupMetadata(g, gD); + private void replacePreviousLocalMessageId(Author author, + BdfDictionary d, MessageId id) throws FormatException { + BdfDictionary i1 = d.getDictionary(SESSION_KEY_INTRODUCEE_1); + BdfDictionary i2 = d.getDictionary(SESSION_KEY_INTRODUCEE_2); + Author a1 = clientHelper + .parseAndValidateAuthor(i1.getList(SESSION_KEY_AUTHOR)); + Author a2 = clientHelper + .parseAndValidateAuthor(i2.getList(SESSION_KEY_AUTHOR)); + + if (a1.equals(author)) { + i1.put(SESSION_KEY_LAST_LOCAL_MESSAGE_ID, id); + d.put(SESSION_KEY_INTRODUCEE_1, i1); + } else if (a2.equals(author)) { + i2.put(SESSION_KEY_LAST_LOCAL_MESSAGE_ID, id); + d.put(SESSION_KEY_INTRODUCEE_2, i2); + } else { + throw new AssertionError(); + } } - private Entry<MessageId, BdfDictionary> getMessageFor(ClientHelper ch, - Contact contact, long type) throws FormatException, DbException { - Entry<MessageId, BdfDictionary> response = null; - Group g = introductionGroupFactory - .createIntroductionGroup(contact); + private AbstractIntroductionMessage getMessageFor(ClientHelper ch, + Contact contact, MessageType type) + throws FormatException, DbException { + Group g = introductionManager0.getContactGroup(contact); + BdfDictionary query = BdfDictionary.of( + new BdfEntry(MSG_KEY_MESSAGE_TYPE, type.getValue()) + ); Map<MessageId, BdfDictionary> map = - ch.getMessageMetadataAsDictionary(g.getId()); - for (Entry<MessageId, BdfDictionary> entry : map.entrySet()) { - if (entry.getValue().getLong(TYPE) == type) { - response = entry; - } - } - assertTrue(response != null); - return response; + ch.getMessageMetadataAsDictionary(g.getId(), query); + assertEquals(1, map.size()); + MessageId id = map.entrySet().iterator().next().getKey(); + Message m = ch.getMessage(id); + BdfList body = ch.getMessageAsList(id); + //noinspection ConstantConditions + return c0.getMessageParser().parseAcceptMessage(m, body); } } diff --git a/briar-core/src/test/java/org/briarproject/briar/introduction/IntroductionIntegrationTestComponent.java b/briar-core/src/test/java/org/briarproject/briar/introduction/IntroductionIntegrationTestComponent.java index bc0ea62410713a6ae9f4a3f5034c8e10c187111b..a46d37cbedd9836ac766eb9f8308c1df3d437777 100644 --- a/briar-core/src/test/java/org/briarproject/briar/introduction/IntroductionIntegrationTestComponent.java +++ b/briar-core/src/test/java/org/briarproject/briar/introduction/IntroductionIntegrationTestComponent.java @@ -59,6 +59,7 @@ interface IntroductionIntegrationTestComponent void inject(IntroductionIntegrationTest init); - MessageSender getMessageSender(); + MessageEncoder getMessageEncoder(); + MessageParser getMessageParser(); } diff --git a/briar-core/src/test/java/org/briarproject/briar/introduction/IntroductionManagerImplTest.java b/briar-core/src/test/java/org/briarproject/briar/introduction/IntroductionManagerImplTest.java deleted file mode 100644 index e445910201364626e62d3d8b74b535d81ebd7d1c..0000000000000000000000000000000000000000 --- a/briar-core/src/test/java/org/briarproject/briar/introduction/IntroductionManagerImplTest.java +++ /dev/null @@ -1,291 +0,0 @@ -package org.briarproject.briar.introduction; - -import org.briarproject.bramble.api.FormatException; -import org.briarproject.bramble.api.client.ClientHelper; -import org.briarproject.bramble.api.contact.Contact; -import org.briarproject.bramble.api.contact.ContactId; -import org.briarproject.bramble.api.data.BdfDictionary; -import org.briarproject.bramble.api.data.BdfEntry; -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.Transaction; -import org.briarproject.bramble.api.identity.Author; -import org.briarproject.bramble.api.identity.AuthorId; -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.sync.MessageStatus; -import org.briarproject.briar.api.client.MessageTracker; -import org.briarproject.briar.api.client.SessionId; -import org.briarproject.briar.test.BriarTestCase; -import org.jmock.Expectations; -import org.jmock.Mockery; -import org.jmock.lib.legacy.ClassImposteriser; -import org.junit.Test; - -import java.util.Collection; -import java.util.Collections; -import java.util.Map; - -import static org.briarproject.bramble.api.sync.SyncConstants.MESSAGE_HEADER_LENGTH; -import static org.briarproject.bramble.test.TestUtils.getAuthor; -import static org.briarproject.bramble.test.TestUtils.getGroup; -import static org.briarproject.bramble.test.TestUtils.getRandomBytes; -import static org.briarproject.bramble.test.TestUtils.getRandomId; -import static org.briarproject.briar.api.introduction.IntroductionConstants.GROUP_ID_1; -import static org.briarproject.briar.api.introduction.IntroductionConstants.GROUP_ID_2; -import static org.briarproject.briar.api.introduction.IntroductionConstants.ROLE; -import static org.briarproject.briar.api.introduction.IntroductionConstants.ROLE_INTRODUCER; -import static org.briarproject.briar.api.introduction.IntroductionConstants.SESSION_ID; -import static org.briarproject.briar.api.introduction.IntroductionConstants.TYPE; -import static org.briarproject.briar.api.introduction.IntroductionConstants.TYPE_REQUEST; -import static org.briarproject.briar.api.introduction.IntroductionConstants.TYPE_RESPONSE; -import static org.briarproject.briar.api.introduction.IntroductionManager.CLIENT_ID; -import static org.junit.Assert.assertFalse; - -public class IntroductionManagerImplTest extends BriarTestCase { - - private final Mockery context; - private final IntroductionManagerImpl introductionManager; - private final IntroducerManager introducerManager; - private final IntroduceeManager introduceeManager; - private final DatabaseComponent db; - private final ClientHelper clientHelper; - private final MessageTracker messageTracker; - private final IntroductionGroupFactory introductionGroupFactory; - private final SessionId sessionId = new SessionId(getRandomId()); - private final MessageId storageId = new MessageId(sessionId.getBytes()); - private final long time = 42L; - private final Contact introducee1; - private final Contact introducee2; - private final Group introductionGroup1; - private final Group introductionGroup2; - private final Message message1; - private Transaction txn; - - public IntroductionManagerImplTest() { - Author author1 = getAuthor(); - AuthorId localAuthorId1 = new AuthorId(getRandomId()); - ContactId contactId1 = new ContactId(234); - introducee1 = - new Contact(contactId1, author1, localAuthorId1, true, true); - - Author author2 = getAuthor(); - AuthorId localAuthorId2 = new AuthorId(getRandomId()); - ContactId contactId2 = new ContactId(235); - introducee2 = - new Contact(contactId2, author2, localAuthorId2, true, true); - - introductionGroup1 = getGroup(CLIENT_ID); - introductionGroup2 = getGroup(CLIENT_ID); - - message1 = new Message( - new MessageId(getRandomId()), - introductionGroup1.getId(), - time, - getRandomBytes(MESSAGE_HEADER_LENGTH + 1) - ); - - // mock ALL THE THINGS!!! - context = new Mockery(); - context.setImposteriser(ClassImposteriser.INSTANCE); - introducerManager = context.mock(IntroducerManager.class); - introduceeManager = context.mock(IntroduceeManager.class); - db = context.mock(DatabaseComponent.class); - clientHelper = context.mock(ClientHelper.class); - MetadataParser metadataParser = context.mock(MetadataParser.class); - messageTracker = context.mock(MessageTracker.class); - introductionGroupFactory = context.mock(IntroductionGroupFactory.class); - - introductionManager = new IntroductionManagerImpl(db, clientHelper, - metadataParser, messageTracker, introducerManager, - introduceeManager, introductionGroupFactory); - } - - @Test - public void testMakeIntroduction() throws DbException, FormatException { - txn = new Transaction(null, false); - - context.checking(new Expectations() {{ - oneOf(db).startTransaction(false); - will(returnValue(txn)); - oneOf(introducerManager) - .makeIntroduction(txn, introducee1, introducee2, null, - time); - // get both introduction groups - oneOf(introductionGroupFactory) - .createIntroductionGroup(introducee1); - will(returnValue(introductionGroup1)); - oneOf(introductionGroupFactory) - .createIntroductionGroup(introducee2); - will(returnValue(introductionGroup2)); - // track message for group 1 - oneOf(messageTracker).trackMessage(txn, - introductionGroup1.getId(), time, true); - // track message for group 2 - oneOf(messageTracker).trackMessage(txn, - introductionGroup2.getId(), time, true); - oneOf(db).commitTransaction(txn); - oneOf(db).endTransaction(txn); - }}); - - introductionManager - .makeIntroduction(introducee1, introducee2, null, time); - - context.assertIsSatisfied(); - } - - @Test - public void testAcceptIntroduction() throws DbException, FormatException { - BdfDictionary state = BdfDictionary.of( - new BdfEntry(GROUP_ID_1, introductionGroup1.getId()), - new BdfEntry(GROUP_ID_2, introductionGroup2.getId()) - ); - txn = new Transaction(null, false); - - context.checking(new Expectations() {{ - oneOf(db).startTransaction(false); - will(returnValue(txn)); - oneOf(db).getContact(txn, introducee1.getId()); - will(returnValue(introducee1)); - oneOf(introductionGroupFactory).createIntroductionGroup(introducee1); - will(returnValue(introductionGroup1)); - oneOf(clientHelper).getMessageMetadataAsDictionary(txn, storageId); - will(returnValue(state)); - oneOf(introduceeManager).acceptIntroduction(txn, state, time); - // track message - oneOf(messageTracker).trackMessage(txn, - introductionGroup1.getId(), time, true); - oneOf(db).commitTransaction(txn); - oneOf(db).endTransaction(txn); - }}); - - introductionManager - .acceptIntroduction(introducee1.getId(), sessionId, time); - - context.assertIsSatisfied(); - } - - @Test - public void testDeclineIntroduction() throws DbException, FormatException { - BdfDictionary state = BdfDictionary.of( - new BdfEntry(GROUP_ID_1, introductionGroup1.getId()), - new BdfEntry(GROUP_ID_2, introductionGroup2.getId()) - ); - txn = new Transaction(null, false); - - context.checking(new Expectations() {{ - oneOf(db).startTransaction(false); - will(returnValue(txn)); - oneOf(db).getContact(txn, introducee1.getId()); - will(returnValue(introducee1)); - oneOf(introductionGroupFactory).createIntroductionGroup(introducee1); - will(returnValue(introductionGroup1)); - oneOf(clientHelper).getMessageMetadataAsDictionary(txn, storageId); - will(returnValue(state)); - oneOf(introduceeManager).declineIntroduction(txn, state, time); - // track message - oneOf(messageTracker).trackMessage(txn, - introductionGroup1.getId(), time, true); - oneOf(db).commitTransaction(txn); - oneOf(db).endTransaction(txn); - }}); - - introductionManager - .declineIntroduction(introducee1.getId(), sessionId, time); - - context.assertIsSatisfied(); - } - - @Test - public void testGetIntroductionMessages() - throws DbException, FormatException { - - Map<MessageId, BdfDictionary> metadata = Collections.emptyMap(); - Collection<MessageStatus> statuses = Collections.emptyList(); - txn = new Transaction(null, false); - - context.checking(new Expectations() {{ - oneOf(db).startTransaction(true); - will(returnValue(txn)); - oneOf(db).getContact(txn, introducee1.getId()); - will(returnValue(introducee1)); - oneOf(introductionGroupFactory).createIntroductionGroup(introducee1); - will(returnValue(introductionGroup1)); - oneOf(clientHelper).getMessageMetadataAsDictionary(txn, - introductionGroup1.getId()); - will(returnValue(metadata)); - oneOf(db).getMessageStatus(txn, introducee1.getId(), - introductionGroup1.getId()); - will(returnValue(statuses)); - oneOf(db).commitTransaction(txn); - oneOf(db).endTransaction(txn); - }}); - - introductionManager.getIntroductionMessages(introducee1.getId()); - - context.assertIsSatisfied(); - } - - @Test - public void testIncomingRequestMessage() - throws DbException, FormatException { - - BdfDictionary msg = new BdfDictionary(); - msg.put(TYPE, TYPE_REQUEST); - - BdfDictionary state = new BdfDictionary(); - txn = new Transaction(null, false); - - context.checking(new Expectations() {{ - oneOf(introduceeManager) - .initialize(txn, introductionGroup1.getId(), msg); - will(returnValue(state)); - oneOf(introduceeManager) - .incomingMessage(txn, state, msg); - // track message - oneOf(messageTracker).trackIncomingMessage(txn, message1); - }}); - - introductionManager - .incomingMessage(txn, message1, new BdfList(), msg); - - context.assertIsSatisfied(); - assertFalse(txn.isCommitted()); - } - - @Test - public void testIncomingResponseMessage() - throws DbException, FormatException { - - BdfDictionary msg = BdfDictionary.of( - new BdfEntry(TYPE, TYPE_RESPONSE), - new BdfEntry(SESSION_ID, sessionId) - ); - - BdfDictionary state = new BdfDictionary(); - state.put(ROLE, ROLE_INTRODUCER); - state.put(GROUP_ID_1, introductionGroup1.getId()); - state.put(GROUP_ID_2, introductionGroup2.getId()); - - txn = new Transaction(null, false); - - context.checking(new Expectations() {{ - oneOf(clientHelper).getMessageMetadataAsDictionary(txn, storageId); - will(returnValue(state)); - oneOf(introducerManager).incomingMessage(txn, state, msg); - // track message - oneOf(messageTracker).trackIncomingMessage(txn, message1); - }}); - - introductionManager - .incomingMessage(txn, message1, new BdfList(), msg); - - context.assertIsSatisfied(); - assertFalse(txn.isCommitted()); - } - - -} 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 a2d481547c7c75e2e53c490f51ac4299bc10997f..4629a1f733c1cdd523b455a3546fea8f8d9e01b5 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 @@ -1,361 +1,424 @@ package org.briarproject.briar.introduction; import org.briarproject.bramble.api.FormatException; -import org.briarproject.bramble.api.client.ClientHelper; +import org.briarproject.bramble.api.client.BdfMessageContext; import org.briarproject.bramble.api.data.BdfDictionary; import org.briarproject.bramble.api.data.BdfEntry; import org.briarproject.bramble.api.data.BdfList; -import org.briarproject.bramble.api.data.MetadataEncoder; -import org.briarproject.bramble.api.identity.Author; -import org.briarproject.bramble.api.plugin.TransportId; -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.bramble.system.SystemClock; +import org.briarproject.bramble.test.ValidatorTestCase; import org.briarproject.briar.api.client.SessionId; -import org.briarproject.briar.test.BriarTestCase; -import org.jmock.Mockery; +import org.jmock.Expectations; import org.junit.Test; -import static org.briarproject.bramble.api.crypto.CryptoConstants.MAX_AGREEMENT_PUBLIC_KEY_BYTES; -import static org.briarproject.bramble.api.identity.AuthorConstants.MAX_AUTHOR_NAME_LENGTH; +import javax.annotation.Nullable; + +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.api.properties.TransportPropertyConstants.MAX_PROPERTY_LENGTH; -import static org.briarproject.bramble.api.sync.SyncConstants.MAX_MESSAGE_BODY_LENGTH; -import static org.briarproject.bramble.test.TestUtils.getAuthor; -import static org.briarproject.bramble.test.TestUtils.getClientId; -import static org.briarproject.bramble.test.TestUtils.getGroup; import static org.briarproject.bramble.test.TestUtils.getRandomBytes; import static org.briarproject.bramble.test.TestUtils.getRandomId; import static org.briarproject.bramble.util.StringUtils.getRandomString; -import static org.briarproject.briar.api.introduction.IntroductionConstants.ACCEPT; -import static org.briarproject.briar.api.introduction.IntroductionConstants.E_PUBLIC_KEY; -import static org.briarproject.briar.api.introduction.IntroductionConstants.GROUP_ID; -import static org.briarproject.briar.api.introduction.IntroductionConstants.MAC; -import static org.briarproject.briar.api.introduction.IntroductionConstants.MAC_LENGTH; -import static org.briarproject.briar.api.introduction.IntroductionConstants.MAX_INTRODUCTION_MESSAGE_LENGTH; -import static org.briarproject.briar.api.introduction.IntroductionConstants.MSG; -import static org.briarproject.briar.api.introduction.IntroductionConstants.NAME; -import static org.briarproject.briar.api.introduction.IntroductionConstants.PUBLIC_KEY; -import static org.briarproject.briar.api.introduction.IntroductionConstants.SESSION_ID; -import static org.briarproject.briar.api.introduction.IntroductionConstants.SIGNATURE; -import static org.briarproject.briar.api.introduction.IntroductionConstants.TIME; -import static org.briarproject.briar.api.introduction.IntroductionConstants.TRANSPORT; -import static org.briarproject.briar.api.introduction.IntroductionConstants.TYPE; -import static org.briarproject.briar.api.introduction.IntroductionConstants.TYPE_ABORT; -import static org.briarproject.briar.api.introduction.IntroductionConstants.TYPE_ACK; -import static org.briarproject.briar.api.introduction.IntroductionConstants.TYPE_REQUEST; -import static org.briarproject.briar.api.introduction.IntroductionConstants.TYPE_RESPONSE; -import static org.junit.Assert.assertArrayEquals; +import static org.briarproject.briar.api.introduction.IntroductionConstants.MAX_REQUEST_MESSAGE_LENGTH; +import static org.briarproject.briar.introduction.MessageType.ABORT; +import static org.briarproject.briar.introduction.MessageType.ACCEPT; +import static org.briarproject.briar.introduction.MessageType.ACTIVATE; +import static org.briarproject.briar.introduction.MessageType.AUTH; +import static org.briarproject.briar.introduction.MessageType.DECLINE; +import static org.briarproject.briar.introduction.MessageType.REQUEST; import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -public class IntroductionValidatorTest extends BriarTestCase { +public class IntroductionValidatorTest extends ValidatorTestCase { + + private final MessageEncoder messageEncoder = + context.mock(MessageEncoder.class); + private final IntroductionValidator validator = + new IntroductionValidator(messageEncoder, clientHelper, + metadataEncoder, clock); + + private final SessionId sessionId = new SessionId(getRandomId()); + private final MessageId previousMsgId = new MessageId(getRandomId()); + private final String text = getRandomString(MAX_REQUEST_MESSAGE_LENGTH); + private final BdfDictionary meta = new BdfDictionary(); + private final long acceptTimestamp = 42; + private final BdfDictionary transportProperties = BdfDictionary.of( + new BdfEntry("transportId", new BdfDictionary()) + ); + private final byte[] mac = getRandomBytes(MAC_BYTES); + private final byte[] signature = getRandomBytes(MAX_SIGNATURE_BYTES); - private final Mockery context = new Mockery(); - private final Group group; - private final Message message; - private final IntroductionValidator validator; - private final Clock clock = new SystemClock(); + // + // Introduction REQUEST + // - public IntroductionValidatorTest() { - group = getGroup(getClientId()); - MessageId messageId = new MessageId(getRandomId()); - long timestamp = System.currentTimeMillis(); - byte[] raw = getRandomBytes(123); - message = new Message(messageId, group.getId(), timestamp, raw); + @Test + public void testAcceptsRequest() throws Exception { + BdfList body = BdfList.of(REQUEST.getValue(), previousMsgId.getBytes(), + authorList, text); + expectParseAuthor(authorList, author); + expectEncodeRequestMetadata(); + BdfMessageContext messageContext = + validator.validateMessage(message, group, body); - ClientHelper clientHelper = context.mock(ClientHelper.class); - MetadataEncoder metadataEncoder = context.mock(MetadataEncoder.class); - validator = new IntroductionValidator(clientHelper, metadataEncoder, - clock); - context.assertIsSatisfied(); + assertExpectedContext(messageContext, previousMsgId); } - // - // Introduction Requests - // - @Test - public void testValidateProperIntroductionRequest() throws Exception { - byte[] sessionId = getRandomId(); - String name = getRandomString(MAX_AUTHOR_NAME_LENGTH); - byte[] publicKey = getRandomBytes(MAX_PUBLIC_KEY_LENGTH); - String text = getRandomString(MAX_INTRODUCTION_MESSAGE_LENGTH); + public void testAcceptsRequestWithPreviousMsgIdNull() throws Exception { + BdfList body = BdfList.of(REQUEST.getValue(), null, authorList, text); - BdfList body = BdfList.of(TYPE_REQUEST, sessionId, - name, publicKey, text); + expectParseAuthor(authorList, author); + expectEncodeRequestMetadata(); + BdfMessageContext messageContext = + validator.validateMessage(message, group, body); - BdfDictionary result = - validator.validateMessage(message, group, body).getDictionary(); + assertExpectedContext(messageContext, null); + } + + @Test + public void testAcceptsRequestWithMessageNull() throws Exception { + BdfList body = BdfList.of(REQUEST.getValue(), null, authorList, null); + + expectParseAuthor(authorList, author); + expectEncodeRequestMetadata(); + BdfMessageContext messageContext = + validator.validateMessage(message, group, body); - assertEquals(Long.valueOf(TYPE_REQUEST), result.getLong(TYPE)); - assertEquals(sessionId, result.getRaw(SESSION_ID)); - assertEquals(name, result.getString(NAME)); - assertEquals(publicKey, result.getRaw(PUBLIC_KEY)); - assertEquals(text, result.getString(MSG)); - context.assertIsSatisfied(); + assertExpectedContext(messageContext, null); } @Test(expected = FormatException.class) - public void testValidateIntroductionRequestWithNoName() throws Exception { - BdfDictionary msg = getValidIntroductionRequest(); + public void testRejectsTooShortBodyForRequest() throws Exception { + BdfList body = BdfList.of(REQUEST.getValue(), null, authorList); + validator.validateMessage(message, group, body); + } - // no NAME is message - BdfList body = BdfList.of(msg.getLong(TYPE), msg.getRaw(SESSION_ID), - msg.getRaw(PUBLIC_KEY)); - if (msg.containsKey(MSG)) body.add(msg.getString(MSG)); + @Test(expected = FormatException.class) + public void testRejectsTooLongBodyForRequest() throws Exception { + BdfList body = + BdfList.of(REQUEST.getValue(), null, authorList, text, null); + validator.validateMessage(message, group, body); + } + @Test(expected = FormatException.class) + public void testRejectsRawMessageForRequest() throws Exception { + BdfList body = + BdfList.of(REQUEST.getValue(), null, authorList, getRandomId()); + expectParseAuthor(authorList, author); validator.validateMessage(message, group, body); } @Test(expected = FormatException.class) - public void testValidateIntroductionRequestWithLongName() throws Exception { - // too long NAME in message - BdfDictionary msg = getValidIntroductionRequest(); - msg.put(NAME, msg.get(NAME) + "x"); - BdfList body = BdfList.of(msg.getLong(TYPE), msg.getRaw(SESSION_ID), - msg.getString(NAME), msg.getRaw(PUBLIC_KEY)); - if (msg.containsKey(MSG)) body.add(msg.getString(MSG)); + public void testRejectsStringMessageIdForRequest() throws Exception { + BdfList body = + BdfList.of(REQUEST.getValue(), "NoMessageId", authorList, null); + validator.validateMessage(message, group, body); + } + // + // Introduction ACCEPT + // + + @Test + public void testAcceptsAccept() throws Exception { + BdfList body = BdfList.of(ACCEPT.getValue(), sessionId.getBytes(), + previousMsgId.getBytes(), getRandomBytes(MAX_PUBLIC_KEY_LENGTH), + acceptTimestamp, transportProperties); + context.checking(new Expectations() {{ + oneOf(clientHelper).parseAndValidateTransportProperties( + transportProperties.getDictionary("transportId")); + }}); + expectEncodeMetadata(ACCEPT); + BdfMessageContext messageContext = + validator.validateMessage(message, group, body); + + assertExpectedContext(messageContext, previousMsgId); + } + + @Test(expected = FormatException.class) + public void testRejectsTooShortBodyForAccept() throws Exception { + BdfList body = BdfList.of(ACCEPT.getValue(), sessionId.getBytes(), + previousMsgId.getBytes(), + getRandomBytes(MAX_PUBLIC_KEY_LENGTH), acceptTimestamp); validator.validateMessage(message, group, body); } @Test(expected = FormatException.class) - public void testValidateIntroductionRequestWithWrongType() - throws Exception { - // wrong message type - BdfDictionary msg = getValidIntroductionRequest(); - msg.put(TYPE, 324234); + public void testRejectsTooLongBodyForAccept() throws Exception { + BdfList body = BdfList.of(ACCEPT.getValue(), sessionId.getBytes(), + previousMsgId.getBytes(), getRandomBytes(MAX_PUBLIC_KEY_LENGTH), + acceptTimestamp, transportProperties, null); + validator.validateMessage(message, group, body); + } - BdfList body = BdfList.of(msg.getLong(TYPE), msg.getRaw(SESSION_ID), - msg.getString(NAME), msg.getRaw(PUBLIC_KEY)); - if (msg.containsKey(MSG)) body.add(msg.getString(MSG)); + @Test(expected = FormatException.class) + public void testRejectsInvalidSessionIdForAccept() throws Exception { + BdfList body = + BdfList.of(ACCEPT.getValue(), null, previousMsgId.getBytes(), + getRandomBytes(MAX_PUBLIC_KEY_LENGTH), acceptTimestamp, + transportProperties); validator.validateMessage(message, group, body); } - private BdfDictionary getValidIntroductionRequest() throws Exception { - byte[] sessionId = getRandomId(); - Author author = getAuthor(); - String text = getRandomString(MAX_MESSAGE_BODY_LENGTH); + @Test(expected = FormatException.class) + public void testRejectsInvalidPreviousMsgIdForAccept() throws Exception { + BdfList body = BdfList.of(ACCEPT.getValue(), sessionId.getBytes(), 1, + getRandomBytes(MAX_PUBLIC_KEY_LENGTH), acceptTimestamp, + transportProperties); + validator.validateMessage(message, group, body); + } - BdfDictionary msg = new BdfDictionary(); - msg.put(TYPE, TYPE_REQUEST); - msg.put(SESSION_ID, sessionId); - msg.put(NAME, author.getName()); - msg.put(PUBLIC_KEY, author.getPublicKey()); - msg.put(MSG, text); + @Test(expected = FormatException.class) + public void testRejectsTooLongPublicKeyForAccept() throws Exception { + BdfList body = BdfList.of(ACCEPT.getValue(), sessionId.getBytes(), + previousMsgId.getBytes(), + getRandomBytes(MAX_PUBLIC_KEY_LENGTH + 1), acceptTimestamp, + transportProperties); + validator.validateMessage(message, group, body); + } - return msg; + @Test(expected = FormatException.class) + public void testRejectsEmptyTransportPropertiesForAccept() + throws Exception { + BdfList body = BdfList.of(ACCEPT.getValue(), sessionId.getBytes(), + previousMsgId.getBytes(), + getRandomBytes(MAX_PUBLIC_KEY_LENGTH + 1), acceptTimestamp, + new BdfDictionary()); + validator.validateMessage(message, group, body); } // - // Introduction Responses + // Introduction DECLINE // @Test - public void testValidateIntroductionAcceptResponse() throws Exception { - byte[] groupId = getRandomId(); - byte[] sessionId = getRandomId(); - long time = clock.currentTimeMillis(); - byte[] publicKey = getRandomBytes(MAX_AGREEMENT_PUBLIC_KEY_BYTES); - String transportId = - getRandomString(TransportId.MAX_TRANSPORT_ID_LENGTH); - BdfDictionary tProps = BdfDictionary.of( - new BdfEntry(getRandomString(MAX_PROPERTY_LENGTH), - getRandomString(MAX_PROPERTY_LENGTH)) - ); - BdfDictionary tp = BdfDictionary.of( - new BdfEntry(transportId, tProps) - ); - - BdfDictionary msg = new BdfDictionary(); - msg.put(TYPE, TYPE_RESPONSE); - msg.put(GROUP_ID, groupId); - msg.put(SESSION_ID, sessionId); - msg.put(ACCEPT, true); - msg.put(TIME, time); - msg.put(E_PUBLIC_KEY, publicKey); - msg.put(TRANSPORT, tp); - - BdfList body = BdfList.of(TYPE_RESPONSE, msg.getRaw(SESSION_ID), - msg.getBoolean(ACCEPT), msg.getLong(TIME), - msg.getRaw(E_PUBLIC_KEY), msg.getDictionary(TRANSPORT)); - - BdfDictionary result = - validator.validateMessage(message, group, body).getDictionary(); - - assertEquals(Long.valueOf(TYPE_RESPONSE), result.getLong(TYPE)); - assertEquals(sessionId, result.getRaw(SESSION_ID)); - assertEquals(true, result.getBoolean(ACCEPT)); - assertEquals(publicKey, result.getRaw(E_PUBLIC_KEY)); - assertEquals(tp, result.getDictionary(TRANSPORT)); - context.assertIsSatisfied(); - } + public void testAcceptsDecline() throws Exception { + BdfList body = BdfList.of(DECLINE.getValue(), sessionId.getBytes(), + previousMsgId.getBytes()); - @Test - public void testValidateIntroductionDeclineResponse() throws Exception { - BdfDictionary msg = getValidIntroductionResponse(false); - BdfList body = BdfList.of(msg.getLong(TYPE), msg.getRaw(SESSION_ID), - msg.getBoolean(ACCEPT)); + expectEncodeMetadata(DECLINE); + BdfMessageContext messageContext = + validator.validateMessage(message, group, body); - BdfDictionary result = validator.validateMessage(message, group, body) - .getDictionary(); + assertExpectedContext(messageContext, previousMsgId); + } - assertFalse(result.getBoolean(ACCEPT)); - context.assertIsSatisfied(); + @Test(expected = FormatException.class) + public void testRejectsTooShortBodyForDecline() throws Exception { + BdfList body = BdfList.of(DECLINE.getValue(), sessionId.getBytes()); + validator.validateMessage(message, group, body); } @Test(expected = FormatException.class) - public void testValidateIntroductionResponseWithoutAccept() - throws Exception { - BdfDictionary msg = getValidIntroductionResponse(false); - BdfList body = BdfList.of(msg.getLong(TYPE), msg.getRaw(SESSION_ID)); + public void testRejectsTooLongBodyForDecline() throws Exception { + BdfList body = BdfList.of(DECLINE.getValue(), sessionId.getBytes(), + previousMsgId.getBytes(), null); + validator.validateMessage(message, group, body); + } + @Test(expected = FormatException.class) + public void testRejectsInvalidSessionIdForDecline() throws Exception { + BdfList body = + BdfList.of(DECLINE.getValue(), null, previousMsgId.getBytes()); validator.validateMessage(message, group, body); } @Test(expected = FormatException.class) - public void testValidateIntroductionResponseWithBrokenTp() - throws Exception { - BdfDictionary msg = getValidIntroductionResponse(true); - BdfDictionary tp = msg.getDictionary(TRANSPORT); - tp.put( - getRandomString(TransportId.MAX_TRANSPORT_ID_LENGTH), "X"); - msg.put(TRANSPORT, tp); + public void testRejectsInvalidPreviousMsgIdForDecline() throws Exception { + BdfList body = BdfList.of(DECLINE.getValue(), sessionId.getBytes(), 1); + validator.validateMessage(message, group, body); + } + + // + // Introduction AUTH + // + + @Test + public void testAcceptsAuth() throws Exception { + BdfList body = BdfList.of(AUTH.getValue(), sessionId.getBytes(), + previousMsgId.getBytes(), mac, signature); - BdfList body = BdfList.of(msg.getLong(TYPE), msg.getRaw(SESSION_ID), - msg.getBoolean(ACCEPT), msg.getLong(TIME), - msg.getRaw(E_PUBLIC_KEY), msg.getDictionary(TRANSPORT)); + expectEncodeMetadata(AUTH); + BdfMessageContext messageContext = + validator.validateMessage(message, group, body); + assertExpectedContext(messageContext, previousMsgId); + } + + @Test(expected = FormatException.class) + public void testRejectsTooShortBodyForAuth() throws Exception { + BdfList body = BdfList.of(AUTH.getValue(), sessionId.getBytes(), + previousMsgId.getBytes(), mac); validator.validateMessage(message, group, body); } @Test(expected = FormatException.class) - public void testValidateIntroductionResponseWithoutPublicKey() - throws Exception { - BdfDictionary msg = getValidIntroductionResponse(true); + public void testRejectsTooLongBodyForAuth() throws Exception { + BdfList body = BdfList.of(AUTH.getValue(), sessionId.getBytes(), + previousMsgId.getBytes(), mac, signature, null); + validator.validateMessage(message, group, body); + } - BdfList body = BdfList.of(msg.getLong(TYPE), msg.getRaw(SESSION_ID), - msg.getBoolean(ACCEPT), msg.getLong(TIME), - msg.getDictionary(TRANSPORT)); + @Test(expected = FormatException.class) + public void testRejectsTooShortMacForAuth() throws Exception { + BdfList body = BdfList.of(AUTH.getValue(), sessionId.getBytes(), + previousMsgId.getBytes(), getRandomBytes(MAC_BYTES - 1), + signature); + validator.validateMessage(message, group, body); + } + @Test(expected = FormatException.class) + public void testRejectsTooLongMacForAuth() throws Exception { + BdfList body = BdfList.of(AUTH.getValue(), sessionId.getBytes(), + previousMsgId.getBytes(), + getRandomBytes(MAC_BYTES + 1), signature); validator.validateMessage(message, group, body); } - private BdfDictionary getValidIntroductionResponse(boolean accept) - throws Exception { + @Test(expected = FormatException.class) + public void testRejectsInvalidMacForAuth() throws Exception { + BdfList body = BdfList.of(AUTH.getValue(), sessionId.getBytes(), + previousMsgId.getBytes(), null, signature); + validator.validateMessage(message, group, body); + } - byte[] groupId = getRandomId(); - byte[] sessionId = getRandomId(); - long time = clock.currentTimeMillis(); - byte[] publicKey = getRandomBytes(MAX_AGREEMENT_PUBLIC_KEY_BYTES); - String transportId = - getRandomString(TransportId.MAX_TRANSPORT_ID_LENGTH); - BdfDictionary tProps = BdfDictionary.of( - new BdfEntry(getRandomString(MAX_PROPERTY_LENGTH), - getRandomString(MAX_PROPERTY_LENGTH)) - ); - BdfDictionary tp = BdfDictionary.of( - new BdfEntry(transportId, tProps) - ); - - BdfDictionary msg = new BdfDictionary(); - msg.put(TYPE, TYPE_RESPONSE); - msg.put(GROUP_ID, groupId); - msg.put(SESSION_ID, sessionId); - msg.put(ACCEPT, accept); - if (accept) { - msg.put(TIME, time); - msg.put(E_PUBLIC_KEY, publicKey); - msg.put(TRANSPORT, tp); - } + @Test(expected = FormatException.class) + public void testRejectsTooShortSignatureForAuth() throws Exception { + BdfList body = BdfList.of(AUTH.getValue(), sessionId.getBytes(), + previousMsgId.getBytes(), mac, getRandomBytes(0)); + validator.validateMessage(message, group, body); + } - return msg; + @Test(expected = FormatException.class) + public void testRejectsTooLongSignatureForAuth() throws Exception { + BdfList body = BdfList.of(AUTH.getValue(), sessionId.getBytes(), + previousMsgId.getBytes(), mac, + getRandomBytes(MAX_SIGNATURE_BYTES + 1)); + validator.validateMessage(message, group, body); + } + + @Test(expected = FormatException.class) + public void testRejectsInvalidSignatureForAuth() throws Exception { + BdfList body = BdfList.of(AUTH.getValue(), sessionId.getBytes(), + previousMsgId.getBytes(), mac, null); + validator.validateMessage(message, group, body); } // - // Introduction ACK + // Introduction ACTIVATE // @Test - public void testValidateProperIntroductionAck() throws Exception { - byte[] sessionId = getRandomId(); - byte[] mac = getRandomBytes(MAC_LENGTH); - byte[] sig = getRandomBytes(MAX_SIGNATURE_LENGTH); - BdfList body = BdfList.of(TYPE_ACK, sessionId, mac, sig); + public void testAcceptsActivate() throws Exception { + BdfList body = BdfList.of(ACTIVATE.getValue(), sessionId.getBytes(), + previousMsgId.getBytes()); - BdfDictionary result = - validator.validateMessage(message, group, body).getDictionary(); + expectEncodeMetadata(ACTIVATE); + BdfMessageContext messageContext = + validator.validateMessage(message, group, body); - assertEquals(Long.valueOf(TYPE_ACK), result.getLong(TYPE)); - assertArrayEquals(sessionId, result.getRaw(SESSION_ID)); - assertArrayEquals(mac, result.getRaw(MAC)); - assertArrayEquals(sig, result.getRaw(SIGNATURE)); - context.assertIsSatisfied(); + assertExpectedContext(messageContext, previousMsgId); } @Test(expected = FormatException.class) - public void testValidateTooLongIntroductionAck() throws Exception { - BdfDictionary msg = BdfDictionary.of( - new BdfEntry(TYPE, TYPE_ACK), - new BdfEntry(SESSION_ID, getRandomId()), - new BdfEntry("garbage", getRandomString(255)) - ); - BdfList body = BdfList.of(msg.getLong(TYPE), msg.getRaw(SESSION_ID), - msg.getString("garbage")); + public void testRejectsTooShortBodyForActivate() throws Exception { + BdfList body = BdfList.of(ACTIVATE.getValue(), sessionId.getBytes()); + validator.validateMessage(message, group, body); + } + @Test(expected = FormatException.class) + public void testRejectsTooLongBodyForActivate() throws Exception { + BdfList body = BdfList.of(ACTIVATE.getValue(), sessionId.getBytes(), + previousMsgId.getBytes(), null); validator.validateMessage(message, group, body); } @Test(expected = FormatException.class) - public void testValidateIntroductionAckWithLongSessionId() - throws Exception { - BdfDictionary msg = BdfDictionary.of( - new BdfEntry(TYPE, TYPE_ACK), - new BdfEntry(SESSION_ID, new byte[SessionId.LENGTH + 1]) - ); - BdfList body = BdfList.of(msg.getLong(TYPE), msg.getRaw(SESSION_ID)); + public void testRejectsInvalidSessionIdForActivate() throws Exception { + BdfList body = + BdfList.of(ACTIVATE.getValue(), null, previousMsgId.getBytes()); + validator.validateMessage(message, group, body); + } + @Test(expected = FormatException.class) + public void testRejectsInvalidPreviousMsgIdForActivate() throws Exception { + BdfList body = BdfList.of(ACTIVATE.getValue(), sessionId.getBytes(), 1); validator.validateMessage(message, group, body); } // - // Introduction Abort + // Introduction ABORT // @Test - public void testValidateProperIntroductionAbort() throws Exception { - byte[] sessionId = getRandomId(); + public void testAcceptsAbort() throws Exception { + BdfList body = BdfList.of(ABORT.getValue(), sessionId.getBytes(), + previousMsgId.getBytes()); - BdfDictionary msg = new BdfDictionary(); - msg.put(TYPE, TYPE_ABORT); - msg.put(SESSION_ID, sessionId); + expectEncodeMetadata(ABORT); + BdfMessageContext messageContext = + validator.validateMessage(message, group, body); - BdfList body = BdfList.of(msg.getLong(TYPE), msg.getRaw(SESSION_ID)); + assertExpectedContext(messageContext, previousMsgId); + } - BdfDictionary result = - validator.validateMessage(message, group, body).getDictionary(); + @Test(expected = FormatException.class) + public void testRejectsTooShortBodyForAbort() throws Exception { + BdfList body = BdfList.of(ABORT.getValue(), sessionId.getBytes()); + validator.validateMessage(message, group, body); + } - assertEquals(Long.valueOf(TYPE_ABORT), result.getLong(TYPE)); - assertEquals(sessionId, result.getRaw(SESSION_ID)); - context.assertIsSatisfied(); + @Test(expected = FormatException.class) + public void testRejectsTooLongBodyForAbort() throws Exception { + BdfList body = BdfList.of(ABORT.getValue(), sessionId.getBytes(), + previousMsgId.getBytes(), null); + validator.validateMessage(message, group, body); } @Test(expected = FormatException.class) - public void testValidateTooLongIntroductionAbort() throws Exception { - BdfDictionary msg = BdfDictionary.of( - new BdfEntry(TYPE, TYPE_ABORT), - new BdfEntry(SESSION_ID, getRandomId()), - new BdfEntry("garbage", getRandomString(255)) - ); - BdfList body = BdfList.of(msg.getLong(TYPE), msg.getRaw(SESSION_ID), - msg.getString("garbage")); + public void testRejectsInvalidSessionIdForAbort() throws Exception { + BdfList body = + BdfList.of(ABORT.getValue(), null, previousMsgId.getBytes()); + validator.validateMessage(message, group, body); + } + @Test(expected = FormatException.class) + public void testRejectsInvalidPreviousMsgIdForAbort() throws Exception { + BdfList body = BdfList.of(ABORT.getValue(), sessionId.getBytes(), 1); validator.validateMessage(message, group, body); } + // + // Introduction Helper Methods + // + + private void expectEncodeRequestMetadata() { + context.checking(new Expectations() {{ + oneOf(messageEncoder) + .encodeRequestMetadata(message.getTimestamp(), false, false, + false, false); + will(returnValue(meta)); + }}); + } + + private void expectEncodeMetadata(MessageType type) { + context.checking(new Expectations() {{ + oneOf(messageEncoder) + .encodeMetadata(type, sessionId, message.getTimestamp(), + false, false, false); + will(returnValue(meta)); + }}); + } + + private void assertExpectedContext(BdfMessageContext c, + @Nullable MessageId dependency) { + assertEquals(meta, c.getDictionary()); + if (dependency == null) { + assertEquals(0, c.getDependencies().size()); + } else { + assertEquals(dependency, c.getDependencies().iterator().next()); + } + } + } diff --git a/briar-core/src/test/java/org/briarproject/briar/introduction2/MessageEncoderParserIntegrationTest.java b/briar-core/src/test/java/org/briarproject/briar/introduction/MessageEncoderParserIntegrationTest.java similarity index 96% rename from briar-core/src/test/java/org/briarproject/briar/introduction2/MessageEncoderParserIntegrationTest.java rename to briar-core/src/test/java/org/briarproject/briar/introduction/MessageEncoderParserIntegrationTest.java index e623f814ac569809cbba77f6c2f0217787cd027c..f8c8fae3483774e8d830cd5f9ed97cd78608485b 100644 --- a/briar-core/src/test/java/org/briarproject/briar/introduction2/MessageEncoderParserIntegrationTest.java +++ b/briar-core/src/test/java/org/briarproject/briar/introduction/MessageEncoderParserIntegrationTest.java @@ -1,4 +1,4 @@ -package org.briarproject.briar.introduction2; +package org.briarproject.briar.introduction; import org.briarproject.bramble.api.FormatException; import org.briarproject.bramble.api.client.ClientHelper; @@ -28,9 +28,9 @@ import static org.briarproject.bramble.test.TestUtils.getRandomBytes; import static org.briarproject.bramble.test.TestUtils.getRandomId; import static org.briarproject.bramble.test.TestUtils.getTransportPropertiesMap; import static org.briarproject.bramble.util.StringUtils.getRandomString; -import static org.briarproject.briar.api.introduction.IntroductionConstants.MAX_INTRODUCTION_MESSAGE_LENGTH; -import static org.briarproject.briar.introduction2.MessageType.ABORT; -import static org.briarproject.briar.introduction2.MessageType.REQUEST; +import static org.briarproject.briar.api.introduction.IntroductionConstants.MAX_REQUEST_MESSAGE_LENGTH; +import static org.briarproject.briar.introduction.MessageType.ABORT; +import static org.briarproject.briar.introduction.MessageType.REQUEST; import static org.briarproject.briar.test.BriarTestUtils.getRealAuthor; import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertEquals; @@ -55,8 +55,7 @@ public class MessageEncoderParserIntegrationTest extends BrambleTestCase { private final SessionId sessionId = new SessionId(getRandomId()); private final MessageId previousMsgId = new MessageId(getRandomId()); private final Author author; - private final String text = - getRandomString(MAX_INTRODUCTION_MESSAGE_LENGTH); + private final String text = getRandomString(MAX_REQUEST_MESSAGE_LENGTH); private final byte[] ephemeralPublicKey = getRandomBytes(MAX_PUBLIC_KEY_LENGTH); private final byte[] mac = getRandomBytes(MAC_BYTES); diff --git a/briar-core/src/test/java/org/briarproject/briar/introduction2/MessageEncoderTest.java b/briar-core/src/test/java/org/briarproject/briar/introduction/MessageEncoderTest.java similarity index 90% rename from briar-core/src/test/java/org/briarproject/briar/introduction2/MessageEncoderTest.java rename to briar-core/src/test/java/org/briarproject/briar/introduction/MessageEncoderTest.java index c7d60662d47664b2263a94236b4c87c054f4fce5..b1dae81c80b3f042f6ee3ab0e574648e65b1fd0f 100644 --- a/briar-core/src/test/java/org/briarproject/briar/introduction2/MessageEncoderTest.java +++ b/briar-core/src/test/java/org/briarproject/briar/introduction/MessageEncoderTest.java @@ -1,4 +1,4 @@ -package org.briarproject.briar.introduction2; +package org.briarproject.briar.introduction; import org.briarproject.bramble.api.FormatException; import org.briarproject.bramble.api.client.ClientHelper; @@ -16,8 +16,8 @@ import static org.briarproject.bramble.test.TestUtils.getAuthor; import static org.briarproject.bramble.test.TestUtils.getRandomBytes; import static org.briarproject.bramble.test.TestUtils.getRandomId; import static org.briarproject.bramble.util.StringUtils.getRandomString; -import static org.briarproject.briar.api.introduction.IntroductionConstants.MAX_INTRODUCTION_MESSAGE_LENGTH; -import static org.briarproject.briar.introduction2.MessageType.REQUEST; +import static org.briarproject.briar.api.introduction.IntroductionConstants.MAX_REQUEST_MESSAGE_LENGTH; +import static org.briarproject.briar.introduction.MessageType.REQUEST; public class MessageEncoderTest extends BrambleMockTestCase { @@ -35,8 +35,7 @@ public class MessageEncoderTest extends BrambleMockTestCase { private final byte[] body = getRandomBytes(42); private final Author author = getAuthor(); private final BdfList authorList = new BdfList(); - private final String text = - getRandomString(MAX_INTRODUCTION_MESSAGE_LENGTH); + private final String text = getRandomString(MAX_REQUEST_MESSAGE_LENGTH); @Test public void testEncodeRequestMessage() throws FormatException { diff --git a/briar-core/src/test/java/org/briarproject/briar/introduction/MessageSenderTest.java b/briar-core/src/test/java/org/briarproject/briar/introduction/MessageSenderTest.java deleted file mode 100644 index 1f922d70644fef119fa0b506dd25707ffa46b9d4..0000000000000000000000000000000000000000 --- a/briar-core/src/test/java/org/briarproject/briar/introduction/MessageSenderTest.java +++ /dev/null @@ -1,98 +0,0 @@ -package org.briarproject.briar.introduction; - -import org.briarproject.bramble.api.FormatException; -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.data.BdfList; -import org.briarproject.bramble.api.data.MetadataEncoder; -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.sync.Group; -import org.briarproject.bramble.api.system.Clock; -import org.briarproject.briar.api.client.MessageQueueManager; -import org.briarproject.briar.api.client.SessionId; -import org.briarproject.briar.test.BriarTestCase; -import org.jmock.Expectations; -import org.jmock.Mockery; -import org.junit.Test; - -import static org.briarproject.bramble.api.identity.AuthorConstants.MAX_SIGNATURE_LENGTH; -import static org.briarproject.bramble.test.TestUtils.getClientId; -import static org.briarproject.bramble.test.TestUtils.getGroup; -import static org.briarproject.bramble.test.TestUtils.getRandomBytes; -import static org.briarproject.bramble.test.TestUtils.getRandomId; -import static org.briarproject.briar.api.introduction.IntroductionConstants.GROUP_ID; -import static org.briarproject.briar.api.introduction.IntroductionConstants.MAC; -import static org.briarproject.briar.api.introduction.IntroductionConstants.SESSION_ID; -import static org.briarproject.briar.api.introduction.IntroductionConstants.SIGNATURE; -import static org.briarproject.briar.api.introduction.IntroductionConstants.TYPE; -import static org.briarproject.briar.api.introduction.IntroductionConstants.TYPE_ACK; -import static org.junit.Assert.assertFalse; - -public class MessageSenderTest extends BriarTestCase { - - private final Mockery context; - private final MessageSender messageSender; - private final DatabaseComponent db; - private final ClientHelper clientHelper; - private final MetadataEncoder metadataEncoder; - private final MessageQueueManager messageQueueManager; - private final Clock clock; - - public MessageSenderTest() { - context = new Mockery(); - db = context.mock(DatabaseComponent.class); - clientHelper = context.mock(ClientHelper.class); - metadataEncoder = - context.mock(MetadataEncoder.class); - messageQueueManager = - context.mock(MessageQueueManager.class); - clock = context.mock(Clock.class); - - messageSender = new MessageSender(db, clientHelper, clock, - metadataEncoder, messageQueueManager); - } - - @Test - public void testSendMessage() throws DbException, FormatException { - Transaction txn = new Transaction(null, false); - Group privateGroup = getGroup(getClientId()); - SessionId sessionId = new SessionId(getRandomId()); - byte[] mac = getRandomBytes(42); - byte[] sig = getRandomBytes(MAX_SIGNATURE_LENGTH); - long time = 42L; - BdfDictionary msg = BdfDictionary.of( - new BdfEntry(TYPE, TYPE_ACK), - new BdfEntry(GROUP_ID, privateGroup.getId()), - new BdfEntry(SESSION_ID, sessionId), - new BdfEntry(MAC, mac), - new BdfEntry(SIGNATURE, sig) - ); - BdfList bodyList = - BdfList.of(TYPE_ACK, sessionId.getBytes(), mac, sig); - byte[] body = getRandomBytes(8); - Metadata metadata = new Metadata(); - - context.checking(new Expectations() {{ - oneOf(clientHelper).toByteArray(bodyList); - will(returnValue(body)); - oneOf(db).getGroup(txn, privateGroup.getId()); - will(returnValue(privateGroup)); - oneOf(metadataEncoder).encode(msg); - will(returnValue(metadata)); - oneOf(clock).currentTimeMillis(); - will(returnValue(time)); - oneOf(messageQueueManager) - .sendMessage(txn, privateGroup, time, body, metadata); - }}); - - messageSender.sendMessage(txn, msg); - - context.assertIsSatisfied(); - assertFalse(txn.isCommitted()); - } - -} diff --git a/briar-core/src/test/java/org/briarproject/briar/introduction2/SessionEncoderParserIntegrationTest.java b/briar-core/src/test/java/org/briarproject/briar/introduction/SessionEncoderParserIntegrationTest.java similarity index 95% rename from briar-core/src/test/java/org/briarproject/briar/introduction2/SessionEncoderParserIntegrationTest.java rename to briar-core/src/test/java/org/briarproject/briar/introduction/SessionEncoderParserIntegrationTest.java index 24ddf208a3873ad9ac9b0c5642eb7f01c20a5d5d..00bec26a832f2e5cb3480fcb943d099fbc47369a 100644 --- a/briar-core/src/test/java/org/briarproject/briar/introduction2/SessionEncoderParserIntegrationTest.java +++ b/briar-core/src/test/java/org/briarproject/briar/introduction/SessionEncoderParserIntegrationTest.java @@ -1,4 +1,4 @@ -package org.briarproject.briar.introduction2; +package org.briarproject.briar.introduction; import org.briarproject.bramble.api.FormatException; import org.briarproject.bramble.api.client.ClientHelper; @@ -13,7 +13,7 @@ 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.briar.introduction2.IntroducerSession.Introducee; +import org.briarproject.briar.introduction.IntroducerSession.Introducee; import org.briarproject.briar.test.BriarIntegrationTestComponent; import org.briarproject.briar.test.DaggerBriarIntegrationTestComponent; import org.junit.Test; @@ -29,11 +29,11 @@ import static org.briarproject.bramble.test.TestUtils.getRandomId; import static org.briarproject.bramble.test.TestUtils.getTransportId; import static org.briarproject.bramble.test.TestUtils.getTransportPropertiesMap; import static org.briarproject.bramble.util.StringUtils.getRandomString; -import static org.briarproject.briar.introduction2.IntroduceeState.LOCAL_ACCEPTED; -import static org.briarproject.briar.introduction2.IntroducerState.AWAIT_AUTHS; -import static org.briarproject.briar.introduction2.IntroductionConstants.SESSION_KEY_ROLE; -import static org.briarproject.briar.api.introduction2.Role.INTRODUCEE; -import static org.briarproject.briar.api.introduction2.Role.INTRODUCER; +import static org.briarproject.briar.introduction.IntroduceeState.LOCAL_ACCEPTED; +import static org.briarproject.briar.introduction.IntroducerState.AWAIT_AUTHS; +import static org.briarproject.briar.introduction.IntroductionConstants.SESSION_KEY_ROLE; +import static org.briarproject.briar.api.introduction.Role.INTRODUCEE; +import static org.briarproject.briar.api.introduction.Role.INTRODUCER; import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNull; diff --git a/briar-core/src/test/java/org/briarproject/briar/introduction2/IntroductionValidatorTest.java b/briar-core/src/test/java/org/briarproject/briar/introduction2/IntroductionValidatorTest.java deleted file mode 100644 index 0fa094a5eaa5fed5466b8743d9d9dbe8d37ad649..0000000000000000000000000000000000000000 --- a/briar-core/src/test/java/org/briarproject/briar/introduction2/IntroductionValidatorTest.java +++ /dev/null @@ -1,428 +0,0 @@ -package org.briarproject.briar.introduction2; - -import org.briarproject.bramble.api.FormatException; -import org.briarproject.bramble.api.client.BdfMessageContext; -import org.briarproject.bramble.api.data.BdfDictionary; -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.jmock.Expectations; -import org.junit.Test; - -import javax.annotation.Nullable; - -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.test.TestUtils.getRandomBytes; -import static org.briarproject.bramble.test.TestUtils.getRandomId; -import static org.briarproject.bramble.util.StringUtils.getRandomString; -import static org.briarproject.briar.api.introduction.IntroductionConstants.MAX_INTRODUCTION_MESSAGE_LENGTH; -import static org.briarproject.briar.introduction2.MessageType.ABORT; -import static org.briarproject.briar.introduction2.MessageType.ACCEPT; -import static org.briarproject.briar.introduction2.MessageType.ACTIVATE; -import static org.briarproject.briar.introduction2.MessageType.AUTH; -import static org.briarproject.briar.introduction2.MessageType.DECLINE; -import static org.briarproject.briar.introduction2.MessageType.REQUEST; -import static org.junit.Assert.assertEquals; - -public class IntroductionValidatorTest extends ValidatorTestCase { - - private final MessageEncoder messageEncoder = - context.mock(MessageEncoder.class); - private final IntroductionValidator validator = - new IntroductionValidator(messageEncoder, clientHelper, - metadataEncoder, clock); - - private final SessionId sessionId = new SessionId(getRandomId()); - private final MessageId previousMsgId = new MessageId(getRandomId()); - private final String text = - getRandomString(MAX_INTRODUCTION_MESSAGE_LENGTH); - private final BdfDictionary meta = new BdfDictionary(); - private final long acceptTimestamp = 42; - private final BdfDictionary transportProperties = BdfDictionary.of( - new BdfEntry("transportId", new BdfDictionary()) - ); - private final byte[] mac = getRandomBytes(MAC_BYTES); - private final byte[] signature = getRandomBytes(MAX_SIGNATURE_BYTES); - - // - // Introduction REQUEST - // - - @Test - public void testAcceptsRequest() throws Exception { - BdfList body = BdfList.of(REQUEST.getValue(), previousMsgId.getBytes(), - authorList, text); - - expectParseAuthor(authorList, author); - expectEncodeRequestMetadata(); - BdfMessageContext messageContext = - validator.validateMessage(message, group, body); - - assertExpectedContext(messageContext, previousMsgId); - } - - @Test - public void testAcceptsRequestWithPreviousMsgIdNull() throws Exception { - BdfList body = BdfList.of(REQUEST.getValue(), null, authorList, text); - - expectParseAuthor(authorList, author); - expectEncodeRequestMetadata(); - BdfMessageContext messageContext = - validator.validateMessage(message, group, body); - - assertExpectedContext(messageContext, null); - } - - @Test - public void testAcceptsRequestWithMessageNull() throws Exception { - BdfList body = BdfList.of(REQUEST.getValue(), null, authorList, null); - - expectParseAuthor(authorList, author); - expectEncodeRequestMetadata(); - BdfMessageContext messageContext = - validator.validateMessage(message, group, body); - - assertExpectedContext(messageContext, null); - } - - @Test(expected = FormatException.class) - public void testRejectsTooShortBodyForRequest() throws Exception { - BdfList body = BdfList.of(REQUEST.getValue(), null, authorList); - validator.validateMessage(message, group, body); - } - - @Test(expected = FormatException.class) - public void testRejectsTooLongBodyForRequest() throws Exception { - BdfList body = - BdfList.of(REQUEST.getValue(), null, authorList, text, null); - validator.validateMessage(message, group, body); - } - - @Test(expected = FormatException.class) - public void testRejectsRawMessageForRequest() throws Exception { - BdfList body = - BdfList.of(REQUEST.getValue(), null, authorList, getRandomId()); - expectParseAuthor(authorList, author); - validator.validateMessage(message, group, body); - } - - @Test(expected = FormatException.class) - public void testRejectsStringMessageIdForRequest() throws Exception { - BdfList body = - BdfList.of(REQUEST.getValue(), "NoMessageId", authorList, null); - validator.validateMessage(message, group, body); - } - - // - // Introduction ACCEPT - // - - @Test - public void testAcceptsAccept() throws Exception { - BdfList body = BdfList.of(ACCEPT.getValue(), sessionId.getBytes(), - previousMsgId.getBytes(), getRandomBytes(MAX_PUBLIC_KEY_LENGTH), - acceptTimestamp, transportProperties); - context.checking(new Expectations() {{ - oneOf(clientHelper).parseAndValidateTransportProperties( - transportProperties.getDictionary("transportId")); - }}); - expectEncodeMetadata(ACCEPT); - BdfMessageContext messageContext = - validator.validateMessage(message, group, body); - - assertExpectedContext(messageContext, previousMsgId); - } - - @Test(expected = FormatException.class) - public void testRejectsTooShortBodyForAccept() throws Exception { - BdfList body = BdfList.of(ACCEPT.getValue(), sessionId.getBytes(), - previousMsgId.getBytes(), - getRandomBytes(MAX_PUBLIC_KEY_LENGTH), acceptTimestamp); - validator.validateMessage(message, group, body); - } - - @Test(expected = FormatException.class) - public void testRejectsTooLongBodyForAccept() throws Exception { - BdfList body = BdfList.of(ACCEPT.getValue(), sessionId.getBytes(), - previousMsgId.getBytes(), getRandomBytes(MAX_PUBLIC_KEY_LENGTH), - acceptTimestamp, transportProperties, null); - validator.validateMessage(message, group, body); - } - - @Test(expected = FormatException.class) - public void testRejectsInvalidSessionIdForAccept() throws Exception { - BdfList body = - BdfList.of(ACCEPT.getValue(), null, previousMsgId.getBytes(), - getRandomBytes(MAX_PUBLIC_KEY_LENGTH), acceptTimestamp, - transportProperties); - validator.validateMessage(message, group, body); - } - - @Test(expected = FormatException.class) - public void testRejectsInvalidPreviousMsgIdForAccept() throws Exception { - BdfList body = BdfList.of(ACCEPT.getValue(), sessionId.getBytes(), - null, getRandomBytes(MAX_PUBLIC_KEY_LENGTH), acceptTimestamp, - transportProperties); - validator.validateMessage(message, group, body); - } - - @Test(expected = FormatException.class) - public void testRejectsTooLongPublicKeyForAccept() throws Exception { - BdfList body = BdfList.of(ACCEPT.getValue(), sessionId.getBytes(), - previousMsgId.getBytes(), - getRandomBytes(MAX_PUBLIC_KEY_LENGTH + 1), acceptTimestamp, - transportProperties); - validator.validateMessage(message, group, body); - } - - @Test(expected = FormatException.class) - public void testRejectsEmptyTransportPropertiesForAccept() - throws Exception { - BdfList body = BdfList.of(ACCEPT.getValue(), sessionId.getBytes(), - previousMsgId.getBytes(), - getRandomBytes(MAX_PUBLIC_KEY_LENGTH + 1), acceptTimestamp, - new BdfDictionary()); - validator.validateMessage(message, group, body); - } - - // - // Introduction DECLINE - // - - @Test - public void testAcceptsDecline() throws Exception { - BdfList body = BdfList.of(DECLINE.getValue(), sessionId.getBytes(), - previousMsgId.getBytes()); - - expectEncodeMetadata(DECLINE); - BdfMessageContext messageContext = - validator.validateMessage(message, group, body); - - assertExpectedContext(messageContext, previousMsgId); - } - - @Test(expected = FormatException.class) - public void testRejectsTooShortBodyForDecline() throws Exception { - BdfList body = BdfList.of(DECLINE.getValue(), sessionId.getBytes()); - validator.validateMessage(message, group, body); - } - - @Test(expected = FormatException.class) - public void testRejectsTooLongBodyForDecline() throws Exception { - BdfList body = BdfList.of(DECLINE.getValue(), sessionId.getBytes(), - previousMsgId.getBytes(), null); - validator.validateMessage(message, group, body); - } - - @Test(expected = FormatException.class) - public void testRejectsInvalidSessionIdForDecline() throws Exception { - BdfList body = - BdfList.of(DECLINE.getValue(), null, previousMsgId.getBytes()); - validator.validateMessage(message, group, body); - } - - @Test(expected = FormatException.class) - public void testRejectsInvalidPreviousMsgIdForDecline() throws Exception { - BdfList body = BdfList.of(DECLINE.getValue(), sessionId.getBytes(), - null); - validator.validateMessage(message, group, body); - } - - // - // Introduction AUTH - // - - @Test - public void testAcceptsAuth() throws Exception { - BdfList body = BdfList.of(AUTH.getValue(), sessionId.getBytes(), - previousMsgId.getBytes(), mac, signature); - - expectEncodeMetadata(AUTH); - BdfMessageContext messageContext = - validator.validateMessage(message, group, body); - - assertExpectedContext(messageContext, previousMsgId); - } - - @Test(expected = FormatException.class) - public void testRejectsTooShortBodyForAuth() throws Exception { - BdfList body = BdfList.of(AUTH.getValue(), sessionId.getBytes(), - previousMsgId.getBytes(), mac); - validator.validateMessage(message, group, body); - } - - @Test(expected = FormatException.class) - public void testRejectsTooLongBodyForAuth() throws Exception { - BdfList body = BdfList.of(AUTH.getValue(), sessionId.getBytes(), - previousMsgId.getBytes(), mac, signature, null); - validator.validateMessage(message, group, body); - } - - @Test(expected = FormatException.class) - public void testRejectsTooShortMacForAuth() throws Exception { - BdfList body = BdfList.of(AUTH.getValue(), sessionId.getBytes(), - previousMsgId.getBytes(), getRandomBytes(MAC_BYTES - 1), - signature); - validator.validateMessage(message, group, body); - } - - @Test(expected = FormatException.class) - public void testRejectsTooLongMacForAuth() throws Exception { - BdfList body = BdfList.of(AUTH.getValue(), sessionId.getBytes(), - previousMsgId.getBytes(), - getRandomBytes(MAC_BYTES + 1), signature); - validator.validateMessage(message, group, body); - } - - @Test(expected = FormatException.class) - public void testRejectsInvalidMacForAuth() throws Exception { - BdfList body = BdfList.of(AUTH.getValue(), sessionId.getBytes(), - previousMsgId.getBytes(), null, signature); - validator.validateMessage(message, group, body); - } - - @Test(expected = FormatException.class) - public void testRejectsTooShortSignatureForAuth() throws Exception { - BdfList body = BdfList.of(AUTH.getValue(), sessionId.getBytes(), - previousMsgId.getBytes(), mac, getRandomBytes(0)); - validator.validateMessage(message, group, body); - } - - @Test(expected = FormatException.class) - public void testRejectsTooLongSignatureForAuth() throws Exception { - BdfList body = BdfList.of(AUTH.getValue(), sessionId.getBytes(), - previousMsgId.getBytes(), mac, - getRandomBytes(MAX_SIGNATURE_BYTES + 1)); - validator.validateMessage(message, group, body); - } - - @Test(expected = FormatException.class) - public void testRejectsInvalidSignatureForAuth() throws Exception { - BdfList body = BdfList.of(AUTH.getValue(), sessionId.getBytes(), - previousMsgId.getBytes(), mac, null); - validator.validateMessage(message, group, body); - } - - // - // Introduction ACTIVATE - // - - @Test - public void testAcceptsActivate() throws Exception { - BdfList body = BdfList.of(ACTIVATE.getValue(), sessionId.getBytes(), - previousMsgId.getBytes()); - - expectEncodeMetadata(ACTIVATE); - BdfMessageContext messageContext = - validator.validateMessage(message, group, body); - - assertExpectedContext(messageContext, previousMsgId); - } - - @Test(expected = FormatException.class) - public void testRejectsTooShortBodyForActivate() throws Exception { - BdfList body = BdfList.of(ACTIVATE.getValue(), sessionId.getBytes()); - validator.validateMessage(message, group, body); - } - - @Test(expected = FormatException.class) - public void testRejectsTooLongBodyForActivate() throws Exception { - BdfList body = BdfList.of(ACTIVATE.getValue(), sessionId.getBytes(), - previousMsgId.getBytes(), null); - validator.validateMessage(message, group, body); - } - - @Test(expected = FormatException.class) - public void testRejectsInvalidSessionIdForActivate() throws Exception { - BdfList body = - BdfList.of(ACTIVATE.getValue(), null, previousMsgId.getBytes()); - validator.validateMessage(message, group, body); - } - - @Test(expected = FormatException.class) - public void testRejectsInvalidPreviousMsgIdForActivate() throws Exception { - BdfList body = BdfList.of(ACTIVATE.getValue(), sessionId.getBytes(), - null); - validator.validateMessage(message, group, body); - } - - // - // Introduction ABORT - // - - @Test - public void testAcceptsAbort() throws Exception { - BdfList body = BdfList.of(ABORT.getValue(), sessionId.getBytes(), - previousMsgId.getBytes()); - - expectEncodeMetadata(ABORT); - BdfMessageContext messageContext = - validator.validateMessage(message, group, body); - - assertExpectedContext(messageContext, previousMsgId); - } - - @Test(expected = FormatException.class) - public void testRejectsTooShortBodyForAbort() throws Exception { - BdfList body = BdfList.of(ABORT.getValue(), sessionId.getBytes()); - validator.validateMessage(message, group, body); - } - - @Test(expected = FormatException.class) - public void testRejectsTooLongBodyForAbort() throws Exception { - BdfList body = BdfList.of(ABORT.getValue(), sessionId.getBytes(), - previousMsgId.getBytes(), null); - validator.validateMessage(message, group, body); - } - - @Test(expected = FormatException.class) - public void testRejectsInvalidSessionIdForAbort() throws Exception { - BdfList body = - BdfList.of(ABORT.getValue(), null, previousMsgId.getBytes()); - validator.validateMessage(message, group, body); - } - - @Test(expected = FormatException.class) - public void testRejectsInvalidPreviousMsgIdForAbort() throws Exception { - BdfList body = BdfList.of(ABORT.getValue(), sessionId.getBytes(), - null); - validator.validateMessage(message, group, body); - } - - // - // Introduction Helper Methods - // - - private void expectEncodeRequestMetadata() { - context.checking(new Expectations() {{ - oneOf(messageEncoder) - .encodeRequestMetadata(message.getTimestamp(), false, false, - false, false); - will(returnValue(meta)); - }}); - } - - private void expectEncodeMetadata(MessageType type) { - context.checking(new Expectations() {{ - oneOf(messageEncoder) - .encodeMetadata(type, sessionId, message.getTimestamp(), - false, false, false); - will(returnValue(meta)); - }}); - } - - private void assertExpectedContext(BdfMessageContext c, - @Nullable MessageId dependency) { - assertEquals(meta, c.getDictionary()); - if (dependency == null) { - assertEquals(0, c.getDependencies().size()); - } else { - assertEquals(dependency, c.getDependencies().iterator().next()); - } - } - -} diff --git a/briar-core/src/test/java/org/briarproject/briar/test/BriarIntegrationTestComponent.java b/briar-core/src/test/java/org/briarproject/briar/test/BriarIntegrationTestComponent.java index fe2e745c0d7d92d0f7c3ee7bcbb71c6ce7b567e8..a76abd0570c8878dc87859ad913debed207199a7 100644 --- a/briar-core/src/test/java/org/briarproject/briar/test/BriarIntegrationTestComponent.java +++ b/briar-core/src/test/java/org/briarproject/briar/test/BriarIntegrationTestComponent.java @@ -37,9 +37,9 @@ import org.briarproject.briar.blog.BlogModule; import org.briarproject.briar.client.BriarClientModule; import org.briarproject.briar.forum.ForumModule; import org.briarproject.briar.introduction.IntroductionModule; -import org.briarproject.briar.introduction2.IntroductionCryptoImplTest; -import org.briarproject.briar.introduction2.MessageEncoderParserIntegrationTest; -import org.briarproject.briar.introduction2.SessionEncoderParserIntegrationTest; +import org.briarproject.briar.introduction.IntroductionCryptoImplTest; +import org.briarproject.briar.introduction.MessageEncoderParserIntegrationTest; +import org.briarproject.briar.introduction.SessionEncoderParserIntegrationTest; import org.briarproject.briar.messaging.MessagingModule; import org.briarproject.briar.privategroup.PrivateGroupModule; import org.briarproject.briar.privategroup.invitation.GroupInvitationModule;