diff --git a/briar-api/src/main/java/org/briarproject/briar/api/conversation/ConversationMessageHeader.java b/briar-api/src/main/java/org/briarproject/briar/api/conversation/ConversationMessageHeader.java index 58d4c2d54..e648869bb 100644 --- a/briar-api/src/main/java/org/briarproject/briar/api/conversation/ConversationMessageHeader.java +++ b/briar-api/src/main/java/org/briarproject/briar/api/conversation/ConversationMessageHeader.java @@ -12,18 +12,20 @@ public abstract class ConversationMessageHeader { private final MessageId id; private final GroupId groupId; - private final long timestamp; - private final boolean local, sent, seen, read; + private final long timestamp, autoDeleteTimer; + private final boolean local, read, sent, seen; - public ConversationMessageHeader(MessageId id, GroupId groupId, long timestamp, - boolean local, boolean read, boolean sent, boolean seen) { + public ConversationMessageHeader(MessageId id, GroupId groupId, + long timestamp, boolean local, boolean read, boolean sent, + boolean seen, long autoDeleteTimer) { this.id = id; this.groupId = groupId; this.timestamp = timestamp; this.local = local; + this.read = read; this.sent = sent; this.seen = seen; - this.read = read; + this.autoDeleteTimer = autoDeleteTimer; } public MessageId getId() { @@ -55,4 +57,8 @@ public abstract class ConversationMessageHeader { } public abstract T accept(ConversationMessageVisitor v); + + public long getAutoDeleteTimer() { + return autoDeleteTimer; + } } diff --git a/briar-api/src/main/java/org/briarproject/briar/api/conversation/ConversationRequest.java b/briar-api/src/main/java/org/briarproject/briar/api/conversation/ConversationRequest.java index 214d0d1d4..62d33ca46 100644 --- a/briar-api/src/main/java/org/briarproject/briar/api/conversation/ConversationRequest.java +++ b/briar-api/src/main/java/org/briarproject/briar/api/conversation/ConversationRequest.java @@ -20,11 +20,12 @@ public abstract class ConversationRequest private final String text; private final boolean answered; - public ConversationRequest(MessageId messageId, GroupId groupId, long time, - boolean local, boolean read, boolean sent, boolean seen, - SessionId sessionId, N nameable, @Nullable String text, - boolean answered) { - super(messageId, groupId, time, local, read, sent, seen); + public ConversationRequest(MessageId messageId, GroupId groupId, + long timestamp, boolean local, boolean read, boolean sent, + boolean seen, SessionId sessionId, N nameable, + @Nullable String text, boolean answered, long autoDeleteTimer) { + super(messageId, groupId, timestamp, local, read, sent, seen, + autoDeleteTimer); this.sessionId = sessionId; this.nameable = nameable; this.text = text; diff --git a/briar-api/src/main/java/org/briarproject/briar/api/conversation/ConversationResponse.java b/briar-api/src/main/java/org/briarproject/briar/api/conversation/ConversationResponse.java index cf6c879f0..974d87c4e 100644 --- a/briar-api/src/main/java/org/briarproject/briar/api/conversation/ConversationResponse.java +++ b/briar-api/src/main/java/org/briarproject/briar/api/conversation/ConversationResponse.java @@ -16,8 +16,8 @@ public abstract class ConversationResponse extends ConversationMessageHeader { public ConversationResponse(MessageId id, GroupId groupId, long time, boolean local, boolean read, boolean sent, boolean seen, - SessionId sessionId, boolean accepted) { - super(id, groupId, time, local, read, sent, seen); + SessionId sessionId, boolean accepted, long autoDeleteTimer) { + super(id, groupId, time, local, read, sent, seen, autoDeleteTimer); this.sessionId = sessionId; this.accepted = accepted; } 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 c6a5db547..bc342596e 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 @@ -18,12 +18,12 @@ public class IntroductionRequest extends ConversationRequest { private final AuthorInfo authorInfo; - public IntroductionRequest(MessageId messageId, GroupId groupId, - long time, boolean local, boolean read, boolean sent, boolean seen, + public IntroductionRequest(MessageId messageId, GroupId groupId, long time, + boolean local, boolean read, boolean sent, boolean seen, SessionId sessionId, Author author, @Nullable String text, - boolean answered, AuthorInfo authorInfo) { + boolean answered, AuthorInfo authorInfo, long autoDeleteTimer) { super(messageId, groupId, time, local, read, sent, seen, sessionId, - author, text, answered); + author, text, answered, autoDeleteTimer); this.authorInfo = authorInfo; } 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 4b1777611..705b10a24 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 @@ -25,9 +25,10 @@ public class IntroductionResponse extends ConversationResponse { public IntroductionResponse(MessageId messageId, GroupId groupId, long time, boolean local, boolean read, boolean sent, boolean seen, SessionId sessionId, boolean accepted, Author author, - AuthorInfo introducedAuthorInfo, Role role, boolean canSucceed) { + AuthorInfo introducedAuthorInfo, Role role, boolean canSucceed, + long autoDeleteTimer) { super(messageId, groupId, time, local, read, sent, seen, sessionId, - accepted); + accepted, autoDeleteTimer); this.introducedAuthor = author; this.introducedAuthorInfo = introducedAuthorInfo; this.ourRole = role; diff --git a/briar-api/src/main/java/org/briarproject/briar/api/messaging/PrivateMessageHeader.java b/briar-api/src/main/java/org/briarproject/briar/api/messaging/PrivateMessageHeader.java index 369401982..afe3638b1 100644 --- a/briar-api/src/main/java/org/briarproject/briar/api/messaging/PrivateMessageHeader.java +++ b/briar-api/src/main/java/org/briarproject/briar/api/messaging/PrivateMessageHeader.java @@ -17,16 +17,14 @@ public class PrivateMessageHeader extends ConversationMessageHeader { private final boolean hasText; private final List attachmentHeaders; - private final long autoDeleteTimer; public PrivateMessageHeader(MessageId id, GroupId groupId, long timestamp, boolean local, boolean read, boolean sent, boolean seen, boolean hasText, List headers, long autoDeleteTimer) { - super(id, groupId, timestamp, local, read, sent, seen); + super(id, groupId, timestamp, local, read, sent, seen, autoDeleteTimer); this.hasText = hasText; this.attachmentHeaders = headers; - this.autoDeleteTimer = autoDeleteTimer; } public boolean hasText() { @@ -37,10 +35,6 @@ public class PrivateMessageHeader extends ConversationMessageHeader { return attachmentHeaders; } - public long getAutoDeleteTimer() { - return autoDeleteTimer; - } - @Override public T accept(ConversationMessageVisitor v) { return v.visitPrivateMessageHeader(this); diff --git a/briar-api/src/main/java/org/briarproject/briar/api/sharing/InvitationRequest.java b/briar-api/src/main/java/org/briarproject/briar/api/sharing/InvitationRequest.java index d122c8aea..432d71cf5 100644 --- a/briar-api/src/main/java/org/briarproject/briar/api/sharing/InvitationRequest.java +++ b/briar-api/src/main/java/org/briarproject/briar/api/sharing/InvitationRequest.java @@ -7,6 +7,8 @@ import org.briarproject.briar.api.conversation.ConversationRequest; import javax.annotation.Nullable; +import static org.briarproject.bramble.api.autodelete.AutoDeleteConstants.NO_AUTO_DELETE_TIMER; + public abstract class InvitationRequest extends ConversationRequest { @@ -17,7 +19,7 @@ public abstract class InvitationRequest extends SessionId sessionId, S object, @Nullable String text, boolean available, boolean canBeOpened) { super(messageId, groupId, time, local, read, sent, seen, sessionId, - object, text, !available); + object, text, !available, NO_AUTO_DELETE_TIMER); this.canBeOpened = canBeOpened; } diff --git a/briar-api/src/main/java/org/briarproject/briar/api/sharing/InvitationResponse.java b/briar-api/src/main/java/org/briarproject/briar/api/sharing/InvitationResponse.java index c5ae5c4d6..6a305cf7c 100644 --- a/briar-api/src/main/java/org/briarproject/briar/api/sharing/InvitationResponse.java +++ b/briar-api/src/main/java/org/briarproject/briar/api/sharing/InvitationResponse.java @@ -5,6 +5,8 @@ import org.briarproject.bramble.api.sync.MessageId; import org.briarproject.briar.api.client.SessionId; import org.briarproject.briar.api.conversation.ConversationResponse; +import static org.briarproject.bramble.api.autodelete.AutoDeleteConstants.NO_AUTO_DELETE_TIMER; + public abstract class InvitationResponse extends ConversationResponse { private final GroupId shareableId; @@ -12,7 +14,8 @@ public abstract class InvitationResponse extends ConversationResponse { public InvitationResponse(MessageId id, GroupId groupId, long time, boolean local, boolean read, boolean sent, boolean seen, SessionId sessionId, boolean accepted, GroupId shareableId) { - super(id, groupId, time, local, read, sent, seen, sessionId, accepted); + super(id, groupId, time, local, read, sent, seen, sessionId, accepted, + NO_AUTO_DELETE_TIMER); this.shareableId = shareableId; } diff --git a/briar-core/src/main/java/org/briarproject/briar/introduction/AbortMessage.java b/briar-core/src/main/java/org/briarproject/briar/introduction/AbortMessage.java index e9a2d1233..af98a1da2 100644 --- a/briar-core/src/main/java/org/briarproject/briar/introduction/AbortMessage.java +++ b/briar-core/src/main/java/org/briarproject/briar/introduction/AbortMessage.java @@ -8,6 +8,8 @@ import org.briarproject.briar.api.client.SessionId; import javax.annotation.Nullable; import javax.annotation.concurrent.Immutable; +import static org.briarproject.bramble.api.autodelete.AutoDeleteConstants.NO_AUTO_DELETE_TIMER; + @Immutable @NotNullByDefault class AbortMessage extends AbstractIntroductionMessage { @@ -16,7 +18,8 @@ class AbortMessage extends AbstractIntroductionMessage { protected AbortMessage(MessageId messageId, GroupId groupId, long timestamp, @Nullable MessageId previousMessageId, SessionId sessionId) { - super(messageId, groupId, timestamp, previousMessageId); + super(messageId, groupId, timestamp, previousMessageId, + NO_AUTO_DELETE_TIMER); this.sessionId = sessionId; } diff --git a/briar-core/src/main/java/org/briarproject/briar/introduction/AbstractIntroductionMessage.java b/briar-core/src/main/java/org/briarproject/briar/introduction/AbstractIntroductionMessage.java index 240b5ddec..d72130337 100644 --- a/briar-core/src/main/java/org/briarproject/briar/introduction/AbstractIntroductionMessage.java +++ b/briar-core/src/main/java/org/briarproject/briar/introduction/AbstractIntroductionMessage.java @@ -16,13 +16,16 @@ abstract class AbstractIntroductionMessage { private final long timestamp; @Nullable private final MessageId previousMessageId; + private final long autoDeleteTimer; AbstractIntroductionMessage(MessageId messageId, GroupId groupId, - long timestamp, @Nullable MessageId previousMessageId) { + long timestamp, @Nullable MessageId previousMessageId, + long autoDeleteTimer) { this.messageId = messageId; this.groupId = groupId; this.timestamp = timestamp; this.previousMessageId = previousMessageId; + this.autoDeleteTimer = autoDeleteTimer; } MessageId getMessageId() { @@ -42,4 +45,7 @@ abstract class AbstractIntroductionMessage { return previousMessageId; } + public long getAutoDeleteTimer() { + return autoDeleteTimer; + } } diff --git a/briar-core/src/main/java/org/briarproject/briar/introduction/AbstractProtocolEngine.java b/briar-core/src/main/java/org/briarproject/briar/introduction/AbstractProtocolEngine.java index 9f7d5febe..89885a12a 100644 --- a/briar-core/src/main/java/org/briarproject/briar/introduction/AbstractProtocolEngine.java +++ b/briar-core/src/main/java/org/briarproject/briar/introduction/AbstractProtocolEngine.java @@ -4,6 +4,7 @@ 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; import org.briarproject.bramble.api.crypto.PublicKey; import org.briarproject.bramble.api.data.BdfDictionary; @@ -16,9 +17,11 @@ import org.briarproject.bramble.api.identity.IdentityManager; import org.briarproject.bramble.api.nullsafety.NotNullByDefault; import org.briarproject.bramble.api.plugin.TransportId; import org.briarproject.bramble.api.properties.TransportProperties; +import org.briarproject.bramble.api.sync.GroupId; import org.briarproject.bramble.api.sync.Message; import org.briarproject.bramble.api.sync.MessageId; import org.briarproject.bramble.api.system.Clock; +import org.briarproject.bramble.api.versioning.ClientVersioningManager; import org.briarproject.briar.api.client.MessageTracker; import org.briarproject.briar.api.client.SessionId; import org.briarproject.briar.api.identity.AuthorInfo; @@ -32,6 +35,9 @@ import javax.annotation.Nullable; import javax.annotation.concurrent.Immutable; import static org.briarproject.bramble.api.autodelete.AutoDeleteConstants.NO_AUTO_DELETE_TIMER; +import static org.briarproject.briar.api.introduction.IntroductionManager.CLIENT_ID; +import static org.briarproject.briar.api.introduction.IntroductionManager.MAJOR_VERSION; +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; @@ -53,6 +59,7 @@ abstract class AbstractProtocolEngine> protected final AuthorManager authorManager; protected final MessageParser messageParser; protected final MessageEncoder messageEncoder; + protected final ClientVersioningManager clientVersioningManager; protected final Clock clock; AbstractProtocolEngine( @@ -65,6 +72,7 @@ abstract class AbstractProtocolEngine> AuthorManager authorManager, MessageParser messageParser, MessageEncoder messageEncoder, + ClientVersioningManager clientVersioningManager, Clock clock) { this.db = db; this.clientHelper = clientHelper; @@ -75,16 +83,26 @@ abstract class AbstractProtocolEngine> this.authorManager = authorManager; this.messageParser = messageParser; this.messageEncoder = messageEncoder; + this.clientVersioningManager = clientVersioningManager; this.clock = clock; } Message sendRequestMessage(Transaction txn, PeerSession s, long timestamp, Author author, @Nullable String text) throws DbException { - Message m = messageEncoder - .encodeRequestMessage(s.getContactGroupId(), timestamp, - s.getLastLocalMessageId(), author, text); - sendMessage(txn, REQUEST, s.getSessionId(), m, true); + Message m; + if (contactSupportsAutoDeletion(txn, s.getContactGroupId())) { + // TODO: Look up the current auto-delete timer + long timer = NO_AUTO_DELETE_TIMER; + m = messageEncoder.encodeRequestMessage(s.getContactGroupId(), + timestamp, s.getLastLocalMessageId(), author, text, timer); + sendMessage(txn, REQUEST, s.getSessionId(), m, true, timer); + } else { + m = messageEncoder.encodeRequestMessage(s.getContactGroupId(), + timestamp, s.getLastLocalMessageId(), author, text); + sendMessage(txn, REQUEST, s.getSessionId(), m, true, + NO_AUTO_DELETE_TIMER); + } return m; } @@ -92,21 +110,41 @@ abstract class AbstractProtocolEngine> PublicKey ephemeralPublicKey, long acceptTimestamp, Map transportProperties, boolean visible) throws DbException { - Message m = messageEncoder - .encodeAcceptMessage(s.getContactGroupId(), timestamp, - s.getLastLocalMessageId(), s.getSessionId(), - ephemeralPublicKey, acceptTimestamp, - transportProperties); - sendMessage(txn, ACCEPT, s.getSessionId(), m, visible); + Message m; + if (contactSupportsAutoDeletion(txn, s.getContactGroupId())) { + // TODO: Look up the current auto-delete timer + long timer = NO_AUTO_DELETE_TIMER; + m = messageEncoder.encodeAcceptMessage(s.getContactGroupId(), + timestamp, s.getLastLocalMessageId(), s.getSessionId(), + ephemeralPublicKey, acceptTimestamp, transportProperties, + timer); + sendMessage(txn, ACCEPT, s.getSessionId(), m, visible, timer); + } else { + m = messageEncoder.encodeAcceptMessage(s.getContactGroupId(), + timestamp, s.getLastLocalMessageId(), s.getSessionId(), + ephemeralPublicKey, acceptTimestamp, transportProperties); + sendMessage(txn, ACCEPT, s.getSessionId(), m, visible, + NO_AUTO_DELETE_TIMER); + } return m; } Message sendDeclineMessage(Transaction txn, PeerSession s, long timestamp, boolean visible) throws DbException { - Message m = messageEncoder - .encodeDeclineMessage(s.getContactGroupId(), timestamp, - s.getLastLocalMessageId(), s.getSessionId()); - sendMessage(txn, DECLINE, s.getSessionId(), m, visible); + Message m; + if (contactSupportsAutoDeletion(txn, s.getContactGroupId())) { + // TODO: Look up the current auto-delete timer + long timer = NO_AUTO_DELETE_TIMER; + m = messageEncoder.encodeDeclineMessage(s.getContactGroupId(), + timestamp, s.getLastLocalMessageId(), s.getSessionId(), + timer); + sendMessage(txn, DECLINE, s.getSessionId(), m, visible, timer); + } else { + m = messageEncoder.encodeDeclineMessage(s.getContactGroupId(), + timestamp, s.getLastLocalMessageId(), s.getSessionId()); + sendMessage(txn, DECLINE, s.getSessionId(), m, visible, + NO_AUTO_DELETE_TIMER); + } return m; } @@ -116,7 +154,8 @@ abstract class AbstractProtocolEngine> .encodeAuthMessage(s.getContactGroupId(), timestamp, s.getLastLocalMessageId(), s.getSessionId(), mac, signature); - sendMessage(txn, AUTH, s.getSessionId(), m, false); + sendMessage(txn, AUTH, s.getSessionId(), m, false, + NO_AUTO_DELETE_TIMER); return m; } @@ -125,7 +164,8 @@ abstract class AbstractProtocolEngine> Message m = messageEncoder .encodeActivateMessage(s.getContactGroupId(), timestamp, s.getLastLocalMessageId(), s.getSessionId(), mac); - sendMessage(txn, ACTIVATE, s.getSessionId(), m, false); + sendMessage(txn, ACTIVATE, s.getSessionId(), m, false, + NO_AUTO_DELETE_TIMER); return m; } @@ -134,18 +174,17 @@ abstract class AbstractProtocolEngine> Message m = messageEncoder .encodeAbortMessage(s.getContactGroupId(), timestamp, s.getLastLocalMessageId(), s.getSessionId()); - sendMessage(txn, ABORT, s.getSessionId(), m, false); + sendMessage(txn, ABORT, s.getSessionId(), m, false, + NO_AUTO_DELETE_TIMER); return m; } private void sendMessage(Transaction txn, MessageType type, - SessionId sessionId, Message m, boolean visibleInConversation) - throws DbException { - // TODO: If message is visible in conversation, look up current - // auto-delete timer and include it in message - BdfDictionary meta = messageEncoder - .encodeMetadata(type, sessionId, m.getTimestamp(), true, true, - visibleInConversation, NO_AUTO_DELETE_TIMER); + SessionId sessionId, Message m, boolean visibleInConversation, + long autoDeleteTimer) throws DbException { + BdfDictionary meta = messageEncoder.encodeMetadata(type, sessionId, + m.getTimestamp(), true, true, visibleInConversation, + autoDeleteTimer); try { clientHelper.addLocalMessage(txn, m, meta, true, false); } catch (FormatException e) { @@ -165,7 +204,8 @@ abstract class AbstractProtocolEngine> new IntroductionResponse(m.getMessageId(), m.getGroupId(), m.getTimestamp(), false, false, false, false, s.getSessionId(), m instanceof AcceptMessage, - otherAuthor, otherAuthorInfo, s.getRole(), canSucceed); + otherAuthor, otherAuthorInfo, s.getRole(), canSucceed, + m.getAutoDeleteTimer()); IntroductionResponseReceivedEvent e = new IntroductionResponseReceivedEvent(response, c.getId()); txn.attach(e); @@ -198,4 +238,19 @@ abstract class AbstractProtocolEngine> ); } + boolean contactSupportsAutoDeletion(Transaction txn, GroupId contactGroupId) + throws DbException { + try { + BdfDictionary meta = clientHelper + .getGroupMetadataAsDictionary(txn, contactGroupId); + int contactId = meta.getLong(GROUP_KEY_CONTACT_ID).intValue(); + ContactId c = new ContactId(contactId); + int minorVersion = clientVersioningManager + .getClientMinorVersion(txn, c, CLIENT_ID, MAJOR_VERSION); + // Auto-delete was added in client version 0.1 + return minorVersion >= 1; + } catch (FormatException e) { + throw new DbException(e); + } + } } diff --git a/briar-core/src/main/java/org/briarproject/briar/introduction/AcceptMessage.java b/briar-core/src/main/java/org/briarproject/briar/introduction/AcceptMessage.java index d76957616..e021ff7f8 100644 --- a/briar-core/src/main/java/org/briarproject/briar/introduction/AcceptMessage.java +++ b/briar-core/src/main/java/org/briarproject/briar/introduction/AcceptMessage.java @@ -26,8 +26,10 @@ class AcceptMessage extends AbstractIntroductionMessage { long timestamp, @Nullable MessageId previousMessageId, SessionId sessionId, PublicKey ephemeralPublicKey, long acceptTimestamp, - Map transportProperties) { - super(messageId, groupId, timestamp, previousMessageId); + Map transportProperties, + long autoDeleteTimer) { + super(messageId, groupId, timestamp, previousMessageId, + autoDeleteTimer); this.sessionId = sessionId; this.ephemeralPublicKey = ephemeralPublicKey; this.acceptTimestamp = acceptTimestamp; diff --git a/briar-core/src/main/java/org/briarproject/briar/introduction/ActivateMessage.java b/briar-core/src/main/java/org/briarproject/briar/introduction/ActivateMessage.java index 5f767737d..5c2f25375 100644 --- a/briar-core/src/main/java/org/briarproject/briar/introduction/ActivateMessage.java +++ b/briar-core/src/main/java/org/briarproject/briar/introduction/ActivateMessage.java @@ -7,6 +7,8 @@ import org.briarproject.briar.api.client.SessionId; import javax.annotation.concurrent.Immutable; +import static org.briarproject.bramble.api.autodelete.AutoDeleteConstants.NO_AUTO_DELETE_TIMER; + @Immutable @NotNullByDefault class ActivateMessage extends AbstractIntroductionMessage { @@ -17,7 +19,8 @@ class ActivateMessage extends AbstractIntroductionMessage { protected ActivateMessage(MessageId messageId, GroupId groupId, long timestamp, MessageId previousMessageId, SessionId sessionId, byte[] mac) { - super(messageId, groupId, timestamp, previousMessageId); + super(messageId, groupId, timestamp, previousMessageId, + NO_AUTO_DELETE_TIMER); this.sessionId = sessionId; this.mac = mac; } diff --git a/briar-core/src/main/java/org/briarproject/briar/introduction/AuthMessage.java b/briar-core/src/main/java/org/briarproject/briar/introduction/AuthMessage.java index 1de1a4eb5..01bdcae33 100644 --- a/briar-core/src/main/java/org/briarproject/briar/introduction/AuthMessage.java +++ b/briar-core/src/main/java/org/briarproject/briar/introduction/AuthMessage.java @@ -7,6 +7,8 @@ import org.briarproject.briar.api.client.SessionId; import javax.annotation.concurrent.Immutable; +import static org.briarproject.bramble.api.autodelete.AutoDeleteConstants.NO_AUTO_DELETE_TIMER; + @Immutable @NotNullByDefault class AuthMessage extends AbstractIntroductionMessage { @@ -17,7 +19,8 @@ class AuthMessage extends AbstractIntroductionMessage { protected AuthMessage(MessageId messageId, GroupId groupId, long timestamp, MessageId previousMessageId, SessionId sessionId, byte[] mac, byte[] signature) { - super(messageId, groupId, timestamp, previousMessageId); + super(messageId, groupId, timestamp, previousMessageId, + NO_AUTO_DELETE_TIMER); this.sessionId = sessionId; this.mac = mac; this.signature = signature; diff --git a/briar-core/src/main/java/org/briarproject/briar/introduction/DeclineMessage.java b/briar-core/src/main/java/org/briarproject/briar/introduction/DeclineMessage.java index 27386b905..631312019 100644 --- a/briar-core/src/main/java/org/briarproject/briar/introduction/DeclineMessage.java +++ b/briar-core/src/main/java/org/briarproject/briar/introduction/DeclineMessage.java @@ -16,8 +16,9 @@ class DeclineMessage extends AbstractIntroductionMessage { protected DeclineMessage(MessageId messageId, GroupId groupId, long timestamp, @Nullable MessageId previousMessageId, - SessionId sessionId) { - super(messageId, groupId, timestamp, previousMessageId); + SessionId sessionId, long autoDeleteTimer) { + super(messageId, groupId, timestamp, previousMessageId, + autoDeleteTimer); this.sessionId = sessionId; } diff --git a/briar-core/src/main/java/org/briarproject/briar/introduction/IntroduceeProtocolEngine.java b/briar-core/src/main/java/org/briarproject/briar/introduction/IntroduceeProtocolEngine.java index 8d7dd4a46..4beba3fb5 100644 --- a/briar-core/src/main/java/org/briarproject/briar/introduction/IntroduceeProtocolEngine.java +++ b/briar-core/src/main/java/org/briarproject/briar/introduction/IntroduceeProtocolEngine.java @@ -25,6 +25,7 @@ import org.briarproject.bramble.api.sync.MessageId; import org.briarproject.bramble.api.system.Clock; import org.briarproject.bramble.api.transport.KeyManager; import org.briarproject.bramble.api.transport.KeySetId; +import org.briarproject.bramble.api.versioning.ClientVersioningManager; import org.briarproject.briar.api.client.MessageTracker; import org.briarproject.briar.api.client.ProtocolStateException; import org.briarproject.briar.api.client.SessionId; @@ -78,10 +79,11 @@ class IntroduceeProtocolEngine Clock clock, IntroductionCrypto crypto, KeyManager keyManager, - TransportPropertyManager transportPropertyManager) { + TransportPropertyManager transportPropertyManager, + ClientVersioningManager clientVersioningManager) { super(db, clientHelper, contactManager, contactGroupFactory, messageTracker, identityManager, authorManager, messageParser, - messageEncoder, clock); + messageEncoder, clientVersioningManager, clock); this.crypto = crypto; this.keyManager = keyManager; this.transportPropertyManager = transportPropertyManager; @@ -260,7 +262,7 @@ class IntroduceeProtocolEngine IntroductionRequest request = new IntroductionRequest(m.getMessageId(), m.getGroupId(), m.getTimestamp(), false, false, false, false, s.getSessionId(), m.getAuthor(), m.getText(), false, - authorInfo); + authorInfo, m.getAutoDeleteTimer()); IntroductionRequestReceivedEvent e = new IntroductionRequestReceivedEvent(request, c.getId()); txn.attach(e); diff --git a/briar-core/src/main/java/org/briarproject/briar/introduction/IntroducerProtocolEngine.java b/briar-core/src/main/java/org/briarproject/briar/introduction/IntroducerProtocolEngine.java index 39f2faf5a..8978c917a 100644 --- a/briar-core/src/main/java/org/briarproject/briar/introduction/IntroducerProtocolEngine.java +++ b/briar-core/src/main/java/org/briarproject/briar/introduction/IntroducerProtocolEngine.java @@ -13,6 +13,7 @@ import org.briarproject.bramble.api.sync.GroupId; import org.briarproject.bramble.api.sync.Message; import org.briarproject.bramble.api.sync.MessageId; import org.briarproject.bramble.api.system.Clock; +import org.briarproject.bramble.api.versioning.ClientVersioningManager; import org.briarproject.briar.api.client.MessageTracker; import org.briarproject.briar.api.client.ProtocolStateException; import org.briarproject.briar.api.identity.AuthorManager; @@ -52,10 +53,11 @@ class IntroducerProtocolEngine AuthorManager authorManager, MessageParser messageParser, MessageEncoder messageEncoder, + ClientVersioningManager clientVersioningManager, Clock clock) { super(db, clientHelper, contactManager, contactGroupFactory, messageTracker, identityManager, authorManager, messageParser, - messageEncoder, clock); + messageEncoder, clientVersioningManager, clock); } @Override 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 dd88159c8..70eee9b45 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 @@ -465,7 +465,7 @@ class IntroductionManagerImpl extends ConversationClientImpl return new IntroductionRequest(m, contactGroupId, meta.getTimestamp(), meta.isLocal(), meta.isRead(), status.isSent(), status.isSeen(), sessionId, author, text, !meta.isAvailableToAnswer(), - authorInfo); + authorInfo, rm.getAutoDeleteTimer()); } private IntroductionResponse parseInvitationResponse(Transaction txn, @@ -503,7 +503,8 @@ class IntroductionManagerImpl extends ConversationClientImpl } return new IntroductionResponse(m, contactGroupId, meta.getTimestamp(), meta.isLocal(), meta.isRead(), status.isSent(), status.isSeen(), - sessionId, accept, author, authorInfo, role, canSucceed); + sessionId, accept, author, authorInfo, role, canSucceed, + meta.getAutoDeleteTimer()); } private void removeSessionWithIntroducer(Transaction txn, 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 7b78cbf47..0112b4a23 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 @@ -15,6 +15,7 @@ import org.briarproject.bramble.api.sync.MessageId; import org.briarproject.bramble.api.system.Clock; import org.briarproject.briar.api.client.SessionId; +import javax.annotation.Nullable; import javax.annotation.concurrent.Immutable; import static java.util.Collections.singletonList; @@ -86,13 +87,8 @@ class IntroductionValidator extends BdfMessageValidator { String text = body.getOptionalString(3); checkLength(text, 1, MAX_INTRODUCTION_TEXT_LENGTH); - Long timer = null; - if (body.size() == 5) { - timer = body.getOptionalLong(4); - checkRange(timer, MIN_AUTO_DELETE_TIMER_MS, - MAX_AUTO_DELETE_TIMER_MS); - } - if (timer == null) timer = NO_AUTO_DELETE_TIMER; + long timer = NO_AUTO_DELETE_TIMER; + if (body.size() == 5) timer = validateTimer(body.getOptionalLong(4)); BdfDictionary meta = messageEncoder.encodeRequestMetadata(m.getTimestamp(), timer); @@ -131,13 +127,8 @@ class IntroductionValidator extends BdfMessageValidator { clientHelper .parseAndValidateTransportPropertiesMap(transportProperties); - Long timer = null; - if (body.size() == 7) { - timer = body.getOptionalLong(6); - checkRange(timer, MIN_AUTO_DELETE_TIMER_MS, - MAX_AUTO_DELETE_TIMER_MS); - } - if (timer == null) timer = NO_AUTO_DELETE_TIMER; + long timer = NO_AUTO_DELETE_TIMER; + if (body.size() == 7) timer = validateTimer(body.getOptionalLong(6)); SessionId sessionId = new SessionId(sessionIdBytes); BdfDictionary meta = messageEncoder.encodeMetadata(ACCEPT, sessionId, @@ -164,13 +155,8 @@ class IntroductionValidator extends BdfMessageValidator { byte[] previousMessageId = body.getOptionalRaw(2); checkLength(previousMessageId, UniqueId.LENGTH); - Long timer = null; - if (body.size() == 4) { - timer = body.getOptionalLong(3); - checkRange(timer, MIN_AUTO_DELETE_TIMER_MS, - MAX_AUTO_DELETE_TIMER_MS); - } - if (timer == null) timer = NO_AUTO_DELETE_TIMER; + long timer = NO_AUTO_DELETE_TIMER; + if (body.size() == 4) timer = validateTimer(body.getOptionalLong(3)); SessionId sessionId = new SessionId(sessionIdBytes); BdfDictionary meta = messageEncoder.encodeMetadata(type, sessionId, @@ -251,4 +237,9 @@ class IntroductionValidator extends BdfMessageValidator { } } + private long validateTimer(@Nullable Long timer) throws FormatException { + if (timer == null) return NO_AUTO_DELETE_TIMER; + checkRange(timer, MIN_AUTO_DELETE_TIMER_MS, MAX_AUTO_DELETE_TIMER_MS); + return timer; + } } diff --git a/briar-core/src/main/java/org/briarproject/briar/introduction/MessageEncoder.java b/briar-core/src/main/java/org/briarproject/briar/introduction/MessageEncoder.java index 2357f7277..85fa4d4aa 100644 --- a/briar-core/src/main/java/org/briarproject/briar/introduction/MessageEncoder.java +++ b/briar-core/src/main/java/org/briarproject/briar/introduction/MessageEncoder.java @@ -31,18 +31,53 @@ interface MessageEncoder { void setAvailableToAnswer(BdfDictionary meta, boolean available); + /** + * Encodes a request message without an auto-delete timer. + */ Message encodeRequestMessage(GroupId contactGroupId, long timestamp, @Nullable MessageId previousMessageId, Author author, @Nullable String text); + /** + * Encodes a request message with an optional auto-delete timer. This + * requires the contact to support client version 0.1 or higher. + */ + Message encodeRequestMessage(GroupId contactGroupId, long timestamp, + @Nullable MessageId previousMessageId, Author author, + @Nullable String text, long autoDeleteTimer); + + /** + * Encodes an accept message without an auto-delete timer. + */ Message encodeAcceptMessage(GroupId contactGroupId, long timestamp, @Nullable MessageId previousMessageId, SessionId sessionId, PublicKey ephemeralPublicKey, long acceptTimestamp, Map transportProperties); + /** + * Encodes an accept message with an optional auto-delete timer. This + * requires the contact to support client version 0.1 or higher. + */ + Message encodeAcceptMessage(GroupId contactGroupId, long timestamp, + @Nullable MessageId previousMessageId, SessionId sessionId, + PublicKey ephemeralPublicKey, long acceptTimestamp, + Map transportProperties, + long autoDeleteTimer); + + /** + * Encodes a decline message without an auto-delete timer. + */ Message encodeDeclineMessage(GroupId contactGroupId, long timestamp, @Nullable MessageId previousMessageId, SessionId sessionId); + /** + * Encodes a decline message with an optional auto-delete timer. This + * requires the contact to support client version 0.1 or higher. + */ + Message encodeDeclineMessage(GroupId contactGroupId, long timestamp, + @Nullable MessageId previousMessageId, SessionId sessionId, + long autoDeleteTimer); + Message encodeAuthMessage(GroupId contactGroupId, long timestamp, @Nullable MessageId previousMessageId, SessionId sessionId, byte[] mac, byte[] signature); diff --git a/briar-core/src/main/java/org/briarproject/briar/introduction/MessageEncoderImpl.java b/briar-core/src/main/java/org/briarproject/briar/introduction/MessageEncoderImpl.java index 901b37cd7..ecb5dbccb 100644 --- a/briar-core/src/main/java/org/briarproject/briar/introduction/MessageEncoderImpl.java +++ b/briar-core/src/main/java/org/briarproject/briar/introduction/MessageEncoderImpl.java @@ -109,6 +109,23 @@ class MessageEncoderImpl implements MessageEncoder { return createMessage(contactGroupId, timestamp, body); } + @Override + public Message encodeRequestMessage(GroupId contactGroupId, long timestamp, + @Nullable MessageId previousMessageId, Author author, + @Nullable String text, long autoDeleteTimer) { + if (text != null && text.isEmpty()) { + throw new IllegalArgumentException(); + } + BdfList body = BdfList.of( + REQUEST.getValue(), + previousMessageId, + clientHelper.toList(author), + text, + encodeTimer(autoDeleteTimer) + ); + return createMessage(contactGroupId, timestamp, body); + } + @Override public Message encodeAcceptMessage(GroupId contactGroupId, long timestamp, @Nullable MessageId previousMessageId, SessionId sessionId, @@ -125,11 +142,46 @@ class MessageEncoderImpl implements MessageEncoder { return createMessage(contactGroupId, timestamp, body); } + @Override + public Message encodeAcceptMessage(GroupId contactGroupId, long timestamp, + @Nullable MessageId previousMessageId, SessionId sessionId, + PublicKey ephemeralPublicKey, long acceptTimestamp, + Map transportProperties, + long autoDeleteTimer) { + BdfList body = BdfList.of( + ACCEPT.getValue(), + sessionId, + previousMessageId, + ephemeralPublicKey.getEncoded(), + acceptTimestamp, + clientHelper.toDictionary(transportProperties), + encodeTimer(autoDeleteTimer) + ); + return createMessage(contactGroupId, timestamp, body); + } + @Override public Message encodeDeclineMessage(GroupId contactGroupId, long timestamp, @Nullable MessageId previousMessageId, SessionId sessionId) { - return encodeMessage(DECLINE, contactGroupId, sessionId, timestamp, - previousMessageId); + BdfList body = BdfList.of( + DECLINE.getValue(), + sessionId, + previousMessageId + ); + return createMessage(contactGroupId, timestamp, body); + } + + @Override + public Message encodeDeclineMessage(GroupId contactGroupId, long timestamp, + @Nullable MessageId previousMessageId, SessionId sessionId, + long autoDeleteTimer) { + BdfList body = BdfList.of( + DECLINE.getValue(), + sessionId, + previousMessageId, + encodeTimer(autoDeleteTimer) + ); + return createMessage(contactGroupId, timestamp, body); } @Override @@ -162,15 +214,8 @@ class MessageEncoderImpl implements MessageEncoder { @Override public Message encodeAbortMessage(GroupId contactGroupId, long timestamp, @Nullable MessageId previousMessageId, SessionId sessionId) { - return encodeMessage(ABORT, contactGroupId, sessionId, timestamp, - previousMessageId); - } - - private Message encodeMessage(MessageType type, GroupId contactGroupId, - SessionId sessionId, long timestamp, - @Nullable MessageId previousMessageId) { BdfList body = BdfList.of( - type.getValue(), + ABORT.getValue(), sessionId, previousMessageId ); @@ -187,4 +232,8 @@ class MessageEncoderImpl implements MessageEncoder { } } + @Nullable + private Long encodeTimer(long autoDeleteTimer) { + return autoDeleteTimer == NO_AUTO_DELETE_TIMER ? null : autoDeleteTimer; + } } diff --git a/briar-core/src/main/java/org/briarproject/briar/introduction/MessageParserImpl.java b/briar-core/src/main/java/org/briarproject/briar/introduction/MessageParserImpl.java index 1e6808c06..bc4160d1e 100644 --- a/briar-core/src/main/java/org/briarproject/briar/introduction/MessageParserImpl.java +++ b/briar-core/src/main/java/org/briarproject/briar/introduction/MessageParserImpl.java @@ -80,8 +80,10 @@ class MessageParserImpl implements MessageParser { new MessageId(previousMsgBytes)); Author author = clientHelper.parseAndValidateAuthor(body.getList(2)); String text = body.getOptionalString(3); + long timer = NO_AUTO_DELETE_TIMER; + if (body.size() == 5) timer = body.getLong(4, NO_AUTO_DELETE_TIMER); return new RequestMessage(m.getId(), m.getGroupId(), - m.getTimestamp(), previousMessageId, author, text); + m.getTimestamp(), previousMessageId, author, text, timer); } @Override @@ -95,9 +97,11 @@ class MessageParserImpl implements MessageParser { long acceptTimestamp = body.getLong(4); Map transportProperties = clientHelper .parseAndValidateTransportPropertiesMap(body.getDictionary(5)); + long timer = NO_AUTO_DELETE_TIMER; + if (body.size() == 7) timer = body.getLong(6, NO_AUTO_DELETE_TIMER); return new AcceptMessage(m.getId(), m.getGroupId(), m.getTimestamp(), previousMessageId, sessionId, ephemeralPublicKey, - acceptTimestamp, transportProperties); + acceptTimestamp, transportProperties, timer); } @Override @@ -107,8 +111,10 @@ class MessageParserImpl implements MessageParser { byte[] previousMsgBytes = body.getOptionalRaw(2); MessageId previousMessageId = (previousMsgBytes == null ? null : new MessageId(previousMsgBytes)); + long timer = NO_AUTO_DELETE_TIMER; + if (body.size() == 4) timer = body.getLong(3, NO_AUTO_DELETE_TIMER); return new DeclineMessage(m.getId(), m.getGroupId(), m.getTimestamp(), - previousMessageId, sessionId); + previousMessageId, sessionId, timer); } @Override diff --git a/briar-core/src/main/java/org/briarproject/briar/introduction/RequestMessage.java b/briar-core/src/main/java/org/briarproject/briar/introduction/RequestMessage.java index f6d8d4870..b192f5e78 100644 --- a/briar-core/src/main/java/org/briarproject/briar/introduction/RequestMessage.java +++ b/briar-core/src/main/java/org/briarproject/briar/introduction/RequestMessage.java @@ -18,8 +18,9 @@ class RequestMessage extends AbstractIntroductionMessage { RequestMessage(MessageId messageId, GroupId groupId, long timestamp, @Nullable MessageId previousMessageId, Author author, - @Nullable String text) { - super(messageId, groupId, timestamp, previousMessageId); + @Nullable String text, long autoDeleteTimer) { + super(messageId, groupId, timestamp, previousMessageId, + autoDeleteTimer); this.author = author; this.text = text; } 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 cee9a8bba..e13aa0aee 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 @@ -45,6 +45,7 @@ import java.util.Map; import java.util.Set; import static java.util.Collections.emptySet; +import static org.briarproject.bramble.api.autodelete.AutoDeleteConstants.NO_AUTO_DELETE_TIMER; import static org.briarproject.bramble.test.TestPluginConfigModule.SIMPLEX_TRANSPORT_ID; import static org.briarproject.bramble.test.TestUtils.getAgreementPublicKey; import static org.briarproject.bramble.test.TestUtils.getSecretKey; @@ -1114,7 +1115,7 @@ public class IntroductionIntegrationTest m.getTimestamp(), m.getPreviousMessageId(), m.getSessionId(), m.getEphemeralPublicKey(), m.getAcceptTimestamp(), - getTransportPropertiesMap(2)) + getTransportPropertiesMap(2), NO_AUTO_DELETE_TIMER) ); } @@ -1125,7 +1126,7 @@ public class IntroductionIntegrationTest m.getTimestamp(), m.getPreviousMessageId(), m.getSessionId(), m.getEphemeralPublicKey(), clock.currentTimeMillis(), - m.getTransportProperties()) + m.getTransportProperties(), NO_AUTO_DELETE_TIMER) ); } @@ -1135,7 +1136,8 @@ public class IntroductionIntegrationTest m -> new AcceptMessage(m.getMessageId(), m.getGroupId(), m.getTimestamp(), m.getPreviousMessageId(), m.getSessionId(), getAgreementPublicKey(), - m.getAcceptTimestamp(), m.getTransportProperties()) + m.getAcceptTimestamp(), m.getTransportProperties(), + NO_AUTO_DELETE_TIMER) ); } @@ -1155,10 +1157,12 @@ public class IntroductionIntegrationTest // introducer can not yet remove messages assertFalse(deleteAllMessages1From0().allDeleted()); - assertTrue(deleteAllMessages1From0().hasIntroductionSessionInProgress()); + assertTrue( + deleteAllMessages1From0().hasIntroductionSessionInProgress()); // introducee1 can not yet remove messages assertFalse(deleteAllMessages0From1().allDeleted()); - assertTrue(deleteAllMessages0From1().hasIntroductionSessionInProgress()); + assertTrue( + deleteAllMessages0From1().hasIntroductionSessionInProgress()); // sync second REQUEST message sync0To2(1, true); @@ -1166,10 +1170,12 @@ public class IntroductionIntegrationTest // introducer can not yet remove messages assertFalse(deleteAllMessages2From0().allDeleted()); - assertTrue(deleteAllMessages2From0().hasIntroductionSessionInProgress()); + assertTrue( + deleteAllMessages2From0().hasIntroductionSessionInProgress()); // introducee2 can not yet remove messages assertFalse(deleteAllMessages0From2().allDeleted()); - assertTrue(deleteAllMessages0From2().hasIntroductionSessionInProgress()); + assertTrue( + deleteAllMessages0From2().hasIntroductionSessionInProgress()); // sync first ACCEPT message sync1To0(1, true); @@ -1177,7 +1183,8 @@ public class IntroductionIntegrationTest // introducer can not yet remove messages assertFalse(deleteAllMessages1From0().allDeleted()); - assertTrue(deleteAllMessages1From0().hasIntroductionSessionInProgress()); + assertTrue( + deleteAllMessages1From0().hasIntroductionSessionInProgress()); // sync second ACCEPT message sync2To0(1, true); @@ -1185,7 +1192,8 @@ public class IntroductionIntegrationTest // introducer can not yet remove messages assertFalse(deleteAllMessages2From0().allDeleted()); - assertTrue(deleteAllMessages2From0().hasIntroductionSessionInProgress()); + assertTrue( + deleteAllMessages2From0().hasIntroductionSessionInProgress()); // sync forwarded ACCEPT messages to introducees sync0To1(1, true); @@ -1193,10 +1201,12 @@ public class IntroductionIntegrationTest // introducee1 can not yet remove messages assertFalse(deleteAllMessages0From1().allDeleted()); - assertTrue(deleteAllMessages0From1().hasIntroductionSessionInProgress()); + assertTrue( + deleteAllMessages0From1().hasIntroductionSessionInProgress()); // introducee2 can not yet remove messages assertFalse(deleteAllMessages0From2().allDeleted()); - assertTrue(deleteAllMessages0From2().hasIntroductionSessionInProgress()); + assertTrue( + deleteAllMessages0From2().hasIntroductionSessionInProgress()); // sync first AUTH and its forward sync1To0(1, true); @@ -1204,12 +1214,15 @@ public class IntroductionIntegrationTest // introducer can not yet remove messages assertFalse(deleteAllMessages1From0().allDeleted()); - assertTrue(deleteAllMessages1From0().hasIntroductionSessionInProgress()); + assertTrue( + deleteAllMessages1From0().hasIntroductionSessionInProgress()); assertFalse(deleteAllMessages2From0().allDeleted()); - assertTrue(deleteAllMessages2From0().hasIntroductionSessionInProgress()); + assertTrue( + deleteAllMessages2From0().hasIntroductionSessionInProgress()); // introducee2 can not yet remove messages assertFalse(deleteAllMessages0From2().allDeleted()); - assertTrue(deleteAllMessages0From2().hasIntroductionSessionInProgress()); + assertTrue( + deleteAllMessages0From2().hasIntroductionSessionInProgress()); // sync second AUTH and its forward as well as the following ACTIVATE sync2To0(2, true); @@ -1217,12 +1230,15 @@ public class IntroductionIntegrationTest // introducer can not yet remove messages assertFalse(deleteAllMessages1From0().allDeleted()); - assertTrue(deleteAllMessages1From0().hasIntroductionSessionInProgress()); + assertTrue( + deleteAllMessages1From0().hasIntroductionSessionInProgress()); assertFalse(deleteAllMessages2From0().allDeleted()); - assertTrue(deleteAllMessages2From0().hasIntroductionSessionInProgress()); + assertTrue( + deleteAllMessages2From0().hasIntroductionSessionInProgress()); // introducee1 can not yet remove messages assertFalse(deleteAllMessages0From1().allDeleted()); - assertTrue(deleteAllMessages0From1().hasIntroductionSessionInProgress()); + assertTrue( + deleteAllMessages0From1().hasIntroductionSessionInProgress()); // sync second ACTIVATE and its forward sync1To0(1, true); @@ -1458,14 +1474,16 @@ public class IntroductionIntegrationTest sendAcks(c1, c0, contactId0From1, 1); assertTrue(deleteAllMessages1From0().allDeleted()); assertEquals(0, getMessages1From0().size()); - assertTrue(deleteAllMessages1From0().allDeleted()); // a second time nothing happens + assertTrue(deleteAllMessages1From0() + .allDeleted()); // a second time nothing happens // introducer can remove messages after getting ACK from introducee2 // if this succeeds, we still had the session object after delete above sendAcks(c2, c0, contactId0From2, 1); assertTrue(deleteAllMessages2From0().allDeleted()); assertEquals(0, getMessages2From0().size()); - assertTrue(deleteAllMessages2From0().allDeleted()); // a second time nothing happens + assertTrue(deleteAllMessages2From0() + .allDeleted()); // a second time nothing happens // no one should have aborted assertFalse(listener0.aborted); @@ -1489,7 +1507,8 @@ public class IntroductionIntegrationTest Set toDelete1 = new HashSet<>(); toDelete1.add(messageId1); assertFalse(deleteMessages1From0(toDelete1).allDeleted()); - assertTrue(deleteMessages1From0(toDelete1).hasIntroductionSessionInProgress()); + assertTrue(deleteMessages1From0(toDelete1) + .hasIntroductionSessionInProgress()); // deleting the introduction for introducee2 will fail as well Collection m2From0 = getMessages2From0(); @@ -1498,7 +1517,8 @@ public class IntroductionIntegrationTest Set toDelete2 = new HashSet<>(); toDelete2.add(messageId2); assertFalse(deleteMessages2From0(toDelete2).allDeleted()); - assertTrue(deleteMessages2From0(toDelete2).hasIntroductionSessionInProgress()); + assertTrue(deleteMessages2From0(toDelete2) + .hasIntroductionSessionInProgress()); // sync REQUEST messages sync0To1(1, true); @@ -1508,9 +1528,11 @@ public class IntroductionIntegrationTest // deleting introduction fails, because responses did not arrive assertFalse(deleteMessages0From1(toDelete1).allDeleted()); - assertTrue(deleteMessages0From1(toDelete1).hasIntroductionSessionInProgress()); + assertTrue(deleteMessages0From1(toDelete1) + .hasIntroductionSessionInProgress()); assertFalse(deleteMessages0From2(toDelete2).allDeleted()); - assertTrue(deleteMessages0From2(toDelete2).hasIntroductionSessionInProgress()); + assertTrue(deleteMessages0From2(toDelete2) + .hasIntroductionSessionInProgress()); // remember response of introducee1 for future deletion Collection m0From1 = getMessages0From1(); @@ -1570,7 +1592,8 @@ public class IntroductionIntegrationTest // deleting introduction fails for introducee 2, // because response is not yet selected for deletion assertFalse(deleteMessages0From2(toDelete2).allDeleted()); - assertTrue(deleteMessages0From2(toDelete2).hasNotAllIntroductionSelected()); + assertTrue(deleteMessages0From2(toDelete2) + .hasNotAllIntroductionSelected()); // add response to be deleted as well toDelete2.add(response2); @@ -1588,7 +1611,8 @@ public class IntroductionIntegrationTest // deleting introduction fails for introducee 1, // because response is not yet selected for deletion assertFalse(deleteMessages0From1(toDelete1).allDeleted()); - assertTrue(deleteMessages0From1(toDelete1).hasNotAllIntroductionSelected()); + assertTrue(deleteMessages0From1(toDelete1) + .hasNotAllIntroductionSelected()); // add response to be deleted as well toDelete1.add(response1); @@ -1730,7 +1754,8 @@ public class IntroductionIntegrationTest @MethodsNotNullByDefault @ParametersNotNullByDefault - private abstract class IntroductionListener implements EventListener { + private abstract static class IntroductionListener + implements EventListener { volatile boolean aborted = false; volatile Event latestEvent; diff --git a/briar-core/src/test/java/org/briarproject/briar/introduction/MessageEncoderParserIntegrationTest.java b/briar-core/src/test/java/org/briarproject/briar/introduction/MessageEncoderParserIntegrationTest.java index 6ee624333..808ca3454 100644 --- a/briar-core/src/test/java/org/briarproject/briar/introduction/MessageEncoderParserIntegrationTest.java +++ b/briar-core/src/test/java/org/briarproject/briar/introduction/MessageEncoderParserIntegrationTest.java @@ -25,6 +25,7 @@ import javax.inject.Inject; import static org.briarproject.bramble.api.autodelete.AutoDeleteConstants.MAX_AUTO_DELETE_TIMER_MS; import static org.briarproject.bramble.api.autodelete.AutoDeleteConstants.MIN_AUTO_DELETE_TIMER_MS; +import static org.briarproject.bramble.api.autodelete.AutoDeleteConstants.NO_AUTO_DELETE_TIMER; 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.test.TestUtils.getAgreementPublicKey; @@ -89,8 +90,8 @@ public class MessageEncoderParserIntegrationTest extends BrambleTestCase { @Test public void testRequestMessageMetadata() throws FormatException { - BdfDictionary d = messageEncoder - .encodeRequestMetadata(timestamp, MIN_AUTO_DELETE_TIMER_MS); + BdfDictionary d = messageEncoder.encodeRequestMetadata(timestamp, + MIN_AUTO_DELETE_TIMER_MS); MessageMetadata meta = messageParser.parseMetadata(d); assertEquals(REQUEST, meta.getMessageType()); @@ -105,9 +106,8 @@ public class MessageEncoderParserIntegrationTest extends BrambleTestCase { @Test public void testMessageMetadata() throws FormatException { - BdfDictionary d = messageEncoder - .encodeMetadata(ABORT, sessionId, timestamp, false, true, - false, MAX_AUTO_DELETE_TIMER_MS); + BdfDictionary d = messageEncoder.encodeMetadata(ABORT, sessionId, + timestamp, false, true, false, MAX_AUTO_DELETE_TIMER_MS); MessageMetadata meta = messageParser.parseMetadata(d); assertEquals(ABORT, meta.getMessageType()); @@ -135,6 +135,42 @@ public class MessageEncoderParserIntegrationTest extends BrambleTestCase { assertEquals(previousMsgId, rm.getPreviousMessageId()); assertEquals(author, rm.getAuthor()); assertEquals(text, rm.getText()); + assertEquals(NO_AUTO_DELETE_TIMER, rm.getAutoDeleteTimer()); + } + + @Test + public void testRequestMessageWithAutoDeleteTimer() throws FormatException { + Message m = messageEncoder.encodeRequestMessage(groupId, timestamp, + previousMsgId, author, text, MIN_AUTO_DELETE_TIMER_MS); + validator.validateMessage(m, group, clientHelper.toList(m)); + RequestMessage rm = + messageParser.parseRequestMessage(m, clientHelper.toList(m)); + + assertEquals(m.getId(), rm.getMessageId()); + assertEquals(m.getGroupId(), rm.getGroupId()); + assertEquals(m.getTimestamp(), rm.getTimestamp()); + assertEquals(previousMsgId, rm.getPreviousMessageId()); + assertEquals(author, rm.getAuthor()); + assertEquals(text, rm.getText()); + assertEquals(MIN_AUTO_DELETE_TIMER_MS, rm.getAutoDeleteTimer()); + } + + @Test + public void testRequestMessageWithoutAutoDeleteTimer() + throws FormatException { + Message m = messageEncoder.encodeRequestMessage(groupId, timestamp, + previousMsgId, author, text, NO_AUTO_DELETE_TIMER); + validator.validateMessage(m, group, clientHelper.toList(m)); + RequestMessage rm = + messageParser.parseRequestMessage(m, clientHelper.toList(m)); + + assertEquals(m.getId(), rm.getMessageId()); + assertEquals(m.getGroupId(), rm.getGroupId()); + assertEquals(m.getTimestamp(), rm.getTimestamp()); + assertEquals(previousMsgId, rm.getPreviousMessageId()); + assertEquals(author, rm.getAuthor()); + assertEquals(text, rm.getText()); + assertEquals(NO_AUTO_DELETE_TIMER, rm.getAutoDeleteTimer()); } @Test @@ -146,6 +182,7 @@ public class MessageEncoderParserIntegrationTest extends BrambleTestCase { messageParser.parseRequestMessage(m, clientHelper.toList(m)); assertNull(rm.getPreviousMessageId()); + assertEquals(NO_AUTO_DELETE_TIMER, rm.getAutoDeleteTimer()); } @Test @@ -158,6 +195,7 @@ public class MessageEncoderParserIntegrationTest extends BrambleTestCase { messageParser.parseRequestMessage(m, clientHelper.toList(m)); assertNull(rm.getText()); + assertEquals(NO_AUTO_DELETE_TIMER, rm.getAutoDeleteTimer()); } @Test @@ -183,6 +221,57 @@ public class MessageEncoderParserIntegrationTest extends BrambleTestCase { am.getEphemeralPublicKey().getEncoded()); assertEquals(acceptTimestamp, am.getAcceptTimestamp()); assertEquals(transportProperties, am.getTransportProperties()); + assertEquals(NO_AUTO_DELETE_TIMER, am.getAutoDeleteTimer()); + } + + @Test + public void testAcceptMessageWithAutoDeleteTimer() throws Exception { + Map transportProperties = + getTransportPropertiesMap(2); + + long acceptTimestamp = 1337L; + Message m = messageEncoder.encodeAcceptMessage(groupId, timestamp, + previousMsgId, sessionId, ephemeralPublicKey, + acceptTimestamp, transportProperties, MAX_AUTO_DELETE_TIMER_MS); + validator.validateMessage(m, group, clientHelper.toList(m)); + AcceptMessage am = + messageParser.parseAcceptMessage(m, clientHelper.toList(m)); + + assertEquals(m.getId(), am.getMessageId()); + assertEquals(m.getGroupId(), am.getGroupId()); + assertEquals(m.getTimestamp(), am.getTimestamp()); + assertEquals(previousMsgId, am.getPreviousMessageId()); + assertEquals(sessionId, am.getSessionId()); + assertArrayEquals(ephemeralPublicKey.getEncoded(), + am.getEphemeralPublicKey().getEncoded()); + assertEquals(acceptTimestamp, am.getAcceptTimestamp()); + assertEquals(transportProperties, am.getTransportProperties()); + assertEquals(MAX_AUTO_DELETE_TIMER_MS, am.getAutoDeleteTimer()); + } + + @Test + public void testAcceptMessageWithoutAutoDeleteTimer() throws Exception { + Map transportProperties = + getTransportPropertiesMap(2); + + long acceptTimestamp = 1337L; + Message m = messageEncoder.encodeAcceptMessage(groupId, timestamp, + previousMsgId, sessionId, ephemeralPublicKey, + acceptTimestamp, transportProperties, NO_AUTO_DELETE_TIMER); + validator.validateMessage(m, group, clientHelper.toList(m)); + AcceptMessage am = + messageParser.parseAcceptMessage(m, clientHelper.toList(m)); + + assertEquals(m.getId(), am.getMessageId()); + assertEquals(m.getGroupId(), am.getGroupId()); + assertEquals(m.getTimestamp(), am.getTimestamp()); + assertEquals(previousMsgId, am.getPreviousMessageId()); + assertEquals(sessionId, am.getSessionId()); + assertArrayEquals(ephemeralPublicKey.getEncoded(), + am.getEphemeralPublicKey().getEncoded()); + assertEquals(acceptTimestamp, am.getAcceptTimestamp()); + assertEquals(transportProperties, am.getTransportProperties()); + assertEquals(NO_AUTO_DELETE_TIMER, am.getAutoDeleteTimer()); } @Test @@ -199,6 +288,39 @@ public class MessageEncoderParserIntegrationTest extends BrambleTestCase { assertEquals(m.getTimestamp(), dm.getTimestamp()); assertEquals(previousMsgId, dm.getPreviousMessageId()); assertEquals(sessionId, dm.getSessionId()); + assertEquals(NO_AUTO_DELETE_TIMER, dm.getAutoDeleteTimer()); + } + + @Test + public void testDeclineMessageWithAutoDeleteTimer() throws Exception { + Message m = messageEncoder.encodeDeclineMessage(groupId, timestamp, + previousMsgId, sessionId, MIN_AUTO_DELETE_TIMER_MS); + validator.validateMessage(m, group, clientHelper.toList(m)); + DeclineMessage dm = + messageParser.parseDeclineMessage(m, clientHelper.toList(m)); + + assertEquals(m.getId(), dm.getMessageId()); + assertEquals(m.getGroupId(), dm.getGroupId()); + assertEquals(m.getTimestamp(), dm.getTimestamp()); + assertEquals(previousMsgId, dm.getPreviousMessageId()); + assertEquals(sessionId, dm.getSessionId()); + assertEquals(MIN_AUTO_DELETE_TIMER_MS, dm.getAutoDeleteTimer()); + } + + @Test + public void testDeclineMessageWithoutAutoDeleteTimer() throws Exception { + Message m = messageEncoder.encodeDeclineMessage(groupId, timestamp, + previousMsgId, sessionId, NO_AUTO_DELETE_TIMER); + validator.validateMessage(m, group, clientHelper.toList(m)); + DeclineMessage dm = + messageParser.parseDeclineMessage(m, clientHelper.toList(m)); + + assertEquals(m.getId(), dm.getMessageId()); + assertEquals(m.getGroupId(), dm.getGroupId()); + assertEquals(m.getTimestamp(), dm.getTimestamp()); + assertEquals(previousMsgId, dm.getPreviousMessageId()); + assertEquals(sessionId, dm.getSessionId()); + assertEquals(NO_AUTO_DELETE_TIMER, dm.getAutoDeleteTimer()); } @Test @@ -217,6 +339,7 @@ public class MessageEncoderParserIntegrationTest extends BrambleTestCase { assertEquals(sessionId, am.getSessionId()); assertArrayEquals(mac, am.getMac()); assertArrayEquals(signature, am.getSignature()); + assertEquals(NO_AUTO_DELETE_TIMER, am.getAutoDeleteTimer()); } @Test @@ -234,6 +357,7 @@ public class MessageEncoderParserIntegrationTest extends BrambleTestCase { assertEquals(previousMsgId, am.getPreviousMessageId()); assertEquals(sessionId, am.getSessionId()); assertArrayEquals(mac, am.getMac()); + assertEquals(NO_AUTO_DELETE_TIMER, am.getAutoDeleteTimer()); } @Test @@ -250,5 +374,6 @@ public class MessageEncoderParserIntegrationTest extends BrambleTestCase { assertEquals(m.getTimestamp(), am.getTimestamp()); assertEquals(previousMsgId, am.getPreviousMessageId()); assertEquals(sessionId, am.getSessionId()); + assertEquals(NO_AUTO_DELETE_TIMER, am.getAutoDeleteTimer()); } } diff --git a/briar-headless/src/test/java/org/briarproject/briar/headless/event/WebSocketControllerTest.kt b/briar-headless/src/test/java/org/briarproject/briar/headless/event/WebSocketControllerTest.kt index 3a9be9b39..58d9e48d0 100644 --- a/briar-headless/src/test/java/org/briarproject/briar/headless/event/WebSocketControllerTest.kt +++ b/briar-headless/src/test/java/org/briarproject/briar/headless/event/WebSocketControllerTest.kt @@ -97,7 +97,8 @@ internal class WebSocketControllerTest : ControllerTest() { author, text, false, - AuthorInfo(VERIFIED) + AuthorInfo(VERIFIED), + NO_AUTO_DELETE_TIMER ) val introductionRequestEvent = IntroductionRequestReceivedEvent(introductionRequest, contact.id) diff --git a/briar-headless/src/test/java/org/briarproject/briar/headless/messaging/MessagingControllerImplTest.kt b/briar-headless/src/test/java/org/briarproject/briar/headless/messaging/MessagingControllerImplTest.kt index 58685c6e4..91441efdf 100644 --- a/briar-headless/src/test/java/org/briarproject/briar/headless/messaging/MessagingControllerImplTest.kt +++ b/briar-headless/src/test/java/org/briarproject/briar/headless/messaging/MessagingControllerImplTest.kt @@ -89,7 +89,7 @@ internal class MessagingControllerImplTest : ControllerTest() { fun listIntroductionRequest() { val request = IntroductionRequest( message.id, group.id, timestamp, true, true, true, false, sessionId, author, text, - false, AuthorInfo(UNVERIFIED) + false, AuthorInfo(UNVERIFIED), NO_AUTO_DELETE_TIMER ) expectGetContact() @@ -330,7 +330,7 @@ internal class MessagingControllerImplTest : ControllerTest() { fun testIntroductionRequestWithNullText() { val request = IntroductionRequest( message.id, group.id, timestamp, true, true, true, false, sessionId, author, null, - false, AuthorInfo(VERIFIED) + false, AuthorInfo(VERIFIED), NO_AUTO_DELETE_TIMER ) val json = """ {