From e1fae7ad95438d627cc1779f0fe0642f1758c947 Mon Sep 17 00:00:00 2001 From: Torsten Grote <t@grobox.de> Date: Wed, 18 Apr 2018 12:04:33 -0300 Subject: [PATCH] Implement SessionEncoder and SessionParser --- .../briar/api/introduction2/Role.java | 29 ++ .../introduction2/IntroduceeSession.java | 227 ++++++++++++++ .../briar/introduction2/IntroduceeState.java | 36 +++ .../introduction2/IntroducerSession.java | 115 +++++++ .../briar/introduction2/IntroducerState.java | 36 +++ .../introduction2/IntroductionConstants.java | 29 ++ .../briar/introduction2/PeerSession.java | 25 ++ .../briar/introduction2/Session.java | 37 +++ .../briar/introduction2/SessionEncoder.java | 13 + .../introduction2/SessionEncoderImpl.java | 125 ++++++++ .../briar/introduction2/SessionParser.java | 23 ++ .../introduction2/SessionParserImpl.java | 183 ++++++++++++ .../briar/introduction2/State.java | 7 + .../SessionEncoderParserIntegrationTest.java | 281 ++++++++++++++++++ .../test/BriarIntegrationTestComponent.java | 2 + 15 files changed, 1168 insertions(+) create mode 100644 briar-api/src/main/java/org/briarproject/briar/api/introduction2/Role.java create mode 100644 briar-core/src/main/java/org/briarproject/briar/introduction2/IntroduceeSession.java create mode 100644 briar-core/src/main/java/org/briarproject/briar/introduction2/IntroduceeState.java create mode 100644 briar-core/src/main/java/org/briarproject/briar/introduction2/IntroducerSession.java create mode 100644 briar-core/src/main/java/org/briarproject/briar/introduction2/IntroducerState.java create mode 100644 briar-core/src/main/java/org/briarproject/briar/introduction2/PeerSession.java create mode 100644 briar-core/src/main/java/org/briarproject/briar/introduction2/Session.java create mode 100644 briar-core/src/main/java/org/briarproject/briar/introduction2/SessionEncoder.java create mode 100644 briar-core/src/main/java/org/briarproject/briar/introduction2/SessionEncoderImpl.java create mode 100644 briar-core/src/main/java/org/briarproject/briar/introduction2/SessionParser.java create mode 100644 briar-core/src/main/java/org/briarproject/briar/introduction2/SessionParserImpl.java create mode 100644 briar-core/src/main/java/org/briarproject/briar/introduction2/State.java create mode 100644 briar-core/src/test/java/org/briarproject/briar/introduction2/SessionEncoderParserIntegrationTest.java 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/introduction2/Role.java new file mode 100644 index 0000000000..bc7e4e3d90 --- /dev/null +++ b/briar-api/src/main/java/org/briarproject/briar/api/introduction2/Role.java @@ -0,0 +1,29 @@ +package org.briarproject.briar.api.introduction2; + +import org.briarproject.bramble.api.FormatException; +import org.briarproject.bramble.api.nullsafety.NotNullByDefault; + +import javax.annotation.concurrent.Immutable; + +@Immutable +@NotNullByDefault +public enum Role { + + INTRODUCER(0), INTRODUCEE(1); + + private final int value; + + Role(int value) { + this.value = value; + } + + public int getValue() { + return value; + } + + public static Role fromValue(int value) throws FormatException { + for (Role r : values()) if (r.value == value) return r; + throw new FormatException(); + } + +} diff --git a/briar-core/src/main/java/org/briarproject/briar/introduction2/IntroduceeSession.java b/briar-core/src/main/java/org/briarproject/briar/introduction2/IntroduceeSession.java new file mode 100644 index 0000000000..61e3014981 --- /dev/null +++ b/briar-core/src/main/java/org/briarproject/briar/introduction2/IntroduceeSession.java @@ -0,0 +1,227 @@ +package org.briarproject.briar.introduction2; + +import org.briarproject.bramble.api.crypto.SecretKey; +import org.briarproject.bramble.api.identity.Author; +import org.briarproject.bramble.api.nullsafety.NotNullByDefault; +import org.briarproject.bramble.api.plugin.TransportId; +import org.briarproject.bramble.api.properties.TransportProperties; +import org.briarproject.bramble.api.sync.GroupId; +import org.briarproject.bramble.api.sync.Message; +import org.briarproject.bramble.api.sync.MessageId; +import org.briarproject.bramble.api.transport.KeySetId; +import org.briarproject.briar.api.client.SessionId; +import org.briarproject.briar.api.introduction2.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; + +@Immutable +@NotNullByDefault +class IntroduceeSession extends Session<IntroduceeState> + implements PeerSession { + + private final GroupId contactGroupId; + private final long localTimestamp, acceptTimestamp, remoteAcceptTimestamp; + @Nullable + private final MessageId lastLocalMessageId, lastRemoteMessageId; + private final Author introducer, remoteAuthor; + @Nullable + private final byte[] ephemeralPublicKey, ephemeralPrivateKey; + @Nullable + private final byte[] masterKey, remoteEphemeralPublicKey; + @Nullable + private final Map<TransportId, TransportProperties> transportProperties; + @Nullable + private final Map<TransportId, TransportProperties> + remoteTransportProperties; + @Nullable + private final Map<TransportId, KeySetId> transportKeys; + + IntroduceeSession(SessionId sessionId, IntroduceeState state, + long requestTimestamp, GroupId contactGroupId, + @Nullable MessageId lastLocalMessageId, long localTimestamp, + @Nullable MessageId lastRemoteMessageId, Author introducer, + @Nullable byte[] ephemeralPublicKey, + @Nullable byte[] ephemeralPrivateKey, + @Nullable Map<TransportId, TransportProperties> transportProperties, + long acceptTimestamp, @Nullable byte[] masterKey, + Author remoteAuthor, + @Nullable byte[] remoteEphemeralPublicKey, @Nullable + Map<TransportId, TransportProperties> remoteTransportProperties, + long remoteAcceptTimestamp, + @Nullable Map<TransportId, KeySetId> transportKeys) { + super(sessionId, state, requestTimestamp); + this.contactGroupId = contactGroupId; + this.lastLocalMessageId = lastLocalMessageId; + this.localTimestamp = localTimestamp; + this.lastRemoteMessageId = lastRemoteMessageId; + this.introducer = introducer; + this.ephemeralPublicKey = ephemeralPublicKey; + this.ephemeralPrivateKey = ephemeralPrivateKey; + this.transportProperties = transportProperties; + this.acceptTimestamp = acceptTimestamp; + this.masterKey = masterKey; + this.remoteAuthor = remoteAuthor; + this.remoteEphemeralPublicKey = remoteEphemeralPublicKey; + this.remoteTransportProperties = remoteTransportProperties; + this.remoteAcceptTimestamp = remoteAcceptTimestamp; + this.transportKeys = transportKeys; + } + + static IntroduceeSession getInitial(GroupId contactGroupId, + SessionId sessionId, Author introducer, Author remoteAuthor) { + return new IntroduceeSession(sessionId, START, -1, contactGroupId, null, + -1, null, introducer, null, null, null, -1, null, remoteAuthor, + null, null, -1, null); + } + + static IntroduceeSession addRemoteRequest(IntroduceeSession s, + IntroduceeState state, RequestMessage m) { + return new IntroduceeSession(s.getSessionId(), state, m.getTimestamp(), + s.contactGroupId, s.lastLocalMessageId, s.localTimestamp, + m.getMessageId(), s.introducer, s.ephemeralPublicKey, + s.ephemeralPrivateKey, s.transportProperties, s.acceptTimestamp, + s.masterKey, s.remoteAuthor, s.remoteEphemeralPublicKey, + s.remoteTransportProperties, s.remoteAcceptTimestamp, + s.transportKeys); + } + + static IntroduceeSession addLocalAccept(IntroduceeSession s, + IntroduceeState state, Message acceptMessage, + byte[] ephemeralPublicKey, byte[] ephemeralPrivateKey, + long acceptTimestamp, + Map<TransportId, TransportProperties> transportProperties) { + return new IntroduceeSession(s.getSessionId(), state, + s.getRequestTimestamp(), s.contactGroupId, + acceptMessage.getId(), acceptMessage.getTimestamp(), + s.lastRemoteMessageId, s.introducer, ephemeralPublicKey, + ephemeralPrivateKey, transportProperties, + acceptTimestamp, s.masterKey, s.remoteAuthor, + s.remoteEphemeralPublicKey, s.remoteTransportProperties, + s.remoteAcceptTimestamp, s.transportKeys); + } + + static IntroduceeSession addRemoteAccept(IntroduceeSession s, + IntroduceeState state, AcceptMessage acceptMessage) { + return new IntroduceeSession(s.getSessionId(), state, + s.getRequestTimestamp(), s.contactGroupId, s.lastLocalMessageId, + s.localTimestamp, acceptMessage.getMessageId(), s.introducer, + s.ephemeralPublicKey, s.ephemeralPrivateKey, + s.transportProperties, s.acceptTimestamp, s.masterKey, + s.remoteAuthor, acceptMessage.getEphemeralPublicKey(), + acceptMessage.getTransportProperties(), + acceptMessage.getAcceptTimestamp(), s.transportKeys); + } + + static IntroduceeSession addLocalAuth(IntroduceeSession s, + IntroduceeState state, SecretKey masterKey, Message m) { + return new IntroduceeSession(s.getSessionId(), state, + s.getRequestTimestamp(), s.contactGroupId, m.getId(), + m.getTimestamp(), s.lastRemoteMessageId, s.introducer, + s.ephemeralPublicKey, s.ephemeralPrivateKey, + s.transportProperties, s.acceptTimestamp, masterKey.getBytes(), + s.remoteAuthor, s.remoteEphemeralPublicKey, + s.remoteTransportProperties, s.remoteAcceptTimestamp, + s.transportKeys); + } + + static IntroduceeSession awaitActivate(IntroduceeSession s, AuthMessage m, + Message sent, Map<TransportId, KeySetId> transportKeys) { + return new IntroduceeSession(s.getSessionId(), AWAIT_ACTIVATE, + s.getRequestTimestamp(), s.contactGroupId, sent.getId(), + sent.getTimestamp(), m.getMessageId(), s.introducer, null, null, + null, s.acceptTimestamp, null, s.getRemoteAuthor(), null, null, + s.remoteAcceptTimestamp, transportKeys); + } + + static IntroduceeSession clear(IntroduceeSession s, + @Nullable MessageId lastLocalMessageId, long localTimestamp, + @Nullable MessageId lastRemoteMessageId) { + return new IntroduceeSession(s.getSessionId(), START, + s.getRequestTimestamp(), s.getContactGroupId(), + lastLocalMessageId, localTimestamp, lastRemoteMessageId, + s.getIntroducer(), null, null, null, -1, null, + s.getRemoteAuthor(), null, null, -1, null); + } + + @Override + Role getRole() { + return INTRODUCEE; + } + + public GroupId getContactGroupId() { + return contactGroupId; + } + + public long getLocalTimestamp() { + return localTimestamp; + } + + @Nullable + public MessageId getLastLocalMessageId() { + return lastLocalMessageId; + } + + @Nullable + public MessageId getLastRemoteMessageId() { + return lastRemoteMessageId; + } + + Author getIntroducer() { + return introducer; + } + + @Nullable + byte[] getEphemeralPublicKey() { + return ephemeralPublicKey; + } + + @Nullable + byte[] getEphemeralPrivateKey() { + return ephemeralPrivateKey; + } + + @Nullable + Map<TransportId, TransportProperties> getTransportProperties() { + return transportProperties; + } + + long getAcceptTimestamp() { + return acceptTimestamp; + } + + @Nullable + byte[] getMasterKey() { + return masterKey; + } + + Author getRemoteAuthor() { + return remoteAuthor; + } + + @Nullable + byte[] getRemotePublicKey() { + return remoteEphemeralPublicKey; + } + + @Nullable + Map<TransportId, TransportProperties> getRemoteTransportProperties() { + return remoteTransportProperties; + } + + long getRemoteAcceptTimestamp() { + return remoteAcceptTimestamp; + } + + @Nullable + Map<TransportId, KeySetId> getTransportKeys() { + return transportKeys; + } + +} diff --git a/briar-core/src/main/java/org/briarproject/briar/introduction2/IntroduceeState.java b/briar-core/src/main/java/org/briarproject/briar/introduction2/IntroduceeState.java new file mode 100644 index 0000000000..4a901752df --- /dev/null +++ b/briar-core/src/main/java/org/briarproject/briar/introduction2/IntroduceeState.java @@ -0,0 +1,36 @@ +package org.briarproject.briar.introduction2; + +import org.briarproject.bramble.api.FormatException; +import org.briarproject.bramble.api.nullsafety.NotNullByDefault; + +import javax.annotation.concurrent.Immutable; + +@Immutable +@NotNullByDefault +enum IntroduceeState implements State { + + START(0), + AWAIT_RESPONSES(1), + LOCAL_DECLINED(2), + LOCAL_ACCEPTED(3), + REMOTE_ACCEPTED(4), + AWAIT_AUTH(5), + AWAIT_ACTIVATE(6); + + private final int value; + + IntroduceeState(int value) { + this.value = value; + } + + @Override + public int getValue() { + return value; + } + + static IntroduceeState fromValue(int value) throws FormatException { + for (IntroduceeState s : values()) if (s.value == value) return s; + throw new FormatException(); + } + +} diff --git a/briar-core/src/main/java/org/briarproject/briar/introduction2/IntroducerSession.java b/briar-core/src/main/java/org/briarproject/briar/introduction2/IntroducerSession.java new file mode 100644 index 0000000000..cbfc53923e --- /dev/null +++ b/briar-core/src/main/java/org/briarproject/briar/introduction2/IntroducerSession.java @@ -0,0 +1,115 @@ +package org.briarproject.briar.introduction2; + +import org.briarproject.bramble.api.identity.Author; +import org.briarproject.bramble.api.nullsafety.NotNullByDefault; +import org.briarproject.bramble.api.sync.GroupId; +import org.briarproject.bramble.api.sync.Message; +import org.briarproject.bramble.api.sync.MessageId; +import org.briarproject.briar.api.client.SessionId; +import org.briarproject.briar.api.introduction2.Role; + +import javax.annotation.Nullable; +import javax.annotation.concurrent.Immutable; + +import static org.briarproject.briar.api.introduction2.Role.INTRODUCER; + +@Immutable +@NotNullByDefault +class IntroducerSession extends Session<IntroducerState> { + + private final Introducee introducee1, introducee2; + + IntroducerSession(SessionId sessionId, IntroducerState state, + long requestTimestamp, Introducee introducee1, + Introducee introducee2) { + super(sessionId, state, requestTimestamp); + this.introducee1 = introducee1; + this.introducee2 = introducee2; + } + + IntroducerSession(SessionId sessionId, GroupId groupId1, Author author1, + GroupId groupId2, Author author2) { + this(sessionId, IntroducerState.START, -1, + new Introducee(sessionId, groupId1, author1), + new Introducee(sessionId, groupId2, author2)); + } + + @Override + Role getRole() { + return INTRODUCER; + } + + Introducee getIntroducee1() { + return introducee1; + } + + Introducee getIntroducee2() { + return introducee2; + } + + @Immutable + @NotNullByDefault + static class Introducee implements PeerSession { + final SessionId sessionId; + final GroupId groupId; + final Author author; + final long localTimestamp; + @Nullable + final MessageId lastLocalMessageId, lastRemoteMessageId; + + Introducee(SessionId sessionId, GroupId groupId, Author author, + long localTimestamp, + @Nullable MessageId lastLocalMessageId, + @Nullable MessageId lastRemoteMessageId) { + this.sessionId = sessionId; + this.groupId = groupId; + this.localTimestamp = localTimestamp; + this.author = author; + this.lastLocalMessageId = lastLocalMessageId; + this.lastRemoteMessageId = lastRemoteMessageId; + } + + Introducee(Introducee i, Message sent) { + this(i.sessionId, i.groupId, i.author, sent.getTimestamp(), + sent.getId(), i.lastRemoteMessageId); + } + + Introducee(Introducee i, MessageId remoteMessageId) { + this(i.sessionId, i.groupId, i.author, i.localTimestamp, + i.lastLocalMessageId, remoteMessageId); + } + + private Introducee(SessionId sessionId, GroupId groupId, + Author author) { + this(sessionId, groupId, author, -1, null, null); + } + + public SessionId getSessionId() { + return sessionId; + } + + @Override + public GroupId getContactGroupId() { + return groupId; + } + + @Override + public long getLocalTimestamp() { + return localTimestamp; + } + + @Nullable + @Override + public MessageId getLastLocalMessageId() { + return lastLocalMessageId; + } + + @Nullable + @Override + public MessageId getLastRemoteMessageId() { + return lastRemoteMessageId; + } + + } + +} diff --git a/briar-core/src/main/java/org/briarproject/briar/introduction2/IntroducerState.java b/briar-core/src/main/java/org/briarproject/briar/introduction2/IntroducerState.java new file mode 100644 index 0000000000..43e51d96af --- /dev/null +++ b/briar-core/src/main/java/org/briarproject/briar/introduction2/IntroducerState.java @@ -0,0 +1,36 @@ +package org.briarproject.briar.introduction2; + +import org.briarproject.bramble.api.FormatException; +import org.briarproject.bramble.api.nullsafety.NotNullByDefault; + +import javax.annotation.concurrent.Immutable; + +@Immutable +@NotNullByDefault +enum IntroducerState implements State { + + START(0), + AWAIT_RESPONSES(1), + AWAIT_RESPONSE_A(2), AWAIT_RESPONSE_B(3), + AWAIT_AUTHS(4), + AWAIT_AUTH_A(5), AWAIT_AUTH_B(6), + AWAIT_ACTIVATES(7), + AWAIT_ACTIVATE_A(8), AWAIT_ACTIVATE_B(9); + + private final int value; + + IntroducerState(int value) { + this.value = value; + } + + @Override + public int getValue() { + return value; + } + + static IntroducerState fromValue(int value) throws FormatException { + for (IntroducerState s : values()) if (s.value == value) return s; + throw new FormatException(); + } + +} diff --git a/briar-core/src/main/java/org/briarproject/briar/introduction2/IntroductionConstants.java b/briar-core/src/main/java/org/briarproject/briar/introduction2/IntroductionConstants.java index 4098b2421e..ea57344682 100644 --- a/briar-core/src/main/java/org/briarproject/briar/introduction2/IntroductionConstants.java +++ b/briar-core/src/main/java/org/briarproject/briar/introduction2/IntroductionConstants.java @@ -11,4 +11,33 @@ interface IntroductionConstants { String MSG_KEY_AVAILABLE_TO_ANSWER = "availableToAnswer"; String MSG_KEY_INVITATION_ACCEPTED = "invitationAccepted"; + // Session Keys + String SESSION_KEY_SESSION_ID = "sessionId"; + String SESSION_KEY_ROLE = "role"; + String SESSION_KEY_STATE = "state"; + String SESSION_KEY_REQUEST_TIMESTAMP = "requestTimestamp"; + String SESSION_KEY_LOCAL_TIMESTAMP = "localTimestamp"; + String SESSION_KEY_LAST_LOCAL_MESSAGE_ID = "lastLocalMessageId"; + String SESSION_KEY_LAST_REMOTE_MESSAGE_ID = "lastRemoteMessageId"; + + // Session Keys Introducer + String SESSION_KEY_INTRODUCEE_1 = "introducee1"; + String SESSION_KEY_INTRODUCEE_2 = "introducee2"; + String SESSION_KEY_GROUP_ID = "groupId"; + String SESSION_KEY_AUTHOR = "author"; + + // Session Keys Introducee + String SESSION_KEY_INTRODUCER = "introducer"; + String SESSION_KEY_EPHEMERAL_PUBLIC_KEY = "ephemeralPublicKey"; + String SESSION_KEY_EPHEMERAL_PRIVATE_KEY = "ephemeralPrivateKey"; + String SESSION_KEY_TRANSPORT_PROPERTIES = "transportProperties"; + String SESSION_KEY_ACCEPT_TIMESTAMP = "acceptTimestamp"; + String SESSION_KEY_MASTER_KEY = "masterKey"; + String SESSION_KEY_REMOTE_AUTHOR = "remoteAuthor"; + String SESSION_KEY_REMOTE_EPHEMERAL_PUBLIC_KEY = "remoteEphemeralPublicKey"; + String SESSION_KEY_REMOTE_TRANSPORT_PROPERTIES = + "remoteTransportProperties"; + String SESSION_KEY_REMOTE_ACCEPT_TIMESTAMP = "remoteAcceptTimestamp"; + String SESSION_KEY_TRANSPORT_KEYS = "transportKeys"; + } diff --git a/briar-core/src/main/java/org/briarproject/briar/introduction2/PeerSession.java b/briar-core/src/main/java/org/briarproject/briar/introduction2/PeerSession.java new file mode 100644 index 0000000000..e2f8b7c46f --- /dev/null +++ b/briar-core/src/main/java/org/briarproject/briar/introduction2/PeerSession.java @@ -0,0 +1,25 @@ +package org.briarproject.briar.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; + +@NotNullByDefault +interface PeerSession { + + SessionId getSessionId(); + + GroupId getContactGroupId(); + + long getLocalTimestamp(); + + @Nullable + MessageId getLastLocalMessageId(); + + @Nullable + MessageId getLastRemoteMessageId(); + +} diff --git a/briar-core/src/main/java/org/briarproject/briar/introduction2/Session.java b/briar-core/src/main/java/org/briarproject/briar/introduction2/Session.java new file mode 100644 index 0000000000..ca2a89c190 --- /dev/null +++ b/briar-core/src/main/java/org/briarproject/briar/introduction2/Session.java @@ -0,0 +1,37 @@ +package org.briarproject.briar.introduction2; + +import org.briarproject.bramble.api.nullsafety.NotNullByDefault; +import org.briarproject.briar.api.client.SessionId; +import org.briarproject.briar.api.introduction2.Role; + +import javax.annotation.concurrent.Immutable; + +@Immutable +@NotNullByDefault +abstract class Session<S extends State> { + + private final SessionId sessionId; + private final S state; + private long requestTimestamp; + + Session(SessionId sessionId, S state, long requestTimestamp) { + this.sessionId = sessionId; + this.state = state; + this.requestTimestamp = requestTimestamp; + } + + abstract Role getRole(); + + public SessionId getSessionId() { + return sessionId; + } + + S getState() { + return state; + } + + public long getRequestTimestamp() { + return requestTimestamp; + } + +} diff --git a/briar-core/src/main/java/org/briarproject/briar/introduction2/SessionEncoder.java b/briar-core/src/main/java/org/briarproject/briar/introduction2/SessionEncoder.java new file mode 100644 index 0000000000..4b45c39ca2 --- /dev/null +++ b/briar-core/src/main/java/org/briarproject/briar/introduction2/SessionEncoder.java @@ -0,0 +1,13 @@ +package org.briarproject.briar.introduction2; + +import org.briarproject.bramble.api.data.BdfDictionary; +import org.briarproject.bramble.api.nullsafety.NotNullByDefault; + +@NotNullByDefault +interface SessionEncoder { + + 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/introduction2/SessionEncoderImpl.java new file mode 100644 index 0000000000..3bce33d853 --- /dev/null +++ b/briar-core/src/main/java/org/briarproject/briar/introduction2/SessionEncoderImpl.java @@ -0,0 +1,125 @@ +package org.briarproject.briar.introduction2; + +import org.briarproject.bramble.api.client.ClientHelper; +import org.briarproject.bramble.api.data.BdfDictionary; +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 java.util.Map; + +import javax.annotation.Nullable; +import javax.annotation.concurrent.Immutable; +import javax.inject.Inject; + +import static org.briarproject.bramble.api.data.BdfDictionary.NULL_VALUE; +import static org.briarproject.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; + +@Immutable +@NotNullByDefault +class SessionEncoderImpl implements SessionEncoder { + + private final ClientHelper clientHelper; + + @Inject + SessionEncoderImpl(ClientHelper clientHelper) { + this.clientHelper = clientHelper; + } + + @Override + public BdfDictionary encodeIntroducerSession(IntroducerSession s) { + BdfDictionary d = encodeSession(s); + d.put(SESSION_KEY_INTRODUCEE_1, encodeIntroducee(s.getIntroducee1())); + d.put(SESSION_KEY_INTRODUCEE_2, encodeIntroducee(s.getIntroducee2())); + return d; + } + + private BdfDictionary encodeIntroducee(Introducee i) { + BdfDictionary d = new BdfDictionary(); + putNullable(d, SESSION_KEY_LAST_LOCAL_MESSAGE_ID, i.lastLocalMessageId); + putNullable(d, SESSION_KEY_LAST_REMOTE_MESSAGE_ID, + i.lastRemoteMessageId); + d.put(SESSION_KEY_LOCAL_TIMESTAMP, i.localTimestamp); + d.put(SESSION_KEY_GROUP_ID, i.groupId); + d.put(SESSION_KEY_AUTHOR, clientHelper.toList(i.author)); + return d; + } + + @Override + public BdfDictionary encodeIntroduceeSession(IntroduceeSession s) { + BdfDictionary d = encodeSession(s); + d.put(SESSION_KEY_LOCAL_TIMESTAMP, s.getLocalTimestamp()); + putNullable(d, SESSION_KEY_LAST_LOCAL_MESSAGE_ID, + s.getLastLocalMessageId()); + putNullable(d, SESSION_KEY_LAST_REMOTE_MESSAGE_ID, + s.getLastRemoteMessageId()); + d.put(SESSION_KEY_INTRODUCER, clientHelper.toList(s.getIntroducer())); + d.put(SESSION_KEY_REMOTE_AUTHOR, + clientHelper.toList(s.getRemoteAuthor())); + putNullable(d, SESSION_KEY_EPHEMERAL_PUBLIC_KEY, + s.getEphemeralPublicKey()); + putNullable(d, SESSION_KEY_EPHEMERAL_PRIVATE_KEY, + s.getEphemeralPrivateKey()); + putNullable(d, SESSION_KEY_TRANSPORT_PROPERTIES, + s.getTransportProperties() == null ? null : + clientHelper.toDictionary(s.getTransportProperties())); + d.put(SESSION_KEY_ACCEPT_TIMESTAMP, s.getAcceptTimestamp()); + putNullable(d, SESSION_KEY_MASTER_KEY, s.getMasterKey()); + putNullable(d, SESSION_KEY_REMOTE_EPHEMERAL_PUBLIC_KEY, + s.getRemotePublicKey()); + putNullable(d, SESSION_KEY_REMOTE_TRANSPORT_PROPERTIES, + s.getRemoteTransportProperties() == null ? null : clientHelper + .toDictionary(s.getRemoteTransportProperties())); + d.put(SESSION_KEY_REMOTE_ACCEPT_TIMESTAMP, s.getRemoteAcceptTimestamp()); + putNullable(d, SESSION_KEY_TRANSPORT_KEYS, + encodeTransportKeys(s.getTransportKeys())); + return d; + } + + private BdfDictionary encodeSession(Session s) { + BdfDictionary d = new BdfDictionary(); + d.put(SESSION_KEY_SESSION_ID, s.getSessionId()); + d.put(SESSION_KEY_ROLE, s.getRole().getValue()); + d.put(SESSION_KEY_STATE, s.getState().getValue()); + d.put(SESSION_KEY_REQUEST_TIMESTAMP, s.getRequestTimestamp()); + return d; + } + + @Nullable + private BdfDictionary encodeTransportKeys( + @Nullable Map<TransportId, KeySetId> keys) { + if (keys == null) return null; + BdfDictionary d = new BdfDictionary(); + for (Map.Entry<TransportId, KeySetId> e : keys.entrySet()) { + d.put(e.getKey().getString(), e.getValue().getInt()); + } + return d; + } + + private void putNullable(BdfDictionary d, String key, @Nullable Object o) { + d.put(key, o == null ? NULL_VALUE : o); + } + +} diff --git a/briar-core/src/main/java/org/briarproject/briar/introduction2/SessionParser.java b/briar-core/src/main/java/org/briarproject/briar/introduction2/SessionParser.java new file mode 100644 index 0000000000..dd3fba09cb --- /dev/null +++ b/briar-core/src/main/java/org/briarproject/briar/introduction2/SessionParser.java @@ -0,0 +1,23 @@ +package org.briarproject.briar.introduction2; + +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; + +@NotNullByDefault +interface SessionParser { + + BdfDictionary getSessionQuery(SessionId s); + + Role getRole(BdfDictionary d) throws FormatException; + + IntroducerSession parseIntroducerSession(BdfDictionary d) + throws FormatException; + + IntroduceeSession parseIntroduceeSession(GroupId introducerGroupId, + BdfDictionary d) throws FormatException; + +} diff --git a/briar-core/src/main/java/org/briarproject/briar/introduction2/SessionParserImpl.java b/briar-core/src/main/java/org/briarproject/briar/introduction2/SessionParserImpl.java new file mode 100644 index 0000000000..dbb609fc1a --- /dev/null +++ b/briar-core/src/main/java/org/briarproject/briar/introduction2/SessionParserImpl.java @@ -0,0 +1,183 @@ +package org.briarproject.briar.introduction2; + +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.identity.Author; +import org.briarproject.bramble.api.nullsafety.NotNullByDefault; +import org.briarproject.bramble.api.plugin.TransportId; +import org.briarproject.bramble.api.properties.TransportProperties; +import org.briarproject.bramble.api.sync.GroupId; +import org.briarproject.bramble.api.sync.MessageId; +import org.briarproject.bramble.api.transport.KeySetId; +import org.briarproject.briar.api.client.SessionId; +import org.briarproject.briar.api.introduction2.Role; +import org.briarproject.briar.introduction2.IntroducerSession.Introducee; + +import java.util.HashMap; +import java.util.Map; + +import javax.annotation.Nullable; +import javax.annotation.concurrent.Immutable; +import javax.inject.Inject; + +import static org.briarproject.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; + +@Immutable +@NotNullByDefault +class SessionParserImpl implements SessionParser { + + private final ClientHelper clientHelper; + + @Inject + SessionParserImpl(ClientHelper clientHelper) { + this.clientHelper = clientHelper; + } + + @Override + public BdfDictionary getSessionQuery(SessionId s) { + return BdfDictionary.of(new BdfEntry(SESSION_KEY_SESSION_ID, s)); + } + + @Override + public Role getRole(BdfDictionary d) throws FormatException { + return Role.fromValue(d.getLong(SESSION_KEY_ROLE).intValue()); + } + + @Override + public IntroducerSession parseIntroducerSession(BdfDictionary d) + throws FormatException { + if (getRole(d) != INTRODUCER) throw new IllegalArgumentException(); + SessionId sessionId = getSessionId(d); + IntroducerState state = IntroducerState.fromValue(getState(d)); + long requestTimestamp = d.getLong(SESSION_KEY_REQUEST_TIMESTAMP); + Introducee introducee1 = parseIntroducee(sessionId, + d.getDictionary(SESSION_KEY_INTRODUCEE_1)); + Introducee introducee2 = parseIntroducee(sessionId, + d.getDictionary(SESSION_KEY_INTRODUCEE_2)); + return new IntroducerSession(sessionId, state, requestTimestamp, + introducee1, introducee2); + } + + private Introducee parseIntroducee(SessionId sessionId, BdfDictionary d) + throws FormatException { + MessageId lastLocalMessageId = + getMessageId(d, SESSION_KEY_LAST_LOCAL_MESSAGE_ID); + MessageId lastRemoteMessageId = + getMessageId(d, SESSION_KEY_LAST_REMOTE_MESSAGE_ID); + long localTimestamp = d.getLong(SESSION_KEY_LOCAL_TIMESTAMP); + GroupId groupId = getGroupId(d, SESSION_KEY_GROUP_ID); + Author author = getAuthor(d, SESSION_KEY_AUTHOR); + return new Introducee(sessionId, groupId, author, localTimestamp, + lastLocalMessageId, lastRemoteMessageId); + } + + @Override + public IntroduceeSession parseIntroduceeSession(GroupId introducerGroupId, + BdfDictionary d) throws FormatException { + if (getRole(d) != INTRODUCEE) throw new IllegalArgumentException(); + SessionId sessionId = getSessionId(d); + IntroduceeState state = IntroduceeState.fromValue(getState(d)); + long requestTimestamp = d.getLong(SESSION_KEY_REQUEST_TIMESTAMP); + MessageId lastLocalMessageId = + getMessageId(d, SESSION_KEY_LAST_LOCAL_MESSAGE_ID); + long localTimestamp = d.getLong(SESSION_KEY_LOCAL_TIMESTAMP); + MessageId lastRemoteMessageId = + getMessageId(d, SESSION_KEY_LAST_REMOTE_MESSAGE_ID); + Author introducer = getAuthor(d, SESSION_KEY_INTRODUCER); + byte[] ephemeralPublicKey = + d.getOptionalRaw(SESSION_KEY_EPHEMERAL_PUBLIC_KEY); + byte[] ephemeralPrivateKey = + d.getOptionalRaw(SESSION_KEY_EPHEMERAL_PRIVATE_KEY); + BdfDictionary tpDict = + d.getOptionalDictionary(SESSION_KEY_TRANSPORT_PROPERTIES); + Map<TransportId, TransportProperties> transportProperties = + tpDict == null ? null : clientHelper + .parseAndValidateTransportPropertiesMap(tpDict); + long acceptTimestamp = d.getLong(SESSION_KEY_ACCEPT_TIMESTAMP); + byte[] masterKey = d.getOptionalRaw(SESSION_KEY_MASTER_KEY); + Author remoteAuthor = getAuthor(d, SESSION_KEY_REMOTE_AUTHOR); + byte[] remoteEphemeralPublicKey = + d.getOptionalRaw(SESSION_KEY_REMOTE_EPHEMERAL_PUBLIC_KEY); + BdfDictionary rptDict = d.getOptionalDictionary( + SESSION_KEY_REMOTE_TRANSPORT_PROPERTIES); + Map<TransportId, TransportProperties> remoteTransportProperties = + rptDict == null ? null : clientHelper + .parseAndValidateTransportPropertiesMap(rptDict); + long remoteAcceptTimestamp = + d.getLong(SESSION_KEY_REMOTE_ACCEPT_TIMESTAMP); + Map<TransportId, KeySetId> transportKeys = parseTransportKeys( + d.getOptionalDictionary(SESSION_KEY_TRANSPORT_KEYS)); + return new IntroduceeSession(sessionId, state, requestTimestamp, + introducerGroupId, lastLocalMessageId, localTimestamp, + lastRemoteMessageId, introducer, ephemeralPublicKey, + ephemeralPrivateKey, transportProperties, acceptTimestamp, + masterKey, remoteAuthor, remoteEphemeralPublicKey, + remoteTransportProperties, remoteAcceptTimestamp, + transportKeys); + } + + private int getState(BdfDictionary d) throws FormatException { + return d.getLong(SESSION_KEY_STATE).intValue(); + } + + private SessionId getSessionId(BdfDictionary d) throws FormatException { + byte[] b = d.getRaw(SESSION_KEY_SESSION_ID); + return new SessionId(b); + } + + @Nullable + private MessageId getMessageId(BdfDictionary d, String key) + throws FormatException { + byte[] b = d.getOptionalRaw(key); + return b == null ? null : new MessageId(b); + } + + private GroupId getGroupId(BdfDictionary d, String key) + throws FormatException { + return new GroupId(d.getRaw(key)); + } + + private Author getAuthor(BdfDictionary d, String key) + throws FormatException { + return clientHelper.parseAndValidateAuthor(d.getList(key)); + } + + @Nullable + private Map<TransportId, KeySetId> parseTransportKeys( + @Nullable BdfDictionary d) throws FormatException { + if (d == null) return null; + Map<TransportId, KeySetId> map = new HashMap<>(d.size()); + for (String key : d.keySet()) { + map.put(new TransportId(key), + new KeySetId(d.getLong(key).intValue()) + ); + } + return map; + } + +} diff --git a/briar-core/src/main/java/org/briarproject/briar/introduction2/State.java b/briar-core/src/main/java/org/briarproject/briar/introduction2/State.java new file mode 100644 index 0000000000..1e1d46e0a6 --- /dev/null +++ b/briar-core/src/main/java/org/briarproject/briar/introduction2/State.java @@ -0,0 +1,7 @@ +package org.briarproject.briar.introduction2; + +interface State { + + int getValue(); + +} diff --git a/briar-core/src/test/java/org/briarproject/briar/introduction2/SessionEncoderParserIntegrationTest.java b/briar-core/src/test/java/org/briarproject/briar/introduction2/SessionEncoderParserIntegrationTest.java new file mode 100644 index 0000000000..24ddf208a3 --- /dev/null +++ b/briar-core/src/test/java/org/briarproject/briar/introduction2/SessionEncoderParserIntegrationTest.java @@ -0,0 +1,281 @@ +package org.briarproject.briar.introduction2; + +import org.briarproject.bramble.api.FormatException; +import org.briarproject.bramble.api.client.ClientHelper; +import org.briarproject.bramble.api.crypto.SecretKey; +import org.briarproject.bramble.api.data.BdfDictionary; +import org.briarproject.bramble.api.identity.Author; +import org.briarproject.bramble.api.identity.AuthorFactory; +import org.briarproject.bramble.api.plugin.TransportId; +import org.briarproject.bramble.api.properties.TransportProperties; +import org.briarproject.bramble.api.sync.GroupId; +import org.briarproject.bramble.api.sync.MessageId; +import org.briarproject.bramble.api.transport.KeySetId; +import org.briarproject.bramble.test.BrambleTestCase; +import org.briarproject.briar.api.client.SessionId; +import org.briarproject.briar.introduction2.IntroducerSession.Introducee; +import org.briarproject.briar.test.BriarIntegrationTestComponent; +import org.briarproject.briar.test.DaggerBriarIntegrationTestComponent; +import org.junit.Test; + +import java.util.HashMap; +import java.util.Map; + +import javax.inject.Inject; + +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.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.junit.Assert.assertArrayEquals; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNull; + +public class SessionEncoderParserIntegrationTest extends BrambleTestCase { + + @Inject + ClientHelper clientHelper; + @Inject + AuthorFactory authorFactory; + + private final SessionEncoder sessionEncoder; + private final SessionParser sessionParser; + + private final GroupId groupId1 = new GroupId(getRandomId()); + private final GroupId groupId2 = new GroupId(getRandomId()); + private final SessionId sessionId = new SessionId(getRandomId()); + private final long requestTimestamp = 42; + private final long localTimestamp = 1337; + private final long localTimestamp2 = 1338; + private final long acceptTimestamp = 123456; + private final long remoteAcceptTimestamp = 1234567; + private final MessageId lastLocalMessageId = new MessageId(getRandomId()); + private final MessageId lastLocalMessageId2 = new MessageId(getRandomId()); + private final MessageId lastRemoteMessageId = new MessageId(getRandomId()); + private final MessageId lastRemoteMessageId2 = new MessageId(getRandomId()); + private final Author author1; + private final Author author2; + private final byte[] ephemeralPublicKey = + getRandomBytes(MAX_PUBLIC_KEY_LENGTH); + private final byte[] ephemeralPrivateKey = + getRandomBytes(MAX_PUBLIC_KEY_LENGTH); + private final byte[] masterKey = getRandomBytes(SecretKey.LENGTH); + private final byte[] remoteEphemeralPublicKey = + getRandomBytes(MAX_PUBLIC_KEY_LENGTH); + private final Map<TransportId, TransportProperties> transportProperties = + getTransportPropertiesMap(3); + private final Map<TransportId, TransportProperties> + remoteTransportProperties = getTransportPropertiesMap(3); + private final Map<TransportId, KeySetId> transportKeys = new HashMap<>(); + + public SessionEncoderParserIntegrationTest() { + BriarIntegrationTestComponent component = + DaggerBriarIntegrationTestComponent.builder().build(); + component.inject(this); + + sessionEncoder = new SessionEncoderImpl(clientHelper); + sessionParser = new SessionParserImpl(clientHelper); + author1 = getRealAuthor(); + author2 = getRealAuthor(); + transportKeys.put(getTransportId(), new KeySetId(1)); + transportKeys.put(getTransportId(), new KeySetId(2)); + transportKeys.put(getTransportId(), new KeySetId(3)); + } + + @Test + public void testIntroducerSession() throws FormatException { + IntroducerSession s1 = getIntroducerSession(); + + BdfDictionary d = sessionEncoder.encodeIntroducerSession(s1); + IntroducerSession s2 = sessionParser.parseIntroducerSession(d); + + assertEquals(INTRODUCER, s1.getRole()); + assertEquals(s1.getRole(), s2.getRole()); + assertEquals(sessionId, s1.getSessionId()); + assertEquals(s1.getSessionId(), s2.getSessionId()); + assertEquals(AWAIT_AUTHS, s1.getState()); + assertEquals(s1.getState(), s2.getState()); + assertIntroduceeEquals(s1.getIntroducee1(), s2.getIntroducee1()); + assertIntroduceeEquals(s1.getIntroducee2(), s2.getIntroducee2()); + } + + @Test + public void testIntroducerSessionWithNulls() throws FormatException { + Introducee introducee1 = + new Introducee(sessionId, groupId1, author1, localTimestamp, + null, null); + Introducee introducee2 = + new Introducee(sessionId, groupId2, author2, localTimestamp2, + null, null); + IntroducerSession s1 = new IntroducerSession(sessionId, + AWAIT_AUTHS, requestTimestamp, introducee1, + introducee2); + + BdfDictionary d = sessionEncoder.encodeIntroducerSession(s1); + IntroducerSession s2 = sessionParser.parseIntroducerSession(d); + + assertNull(s1.getIntroducee1().lastLocalMessageId); + assertEquals(s1.getIntroducee1().lastLocalMessageId, + s2.getIntroducee1().lastLocalMessageId); + assertNull(s1.getIntroducee1().lastRemoteMessageId); + assertEquals(s1.getIntroducee1().lastRemoteMessageId, + s2.getIntroducee1().lastRemoteMessageId); + + assertNull(s1.getIntroducee2().lastLocalMessageId); + assertEquals(s1.getIntroducee2().lastLocalMessageId, + s2.getIntroducee2().lastLocalMessageId); + assertNull(s1.getIntroducee2().lastRemoteMessageId); + assertEquals(s1.getIntroducee2().lastRemoteMessageId, + s2.getIntroducee2().lastRemoteMessageId); + } + + @Test(expected = FormatException.class) + public void testIntroducerSessionUnknownRole() throws FormatException { + IntroducerSession s = getIntroducerSession(); + BdfDictionary d = sessionEncoder.encodeIntroducerSession(s); + d.put(SESSION_KEY_ROLE, 1337); + sessionParser.parseIntroducerSession(d); + } + + @Test(expected = IllegalArgumentException.class) + public void testIntroducerSessionWrongRole() throws FormatException { + IntroducerSession s = getIntroducerSession(); + BdfDictionary d = sessionEncoder.encodeIntroducerSession(s); + d.put(SESSION_KEY_ROLE, INTRODUCEE.getValue()); + sessionParser.parseIntroducerSession(d); + } + + @Test + public void testIntroduceeSession() throws FormatException { + IntroduceeSession s1 = getIntroduceeSession(); + BdfDictionary d = sessionEncoder.encodeIntroduceeSession(s1); + IntroduceeSession s2 = + sessionParser.parseIntroduceeSession(groupId1, d); + + assertEquals(LOCAL_ACCEPTED, s1.getState()); + assertEquals(s1.getState(), s2.getState()); + assertEquals(INTRODUCEE, s1.getRole()); + assertEquals(s1.getRole(), s2.getRole()); + assertEquals(sessionId, s1.getSessionId()); + assertEquals(s1.getSessionId(), s2.getSessionId()); + assertEquals(groupId1, s1.getContactGroupId()); + assertEquals(s1.getContactGroupId(), s2.getContactGroupId()); + assertEquals(localTimestamp, s1.getLocalTimestamp()); + assertEquals(s1.getLocalTimestamp(), s2.getLocalTimestamp()); + assertEquals(lastLocalMessageId, s1.getLastLocalMessageId()); + assertEquals(s1.getLastLocalMessageId(), s2.getLastLocalMessageId()); + assertEquals(lastRemoteMessageId, s1.getLastRemoteMessageId()); + assertEquals(s1.getLastRemoteMessageId(), s2.getLastRemoteMessageId()); + assertEquals(author1, s1.getIntroducer()); + assertEquals(s1.getIntroducer(), s2.getIntroducer()); + assertEquals(author2, s1.getRemoteAuthor()); + assertEquals(s1.getRemoteAuthor(), s2.getRemoteAuthor()); + assertArrayEquals(ephemeralPublicKey, s1.getEphemeralPublicKey()); + assertArrayEquals(s1.getEphemeralPublicKey(), + s2.getEphemeralPublicKey()); + assertArrayEquals(ephemeralPrivateKey, s1.getEphemeralPrivateKey()); + assertArrayEquals(s1.getEphemeralPrivateKey(), + s2.getEphemeralPrivateKey()); + assertEquals(acceptTimestamp, s1.getAcceptTimestamp()); + assertEquals(s1.getAcceptTimestamp(), s2.getAcceptTimestamp()); + assertArrayEquals(masterKey, s1.getMasterKey()); + assertArrayEquals(s1.getMasterKey(), s2.getMasterKey()); + assertArrayEquals(remoteEphemeralPublicKey, s1.getRemotePublicKey()); + assertArrayEquals(s1.getRemotePublicKey(), + s2.getRemotePublicKey()); + assertEquals(transportProperties, s1.getTransportProperties()); + assertEquals(s1.getTransportProperties(), s2.getTransportProperties()); + assertEquals(remoteTransportProperties, + s1.getRemoteTransportProperties()); + assertEquals(s1.getRemoteTransportProperties(), + s2.getRemoteTransportProperties()); + assertEquals(remoteAcceptTimestamp, s1.getRemoteAcceptTimestamp()); + assertEquals(s1.getRemoteAcceptTimestamp(), s2.getRemoteAcceptTimestamp()); + assertEquals(transportKeys, s1.getTransportKeys()); + assertEquals(s1.getTransportKeys(), s2.getTransportKeys()); + } + + @Test + public void testIntroduceeSessionWithNulls() throws FormatException { + IntroduceeSession s1 = + new IntroduceeSession(sessionId, LOCAL_ACCEPTED, + requestTimestamp, groupId1, null, localTimestamp, null, + author1, null, null, null, acceptTimestamp, null, + author2, null, null, remoteAcceptTimestamp, null); + + BdfDictionary d = sessionEncoder.encodeIntroduceeSession(s1); + IntroduceeSession s2 = + sessionParser.parseIntroduceeSession(groupId1, d); + + assertNull(s1.getLastLocalMessageId()); + assertEquals(s1.getLastLocalMessageId(), s2.getLastLocalMessageId()); + assertNull(s1.getLastRemoteMessageId()); + assertEquals(s1.getLastRemoteMessageId(), s2.getLastRemoteMessageId()); + assertNull(s1.getEphemeralPublicKey()); + assertArrayEquals(s1.getEphemeralPublicKey(), + s2.getEphemeralPublicKey()); + assertNull(s1.getEphemeralPrivateKey()); + assertArrayEquals(s1.getEphemeralPrivateKey(), + s2.getEphemeralPrivateKey()); + assertNull(s1.getTransportKeys()); + assertEquals(s1.getTransportKeys(), s2.getTransportKeys()); + } + + @Test(expected = FormatException.class) + public void testIntroduceeSessionUnknownRole() throws FormatException { + IntroduceeSession s = getIntroduceeSession(); + BdfDictionary d = sessionEncoder.encodeIntroduceeSession(s); + d.put(SESSION_KEY_ROLE, 1337); + sessionParser.parseIntroduceeSession(groupId1, d); + } + + @Test(expected = IllegalArgumentException.class) + public void testIntroduceeSessionWrongRole() throws FormatException { + IntroduceeSession s = getIntroduceeSession(); + BdfDictionary d = sessionEncoder.encodeIntroduceeSession(s); + d.put(SESSION_KEY_ROLE, INTRODUCER.getValue()); + sessionParser.parseIntroduceeSession(groupId1, d); + } + + private IntroducerSession getIntroducerSession() { + Introducee introducee1 = + new Introducee(sessionId, groupId1, author1, localTimestamp, + lastLocalMessageId, lastRemoteMessageId); + Introducee introducee2 = + new Introducee(sessionId, groupId2, author2, localTimestamp2, + lastLocalMessageId2, lastRemoteMessageId2); + return new IntroducerSession(sessionId, AWAIT_AUTHS, + requestTimestamp, introducee1, introducee2); + } + + private IntroduceeSession getIntroduceeSession() { + return new IntroduceeSession(sessionId, LOCAL_ACCEPTED, + requestTimestamp, groupId1, lastLocalMessageId, localTimestamp, + lastRemoteMessageId, author1, ephemeralPublicKey, + ephemeralPrivateKey, transportProperties, acceptTimestamp, + masterKey, author2, remoteEphemeralPublicKey, + remoteTransportProperties, remoteAcceptTimestamp, + transportKeys); + } + + private void assertIntroduceeEquals(Introducee i1, Introducee i2) { + assertEquals(i1.author, i2.author); + assertEquals(i1.groupId, i2.groupId); + assertEquals(i1.localTimestamp, i2.localTimestamp); + assertEquals(i1.lastLocalMessageId, i2.lastLocalMessageId); + assertEquals(i1.lastRemoteMessageId, i2.lastRemoteMessageId); + } + + private Author getRealAuthor() { + return authorFactory.createAuthor(getRandomString(5), + getRandomBytes(MAX_PUBLIC_KEY_LENGTH)); + } + +} 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 1afcdea7bc..54709815e4 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 @@ -38,6 +38,7 @@ import org.briarproject.briar.client.BriarClientModule; import org.briarproject.briar.forum.ForumModule; import org.briarproject.briar.introduction.IntroductionModule; import org.briarproject.briar.introduction2.MessageEncoderParserIntegrationTest; +import org.briarproject.briar.introduction2.SessionEncoderParserIntegrationTest; import org.briarproject.briar.messaging.MessagingModule; import org.briarproject.briar.privategroup.PrivateGroupModule; import org.briarproject.briar.privategroup.invitation.GroupInvitationModule; @@ -78,6 +79,7 @@ public interface BriarIntegrationTestComponent { void inject(BriarIntegrationTest<BriarIntegrationTestComponent> init); void inject(MessageEncoderParserIntegrationTest init); + void inject(SessionEncoderParserIntegrationTest init); void inject(BlogModule.EagerSingletons init); -- GitLab