Update message parsing and encoding to include auto-delete timer.

This commit is contained in:
akwizgran
2020-11-19 17:26:52 +00:00
parent 28cd086972
commit 28ecece34d
27 changed files with 454 additions and 136 deletions

View File

@@ -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;
}

View File

@@ -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;
}
}

View File

@@ -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<S extends Session<?>>
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<S extends Session<?>>
IdentityManager identityManager,
MessageParser messageParser,
MessageEncoder messageEncoder,
ClientVersioningManager clientVersioningManager,
Clock clock) {
this.db = db;
this.clientHelper = clientHelper;
@@ -71,16 +79,26 @@ abstract class AbstractProtocolEngine<S extends Session<?>>
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<S extends Session<?>>
PublicKey ephemeralPublicKey, long acceptTimestamp,
Map<TransportId, TransportProperties> 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<S extends Session<?>>
.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<S extends Session<?>>
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<S extends Session<?>>
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<S extends Session<?>>
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<S extends Session<?>>
);
}
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);
}
}
}

View File

@@ -26,8 +26,10 @@ class AcceptMessage extends AbstractIntroductionMessage {
long timestamp, @Nullable MessageId previousMessageId,
SessionId sessionId, PublicKey ephemeralPublicKey,
long acceptTimestamp,
Map<TransportId, TransportProperties> transportProperties) {
super(messageId, groupId, timestamp, previousMessageId);
Map<TransportId, TransportProperties> transportProperties,
long autoDeleteTimer) {
super(messageId, groupId, timestamp, previousMessageId,
autoDeleteTimer);
this.sessionId = sessionId;
this.ephemeralPublicKey = ephemeralPublicKey;
this.acceptTimestamp = acceptTimestamp;

View File

@@ -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;
}

View File

@@ -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;

View File

@@ -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;
}

View File

@@ -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);

View File

@@ -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

View File

@@ -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,

View File

@@ -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;
}
}

View File

@@ -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<TransportId, TransportProperties> 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<TransportId, TransportProperties> 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);

View File

@@ -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<TransportId, TransportProperties> 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;
}
}

View File

@@ -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<TransportId, TransportProperties> 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

View File

@@ -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;
}

View File

@@ -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<MessageId> 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<ConversationMessageHeader> m2From0 = getMessages2From0();
@@ -1498,7 +1517,8 @@ public class IntroductionIntegrationTest
Set<MessageId> 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<ConversationMessageHeader> 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;

View File

@@ -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<TransportId, TransportProperties> 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<TransportId, TransportProperties> 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());
}
}