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)
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 GroupId groupId;
private final long timestamp;
private final boolean local, sent, seen, read;
private final long timestamp, autoDeleteTimer;
private final boolean local, read, sent, seen;
public ConversationMessageHeader(MessageId id, GroupId groupId, long timestamp,
boolean local, boolean read, boolean sent, boolean seen) {
public ConversationMessageHeader(MessageId id, GroupId groupId,
long timestamp, boolean local, boolean read, boolean sent,
boolean seen, long autoDeleteTimer) {
this.id = id;
this.groupId = groupId;
this.timestamp = timestamp;
this.local = local;
this.read = read;
this.sent = sent;
this.seen = seen;
this.read = read;
this.autoDeleteTimer = autoDeleteTimer;
}
public MessageId getId() {
@@ -55,4 +57,8 @@ public abstract class ConversationMessageHeader {
}
public abstract <T> 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 boolean answered;
public ConversationRequest(MessageId messageId, GroupId groupId, long time,
boolean local, boolean read, boolean sent, boolean seen,
SessionId sessionId, N nameable, @Nullable String text,
boolean answered) {
super(messageId, groupId, time, local, read, sent, seen);
public ConversationRequest(MessageId messageId, GroupId groupId,
long timestamp, boolean local, boolean read, boolean sent,
boolean seen, SessionId sessionId, N nameable,
@Nullable String text, boolean answered, long autoDeleteTimer) {
super(messageId, groupId, timestamp, local, read, sent, seen,
autoDeleteTimer);
this.sessionId = sessionId;
this.nameable = nameable;
this.text = text;

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

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

View File

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

View File

@@ -16,13 +16,16 @@ abstract class AbstractIntroductionMessage {
private final long timestamp;
@Nullable
private final MessageId previousMessageId;
private final long autoDeleteTimer;
AbstractIntroductionMessage(MessageId messageId, GroupId groupId,
long timestamp, @Nullable MessageId previousMessageId) {
long timestamp, @Nullable MessageId previousMessageId,
long autoDeleteTimer) {
this.messageId = messageId;
this.groupId = groupId;
this.timestamp = timestamp;
this.previousMessageId = previousMessageId;
this.autoDeleteTimer = autoDeleteTimer;
}
MessageId getMessageId() {
@@ -42,4 +45,7 @@ abstract class AbstractIntroductionMessage {
return previousMessageId;
}
public long getAutoDeleteTimer() {
return autoDeleteTimer;
}
}

View File

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

View File

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

View File

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

View File

@@ -16,8 +16,9 @@ class DeclineMessage extends AbstractIntroductionMessage {
protected DeclineMessage(MessageId messageId, GroupId groupId,
long timestamp, @Nullable MessageId previousMessageId,
SessionId sessionId) {
super(messageId, groupId, timestamp, previousMessageId);
SessionId sessionId, long autoDeleteTimer) {
super(messageId, groupId, timestamp, previousMessageId,
autoDeleteTimer);
this.sessionId = sessionId;
}

View File

@@ -26,6 +26,7 @@ import org.briarproject.bramble.api.sync.MessageId;
import org.briarproject.bramble.api.system.Clock;
import org.briarproject.bramble.api.transport.KeyManager;
import org.briarproject.bramble.api.transport.KeySetId;
import org.briarproject.bramble.api.versioning.ClientVersioningManager;
import org.briarproject.briar.api.client.MessageTracker;
import org.briarproject.briar.api.client.ProtocolStateException;
import org.briarproject.briar.api.client.SessionId;
@@ -76,10 +77,11 @@ class IntroduceeProtocolEngine
Clock clock,
IntroductionCrypto crypto,
KeyManager keyManager,
TransportPropertyManager transportPropertyManager) {
TransportPropertyManager transportPropertyManager,
ClientVersioningManager clientVersioningManager) {
super(db, clientHelper, contactManager, contactGroupFactory,
messageTracker, identityManager, messageParser, messageEncoder,
clock);
clientVersioningManager, clock);
this.crypto = crypto;
this.keyManager = keyManager;
this.transportPropertyManager = transportPropertyManager;
@@ -258,7 +260,7 @@ class IntroduceeProtocolEngine
IntroductionRequest request = new IntroductionRequest(m.getMessageId(),
m.getGroupId(), m.getTimestamp(), false, false, false, false,
s.getSessionId(), m.getAuthor(), m.getText(), false,
authorInfo);
authorInfo, m.getAutoDeleteTimer());
IntroductionRequestReceivedEvent e =
new IntroductionRequestReceivedEvent(request, c.getId());
txn.attach(e);

View File

@@ -13,6 +13,7 @@ import org.briarproject.bramble.api.sync.GroupId;
import org.briarproject.bramble.api.sync.Message;
import org.briarproject.bramble.api.sync.MessageId;
import org.briarproject.bramble.api.system.Clock;
import org.briarproject.bramble.api.versioning.ClientVersioningManager;
import org.briarproject.briar.api.client.MessageTracker;
import org.briarproject.briar.api.client.ProtocolStateException;
import org.briarproject.briar.api.introduction.event.IntroductionAbortedEvent;
@@ -50,10 +51,11 @@ class IntroducerProtocolEngine
IdentityManager identityManager,
MessageParser messageParser,
MessageEncoder messageEncoder,
ClientVersioningManager clientVersioningManager,
Clock clock) {
super(db, clientHelper, contactManager, contactGroupFactory,
messageTracker, identityManager, messageParser, messageEncoder,
clock);
clientVersioningManager, clock);
}
@Override

View File

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

View File

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

View File

@@ -15,13 +15,18 @@ import org.briarproject.bramble.api.sync.MessageId;
import org.briarproject.bramble.api.system.Clock;
import org.briarproject.briar.api.client.SessionId;
import javax.annotation.Nullable;
import javax.annotation.concurrent.Immutable;
import static java.util.Collections.singletonList;
import static org.briarproject.bramble.api.autodelete.AutoDeleteConstants.MAX_AUTO_DELETE_TIMER_MS;
import static org.briarproject.bramble.api.autodelete.AutoDeleteConstants.MIN_AUTO_DELETE_TIMER_MS;
import static org.briarproject.bramble.api.autodelete.AutoDeleteConstants.NO_AUTO_DELETE_TIMER;
import static org.briarproject.bramble.api.crypto.CryptoConstants.MAC_BYTES;
import static org.briarproject.bramble.api.crypto.CryptoConstants.MAX_SIGNATURE_BYTES;
import static org.briarproject.bramble.api.identity.AuthorConstants.MAX_PUBLIC_KEY_LENGTH;
import static org.briarproject.bramble.util.ValidationUtils.checkLength;
import static org.briarproject.bramble.util.ValidationUtils.checkRange;
import static org.briarproject.bramble.util.ValidationUtils.checkSize;
import static org.briarproject.briar.api.introduction.IntroductionConstants.MAX_INTRODUCTION_TEXT_LENGTH;
import static org.briarproject.briar.introduction.MessageType.ACCEPT;
@@ -52,13 +57,14 @@ class IntroductionValidator extends BdfMessageValidator {
return validateRequestMessage(m, body);
case ACCEPT:
return validateAcceptMessage(m, body);
case DECLINE:
return validateDeclineMessage(type, m, body);
case AUTH:
return validateAuthMessage(m, body);
case ACTIVATE:
return validateActivateMessage(m, body);
case DECLINE:
case ABORT:
return validateOtherMessage(type, m, body);
return validateAbortMessage(type, m, body);
default:
throw new FormatException();
}
@@ -66,7 +72,11 @@ class IntroductionValidator extends BdfMessageValidator {
private BdfMessageContext validateRequestMessage(Message m, BdfList body)
throws FormatException {
checkSize(body, 4);
// Client version 0.0: Message type, optional previous message ID,
// author, optional text.
// Client version 0.1: Message type, optional previous message ID,
// author, optional text, optional auto-delete timer.
checkSize(body, 4, 5);
byte[] previousMessageId = body.getOptionalRaw(1);
checkLength(previousMessageId, UniqueId.LENGTH);
@@ -77,8 +87,11 @@ class IntroductionValidator extends BdfMessageValidator {
String text = body.getOptionalString(3);
checkLength(text, 1, MAX_INTRODUCTION_TEXT_LENGTH);
long timer = NO_AUTO_DELETE_TIMER;
if (body.size() == 5) timer = validateTimer(body.getOptionalLong(4));
BdfDictionary meta =
messageEncoder.encodeRequestMetadata(m.getTimestamp());
messageEncoder.encodeRequestMetadata(m.getTimestamp(), timer);
if (previousMessageId == null) {
return new BdfMessageContext(meta);
} else {
@@ -89,7 +102,12 @@ class IntroductionValidator extends BdfMessageValidator {
private BdfMessageContext validateAcceptMessage(Message m, BdfList body)
throws FormatException {
checkSize(body, 6);
// Client version 0.0: Message type, session ID, optional previous
// message ID, ephemeral public key, timestamp, transport properties.
// Client version 0.1: Message type, session ID, optional previous
// message ID, ephemeral public key, timestamp, transport properties,
// optional auto-delete timer.
checkSize(body, 6, 7);
byte[] sessionIdBytes = body.getRaw(1);
checkLength(sessionIdBytes, UniqueId.LENGTH);
@@ -109,9 +127,40 @@ class IntroductionValidator extends BdfMessageValidator {
clientHelper
.parseAndValidateTransportPropertiesMap(transportProperties);
long timer = NO_AUTO_DELETE_TIMER;
if (body.size() == 7) timer = validateTimer(body.getOptionalLong(6));
SessionId sessionId = new SessionId(sessionIdBytes);
BdfDictionary meta = messageEncoder.encodeMetadata(ACCEPT, sessionId,
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) {
return new BdfMessageContext(meta);
} else {
@@ -138,7 +187,7 @@ class IntroductionValidator extends BdfMessageValidator {
SessionId sessionId = new SessionId(sessionIdBytes);
BdfDictionary meta = messageEncoder.encodeMetadata(AUTH, sessionId,
m.getTimestamp(), false, false, false);
m.getTimestamp(), false, false, false, NO_AUTO_DELETE_TIMER);
MessageId dependency = new MessageId(previousMessageId);
return new BdfMessageContext(meta, singletonList(dependency));
}
@@ -158,7 +207,7 @@ class IntroductionValidator extends BdfMessageValidator {
SessionId sessionId = new SessionId(sessionIdBytes);
BdfDictionary meta = messageEncoder.encodeMetadata(ACTIVATE, sessionId,
m.getTimestamp(), false, false, false);
m.getTimestamp(), false, false, false, NO_AUTO_DELETE_TIMER);
if (previousMessageId == null) {
return new BdfMessageContext(meta);
} else {
@@ -167,7 +216,7 @@ class IntroductionValidator extends BdfMessageValidator {
}
}
private BdfMessageContext validateOtherMessage(MessageType type,
private BdfMessageContext validateAbortMessage(MessageType type,
Message m, BdfList body) throws FormatException {
checkSize(body, 3);
@@ -179,7 +228,7 @@ class IntroductionValidator extends BdfMessageValidator {
SessionId sessionId = new SessionId(sessionIdBytes);
BdfDictionary meta = messageEncoder.encodeMetadata(type, sessionId,
m.getTimestamp(), false, false, false);
m.getTimestamp(), false, false, false, NO_AUTO_DELETE_TIMER);
if (previousMessageId == null) {
return new BdfMessageContext(meta);
} else {
@@ -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
interface MessageEncoder {
BdfDictionary encodeRequestMetadata(long timestamp);
BdfDictionary encodeRequestMetadata(long timestamp,
long autoDeleteTimer);
BdfDictionary encodeMetadata(MessageType type,
@Nullable SessionId sessionId, long timestamp, boolean local,
boolean read, boolean visible);
boolean read, boolean visible, long autoDeleteTimer);
void addSessionId(BdfDictionary meta, SessionId sessionId);
@@ -30,18 +31,53 @@ interface MessageEncoder {
void setAvailableToAnswer(BdfDictionary meta, boolean available);
/**
* Encodes a request message without an auto-delete timer.
*/
Message encodeRequestMessage(GroupId contactGroupId, long timestamp,
@Nullable MessageId previousMessageId, Author author,
@Nullable String text);
/**
* Encodes a request message with an optional auto-delete timer. This
* requires the contact to support client version 0.1 or higher.
*/
Message encodeRequestMessage(GroupId contactGroupId, long timestamp,
@Nullable MessageId previousMessageId, Author author,
@Nullable String text, long autoDeleteTimer);
/**
* Encodes an accept message without an auto-delete timer.
*/
Message encodeAcceptMessage(GroupId contactGroupId, long timestamp,
@Nullable MessageId previousMessageId, SessionId sessionId,
PublicKey ephemeralPublicKey, long acceptTimestamp,
Map<TransportId, TransportProperties> transportProperties);
/**
* Encodes an accept message with an optional auto-delete timer. This
* requires the contact to support client version 0.1 or higher.
*/
Message encodeAcceptMessage(GroupId contactGroupId, long timestamp,
@Nullable MessageId previousMessageId, SessionId sessionId,
PublicKey ephemeralPublicKey, long acceptTimestamp,
Map<TransportId, TransportProperties> transportProperties,
long autoDeleteTimer);
/**
* Encodes a decline message without an auto-delete timer.
*/
Message encodeDeclineMessage(GroupId contactGroupId, long timestamp,
@Nullable MessageId previousMessageId, SessionId sessionId);
/**
* Encodes a decline message with an optional auto-delete timer. This
* requires the contact to support client version 0.1 or higher.
*/
Message encodeDeclineMessage(GroupId contactGroupId, long timestamp,
@Nullable MessageId previousMessageId, SessionId sessionId,
long autoDeleteTimer);
Message encodeAuthMessage(GroupId contactGroupId, long timestamp,
@Nullable MessageId previousMessageId, SessionId sessionId,
byte[] mac, byte[] signature);

View File

@@ -20,7 +20,9 @@ import java.util.Map;
import javax.annotation.Nullable;
import javax.inject.Inject;
import static org.briarproject.bramble.api.autodelete.AutoDeleteConstants.NO_AUTO_DELETE_TIMER;
import static org.briarproject.briar.client.MessageTrackerConstants.MSG_KEY_READ;
import static org.briarproject.briar.introduction.IntroductionConstants.MSG_KEY_AUTO_DELETE_TIMER;
import static org.briarproject.briar.introduction.IntroductionConstants.MSG_KEY_AVAILABLE_TO_ANSWER;
import static org.briarproject.briar.introduction.IntroductionConstants.MSG_KEY_LOCAL;
import static org.briarproject.briar.introduction.IntroductionConstants.MSG_KEY_MESSAGE_TYPE;
@@ -48,9 +50,10 @@ class MessageEncoderImpl implements MessageEncoder {
}
@Override
public BdfDictionary encodeRequestMetadata(long timestamp) {
BdfDictionary meta =
encodeMetadata(REQUEST, null, timestamp, false, false, false);
public BdfDictionary encodeRequestMetadata(long timestamp,
long autoDeleteTimer) {
BdfDictionary meta = encodeMetadata(REQUEST, null, timestamp,
false, false, false, autoDeleteTimer);
meta.put(MSG_KEY_AVAILABLE_TO_ANSWER, false);
return meta;
}
@@ -58,7 +61,7 @@ class MessageEncoderImpl implements MessageEncoder {
@Override
public BdfDictionary encodeMetadata(MessageType type,
@Nullable SessionId sessionId, long timestamp, boolean local,
boolean read, boolean visible) {
boolean read, boolean visible, long autoDeleteTimer) {
BdfDictionary meta = new BdfDictionary();
meta.put(MSG_KEY_MESSAGE_TYPE, type.getValue());
if (sessionId != null)
@@ -69,6 +72,9 @@ class MessageEncoderImpl implements MessageEncoder {
meta.put(MSG_KEY_LOCAL, local);
meta.put(MSG_KEY_READ, read);
meta.put(MSG_KEY_VISIBLE_IN_UI, visible);
if (autoDeleteTimer != NO_AUTO_DELETE_TIMER) {
meta.put(MSG_KEY_AUTO_DELETE_TIMER, autoDeleteTimer);
}
return meta;
}
@@ -103,6 +109,23 @@ class MessageEncoderImpl implements MessageEncoder {
return createMessage(contactGroupId, timestamp, body);
}
@Override
public Message encodeRequestMessage(GroupId contactGroupId, long timestamp,
@Nullable MessageId previousMessageId, Author author,
@Nullable String text, long autoDeleteTimer) {
if (text != null && text.isEmpty()) {
throw new IllegalArgumentException();
}
BdfList body = BdfList.of(
REQUEST.getValue(),
previousMessageId,
clientHelper.toList(author),
text,
encodeTimer(autoDeleteTimer)
);
return createMessage(contactGroupId, timestamp, body);
}
@Override
public Message encodeAcceptMessage(GroupId contactGroupId, long timestamp,
@Nullable MessageId previousMessageId, SessionId sessionId,
@@ -119,11 +142,46 @@ class MessageEncoderImpl implements MessageEncoder {
return createMessage(contactGroupId, timestamp, body);
}
@Override
public Message encodeAcceptMessage(GroupId contactGroupId, long timestamp,
@Nullable MessageId previousMessageId, SessionId sessionId,
PublicKey ephemeralPublicKey, long acceptTimestamp,
Map<TransportId, TransportProperties> transportProperties,
long autoDeleteTimer) {
BdfList body = BdfList.of(
ACCEPT.getValue(),
sessionId,
previousMessageId,
ephemeralPublicKey.getEncoded(),
acceptTimestamp,
clientHelper.toDictionary(transportProperties),
encodeTimer(autoDeleteTimer)
);
return createMessage(contactGroupId, timestamp, body);
}
@Override
public Message encodeDeclineMessage(GroupId contactGroupId, long timestamp,
@Nullable MessageId previousMessageId, SessionId sessionId) {
return encodeMessage(DECLINE, contactGroupId, sessionId, timestamp,
previousMessageId);
BdfList body = BdfList.of(
DECLINE.getValue(),
sessionId,
previousMessageId
);
return createMessage(contactGroupId, timestamp, body);
}
@Override
public Message encodeDeclineMessage(GroupId contactGroupId, long timestamp,
@Nullable MessageId previousMessageId, SessionId sessionId,
long autoDeleteTimer) {
BdfList body = BdfList.of(
DECLINE.getValue(),
sessionId,
previousMessageId,
encodeTimer(autoDeleteTimer)
);
return createMessage(contactGroupId, timestamp, body);
}
@Override
@@ -156,15 +214,8 @@ class MessageEncoderImpl implements MessageEncoder {
@Override
public Message encodeAbortMessage(GroupId contactGroupId, long timestamp,
@Nullable MessageId previousMessageId, SessionId sessionId) {
return encodeMessage(ABORT, contactGroupId, sessionId, timestamp,
previousMessageId);
}
private Message encodeMessage(MessageType type, GroupId contactGroupId,
SessionId sessionId, long timestamp,
@Nullable MessageId previousMessageId) {
BdfList body = BdfList.of(
type.getValue(),
ABORT.getValue(),
sessionId,
previousMessageId
);
@@ -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;
@Nullable
private final SessionId sessionId;
private final long timestamp;
private final long timestamp, autoDeleteTimer;
private final boolean local, read, visible, available;
MessageMetadata(MessageType type, @Nullable SessionId sessionId,
long timestamp, boolean local, boolean read, boolean visible,
boolean available) {
boolean available, long autoDeleteTimer) {
this.type = type;
this.sessionId = sessionId;
this.timestamp = timestamp;
@@ -26,6 +26,7 @@ class MessageMetadata {
this.read = read;
this.visible = visible;
this.available = available;
this.autoDeleteTimer = autoDeleteTimer;
}
MessageType getMessageType() {
@@ -57,4 +58,7 @@ class MessageMetadata {
return available;
}
public long getAutoDeleteTimer() {
return autoDeleteTimer;
}
}

View File

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

View File

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

View File

@@ -28,6 +28,7 @@ import static org.briarproject.bramble.api.autodelete.AutoDeleteConstants.MIN_AU
import static org.briarproject.bramble.api.sync.SyncConstants.MAX_MESSAGE_BODY_LENGTH;
import static org.briarproject.bramble.api.transport.TransportConstants.MAX_CLOCK_DIFFERENCE;
import static org.briarproject.bramble.util.ValidationUtils.checkLength;
import static org.briarproject.bramble.util.ValidationUtils.checkRange;
import static org.briarproject.bramble.util.ValidationUtils.checkSize;
import static org.briarproject.briar.api.messaging.MessagingConstants.MAX_ATTACHMENTS_PER_MESSAGE;
import static org.briarproject.briar.api.messaging.MessagingConstants.MAX_CONTENT_TYPE_BYTES;
@@ -136,10 +137,10 @@ class PrivateMessageValidator implements MessageValidator {
checkLength(contentType, 1, MAX_CONTENT_TYPE_BYTES);
}
Long timer = null;
if (body.size() == 4) timer = body.getOptionalLong(3);
if (timer != null && (timer < MIN_AUTO_DELETE_TIMER_MS ||
timer > MAX_AUTO_DELETE_TIMER_MS)) {
throw new FormatException();
if (body.size() == 4) {
timer = body.getOptionalLong(3);
checkRange(timer, MIN_AUTO_DELETE_TIMER_MS,
MAX_AUTO_DELETE_TIMER_MS);
}
// Return the metadata
BdfDictionary meta = new BdfDictionary();

View File

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

View File

@@ -6,20 +6,29 @@ import org.briarproject.bramble.api.crypto.PublicKey;
import org.briarproject.bramble.api.data.BdfDictionary;
import org.briarproject.bramble.api.data.BdfEntry;
import org.briarproject.bramble.api.data.BdfList;
import org.briarproject.bramble.api.plugin.TransportId;
import org.briarproject.bramble.api.properties.TransportProperties;
import org.briarproject.bramble.api.sync.MessageId;
import org.briarproject.bramble.test.ValidatorTestCase;
import org.briarproject.briar.api.client.SessionId;
import org.jmock.Expectations;
import org.junit.Test;
import java.util.Map;
import javax.annotation.Nullable;
import static java.util.Collections.singletonMap;
import static org.briarproject.bramble.api.autodelete.AutoDeleteConstants.MAX_AUTO_DELETE_TIMER_MS;
import static org.briarproject.bramble.api.autodelete.AutoDeleteConstants.MIN_AUTO_DELETE_TIMER_MS;
import static org.briarproject.bramble.api.autodelete.AutoDeleteConstants.NO_AUTO_DELETE_TIMER;
import static org.briarproject.bramble.api.crypto.CryptoConstants.MAC_BYTES;
import static org.briarproject.bramble.api.crypto.CryptoConstants.MAX_AGREEMENT_PUBLIC_KEY_BYTES;
import static org.briarproject.bramble.api.crypto.CryptoConstants.MAX_SIGNATURE_BYTES;
import static org.briarproject.bramble.test.TestUtils.getAgreementPublicKey;
import static org.briarproject.bramble.test.TestUtils.getRandomBytes;
import static org.briarproject.bramble.test.TestUtils.getRandomId;
import static org.briarproject.bramble.test.TestUtils.getTransportId;
import static org.briarproject.bramble.util.StringUtils.getRandomString;
import static org.briarproject.briar.api.introduction.IntroductionConstants.MAX_INTRODUCTION_TEXT_LENGTH;
import static org.briarproject.briar.introduction.MessageType.ABORT;
@@ -44,9 +53,12 @@ public class IntroductionValidatorTest extends ValidatorTestCase {
private final BdfDictionary meta = new BdfDictionary();
private final PublicKey ephemeralPublicKey = getAgreementPublicKey();
private final long acceptTimestamp = 42;
private final TransportId transportId = getTransportId();
private final BdfDictionary transportProperties = BdfDictionary.of(
new BdfEntry("transportId", new BdfDictionary())
new BdfEntry(transportId.getString(), new BdfDictionary())
);
private final Map<TransportId, TransportProperties> transportPropertiesMap =
singletonMap(transportId, new TransportProperties());
private final byte[] mac = getRandomBytes(MAC_BYTES);
private final byte[] signature = getRandomBytes(MAX_SIGNATURE_BYTES);
@@ -60,7 +72,7 @@ public class IntroductionValidatorTest extends ValidatorTestCase {
authorList, text);
expectParseAuthor(authorList, author);
expectEncodeRequestMetadata();
expectEncodeRequestMetadata(NO_AUTO_DELETE_TIMER);
BdfMessageContext messageContext =
validator.validateMessage(message, group, body);
@@ -72,7 +84,7 @@ public class IntroductionValidatorTest extends ValidatorTestCase {
BdfList body = BdfList.of(REQUEST.getValue(), null, authorList, text);
expectParseAuthor(authorList, author);
expectEncodeRequestMetadata();
expectEncodeRequestMetadata(NO_AUTO_DELETE_TIMER);
BdfMessageContext messageContext =
validator.validateMessage(message, group, body);
@@ -84,13 +96,42 @@ public class IntroductionValidatorTest extends ValidatorTestCase {
BdfList body = BdfList.of(REQUEST.getValue(), null, authorList, null);
expectParseAuthor(authorList, author);
expectEncodeRequestMetadata();
expectEncodeRequestMetadata(NO_AUTO_DELETE_TIMER);
BdfMessageContext messageContext =
validator.validateMessage(message, group, body);
assertExpectedContext(messageContext, null);
}
@Test
public void testAcceptsRequestWithNullAutoDeleteTimer() throws Exception {
testAcceptsRequestWithAutoDeleteTimer(null);
}
@Test
public void testAcceptsRequestWithMinAutoDeleteTimer() throws Exception {
testAcceptsRequestWithAutoDeleteTimer(MIN_AUTO_DELETE_TIMER_MS);
}
@Test
public void testAcceptsRequestWithMaxAutoDeleteTimer() throws Exception {
testAcceptsRequestWithAutoDeleteTimer(MAX_AUTO_DELETE_TIMER_MS);
}
private void testAcceptsRequestWithAutoDeleteTimer(@Nullable Long timer)
throws Exception {
BdfList body = BdfList.of(REQUEST.getValue(), previousMsgId.getBytes(),
authorList, text, timer);
expectParseAuthor(authorList, author);
long autoDeleteTimer = timer == null ? NO_AUTO_DELETE_TIMER : timer;
expectEncodeRequestMetadata(autoDeleteTimer);
BdfMessageContext messageContext =
validator.validateMessage(message, group, body);
assertExpectedContext(messageContext, previousMsgId);
}
@Test(expected = FormatException.class)
public void testRejectsTooShortBodyForRequest() throws Exception {
BdfList body = BdfList.of(REQUEST.getValue(), null, authorList);
@@ -99,8 +140,8 @@ public class IntroductionValidatorTest extends ValidatorTestCase {
@Test(expected = FormatException.class)
public void testRejectsTooLongBodyForRequest() throws Exception {
BdfList body =
BdfList.of(REQUEST.getValue(), null, authorList, text, null);
BdfList body = BdfList.of(REQUEST.getValue(), null, authorList, text,
null, null);
validator.validateMessage(message, group, body);
}
@@ -119,6 +160,32 @@ public class IntroductionValidatorTest extends ValidatorTestCase {
validator.validateMessage(message, group, body);
}
@Test(expected = FormatException.class)
public void testRejectsRequestWithNonLongAutoDeleteTimer()
throws Exception {
BdfList body = BdfList.of(REQUEST.getValue(), previousMsgId.getBytes(),
authorList, text, "foo");
expectParseAuthor(authorList, author);
validator.validateMessage(message, group, body);
}
@Test(expected = FormatException.class)
public void testRejectsRequestWithTooSmallAutoDeleteTimer()
throws Exception {
BdfList body = BdfList.of(REQUEST.getValue(), previousMsgId.getBytes(),
authorList, text, MIN_AUTO_DELETE_TIMER_MS - 1);
expectParseAuthor(authorList, author);
validator.validateMessage(message, group, body);
}
@Test(expected = FormatException.class)
public void testRejectsRequestWithTooBigAutoDeleteTimer() throws Exception {
BdfList body = BdfList.of(REQUEST.getValue(), previousMsgId.getBytes(),
authorList, text, MAX_AUTO_DELETE_TIMER_MS + 1);
expectParseAuthor(authorList, author);
validator.validateMessage(message, group, body);
}
//
// Introduction ACCEPT
//
@@ -129,11 +196,38 @@ public class IntroductionValidatorTest extends ValidatorTestCase {
previousMsgId.getBytes(), ephemeralPublicKey.getEncoded(),
acceptTimestamp, transportProperties);
expectParsePublicKey();
context.checking(new Expectations() {{
oneOf(clientHelper).parseAndValidateTransportPropertiesMap(
transportProperties);
}});
expectEncodeMetadata(ACCEPT);
expectParseTransportProperties();
expectEncodeMetadata(ACCEPT, NO_AUTO_DELETE_TIMER);
BdfMessageContext messageContext =
validator.validateMessage(message, group, body);
assertExpectedContext(messageContext, previousMsgId);
}
@Test
public void testAcceptsAcceptWithNullAutoDeleteTimer() throws Exception {
testAcceptsAcceptWithAutoDeleteTimer(null);
}
@Test
public void testAcceptsAcceptWithMinAutoDeleteTimer() throws Exception {
testAcceptsAcceptWithAutoDeleteTimer(MIN_AUTO_DELETE_TIMER_MS);
}
@Test
public void testAcceptsAcceptWithMaxAutoDeleteTimer() throws Exception {
testAcceptsAcceptWithAutoDeleteTimer(MAX_AUTO_DELETE_TIMER_MS);
}
private void testAcceptsAcceptWithAutoDeleteTimer(@Nullable Long timer)
throws Exception {
BdfList body = BdfList.of(ACCEPT.getValue(), sessionId.getBytes(),
previousMsgId.getBytes(), ephemeralPublicKey.getEncoded(),
acceptTimestamp, transportProperties, timer);
expectParsePublicKey();
expectParseTransportProperties();
long autoDeleteTimer = timer == null ? NO_AUTO_DELETE_TIMER : timer;
expectEncodeMetadata(ACCEPT, autoDeleteTimer);
BdfMessageContext messageContext =
validator.validateMessage(message, group, body);
@@ -152,7 +246,7 @@ public class IntroductionValidatorTest extends ValidatorTestCase {
public void testRejectsTooLongBodyForAccept() throws Exception {
BdfList body = BdfList.of(ACCEPT.getValue(), sessionId.getBytes(),
previousMsgId.getBytes(), ephemeralPublicKey.getEncoded(),
acceptTimestamp, transportProperties, null);
acceptTimestamp, transportProperties, null, null);
validator.validateMessage(message, group, body);
}
@@ -200,6 +294,40 @@ public class IntroductionValidatorTest extends ValidatorTestCase {
validator.validateMessage(message, group, body);
}
@Test(expected = FormatException.class)
public void testRejectsAcceptWithNonLongAutoDeleteTimer()
throws Exception {
BdfList body = BdfList.of(ACCEPT.getValue(), sessionId.getBytes(),
previousMsgId.getBytes(), ephemeralPublicKey.getEncoded(),
acceptTimestamp, transportProperties, "foo");
expectParsePublicKey();
expectParseTransportProperties();
validator.validateMessage(message, group, body);
}
@Test(expected = FormatException.class)
public void testRejectsAcceptWithTooSmallAutoDeleteTimer()
throws Exception {
BdfList body = BdfList.of(ACCEPT.getValue(), sessionId.getBytes(),
previousMsgId.getBytes(), ephemeralPublicKey.getEncoded(),
acceptTimestamp, transportProperties,
MIN_AUTO_DELETE_TIMER_MS - 1);
expectParsePublicKey();
expectParseTransportProperties();
validator.validateMessage(message, group, body);
}
@Test(expected = FormatException.class)
public void testRejectsAcceptWithTooBigAutoDeleteTimer() throws Exception {
BdfList body = BdfList.of(ACCEPT.getValue(), sessionId.getBytes(),
previousMsgId.getBytes(), ephemeralPublicKey.getEncoded(),
acceptTimestamp, transportProperties,
MAX_AUTO_DELETE_TIMER_MS + 1);
expectParsePublicKey();
expectParseTransportProperties();
validator.validateMessage(message, group, body);
}
//
// Introduction DECLINE
//
@@ -209,7 +337,35 @@ public class IntroductionValidatorTest extends ValidatorTestCase {
BdfList body = BdfList.of(DECLINE.getValue(), sessionId.getBytes(),
previousMsgId.getBytes());
expectEncodeMetadata(DECLINE);
expectEncodeMetadata(DECLINE, NO_AUTO_DELETE_TIMER);
BdfMessageContext messageContext =
validator.validateMessage(message, group, body);
assertExpectedContext(messageContext, previousMsgId);
}
@Test
public void testAcceptsDeclineWithNullAutoDeleteTimer() throws Exception {
testAcceptsDeclineWithAutoDeleteTimer(null);
}
@Test
public void testAcceptsDeclineWithMinAutoDeleteTimer() throws Exception {
testAcceptsDeclineWithAutoDeleteTimer(MIN_AUTO_DELETE_TIMER_MS);
}
@Test
public void testAcceptsDeclineWithMaxAutoDeleteTimer() throws Exception {
testAcceptsDeclineWithAutoDeleteTimer(MAX_AUTO_DELETE_TIMER_MS);
}
private void testAcceptsDeclineWithAutoDeleteTimer(@Nullable Long timer)
throws Exception {
BdfList body = BdfList.of(DECLINE.getValue(), sessionId.getBytes(),
previousMsgId.getBytes(), timer);
long autoDeleteTimer = timer == null ? NO_AUTO_DELETE_TIMER : timer;
expectEncodeMetadata(DECLINE, autoDeleteTimer);
BdfMessageContext messageContext =
validator.validateMessage(message, group, body);
@@ -225,7 +381,7 @@ public class IntroductionValidatorTest extends ValidatorTestCase {
@Test(expected = FormatException.class)
public void testRejectsTooLongBodyForDecline() throws Exception {
BdfList body = BdfList.of(DECLINE.getValue(), sessionId.getBytes(),
previousMsgId.getBytes(), null);
previousMsgId.getBytes(), null, null);
validator.validateMessage(message, group, body);
}
@@ -242,6 +398,28 @@ public class IntroductionValidatorTest extends ValidatorTestCase {
validator.validateMessage(message, group, body);
}
@Test(expected = FormatException.class)
public void testRejectsNonLongAutoDeleteTimerForDecline() throws Exception {
BdfList body = BdfList.of(DECLINE.getValue(), sessionId.getBytes(),
previousMsgId.getBytes(), "foo");
validator.validateMessage(message, group, body);
}
@Test(expected = FormatException.class)
public void testRejectsTooSmallAutoDeleteTimerForDecline()
throws Exception {
BdfList body = BdfList.of(DECLINE.getValue(), sessionId.getBytes(),
previousMsgId.getBytes(), MIN_AUTO_DELETE_TIMER_MS - 1);
validator.validateMessage(message, group, body);
}
@Test(expected = FormatException.class)
public void testRejectsTooBigAutoDeleteTimerForDecline() throws Exception {
BdfList body = BdfList.of(DECLINE.getValue(), sessionId.getBytes(),
previousMsgId.getBytes(), MAX_AUTO_DELETE_TIMER_MS + 1);
validator.validateMessage(message, group, body);
}
//
// Introduction AUTH
//
@@ -251,7 +429,7 @@ public class IntroductionValidatorTest extends ValidatorTestCase {
BdfList body = BdfList.of(AUTH.getValue(), sessionId.getBytes(),
previousMsgId.getBytes(), mac, signature);
expectEncodeMetadata(AUTH);
expectEncodeMetadata(AUTH, NO_AUTO_DELETE_TIMER);
BdfMessageContext messageContext =
validator.validateMessage(message, group, body);
@@ -340,7 +518,7 @@ public class IntroductionValidatorTest extends ValidatorTestCase {
BdfList body = BdfList.of(ACTIVATE.getValue(), sessionId.getBytes(),
previousMsgId.getBytes(), mac);
expectEncodeMetadata(ACTIVATE);
expectEncodeMetadata(ACTIVATE, NO_AUTO_DELETE_TIMER);
BdfMessageContext messageContext =
validator.validateMessage(message, group, body);
@@ -398,7 +576,7 @@ public class IntroductionValidatorTest extends ValidatorTestCase {
BdfList body = BdfList.of(ABORT.getValue(), sessionId.getBytes(),
previousMsgId.getBytes());
expectEncodeMetadata(ABORT);
expectEncodeMetadata(ABORT, NO_AUTO_DELETE_TIMER);
BdfMessageContext messageContext =
validator.validateMessage(message, group, body);
@@ -442,17 +620,28 @@ public class IntroductionValidatorTest extends ValidatorTestCase {
will(returnValue(ephemeralPublicKey));
}});
}
private void expectEncodeRequestMetadata() {
private void expectParseTransportProperties() throws Exception {
context.checking(new Expectations() {{
oneOf(messageEncoder).encodeRequestMetadata(message.getTimestamp());
oneOf(clientHelper).parseAndValidateTransportPropertiesMap(
transportProperties);
will(returnValue(transportPropertiesMap));
}});
}
private void expectEncodeRequestMetadata(long autoDeleteTimer) {
context.checking(new Expectations() {{
oneOf(messageEncoder).encodeRequestMetadata(message.getTimestamp(),
autoDeleteTimer);
will(returnValue(meta));
}});
}
private void expectEncodeMetadata(MessageType type) {
private void expectEncodeMetadata(MessageType type, long autoDeleteTimer) {
context.checking(new Expectations() {{
oneOf(messageEncoder).encodeMetadata(type, sessionId,
message.getTimestamp(), false, false, false);
message.getTimestamp(), false, false, false,
autoDeleteTimer);
will(returnValue(meta));
}});
}

View File

@@ -23,6 +23,9 @@ import java.util.Map;
import javax.inject.Inject;
import static org.briarproject.bramble.api.autodelete.AutoDeleteConstants.MAX_AUTO_DELETE_TIMER_MS;
import static org.briarproject.bramble.api.autodelete.AutoDeleteConstants.MIN_AUTO_DELETE_TIMER_MS;
import static org.briarproject.bramble.api.autodelete.AutoDeleteConstants.NO_AUTO_DELETE_TIMER;
import static org.briarproject.bramble.api.crypto.CryptoConstants.MAC_BYTES;
import static org.briarproject.bramble.api.crypto.CryptoConstants.MAX_SIGNATURE_BYTES;
import static org.briarproject.bramble.test.TestUtils.getAgreementPublicKey;
@@ -87,8 +90,8 @@ public class MessageEncoderParserIntegrationTest extends BrambleTestCase {
@Test
public void testRequestMessageMetadata() throws FormatException {
BdfDictionary d = messageEncoder
.encodeRequestMetadata(timestamp);
BdfDictionary d = messageEncoder.encodeRequestMetadata(timestamp,
MIN_AUTO_DELETE_TIMER_MS);
MessageMetadata meta = messageParser.parseMetadata(d);
assertEquals(REQUEST, meta.getMessageType());
@@ -98,13 +101,13 @@ public class MessageEncoderParserIntegrationTest extends BrambleTestCase {
assertFalse(meta.isRead());
assertFalse(meta.isVisibleInConversation());
assertFalse(meta.isAvailableToAnswer());
assertEquals(MIN_AUTO_DELETE_TIMER_MS, meta.getAutoDeleteTimer());
}
@Test
public void testMessageMetadata() throws FormatException {
BdfDictionary d = messageEncoder
.encodeMetadata(ABORT, sessionId, timestamp, false, true,
false);
BdfDictionary d = messageEncoder.encodeMetadata(ABORT, sessionId,
timestamp, false, true, false, MAX_AUTO_DELETE_TIMER_MS);
MessageMetadata meta = messageParser.parseMetadata(d);
assertEquals(ABORT, meta.getMessageType());
@@ -114,6 +117,7 @@ public class MessageEncoderParserIntegrationTest extends BrambleTestCase {
assertTrue(meta.isRead());
assertFalse(meta.isVisibleInConversation());
assertFalse(meta.isAvailableToAnswer());
assertEquals(MAX_AUTO_DELETE_TIMER_MS, meta.getAutoDeleteTimer());
}
@Test
@@ -131,6 +135,42 @@ public class MessageEncoderParserIntegrationTest extends BrambleTestCase {
assertEquals(previousMsgId, rm.getPreviousMessageId());
assertEquals(author, rm.getAuthor());
assertEquals(text, rm.getText());
assertEquals(NO_AUTO_DELETE_TIMER, rm.getAutoDeleteTimer());
}
@Test
public void testRequestMessageWithAutoDeleteTimer() throws FormatException {
Message m = messageEncoder.encodeRequestMessage(groupId, timestamp,
previousMsgId, author, text, MIN_AUTO_DELETE_TIMER_MS);
validator.validateMessage(m, group, clientHelper.toList(m));
RequestMessage rm =
messageParser.parseRequestMessage(m, clientHelper.toList(m));
assertEquals(m.getId(), rm.getMessageId());
assertEquals(m.getGroupId(), rm.getGroupId());
assertEquals(m.getTimestamp(), rm.getTimestamp());
assertEquals(previousMsgId, rm.getPreviousMessageId());
assertEquals(author, rm.getAuthor());
assertEquals(text, rm.getText());
assertEquals(MIN_AUTO_DELETE_TIMER_MS, rm.getAutoDeleteTimer());
}
@Test
public void testRequestMessageWithoutAutoDeleteTimer()
throws FormatException {
Message m = messageEncoder.encodeRequestMessage(groupId, timestamp,
previousMsgId, author, text, NO_AUTO_DELETE_TIMER);
validator.validateMessage(m, group, clientHelper.toList(m));
RequestMessage rm =
messageParser.parseRequestMessage(m, clientHelper.toList(m));
assertEquals(m.getId(), rm.getMessageId());
assertEquals(m.getGroupId(), rm.getGroupId());
assertEquals(m.getTimestamp(), rm.getTimestamp());
assertEquals(previousMsgId, rm.getPreviousMessageId());
assertEquals(author, rm.getAuthor());
assertEquals(text, rm.getText());
assertEquals(NO_AUTO_DELETE_TIMER, rm.getAutoDeleteTimer());
}
@Test
@@ -142,6 +182,7 @@ public class MessageEncoderParserIntegrationTest extends BrambleTestCase {
messageParser.parseRequestMessage(m, clientHelper.toList(m));
assertNull(rm.getPreviousMessageId());
assertEquals(NO_AUTO_DELETE_TIMER, rm.getAutoDeleteTimer());
}
@Test
@@ -154,6 +195,7 @@ public class MessageEncoderParserIntegrationTest extends BrambleTestCase {
messageParser.parseRequestMessage(m, clientHelper.toList(m));
assertNull(rm.getText());
assertEquals(NO_AUTO_DELETE_TIMER, rm.getAutoDeleteTimer());
}
@Test
@@ -179,6 +221,57 @@ public class MessageEncoderParserIntegrationTest extends BrambleTestCase {
am.getEphemeralPublicKey().getEncoded());
assertEquals(acceptTimestamp, am.getAcceptTimestamp());
assertEquals(transportProperties, am.getTransportProperties());
assertEquals(NO_AUTO_DELETE_TIMER, am.getAutoDeleteTimer());
}
@Test
public void testAcceptMessageWithAutoDeleteTimer() throws Exception {
Map<TransportId, TransportProperties> transportProperties =
getTransportPropertiesMap(2);
long acceptTimestamp = 1337L;
Message m = messageEncoder.encodeAcceptMessage(groupId, timestamp,
previousMsgId, sessionId, ephemeralPublicKey,
acceptTimestamp, transportProperties, MAX_AUTO_DELETE_TIMER_MS);
validator.validateMessage(m, group, clientHelper.toList(m));
AcceptMessage am =
messageParser.parseAcceptMessage(m, clientHelper.toList(m));
assertEquals(m.getId(), am.getMessageId());
assertEquals(m.getGroupId(), am.getGroupId());
assertEquals(m.getTimestamp(), am.getTimestamp());
assertEquals(previousMsgId, am.getPreviousMessageId());
assertEquals(sessionId, am.getSessionId());
assertArrayEquals(ephemeralPublicKey.getEncoded(),
am.getEphemeralPublicKey().getEncoded());
assertEquals(acceptTimestamp, am.getAcceptTimestamp());
assertEquals(transportProperties, am.getTransportProperties());
assertEquals(MAX_AUTO_DELETE_TIMER_MS, am.getAutoDeleteTimer());
}
@Test
public void testAcceptMessageWithoutAutoDeleteTimer() throws Exception {
Map<TransportId, TransportProperties> transportProperties =
getTransportPropertiesMap(2);
long acceptTimestamp = 1337L;
Message m = messageEncoder.encodeAcceptMessage(groupId, timestamp,
previousMsgId, sessionId, ephemeralPublicKey,
acceptTimestamp, transportProperties, NO_AUTO_DELETE_TIMER);
validator.validateMessage(m, group, clientHelper.toList(m));
AcceptMessage am =
messageParser.parseAcceptMessage(m, clientHelper.toList(m));
assertEquals(m.getId(), am.getMessageId());
assertEquals(m.getGroupId(), am.getGroupId());
assertEquals(m.getTimestamp(), am.getTimestamp());
assertEquals(previousMsgId, am.getPreviousMessageId());
assertEquals(sessionId, am.getSessionId());
assertArrayEquals(ephemeralPublicKey.getEncoded(),
am.getEphemeralPublicKey().getEncoded());
assertEquals(acceptTimestamp, am.getAcceptTimestamp());
assertEquals(transportProperties, am.getTransportProperties());
assertEquals(NO_AUTO_DELETE_TIMER, am.getAutoDeleteTimer());
}
@Test
@@ -195,6 +288,39 @@ public class MessageEncoderParserIntegrationTest extends BrambleTestCase {
assertEquals(m.getTimestamp(), dm.getTimestamp());
assertEquals(previousMsgId, dm.getPreviousMessageId());
assertEquals(sessionId, dm.getSessionId());
assertEquals(NO_AUTO_DELETE_TIMER, dm.getAutoDeleteTimer());
}
@Test
public void testDeclineMessageWithAutoDeleteTimer() throws Exception {
Message m = messageEncoder.encodeDeclineMessage(groupId, timestamp,
previousMsgId, sessionId, MIN_AUTO_DELETE_TIMER_MS);
validator.validateMessage(m, group, clientHelper.toList(m));
DeclineMessage dm =
messageParser.parseDeclineMessage(m, clientHelper.toList(m));
assertEquals(m.getId(), dm.getMessageId());
assertEquals(m.getGroupId(), dm.getGroupId());
assertEquals(m.getTimestamp(), dm.getTimestamp());
assertEquals(previousMsgId, dm.getPreviousMessageId());
assertEquals(sessionId, dm.getSessionId());
assertEquals(MIN_AUTO_DELETE_TIMER_MS, dm.getAutoDeleteTimer());
}
@Test
public void testDeclineMessageWithoutAutoDeleteTimer() throws Exception {
Message m = messageEncoder.encodeDeclineMessage(groupId, timestamp,
previousMsgId, sessionId, NO_AUTO_DELETE_TIMER);
validator.validateMessage(m, group, clientHelper.toList(m));
DeclineMessage dm =
messageParser.parseDeclineMessage(m, clientHelper.toList(m));
assertEquals(m.getId(), dm.getMessageId());
assertEquals(m.getGroupId(), dm.getGroupId());
assertEquals(m.getTimestamp(), dm.getTimestamp());
assertEquals(previousMsgId, dm.getPreviousMessageId());
assertEquals(sessionId, dm.getSessionId());
assertEquals(NO_AUTO_DELETE_TIMER, dm.getAutoDeleteTimer());
}
@Test
@@ -213,6 +339,7 @@ public class MessageEncoderParserIntegrationTest extends BrambleTestCase {
assertEquals(sessionId, am.getSessionId());
assertArrayEquals(mac, am.getMac());
assertArrayEquals(signature, am.getSignature());
assertEquals(NO_AUTO_DELETE_TIMER, am.getAutoDeleteTimer());
}
@Test
@@ -230,6 +357,7 @@ public class MessageEncoderParserIntegrationTest extends BrambleTestCase {
assertEquals(previousMsgId, am.getPreviousMessageId());
assertEquals(sessionId, am.getSessionId());
assertArrayEquals(mac, am.getMac());
assertEquals(NO_AUTO_DELETE_TIMER, am.getAutoDeleteTimer());
}
@Test
@@ -246,5 +374,6 @@ public class MessageEncoderParserIntegrationTest extends BrambleTestCase {
assertEquals(m.getTimestamp(), am.getTimestamp());
assertEquals(previousMsgId, am.getPreviousMessageId());
assertEquals(sessionId, am.getSessionId());
assertEquals(NO_AUTO_DELETE_TIMER, am.getAutoDeleteTimer());
}
}

View File

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

View File

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