Merge branch '1829-self-destruct-timer-introductions' into '804-self-destructing-messages'

Update introduction client to include a self-destruct timer in each message

See merge request briar/briar!1300
This commit is contained in:
akwizgran
2020-11-20 17:14:57 +00:00
33 changed files with 761 additions and 162 deletions

View File

@@ -64,4 +64,9 @@ public class ValidationUtils {
if (dictionary != null && dictionary.size() != size) if (dictionary != null && dictionary.size() != size)
throw new FormatException(); 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();
}
} }

View File

@@ -12,18 +12,20 @@ public abstract class ConversationMessageHeader {
private final MessageId id; private final MessageId id;
private final GroupId groupId; private final GroupId groupId;
private final long timestamp; private final long timestamp, autoDeleteTimer;
private final boolean local, sent, seen, read; private final boolean local, read, sent, seen;
public ConversationMessageHeader(MessageId id, GroupId groupId, long timestamp, public ConversationMessageHeader(MessageId id, GroupId groupId,
boolean local, boolean read, boolean sent, boolean seen) { long timestamp, boolean local, boolean read, boolean sent,
boolean seen, long autoDeleteTimer) {
this.id = id; this.id = id;
this.groupId = groupId; this.groupId = groupId;
this.timestamp = timestamp; this.timestamp = timestamp;
this.local = local; this.local = local;
this.read = read;
this.sent = sent; this.sent = sent;
this.seen = seen; this.seen = seen;
this.read = read; this.autoDeleteTimer = autoDeleteTimer;
} }
public MessageId getId() { public MessageId getId() {
@@ -55,4 +57,8 @@ public abstract class ConversationMessageHeader {
} }
public abstract <T> T accept(ConversationMessageVisitor<T> v); public abstract <T> T accept(ConversationMessageVisitor<T> v);
public long getAutoDeleteTimer() {
return autoDeleteTimer;
}
} }

View File

@@ -20,11 +20,12 @@ public abstract class ConversationRequest<N extends Nameable>
private final String text; private final String text;
private final boolean answered; private final boolean answered;
public ConversationRequest(MessageId messageId, GroupId groupId, long time, public ConversationRequest(MessageId messageId, GroupId groupId,
boolean local, boolean read, boolean sent, boolean seen, long timestamp, boolean local, boolean read, boolean sent,
SessionId sessionId, N nameable, @Nullable String text, boolean seen, SessionId sessionId, N nameable,
boolean answered) { @Nullable String text, boolean answered, long autoDeleteTimer) {
super(messageId, groupId, time, local, read, sent, seen); super(messageId, groupId, timestamp, local, read, sent, seen,
autoDeleteTimer);
this.sessionId = sessionId; this.sessionId = sessionId;
this.nameable = nameable; this.nameable = nameable;
this.text = text; this.text = text;

View File

@@ -16,8 +16,8 @@ public abstract class ConversationResponse extends ConversationMessageHeader {
public ConversationResponse(MessageId id, GroupId groupId, long time, public ConversationResponse(MessageId id, GroupId groupId, long time,
boolean local, boolean read, boolean sent, boolean seen, boolean local, boolean read, boolean sent, boolean seen,
SessionId sessionId, boolean accepted) { SessionId sessionId, boolean accepted, long autoDeleteTimer) {
super(id, groupId, time, local, read, sent, seen); super(id, groupId, time, local, read, sent, seen, autoDeleteTimer);
this.sessionId = sessionId; this.sessionId = sessionId;
this.accepted = accepted; this.accepted = accepted;
} }

View File

@@ -31,7 +31,7 @@ public interface IntroductionManager extends ConversationClient {
/** /**
* The current minor version of the introduction client. * The current minor version of the introduction client.
*/ */
int MINOR_VERSION = 0; int MINOR_VERSION = 1;
/** /**
* Sends two initial introduction messages. * Sends two initial introduction messages.

View File

@@ -18,12 +18,12 @@ public class IntroductionRequest extends ConversationRequest<Author> {
private final AuthorInfo authorInfo; private final AuthorInfo authorInfo;
public IntroductionRequest(MessageId messageId, GroupId groupId, public IntroductionRequest(MessageId messageId, GroupId groupId, long time,
long time, boolean local, boolean read, boolean sent, boolean seen, boolean local, boolean read, boolean sent, boolean seen,
SessionId sessionId, Author author, @Nullable String text, 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, super(messageId, groupId, time, local, read, sent, seen, sessionId,
author, text, answered); author, text, answered, autoDeleteTimer);
this.authorInfo = authorInfo; this.authorInfo = authorInfo;
} }

View File

@@ -25,9 +25,10 @@ public class IntroductionResponse extends ConversationResponse {
public IntroductionResponse(MessageId messageId, GroupId groupId, long time, public IntroductionResponse(MessageId messageId, GroupId groupId, long time,
boolean local, boolean read, boolean sent, boolean seen, boolean local, boolean read, boolean sent, boolean seen,
SessionId sessionId, boolean accepted, Author author, 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, super(messageId, groupId, time, local, read, sent, seen, sessionId,
accepted); accepted, autoDeleteTimer);
this.introducedAuthor = author; this.introducedAuthor = author;
this.introducedAuthorInfo = introducedAuthorInfo; this.introducedAuthorInfo = introducedAuthorInfo;
this.ourRole = role; this.ourRole = role;

View File

@@ -16,16 +16,14 @@ public class PrivateMessageHeader extends ConversationMessageHeader {
private final boolean hasText; private final boolean hasText;
private final List<AttachmentHeader> attachmentHeaders; private final List<AttachmentHeader> attachmentHeaders;
private final long autoDeleteTimer;
public PrivateMessageHeader(MessageId id, GroupId groupId, long timestamp, public PrivateMessageHeader(MessageId id, GroupId groupId, long timestamp,
boolean local, boolean read, boolean sent, boolean seen, boolean local, boolean read, boolean sent, boolean seen,
boolean hasText, List<AttachmentHeader> headers, boolean hasText, List<AttachmentHeader> headers,
long autoDeleteTimer) { long autoDeleteTimer) {
super(id, groupId, timestamp, local, read, sent, seen); super(id, groupId, timestamp, local, read, sent, seen, autoDeleteTimer);
this.hasText = hasText; this.hasText = hasText;
this.attachmentHeaders = headers; this.attachmentHeaders = headers;
this.autoDeleteTimer = autoDeleteTimer;
} }
public boolean hasText() { public boolean hasText() {
@@ -36,10 +34,6 @@ public class PrivateMessageHeader extends ConversationMessageHeader {
return attachmentHeaders; return attachmentHeaders;
} }
public long getAutoDeleteTimer() {
return autoDeleteTimer;
}
@Override @Override
public <T> T accept(ConversationMessageVisitor<T> v) { public <T> T accept(ConversationMessageVisitor<T> v) {
return v.visitPrivateMessageHeader(this); return v.visitPrivateMessageHeader(this);

View File

@@ -7,6 +7,8 @@ import org.briarproject.briar.api.conversation.ConversationRequest;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import static org.briarproject.bramble.api.autodelete.AutoDeleteConstants.NO_AUTO_DELETE_TIMER;
public abstract class InvitationRequest<S extends Shareable> extends public abstract class InvitationRequest<S extends Shareable> extends
ConversationRequest<S> { ConversationRequest<S> {
@@ -17,7 +19,7 @@ public abstract class InvitationRequest<S extends Shareable> extends
SessionId sessionId, S object, @Nullable String text, SessionId sessionId, S object, @Nullable String text,
boolean available, boolean canBeOpened) { boolean available, boolean canBeOpened) {
super(messageId, groupId, time, local, read, sent, seen, sessionId, super(messageId, groupId, time, local, read, sent, seen, sessionId,
object, text, !available); object, text, !available, NO_AUTO_DELETE_TIMER);
this.canBeOpened = canBeOpened; this.canBeOpened = canBeOpened;
} }

View File

@@ -5,6 +5,8 @@ import org.briarproject.bramble.api.sync.MessageId;
import org.briarproject.briar.api.client.SessionId; import org.briarproject.briar.api.client.SessionId;
import org.briarproject.briar.api.conversation.ConversationResponse; 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 { public abstract class InvitationResponse extends ConversationResponse {
private final GroupId shareableId; private final GroupId shareableId;
@@ -12,7 +14,8 @@ public abstract class InvitationResponse extends ConversationResponse {
public InvitationResponse(MessageId id, GroupId groupId, long time, public InvitationResponse(MessageId id, GroupId groupId, long time,
boolean local, boolean read, boolean sent, boolean seen, boolean local, boolean read, boolean sent, boolean seen,
SessionId sessionId, boolean accepted, GroupId shareableId) { 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; this.shareableId = shareableId;
} }

View File

@@ -8,6 +8,8 @@ import org.briarproject.briar.api.client.SessionId;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import javax.annotation.concurrent.Immutable; import javax.annotation.concurrent.Immutable;
import static org.briarproject.bramble.api.autodelete.AutoDeleteConstants.NO_AUTO_DELETE_TIMER;
@Immutable @Immutable
@NotNullByDefault @NotNullByDefault
class AbortMessage extends AbstractIntroductionMessage { class AbortMessage extends AbstractIntroductionMessage {
@@ -16,7 +18,8 @@ class AbortMessage extends AbstractIntroductionMessage {
protected AbortMessage(MessageId messageId, GroupId groupId, long timestamp, protected AbortMessage(MessageId messageId, GroupId groupId, long timestamp,
@Nullable MessageId previousMessageId, SessionId sessionId) { @Nullable MessageId previousMessageId, SessionId sessionId) {
super(messageId, groupId, timestamp, previousMessageId); super(messageId, groupId, timestamp, previousMessageId,
NO_AUTO_DELETE_TIMER);
this.sessionId = sessionId; this.sessionId = sessionId;
} }

View File

@@ -16,13 +16,16 @@ abstract class AbstractIntroductionMessage {
private final long timestamp; private final long timestamp;
@Nullable @Nullable
private final MessageId previousMessageId; private final MessageId previousMessageId;
private final long autoDeleteTimer;
AbstractIntroductionMessage(MessageId messageId, GroupId groupId, AbstractIntroductionMessage(MessageId messageId, GroupId groupId,
long timestamp, @Nullable MessageId previousMessageId) { long timestamp, @Nullable MessageId previousMessageId,
long autoDeleteTimer) {
this.messageId = messageId; this.messageId = messageId;
this.groupId = groupId; this.groupId = groupId;
this.timestamp = timestamp; this.timestamp = timestamp;
this.previousMessageId = previousMessageId; this.previousMessageId = previousMessageId;
this.autoDeleteTimer = autoDeleteTimer;
} }
MessageId getMessageId() { MessageId getMessageId() {
@@ -42,4 +45,7 @@ abstract class AbstractIntroductionMessage {
return previousMessageId; 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.ClientHelper;
import org.briarproject.bramble.api.client.ContactGroupFactory; import org.briarproject.bramble.api.client.ContactGroupFactory;
import org.briarproject.bramble.api.contact.Contact; 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.contact.ContactManager;
import org.briarproject.bramble.api.crypto.PublicKey; import org.briarproject.bramble.api.crypto.PublicKey;
import org.briarproject.bramble.api.data.BdfDictionary; 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.nullsafety.NotNullByDefault;
import org.briarproject.bramble.api.plugin.TransportId; import org.briarproject.bramble.api.plugin.TransportId;
import org.briarproject.bramble.api.properties.TransportProperties; 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.Message;
import org.briarproject.bramble.api.sync.MessageId; import org.briarproject.bramble.api.sync.MessageId;
import org.briarproject.bramble.api.system.Clock; 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.MessageTracker;
import org.briarproject.briar.api.client.SessionId; import org.briarproject.briar.api.client.SessionId;
import org.briarproject.briar.api.introduction.IntroductionResponse; import org.briarproject.briar.api.introduction.IntroductionResponse;
@@ -30,6 +33,10 @@ import java.util.Map;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import javax.annotation.concurrent.Immutable; 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.ABORT;
import static org.briarproject.briar.introduction.MessageType.ACCEPT; import static org.briarproject.briar.introduction.MessageType.ACCEPT;
import static org.briarproject.briar.introduction.MessageType.ACTIVATE; import static org.briarproject.briar.introduction.MessageType.ACTIVATE;
@@ -39,7 +46,7 @@ import static org.briarproject.briar.introduction.MessageType.REQUEST;
@Immutable @Immutable
@NotNullByDefault @NotNullByDefault
abstract class AbstractProtocolEngine<S extends Session> abstract class AbstractProtocolEngine<S extends Session<?>>
implements ProtocolEngine<S> { implements ProtocolEngine<S> {
protected final DatabaseComponent db; protected final DatabaseComponent db;
@@ -50,6 +57,7 @@ abstract class AbstractProtocolEngine<S extends Session>
protected final IdentityManager identityManager; protected final IdentityManager identityManager;
protected final MessageParser messageParser; protected final MessageParser messageParser;
protected final MessageEncoder messageEncoder; protected final MessageEncoder messageEncoder;
protected final ClientVersioningManager clientVersioningManager;
protected final Clock clock; protected final Clock clock;
AbstractProtocolEngine( AbstractProtocolEngine(
@@ -61,6 +69,7 @@ abstract class AbstractProtocolEngine<S extends Session>
IdentityManager identityManager, IdentityManager identityManager,
MessageParser messageParser, MessageParser messageParser,
MessageEncoder messageEncoder, MessageEncoder messageEncoder,
ClientVersioningManager clientVersioningManager,
Clock clock) { Clock clock) {
this.db = db; this.db = db;
this.clientHelper = clientHelper; this.clientHelper = clientHelper;
@@ -70,16 +79,26 @@ abstract class AbstractProtocolEngine<S extends Session>
this.identityManager = identityManager; this.identityManager = identityManager;
this.messageParser = messageParser; this.messageParser = messageParser;
this.messageEncoder = messageEncoder; this.messageEncoder = messageEncoder;
this.clientVersioningManager = clientVersioningManager;
this.clock = clock; this.clock = clock;
} }
Message sendRequestMessage(Transaction txn, PeerSession s, Message sendRequestMessage(Transaction txn, PeerSession s,
long timestamp, Author author, @Nullable String text) long timestamp, Author author, @Nullable String text)
throws DbException { throws DbException {
Message m = messageEncoder Message m;
.encodeRequestMessage(s.getContactGroupId(), timestamp, if (contactSupportsAutoDeletion(txn, s.getContactGroupId())) {
s.getLastLocalMessageId(), author, text); // TODO: Look up the current auto-delete timer
sendMessage(txn, REQUEST, s.getSessionId(), m, true); 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; return m;
} }
@@ -87,21 +106,41 @@ abstract class AbstractProtocolEngine<S extends Session>
PublicKey ephemeralPublicKey, long acceptTimestamp, PublicKey ephemeralPublicKey, long acceptTimestamp,
Map<TransportId, TransportProperties> transportProperties, Map<TransportId, TransportProperties> transportProperties,
boolean visible) throws DbException { boolean visible) throws DbException {
Message m = messageEncoder Message m;
.encodeAcceptMessage(s.getContactGroupId(), timestamp, if (contactSupportsAutoDeletion(txn, s.getContactGroupId())) {
s.getLastLocalMessageId(), s.getSessionId(), // TODO: Look up the current auto-delete timer
ephemeralPublicKey, acceptTimestamp, long timer = NO_AUTO_DELETE_TIMER;
transportProperties); m = messageEncoder.encodeAcceptMessage(s.getContactGroupId(),
sendMessage(txn, ACCEPT, s.getSessionId(), m, visible); 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; return m;
} }
Message sendDeclineMessage(Transaction txn, PeerSession s, long timestamp, Message sendDeclineMessage(Transaction txn, PeerSession s, long timestamp,
boolean visible) throws DbException { boolean visible) throws DbException {
Message m = messageEncoder Message m;
.encodeDeclineMessage(s.getContactGroupId(), timestamp, if (contactSupportsAutoDeletion(txn, s.getContactGroupId())) {
s.getLastLocalMessageId(), s.getSessionId()); // TODO: Look up the current auto-delete timer
sendMessage(txn, DECLINE, s.getSessionId(), m, visible); 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; return m;
} }
@@ -111,7 +150,8 @@ abstract class AbstractProtocolEngine<S extends Session>
.encodeAuthMessage(s.getContactGroupId(), timestamp, .encodeAuthMessage(s.getContactGroupId(), timestamp,
s.getLastLocalMessageId(), s.getSessionId(), mac, s.getLastLocalMessageId(), s.getSessionId(), mac,
signature); signature);
sendMessage(txn, AUTH, s.getSessionId(), m, false); sendMessage(txn, AUTH, s.getSessionId(), m, false,
NO_AUTO_DELETE_TIMER);
return m; return m;
} }
@@ -120,7 +160,8 @@ abstract class AbstractProtocolEngine<S extends Session>
Message m = messageEncoder Message m = messageEncoder
.encodeActivateMessage(s.getContactGroupId(), timestamp, .encodeActivateMessage(s.getContactGroupId(), timestamp,
s.getLastLocalMessageId(), s.getSessionId(), mac); 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; return m;
} }
@@ -129,16 +170,17 @@ abstract class AbstractProtocolEngine<S extends Session>
Message m = messageEncoder Message m = messageEncoder
.encodeAbortMessage(s.getContactGroupId(), timestamp, .encodeAbortMessage(s.getContactGroupId(), timestamp,
s.getLastLocalMessageId(), s.getSessionId()); s.getLastLocalMessageId(), s.getSessionId());
sendMessage(txn, ABORT, s.getSessionId(), m, false); sendMessage(txn, ABORT, s.getSessionId(), m, false,
NO_AUTO_DELETE_TIMER);
return m; return m;
} }
private void sendMessage(Transaction txn, MessageType type, private void sendMessage(Transaction txn, MessageType type,
SessionId sessionId, Message m, boolean visibleInConversation) SessionId sessionId, Message m, boolean visibleInConversation,
throws DbException { long autoDeleteTimer) throws DbException {
BdfDictionary meta = messageEncoder BdfDictionary meta = messageEncoder.encodeMetadata(type, sessionId,
.encodeMetadata(type, sessionId, m.getTimestamp(), true, true, m.getTimestamp(), true, true, visibleInConversation,
visibleInConversation); autoDeleteTimer);
try { try {
clientHelper.addLocalMessage(txn, m, meta, true, false); clientHelper.addLocalMessage(txn, m, meta, true, false);
} catch (FormatException e) { } catch (FormatException e) {
@@ -146,9 +188,10 @@ abstract class AbstractProtocolEngine<S extends Session>
} }
} }
void broadcastIntroductionResponseReceivedEvent(Transaction txn, Session s, void broadcastIntroductionResponseReceivedEvent(Transaction txn,
AuthorId sender, Author otherAuthor, AbstractIntroductionMessage m, Session<?> s, AuthorId sender, Author otherAuthor,
boolean canSucceed) throws DbException { AbstractIntroductionMessage m, boolean canSucceed)
throws DbException {
AuthorId localAuthorId = identityManager.getLocalAuthor(txn).getId(); AuthorId localAuthorId = identityManager.getLocalAuthor(txn).getId();
Contact c = contactManager.getContact(txn, sender, localAuthorId); Contact c = contactManager.getContact(txn, sender, localAuthorId);
AuthorInfo otherAuthorInfo = AuthorInfo otherAuthorInfo =
@@ -157,7 +200,8 @@ abstract class AbstractProtocolEngine<S extends Session>
new IntroductionResponse(m.getMessageId(), m.getGroupId(), new IntroductionResponse(m.getMessageId(), m.getGroupId(),
m.getTimestamp(), false, false, false, false, m.getTimestamp(), false, false, false, false,
s.getSessionId(), m instanceof AcceptMessage, s.getSessionId(), m instanceof AcceptMessage,
otherAuthor, otherAuthorInfo, s.getRole(), canSucceed); otherAuthor, otherAuthorInfo, s.getRole(), canSucceed,
m.getAutoDeleteTimer());
IntroductionResponseReceivedEvent e = IntroductionResponseReceivedEvent e =
new IntroductionResponseReceivedEvent(response, c.getId()); new IntroductionResponseReceivedEvent(response, c.getId());
txn.attach(e); txn.attach(e);
@@ -190,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, long timestamp, @Nullable MessageId previousMessageId,
SessionId sessionId, PublicKey ephemeralPublicKey, SessionId sessionId, PublicKey ephemeralPublicKey,
long acceptTimestamp, long acceptTimestamp,
Map<TransportId, TransportProperties> transportProperties) { Map<TransportId, TransportProperties> transportProperties,
super(messageId, groupId, timestamp, previousMessageId); long autoDeleteTimer) {
super(messageId, groupId, timestamp, previousMessageId,
autoDeleteTimer);
this.sessionId = sessionId; this.sessionId = sessionId;
this.ephemeralPublicKey = ephemeralPublicKey; this.ephemeralPublicKey = ephemeralPublicKey;
this.acceptTimestamp = acceptTimestamp; this.acceptTimestamp = acceptTimestamp;

View File

@@ -7,6 +7,8 @@ import org.briarproject.briar.api.client.SessionId;
import javax.annotation.concurrent.Immutable; import javax.annotation.concurrent.Immutable;
import static org.briarproject.bramble.api.autodelete.AutoDeleteConstants.NO_AUTO_DELETE_TIMER;
@Immutable @Immutable
@NotNullByDefault @NotNullByDefault
class ActivateMessage extends AbstractIntroductionMessage { class ActivateMessage extends AbstractIntroductionMessage {
@@ -17,7 +19,8 @@ class ActivateMessage extends AbstractIntroductionMessage {
protected ActivateMessage(MessageId messageId, GroupId groupId, protected ActivateMessage(MessageId messageId, GroupId groupId,
long timestamp, MessageId previousMessageId, SessionId sessionId, long timestamp, MessageId previousMessageId, SessionId sessionId,
byte[] mac) { byte[] mac) {
super(messageId, groupId, timestamp, previousMessageId); super(messageId, groupId, timestamp, previousMessageId,
NO_AUTO_DELETE_TIMER);
this.sessionId = sessionId; this.sessionId = sessionId;
this.mac = mac; this.mac = mac;
} }

View File

@@ -7,6 +7,8 @@ import org.briarproject.briar.api.client.SessionId;
import javax.annotation.concurrent.Immutable; import javax.annotation.concurrent.Immutable;
import static org.briarproject.bramble.api.autodelete.AutoDeleteConstants.NO_AUTO_DELETE_TIMER;
@Immutable @Immutable
@NotNullByDefault @NotNullByDefault
class AuthMessage extends AbstractIntroductionMessage { class AuthMessage extends AbstractIntroductionMessage {
@@ -17,7 +19,8 @@ class AuthMessage extends AbstractIntroductionMessage {
protected AuthMessage(MessageId messageId, GroupId groupId, protected AuthMessage(MessageId messageId, GroupId groupId,
long timestamp, MessageId previousMessageId, SessionId sessionId, long timestamp, MessageId previousMessageId, SessionId sessionId,
byte[] mac, byte[] signature) { byte[] mac, byte[] signature) {
super(messageId, groupId, timestamp, previousMessageId); super(messageId, groupId, timestamp, previousMessageId,
NO_AUTO_DELETE_TIMER);
this.sessionId = sessionId; this.sessionId = sessionId;
this.mac = mac; this.mac = mac;
this.signature = signature; this.signature = signature;

View File

@@ -16,8 +16,9 @@ class DeclineMessage extends AbstractIntroductionMessage {
protected DeclineMessage(MessageId messageId, GroupId groupId, protected DeclineMessage(MessageId messageId, GroupId groupId,
long timestamp, @Nullable MessageId previousMessageId, long timestamp, @Nullable MessageId previousMessageId,
SessionId sessionId) { SessionId sessionId, long autoDeleteTimer) {
super(messageId, groupId, timestamp, previousMessageId); super(messageId, groupId, timestamp, previousMessageId,
autoDeleteTimer);
this.sessionId = sessionId; 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.system.Clock;
import org.briarproject.bramble.api.transport.KeyManager; import org.briarproject.bramble.api.transport.KeyManager;
import org.briarproject.bramble.api.transport.KeySetId; 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.MessageTracker;
import org.briarproject.briar.api.client.ProtocolStateException; import org.briarproject.briar.api.client.ProtocolStateException;
import org.briarproject.briar.api.client.SessionId; import org.briarproject.briar.api.client.SessionId;
@@ -76,10 +77,11 @@ class IntroduceeProtocolEngine
Clock clock, Clock clock,
IntroductionCrypto crypto, IntroductionCrypto crypto,
KeyManager keyManager, KeyManager keyManager,
TransportPropertyManager transportPropertyManager) { TransportPropertyManager transportPropertyManager,
ClientVersioningManager clientVersioningManager) {
super(db, clientHelper, contactManager, contactGroupFactory, super(db, clientHelper, contactManager, contactGroupFactory,
messageTracker, identityManager, messageParser, messageEncoder, messageTracker, identityManager, messageParser, messageEncoder,
clock); clientVersioningManager, clock);
this.crypto = crypto; this.crypto = crypto;
this.keyManager = keyManager; this.keyManager = keyManager;
this.transportPropertyManager = transportPropertyManager; this.transportPropertyManager = transportPropertyManager;
@@ -258,7 +260,7 @@ class IntroduceeProtocolEngine
IntroductionRequest request = new IntroductionRequest(m.getMessageId(), IntroductionRequest request = new IntroductionRequest(m.getMessageId(),
m.getGroupId(), m.getTimestamp(), false, false, false, false, m.getGroupId(), m.getTimestamp(), false, false, false, false,
s.getSessionId(), m.getAuthor(), m.getText(), false, s.getSessionId(), m.getAuthor(), m.getText(), false,
authorInfo); authorInfo, m.getAutoDeleteTimer());
IntroductionRequestReceivedEvent e = IntroductionRequestReceivedEvent e =
new IntroductionRequestReceivedEvent(request, c.getId()); new IntroductionRequestReceivedEvent(request, c.getId());
txn.attach(e); 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.Message;
import org.briarproject.bramble.api.sync.MessageId; import org.briarproject.bramble.api.sync.MessageId;
import org.briarproject.bramble.api.system.Clock; 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.MessageTracker;
import org.briarproject.briar.api.client.ProtocolStateException; import org.briarproject.briar.api.client.ProtocolStateException;
import org.briarproject.briar.api.introduction.event.IntroductionAbortedEvent; import org.briarproject.briar.api.introduction.event.IntroductionAbortedEvent;
@@ -50,10 +51,11 @@ class IntroducerProtocolEngine
IdentityManager identityManager, IdentityManager identityManager,
MessageParser messageParser, MessageParser messageParser,
MessageEncoder messageEncoder, MessageEncoder messageEncoder,
ClientVersioningManager clientVersioningManager,
Clock clock) { Clock clock) {
super(db, clientHelper, contactManager, contactGroupFactory, super(db, clientHelper, contactManager, contactGroupFactory,
messageTracker, identityManager, messageParser, messageEncoder, messageTracker, identityManager, messageParser, messageEncoder,
clock); clientVersioningManager, clock);
} }
@Override @Override

View File

@@ -12,6 +12,7 @@ interface IntroductionConstants {
String MSG_KEY_LOCAL = "local"; String MSG_KEY_LOCAL = "local";
String MSG_KEY_VISIBLE_IN_UI = "visibleInUi"; String MSG_KEY_VISIBLE_IN_UI = "visibleInUi";
String MSG_KEY_AVAILABLE_TO_ANSWER = "availableToAnswer"; String MSG_KEY_AVAILABLE_TO_ANSWER = "availableToAnswer";
String MSG_KEY_AUTO_DELETE_TIMER = "autoDeleteTimer";
// Session Keys // Session Keys
String SESSION_KEY_SESSION_ID = "sessionId"; String SESSION_KEY_SESSION_ID = "sessionId";

View File

@@ -461,7 +461,7 @@ class IntroductionManagerImpl extends ConversationClientImpl
return new IntroductionRequest(m, contactGroupId, meta.getTimestamp(), return new IntroductionRequest(m, contactGroupId, meta.getTimestamp(),
meta.isLocal(), meta.isRead(), status.isSent(), status.isSeen(), meta.isLocal(), meta.isRead(), status.isSent(), status.isSeen(),
sessionId, author, text, !meta.isAvailableToAnswer(), sessionId, author, text, !meta.isAvailableToAnswer(),
authorInfo); authorInfo, rm.getAutoDeleteTimer());
} }
private IntroductionResponse parseInvitationResponse(Transaction txn, private IntroductionResponse parseInvitationResponse(Transaction txn,
@@ -499,7 +499,8 @@ class IntroductionManagerImpl extends ConversationClientImpl
} }
return new IntroductionResponse(m, contactGroupId, meta.getTimestamp(), return new IntroductionResponse(m, contactGroupId, meta.getTimestamp(),
meta.isLocal(), meta.isRead(), status.isSent(), status.isSeen(), 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, private void removeSessionWithIntroducer(Transaction txn,

View File

@@ -15,13 +15,18 @@ import org.briarproject.bramble.api.sync.MessageId;
import org.briarproject.bramble.api.system.Clock; import org.briarproject.bramble.api.system.Clock;
import org.briarproject.briar.api.client.SessionId; import org.briarproject.briar.api.client.SessionId;
import javax.annotation.Nullable;
import javax.annotation.concurrent.Immutable; import javax.annotation.concurrent.Immutable;
import static java.util.Collections.singletonList; 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.MAC_BYTES;
import static org.briarproject.bramble.api.crypto.CryptoConstants.MAX_SIGNATURE_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.api.identity.AuthorConstants.MAX_PUBLIC_KEY_LENGTH;
import static org.briarproject.bramble.util.ValidationUtils.checkLength; 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.bramble.util.ValidationUtils.checkSize;
import static org.briarproject.briar.api.introduction.IntroductionConstants.MAX_INTRODUCTION_TEXT_LENGTH; import static org.briarproject.briar.api.introduction.IntroductionConstants.MAX_INTRODUCTION_TEXT_LENGTH;
import static org.briarproject.briar.introduction.MessageType.ACCEPT; import static org.briarproject.briar.introduction.MessageType.ACCEPT;
@@ -52,13 +57,14 @@ class IntroductionValidator extends BdfMessageValidator {
return validateRequestMessage(m, body); return validateRequestMessage(m, body);
case ACCEPT: case ACCEPT:
return validateAcceptMessage(m, body); return validateAcceptMessage(m, body);
case DECLINE:
return validateDeclineMessage(type, m, body);
case AUTH: case AUTH:
return validateAuthMessage(m, body); return validateAuthMessage(m, body);
case ACTIVATE: case ACTIVATE:
return validateActivateMessage(m, body); return validateActivateMessage(m, body);
case DECLINE:
case ABORT: case ABORT:
return validateOtherMessage(type, m, body); return validateAbortMessage(type, m, body);
default: default:
throw new FormatException(); throw new FormatException();
} }
@@ -66,7 +72,11 @@ class IntroductionValidator extends BdfMessageValidator {
private BdfMessageContext validateRequestMessage(Message m, BdfList body) private BdfMessageContext validateRequestMessage(Message m, BdfList body)
throws FormatException { 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); byte[] previousMessageId = body.getOptionalRaw(1);
checkLength(previousMessageId, UniqueId.LENGTH); checkLength(previousMessageId, UniqueId.LENGTH);
@@ -77,8 +87,11 @@ class IntroductionValidator extends BdfMessageValidator {
String text = body.getOptionalString(3); String text = body.getOptionalString(3);
checkLength(text, 1, MAX_INTRODUCTION_TEXT_LENGTH); checkLength(text, 1, MAX_INTRODUCTION_TEXT_LENGTH);
long timer = NO_AUTO_DELETE_TIMER;
if (body.size() == 5) timer = validateTimer(body.getOptionalLong(4));
BdfDictionary meta = BdfDictionary meta =
messageEncoder.encodeRequestMetadata(m.getTimestamp()); messageEncoder.encodeRequestMetadata(m.getTimestamp(), timer);
if (previousMessageId == null) { if (previousMessageId == null) {
return new BdfMessageContext(meta); return new BdfMessageContext(meta);
} else { } else {
@@ -89,7 +102,12 @@ class IntroductionValidator extends BdfMessageValidator {
private BdfMessageContext validateAcceptMessage(Message m, BdfList body) private BdfMessageContext validateAcceptMessage(Message m, BdfList body)
throws FormatException { 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); byte[] sessionIdBytes = body.getRaw(1);
checkLength(sessionIdBytes, UniqueId.LENGTH); checkLength(sessionIdBytes, UniqueId.LENGTH);
@@ -109,9 +127,40 @@ class IntroductionValidator extends BdfMessageValidator {
clientHelper clientHelper
.parseAndValidateTransportPropertiesMap(transportProperties); .parseAndValidateTransportPropertiesMap(transportProperties);
long timer = NO_AUTO_DELETE_TIMER;
if (body.size() == 7) timer = validateTimer(body.getOptionalLong(6));
SessionId sessionId = new SessionId(sessionIdBytes); SessionId sessionId = new SessionId(sessionIdBytes);
BdfDictionary meta = messageEncoder.encodeMetadata(ACCEPT, sessionId, 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 = NO_AUTO_DELETE_TIMER;
if (body.size() == 4) timer = validateTimer(body.getOptionalLong(3));
SessionId sessionId = new SessionId(sessionIdBytes);
BdfDictionary meta = messageEncoder.encodeMetadata(type, sessionId,
m.getTimestamp(), false, false, false, timer);
if (previousMessageId == null) { if (previousMessageId == null) {
return new BdfMessageContext(meta); return new BdfMessageContext(meta);
} else { } else {
@@ -138,7 +187,7 @@ class IntroductionValidator extends BdfMessageValidator {
SessionId sessionId = new SessionId(sessionIdBytes); SessionId sessionId = new SessionId(sessionIdBytes);
BdfDictionary meta = messageEncoder.encodeMetadata(AUTH, sessionId, 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); MessageId dependency = new MessageId(previousMessageId);
return new BdfMessageContext(meta, singletonList(dependency)); return new BdfMessageContext(meta, singletonList(dependency));
} }
@@ -158,7 +207,7 @@ class IntroductionValidator extends BdfMessageValidator {
SessionId sessionId = new SessionId(sessionIdBytes); SessionId sessionId = new SessionId(sessionIdBytes);
BdfDictionary meta = messageEncoder.encodeMetadata(ACTIVATE, sessionId, BdfDictionary meta = messageEncoder.encodeMetadata(ACTIVATE, sessionId,
m.getTimestamp(), false, false, false); m.getTimestamp(), false, false, false, NO_AUTO_DELETE_TIMER);
if (previousMessageId == null) { if (previousMessageId == null) {
return new BdfMessageContext(meta); return new BdfMessageContext(meta);
} else { } else {
@@ -167,7 +216,7 @@ class IntroductionValidator extends BdfMessageValidator {
} }
} }
private BdfMessageContext validateOtherMessage(MessageType type, private BdfMessageContext validateAbortMessage(MessageType type,
Message m, BdfList body) throws FormatException { Message m, BdfList body) throws FormatException {
checkSize(body, 3); checkSize(body, 3);
@@ -179,7 +228,7 @@ class IntroductionValidator extends BdfMessageValidator {
SessionId sessionId = new SessionId(sessionIdBytes); SessionId sessionId = new SessionId(sessionIdBytes);
BdfDictionary meta = messageEncoder.encodeMetadata(type, sessionId, BdfDictionary meta = messageEncoder.encodeMetadata(type, sessionId,
m.getTimestamp(), false, false, false); m.getTimestamp(), false, false, false, NO_AUTO_DELETE_TIMER);
if (previousMessageId == null) { if (previousMessageId == null) {
return new BdfMessageContext(meta); return new BdfMessageContext(meta);
} else { } else {
@@ -188,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

@@ -18,11 +18,12 @@ import javax.annotation.Nullable;
@NotNullByDefault @NotNullByDefault
interface MessageEncoder { interface MessageEncoder {
BdfDictionary encodeRequestMetadata(long timestamp); BdfDictionary encodeRequestMetadata(long timestamp,
long autoDeleteTimer);
BdfDictionary encodeMetadata(MessageType type, BdfDictionary encodeMetadata(MessageType type,
@Nullable SessionId sessionId, long timestamp, boolean local, @Nullable SessionId sessionId, long timestamp, boolean local,
boolean read, boolean visible); boolean read, boolean visible, long autoDeleteTimer);
void addSessionId(BdfDictionary meta, SessionId sessionId); void addSessionId(BdfDictionary meta, SessionId sessionId);
@@ -30,18 +31,53 @@ interface MessageEncoder {
void setAvailableToAnswer(BdfDictionary meta, boolean available); void setAvailableToAnswer(BdfDictionary meta, boolean available);
/**
* Encodes a request message without an auto-delete timer.
*/
Message encodeRequestMessage(GroupId contactGroupId, long timestamp, Message encodeRequestMessage(GroupId contactGroupId, long timestamp,
@Nullable MessageId previousMessageId, Author author, @Nullable MessageId previousMessageId, Author author,
@Nullable String text); @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, Message encodeAcceptMessage(GroupId contactGroupId, long timestamp,
@Nullable MessageId previousMessageId, SessionId sessionId, @Nullable MessageId previousMessageId, SessionId sessionId,
PublicKey ephemeralPublicKey, long acceptTimestamp, PublicKey ephemeralPublicKey, long acceptTimestamp,
Map<TransportId, TransportProperties> transportProperties); 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, Message encodeDeclineMessage(GroupId contactGroupId, long timestamp,
@Nullable MessageId previousMessageId, SessionId sessionId); @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, Message encodeAuthMessage(GroupId contactGroupId, long timestamp,
@Nullable MessageId previousMessageId, SessionId sessionId, @Nullable MessageId previousMessageId, SessionId sessionId,
byte[] mac, byte[] signature); byte[] mac, byte[] signature);

View File

@@ -20,7 +20,9 @@ import java.util.Map;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import javax.inject.Inject; 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.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_AVAILABLE_TO_ANSWER;
import static org.briarproject.briar.introduction.IntroductionConstants.MSG_KEY_LOCAL; import static org.briarproject.briar.introduction.IntroductionConstants.MSG_KEY_LOCAL;
import static org.briarproject.briar.introduction.IntroductionConstants.MSG_KEY_MESSAGE_TYPE; import static org.briarproject.briar.introduction.IntroductionConstants.MSG_KEY_MESSAGE_TYPE;
@@ -48,9 +50,10 @@ class MessageEncoderImpl implements MessageEncoder {
} }
@Override @Override
public BdfDictionary encodeRequestMetadata(long timestamp) { public BdfDictionary encodeRequestMetadata(long timestamp,
BdfDictionary meta = long autoDeleteTimer) {
encodeMetadata(REQUEST, null, timestamp, false, false, false); BdfDictionary meta = encodeMetadata(REQUEST, null, timestamp,
false, false, false, autoDeleteTimer);
meta.put(MSG_KEY_AVAILABLE_TO_ANSWER, false); meta.put(MSG_KEY_AVAILABLE_TO_ANSWER, false);
return meta; return meta;
} }
@@ -58,7 +61,7 @@ class MessageEncoderImpl implements MessageEncoder {
@Override @Override
public BdfDictionary encodeMetadata(MessageType type, public BdfDictionary encodeMetadata(MessageType type,
@Nullable SessionId sessionId, long timestamp, boolean local, @Nullable SessionId sessionId, long timestamp, boolean local,
boolean read, boolean visible) { boolean read, boolean visible, long autoDeleteTimer) {
BdfDictionary meta = new BdfDictionary(); BdfDictionary meta = new BdfDictionary();
meta.put(MSG_KEY_MESSAGE_TYPE, type.getValue()); meta.put(MSG_KEY_MESSAGE_TYPE, type.getValue());
if (sessionId != null) if (sessionId != null)
@@ -69,6 +72,9 @@ class MessageEncoderImpl implements MessageEncoder {
meta.put(MSG_KEY_LOCAL, local); meta.put(MSG_KEY_LOCAL, local);
meta.put(MSG_KEY_READ, read); meta.put(MSG_KEY_READ, read);
meta.put(MSG_KEY_VISIBLE_IN_UI, visible); meta.put(MSG_KEY_VISIBLE_IN_UI, visible);
if (autoDeleteTimer != NO_AUTO_DELETE_TIMER) {
meta.put(MSG_KEY_AUTO_DELETE_TIMER, autoDeleteTimer);
}
return meta; return meta;
} }
@@ -103,6 +109,23 @@ class MessageEncoderImpl implements MessageEncoder {
return createMessage(contactGroupId, timestamp, body); 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 @Override
public Message encodeAcceptMessage(GroupId contactGroupId, long timestamp, public Message encodeAcceptMessage(GroupId contactGroupId, long timestamp,
@Nullable MessageId previousMessageId, SessionId sessionId, @Nullable MessageId previousMessageId, SessionId sessionId,
@@ -119,11 +142,46 @@ class MessageEncoderImpl implements MessageEncoder {
return createMessage(contactGroupId, timestamp, body); 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 @Override
public Message encodeDeclineMessage(GroupId contactGroupId, long timestamp, public Message encodeDeclineMessage(GroupId contactGroupId, long timestamp,
@Nullable MessageId previousMessageId, SessionId sessionId) { @Nullable MessageId previousMessageId, SessionId sessionId) {
return encodeMessage(DECLINE, contactGroupId, sessionId, timestamp, BdfList body = BdfList.of(
previousMessageId); 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 @Override
@@ -156,15 +214,8 @@ class MessageEncoderImpl implements MessageEncoder {
@Override @Override
public Message encodeAbortMessage(GroupId contactGroupId, long timestamp, public Message encodeAbortMessage(GroupId contactGroupId, long timestamp,
@Nullable MessageId previousMessageId, SessionId sessionId) { @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( BdfList body = BdfList.of(
type.getValue(), ABORT.getValue(),
sessionId, sessionId,
previousMessageId previousMessageId
); );
@@ -181,4 +232,8 @@ class MessageEncoderImpl implements MessageEncoder {
} }
} }
@Nullable
private Long encodeTimer(long autoDeleteTimer) {
return autoDeleteTimer == NO_AUTO_DELETE_TIMER ? null : autoDeleteTimer;
}
} }

View File

@@ -13,12 +13,12 @@ class MessageMetadata {
private final MessageType type; private final MessageType type;
@Nullable @Nullable
private final SessionId sessionId; private final SessionId sessionId;
private final long timestamp; private final long timestamp, autoDeleteTimer;
private final boolean local, read, visible, available; private final boolean local, read, visible, available;
MessageMetadata(MessageType type, @Nullable SessionId sessionId, MessageMetadata(MessageType type, @Nullable SessionId sessionId,
long timestamp, boolean local, boolean read, boolean visible, long timestamp, boolean local, boolean read, boolean visible,
boolean available) { boolean available, long autoDeleteTimer) {
this.type = type; this.type = type;
this.sessionId = sessionId; this.sessionId = sessionId;
this.timestamp = timestamp; this.timestamp = timestamp;
@@ -26,6 +26,7 @@ class MessageMetadata {
this.read = read; this.read = read;
this.visible = visible; this.visible = visible;
this.available = available; this.available = available;
this.autoDeleteTimer = autoDeleteTimer;
} }
MessageType getMessageType() { MessageType getMessageType() {
@@ -57,4 +58,7 @@ class MessageMetadata {
return available; return available;
} }
public long getAutoDeleteTimer() {
return autoDeleteTimer;
}
} }

View File

@@ -19,7 +19,9 @@ import java.util.Map;
import javax.inject.Inject; 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.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_AVAILABLE_TO_ANSWER;
import static org.briarproject.briar.introduction.IntroductionConstants.MSG_KEY_LOCAL; import static org.briarproject.briar.introduction.IntroductionConstants.MSG_KEY_LOCAL;
import static org.briarproject.briar.introduction.IntroductionConstants.MSG_KEY_MESSAGE_TYPE; 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 read = d.getBoolean(MSG_KEY_READ);
boolean visible = d.getBoolean(MSG_KEY_VISIBLE_IN_UI); boolean visible = d.getBoolean(MSG_KEY_VISIBLE_IN_UI);
boolean available = d.getBoolean(MSG_KEY_AVAILABLE_TO_ANSWER, false); 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, return new MessageMetadata(type, sessionId, timestamp, local, read,
visible, available); visible, available, timer);
} }
@Override @Override
@@ -77,8 +80,10 @@ class MessageParserImpl implements MessageParser {
new MessageId(previousMsgBytes)); new MessageId(previousMsgBytes));
Author author = clientHelper.parseAndValidateAuthor(body.getList(2)); Author author = clientHelper.parseAndValidateAuthor(body.getList(2));
String text = body.getOptionalString(3); 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(), return new RequestMessage(m.getId(), m.getGroupId(),
m.getTimestamp(), previousMessageId, author, text); m.getTimestamp(), previousMessageId, author, text, timer);
} }
@Override @Override
@@ -92,9 +97,11 @@ class MessageParserImpl implements MessageParser {
long acceptTimestamp = body.getLong(4); long acceptTimestamp = body.getLong(4);
Map<TransportId, TransportProperties> transportProperties = clientHelper Map<TransportId, TransportProperties> transportProperties = clientHelper
.parseAndValidateTransportPropertiesMap(body.getDictionary(5)); .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(), return new AcceptMessage(m.getId(), m.getGroupId(), m.getTimestamp(),
previousMessageId, sessionId, ephemeralPublicKey, previousMessageId, sessionId, ephemeralPublicKey,
acceptTimestamp, transportProperties); acceptTimestamp, transportProperties, timer);
} }
@Override @Override
@@ -104,8 +111,10 @@ class MessageParserImpl implements MessageParser {
byte[] previousMsgBytes = body.getOptionalRaw(2); byte[] previousMsgBytes = body.getOptionalRaw(2);
MessageId previousMessageId = (previousMsgBytes == null ? null : MessageId previousMessageId = (previousMsgBytes == null ? null :
new MessageId(previousMsgBytes)); 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(), return new DeclineMessage(m.getId(), m.getGroupId(), m.getTimestamp(),
previousMessageId, sessionId); previousMessageId, sessionId, timer);
} }
@Override @Override

View File

@@ -18,8 +18,9 @@ class RequestMessage extends AbstractIntroductionMessage {
RequestMessage(MessageId messageId, GroupId groupId, long timestamp, RequestMessage(MessageId messageId, GroupId groupId, long timestamp,
@Nullable MessageId previousMessageId, Author author, @Nullable MessageId previousMessageId, Author author,
@Nullable String text) { @Nullable String text, long autoDeleteTimer) {
super(messageId, groupId, timestamp, previousMessageId); super(messageId, groupId, timestamp, previousMessageId,
autoDeleteTimer);
this.author = author; this.author = author;
this.text = text; this.text = text;
} }

View File

@@ -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.sync.SyncConstants.MAX_MESSAGE_BODY_LENGTH;
import static org.briarproject.bramble.api.transport.TransportConstants.MAX_CLOCK_DIFFERENCE; 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.checkLength;
import static org.briarproject.bramble.util.ValidationUtils.checkRange;
import static org.briarproject.bramble.util.ValidationUtils.checkSize; 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_ATTACHMENTS_PER_MESSAGE;
import static org.briarproject.briar.api.messaging.MessagingConstants.MAX_CONTENT_TYPE_BYTES; 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); checkLength(contentType, 1, MAX_CONTENT_TYPE_BYTES);
} }
Long timer = null; Long timer = null;
if (body.size() == 4) timer = body.getOptionalLong(3); if (body.size() == 4) {
if (timer != null && (timer < MIN_AUTO_DELETE_TIMER_MS || timer = body.getOptionalLong(3);
timer > MAX_AUTO_DELETE_TIMER_MS)) { checkRange(timer, MIN_AUTO_DELETE_TIMER_MS,
throw new FormatException(); MAX_AUTO_DELETE_TIMER_MS);
} }
// Return the metadata // Return the metadata
BdfDictionary meta = new BdfDictionary(); BdfDictionary meta = new BdfDictionary();

View File

@@ -45,6 +45,7 @@ import java.util.Map;
import java.util.Set; import java.util.Set;
import static java.util.Collections.emptySet; 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.TestPluginConfigModule.SIMPLEX_TRANSPORT_ID;
import static org.briarproject.bramble.test.TestUtils.getAgreementPublicKey; import static org.briarproject.bramble.test.TestUtils.getAgreementPublicKey;
import static org.briarproject.bramble.test.TestUtils.getSecretKey; import static org.briarproject.bramble.test.TestUtils.getSecretKey;
@@ -1114,7 +1115,7 @@ public class IntroductionIntegrationTest
m.getTimestamp(), m.getPreviousMessageId(), m.getTimestamp(), m.getPreviousMessageId(),
m.getSessionId(), m.getEphemeralPublicKey(), m.getSessionId(), m.getEphemeralPublicKey(),
m.getAcceptTimestamp(), m.getAcceptTimestamp(),
getTransportPropertiesMap(2)) getTransportPropertiesMap(2), NO_AUTO_DELETE_TIMER)
); );
} }
@@ -1125,7 +1126,7 @@ public class IntroductionIntegrationTest
m.getTimestamp(), m.getPreviousMessageId(), m.getTimestamp(), m.getPreviousMessageId(),
m.getSessionId(), m.getEphemeralPublicKey(), m.getSessionId(), m.getEphemeralPublicKey(),
clock.currentTimeMillis(), 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 -> new AcceptMessage(m.getMessageId(), m.getGroupId(),
m.getTimestamp(), m.getPreviousMessageId(), m.getTimestamp(), m.getPreviousMessageId(),
m.getSessionId(), getAgreementPublicKey(), 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 // introducer can not yet remove messages
assertFalse(deleteAllMessages1From0().allDeleted()); assertFalse(deleteAllMessages1From0().allDeleted());
assertTrue(deleteAllMessages1From0().hasIntroductionSessionInProgress()); assertTrue(
deleteAllMessages1From0().hasIntroductionSessionInProgress());
// introducee1 can not yet remove messages // introducee1 can not yet remove messages
assertFalse(deleteAllMessages0From1().allDeleted()); assertFalse(deleteAllMessages0From1().allDeleted());
assertTrue(deleteAllMessages0From1().hasIntroductionSessionInProgress()); assertTrue(
deleteAllMessages0From1().hasIntroductionSessionInProgress());
// sync second REQUEST message // sync second REQUEST message
sync0To2(1, true); sync0To2(1, true);
@@ -1166,10 +1170,12 @@ public class IntroductionIntegrationTest
// introducer can not yet remove messages // introducer can not yet remove messages
assertFalse(deleteAllMessages2From0().allDeleted()); assertFalse(deleteAllMessages2From0().allDeleted());
assertTrue(deleteAllMessages2From0().hasIntroductionSessionInProgress()); assertTrue(
deleteAllMessages2From0().hasIntroductionSessionInProgress());
// introducee2 can not yet remove messages // introducee2 can not yet remove messages
assertFalse(deleteAllMessages0From2().allDeleted()); assertFalse(deleteAllMessages0From2().allDeleted());
assertTrue(deleteAllMessages0From2().hasIntroductionSessionInProgress()); assertTrue(
deleteAllMessages0From2().hasIntroductionSessionInProgress());
// sync first ACCEPT message // sync first ACCEPT message
sync1To0(1, true); sync1To0(1, true);
@@ -1177,7 +1183,8 @@ public class IntroductionIntegrationTest
// introducer can not yet remove messages // introducer can not yet remove messages
assertFalse(deleteAllMessages1From0().allDeleted()); assertFalse(deleteAllMessages1From0().allDeleted());
assertTrue(deleteAllMessages1From0().hasIntroductionSessionInProgress()); assertTrue(
deleteAllMessages1From0().hasIntroductionSessionInProgress());
// sync second ACCEPT message // sync second ACCEPT message
sync2To0(1, true); sync2To0(1, true);
@@ -1185,7 +1192,8 @@ public class IntroductionIntegrationTest
// introducer can not yet remove messages // introducer can not yet remove messages
assertFalse(deleteAllMessages2From0().allDeleted()); assertFalse(deleteAllMessages2From0().allDeleted());
assertTrue(deleteAllMessages2From0().hasIntroductionSessionInProgress()); assertTrue(
deleteAllMessages2From0().hasIntroductionSessionInProgress());
// sync forwarded ACCEPT messages to introducees // sync forwarded ACCEPT messages to introducees
sync0To1(1, true); sync0To1(1, true);
@@ -1193,10 +1201,12 @@ public class IntroductionIntegrationTest
// introducee1 can not yet remove messages // introducee1 can not yet remove messages
assertFalse(deleteAllMessages0From1().allDeleted()); assertFalse(deleteAllMessages0From1().allDeleted());
assertTrue(deleteAllMessages0From1().hasIntroductionSessionInProgress()); assertTrue(
deleteAllMessages0From1().hasIntroductionSessionInProgress());
// introducee2 can not yet remove messages // introducee2 can not yet remove messages
assertFalse(deleteAllMessages0From2().allDeleted()); assertFalse(deleteAllMessages0From2().allDeleted());
assertTrue(deleteAllMessages0From2().hasIntroductionSessionInProgress()); assertTrue(
deleteAllMessages0From2().hasIntroductionSessionInProgress());
// sync first AUTH and its forward // sync first AUTH and its forward
sync1To0(1, true); sync1To0(1, true);
@@ -1204,12 +1214,15 @@ public class IntroductionIntegrationTest
// introducer can not yet remove messages // introducer can not yet remove messages
assertFalse(deleteAllMessages1From0().allDeleted()); assertFalse(deleteAllMessages1From0().allDeleted());
assertTrue(deleteAllMessages1From0().hasIntroductionSessionInProgress()); assertTrue(
deleteAllMessages1From0().hasIntroductionSessionInProgress());
assertFalse(deleteAllMessages2From0().allDeleted()); assertFalse(deleteAllMessages2From0().allDeleted());
assertTrue(deleteAllMessages2From0().hasIntroductionSessionInProgress()); assertTrue(
deleteAllMessages2From0().hasIntroductionSessionInProgress());
// introducee2 can not yet remove messages // introducee2 can not yet remove messages
assertFalse(deleteAllMessages0From2().allDeleted()); assertFalse(deleteAllMessages0From2().allDeleted());
assertTrue(deleteAllMessages0From2().hasIntroductionSessionInProgress()); assertTrue(
deleteAllMessages0From2().hasIntroductionSessionInProgress());
// sync second AUTH and its forward as well as the following ACTIVATE // sync second AUTH and its forward as well as the following ACTIVATE
sync2To0(2, true); sync2To0(2, true);
@@ -1217,12 +1230,15 @@ public class IntroductionIntegrationTest
// introducer can not yet remove messages // introducer can not yet remove messages
assertFalse(deleteAllMessages1From0().allDeleted()); assertFalse(deleteAllMessages1From0().allDeleted());
assertTrue(deleteAllMessages1From0().hasIntroductionSessionInProgress()); assertTrue(
deleteAllMessages1From0().hasIntroductionSessionInProgress());
assertFalse(deleteAllMessages2From0().allDeleted()); assertFalse(deleteAllMessages2From0().allDeleted());
assertTrue(deleteAllMessages2From0().hasIntroductionSessionInProgress()); assertTrue(
deleteAllMessages2From0().hasIntroductionSessionInProgress());
// introducee1 can not yet remove messages // introducee1 can not yet remove messages
assertFalse(deleteAllMessages0From1().allDeleted()); assertFalse(deleteAllMessages0From1().allDeleted());
assertTrue(deleteAllMessages0From1().hasIntroductionSessionInProgress()); assertTrue(
deleteAllMessages0From1().hasIntroductionSessionInProgress());
// sync second ACTIVATE and its forward // sync second ACTIVATE and its forward
sync1To0(1, true); sync1To0(1, true);
@@ -1458,14 +1474,16 @@ public class IntroductionIntegrationTest
sendAcks(c1, c0, contactId0From1, 1); sendAcks(c1, c0, contactId0From1, 1);
assertTrue(deleteAllMessages1From0().allDeleted()); assertTrue(deleteAllMessages1From0().allDeleted());
assertEquals(0, getMessages1From0().size()); 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 // introducer can remove messages after getting ACK from introducee2
// if this succeeds, we still had the session object after delete above // if this succeeds, we still had the session object after delete above
sendAcks(c2, c0, contactId0From2, 1); sendAcks(c2, c0, contactId0From2, 1);
assertTrue(deleteAllMessages2From0().allDeleted()); assertTrue(deleteAllMessages2From0().allDeleted());
assertEquals(0, getMessages2From0().size()); 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 // no one should have aborted
assertFalse(listener0.aborted); assertFalse(listener0.aborted);
@@ -1489,7 +1507,8 @@ public class IntroductionIntegrationTest
Set<MessageId> toDelete1 = new HashSet<>(); Set<MessageId> toDelete1 = new HashSet<>();
toDelete1.add(messageId1); toDelete1.add(messageId1);
assertFalse(deleteMessages1From0(toDelete1).allDeleted()); assertFalse(deleteMessages1From0(toDelete1).allDeleted());
assertTrue(deleteMessages1From0(toDelete1).hasIntroductionSessionInProgress()); assertTrue(deleteMessages1From0(toDelete1)
.hasIntroductionSessionInProgress());
// deleting the introduction for introducee2 will fail as well // deleting the introduction for introducee2 will fail as well
Collection<ConversationMessageHeader> m2From0 = getMessages2From0(); Collection<ConversationMessageHeader> m2From0 = getMessages2From0();
@@ -1498,7 +1517,8 @@ public class IntroductionIntegrationTest
Set<MessageId> toDelete2 = new HashSet<>(); Set<MessageId> toDelete2 = new HashSet<>();
toDelete2.add(messageId2); toDelete2.add(messageId2);
assertFalse(deleteMessages2From0(toDelete2).allDeleted()); assertFalse(deleteMessages2From0(toDelete2).allDeleted());
assertTrue(deleteMessages2From0(toDelete2).hasIntroductionSessionInProgress()); assertTrue(deleteMessages2From0(toDelete2)
.hasIntroductionSessionInProgress());
// sync REQUEST messages // sync REQUEST messages
sync0To1(1, true); sync0To1(1, true);
@@ -1508,9 +1528,11 @@ public class IntroductionIntegrationTest
// deleting introduction fails, because responses did not arrive // deleting introduction fails, because responses did not arrive
assertFalse(deleteMessages0From1(toDelete1).allDeleted()); assertFalse(deleteMessages0From1(toDelete1).allDeleted());
assertTrue(deleteMessages0From1(toDelete1).hasIntroductionSessionInProgress()); assertTrue(deleteMessages0From1(toDelete1)
.hasIntroductionSessionInProgress());
assertFalse(deleteMessages0From2(toDelete2).allDeleted()); assertFalse(deleteMessages0From2(toDelete2).allDeleted());
assertTrue(deleteMessages0From2(toDelete2).hasIntroductionSessionInProgress()); assertTrue(deleteMessages0From2(toDelete2)
.hasIntroductionSessionInProgress());
// remember response of introducee1 for future deletion // remember response of introducee1 for future deletion
Collection<ConversationMessageHeader> m0From1 = getMessages0From1(); Collection<ConversationMessageHeader> m0From1 = getMessages0From1();
@@ -1570,7 +1592,8 @@ public class IntroductionIntegrationTest
// deleting introduction fails for introducee 2, // deleting introduction fails for introducee 2,
// because response is not yet selected for deletion // because response is not yet selected for deletion
assertFalse(deleteMessages0From2(toDelete2).allDeleted()); assertFalse(deleteMessages0From2(toDelete2).allDeleted());
assertTrue(deleteMessages0From2(toDelete2).hasNotAllIntroductionSelected()); assertTrue(deleteMessages0From2(toDelete2)
.hasNotAllIntroductionSelected());
// add response to be deleted as well // add response to be deleted as well
toDelete2.add(response2); toDelete2.add(response2);
@@ -1588,7 +1611,8 @@ public class IntroductionIntegrationTest
// deleting introduction fails for introducee 1, // deleting introduction fails for introducee 1,
// because response is not yet selected for deletion // because response is not yet selected for deletion
assertFalse(deleteMessages0From1(toDelete1).allDeleted()); assertFalse(deleteMessages0From1(toDelete1).allDeleted());
assertTrue(deleteMessages0From1(toDelete1).hasNotAllIntroductionSelected()); assertTrue(deleteMessages0From1(toDelete1)
.hasNotAllIntroductionSelected());
// add response to be deleted as well // add response to be deleted as well
toDelete1.add(response1); toDelete1.add(response1);
@@ -1730,7 +1754,8 @@ public class IntroductionIntegrationTest
@MethodsNotNullByDefault @MethodsNotNullByDefault
@ParametersNotNullByDefault @ParametersNotNullByDefault
private abstract class IntroductionListener implements EventListener { private abstract static class IntroductionListener
implements EventListener {
volatile boolean aborted = false; volatile boolean aborted = false;
volatile Event latestEvent; volatile Event latestEvent;

View File

@@ -6,20 +6,29 @@ import org.briarproject.bramble.api.crypto.PublicKey;
import org.briarproject.bramble.api.data.BdfDictionary; import org.briarproject.bramble.api.data.BdfDictionary;
import org.briarproject.bramble.api.data.BdfEntry; import org.briarproject.bramble.api.data.BdfEntry;
import org.briarproject.bramble.api.data.BdfList; 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.api.sync.MessageId;
import org.briarproject.bramble.test.ValidatorTestCase; import org.briarproject.bramble.test.ValidatorTestCase;
import org.briarproject.briar.api.client.SessionId; import org.briarproject.briar.api.client.SessionId;
import org.jmock.Expectations; import org.jmock.Expectations;
import org.junit.Test; import org.junit.Test;
import java.util.Map;
import javax.annotation.Nullable; 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.MAC_BYTES;
import static org.briarproject.bramble.api.crypto.CryptoConstants.MAX_AGREEMENT_PUBLIC_KEY_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.api.crypto.CryptoConstants.MAX_SIGNATURE_BYTES;
import static org.briarproject.bramble.test.TestUtils.getAgreementPublicKey; import static org.briarproject.bramble.test.TestUtils.getAgreementPublicKey;
import static org.briarproject.bramble.test.TestUtils.getRandomBytes; import static org.briarproject.bramble.test.TestUtils.getRandomBytes;
import static org.briarproject.bramble.test.TestUtils.getRandomId; 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.bramble.util.StringUtils.getRandomString;
import static org.briarproject.briar.api.introduction.IntroductionConstants.MAX_INTRODUCTION_TEXT_LENGTH; import static org.briarproject.briar.api.introduction.IntroductionConstants.MAX_INTRODUCTION_TEXT_LENGTH;
import static org.briarproject.briar.introduction.MessageType.ABORT; 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 BdfDictionary meta = new BdfDictionary();
private final PublicKey ephemeralPublicKey = getAgreementPublicKey(); private final PublicKey ephemeralPublicKey = getAgreementPublicKey();
private final long acceptTimestamp = 42; private final long acceptTimestamp = 42;
private final TransportId transportId = getTransportId();
private final BdfDictionary transportProperties = BdfDictionary.of( private final BdfDictionary transportProperties = BdfDictionary.of(
new BdfEntry("transportId", new BdfDictionary()) new BdfEntry(transportId.getString(), new BdfDictionary())
); );
private final Map<TransportId, TransportProperties> transportPropertiesMap =
singletonMap(transportId, new TransportProperties());
private final byte[] mac = getRandomBytes(MAC_BYTES); private final byte[] mac = getRandomBytes(MAC_BYTES);
private final byte[] signature = getRandomBytes(MAX_SIGNATURE_BYTES); private final byte[] signature = getRandomBytes(MAX_SIGNATURE_BYTES);
@@ -60,7 +72,7 @@ public class IntroductionValidatorTest extends ValidatorTestCase {
authorList, text); authorList, text);
expectParseAuthor(authorList, author); expectParseAuthor(authorList, author);
expectEncodeRequestMetadata(); expectEncodeRequestMetadata(NO_AUTO_DELETE_TIMER);
BdfMessageContext messageContext = BdfMessageContext messageContext =
validator.validateMessage(message, group, body); validator.validateMessage(message, group, body);
@@ -72,7 +84,7 @@ public class IntroductionValidatorTest extends ValidatorTestCase {
BdfList body = BdfList.of(REQUEST.getValue(), null, authorList, text); BdfList body = BdfList.of(REQUEST.getValue(), null, authorList, text);
expectParseAuthor(authorList, author); expectParseAuthor(authorList, author);
expectEncodeRequestMetadata(); expectEncodeRequestMetadata(NO_AUTO_DELETE_TIMER);
BdfMessageContext messageContext = BdfMessageContext messageContext =
validator.validateMessage(message, group, body); validator.validateMessage(message, group, body);
@@ -84,13 +96,42 @@ public class IntroductionValidatorTest extends ValidatorTestCase {
BdfList body = BdfList.of(REQUEST.getValue(), null, authorList, null); BdfList body = BdfList.of(REQUEST.getValue(), null, authorList, null);
expectParseAuthor(authorList, author); expectParseAuthor(authorList, author);
expectEncodeRequestMetadata(); expectEncodeRequestMetadata(NO_AUTO_DELETE_TIMER);
BdfMessageContext messageContext = BdfMessageContext messageContext =
validator.validateMessage(message, group, body); validator.validateMessage(message, group, body);
assertExpectedContext(messageContext, null); 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) @Test(expected = FormatException.class)
public void testRejectsTooShortBodyForRequest() throws Exception { public void testRejectsTooShortBodyForRequest() throws Exception {
BdfList body = BdfList.of(REQUEST.getValue(), null, authorList); BdfList body = BdfList.of(REQUEST.getValue(), null, authorList);
@@ -99,8 +140,8 @@ public class IntroductionValidatorTest extends ValidatorTestCase {
@Test(expected = FormatException.class) @Test(expected = FormatException.class)
public void testRejectsTooLongBodyForRequest() throws Exception { public void testRejectsTooLongBodyForRequest() throws Exception {
BdfList body = BdfList body = BdfList.of(REQUEST.getValue(), null, authorList, text,
BdfList.of(REQUEST.getValue(), null, authorList, text, null); null, null);
validator.validateMessage(message, group, body); validator.validateMessage(message, group, body);
} }
@@ -119,6 +160,32 @@ public class IntroductionValidatorTest extends ValidatorTestCase {
validator.validateMessage(message, group, body); 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 // Introduction ACCEPT
// //
@@ -129,11 +196,38 @@ public class IntroductionValidatorTest extends ValidatorTestCase {
previousMsgId.getBytes(), ephemeralPublicKey.getEncoded(), previousMsgId.getBytes(), ephemeralPublicKey.getEncoded(),
acceptTimestamp, transportProperties); acceptTimestamp, transportProperties);
expectParsePublicKey(); expectParsePublicKey();
context.checking(new Expectations() {{ expectParseTransportProperties();
oneOf(clientHelper).parseAndValidateTransportPropertiesMap( expectEncodeMetadata(ACCEPT, NO_AUTO_DELETE_TIMER);
transportProperties); BdfMessageContext messageContext =
}}); validator.validateMessage(message, group, body);
expectEncodeMetadata(ACCEPT);
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 = BdfMessageContext messageContext =
validator.validateMessage(message, group, body); validator.validateMessage(message, group, body);
@@ -152,7 +246,7 @@ public class IntroductionValidatorTest extends ValidatorTestCase {
public void testRejectsTooLongBodyForAccept() throws Exception { public void testRejectsTooLongBodyForAccept() throws Exception {
BdfList body = BdfList.of(ACCEPT.getValue(), sessionId.getBytes(), BdfList body = BdfList.of(ACCEPT.getValue(), sessionId.getBytes(),
previousMsgId.getBytes(), ephemeralPublicKey.getEncoded(), previousMsgId.getBytes(), ephemeralPublicKey.getEncoded(),
acceptTimestamp, transportProperties, null); acceptTimestamp, transportProperties, null, null);
validator.validateMessage(message, group, body); validator.validateMessage(message, group, body);
} }
@@ -200,6 +294,40 @@ public class IntroductionValidatorTest extends ValidatorTestCase {
validator.validateMessage(message, group, body); 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 // Introduction DECLINE
// //
@@ -209,7 +337,35 @@ public class IntroductionValidatorTest extends ValidatorTestCase {
BdfList body = BdfList.of(DECLINE.getValue(), sessionId.getBytes(), BdfList body = BdfList.of(DECLINE.getValue(), sessionId.getBytes(),
previousMsgId.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 = BdfMessageContext messageContext =
validator.validateMessage(message, group, body); validator.validateMessage(message, group, body);
@@ -225,7 +381,7 @@ public class IntroductionValidatorTest extends ValidatorTestCase {
@Test(expected = FormatException.class) @Test(expected = FormatException.class)
public void testRejectsTooLongBodyForDecline() throws Exception { public void testRejectsTooLongBodyForDecline() throws Exception {
BdfList body = BdfList.of(DECLINE.getValue(), sessionId.getBytes(), BdfList body = BdfList.of(DECLINE.getValue(), sessionId.getBytes(),
previousMsgId.getBytes(), null); previousMsgId.getBytes(), null, null);
validator.validateMessage(message, group, body); validator.validateMessage(message, group, body);
} }
@@ -242,6 +398,28 @@ public class IntroductionValidatorTest extends ValidatorTestCase {
validator.validateMessage(message, group, body); 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 // Introduction AUTH
// //
@@ -251,7 +429,7 @@ public class IntroductionValidatorTest extends ValidatorTestCase {
BdfList body = BdfList.of(AUTH.getValue(), sessionId.getBytes(), BdfList body = BdfList.of(AUTH.getValue(), sessionId.getBytes(),
previousMsgId.getBytes(), mac, signature); previousMsgId.getBytes(), mac, signature);
expectEncodeMetadata(AUTH); expectEncodeMetadata(AUTH, NO_AUTO_DELETE_TIMER);
BdfMessageContext messageContext = BdfMessageContext messageContext =
validator.validateMessage(message, group, body); validator.validateMessage(message, group, body);
@@ -340,7 +518,7 @@ public class IntroductionValidatorTest extends ValidatorTestCase {
BdfList body = BdfList.of(ACTIVATE.getValue(), sessionId.getBytes(), BdfList body = BdfList.of(ACTIVATE.getValue(), sessionId.getBytes(),
previousMsgId.getBytes(), mac); previousMsgId.getBytes(), mac);
expectEncodeMetadata(ACTIVATE); expectEncodeMetadata(ACTIVATE, NO_AUTO_DELETE_TIMER);
BdfMessageContext messageContext = BdfMessageContext messageContext =
validator.validateMessage(message, group, body); validator.validateMessage(message, group, body);
@@ -398,7 +576,7 @@ public class IntroductionValidatorTest extends ValidatorTestCase {
BdfList body = BdfList.of(ABORT.getValue(), sessionId.getBytes(), BdfList body = BdfList.of(ABORT.getValue(), sessionId.getBytes(),
previousMsgId.getBytes()); previousMsgId.getBytes());
expectEncodeMetadata(ABORT); expectEncodeMetadata(ABORT, NO_AUTO_DELETE_TIMER);
BdfMessageContext messageContext = BdfMessageContext messageContext =
validator.validateMessage(message, group, body); validator.validateMessage(message, group, body);
@@ -442,17 +620,28 @@ public class IntroductionValidatorTest extends ValidatorTestCase {
will(returnValue(ephemeralPublicKey)); will(returnValue(ephemeralPublicKey));
}}); }});
} }
private void expectEncodeRequestMetadata() {
private void expectParseTransportProperties() throws Exception {
context.checking(new Expectations() {{ 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)); will(returnValue(meta));
}}); }});
} }
private void expectEncodeMetadata(MessageType type) { private void expectEncodeMetadata(MessageType type, long autoDeleteTimer) {
context.checking(new Expectations() {{ context.checking(new Expectations() {{
oneOf(messageEncoder).encodeMetadata(type, sessionId, oneOf(messageEncoder).encodeMetadata(type, sessionId,
message.getTimestamp(), false, false, false); message.getTimestamp(), false, false, false,
autoDeleteTimer);
will(returnValue(meta)); will(returnValue(meta));
}}); }});
} }

View File

@@ -23,6 +23,9 @@ import java.util.Map;
import javax.inject.Inject; 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.MAC_BYTES;
import static org.briarproject.bramble.api.crypto.CryptoConstants.MAX_SIGNATURE_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.getAgreementPublicKey;
@@ -87,8 +90,8 @@ public class MessageEncoderParserIntegrationTest extends BrambleTestCase {
@Test @Test
public void testRequestMessageMetadata() throws FormatException { public void testRequestMessageMetadata() throws FormatException {
BdfDictionary d = messageEncoder BdfDictionary d = messageEncoder.encodeRequestMetadata(timestamp,
.encodeRequestMetadata(timestamp); MIN_AUTO_DELETE_TIMER_MS);
MessageMetadata meta = messageParser.parseMetadata(d); MessageMetadata meta = messageParser.parseMetadata(d);
assertEquals(REQUEST, meta.getMessageType()); assertEquals(REQUEST, meta.getMessageType());
@@ -98,13 +101,13 @@ public class MessageEncoderParserIntegrationTest extends BrambleTestCase {
assertFalse(meta.isRead()); assertFalse(meta.isRead());
assertFalse(meta.isVisibleInConversation()); assertFalse(meta.isVisibleInConversation());
assertFalse(meta.isAvailableToAnswer()); assertFalse(meta.isAvailableToAnswer());
assertEquals(MIN_AUTO_DELETE_TIMER_MS, meta.getAutoDeleteTimer());
} }
@Test @Test
public void testMessageMetadata() throws FormatException { public void testMessageMetadata() throws FormatException {
BdfDictionary d = messageEncoder BdfDictionary d = messageEncoder.encodeMetadata(ABORT, sessionId,
.encodeMetadata(ABORT, sessionId, timestamp, false, true, timestamp, false, true, false, MAX_AUTO_DELETE_TIMER_MS);
false);
MessageMetadata meta = messageParser.parseMetadata(d); MessageMetadata meta = messageParser.parseMetadata(d);
assertEquals(ABORT, meta.getMessageType()); assertEquals(ABORT, meta.getMessageType());
@@ -114,6 +117,7 @@ public class MessageEncoderParserIntegrationTest extends BrambleTestCase {
assertTrue(meta.isRead()); assertTrue(meta.isRead());
assertFalse(meta.isVisibleInConversation()); assertFalse(meta.isVisibleInConversation());
assertFalse(meta.isAvailableToAnswer()); assertFalse(meta.isAvailableToAnswer());
assertEquals(MAX_AUTO_DELETE_TIMER_MS, meta.getAutoDeleteTimer());
} }
@Test @Test
@@ -131,6 +135,42 @@ public class MessageEncoderParserIntegrationTest extends BrambleTestCase {
assertEquals(previousMsgId, rm.getPreviousMessageId()); assertEquals(previousMsgId, rm.getPreviousMessageId());
assertEquals(author, rm.getAuthor()); assertEquals(author, rm.getAuthor());
assertEquals(text, rm.getText()); 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 @Test
@@ -142,6 +182,7 @@ public class MessageEncoderParserIntegrationTest extends BrambleTestCase {
messageParser.parseRequestMessage(m, clientHelper.toList(m)); messageParser.parseRequestMessage(m, clientHelper.toList(m));
assertNull(rm.getPreviousMessageId()); assertNull(rm.getPreviousMessageId());
assertEquals(NO_AUTO_DELETE_TIMER, rm.getAutoDeleteTimer());
} }
@Test @Test
@@ -154,6 +195,7 @@ public class MessageEncoderParserIntegrationTest extends BrambleTestCase {
messageParser.parseRequestMessage(m, clientHelper.toList(m)); messageParser.parseRequestMessage(m, clientHelper.toList(m));
assertNull(rm.getText()); assertNull(rm.getText());
assertEquals(NO_AUTO_DELETE_TIMER, rm.getAutoDeleteTimer());
} }
@Test @Test
@@ -179,6 +221,57 @@ public class MessageEncoderParserIntegrationTest extends BrambleTestCase {
am.getEphemeralPublicKey().getEncoded()); am.getEphemeralPublicKey().getEncoded());
assertEquals(acceptTimestamp, am.getAcceptTimestamp()); assertEquals(acceptTimestamp, am.getAcceptTimestamp());
assertEquals(transportProperties, am.getTransportProperties()); 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 @Test
@@ -195,6 +288,39 @@ public class MessageEncoderParserIntegrationTest extends BrambleTestCase {
assertEquals(m.getTimestamp(), dm.getTimestamp()); assertEquals(m.getTimestamp(), dm.getTimestamp());
assertEquals(previousMsgId, dm.getPreviousMessageId()); assertEquals(previousMsgId, dm.getPreviousMessageId());
assertEquals(sessionId, dm.getSessionId()); 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 @Test
@@ -213,6 +339,7 @@ public class MessageEncoderParserIntegrationTest extends BrambleTestCase {
assertEquals(sessionId, am.getSessionId()); assertEquals(sessionId, am.getSessionId());
assertArrayEquals(mac, am.getMac()); assertArrayEquals(mac, am.getMac());
assertArrayEquals(signature, am.getSignature()); assertArrayEquals(signature, am.getSignature());
assertEquals(NO_AUTO_DELETE_TIMER, am.getAutoDeleteTimer());
} }
@Test @Test
@@ -230,6 +357,7 @@ public class MessageEncoderParserIntegrationTest extends BrambleTestCase {
assertEquals(previousMsgId, am.getPreviousMessageId()); assertEquals(previousMsgId, am.getPreviousMessageId());
assertEquals(sessionId, am.getSessionId()); assertEquals(sessionId, am.getSessionId());
assertArrayEquals(mac, am.getMac()); assertArrayEquals(mac, am.getMac());
assertEquals(NO_AUTO_DELETE_TIMER, am.getAutoDeleteTimer());
} }
@Test @Test
@@ -246,5 +374,6 @@ public class MessageEncoderParserIntegrationTest extends BrambleTestCase {
assertEquals(m.getTimestamp(), am.getTimestamp()); assertEquals(m.getTimestamp(), am.getTimestamp());
assertEquals(previousMsgId, am.getPreviousMessageId()); assertEquals(previousMsgId, am.getPreviousMessageId());
assertEquals(sessionId, am.getSessionId()); assertEquals(sessionId, am.getSessionId());
assertEquals(NO_AUTO_DELETE_TIMER, am.getAutoDeleteTimer());
} }
} }

View File

@@ -97,7 +97,8 @@ internal class WebSocketControllerTest : ControllerTest() {
author, author,
text, text,
false, false,
AuthorInfo(VERIFIED) AuthorInfo(VERIFIED),
NO_AUTO_DELETE_TIMER
) )
val introductionRequestEvent = val introductionRequestEvent =
IntroductionRequestReceivedEvent(introductionRequest, contact.id) IntroductionRequestReceivedEvent(introductionRequest, contact.id)

View File

@@ -89,7 +89,7 @@ internal class MessagingControllerImplTest : ControllerTest() {
fun listIntroductionRequest() { fun listIntroductionRequest() {
val request = IntroductionRequest( val request = IntroductionRequest(
message.id, group.id, timestamp, true, true, true, false, sessionId, author, text, message.id, group.id, timestamp, true, true, true, false, sessionId, author, text,
false, AuthorInfo(UNVERIFIED) false, AuthorInfo(UNVERIFIED), NO_AUTO_DELETE_TIMER
) )
expectGetContact() expectGetContact()
@@ -330,7 +330,7 @@ internal class MessagingControllerImplTest : ControllerTest() {
fun testIntroductionRequestWithNullText() { fun testIntroductionRequestWithNullText() {
val request = IntroductionRequest( val request = IntroductionRequest(
message.id, group.id, timestamp, true, true, true, false, sessionId, author, null, message.id, group.id, timestamp, true, true, true, false, sessionId, author, null,
false, AuthorInfo(VERIFIED) false, AuthorInfo(VERIFIED), NO_AUTO_DELETE_TIMER
) )
val json = """ val json = """
{ {