From 28cd086972745f450fbe32e813262a725e820dc6 Mon Sep 17 00:00:00 2001 From: akwizgran Date: Thu, 19 Nov 2020 15:35:13 +0000 Subject: [PATCH 1/2] Update introduction validator to support auto-delete timers. --- .../bramble/util/ValidationUtils.java | 5 + .../api/introduction/IntroductionManager.java | 2 +- .../introduction/AbstractProtocolEngine.java | 14 +- .../introduction/IntroductionConstants.java | 1 + .../introduction/IntroductionValidator.java | 83 ++++++- .../briar/introduction/MessageEncoder.java | 5 +- .../introduction/MessageEncoderImpl.java | 14 +- .../briar/introduction/MessageMetadata.java | 8 +- .../briar/introduction/MessageParserImpl.java | 5 +- .../messaging/PrivateMessageValidator.java | 9 +- .../IntroductionValidatorTest.java | 231 ++++++++++++++++-- .../MessageEncoderParserIntegrationTest.java | 8 +- 12 files changed, 333 insertions(+), 52 deletions(-) diff --git a/bramble-api/src/main/java/org/briarproject/bramble/util/ValidationUtils.java b/bramble-api/src/main/java/org/briarproject/bramble/util/ValidationUtils.java index fffacae0c..1bb56a799 100644 --- a/bramble-api/src/main/java/org/briarproject/bramble/util/ValidationUtils.java +++ b/bramble-api/src/main/java/org/briarproject/bramble/util/ValidationUtils.java @@ -64,4 +64,9 @@ public class ValidationUtils { if (dictionary != null && dictionary.size() != size) throw new FormatException(); } + + public static void checkRange(@Nullable Long l, long min, long max) + throws FormatException { + if (l != null && (l < min || l > max)) throw new FormatException(); + } } diff --git a/briar-api/src/main/java/org/briarproject/briar/api/introduction/IntroductionManager.java b/briar-api/src/main/java/org/briarproject/briar/api/introduction/IntroductionManager.java index 49994c4b7..8eef68eea 100644 --- a/briar-api/src/main/java/org/briarproject/briar/api/introduction/IntroductionManager.java +++ b/briar-api/src/main/java/org/briarproject/briar/api/introduction/IntroductionManager.java @@ -31,7 +31,7 @@ public interface IntroductionManager extends ConversationClient { /** * The current minor version of the introduction client. */ - int MINOR_VERSION = 0; + int MINOR_VERSION = 1; /** * Sends two initial introduction messages. 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 b84f62463..fbb6be81b 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 @@ -30,6 +30,7 @@ import java.util.Map; 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.introduction.MessageType.ABORT; import static org.briarproject.briar.introduction.MessageType.ACCEPT; import static org.briarproject.briar.introduction.MessageType.ACTIVATE; @@ -39,7 +40,7 @@ import static org.briarproject.briar.introduction.MessageType.REQUEST; @Immutable @NotNullByDefault -abstract class AbstractProtocolEngine +abstract class AbstractProtocolEngine> implements ProtocolEngine { protected final DatabaseComponent db; @@ -136,9 +137,11 @@ abstract class AbstractProtocolEngine 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); + visibleInConversation, NO_AUTO_DELETE_TIMER); try { clientHelper.addLocalMessage(txn, m, meta, true, false); } catch (FormatException e) { @@ -146,9 +149,10 @@ abstract class AbstractProtocolEngine } } - void broadcastIntroductionResponseReceivedEvent(Transaction txn, Session s, - AuthorId sender, Author otherAuthor, AbstractIntroductionMessage m, - boolean canSucceed) throws DbException { + void broadcastIntroductionResponseReceivedEvent(Transaction txn, + Session s, AuthorId sender, Author otherAuthor, + AbstractIntroductionMessage m, boolean canSucceed) + throws DbException { AuthorId localAuthorId = identityManager.getLocalAuthor(txn).getId(); Contact c = contactManager.getContact(txn, sender, localAuthorId); AuthorInfo otherAuthorInfo = diff --git a/briar-core/src/main/java/org/briarproject/briar/introduction/IntroductionConstants.java b/briar-core/src/main/java/org/briarproject/briar/introduction/IntroductionConstants.java index 522759a55..16a09e93e 100644 --- a/briar-core/src/main/java/org/briarproject/briar/introduction/IntroductionConstants.java +++ b/briar-core/src/main/java/org/briarproject/briar/introduction/IntroductionConstants.java @@ -12,6 +12,7 @@ interface IntroductionConstants { String MSG_KEY_LOCAL = "local"; String MSG_KEY_VISIBLE_IN_UI = "visibleInUi"; String MSG_KEY_AVAILABLE_TO_ANSWER = "availableToAnswer"; + String MSG_KEY_AUTO_DELETE_TIMER = "autoDeleteTimer"; // Session Keys String SESSION_KEY_SESSION_ID = "sessionId"; 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 a4ac7a45d..7b78cbf47 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 @@ -18,10 +18,14 @@ import org.briarproject.briar.api.client.SessionId; import javax.annotation.concurrent.Immutable; import static java.util.Collections.singletonList; +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.api.identity.AuthorConstants.MAX_PUBLIC_KEY_LENGTH; import static org.briarproject.bramble.util.ValidationUtils.checkLength; +import static org.briarproject.bramble.util.ValidationUtils.checkRange; import static org.briarproject.bramble.util.ValidationUtils.checkSize; import static org.briarproject.briar.api.introduction.IntroductionConstants.MAX_INTRODUCTION_TEXT_LENGTH; import static org.briarproject.briar.introduction.MessageType.ACCEPT; @@ -52,13 +56,14 @@ class IntroductionValidator extends BdfMessageValidator { return validateRequestMessage(m, body); case ACCEPT: return validateAcceptMessage(m, body); + case DECLINE: + return validateDeclineMessage(type, m, body); case AUTH: return validateAuthMessage(m, body); case ACTIVATE: return validateActivateMessage(m, body); - case DECLINE: case ABORT: - return validateOtherMessage(type, m, body); + return validateAbortMessage(type, m, body); default: throw new FormatException(); } @@ -66,7 +71,11 @@ class IntroductionValidator extends BdfMessageValidator { private BdfMessageContext validateRequestMessage(Message m, BdfList body) throws FormatException { - checkSize(body, 4); + // Client version 0.0: Message type, optional previous message ID, + // author, optional text. + // Client version 0.1: Message type, optional previous message ID, + // author, optional text, optional auto-delete timer. + checkSize(body, 4, 5); byte[] previousMessageId = body.getOptionalRaw(1); checkLength(previousMessageId, UniqueId.LENGTH); @@ -77,8 +86,16 @@ 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; + BdfDictionary meta = - messageEncoder.encodeRequestMetadata(m.getTimestamp()); + messageEncoder.encodeRequestMetadata(m.getTimestamp(), timer); if (previousMessageId == null) { return new BdfMessageContext(meta); } else { @@ -89,7 +106,12 @@ class IntroductionValidator extends BdfMessageValidator { private BdfMessageContext validateAcceptMessage(Message m, BdfList body) throws FormatException { - checkSize(body, 6); + // Client version 0.0: Message type, session ID, optional previous + // message ID, ephemeral public key, timestamp, transport properties. + // Client version 0.1: Message type, session ID, optional previous + // message ID, ephemeral public key, timestamp, transport properties, + // optional auto-delete timer. + checkSize(body, 6, 7); byte[] sessionIdBytes = body.getRaw(1); checkLength(sessionIdBytes, UniqueId.LENGTH); @@ -109,9 +131,50 @@ 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; + SessionId sessionId = new SessionId(sessionIdBytes); BdfDictionary meta = messageEncoder.encodeMetadata(ACCEPT, sessionId, - m.getTimestamp(), false, false, false); + m.getTimestamp(), false, false, false, timer); + if (previousMessageId == null) { + return new BdfMessageContext(meta); + } else { + MessageId dependency = new MessageId(previousMessageId); + return new BdfMessageContext(meta, singletonList(dependency)); + } + } + + private BdfMessageContext validateDeclineMessage(MessageType type, + Message m, BdfList body) throws FormatException { + // Client version 0.0: Message type, session ID, optional previous + // message ID. + // Client version 0.1: Message type, session ID, optional previous + // message ID, optional auto-delete timer. + checkSize(body, 3, 4); + + byte[] sessionIdBytes = body.getRaw(1); + checkLength(sessionIdBytes, UniqueId.LENGTH); + + 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; + + SessionId sessionId = new SessionId(sessionIdBytes); + BdfDictionary meta = messageEncoder.encodeMetadata(type, sessionId, + m.getTimestamp(), false, false, false, timer); if (previousMessageId == null) { return new BdfMessageContext(meta); } else { @@ -138,7 +201,7 @@ class IntroductionValidator extends BdfMessageValidator { SessionId sessionId = new SessionId(sessionIdBytes); BdfDictionary meta = messageEncoder.encodeMetadata(AUTH, sessionId, - m.getTimestamp(), false, false, false); + m.getTimestamp(), false, false, false, NO_AUTO_DELETE_TIMER); MessageId dependency = new MessageId(previousMessageId); return new BdfMessageContext(meta, singletonList(dependency)); } @@ -158,7 +221,7 @@ class IntroductionValidator extends BdfMessageValidator { SessionId sessionId = new SessionId(sessionIdBytes); BdfDictionary meta = messageEncoder.encodeMetadata(ACTIVATE, sessionId, - m.getTimestamp(), false, false, false); + m.getTimestamp(), false, false, false, NO_AUTO_DELETE_TIMER); if (previousMessageId == null) { return new BdfMessageContext(meta); } else { @@ -167,7 +230,7 @@ class IntroductionValidator extends BdfMessageValidator { } } - private BdfMessageContext validateOtherMessage(MessageType type, + private BdfMessageContext validateAbortMessage(MessageType type, Message m, BdfList body) throws FormatException { checkSize(body, 3); @@ -179,7 +242,7 @@ class IntroductionValidator extends BdfMessageValidator { SessionId sessionId = new SessionId(sessionIdBytes); BdfDictionary meta = messageEncoder.encodeMetadata(type, sessionId, - m.getTimestamp(), false, false, false); + m.getTimestamp(), false, false, false, NO_AUTO_DELETE_TIMER); if (previousMessageId == null) { return new BdfMessageContext(meta); } else { 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 38a4841ea..2357f7277 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 @@ -18,11 +18,12 @@ import javax.annotation.Nullable; @NotNullByDefault interface MessageEncoder { - BdfDictionary encodeRequestMetadata(long timestamp); + BdfDictionary encodeRequestMetadata(long timestamp, + long autoDeleteTimer); BdfDictionary encodeMetadata(MessageType type, @Nullable SessionId sessionId, long timestamp, boolean local, - boolean read, boolean visible); + boolean read, boolean visible, long autoDeleteTimer); void addSessionId(BdfDictionary meta, SessionId sessionId); 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 e11d6ecd3..901b37cd7 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 @@ -20,7 +20,9 @@ import java.util.Map; import javax.annotation.Nullable; import javax.inject.Inject; +import static org.briarproject.bramble.api.autodelete.AutoDeleteConstants.NO_AUTO_DELETE_TIMER; import static org.briarproject.briar.client.MessageTrackerConstants.MSG_KEY_READ; +import static org.briarproject.briar.introduction.IntroductionConstants.MSG_KEY_AUTO_DELETE_TIMER; import static org.briarproject.briar.introduction.IntroductionConstants.MSG_KEY_AVAILABLE_TO_ANSWER; import static org.briarproject.briar.introduction.IntroductionConstants.MSG_KEY_LOCAL; import static org.briarproject.briar.introduction.IntroductionConstants.MSG_KEY_MESSAGE_TYPE; @@ -48,9 +50,10 @@ class MessageEncoderImpl implements MessageEncoder { } @Override - public BdfDictionary encodeRequestMetadata(long timestamp) { - BdfDictionary meta = - encodeMetadata(REQUEST, null, timestamp, false, false, false); + public BdfDictionary encodeRequestMetadata(long timestamp, + long autoDeleteTimer) { + BdfDictionary meta = encodeMetadata(REQUEST, null, timestamp, + false, false, false, autoDeleteTimer); meta.put(MSG_KEY_AVAILABLE_TO_ANSWER, false); return meta; } @@ -58,7 +61,7 @@ class MessageEncoderImpl implements MessageEncoder { @Override public BdfDictionary encodeMetadata(MessageType type, @Nullable SessionId sessionId, long timestamp, boolean local, - boolean read, boolean visible) { + boolean read, boolean visible, long autoDeleteTimer) { BdfDictionary meta = new BdfDictionary(); meta.put(MSG_KEY_MESSAGE_TYPE, type.getValue()); if (sessionId != null) @@ -69,6 +72,9 @@ class MessageEncoderImpl implements MessageEncoder { meta.put(MSG_KEY_LOCAL, local); meta.put(MSG_KEY_READ, read); meta.put(MSG_KEY_VISIBLE_IN_UI, visible); + if (autoDeleteTimer != NO_AUTO_DELETE_TIMER) { + meta.put(MSG_KEY_AUTO_DELETE_TIMER, autoDeleteTimer); + } return meta; } diff --git a/briar-core/src/main/java/org/briarproject/briar/introduction/MessageMetadata.java b/briar-core/src/main/java/org/briarproject/briar/introduction/MessageMetadata.java index 102d72bfc..2ae4e8daa 100644 --- a/briar-core/src/main/java/org/briarproject/briar/introduction/MessageMetadata.java +++ b/briar-core/src/main/java/org/briarproject/briar/introduction/MessageMetadata.java @@ -13,12 +13,12 @@ class MessageMetadata { private final MessageType type; @Nullable private final SessionId sessionId; - private final long timestamp; + private final long timestamp, autoDeleteTimer; private final boolean local, read, visible, available; MessageMetadata(MessageType type, @Nullable SessionId sessionId, long timestamp, boolean local, boolean read, boolean visible, - boolean available) { + boolean available, long autoDeleteTimer) { this.type = type; this.sessionId = sessionId; this.timestamp = timestamp; @@ -26,6 +26,7 @@ class MessageMetadata { this.read = read; this.visible = visible; this.available = available; + this.autoDeleteTimer = autoDeleteTimer; } MessageType getMessageType() { @@ -57,4 +58,7 @@ class MessageMetadata { return available; } + public long getAutoDeleteTimer() { + return 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 fb727c0b4..1e6808c06 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 @@ -19,7 +19,9 @@ import java.util.Map; import javax.inject.Inject; +import static org.briarproject.bramble.api.autodelete.AutoDeleteConstants.NO_AUTO_DELETE_TIMER; import static org.briarproject.briar.client.MessageTrackerConstants.MSG_KEY_READ; +import static org.briarproject.briar.introduction.IntroductionConstants.MSG_KEY_AUTO_DELETE_TIMER; import static org.briarproject.briar.introduction.IntroductionConstants.MSG_KEY_AVAILABLE_TO_ANSWER; import static org.briarproject.briar.introduction.IntroductionConstants.MSG_KEY_LOCAL; import static org.briarproject.briar.introduction.IntroductionConstants.MSG_KEY_MESSAGE_TYPE; @@ -65,8 +67,9 @@ class MessageParserImpl implements MessageParser { boolean read = d.getBoolean(MSG_KEY_READ); boolean visible = d.getBoolean(MSG_KEY_VISIBLE_IN_UI); boolean available = d.getBoolean(MSG_KEY_AVAILABLE_TO_ANSWER, false); + long timer = d.getLong(MSG_KEY_AUTO_DELETE_TIMER, NO_AUTO_DELETE_TIMER); return new MessageMetadata(type, sessionId, timestamp, local, read, - visible, available); + visible, available, timer); } @Override diff --git a/briar-core/src/main/java/org/briarproject/briar/messaging/PrivateMessageValidator.java b/briar-core/src/main/java/org/briarproject/briar/messaging/PrivateMessageValidator.java index 692dd580d..75a9ad8fd 100644 --- a/briar-core/src/main/java/org/briarproject/briar/messaging/PrivateMessageValidator.java +++ b/briar-core/src/main/java/org/briarproject/briar/messaging/PrivateMessageValidator.java @@ -28,6 +28,7 @@ import static org.briarproject.bramble.api.autodelete.AutoDeleteConstants.MIN_AU import static org.briarproject.bramble.api.sync.SyncConstants.MAX_MESSAGE_BODY_LENGTH; import static org.briarproject.bramble.api.transport.TransportConstants.MAX_CLOCK_DIFFERENCE; import static org.briarproject.bramble.util.ValidationUtils.checkLength; +import static org.briarproject.bramble.util.ValidationUtils.checkRange; import static org.briarproject.bramble.util.ValidationUtils.checkSize; import static org.briarproject.briar.api.messaging.MessagingConstants.MAX_ATTACHMENTS_PER_MESSAGE; import static org.briarproject.briar.api.messaging.MessagingConstants.MAX_CONTENT_TYPE_BYTES; @@ -136,10 +137,10 @@ class PrivateMessageValidator implements MessageValidator { checkLength(contentType, 1, MAX_CONTENT_TYPE_BYTES); } Long timer = null; - if (body.size() == 4) timer = body.getOptionalLong(3); - if (timer != null && (timer < MIN_AUTO_DELETE_TIMER_MS || - timer > MAX_AUTO_DELETE_TIMER_MS)) { - throw new FormatException(); + if (body.size() == 4) { + timer = body.getOptionalLong(3); + checkRange(timer, MIN_AUTO_DELETE_TIMER_MS, + MAX_AUTO_DELETE_TIMER_MS); } // Return the metadata BdfDictionary meta = new BdfDictionary(); diff --git a/briar-core/src/test/java/org/briarproject/briar/introduction/IntroductionValidatorTest.java b/briar-core/src/test/java/org/briarproject/briar/introduction/IntroductionValidatorTest.java index 249ba8852..7cd82468a 100644 --- a/briar-core/src/test/java/org/briarproject/briar/introduction/IntroductionValidatorTest.java +++ b/briar-core/src/test/java/org/briarproject/briar/introduction/IntroductionValidatorTest.java @@ -6,20 +6,29 @@ import org.briarproject.bramble.api.crypto.PublicKey; import org.briarproject.bramble.api.data.BdfDictionary; import org.briarproject.bramble.api.data.BdfEntry; import org.briarproject.bramble.api.data.BdfList; +import org.briarproject.bramble.api.plugin.TransportId; +import org.briarproject.bramble.api.properties.TransportProperties; import org.briarproject.bramble.api.sync.MessageId; import org.briarproject.bramble.test.ValidatorTestCase; import org.briarproject.briar.api.client.SessionId; import org.jmock.Expectations; import org.junit.Test; +import java.util.Map; + import javax.annotation.Nullable; +import static java.util.Collections.singletonMap; +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_AGREEMENT_PUBLIC_KEY_BYTES; import static org.briarproject.bramble.api.crypto.CryptoConstants.MAX_SIGNATURE_BYTES; import static org.briarproject.bramble.test.TestUtils.getAgreementPublicKey; 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.util.StringUtils.getRandomString; import static org.briarproject.briar.api.introduction.IntroductionConstants.MAX_INTRODUCTION_TEXT_LENGTH; import static org.briarproject.briar.introduction.MessageType.ABORT; @@ -44,9 +53,12 @@ public class IntroductionValidatorTest extends ValidatorTestCase { private final BdfDictionary meta = new BdfDictionary(); private final PublicKey ephemeralPublicKey = getAgreementPublicKey(); private final long acceptTimestamp = 42; + private final TransportId transportId = getTransportId(); private final BdfDictionary transportProperties = BdfDictionary.of( - new BdfEntry("transportId", new BdfDictionary()) + new BdfEntry(transportId.getString(), new BdfDictionary()) ); + private final Map transportPropertiesMap = + singletonMap(transportId, new TransportProperties()); private final byte[] mac = getRandomBytes(MAC_BYTES); private final byte[] signature = getRandomBytes(MAX_SIGNATURE_BYTES); @@ -60,7 +72,7 @@ public class IntroductionValidatorTest extends ValidatorTestCase { authorList, text); expectParseAuthor(authorList, author); - expectEncodeRequestMetadata(); + expectEncodeRequestMetadata(NO_AUTO_DELETE_TIMER); BdfMessageContext messageContext = validator.validateMessage(message, group, body); @@ -72,7 +84,7 @@ public class IntroductionValidatorTest extends ValidatorTestCase { BdfList body = BdfList.of(REQUEST.getValue(), null, authorList, text); expectParseAuthor(authorList, author); - expectEncodeRequestMetadata(); + expectEncodeRequestMetadata(NO_AUTO_DELETE_TIMER); BdfMessageContext messageContext = validator.validateMessage(message, group, body); @@ -84,13 +96,42 @@ public class IntroductionValidatorTest extends ValidatorTestCase { BdfList body = BdfList.of(REQUEST.getValue(), null, authorList, null); expectParseAuthor(authorList, author); - expectEncodeRequestMetadata(); + expectEncodeRequestMetadata(NO_AUTO_DELETE_TIMER); BdfMessageContext messageContext = validator.validateMessage(message, group, body); assertExpectedContext(messageContext, null); } + @Test + public void testAcceptsRequestWithNullAutoDeleteTimer() throws Exception { + testAcceptsRequestWithAutoDeleteTimer(null); + } + + @Test + public void testAcceptsRequestWithMinAutoDeleteTimer() throws Exception { + testAcceptsRequestWithAutoDeleteTimer(MIN_AUTO_DELETE_TIMER_MS); + } + + @Test + public void testAcceptsRequestWithMaxAutoDeleteTimer() throws Exception { + testAcceptsRequestWithAutoDeleteTimer(MAX_AUTO_DELETE_TIMER_MS); + } + + private void testAcceptsRequestWithAutoDeleteTimer(@Nullable Long timer) + throws Exception { + BdfList body = BdfList.of(REQUEST.getValue(), previousMsgId.getBytes(), + authorList, text, timer); + + expectParseAuthor(authorList, author); + long autoDeleteTimer = timer == null ? NO_AUTO_DELETE_TIMER : timer; + expectEncodeRequestMetadata(autoDeleteTimer); + BdfMessageContext messageContext = + validator.validateMessage(message, group, body); + + assertExpectedContext(messageContext, previousMsgId); + } + @Test(expected = FormatException.class) public void testRejectsTooShortBodyForRequest() throws Exception { BdfList body = BdfList.of(REQUEST.getValue(), null, authorList); @@ -99,8 +140,8 @@ public class IntroductionValidatorTest extends ValidatorTestCase { @Test(expected = FormatException.class) public void testRejectsTooLongBodyForRequest() throws Exception { - BdfList body = - BdfList.of(REQUEST.getValue(), null, authorList, text, null); + BdfList body = BdfList.of(REQUEST.getValue(), null, authorList, text, + null, null); validator.validateMessage(message, group, body); } @@ -119,6 +160,32 @@ public class IntroductionValidatorTest extends ValidatorTestCase { validator.validateMessage(message, group, body); } + @Test(expected = FormatException.class) + public void testRejectsRequestWithNonLongAutoDeleteTimer() + throws Exception { + BdfList body = BdfList.of(REQUEST.getValue(), previousMsgId.getBytes(), + authorList, text, "foo"); + expectParseAuthor(authorList, author); + validator.validateMessage(message, group, body); + } + + @Test(expected = FormatException.class) + public void testRejectsRequestWithTooSmallAutoDeleteTimer() + throws Exception { + BdfList body = BdfList.of(REQUEST.getValue(), previousMsgId.getBytes(), + authorList, text, MIN_AUTO_DELETE_TIMER_MS - 1); + expectParseAuthor(authorList, author); + validator.validateMessage(message, group, body); + } + + @Test(expected = FormatException.class) + public void testRejectsRequestWithTooBigAutoDeleteTimer() throws Exception { + BdfList body = BdfList.of(REQUEST.getValue(), previousMsgId.getBytes(), + authorList, text, MAX_AUTO_DELETE_TIMER_MS + 1); + expectParseAuthor(authorList, author); + validator.validateMessage(message, group, body); + } + // // Introduction ACCEPT // @@ -129,11 +196,38 @@ public class IntroductionValidatorTest extends ValidatorTestCase { previousMsgId.getBytes(), ephemeralPublicKey.getEncoded(), acceptTimestamp, transportProperties); expectParsePublicKey(); - context.checking(new Expectations() {{ - oneOf(clientHelper).parseAndValidateTransportPropertiesMap( - transportProperties); - }}); - expectEncodeMetadata(ACCEPT); + expectParseTransportProperties(); + expectEncodeMetadata(ACCEPT, NO_AUTO_DELETE_TIMER); + BdfMessageContext messageContext = + validator.validateMessage(message, group, body); + + assertExpectedContext(messageContext, previousMsgId); + } + + @Test + public void testAcceptsAcceptWithNullAutoDeleteTimer() throws Exception { + testAcceptsAcceptWithAutoDeleteTimer(null); + } + + @Test + public void testAcceptsAcceptWithMinAutoDeleteTimer() throws Exception { + testAcceptsAcceptWithAutoDeleteTimer(MIN_AUTO_DELETE_TIMER_MS); + } + + @Test + public void testAcceptsAcceptWithMaxAutoDeleteTimer() throws Exception { + testAcceptsAcceptWithAutoDeleteTimer(MAX_AUTO_DELETE_TIMER_MS); + } + + private void testAcceptsAcceptWithAutoDeleteTimer(@Nullable Long timer) + throws Exception { + BdfList body = BdfList.of(ACCEPT.getValue(), sessionId.getBytes(), + previousMsgId.getBytes(), ephemeralPublicKey.getEncoded(), + acceptTimestamp, transportProperties, timer); + expectParsePublicKey(); + expectParseTransportProperties(); + long autoDeleteTimer = timer == null ? NO_AUTO_DELETE_TIMER : timer; + expectEncodeMetadata(ACCEPT, autoDeleteTimer); BdfMessageContext messageContext = validator.validateMessage(message, group, body); @@ -152,7 +246,7 @@ public class IntroductionValidatorTest extends ValidatorTestCase { public void testRejectsTooLongBodyForAccept() throws Exception { BdfList body = BdfList.of(ACCEPT.getValue(), sessionId.getBytes(), previousMsgId.getBytes(), ephemeralPublicKey.getEncoded(), - acceptTimestamp, transportProperties, null); + acceptTimestamp, transportProperties, null, null); validator.validateMessage(message, group, body); } @@ -200,6 +294,40 @@ public class IntroductionValidatorTest extends ValidatorTestCase { validator.validateMessage(message, group, body); } + @Test(expected = FormatException.class) + public void testRejectsAcceptWithNonLongAutoDeleteTimer() + throws Exception { + BdfList body = BdfList.of(ACCEPT.getValue(), sessionId.getBytes(), + previousMsgId.getBytes(), ephemeralPublicKey.getEncoded(), + acceptTimestamp, transportProperties, "foo"); + expectParsePublicKey(); + expectParseTransportProperties(); + validator.validateMessage(message, group, body); + } + + @Test(expected = FormatException.class) + public void testRejectsAcceptWithTooSmallAutoDeleteTimer() + throws Exception { + BdfList body = BdfList.of(ACCEPT.getValue(), sessionId.getBytes(), + previousMsgId.getBytes(), ephemeralPublicKey.getEncoded(), + acceptTimestamp, transportProperties, + MIN_AUTO_DELETE_TIMER_MS - 1); + expectParsePublicKey(); + expectParseTransportProperties(); + validator.validateMessage(message, group, body); + } + + @Test(expected = FormatException.class) + public void testRejectsAcceptWithTooBigAutoDeleteTimer() throws Exception { + BdfList body = BdfList.of(ACCEPT.getValue(), sessionId.getBytes(), + previousMsgId.getBytes(), ephemeralPublicKey.getEncoded(), + acceptTimestamp, transportProperties, + MAX_AUTO_DELETE_TIMER_MS + 1); + expectParsePublicKey(); + expectParseTransportProperties(); + validator.validateMessage(message, group, body); + } + // // Introduction DECLINE // @@ -209,7 +337,35 @@ public class IntroductionValidatorTest extends ValidatorTestCase { BdfList body = BdfList.of(DECLINE.getValue(), sessionId.getBytes(), previousMsgId.getBytes()); - expectEncodeMetadata(DECLINE); + expectEncodeMetadata(DECLINE, NO_AUTO_DELETE_TIMER); + BdfMessageContext messageContext = + validator.validateMessage(message, group, body); + + assertExpectedContext(messageContext, previousMsgId); + } + + @Test + public void testAcceptsDeclineWithNullAutoDeleteTimer() throws Exception { + testAcceptsDeclineWithAutoDeleteTimer(null); + } + + @Test + public void testAcceptsDeclineWithMinAutoDeleteTimer() throws Exception { + testAcceptsDeclineWithAutoDeleteTimer(MIN_AUTO_DELETE_TIMER_MS); + } + + @Test + public void testAcceptsDeclineWithMaxAutoDeleteTimer() throws Exception { + testAcceptsDeclineWithAutoDeleteTimer(MAX_AUTO_DELETE_TIMER_MS); + } + + private void testAcceptsDeclineWithAutoDeleteTimer(@Nullable Long timer) + throws Exception { + BdfList body = BdfList.of(DECLINE.getValue(), sessionId.getBytes(), + previousMsgId.getBytes(), timer); + + long autoDeleteTimer = timer == null ? NO_AUTO_DELETE_TIMER : timer; + expectEncodeMetadata(DECLINE, autoDeleteTimer); BdfMessageContext messageContext = validator.validateMessage(message, group, body); @@ -225,7 +381,7 @@ public class IntroductionValidatorTest extends ValidatorTestCase { @Test(expected = FormatException.class) public void testRejectsTooLongBodyForDecline() throws Exception { BdfList body = BdfList.of(DECLINE.getValue(), sessionId.getBytes(), - previousMsgId.getBytes(), null); + previousMsgId.getBytes(), null, null); validator.validateMessage(message, group, body); } @@ -242,6 +398,28 @@ public class IntroductionValidatorTest extends ValidatorTestCase { validator.validateMessage(message, group, body); } + @Test(expected = FormatException.class) + public void testRejectsNonLongAutoDeleteTimerForDecline() throws Exception { + BdfList body = BdfList.of(DECLINE.getValue(), sessionId.getBytes(), + previousMsgId.getBytes(), "foo"); + validator.validateMessage(message, group, body); + } + + @Test(expected = FormatException.class) + public void testRejectsTooSmallAutoDeleteTimerForDecline() + throws Exception { + BdfList body = BdfList.of(DECLINE.getValue(), sessionId.getBytes(), + previousMsgId.getBytes(), MIN_AUTO_DELETE_TIMER_MS - 1); + validator.validateMessage(message, group, body); + } + + @Test(expected = FormatException.class) + public void testRejectsTooBigAutoDeleteTimerForDecline() throws Exception { + BdfList body = BdfList.of(DECLINE.getValue(), sessionId.getBytes(), + previousMsgId.getBytes(), MAX_AUTO_DELETE_TIMER_MS + 1); + validator.validateMessage(message, group, body); + } + // // Introduction AUTH // @@ -251,7 +429,7 @@ public class IntroductionValidatorTest extends ValidatorTestCase { BdfList body = BdfList.of(AUTH.getValue(), sessionId.getBytes(), previousMsgId.getBytes(), mac, signature); - expectEncodeMetadata(AUTH); + expectEncodeMetadata(AUTH, NO_AUTO_DELETE_TIMER); BdfMessageContext messageContext = validator.validateMessage(message, group, body); @@ -340,7 +518,7 @@ public class IntroductionValidatorTest extends ValidatorTestCase { BdfList body = BdfList.of(ACTIVATE.getValue(), sessionId.getBytes(), previousMsgId.getBytes(), mac); - expectEncodeMetadata(ACTIVATE); + expectEncodeMetadata(ACTIVATE, NO_AUTO_DELETE_TIMER); BdfMessageContext messageContext = validator.validateMessage(message, group, body); @@ -398,7 +576,7 @@ public class IntroductionValidatorTest extends ValidatorTestCase { BdfList body = BdfList.of(ABORT.getValue(), sessionId.getBytes(), previousMsgId.getBytes()); - expectEncodeMetadata(ABORT); + expectEncodeMetadata(ABORT, NO_AUTO_DELETE_TIMER); BdfMessageContext messageContext = validator.validateMessage(message, group, body); @@ -442,17 +620,28 @@ public class IntroductionValidatorTest extends ValidatorTestCase { will(returnValue(ephemeralPublicKey)); }}); } - private void expectEncodeRequestMetadata() { + + private void expectParseTransportProperties() throws Exception { context.checking(new Expectations() {{ - oneOf(messageEncoder).encodeRequestMetadata(message.getTimestamp()); + oneOf(clientHelper).parseAndValidateTransportPropertiesMap( + transportProperties); + will(returnValue(transportPropertiesMap)); + }}); + } + + private void expectEncodeRequestMetadata(long autoDeleteTimer) { + context.checking(new Expectations() {{ + oneOf(messageEncoder).encodeRequestMetadata(message.getTimestamp(), + autoDeleteTimer); will(returnValue(meta)); }}); } - private void expectEncodeMetadata(MessageType type) { + private void expectEncodeMetadata(MessageType type, long autoDeleteTimer) { context.checking(new Expectations() {{ oneOf(messageEncoder).encodeMetadata(type, sessionId, - message.getTimestamp(), false, false, false); + message.getTimestamp(), false, false, false, + autoDeleteTimer); will(returnValue(meta)); }}); } 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 21ea8024c..6ee624333 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 @@ -23,6 +23,8 @@ import java.util.Map; 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.crypto.CryptoConstants.MAC_BYTES; import static org.briarproject.bramble.api.crypto.CryptoConstants.MAX_SIGNATURE_BYTES; import static org.briarproject.bramble.test.TestUtils.getAgreementPublicKey; @@ -88,7 +90,7 @@ public class MessageEncoderParserIntegrationTest extends BrambleTestCase { @Test public void testRequestMessageMetadata() throws FormatException { BdfDictionary d = messageEncoder - .encodeRequestMetadata(timestamp); + .encodeRequestMetadata(timestamp, MIN_AUTO_DELETE_TIMER_MS); MessageMetadata meta = messageParser.parseMetadata(d); assertEquals(REQUEST, meta.getMessageType()); @@ -98,13 +100,14 @@ public class MessageEncoderParserIntegrationTest extends BrambleTestCase { assertFalse(meta.isRead()); assertFalse(meta.isVisibleInConversation()); assertFalse(meta.isAvailableToAnswer()); + assertEquals(MIN_AUTO_DELETE_TIMER_MS, meta.getAutoDeleteTimer()); } @Test public void testMessageMetadata() throws FormatException { BdfDictionary d = messageEncoder .encodeMetadata(ABORT, sessionId, timestamp, false, true, - false); + false, MAX_AUTO_DELETE_TIMER_MS); MessageMetadata meta = messageParser.parseMetadata(d); assertEquals(ABORT, meta.getMessageType()); @@ -114,6 +117,7 @@ public class MessageEncoderParserIntegrationTest extends BrambleTestCase { assertTrue(meta.isRead()); assertFalse(meta.isVisibleInConversation()); assertFalse(meta.isAvailableToAnswer()); + assertEquals(MAX_AUTO_DELETE_TIMER_MS, meta.getAutoDeleteTimer()); } @Test From 28ecece34dcba6499d0373335baccb43a775c41d Mon Sep 17 00:00:00 2001 From: akwizgran Date: Thu, 19 Nov 2020 17:26:52 +0000 Subject: [PATCH 2/2] Update message parsing and encoding to include auto-delete timer. --- .../ConversationMessageHeader.java | 16 ++- .../api/conversation/ConversationRequest.java | 11 +- .../conversation/ConversationResponse.java | 4 +- .../api/introduction/IntroductionRequest.java | 8 +- .../introduction/IntroductionResponse.java | 5 +- .../api/messaging/PrivateMessageHeader.java | 8 +- .../briar/api/sharing/InvitationRequest.java | 4 +- .../briar/api/sharing/InvitationResponse.java | 5 +- .../briar/introduction/AbortMessage.java | 5 +- .../AbstractIntroductionMessage.java | 8 +- .../introduction/AbstractProtocolEngine.java | 105 ++++++++++---- .../briar/introduction/AcceptMessage.java | 6 +- .../briar/introduction/ActivateMessage.java | 5 +- .../briar/introduction/AuthMessage.java | 5 +- .../briar/introduction/DeclineMessage.java | 5 +- .../IntroduceeProtocolEngine.java | 8 +- .../IntroducerProtocolEngine.java | 4 +- .../introduction/IntroductionManagerImpl.java | 5 +- .../introduction/IntroductionValidator.java | 33 ++--- .../briar/introduction/MessageEncoder.java | 35 +++++ .../introduction/MessageEncoderImpl.java | 69 +++++++-- .../briar/introduction/MessageParserImpl.java | 12 +- .../briar/introduction/RequestMessage.java | 5 +- .../IntroductionIntegrationTest.java | 77 ++++++---- .../MessageEncoderParserIntegrationTest.java | 135 +++++++++++++++++- .../headless/event/WebSocketControllerTest.kt | 3 +- .../messaging/MessagingControllerImplTest.kt | 4 +- 27 files changed, 454 insertions(+), 136 deletions(-) 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 fbb341ce0..b039816d5 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 18c68c159..bda4cb44d 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 71d7d0c23..3a3eb179a 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 @@ -16,16 +16,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() { @@ -36,10 +34,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 fbb6be81b..3a9e55ebf 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; @@ -17,9 +18,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.introduction.IntroductionResponse; @@ -31,6 +34,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; @@ -51,6 +57,7 @@ abstract class AbstractProtocolEngine> protected final IdentityManager identityManager; protected final MessageParser messageParser; protected final MessageEncoder messageEncoder; + protected final ClientVersioningManager clientVersioningManager; protected final Clock clock; AbstractProtocolEngine( @@ -62,6 +69,7 @@ abstract class AbstractProtocolEngine> IdentityManager identityManager, MessageParser messageParser, MessageEncoder messageEncoder, + ClientVersioningManager clientVersioningManager, Clock clock) { this.db = db; this.clientHelper = clientHelper; @@ -71,16 +79,26 @@ abstract class AbstractProtocolEngine> this.identityManager = identityManager; 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; } @@ -88,21 +106,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; } @@ -112,7 +150,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; } @@ -121,7 +160,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; } @@ -130,18 +170,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) { @@ -161,7 +200,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); @@ -194,4 +234,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 33750f358..2ace6aa3e 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 @@ -26,6 +26,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; @@ -76,10 +77,11 @@ class IntroduceeProtocolEngine Clock clock, IntroductionCrypto crypto, KeyManager keyManager, - TransportPropertyManager transportPropertyManager) { + TransportPropertyManager transportPropertyManager, + ClientVersioningManager clientVersioningManager) { super(db, clientHelper, contactManager, contactGroupFactory, messageTracker, identityManager, messageParser, messageEncoder, - clock); + clientVersioningManager, clock); this.crypto = crypto; this.keyManager = keyManager; this.transportPropertyManager = transportPropertyManager; @@ -258,7 +260,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 fa468a939..18773c047 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.introduction.event.IntroductionAbortedEvent; @@ -50,10 +51,11 @@ class IntroducerProtocolEngine IdentityManager identityManager, MessageParser messageParser, MessageEncoder messageEncoder, + ClientVersioningManager clientVersioningManager, Clock clock) { super(db, clientHelper, contactManager, contactGroupFactory, messageTracker, identityManager, messageParser, messageEncoder, - clock); + 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 2ee085969..79452fd44 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 @@ -461,7 +461,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, @@ -499,7 +499,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 4d423305d..4f2fdc36a 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 2f1e451f3..8abf24e94 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 = """ {