From 3798ca1e174f65bacd5f693fc26c9dd294ab6900 Mon Sep 17 00:00:00 2001 From: akwizgran Date: Thu, 19 Nov 2020 15:35:13 +0000 Subject: [PATCH] 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 37b84e516..9f7d5febe 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 @@ -31,6 +31,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; @@ -40,7 +41,7 @@ import static org.briarproject.briar.introduction.MessageType.REQUEST; @Immutable @NotNullByDefault -abstract class AbstractProtocolEngine +abstract class AbstractProtocolEngine> implements ProtocolEngine { protected final DatabaseComponent db; @@ -140,9 +141,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) { @@ -150,9 +153,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 408752b88..761e27842 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 @@ -29,6 +29,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.attachment.MediaConstants.MAX_CONTENT_TYPE_BYTES; import static org.briarproject.briar.api.attachment.MediaConstants.MSG_KEY_CONTENT_TYPE; @@ -137,10 +138,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