Merge branch '1831-self-destruct-timers-private-groups' into '804-self-destructing-messages'

Update private group sharing client to include a self-destruct timer in each message

See merge request briar/briar!1303
This commit is contained in:
Torsten Grote
2020-11-23 17:52:20 +00:00
23 changed files with 608 additions and 241 deletions

View File

@@ -32,7 +32,7 @@ public interface GroupInvitationManager extends ConversationClient {
/** /**
* The current minor version of the private group invitation client. * The current minor version of the private group invitation client.
*/ */
int MINOR_VERSION = 0; int MINOR_VERSION = 1;
/** /**
* Sends an invitation to share the given private group with the given * Sends an invitation to share the given private group with the given

View File

@@ -11,8 +11,6 @@ import org.briarproject.briar.api.sharing.InvitationRequest;
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
public class GroupInvitationRequest extends InvitationRequest<PrivateGroup> { public class GroupInvitationRequest extends InvitationRequest<PrivateGroup> {
@@ -20,9 +18,10 @@ public class GroupInvitationRequest extends InvitationRequest<PrivateGroup> {
public GroupInvitationRequest(MessageId id, GroupId groupId, long time, public GroupInvitationRequest(MessageId id, GroupId groupId, long time,
boolean local, boolean read, boolean sent, boolean seen, boolean local, boolean read, boolean sent, boolean seen,
SessionId sessionId, PrivateGroup shareable, SessionId sessionId, PrivateGroup shareable,
@Nullable String text, boolean available, boolean canBeOpened) { @Nullable String text, boolean available, boolean canBeOpened,
long autoDeleteTimer) {
super(id, groupId, time, local, read, sent, seen, sessionId, shareable, super(id, groupId, time, local, read, sent, seen, sessionId, shareable,
text, available, canBeOpened, NO_AUTO_DELETE_TIMER); text, available, canBeOpened, autoDeleteTimer);
} }
@Override @Override

View File

@@ -9,17 +9,16 @@ import org.briarproject.briar.api.sharing.InvitationResponse;
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
public class GroupInvitationResponse extends InvitationResponse { public class GroupInvitationResponse extends InvitationResponse {
public GroupInvitationResponse(MessageId id, GroupId groupId, long time, public GroupInvitationResponse(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 accept, GroupId shareableId) { SessionId sessionId, boolean accept, GroupId shareableId,
long autoDeleteTimer) {
super(id, groupId, time, local, read, sent, seen, sessionId, super(id, groupId, time, local, read, sent, seen, sessionId,
accept, shareableId, NO_AUTO_DELETE_TIMER); accept, shareableId, autoDeleteTimer);
} }
@Override @Override

View File

@@ -23,14 +23,14 @@ import org.briarproject.briar.api.privategroup.GroupMessageFactory;
import org.briarproject.briar.api.privategroup.PrivateGroup; import org.briarproject.briar.api.privategroup.PrivateGroup;
import org.briarproject.briar.api.privategroup.PrivateGroupFactory; import org.briarproject.briar.api.privategroup.PrivateGroupFactory;
import org.briarproject.briar.api.privategroup.PrivateGroupManager; import org.briarproject.briar.api.privategroup.PrivateGroupManager;
import org.briarproject.briar.api.privategroup.invitation.GroupInvitationManager;
import java.util.Map; 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.briar.api.privategroup.PrivateGroupManager.CLIENT_ID; import static org.briarproject.bramble.api.autodelete.AutoDeleteConstants.NO_AUTO_DELETE_TIMER;
import static org.briarproject.briar.api.privategroup.PrivateGroupManager.MAJOR_VERSION;
import static org.briarproject.briar.privategroup.invitation.GroupInvitationConstants.GROUP_KEY_CONTACT_ID; import static org.briarproject.briar.privategroup.invitation.GroupInvitationConstants.GROUP_KEY_CONTACT_ID;
import static org.briarproject.briar.privategroup.invitation.MessageType.ABORT; import static org.briarproject.briar.privategroup.invitation.MessageType.ABORT;
import static org.briarproject.briar.privategroup.invitation.MessageType.INVITE; import static org.briarproject.briar.privategroup.invitation.MessageType.INVITE;
@@ -39,7 +39,7 @@ import static org.briarproject.briar.privategroup.invitation.MessageType.LEAVE;
@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;
@@ -90,6 +90,7 @@ abstract class AbstractProtocolEngine<S extends Session>
return group.getClientId().equals(PrivateGroupManager.CLIENT_ID); return group.getClientId().equals(PrivateGroupManager.CLIENT_ID);
} }
@SuppressWarnings("BooleanMethodIsAlwaysInverted")
boolean isValidDependency(S session, @Nullable MessageId dependency) { boolean isValidDependency(S session, @Nullable MessageId dependency) {
MessageId expected = session.getLastRemoteMessageId(); MessageId expected = session.getLastRemoteMessageId();
if (dependency == null) return expected == null; if (dependency == null) return expected == null;
@@ -101,44 +102,83 @@ abstract class AbstractProtocolEngine<S extends Session>
// Apply min of preferred visibility and client's visibility // Apply min of preferred visibility and client's visibility
ContactId contactId = getContactId(txn, session.getContactGroupId()); ContactId contactId = getContactId(txn, session.getContactGroupId());
Visibility client = clientVersioningManager.getClientVisibility(txn, Visibility client = clientVersioningManager.getClientVisibility(txn,
contactId, CLIENT_ID, MAJOR_VERSION); contactId, PrivateGroupManager.CLIENT_ID,
PrivateGroupManager.MAJOR_VERSION);
Visibility min = Visibility.min(preferred, client); Visibility min = Visibility.min(preferred, client);
db.setGroupVisibility(txn, contactId, session.getPrivateGroupId(), min); db.setGroupVisibility(txn, contactId, session.getPrivateGroupId(), min);
} }
Message sendInviteMessage(Transaction txn, S session, Message sendInviteMessage(Transaction txn, S s,
@Nullable String text, long timestamp, byte[] signature) @Nullable String text, long timestamp, byte[] signature)
throws DbException { throws DbException {
Group g = db.getGroup(txn, session.getPrivateGroupId()); Group g = db.getGroup(txn, s.getPrivateGroupId());
PrivateGroup privateGroup; PrivateGroup privateGroup;
try { try {
privateGroup = privateGroupFactory.parsePrivateGroup(g); privateGroup = privateGroupFactory.parsePrivateGroup(g);
} catch (FormatException e) { } catch (FormatException e) {
throw new DbException(e); // Invalid group descriptor throw new DbException(e); // Invalid group descriptor
} }
Message m = messageEncoder.encodeInviteMessage( Message m;
session.getContactGroupId(), privateGroup.getId(), if (contactSupportsAutoDeletion(txn, s.getContactGroupId())) {
timestamp, privateGroup.getName(), privateGroup.getCreator(), // TODO: Look up the current auto-delete timer
privateGroup.getSalt(), text, signature); long timer = NO_AUTO_DELETE_TIMER;
sendMessage(txn, m, INVITE, privateGroup.getId(), true); m = messageEncoder.encodeInviteMessage(s.getContactGroupId(),
privateGroup.getId(), timestamp, privateGroup.getName(),
privateGroup.getCreator(), privateGroup.getSalt(), text,
signature, timer);
sendMessage(txn, m, INVITE, privateGroup.getId(), true, timer);
} else {
m = messageEncoder.encodeInviteMessage(s.getContactGroupId(),
privateGroup.getId(), timestamp, privateGroup.getName(),
privateGroup.getCreator(), privateGroup.getSalt(), text,
signature);
sendMessage(txn, m, INVITE, privateGroup.getId(), true,
NO_AUTO_DELETE_TIMER);
}
return m; return m;
} }
Message sendJoinMessage(Transaction txn, S session, boolean visibleInUi) Message sendJoinMessage(Transaction txn, S s, boolean visibleInUi)
throws DbException { throws DbException {
Message m = messageEncoder.encodeJoinMessage( Message m;
session.getContactGroupId(), session.getPrivateGroupId(), if (contactSupportsAutoDeletion(txn, s.getContactGroupId())) {
getLocalTimestamp(session), session.getLastLocalMessageId()); // TODO: Look up the current auto-delete timer if the message is
sendMessage(txn, m, JOIN, session.getPrivateGroupId(), visibleInUi); // visible in the UI (accepting an invitation)
long timer = NO_AUTO_DELETE_TIMER;
m = messageEncoder.encodeJoinMessage(s.getContactGroupId(),
s.getPrivateGroupId(), getLocalTimestamp(s),
s.getLastLocalMessageId(), timer);
sendMessage(txn, m, JOIN, s.getPrivateGroupId(), visibleInUi,
timer);
} else {
m = messageEncoder.encodeJoinMessage(s.getContactGroupId(),
s.getPrivateGroupId(), getLocalTimestamp(s),
s.getLastLocalMessageId());
sendMessage(txn, m, JOIN, s.getPrivateGroupId(), visibleInUi,
NO_AUTO_DELETE_TIMER);
}
return m; return m;
} }
Message sendLeaveMessage(Transaction txn, S session, boolean visibleInUi) Message sendLeaveMessage(Transaction txn, S s, boolean visibleInUi)
throws DbException { throws DbException {
Message m = messageEncoder.encodeLeaveMessage( Message m;
session.getContactGroupId(), session.getPrivateGroupId(), if (contactSupportsAutoDeletion(txn, s.getContactGroupId())) {
getLocalTimestamp(session), session.getLastLocalMessageId()); // TODO: Look up the current auto-delete timer if the message is
sendMessage(txn, m, LEAVE, session.getPrivateGroupId(), visibleInUi); // visible in the UI (declining an invitation)
long timer = NO_AUTO_DELETE_TIMER;
m = messageEncoder.encodeLeaveMessage(s.getContactGroupId(),
s.getPrivateGroupId(), getLocalTimestamp(s),
s.getLastLocalMessageId(), timer);
sendMessage(txn, m, LEAVE, s.getPrivateGroupId(), visibleInUi,
timer);
} else {
m = messageEncoder.encodeLeaveMessage(s.getContactGroupId(),
s.getPrivateGroupId(), getLocalTimestamp(s),
s.getLastLocalMessageId());
sendMessage(txn, m, LEAVE, s.getPrivateGroupId(), visibleInUi,
NO_AUTO_DELETE_TIMER);
}
return m; return m;
} }
@@ -146,7 +186,8 @@ abstract class AbstractProtocolEngine<S extends Session>
Message m = messageEncoder.encodeAbortMessage( Message m = messageEncoder.encodeAbortMessage(
session.getContactGroupId(), session.getPrivateGroupId(), session.getContactGroupId(), session.getPrivateGroupId(),
getLocalTimestamp(session)); getLocalTimestamp(session));
sendMessage(txn, m, ABORT, session.getPrivateGroupId(), false); sendMessage(txn, m, ABORT, session.getPrivateGroupId(), false,
NO_AUTO_DELETE_TIMER);
return m; return m;
} }
@@ -217,11 +258,11 @@ abstract class AbstractProtocolEngine<S extends Session>
} }
private void sendMessage(Transaction txn, Message m, MessageType type, private void sendMessage(Transaction txn, Message m, MessageType type,
GroupId privateGroupId, boolean visibleInConversation) GroupId privateGroupId, boolean visibleInConversation,
throws DbException { long autoDeleteTimer) throws DbException {
BdfDictionary meta = messageEncoder BdfDictionary meta = messageEncoder.encodeMetadata(type,
.encodeMetadata(type, privateGroupId, m.getTimestamp(), true, privateGroupId, m.getTimestamp(), true, true,
true, visibleInConversation, false, false); visibleInConversation, false, false, autoDeleteTimer);
try { try {
clientHelper.addLocalMessage(txn, m, meta, true, false); clientHelper.addLocalMessage(txn, m, meta, true, false);
} catch (FormatException e) { } catch (FormatException e) {
@@ -229,4 +270,21 @@ 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,
GroupInvitationManager.CLIENT_ID,
GroupInvitationManager.MAJOR_VERSION);
// Auto-delete was added in client version 0.1
return minorVersion >= 1;
} catch (FormatException e) {
throw new DbException(e);
}
}
} }

View File

@@ -253,10 +253,10 @@ class CreatorProtocolEngine extends AbstractProtocolEngine<CreatorSession> {
} }
private GroupInvitationResponse createInvitationResponse( private GroupInvitationResponse createInvitationResponse(
GroupInvitationMessage m, boolean accept) { DeletableGroupInvitationMessage m, boolean accept) {
SessionId sessionId = new SessionId(m.getPrivateGroupId().getBytes()); SessionId sessionId = new SessionId(m.getPrivateGroupId().getBytes());
return new GroupInvitationResponse(m.getId(), m.getContactGroupId(), return new GroupInvitationResponse(m.getId(), m.getContactGroupId(),
m.getTimestamp(), false, false, false, false, sessionId, m.getTimestamp(), false, false, false, false, sessionId,
accept, m.getPrivateGroupId()); accept, m.getPrivateGroupId(), m.getAutoDeleteTimer());
} }
} }

View File

@@ -0,0 +1,24 @@
package org.briarproject.briar.privategroup.invitation;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import org.briarproject.bramble.api.sync.GroupId;
import org.briarproject.bramble.api.sync.MessageId;
import javax.annotation.concurrent.Immutable;
@Immutable
@NotNullByDefault
abstract class DeletableGroupInvitationMessage extends GroupInvitationMessage {
private final long autoDeleteTimer;
DeletableGroupInvitationMessage(MessageId id, GroupId contactGroupId,
GroupId privateGroupId, long timestamp, long autoDeleteTimer) {
super(id, contactGroupId, privateGroupId, timestamp);
this.autoDeleteTimer = autoDeleteTimer;
}
public long getAutoDeleteTimer() {
return autoDeleteTimer;
}
}

View File

@@ -13,6 +13,7 @@ interface GroupInvitationConstants {
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_INVITATION_ACCEPTED = "invitationAccepted"; String MSG_KEY_INVITATION_ACCEPTED = "invitationAccepted";
String MSG_KEY_AUTO_DELETE_TIMER = "autoDeleteTimer";
// Session keys // Session keys
String SESSION_KEY_IS_SESSION = "isSession"; String SESSION_KEY_IS_SESSION = "isSession";

View File

@@ -159,7 +159,7 @@ class GroupInvitationManagerImpl extends ConversationClientImpl
SessionId sessionId = getSessionId(meta.getPrivateGroupId()); SessionId sessionId = getSessionId(meta.getPrivateGroupId());
StoredSession ss = getSession(txn, m.getGroupId(), sessionId); StoredSession ss = getSession(txn, m.getGroupId(), sessionId);
// Handle the message // Handle the message
Session session; Session<?> session;
MessageId storageId; MessageId storageId;
if (ss == null) { if (ss == null) {
session = handleFirstMessage(txn, m, body, meta); session = handleFirstMessage(txn, m, body, meta);
@@ -189,7 +189,7 @@ class GroupInvitationManagerImpl extends ConversationClientImpl
results.values().iterator().next()); results.values().iterator().next());
} }
private Session handleFirstMessage(Transaction txn, Message m, BdfList body, private Session<?> handleFirstMessage(Transaction txn, Message m, BdfList body,
MessageMetadata meta) throws DbException, FormatException { MessageMetadata meta) throws DbException, FormatException {
GroupId privateGroupId = meta.getPrivateGroupId(); GroupId privateGroupId = meta.getPrivateGroupId();
MessageType type = meta.getMessageType(); MessageType type = meta.getMessageType();
@@ -206,7 +206,7 @@ class GroupInvitationManagerImpl extends ConversationClientImpl
} }
} }
private Session handleMessage(Transaction txn, Message m, BdfList body, private Session<?> handleMessage(Transaction txn, Message m, BdfList body,
MessageMetadata meta, BdfDictionary bdfSession) MessageMetadata meta, BdfDictionary bdfSession)
throws DbException, FormatException { throws DbException, FormatException {
MessageType type = meta.getMessageType(); MessageType type = meta.getMessageType();
@@ -228,7 +228,7 @@ class GroupInvitationManagerImpl extends ConversationClientImpl
} }
} }
private <S extends Session> S handleMessage(Transaction txn, Message m, private <S extends Session<?>> S handleMessage(Transaction txn, Message m,
BdfList body, MessageType type, S session, ProtocolEngine<S> engine) BdfList body, MessageType type, S session, ProtocolEngine<S> engine)
throws DbException, FormatException { throws DbException, FormatException {
if (type == INVITE) { if (type == INVITE) {
@@ -256,7 +256,7 @@ class GroupInvitationManagerImpl extends ConversationClientImpl
} }
private void storeSession(Transaction txn, MessageId storageId, private void storeSession(Transaction txn, MessageId storageId,
Session session) throws DbException, FormatException { Session<?> session) throws DbException, FormatException {
BdfDictionary d = sessionEncoder.encodeSession(session); BdfDictionary d = sessionEncoder.encodeSession(session);
clientHelper.mergeMessageMetadata(txn, storageId, d); clientHelper.mergeMessageMetadata(txn, storageId, d);
} }
@@ -354,7 +354,7 @@ class GroupInvitationManagerImpl extends ConversationClientImpl
} }
} }
private <S extends Session> S handleAction(Transaction txn, private <S extends Session<?>> S handleAction(Transaction txn,
LocalAction type, S session, ProtocolEngine<S> engine) LocalAction type, S session, ProtocolEngine<S> engine)
throws DbException { throws DbException {
if (type == LocalAction.INVITE) { if (type == LocalAction.INVITE) {
@@ -420,7 +420,8 @@ class GroupInvitationManagerImpl extends ConversationClientImpl
return new GroupInvitationRequest(m, contactGroupId, return new GroupInvitationRequest(m, contactGroupId,
meta.getTimestamp(), meta.isLocal(), meta.isRead(), meta.getTimestamp(), meta.isLocal(), meta.isRead(),
status.isSent(), status.isSeen(), sessionId, pg, status.isSent(), status.isSeen(), sessionId, pg,
invite.getText(), meta.isAvailableToAnswer(), canBeOpened); invite.getText(), meta.isAvailableToAnswer(), canBeOpened,
invite.getAutoDeleteTimer());
} }
private GroupInvitationResponse parseInvitationResponse( private GroupInvitationResponse parseInvitationResponse(
@@ -430,7 +431,7 @@ class GroupInvitationManagerImpl extends ConversationClientImpl
return new GroupInvitationResponse(m, contactGroupId, return new GroupInvitationResponse(m, contactGroupId,
meta.getTimestamp(), meta.isLocal(), meta.isRead(), meta.getTimestamp(), meta.isLocal(), meta.isRead(),
status.isSent(), status.isSeen(), sessionId, accept, status.isSent(), status.isSeen(), sessionId, accept,
meta.getPrivateGroupId()); meta.getPrivateGroupId(), meta.getAutoDeleteTimer());
} }
@Override @Override
@@ -508,7 +509,7 @@ class GroupInvitationManagerImpl extends ConversationClientImpl
SessionId sessionId = getSessionId(privateGroupId); SessionId sessionId = getSessionId(privateGroupId);
StoredSession ss = getSession(txn, contactGroupId, sessionId); StoredSession ss = getSession(txn, contactGroupId, sessionId);
// Create or parse the session // Create or parse the session
Session session; Session<?> session;
MessageId storageId; MessageId storageId;
if (ss == null) { if (ss == null) {
// If there's no session the contact must be a peer, // If there's no session the contact must be a peer,
@@ -543,7 +544,7 @@ class GroupInvitationManagerImpl extends ConversationClientImpl
StoredSession ss = getSession(txn, contactGroupId, sessionId); StoredSession ss = getSession(txn, contactGroupId, sessionId);
if (ss == null) continue; // No session for this contact if (ss == null) continue; // No session for this contact
// Handle the action // Handle the action
Session session = handleAction(txn, LocalAction.LEAVE, Session<?> session = handleAction(txn, LocalAction.LEAVE,
contactGroupId, ss.bdfSession); contactGroupId, ss.bdfSession);
// Store the updated session // Store the updated session
storeSession(txn, ss.storageId, session); storeSession(txn, ss.storageId, session);
@@ -553,7 +554,7 @@ class GroupInvitationManagerImpl extends ConversationClientImpl
} }
} }
private Session handleAction(Transaction txn, LocalAction a, private Session<?> handleAction(Transaction txn, LocalAction a,
GroupId contactGroupId, BdfDictionary bdfSession) GroupId contactGroupId, BdfDictionary bdfSession)
throws DbException, FormatException { throws DbException, FormatException {
Role role = sessionParser.getRole(bdfSession); Role role = sessionParser.getRole(bdfSession);
@@ -613,7 +614,7 @@ class GroupInvitationManagerImpl extends ConversationClientImpl
.getMessageMetadataAsDictionary(txn, contactGroupId, query); .getMessageMetadataAsDictionary(txn, contactGroupId, query);
Map<GroupId, Visibility> m = new HashMap<>(); Map<GroupId, Visibility> m = new HashMap<>();
for (BdfDictionary d : results.values()) { for (BdfDictionary d : results.values()) {
Session s = sessionParser.parseSession(contactGroupId, d); Session<?> s = sessionParser.parseSession(contactGroupId, d);
m.put(s.getPrivateGroupId(), s.getState().getVisibility()); m.put(s.getPrivateGroupId(), s.getState().getVisibility());
} }
return m; return m;
@@ -644,7 +645,7 @@ class GroupInvitationManagerImpl extends ConversationClientImpl
Map<GroupId, DeletableSession> sessions = new HashMap<>(); Map<GroupId, DeletableSession> sessions = new HashMap<>();
for (BdfDictionary d : metadata.values()) { for (BdfDictionary d : metadata.values()) {
if (!sessionParser.isSession(d)) continue; if (!sessionParser.isSession(d)) continue;
Session session; Session<?> session;
try { try {
session = sessionParser.parseSession(g, d); session = sessionParser.parseSession(g, d);
} catch (FormatException e) { } catch (FormatException e) {
@@ -673,7 +674,7 @@ class GroupInvitationManagerImpl extends ConversationClientImpl
getSessionId(messageMetadata.getPrivateGroupId()); getSessionId(messageMetadata.getPrivateGroupId());
StoredSession ss = getSession(txn1, g, sessionId); StoredSession ss = getSession(txn1, g, sessionId);
if (ss == null) throw new DbException(); if (ss == null) throw new DbException();
Session session = sessionParser Session<?> session = sessionParser
.parseSession(g, metadata.get(ss.storageId)); .parseSession(g, metadata.get(ss.storageId));
sessions.put(session.getPrivateGroupId(), sessions.put(session.getPrivateGroupId(),
new DeletableSession(session.getState())); new DeletableSession(session.getState()));

View File

@@ -21,10 +21,15 @@ import org.briarproject.briar.api.privategroup.PrivateGroupFactory;
import java.security.GeneralSecurityException; import java.security.GeneralSecurityException;
import java.util.Collections; import java.util.Collections;
import javax.annotation.Nullable;
import javax.annotation.concurrent.Immutable; import javax.annotation.concurrent.Immutable;
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.identity.AuthorConstants.MAX_SIGNATURE_LENGTH; import static org.briarproject.bramble.api.identity.AuthorConstants.MAX_SIGNATURE_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.privategroup.PrivateGroupConstants.GROUP_SALT_LENGTH; import static org.briarproject.briar.api.privategroup.PrivateGroupConstants.GROUP_SALT_LENGTH;
import static org.briarproject.briar.api.privategroup.PrivateGroupConstants.MAX_GROUP_INVITATION_TEXT_LENGTH; import static org.briarproject.briar.api.privategroup.PrivateGroupConstants.MAX_GROUP_INVITATION_TEXT_LENGTH;
@@ -71,8 +76,11 @@ class GroupInvitationValidator extends BdfMessageValidator {
private BdfMessageContext validateInviteMessage(Message m, BdfList body) private BdfMessageContext validateInviteMessage(Message m, BdfList body)
throws FormatException { throws FormatException {
// Message type, creator, group name, salt, optional text, signature // Client version 0.0: Message type, creator, group name, salt,
checkSize(body, 6); // optional text, signature.
// Client version 0.1: Message type, creator, group name, salt,
// optional text, signature, optional auto-delete timer.
checkSize(body, 6, 7);
BdfList creatorList = body.getList(1); BdfList creatorList = body.getList(1);
String groupName = body.getString(2); String groupName = body.getString(2);
checkLength(groupName, 1, MAX_GROUP_NAME_LENGTH); checkLength(groupName, 1, MAX_GROUP_NAME_LENGTH);
@@ -82,6 +90,8 @@ class GroupInvitationValidator extends BdfMessageValidator {
checkLength(text, 1, MAX_GROUP_INVITATION_TEXT_LENGTH); checkLength(text, 1, MAX_GROUP_INVITATION_TEXT_LENGTH);
byte[] signature = body.getRaw(5); byte[] signature = body.getRaw(5);
checkLength(signature, 1, MAX_SIGNATURE_LENGTH); checkLength(signature, 1, MAX_SIGNATURE_LENGTH);
long timer = NO_AUTO_DELETE_TIMER;
if (body.size() == 7) timer = validateTimer(body.getOptionalLong(6));
// Validate the creator and create the private group // Validate the creator and create the private group
Author creator = clientHelper.parseAndValidateAuthor(creatorList); Author creator = clientHelper.parseAndValidateAuthor(creatorList);
@@ -102,20 +112,27 @@ class GroupInvitationValidator extends BdfMessageValidator {
// Create the metadata // Create the metadata
BdfDictionary meta = messageEncoder.encodeMetadata(INVITE, BdfDictionary meta = messageEncoder.encodeMetadata(INVITE,
privateGroup.getId(), m.getTimestamp(), false, false, false, privateGroup.getId(), m.getTimestamp(), false, false, false,
false, false); false, false, timer);
return new BdfMessageContext(meta); return new BdfMessageContext(meta);
} }
private BdfMessageContext validateJoinMessage(Message m, BdfList body) private BdfMessageContext validateJoinMessage(Message m, BdfList body)
throws FormatException { throws FormatException {
checkSize(body, 3); // Client version 0.0: Message type, private group ID, optional
// previous message ID.
// Client version 0.1: Message type, private group ID, optional
// previous message ID, optional auto-delete timer.
checkSize(body, 3, 4);
byte[] privateGroupId = body.getRaw(1); byte[] privateGroupId = body.getRaw(1);
checkLength(privateGroupId, UniqueId.LENGTH); checkLength(privateGroupId, UniqueId.LENGTH);
byte[] previousMessageId = body.getOptionalRaw(2); byte[] previousMessageId = body.getOptionalRaw(2);
checkLength(previousMessageId, UniqueId.LENGTH); checkLength(previousMessageId, UniqueId.LENGTH);
long timer = NO_AUTO_DELETE_TIMER;
if (body.size() == 4) timer = validateTimer(body.getOptionalLong(3));
BdfDictionary meta = messageEncoder.encodeMetadata(JOIN, BdfDictionary meta = messageEncoder.encodeMetadata(JOIN,
new GroupId(privateGroupId), m.getTimestamp(), false, false, new GroupId(privateGroupId), m.getTimestamp(), false, false,
false, false, false); false, false, false, timer);
if (previousMessageId == null) { if (previousMessageId == null) {
return new BdfMessageContext(meta); return new BdfMessageContext(meta);
} else { } else {
@@ -127,14 +144,21 @@ class GroupInvitationValidator extends BdfMessageValidator {
private BdfMessageContext validateLeaveMessage(Message m, BdfList body) private BdfMessageContext validateLeaveMessage(Message m, BdfList body)
throws FormatException { throws FormatException {
checkSize(body, 3); // Client version 0.0: Message type, private group ID, optional
// previous message ID.
// Client version 0.1: Message type, private group ID, optional
// previous message ID, optional auto-delete timer.
checkSize(body, 3, 4);
byte[] privateGroupId = body.getRaw(1); byte[] privateGroupId = body.getRaw(1);
checkLength(privateGroupId, UniqueId.LENGTH); checkLength(privateGroupId, UniqueId.LENGTH);
byte[] previousMessageId = body.getOptionalRaw(2); byte[] previousMessageId = body.getOptionalRaw(2);
checkLength(previousMessageId, UniqueId.LENGTH); checkLength(previousMessageId, UniqueId.LENGTH);
long timer = NO_AUTO_DELETE_TIMER;
if (body.size() == 4) timer = validateTimer(body.getOptionalLong(3));
BdfDictionary meta = messageEncoder.encodeMetadata(LEAVE, BdfDictionary meta = messageEncoder.encodeMetadata(LEAVE,
new GroupId(privateGroupId), m.getTimestamp(), false, false, new GroupId(privateGroupId), m.getTimestamp(), false, false,
false, false, false); false, false, false, timer);
if (previousMessageId == null) { if (previousMessageId == null) {
return new BdfMessageContext(meta); return new BdfMessageContext(meta);
} else { } else {
@@ -151,7 +175,13 @@ class GroupInvitationValidator extends BdfMessageValidator {
checkLength(privateGroupId, UniqueId.LENGTH); checkLength(privateGroupId, UniqueId.LENGTH);
BdfDictionary meta = messageEncoder.encodeMetadata(ABORT, BdfDictionary meta = messageEncoder.encodeMetadata(ABORT,
new GroupId(privateGroupId), m.getTimestamp(), false, false, new GroupId(privateGroupId), m.getTimestamp(), false, false,
false, false, false); false, false, false, NO_AUTO_DELETE_TIMER);
return new BdfMessageContext(meta); return new BdfMessageContext(meta);
} }
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

@@ -10,7 +10,7 @@ import javax.annotation.concurrent.Immutable;
@Immutable @Immutable
@NotNullByDefault @NotNullByDefault
class InviteMessage extends GroupInvitationMessage { class InviteMessage extends DeletableGroupInvitationMessage {
private final String groupName; private final String groupName;
private final Author creator; private final Author creator;
@@ -20,8 +20,8 @@ class InviteMessage extends GroupInvitationMessage {
InviteMessage(MessageId id, GroupId contactGroupId, GroupId privateGroupId, InviteMessage(MessageId id, GroupId contactGroupId, GroupId privateGroupId,
long timestamp, String groupName, Author creator, byte[] salt, long timestamp, String groupName, Author creator, byte[] salt,
@Nullable String text, byte[] signature) { @Nullable String text, byte[] signature, long autoDeleteTimer) {
super(id, contactGroupId, privateGroupId, timestamp); super(id, contactGroupId, privateGroupId, timestamp, autoDeleteTimer);
this.groupName = groupName; this.groupName = groupName;
this.creator = creator; this.creator = creator;
this.salt = salt; this.salt = salt;

View File

@@ -330,7 +330,7 @@ class InviteeProtocolEngine extends AbstractProtocolEngine<InviteeSession> {
SessionId sessionId = new SessionId(m.getPrivateGroupId().getBytes()); SessionId sessionId = new SessionId(m.getPrivateGroupId().getBytes());
return new GroupInvitationRequest(m.getId(), m.getContactGroupId(), return new GroupInvitationRequest(m.getId(), m.getContactGroupId(),
m.getTimestamp(), false, false, false, false, sessionId, pg, m.getTimestamp(), false, false, false, false, sessionId, pg,
m.getText(), true, false); m.getText(), true, false, m.getAutoDeleteTimer());
} }
} }

View File

@@ -9,14 +9,15 @@ import javax.annotation.concurrent.Immutable;
@Immutable @Immutable
@NotNullByDefault @NotNullByDefault
class JoinMessage extends GroupInvitationMessage { class JoinMessage extends DeletableGroupInvitationMessage {
@Nullable @Nullable
private final MessageId previousMessageId; private final MessageId previousMessageId;
JoinMessage(MessageId id, GroupId contactGroupId, GroupId privateGroupId, JoinMessage(MessageId id, GroupId contactGroupId, GroupId privateGroupId,
long timestamp, @Nullable MessageId previousMessageId) { long timestamp, @Nullable MessageId previousMessageId,
super(id, contactGroupId, privateGroupId, timestamp); long autoDeleteTimer) {
super(id, contactGroupId, privateGroupId, timestamp, autoDeleteTimer);
this.previousMessageId = previousMessageId; this.previousMessageId = previousMessageId;
} }

View File

@@ -9,14 +9,15 @@ import javax.annotation.concurrent.Immutable;
@Immutable @Immutable
@NotNullByDefault @NotNullByDefault
class LeaveMessage extends GroupInvitationMessage { class LeaveMessage extends DeletableGroupInvitationMessage {
@Nullable @Nullable
private final MessageId previousMessageId; private final MessageId previousMessageId;
LeaveMessage(MessageId id, GroupId contactGroupId, GroupId privateGroupId, LeaveMessage(MessageId id, GroupId contactGroupId, GroupId privateGroupId,
long timestamp, @Nullable MessageId previousMessageId) { long timestamp, @Nullable MessageId previousMessageId,
super(id, contactGroupId, privateGroupId, timestamp); long autoDeleteTimer) {
super(id, contactGroupId, privateGroupId, timestamp, autoDeleteTimer);
this.previousMessageId = previousMessageId; this.previousMessageId = previousMessageId;
} }

View File

@@ -14,7 +14,7 @@ interface MessageEncoder {
BdfDictionary encodeMetadata(MessageType type, GroupId privateGroupId, BdfDictionary encodeMetadata(MessageType type, GroupId privateGroupId,
long timestamp, boolean local, boolean read, boolean visible, long timestamp, boolean local, boolean read, boolean visible,
boolean available, boolean accepted); boolean available, boolean accepted, long autoDeleteTimer);
void setVisibleInUi(BdfDictionary meta, boolean visible); void setVisibleInUi(BdfDictionary meta, boolean visible);
@@ -22,16 +22,49 @@ interface MessageEncoder {
void setInvitationAccepted(BdfDictionary meta, boolean accepted); void setInvitationAccepted(BdfDictionary meta, boolean accepted);
/**
* Encodes an invite message without an auto-delete timer.
*/
Message encodeInviteMessage(GroupId contactGroupId, GroupId privateGroupId, Message encodeInviteMessage(GroupId contactGroupId, GroupId privateGroupId,
long timestamp, String groupName, Author creator, byte[] salt, long timestamp, String groupName, Author creator, byte[] salt,
@Nullable String text, byte[] signature); @Nullable String text, byte[] signature);
/**
* Encodes an invite message with an optional auto-delete timer. This
* requires the contact to support client version 0.1 or higher.
*/
Message encodeInviteMessage(GroupId contactGroupId, GroupId privateGroupId,
long timestamp, String groupName, Author creator, byte[] salt,
@Nullable String text, byte[] signature, long autoDeleteTimer);
/**
* Encodes a join message without an auto-delete timer.
*/
Message encodeJoinMessage(GroupId contactGroupId, GroupId privateGroupId, Message encodeJoinMessage(GroupId contactGroupId, GroupId privateGroupId,
long timestamp, @Nullable MessageId previousMessageId); long timestamp, @Nullable MessageId previousMessageId);
/**
* Encodes a join message with an optional auto-delete timer. This
* requires the contact to support client version 0.1 or higher.
*/
Message encodeJoinMessage(GroupId contactGroupId, GroupId privateGroupId,
long timestamp, @Nullable MessageId previousMessageId,
long autoDeleteTimer);
/**
* Encodes a leave message without an auto-delete timer.
*/
Message encodeLeaveMessage(GroupId contactGroupId, GroupId privateGroupId, Message encodeLeaveMessage(GroupId contactGroupId, GroupId privateGroupId,
long timestamp, @Nullable MessageId previousMessageId); long timestamp, @Nullable MessageId previousMessageId);
/**
* Encodes a leave message with an optional auto-delete timer. This
* requires the contact to support client version 0.1 or higher.
*/
Message encodeLeaveMessage(GroupId contactGroupId, GroupId privateGroupId,
long timestamp, @Nullable MessageId previousMessageId,
long autoDeleteTimer);
Message encodeAbortMessage(GroupId contactGroupId, GroupId privateGroupId, Message encodeAbortMessage(GroupId contactGroupId, GroupId privateGroupId,
long timestamp); long timestamp);
} }

View File

@@ -15,7 +15,9 @@ import javax.annotation.Nullable;
import javax.annotation.concurrent.Immutable; import javax.annotation.concurrent.Immutable;
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.privategroup.invitation.GroupInvitationConstants.MSG_KEY_AUTO_DELETE_TIMER;
import static org.briarproject.briar.privategroup.invitation.GroupInvitationConstants.MSG_KEY_AVAILABLE_TO_ANSWER; import static org.briarproject.briar.privategroup.invitation.GroupInvitationConstants.MSG_KEY_AVAILABLE_TO_ANSWER;
import static org.briarproject.briar.privategroup.invitation.GroupInvitationConstants.MSG_KEY_INVITATION_ACCEPTED; import static org.briarproject.briar.privategroup.invitation.GroupInvitationConstants.MSG_KEY_INVITATION_ACCEPTED;
import static org.briarproject.briar.privategroup.invitation.GroupInvitationConstants.MSG_KEY_LOCAL; import static org.briarproject.briar.privategroup.invitation.GroupInvitationConstants.MSG_KEY_LOCAL;
@@ -45,7 +47,8 @@ class MessageEncoderImpl implements MessageEncoder {
@Override @Override
public BdfDictionary encodeMetadata(MessageType type, public BdfDictionary encodeMetadata(MessageType type,
GroupId privateGroupId, long timestamp, boolean local, boolean read, GroupId privateGroupId, long timestamp, boolean local, boolean read,
boolean visible, boolean available, boolean accepted) { boolean visible, boolean available, boolean accepted,
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());
meta.put(MSG_KEY_PRIVATE_GROUP_ID, privateGroupId); meta.put(MSG_KEY_PRIVATE_GROUP_ID, privateGroupId);
@@ -55,6 +58,9 @@ class MessageEncoderImpl implements MessageEncoder {
meta.put(MSG_KEY_VISIBLE_IN_UI, visible); meta.put(MSG_KEY_VISIBLE_IN_UI, visible);
meta.put(MSG_KEY_AVAILABLE_TO_ANSWER, available); meta.put(MSG_KEY_AVAILABLE_TO_ANSWER, available);
meta.put(MSG_KEY_INVITATION_ACCEPTED, accepted); meta.put(MSG_KEY_INVITATION_ACCEPTED, accepted);
if (autoDeleteTimer != NO_AUTO_DELETE_TIMER) {
meta.put(MSG_KEY_AUTO_DELETE_TIMER, autoDeleteTimer);
}
return meta; return meta;
} }
@@ -87,12 +93,25 @@ class MessageEncoderImpl implements MessageEncoder {
text, text,
signature signature
); );
try { return createMessage(contactGroupId, timestamp, body);
return messageFactory.createMessage(contactGroupId, timestamp, }
clientHelper.toByteArray(body));
} catch (FormatException e) { @Override
throw new AssertionError(e); public Message encodeInviteMessage(GroupId contactGroupId,
} GroupId privateGroupId, long timestamp, String groupName,
Author creator, byte[] salt, @Nullable String text,
byte[] signature, long autoDeleteTimer) {
BdfList creatorList = clientHelper.toList(creator);
BdfList body = BdfList.of(
INVITE.getValue(),
creatorList,
groupName,
salt,
text,
signature,
encodeTimer(autoDeleteTimer)
);
return createMessage(contactGroupId, timestamp, body);
} }
@Override @Override
@@ -104,12 +123,20 @@ class MessageEncoderImpl implements MessageEncoder {
privateGroupId, privateGroupId,
previousMessageId previousMessageId
); );
try { return createMessage(contactGroupId, timestamp, body);
return messageFactory.createMessage(contactGroupId, timestamp, }
clientHelper.toByteArray(body));
} catch (FormatException e) { @Override
throw new AssertionError(e); public Message encodeJoinMessage(GroupId contactGroupId,
} GroupId privateGroupId, long timestamp,
@Nullable MessageId previousMessageId, long autoDeleteTimer) {
BdfList body = BdfList.of(
JOIN.getValue(),
privateGroupId,
previousMessageId,
encodeTimer(autoDeleteTimer)
);
return createMessage(contactGroupId, timestamp, body);
} }
@Override @Override
@@ -121,12 +148,20 @@ class MessageEncoderImpl implements MessageEncoder {
privateGroupId, privateGroupId,
previousMessageId previousMessageId
); );
try { return createMessage(contactGroupId, timestamp, body);
return messageFactory.createMessage(contactGroupId, timestamp, }
clientHelper.toByteArray(body));
} catch (FormatException e) { @Override
throw new AssertionError(e); public Message encodeLeaveMessage(GroupId contactGroupId,
} GroupId privateGroupId, long timestamp,
@Nullable MessageId previousMessageId, long autoDeleteTimer) {
BdfList body = BdfList.of(
LEAVE.getValue(),
privateGroupId,
previousMessageId,
encodeTimer(autoDeleteTimer)
);
return createMessage(contactGroupId, timestamp, body);
} }
@Override @Override
@@ -136,6 +171,11 @@ class MessageEncoderImpl implements MessageEncoder {
ABORT.getValue(), ABORT.getValue(),
privateGroupId privateGroupId
); );
return createMessage(contactGroupId, timestamp, body);
}
private Message createMessage(GroupId contactGroupId, long timestamp,
BdfList body) {
try { try {
return messageFactory.createMessage(contactGroupId, timestamp, return messageFactory.createMessage(contactGroupId, timestamp,
clientHelper.toByteArray(body)); clientHelper.toByteArray(body));
@@ -143,4 +183,9 @@ class MessageEncoderImpl implements MessageEncoder {
throw new AssertionError(e); throw new AssertionError(e);
} }
} }
@Nullable
private Long encodeTimer(long autoDeleteTimer) {
return autoDeleteTimer == NO_AUTO_DELETE_TIMER ? null : autoDeleteTimer;
}
} }

View File

@@ -11,12 +11,12 @@ class MessageMetadata {
private final MessageType type; private final MessageType type;
private final GroupId privateGroupId; private final GroupId privateGroupId;
private final long timestamp; private final long timestamp, autoDeleteTimer;
private final boolean local, read, visible, available, accepted; private final boolean local, read, visible, available, accepted;
MessageMetadata(MessageType type, GroupId privateGroupId, MessageMetadata(MessageType type, GroupId privateGroupId,
long timestamp, boolean local, boolean read, boolean visible, long timestamp, boolean local, boolean read, boolean visible,
boolean available, boolean accepted) { boolean available, boolean accepted, long autoDeleteTimer) {
this.privateGroupId = privateGroupId; this.privateGroupId = privateGroupId;
this.type = type; this.type = type;
this.timestamp = timestamp; this.timestamp = timestamp;
@@ -25,6 +25,7 @@ class MessageMetadata {
this.visible = visible; this.visible = visible;
this.available = available; this.available = available;
this.accepted = accepted; this.accepted = accepted;
this.autoDeleteTimer = autoDeleteTimer;
} }
MessageType getMessageType() { MessageType getMessageType() {
@@ -64,4 +65,7 @@ class MessageMetadata {
return accepted; return accepted;
} }
public long getAutoDeleteTimer() {
return autoDeleteTimer;
}
} }

View File

@@ -8,7 +8,6 @@ import org.briarproject.bramble.api.data.BdfList;
import org.briarproject.bramble.api.db.DbException; import org.briarproject.bramble.api.db.DbException;
import org.briarproject.bramble.api.db.Transaction; import org.briarproject.bramble.api.db.Transaction;
import org.briarproject.bramble.api.identity.Author; import org.briarproject.bramble.api.identity.Author;
import org.briarproject.bramble.api.identity.AuthorFactory;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault; import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import org.briarproject.bramble.api.sync.GroupId; import org.briarproject.bramble.api.sync.GroupId;
import org.briarproject.bramble.api.sync.Message; import org.briarproject.bramble.api.sync.Message;
@@ -19,7 +18,9 @@ import org.briarproject.briar.api.privategroup.PrivateGroupFactory;
import javax.annotation.concurrent.Immutable; import javax.annotation.concurrent.Immutable;
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.privategroup.invitation.GroupInvitationConstants.MSG_KEY_AUTO_DELETE_TIMER;
import static org.briarproject.briar.privategroup.invitation.GroupInvitationConstants.MSG_KEY_AVAILABLE_TO_ANSWER; import static org.briarproject.briar.privategroup.invitation.GroupInvitationConstants.MSG_KEY_AVAILABLE_TO_ANSWER;
import static org.briarproject.briar.privategroup.invitation.GroupInvitationConstants.MSG_KEY_INVITATION_ACCEPTED; import static org.briarproject.briar.privategroup.invitation.GroupInvitationConstants.MSG_KEY_INVITATION_ACCEPTED;
import static org.briarproject.briar.privategroup.invitation.GroupInvitationConstants.MSG_KEY_LOCAL; import static org.briarproject.briar.privategroup.invitation.GroupInvitationConstants.MSG_KEY_LOCAL;
@@ -33,15 +34,12 @@ import static org.briarproject.briar.privategroup.invitation.MessageType.INVITE;
@NotNullByDefault @NotNullByDefault
class MessageParserImpl implements MessageParser { class MessageParserImpl implements MessageParser {
private final AuthorFactory authorFactory;
private final PrivateGroupFactory privateGroupFactory; private final PrivateGroupFactory privateGroupFactory;
private final ClientHelper clientHelper; private final ClientHelper clientHelper;
@Inject @Inject
MessageParserImpl(AuthorFactory authorFactory, MessageParserImpl(PrivateGroupFactory privateGroupFactory,
PrivateGroupFactory privateGroupFactory,
ClientHelper clientHelper) { ClientHelper clientHelper) {
this.authorFactory = authorFactory;
this.privateGroupFactory = privateGroupFactory; this.privateGroupFactory = privateGroupFactory;
this.clientHelper = clientHelper; this.clientHelper = clientHelper;
} }
@@ -82,8 +80,10 @@ class MessageParserImpl implements MessageParser {
boolean visible = meta.getBoolean(MSG_KEY_VISIBLE_IN_UI, false); boolean visible = meta.getBoolean(MSG_KEY_VISIBLE_IN_UI, false);
boolean available = meta.getBoolean(MSG_KEY_AVAILABLE_TO_ANSWER, false); boolean available = meta.getBoolean(MSG_KEY_AVAILABLE_TO_ANSWER, false);
boolean accepted = meta.getBoolean(MSG_KEY_INVITATION_ACCEPTED, false); boolean accepted = meta.getBoolean(MSG_KEY_INVITATION_ACCEPTED, false);
long timer = meta.getLong(MSG_KEY_AUTO_DELETE_TIMER,
NO_AUTO_DELETE_TIMER);
return new MessageMetadata(type, privateGroupId, timestamp, local, read, return new MessageMetadata(type, privateGroupId, timestamp, local, read,
visible, available, accepted); visible, available, accepted, timer);
} }
@Override @Override
@@ -97,39 +97,58 @@ class MessageParserImpl implements MessageParser {
@Override @Override
public InviteMessage parseInviteMessage(Message m, BdfList body) public InviteMessage parseInviteMessage(Message m, BdfList body)
throws FormatException { throws FormatException {
// Message type, creator, group name, salt, optional text, signature // Client version 0.0: Message type, creator, group name, salt,
// optional text, signature.
// Client version 0.1: Message type, creator, group name, salt,
// optional text, signature, optional auto-delete timer.
BdfList creatorList = body.getList(1); BdfList creatorList = body.getList(1);
String groupName = body.getString(2); String groupName = body.getString(2);
byte[] salt = body.getRaw(3); byte[] salt = body.getRaw(3);
String text = body.getOptionalString(4); String text = body.getOptionalString(4);
byte[] signature = body.getRaw(5); byte[] signature = body.getRaw(5);
long timer = NO_AUTO_DELETE_TIMER;
if (body.size() == 7) timer = body.getLong(6, NO_AUTO_DELETE_TIMER);
Author creator = clientHelper.parseAndValidateAuthor(creatorList); Author creator = clientHelper.parseAndValidateAuthor(creatorList);
PrivateGroup privateGroup = privateGroupFactory.createPrivateGroup( PrivateGroup privateGroup = privateGroupFactory.createPrivateGroup(
groupName, creator, salt); groupName, creator, salt);
return new InviteMessage(m.getId(), m.getGroupId(), return new InviteMessage(m.getId(), m.getGroupId(),
privateGroup.getId(), m.getTimestamp(), groupName, creator, privateGroup.getId(), m.getTimestamp(), groupName, creator,
salt, text, signature); salt, text, signature, timer);
} }
@Override @Override
public JoinMessage parseJoinMessage(Message m, BdfList body) public JoinMessage parseJoinMessage(Message m, BdfList body)
throws FormatException { throws FormatException {
// Client version 0.0: Message type, private group ID, optional
// previous message ID.
// Client version 0.1: Message type, private group ID, optional
// previous message ID, optional auto-delete timer.
GroupId privateGroupId = new GroupId(body.getRaw(1)); GroupId privateGroupId = new GroupId(body.getRaw(1));
byte[] b = body.getOptionalRaw(2); byte[] b = body.getOptionalRaw(2);
MessageId previousMessageId = b == null ? null : new MessageId(b); MessageId previousMessageId = b == null ? null : new MessageId(b);
long timer = NO_AUTO_DELETE_TIMER;
if (body.size() == 4) timer = body.getLong(3, NO_AUTO_DELETE_TIMER);
return new JoinMessage(m.getId(), m.getGroupId(), privateGroupId, return new JoinMessage(m.getId(), m.getGroupId(), privateGroupId,
m.getTimestamp(), previousMessageId); m.getTimestamp(), previousMessageId, timer);
} }
@Override @Override
public LeaveMessage parseLeaveMessage(Message m, BdfList body) public LeaveMessage parseLeaveMessage(Message m, BdfList body)
throws FormatException { throws FormatException {
// Client version 0.0: Message type, private group ID, optional
// previous message ID.
// Client version 0.1: Message type, private group ID, optional
// previous message ID, optional auto-delete timer.
GroupId privateGroupId = new GroupId(body.getRaw(1)); GroupId privateGroupId = new GroupId(body.getRaw(1));
byte[] b = body.getOptionalRaw(2); byte[] b = body.getOptionalRaw(2);
MessageId previousMessageId = b == null ? null : new MessageId(b); MessageId previousMessageId = b == null ? null : new MessageId(b);
long timer = NO_AUTO_DELETE_TIMER;
if (body.size() == 4) timer = body.getLong(3, NO_AUTO_DELETE_TIMER);
return new LeaveMessage(m.getId(), m.getGroupId(), privateGroupId, return new LeaveMessage(m.getId(), m.getGroupId(), privateGroupId,
m.getTimestamp(), previousMessageId); m.getTimestamp(), previousMessageId, timer);
} }
@Override @Override

View File

@@ -22,8 +22,10 @@ import org.briarproject.briar.api.privategroup.GroupMessageFactory;
import org.briarproject.briar.api.privategroup.PrivateGroup; import org.briarproject.briar.api.privategroup.PrivateGroup;
import org.briarproject.briar.api.privategroup.PrivateGroupFactory; import org.briarproject.briar.api.privategroup.PrivateGroupFactory;
import org.briarproject.briar.api.privategroup.PrivateGroupManager; import org.briarproject.briar.api.privategroup.PrivateGroupManager;
import org.briarproject.briar.api.privategroup.invitation.GroupInvitationManager;
import org.jmock.Expectations; import org.jmock.Expectations;
import static org.briarproject.bramble.api.autodelete.AutoDeleteConstants.NO_AUTO_DELETE_TIMER;
import static org.briarproject.bramble.api.identity.AuthorConstants.MAX_SIGNATURE_LENGTH; import static org.briarproject.bramble.api.identity.AuthorConstants.MAX_SIGNATURE_LENGTH;
import static org.briarproject.bramble.api.sync.Group.Visibility.SHARED; import static org.briarproject.bramble.api.sync.Group.Visibility.SHARED;
import static org.briarproject.bramble.test.TestUtils.getContact; import static org.briarproject.bramble.test.TestUtils.getContact;
@@ -35,8 +37,6 @@ import static org.briarproject.bramble.util.StringUtils.getRandomString;
import static org.briarproject.briar.api.privategroup.PrivateGroupConstants.GROUP_SALT_LENGTH; import static org.briarproject.briar.api.privategroup.PrivateGroupConstants.GROUP_SALT_LENGTH;
import static org.briarproject.briar.api.privategroup.PrivateGroupConstants.MAX_GROUP_INVITATION_TEXT_LENGTH; import static org.briarproject.briar.api.privategroup.PrivateGroupConstants.MAX_GROUP_INVITATION_TEXT_LENGTH;
import static org.briarproject.briar.api.privategroup.PrivateGroupConstants.MAX_GROUP_NAME_LENGTH; import static org.briarproject.briar.api.privategroup.PrivateGroupConstants.MAX_GROUP_NAME_LENGTH;
import static org.briarproject.briar.api.privategroup.PrivateGroupManager.CLIENT_ID;
import static org.briarproject.briar.api.privategroup.PrivateGroupManager.MAJOR_VERSION;
import static org.briarproject.briar.privategroup.invitation.GroupInvitationConstants.GROUP_KEY_CONTACT_ID; import static org.briarproject.briar.privategroup.invitation.GroupInvitationConstants.GROUP_KEY_CONTACT_ID;
import static org.briarproject.briar.privategroup.invitation.MessageType.ABORT; import static org.briarproject.briar.privategroup.invitation.MessageType.ABORT;
import static org.briarproject.briar.privategroup.invitation.MessageType.INVITE; import static org.briarproject.briar.privategroup.invitation.MessageType.INVITE;
@@ -67,7 +67,8 @@ abstract class AbstractProtocolEngineTest extends BrambleMockTestCase {
final ContactId contactId = contact.getId(); final ContactId contactId = contact.getId();
final Author author = contact.getAuthor(); final Author author = contact.getAuthor();
final GroupId contactGroupId = new GroupId(getRandomId()); final GroupId contactGroupId = new GroupId(getRandomId());
final Group privateGroupGroup = getGroup(CLIENT_ID, MAJOR_VERSION); final Group privateGroupGroup = getGroup(PrivateGroupManager.CLIENT_ID,
PrivateGroupManager.MAJOR_VERSION);
final GroupId privateGroupId = privateGroupGroup.getId(); final GroupId privateGroupId = privateGroupGroup.getId();
final PrivateGroup privateGroup = new PrivateGroup(privateGroupGroup, final PrivateGroup privateGroup = new PrivateGroup(privateGroupGroup,
getRandomString(MAX_GROUP_NAME_LENGTH), author, getRandomString(MAX_GROUP_NAME_LENGTH), author,
@@ -80,30 +81,34 @@ abstract class AbstractProtocolEngineTest extends BrambleMockTestCase {
final long messageTimestamp = message.getTimestamp(); final long messageTimestamp = message.getTimestamp();
final long inviteTimestamp = messageTimestamp - 1; final long inviteTimestamp = messageTimestamp - 1;
final long localTimestamp = inviteTimestamp - 1; final long localTimestamp = inviteTimestamp - 1;
final BdfDictionary groupMeta = BdfDictionary.of(
new BdfEntry(GROUP_KEY_CONTACT_ID, contactId.getInt()));
final InviteMessage inviteMessage = final InviteMessage inviteMessage =
new InviteMessage(new MessageId(getRandomId()), contactGroupId, new InviteMessage(new MessageId(getRandomId()), contactGroupId,
privateGroupId, 0L, privateGroup.getName(), privateGroupId, 0L, privateGroup.getName(),
privateGroup.getCreator(), privateGroup.getSalt(), privateGroup.getCreator(), privateGroup.getSalt(),
getRandomString(MAX_GROUP_INVITATION_TEXT_LENGTH), getRandomString(MAX_GROUP_INVITATION_TEXT_LENGTH),
signature); signature, NO_AUTO_DELETE_TIMER);
final JoinMessage joinMessage = final JoinMessage joinMessage =
new JoinMessage(new MessageId(getRandomId()), contactGroupId, new JoinMessage(new MessageId(getRandomId()), contactGroupId,
privateGroupId, 0L, lastRemoteMessageId); privateGroupId, 0L, lastRemoteMessageId,
NO_AUTO_DELETE_TIMER);
final LeaveMessage leaveMessage = final LeaveMessage leaveMessage =
new LeaveMessage(new MessageId(getRandomId()), contactGroupId, new LeaveMessage(new MessageId(getRandomId()), contactGroupId,
privateGroupId, 0L, lastRemoteMessageId); privateGroupId, 0L, lastRemoteMessageId,
NO_AUTO_DELETE_TIMER);
final AbortMessage abortMessage = final AbortMessage abortMessage =
new AbortMessage(messageId, contactGroupId, privateGroupId, new AbortMessage(messageId, contactGroupId, privateGroupId,
inviteTimestamp + 1); inviteTimestamp + 1);
void assertSessionConstantsUnchanged(Session s1, Session s2) { void assertSessionConstantsUnchanged(Session<?> s1, Session<?> s2) {
assertEquals(s1.getRole(), s2.getRole()); assertEquals(s1.getRole(), s2.getRole());
assertEquals(s1.getContactGroupId(), s2.getContactGroupId()); assertEquals(s1.getContactGroupId(), s2.getContactGroupId());
assertEquals(s1.getPrivateGroupId(), s2.getPrivateGroupId()); assertEquals(s1.getPrivateGroupId(), s2.getPrivateGroupId());
} }
void assertSessionRecordedSentMessage(Session s) { void assertSessionRecordedSentMessage(Session<?> s) {
assertEquals(messageId, s.getLastLocalMessageId()); assertEquals(messageId, s.getLastLocalMessageId());
assertEquals(lastRemoteMessageId, s.getLastRemoteMessageId()); assertEquals(lastRemoteMessageId, s.getLastRemoteMessageId());
assertEquals(messageTimestamp, s.getLocalTimestamp()); assertEquals(messageTimestamp, s.getLocalTimestamp());
@@ -118,11 +123,13 @@ abstract class AbstractProtocolEngineTest extends BrambleMockTestCase {
} }
void expectSendInviteMessage(String text) throws Exception { void expectSendInviteMessage(String text) throws Exception {
expectCheckWhetherContactSupportsAutoDeletion();
expectGetLocalTimestamp(messageTimestamp);
context.checking(new Expectations() {{ context.checking(new Expectations() {{
oneOf(messageEncoder) oneOf(messageEncoder).encodeInviteMessage(contactGroupId,
.encodeInviteMessage(contactGroupId, privateGroupId, privateGroupId, inviteTimestamp, privateGroup.getName(),
inviteTimestamp, privateGroup.getName(), author, author, privateGroup.getSalt(), text, signature,
privateGroup.getSalt(), text, signature); NO_AUTO_DELETE_TIMER);
will(returnValue(message)); will(returnValue(message));
}}); }});
expectSendMessage(INVITE, true); expectSendMessage(INVITE, true);
@@ -130,22 +137,24 @@ abstract class AbstractProtocolEngineTest extends BrambleMockTestCase {
void expectSendJoinMessage(JoinMessage m, boolean visible) void expectSendJoinMessage(JoinMessage m, boolean visible)
throws Exception { throws Exception {
expectCheckWhetherContactSupportsAutoDeletion();
expectGetLocalTimestamp(messageTimestamp); expectGetLocalTimestamp(messageTimestamp);
context.checking(new Expectations() {{ context.checking(new Expectations() {{
oneOf(messageEncoder).encodeJoinMessage(m.getContactGroupId(), oneOf(messageEncoder).encodeJoinMessage(m.getContactGroupId(),
m.getPrivateGroupId(), m.getTimestamp(), m.getPrivateGroupId(), m.getTimestamp(),
lastLocalMessageId); lastLocalMessageId, NO_AUTO_DELETE_TIMER);
will(returnValue(message)); will(returnValue(message));
}}); }});
expectSendMessage(JOIN, visible); expectSendMessage(JOIN, visible);
} }
void expectSendLeaveMessage(boolean visible) throws Exception { void expectSendLeaveMessage(boolean visible) throws Exception {
expectCheckWhetherContactSupportsAutoDeletion();
expectGetLocalTimestamp(messageTimestamp); expectGetLocalTimestamp(messageTimestamp);
context.checking(new Expectations() {{ context.checking(new Expectations() {{
oneOf(messageEncoder) oneOf(messageEncoder).encodeLeaveMessage(contactGroupId,
.encodeLeaveMessage(contactGroupId, privateGroupId, privateGroupId, messageTimestamp, lastLocalMessageId,
messageTimestamp, lastLocalMessageId); NO_AUTO_DELETE_TIMER);
will(returnValue(message)); will(returnValue(message));
}}); }});
expectSendMessage(LEAVE, visible); expectSendMessage(LEAVE, visible);
@@ -167,7 +176,8 @@ abstract class AbstractProtocolEngineTest extends BrambleMockTestCase {
BdfDictionary meta = BdfDictionary.of(new BdfEntry("me", "ta")); BdfDictionary meta = BdfDictionary.of(new BdfEntry("me", "ta"));
context.checking(new Expectations() {{ context.checking(new Expectations() {{
oneOf(messageEncoder).encodeMetadata(type, privateGroupId, oneOf(messageEncoder).encodeMetadata(type, privateGroupId,
message.getTimestamp(), true, true, visible, false, false); message.getTimestamp(), true, true, visible, false, false,
NO_AUTO_DELETE_TIMER);
will(returnValue(meta)); will(returnValue(meta));
oneOf(clientHelper).addLocalMessage(txn, message, meta, true, oneOf(clientHelper).addLocalMessage(txn, message, meta, true,
false); false);
@@ -178,7 +188,8 @@ abstract class AbstractProtocolEngineTest extends BrambleMockTestCase {
expectGetContactId(); expectGetContactId();
context.checking(new Expectations() {{ context.checking(new Expectations() {{
oneOf(clientVersioningManager).getClientVisibility(txn, contactId, oneOf(clientVersioningManager).getClientVisibility(txn, contactId,
CLIENT_ID, MAJOR_VERSION); PrivateGroupManager.CLIENT_ID,
PrivateGroupManager.MAJOR_VERSION);
will(returnValue(SHARED)); will(returnValue(SHARED));
oneOf(db).setGroupVisibility(txn, contactId, privateGroupId, v); oneOf(db).setGroupVisibility(txn, contactId, privateGroupId, v);
}}); }});
@@ -218,4 +229,15 @@ abstract class AbstractProtocolEngineTest extends BrambleMockTestCase {
}}); }});
} }
void expectCheckWhetherContactSupportsAutoDeletion() throws Exception {
context.checking(new Expectations() {{
oneOf(clientHelper).getGroupMetadataAsDictionary(txn,
contactGroupId);
will(returnValue(groupMeta));
oneOf(clientVersioningManager).getClientMinorVersion(txn, contactId,
GroupInvitationManager.CLIENT_ID,
GroupInvitationManager.MAJOR_VERSION);
will(returnValue(GroupInvitationManager.MINOR_VERSION));
}});
}
} }

View File

@@ -5,6 +5,7 @@ import org.briarproject.briar.api.client.ProtocolStateException;
import org.jmock.Expectations; import org.jmock.Expectations;
import org.junit.Test; import org.junit.Test;
import static org.briarproject.bramble.api.autodelete.AutoDeleteConstants.NO_AUTO_DELETE_TIMER;
import static org.briarproject.bramble.api.sync.Group.Visibility.INVISIBLE; import static org.briarproject.bramble.api.sync.Group.Visibility.INVISIBLE;
import static org.briarproject.bramble.api.sync.Group.Visibility.SHARED; import static org.briarproject.bramble.api.sync.Group.Visibility.SHARED;
import static org.briarproject.bramble.test.TestUtils.getRandomId; import static org.briarproject.bramble.test.TestUtils.getRandomId;
@@ -77,7 +78,6 @@ public class CreatorProtocolEngineTest extends AbstractProtocolEngineTest {
oneOf(messageTracker).trackOutgoingMessage(txn, message); oneOf(messageTracker).trackOutgoingMessage(txn, message);
}}); }});
expectSendInviteMessage(text); expectSendInviteMessage(text);
expectGetLocalTimestamp(messageTimestamp);
} }
@Test(expected = ProtocolStateException.class) @Test(expected = ProtocolStateException.class)
@@ -289,7 +289,7 @@ public class CreatorProtocolEngineTest extends AbstractProtocolEngineTest {
CreatorSession session = getDefaultSession(INVITED); CreatorSession session = getDefaultSession(INVITED);
JoinMessage invalidJoinMessage = JoinMessage invalidJoinMessage =
new JoinMessage(messageId, contactGroupId, privateGroupId, new JoinMessage(messageId, contactGroupId, privateGroupId,
inviteTimestamp + 1, messageId); inviteTimestamp + 1, messageId, NO_AUTO_DELETE_TIMER);
expectAbortWhenSubscribedToGroup(); expectAbortWhenSubscribedToGroup();
CreatorSession newSession = CreatorSession newSession =
@@ -303,7 +303,7 @@ public class CreatorProtocolEngineTest extends AbstractProtocolEngineTest {
JoinMessage properJoinMessage = JoinMessage properJoinMessage =
new JoinMessage(new MessageId(getRandomId()), contactGroupId, new JoinMessage(new MessageId(getRandomId()), contactGroupId,
privateGroupId, inviteTimestamp + 1, privateGroupId, inviteTimestamp + 1,
lastRemoteMessageId); lastRemoteMessageId, NO_AUTO_DELETE_TIMER);
expectSendJoinMessage(properJoinMessage, false); expectSendJoinMessage(properJoinMessage, false);
expectMarkMessageVisibleInUi(properJoinMessage.getId()); expectMarkMessageVisibleInUi(properJoinMessage.getId());
@@ -343,7 +343,8 @@ public class CreatorProtocolEngineTest extends AbstractProtocolEngineTest {
public void testOnLeaveMessageFromStart() throws Exception { public void testOnLeaveMessageFromStart() throws Exception {
LeaveMessage leaveMessage = LeaveMessage leaveMessage =
new LeaveMessage(messageId, contactGroupId, privateGroupId, new LeaveMessage(messageId, contactGroupId, privateGroupId,
inviteTimestamp, lastLocalMessageId); inviteTimestamp, lastLocalMessageId,
NO_AUTO_DELETE_TIMER);
CreatorSession session = getDefaultSession(START); CreatorSession session = getDefaultSession(START);
expectAbortWhenSubscribedToGroup(); expectAbortWhenSubscribedToGroup();
@@ -377,7 +378,8 @@ public class CreatorProtocolEngineTest extends AbstractProtocolEngineTest {
throws Exception { throws Exception {
LeaveMessage invalidLeaveMessage = LeaveMessage invalidLeaveMessage =
new LeaveMessage(messageId, contactGroupId, privateGroupId, new LeaveMessage(messageId, contactGroupId, privateGroupId,
inviteTimestamp + 1, lastLocalMessageId); inviteTimestamp + 1, lastLocalMessageId,
NO_AUTO_DELETE_TIMER);
CreatorSession session = getDefaultSession(INVITED); CreatorSession session = getDefaultSession(INVITED);
expectAbortWhenSubscribedToGroup(); expectAbortWhenSubscribedToGroup();
@@ -392,7 +394,7 @@ public class CreatorProtocolEngineTest extends AbstractProtocolEngineTest {
LeaveMessage properLeaveMessage = LeaveMessage properLeaveMessage =
new LeaveMessage(new MessageId(getRandomId()), contactGroupId, new LeaveMessage(new MessageId(getRandomId()), contactGroupId,
privateGroupId, inviteTimestamp + 1, privateGroupId, inviteTimestamp + 1,
lastRemoteMessageId); lastRemoteMessageId, NO_AUTO_DELETE_TIMER);
CreatorSession session = getDefaultSession(INVITED); CreatorSession session = getDefaultSession(INVITED);
expectMarkMessageVisibleInUi(properLeaveMessage.getId()); expectMarkMessageVisibleInUi(properLeaveMessage.getId());

View File

@@ -45,6 +45,7 @@ import javax.annotation.Nullable;
import static java.util.Arrays.asList; import static java.util.Arrays.asList;
import static junit.framework.TestCase.fail; import static junit.framework.TestCase.fail;
import static org.briarproject.bramble.api.autodelete.AutoDeleteConstants.NO_AUTO_DELETE_TIMER;
import static org.briarproject.bramble.api.sync.Group.Visibility.SHARED; import static org.briarproject.bramble.api.sync.Group.Visibility.SHARED;
import static org.briarproject.bramble.test.TestUtils.getAuthor; import static org.briarproject.bramble.test.TestUtils.getAuthor;
import static org.briarproject.bramble.test.TestUtils.getContact; import static org.briarproject.bramble.test.TestUtils.getContact;
@@ -230,7 +231,7 @@ public class GroupInvitationManagerImplTest extends BrambleMockTestCase {
}}); }});
} }
private void expectStoreSession(Session session, MessageId storageId) private void expectStoreSession(Session<?> session, MessageId storageId)
throws Exception { throws Exception {
context.checking(new Expectations() {{ context.checking(new Expectations() {{
oneOf(sessionEncoder).encodeSession(session); oneOf(sessionEncoder).encodeSession(session);
@@ -320,7 +321,8 @@ public class GroupInvitationManagerImplTest extends BrambleMockTestCase {
throws Exception { throws Exception {
expectParseMessageMetadata(); expectParseMessageMetadata();
expectGetSession(noResults, sessionId, contactGroup.getId()); expectGetSession(noResults, sessionId, contactGroup.getId());
Session session = expectHandleFirstMessage(role, messageMetadata, type); Session<?> session =
expectHandleFirstMessage(role, messageMetadata, type);
if (session != null) { if (session != null) {
expectCreateStorageId(); expectCreateStorageId();
expectStoreSession(session, storageMessage.getId()); expectStoreSession(session, storageMessage.getId());
@@ -347,13 +349,13 @@ public class GroupInvitationManagerImplTest extends BrambleMockTestCase {
BdfDictionary bdfSession) throws Exception { BdfDictionary bdfSession) throws Exception {
expectParseMessageMetadata(); expectParseMessageMetadata();
expectGetSession(oneResult, sessionId, contactGroup.getId()); expectGetSession(oneResult, sessionId, contactGroup.getId());
Session session = expectHandleMessage(role, messageMetadata, bdfSession, Session<?> session =
type); expectHandleMessage(role, messageMetadata, bdfSession, type);
expectStoreSession(session, storageMessage.getId()); expectStoreSession(session, storageMessage.getId());
} }
@Nullable @Nullable
private Session expectHandleFirstMessage(Role role, private Session<?> expectHandleFirstMessage(Role role,
MessageMetadata messageMetadata, MessageType type) MessageMetadata messageMetadata, MessageType type)
throws Exception { throws Exception {
context.checking(new Expectations() {{ context.checking(new Expectations() {{
@@ -382,7 +384,7 @@ public class GroupInvitationManagerImplTest extends BrambleMockTestCase {
} }
@Nullable @Nullable
private Session expectHandleMessage(Role role, private Session<?> expectHandleMessage(Role role,
MessageMetadata messageMetadata, BdfDictionary state, MessageMetadata messageMetadata, BdfDictionary state,
MessageType type) throws Exception { MessageType type) throws Exception {
context.checking(new Expectations() {{ context.checking(new Expectations() {{
@@ -420,8 +422,9 @@ public class GroupInvitationManagerImplTest extends BrambleMockTestCase {
} }
} }
private <S extends Session> void expectIndividualMessage(MessageType type, private <S extends Session<?>> void expectIndividualMessage(
ProtocolEngine<S> engine, S session) throws Exception { MessageType type, ProtocolEngine<S> engine, S session)
throws Exception {
if (type == INVITE) { if (type == INVITE) {
InviteMessage msg = context.mock(InviteMessage.class); InviteMessage msg = context.mock(InviteMessage.class);
context.checking(new Expectations() {{ context.checking(new Expectations() {{
@@ -657,14 +660,14 @@ public class GroupInvitationManagerImplTest extends BrambleMockTestCase {
long time1 = 1L, time2 = 2L; long time1 = 1L, time2 = 2L;
MessageMetadata messageMetadata1 = MessageMetadata messageMetadata1 =
new MessageMetadata(INVITE, privateGroup.getId(), time1, true, new MessageMetadata(INVITE, privateGroup.getId(), time1, true,
true, true, false, true); true, true, false, true, NO_AUTO_DELETE_TIMER);
MessageMetadata messageMetadata2 = MessageMetadata messageMetadata2 =
new MessageMetadata(JOIN, privateGroup.getId(), time2, true, new MessageMetadata(JOIN, privateGroup.getId(), time2, true,
true, true, true, false); true, true, true, false, NO_AUTO_DELETE_TIMER);
InviteMessage invite = InviteMessage invite =
new InviteMessage(message.getId(), contactGroup.getId(), new InviteMessage(message.getId(), contactGroup.getId(),
privateGroup.getId(), time1, "name", author, privateGroup.getId(), time1, "name", author,
new byte[0], null, new byte[0]); new byte[0], null, new byte[0], NO_AUTO_DELETE_TIMER);
PrivateGroup pg = PrivateGroup pg =
new PrivateGroup(privateGroup, invite.getGroupName(), new PrivateGroup(privateGroup, invite.getGroupName(),
invite.getCreator(), invite.getSalt()); invite.getCreator(), invite.getSalt());
@@ -731,11 +734,11 @@ public class GroupInvitationManagerImplTest extends BrambleMockTestCase {
InviteMessage inviteMessage1 = InviteMessage inviteMessage1 =
new InviteMessage(message.getId(), contactGroup.getId(), new InviteMessage(message.getId(), contactGroup.getId(),
privateGroup.getId(), time1, groupName, author, salt, privateGroup.getId(), time1, groupName, author, salt,
null, getRandomBytes(5)); null, getRandomBytes(5), NO_AUTO_DELETE_TIMER);
InviteMessage inviteMessage2 = InviteMessage inviteMessage2 =
new InviteMessage(message2.getId(), contactGroup.getId(), new InviteMessage(message2.getId(), contactGroup.getId(),
privateGroup.getId(), time2, groupName, author, salt, privateGroup.getId(), time2, groupName, author, salt,
null, getRandomBytes(5)); null, getRandomBytes(5), NO_AUTO_DELETE_TIMER);
PrivateGroup pg = new PrivateGroup(privateGroup, groupName, PrivateGroup pg = new PrivateGroup(privateGroup, groupName,
author, salt); author, salt);

View File

@@ -16,6 +16,11 @@ import org.junit.Test;
import java.security.GeneralSecurityException; import java.security.GeneralSecurityException;
import static java.util.Collections.emptyList;
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.identity.AuthorConstants.MAX_SIGNATURE_LENGTH; import static org.briarproject.bramble.api.identity.AuthorConstants.MAX_SIGNATURE_LENGTH;
import static org.briarproject.bramble.test.TestUtils.getAuthor; import static org.briarproject.bramble.test.TestUtils.getAuthor;
import static org.briarproject.bramble.test.TestUtils.getRandomBytes; import static org.briarproject.bramble.test.TestUtils.getRandomBytes;
@@ -25,12 +30,12 @@ import static org.briarproject.briar.api.privategroup.PrivateGroupConstants.GROU
import static org.briarproject.briar.api.privategroup.PrivateGroupConstants.MAX_GROUP_INVITATION_TEXT_LENGTH; import static org.briarproject.briar.api.privategroup.PrivateGroupConstants.MAX_GROUP_INVITATION_TEXT_LENGTH;
import static org.briarproject.briar.api.privategroup.PrivateGroupConstants.MAX_GROUP_NAME_LENGTH; import static org.briarproject.briar.api.privategroup.PrivateGroupConstants.MAX_GROUP_NAME_LENGTH;
import static org.briarproject.briar.api.privategroup.invitation.GroupInvitationFactory.SIGNING_LABEL_INVITE; import static org.briarproject.briar.api.privategroup.invitation.GroupInvitationFactory.SIGNING_LABEL_INVITE;
import static org.briarproject.briar.privategroup.invitation.GroupInvitationConstants.MSG_KEY_AUTO_DELETE_TIMER;
import static org.briarproject.briar.privategroup.invitation.MessageType.ABORT; import static org.briarproject.briar.privategroup.invitation.MessageType.ABORT;
import static org.briarproject.briar.privategroup.invitation.MessageType.INVITE; import static org.briarproject.briar.privategroup.invitation.MessageType.INVITE;
import static org.briarproject.briar.privategroup.invitation.MessageType.JOIN; import static org.briarproject.briar.privategroup.invitation.MessageType.JOIN;
import static org.briarproject.briar.privategroup.invitation.MessageType.LEAVE; import static org.briarproject.briar.privategroup.invitation.MessageType.LEAVE;
import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
public class GroupInvitationValidatorTest extends ValidatorTestCase { public class GroupInvitationValidatorTest extends ValidatorTestCase {
@@ -71,7 +76,7 @@ public class GroupInvitationValidatorTest extends ValidatorTestCase {
@Test(expected = FormatException.class) @Test(expected = FormatException.class)
public void testRejectsTooLongInviteMessage() throws Exception { public void testRejectsTooLongInviteMessage() throws Exception {
BdfList body = BdfList.of(INVITE.getValue(), creatorList, groupName, BdfList body = BdfList.of(INVITE.getValue(), creatorList, groupName,
salt, text, signature, ""); salt, text, signature, NO_AUTO_DELETE_TIMER, null);
validator.validateMessage(message, group, body); validator.validateMessage(message, group, body);
} }
@@ -182,8 +187,7 @@ public class GroupInvitationValidatorTest extends ValidatorTestCase {
public void testAcceptsInviteMessageWithNullText() throws Exception { public void testAcceptsInviteMessageWithNullText() throws Exception {
BdfList body = BdfList.of(INVITE.getValue(), creatorList, groupName, BdfList body = BdfList.of(INVITE.getValue(), creatorList, groupName,
salt, null, signature); salt, null, signature);
expectInviteMessage(false); testAcceptsInviteMessage(body, NO_AUTO_DELETE_TIMER, meta);
validator.validateMessage(message, group, body);
} }
@Test(expected = FormatException.class) @Test(expected = FormatException.class)
@@ -233,15 +237,73 @@ public class GroupInvitationValidatorTest extends ValidatorTestCase {
validator.validateMessage(message, group, body); validator.validateMessage(message, group, body);
} }
@Test(expected = FormatException.class)
public void testRejectsInviteMessageWithTooBigAutoDeleteTimer()
throws Exception {
BdfList body = BdfList.of(INVITE.getValue(), creatorList, groupName,
salt, text, signature, MAX_AUTO_DELETE_TIMER_MS + 1);
validator.validateMessage(message, group, body);
}
@Test(expected = FormatException.class)
public void testRejectsInviteMessageWithTooSmallAutoDeleteTimer()
throws Exception {
BdfList body = BdfList.of(INVITE.getValue(), creatorList, groupName,
salt, text, signature, MIN_AUTO_DELETE_TIMER_MS - 1);
validator.validateMessage(message, group, body);
}
@Test(expected = FormatException.class)
public void testRejectsInviteMessageWithNonLongAutoDeleteTimer()
throws Exception {
BdfList body = BdfList.of(INVITE.getValue(), creatorList, groupName,
salt, text, signature, "foo");
validator.validateMessage(message, group, body);
}
@Test @Test
public void testAcceptsValidInviteMessage() throws Exception { public void testAcceptsValidInviteMessage() throws Exception {
BdfList body = BdfList.of(INVITE.getValue(), creatorList, groupName, BdfList body = BdfList.of(INVITE.getValue(), creatorList, groupName,
salt, text, signature); salt, text, signature);
testAcceptsInviteMessage(body, NO_AUTO_DELETE_TIMER, meta);
}
@Test
public void testAcceptsInviteMessageWithNullAutoDeleteTimer()
throws Exception {
BdfList body = BdfList.of(INVITE.getValue(), creatorList, groupName,
salt, text, signature, null);
testAcceptsInviteMessage(body, NO_AUTO_DELETE_TIMER, meta);
}
@Test
public void testAcceptsInviteMessageWithMinAutoDeleteTimer()
throws Exception {
BdfList body = BdfList.of(INVITE.getValue(), creatorList, groupName,
salt, text, signature, MIN_AUTO_DELETE_TIMER_MS);
BdfDictionary metadata = new BdfDictionary(meta);
metadata.put(MSG_KEY_AUTO_DELETE_TIMER, MIN_AUTO_DELETE_TIMER_MS);
testAcceptsInviteMessage(body, MIN_AUTO_DELETE_TIMER_MS, metadata);
}
@Test
public void testAcceptsInviteMessageWithMaxAutoDeleteTimer()
throws Exception {
BdfList body = BdfList.of(INVITE.getValue(), creatorList, groupName,
salt, text, signature, MAX_AUTO_DELETE_TIMER_MS);
BdfDictionary metadata = new BdfDictionary(meta);
metadata.put(MSG_KEY_AUTO_DELETE_TIMER, MAX_AUTO_DELETE_TIMER_MS);
testAcceptsInviteMessage(body, MAX_AUTO_DELETE_TIMER_MS, metadata);
}
private void testAcceptsInviteMessage(BdfList body, long autoDeleteTimer,
BdfDictionary metadata) throws Exception {
expectInviteMessage(false); expectInviteMessage(false);
expectEncodeMetadata(INVITE, autoDeleteTimer, metadata);
BdfMessageContext messageContext = BdfMessageContext messageContext =
validator.validateMessage(message, group, body); validator.validateMessage(message, group, body);
assertTrue(messageContext.getDependencies().isEmpty()); assertEquals(emptyList(), messageContext.getDependencies());
assertEquals(meta, messageContext.getDictionary()); assertEquals(metadata, messageContext.getDictionary());
} }
private void expectInviteMessage(boolean exception) throws Exception { private void expectInviteMessage(boolean exception) throws Exception {
@@ -260,11 +322,6 @@ public class GroupInvitationValidatorTest extends ValidatorTestCase {
signed, creator.getPublicKey()); signed, creator.getPublicKey());
if (exception) { if (exception) {
will(throwException(new GeneralSecurityException())); will(throwException(new GeneralSecurityException()));
} else {
oneOf(messageEncoder).encodeMetadata(INVITE,
message.getGroupId(), message.getTimestamp(), false,
false, false, false, false);
will(returnValue(meta));
} }
}}); }});
} }
@@ -280,7 +337,7 @@ public class GroupInvitationValidatorTest extends ValidatorTestCase {
@Test(expected = FormatException.class) @Test(expected = FormatException.class)
public void testRejectsTooLongJoinMessage() throws Exception { public void testRejectsTooLongJoinMessage() throws Exception {
BdfList body = BdfList.of(JOIN.getValue(), privateGroup.getId(), BdfList body = BdfList.of(JOIN.getValue(), privateGroup.getId(),
previousMessageId, ""); previousMessageId, NO_AUTO_DELETE_TIMER, null);
validator.validateMessage(message, group, body); validator.validateMessage(message, group, body);
} }
@@ -339,14 +396,10 @@ public class GroupInvitationValidatorTest extends ValidatorTestCase {
public void testAcceptsJoinMessageWithNullPreviousMessageId() public void testAcceptsJoinMessageWithNullPreviousMessageId()
throws Exception { throws Exception {
BdfList body = BdfList.of(JOIN.getValue(), privateGroup.getId(), null); BdfList body = BdfList.of(JOIN.getValue(), privateGroup.getId(), null);
context.checking(new Expectations() {{ expectEncodeMetadata(JOIN, NO_AUTO_DELETE_TIMER, meta);
oneOf(messageEncoder).encodeMetadata(JOIN, message.getGroupId(),
message.getTimestamp(), false, false, false, false, false);
will(returnValue(meta));
}});
BdfMessageContext messageContext = BdfMessageContext messageContext =
validator.validateMessage(message, group, body); validator.validateMessage(message, group, body);
assertEquals(0, messageContext.getDependencies().size()); assertEquals(emptyList(), messageContext.getDependencies());
assertEquals(meta, messageContext.getDictionary()); assertEquals(meta, messageContext.getDictionary());
} }
@@ -354,17 +407,45 @@ public class GroupInvitationValidatorTest extends ValidatorTestCase {
public void testAcceptsValidJoinMessage() throws Exception { public void testAcceptsValidJoinMessage() throws Exception {
BdfList body = BdfList.of(JOIN.getValue(), privateGroup.getId(), BdfList body = BdfList.of(JOIN.getValue(), privateGroup.getId(),
previousMessageId); previousMessageId);
context.checking(new Expectations() {{ testAcceptsJoinMessage(body, NO_AUTO_DELETE_TIMER, meta);
oneOf(messageEncoder).encodeMetadata(JOIN, message.getGroupId(), }
message.getTimestamp(), false, false, false, false, false);
will(returnValue(meta)); @Test
}}); public void testAcceptsJoinMessageWithNullAutoDeleteTimer()
throws Exception {
BdfList body = BdfList.of(JOIN.getValue(), privateGroup.getId(),
previousMessageId, null);
testAcceptsJoinMessage(body, NO_AUTO_DELETE_TIMER, meta);
}
@Test
public void testAcceptsJoinMessageWitMinAutoDeleteTimer()
throws Exception {
BdfList body = BdfList.of(JOIN.getValue(), privateGroup.getId(),
previousMessageId, MIN_AUTO_DELETE_TIMER_MS);
BdfDictionary metadata = new BdfDictionary(meta);
metadata.put(MSG_KEY_AUTO_DELETE_TIMER, MIN_AUTO_DELETE_TIMER_MS);
testAcceptsJoinMessage(body, MIN_AUTO_DELETE_TIMER_MS, metadata);
}
@Test
public void testAcceptsJoinMessageWitMaxAutoDeleteTimer()
throws Exception {
BdfList body = BdfList.of(JOIN.getValue(), privateGroup.getId(),
previousMessageId, MAX_AUTO_DELETE_TIMER_MS);
BdfDictionary metadata = new BdfDictionary(meta);
metadata.put(MSG_KEY_AUTO_DELETE_TIMER, MAX_AUTO_DELETE_TIMER_MS);
testAcceptsJoinMessage(body, MAX_AUTO_DELETE_TIMER_MS, metadata);
}
private void testAcceptsJoinMessage(BdfList body, long autoDeleteTimer,
BdfDictionary metadata) throws Exception {
expectEncodeMetadata(JOIN, autoDeleteTimer, metadata);
BdfMessageContext messageContext = BdfMessageContext messageContext =
validator.validateMessage(message, group, body); validator.validateMessage(message, group, body);
assertEquals(1, messageContext.getDependencies().size()); assertEquals(singletonList(previousMessageId),
assertEquals(previousMessageId, messageContext.getDependencies());
messageContext.getDependencies().iterator().next()); assertEquals(metadata, messageContext.getDictionary());
assertEquals(meta, messageContext.getDictionary());
} }
// LEAVE message // LEAVE message
@@ -437,32 +518,56 @@ public class GroupInvitationValidatorTest extends ValidatorTestCase {
public void testAcceptsLeaveMessageWithNullPreviousMessageId() public void testAcceptsLeaveMessageWithNullPreviousMessageId()
throws Exception { throws Exception {
BdfList body = BdfList.of(LEAVE.getValue(), privateGroup.getId(), null); BdfList body = BdfList.of(LEAVE.getValue(), privateGroup.getId(), null);
context.checking(new Expectations() {{ expectEncodeMetadata(LEAVE, NO_AUTO_DELETE_TIMER, meta);
oneOf(messageEncoder).encodeMetadata(LEAVE, message.getGroupId(),
message.getTimestamp(), false, false, false, false, false);
will(returnValue(meta));
}});
BdfMessageContext messageContext = BdfMessageContext messageContext =
validator.validateMessage(message, group, body); validator.validateMessage(message, group, body);
assertEquals(0, messageContext.getDependencies().size()); assertEquals(emptyList(), messageContext.getDependencies());
assertEquals(meta, messageContext.getDictionary()); assertEquals(meta, messageContext.getDictionary());
} }
@Test @Test
public void testAcceptsValidLeaveMessage() throws Exception { public void testAcceptsValidLeaveMessage() throws Exception {
context.checking(new Expectations() {{
oneOf(messageEncoder).encodeMetadata(LEAVE, message.getGroupId(),
message.getTimestamp(), false, false, false, false, false);
will(returnValue(meta));
}});
BdfList body = BdfList.of(LEAVE.getValue(), privateGroup.getId(), BdfList body = BdfList.of(LEAVE.getValue(), privateGroup.getId(),
previousMessageId); previousMessageId);
testAcceptsLeaveMessage(body, NO_AUTO_DELETE_TIMER, meta);
}
@Test
public void testAcceptsLeaveMessageWithNullAutoDeleteTimer()
throws Exception {
BdfList body = BdfList.of(LEAVE.getValue(), privateGroup.getId(),
previousMessageId, null);
testAcceptsLeaveMessage(body, NO_AUTO_DELETE_TIMER, meta);
}
@Test
public void testAcceptsLeaveMessageWithMinAutoDeleteTimer()
throws Exception {
BdfList body = BdfList.of(LEAVE.getValue(), privateGroup.getId(),
previousMessageId, MIN_AUTO_DELETE_TIMER_MS);
BdfDictionary metadata = new BdfDictionary(meta);
metadata.put(MSG_KEY_AUTO_DELETE_TIMER, MIN_AUTO_DELETE_TIMER_MS);
testAcceptsLeaveMessage(body, MIN_AUTO_DELETE_TIMER_MS, metadata);
}
@Test
public void testAcceptsLeaveMessageWithMaxAutoDeleteTimer()
throws Exception {
BdfList body = BdfList.of(LEAVE.getValue(), privateGroup.getId(),
previousMessageId, MAX_AUTO_DELETE_TIMER_MS);
BdfDictionary metadata = new BdfDictionary(meta);
metadata.put(MSG_KEY_AUTO_DELETE_TIMER, MAX_AUTO_DELETE_TIMER_MS);
testAcceptsLeaveMessage(body, MAX_AUTO_DELETE_TIMER_MS, metadata);
}
private void testAcceptsLeaveMessage(BdfList body, long autoDeleteTimer,
BdfDictionary metadata) throws Exception {
expectEncodeMetadata(LEAVE, autoDeleteTimer, metadata);
BdfMessageContext messageContext = BdfMessageContext messageContext =
validator.validateMessage(message, group, body); validator.validateMessage(message, group, body);
assertEquals(1, messageContext.getDependencies().size()); assertEquals(singletonList(previousMessageId),
assertEquals(previousMessageId, messageContext.getDependencies());
messageContext.getDependencies().iterator().next()); assertEquals(metadata, messageContext.getDictionary());
assertEquals(meta, messageContext.getDictionary());
} }
// ABORT message // ABORT message
@@ -507,15 +612,11 @@ public class GroupInvitationValidatorTest extends ValidatorTestCase {
@Test @Test
public void testAcceptsValidAbortMessage() throws Exception { public void testAcceptsValidAbortMessage() throws Exception {
context.checking(new Expectations() {{
oneOf(messageEncoder).encodeMetadata(ABORT, message.getGroupId(),
message.getTimestamp(), false, false, false, false, false);
will(returnValue(meta));
}});
BdfList body = BdfList.of(ABORT.getValue(), privateGroup.getId()); BdfList body = BdfList.of(ABORT.getValue(), privateGroup.getId());
expectEncodeMetadata(ABORT, NO_AUTO_DELETE_TIMER, meta);
BdfMessageContext messageContext = BdfMessageContext messageContext =
validator.validateMessage(message, group, body); validator.validateMessage(message, group, body);
assertEquals(0, messageContext.getDependencies().size()); assertEquals(emptyList(), messageContext.getDependencies());
assertEquals(meta, messageContext.getDictionary()); assertEquals(meta, messageContext.getDictionary());
} }
@@ -531,4 +632,13 @@ public class GroupInvitationValidatorTest extends ValidatorTestCase {
validator.validateMessage(message, group, body); validator.validateMessage(message, group, body);
} }
private void expectEncodeMetadata(MessageType type,
long autoDeleteTimer, BdfDictionary metadata) {
context.checking(new Expectations() {{
oneOf(messageEncoder).encodeMetadata(type, message.getGroupId(),
message.getTimestamp(), false, false, false, false, false,
autoDeleteTimer);
will(returnValue(metadata));
}});
}
} }

View File

@@ -13,6 +13,7 @@ import org.junit.Test;
import java.util.Collections; import java.util.Collections;
import java.util.Map; import java.util.Map;
import static org.briarproject.bramble.api.autodelete.AutoDeleteConstants.NO_AUTO_DELETE_TIMER;
import static org.briarproject.bramble.api.sync.Group.Visibility.INVISIBLE; import static org.briarproject.bramble.api.sync.Group.Visibility.INVISIBLE;
import static org.briarproject.bramble.api.sync.Group.Visibility.SHARED; import static org.briarproject.bramble.api.sync.Group.Visibility.SHARED;
import static org.briarproject.bramble.api.sync.Group.Visibility.VISIBLE; import static org.briarproject.bramble.api.sync.Group.Visibility.VISIBLE;
@@ -131,7 +132,8 @@ public class InviteeProtocolEngineTest extends AbstractProtocolEngineTest {
public void testOnJoinActionFromInvited() throws Exception { public void testOnJoinActionFromInvited() throws Exception {
JoinMessage properJoinMessage = JoinMessage properJoinMessage =
new JoinMessage(messageId, contactGroupId, privateGroupId, new JoinMessage(messageId, contactGroupId, privateGroupId,
messageTimestamp, lastRemoteMessageId); messageTimestamp, lastRemoteMessageId,
NO_AUTO_DELETE_TIMER);
long timestamp = 0L; long timestamp = 0L;
GroupMessage joinGroupMessage = GroupMessage joinGroupMessage =
new GroupMessage(message, null, localAuthor); new GroupMessage(message, null, localAuthor);
@@ -329,7 +331,7 @@ public class InviteeProtocolEngineTest extends AbstractProtocolEngineTest {
privateGroup.getName(), privateGroup.getCreator(), privateGroup.getName(), privateGroup.getCreator(),
privateGroup.getSalt(), privateGroup.getSalt(),
getRandomString(MAX_GROUP_INVITATION_TEXT_LENGTH), getRandomString(MAX_GROUP_INVITATION_TEXT_LENGTH),
signature); signature, NO_AUTO_DELETE_TIMER);
Contact notCreatorContact = getContact(contactId, getAuthor(), Contact notCreatorContact = getContact(contactId, getAuthor(),
localAuthor.getId(), true); localAuthor.getId(), true);
@@ -352,7 +354,8 @@ public class InviteeProtocolEngineTest extends AbstractProtocolEngineTest {
new InviteMessage(new MessageId(getRandomId()), contactGroupId, new InviteMessage(new MessageId(getRandomId()), contactGroupId,
privateGroupId, session.getInviteTimestamp() + 1, privateGroupId, session.getInviteTimestamp() + 1,
privateGroup.getName(), privateGroup.getCreator(), privateGroup.getName(), privateGroup.getCreator(),
privateGroup.getSalt(), "msg", signature); privateGroup.getSalt(), "msg", signature,
NO_AUTO_DELETE_TIMER);
assertEquals(contact.getAuthor(), privateGroup.getCreator()); assertEquals(contact.getAuthor(), privateGroup.getCreator());
expectGetContactId(); expectGetContactId();
@@ -505,7 +508,7 @@ public class InviteeProtocolEngineTest extends AbstractProtocolEngineTest {
JoinMessage invalidJoinMessage = JoinMessage invalidJoinMessage =
new JoinMessage(new MessageId(getRandomId()), contactGroupId, new JoinMessage(new MessageId(getRandomId()), contactGroupId,
privateGroupId, session.getInviteTimestamp() + 1, privateGroupId, session.getInviteTimestamp() + 1,
lastLocalMessageId); lastLocalMessageId, NO_AUTO_DELETE_TIMER);
assertFalse(invalidJoinMessage.getTimestamp() <= assertFalse(invalidJoinMessage.getTimestamp() <=
session.getInviteTimestamp()); session.getInviteTimestamp());
assertNotNull(session.getLastRemoteMessageId()); assertNotNull(session.getLastRemoteMessageId());
@@ -525,7 +528,7 @@ public class InviteeProtocolEngineTest extends AbstractProtocolEngineTest {
JoinMessage properJoinMessage = JoinMessage properJoinMessage =
new JoinMessage(new MessageId(getRandomId()), contactGroupId, new JoinMessage(new MessageId(getRandomId()), contactGroupId,
privateGroupId, session.getInviteTimestamp() + 1, privateGroupId, session.getInviteTimestamp() + 1,
lastRemoteMessageId); lastRemoteMessageId, NO_AUTO_DELETE_TIMER);
assertFalse(properJoinMessage.getTimestamp() <= assertFalse(properJoinMessage.getTimestamp() <=
session.getInviteTimestamp()); session.getInviteTimestamp());
assertNotNull(session.getLastRemoteMessageId()); assertNotNull(session.getLastRemoteMessageId());
@@ -607,7 +610,8 @@ public class InviteeProtocolEngineTest extends AbstractProtocolEngineTest {
InviteeSession session = getDefaultSession(INVITED); InviteeSession session = getDefaultSession(INVITED);
LeaveMessage invalidLeaveMessage = LeaveMessage invalidLeaveMessage =
new LeaveMessage(new MessageId(getRandomId()), contactGroupId, new LeaveMessage(new MessageId(getRandomId()), contactGroupId,
privateGroupId, session.getInviteTimestamp() + 1, null); privateGroupId, session.getInviteTimestamp() + 1, null,
NO_AUTO_DELETE_TIMER);
assertFalse(invalidLeaveMessage.getTimestamp() <= assertFalse(invalidLeaveMessage.getTimestamp() <=
session.getInviteTimestamp()); session.getInviteTimestamp());
assertNull(invalidLeaveMessage.getPreviousMessageId()); assertNull(invalidLeaveMessage.getPreviousMessageId());
@@ -624,7 +628,8 @@ public class InviteeProtocolEngineTest extends AbstractProtocolEngineTest {
InviteeSession session = getDefaultSession(LEFT); InviteeSession session = getDefaultSession(LEFT);
LeaveMessage invalidLeaveMessage = LeaveMessage invalidLeaveMessage =
new LeaveMessage(new MessageId(getRandomId()), contactGroupId, new LeaveMessage(new MessageId(getRandomId()), contactGroupId,
privateGroupId, session.getInviteTimestamp() + 1, null); privateGroupId, session.getInviteTimestamp() + 1, null,
NO_AUTO_DELETE_TIMER);
assertFalse(invalidLeaveMessage.getTimestamp() <= assertFalse(invalidLeaveMessage.getTimestamp() <=
session.getInviteTimestamp()); session.getInviteTimestamp());
assertNull(invalidLeaveMessage.getPreviousMessageId()); assertNull(invalidLeaveMessage.getPreviousMessageId());
@@ -641,7 +646,7 @@ public class InviteeProtocolEngineTest extends AbstractProtocolEngineTest {
LeaveMessage properLeaveMessage = LeaveMessage properLeaveMessage =
new LeaveMessage(new MessageId(getRandomId()), contactGroupId, new LeaveMessage(new MessageId(getRandomId()), contactGroupId,
privateGroupId, session.getInviteTimestamp() + 1, privateGroupId, session.getInviteTimestamp() + 1,
lastRemoteMessageId); lastRemoteMessageId, NO_AUTO_DELETE_TIMER);
assertFalse(properLeaveMessage.getTimestamp() <= assertFalse(properLeaveMessage.getTimestamp() <=
session.getInviteTimestamp()); session.getInviteTimestamp());
assertNotNull(session.getLastRemoteMessageId()); assertNotNull(session.getLastRemoteMessageId());
@@ -671,7 +676,7 @@ public class InviteeProtocolEngineTest extends AbstractProtocolEngineTest {
LeaveMessage properLeaveMessage = LeaveMessage properLeaveMessage =
new LeaveMessage(new MessageId(getRandomId()), contactGroupId, new LeaveMessage(new MessageId(getRandomId()), contactGroupId,
privateGroupId, session.getInviteTimestamp() + 1, privateGroupId, session.getInviteTimestamp() + 1,
lastRemoteMessageId); lastRemoteMessageId, NO_AUTO_DELETE_TIMER);
assertFalse(properLeaveMessage.getTimestamp() <= assertFalse(properLeaveMessage.getTimestamp() <=
session.getInviteTimestamp()); session.getInviteTimestamp());
assertNotNull(session.getLastRemoteMessageId()); assertNotNull(session.getLastRemoteMessageId());

View File

@@ -5,6 +5,7 @@ import org.briarproject.briar.api.client.ProtocolStateException;
import org.jmock.Expectations; import org.jmock.Expectations;
import org.junit.Test; import org.junit.Test;
import static org.briarproject.bramble.api.autodelete.AutoDeleteConstants.NO_AUTO_DELETE_TIMER;
import static org.briarproject.bramble.api.sync.Group.Visibility.INVISIBLE; import static org.briarproject.bramble.api.sync.Group.Visibility.INVISIBLE;
import static org.briarproject.bramble.api.sync.Group.Visibility.SHARED; import static org.briarproject.bramble.api.sync.Group.Visibility.SHARED;
import static org.briarproject.bramble.api.sync.Group.Visibility.VISIBLE; import static org.briarproject.bramble.api.sync.Group.Visibility.VISIBLE;
@@ -17,9 +18,8 @@ import static org.briarproject.briar.privategroup.invitation.PeerState.LOCAL_LEF
import static org.briarproject.briar.privategroup.invitation.PeerState.NEITHER_JOINED; import static org.briarproject.briar.privategroup.invitation.PeerState.NEITHER_JOINED;
import static org.briarproject.briar.privategroup.invitation.PeerState.START; import static org.briarproject.briar.privategroup.invitation.PeerState.START;
import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
public class PeerProtocolEngineTest extends AbstractProtocolEngineTest { public class PeerProtocolEngineTest extends AbstractProtocolEngineTest {
@@ -37,43 +37,43 @@ public class PeerProtocolEngineTest extends AbstractProtocolEngineTest {
// onInviteAction // onInviteAction
@Test(expected = UnsupportedOperationException.class) @Test(expected = UnsupportedOperationException.class)
public void testOnInviteActionFromStart() throws Exception { public void testOnInviteActionFromStart() {
engine.onInviteAction(txn, getDefaultSession(START), null, engine.onInviteAction(txn, getDefaultSession(START), null,
messageTimestamp, signature); messageTimestamp, signature);
} }
@Test(expected = UnsupportedOperationException.class) @Test(expected = UnsupportedOperationException.class)
public void testOnInviteActionFromAwaitMember() throws Exception { public void testOnInviteActionFromAwaitMember() {
engine.onInviteAction(txn, getDefaultSession(AWAIT_MEMBER), null, engine.onInviteAction(txn, getDefaultSession(AWAIT_MEMBER), null,
messageTimestamp, signature); messageTimestamp, signature);
} }
@Test(expected = UnsupportedOperationException.class) @Test(expected = UnsupportedOperationException.class)
public void testOnInviteActionFromNeitherJoined() throws Exception { public void testOnInviteActionFromNeitherJoined() {
engine.onInviteAction(txn, getDefaultSession(NEITHER_JOINED), null, engine.onInviteAction(txn, getDefaultSession(NEITHER_JOINED), null,
messageTimestamp, signature); messageTimestamp, signature);
} }
@Test(expected = UnsupportedOperationException.class) @Test(expected = UnsupportedOperationException.class)
public void testOnInviteActionFromLocalJoined() throws Exception { public void testOnInviteActionFromLocalJoined() {
engine.onInviteAction(txn, getDefaultSession(LOCAL_JOINED), null, engine.onInviteAction(txn, getDefaultSession(LOCAL_JOINED), null,
messageTimestamp, signature); messageTimestamp, signature);
} }
@Test(expected = UnsupportedOperationException.class) @Test(expected = UnsupportedOperationException.class)
public void testOnInviteActionFromBothJoined() throws Exception { public void testOnInviteActionFromBothJoined() {
engine.onInviteAction(txn, getDefaultSession(BOTH_JOINED), null, engine.onInviteAction(txn, getDefaultSession(BOTH_JOINED), null,
messageTimestamp, signature); messageTimestamp, signature);
} }
@Test(expected = UnsupportedOperationException.class) @Test(expected = UnsupportedOperationException.class)
public void testOnInviteActionFromLocalLeft() throws Exception { public void testOnInviteActionFromLocalLeft() {
engine.onInviteAction(txn, getDefaultSession(LOCAL_LEFT), null, engine.onInviteAction(txn, getDefaultSession(LOCAL_LEFT), null,
messageTimestamp, signature); messageTimestamp, signature);
} }
@Test(expected = UnsupportedOperationException.class) @Test(expected = UnsupportedOperationException.class)
public void testOnInviteActionFromError() throws Exception { public void testOnInviteActionFromError() {
engine.onInviteAction(txn, getDefaultSession(ERROR), null, engine.onInviteAction(txn, getDefaultSession(ERROR), null,
messageTimestamp, signature); messageTimestamp, signature);
} }
@@ -109,7 +109,8 @@ public class PeerProtocolEngineTest extends AbstractProtocolEngineTest {
public void testOnJoinActionFromNeitherJoined() throws Exception { public void testOnJoinActionFromNeitherJoined() throws Exception {
JoinMessage joinMessage = JoinMessage joinMessage =
new JoinMessage(messageId, contactGroupId, new JoinMessage(messageId, contactGroupId,
privateGroupId, messageTimestamp, lastRemoteMessageId); privateGroupId, messageTimestamp, lastRemoteMessageId,
NO_AUTO_DELETE_TIMER);
PeerSession session = getDefaultSession(NEITHER_JOINED); PeerSession session = getDefaultSession(NEITHER_JOINED);
expectSendJoinMessage(joinMessage, false); expectSendJoinMessage(joinMessage, false);
@@ -125,7 +126,8 @@ public class PeerProtocolEngineTest extends AbstractProtocolEngineTest {
public void testOnJoinActionFromLocalLeft() throws Exception { public void testOnJoinActionFromLocalLeft() throws Exception {
JoinMessage joinMessage = JoinMessage joinMessage =
new JoinMessage(messageId, contactGroupId, new JoinMessage(messageId, contactGroupId,
privateGroupId, messageTimestamp, lastRemoteMessageId); privateGroupId, messageTimestamp, lastRemoteMessageId,
NO_AUTO_DELETE_TIMER);
PeerSession session = getDefaultSession(LOCAL_LEFT); PeerSession session = getDefaultSession(LOCAL_LEFT);
expectSendJoinMessage(joinMessage, false); expectSendJoinMessage(joinMessage, false);
@@ -216,7 +218,8 @@ public class PeerProtocolEngineTest extends AbstractProtocolEngineTest {
public void testOnMemberAddedFromAwaitMember() throws Exception { public void testOnMemberAddedFromAwaitMember() throws Exception {
JoinMessage joinMessage = JoinMessage joinMessage =
new JoinMessage(messageId, contactGroupId, new JoinMessage(messageId, contactGroupId,
privateGroupId, messageTimestamp, lastRemoteMessageId); privateGroupId, messageTimestamp, lastRemoteMessageId,
NO_AUTO_DELETE_TIMER);
PeerSession session = getDefaultSession(AWAIT_MEMBER); PeerSession session = getDefaultSession(AWAIT_MEMBER);
expectSendJoinMessage(joinMessage, false); expectSendJoinMessage(joinMessage, false);
@@ -361,12 +364,13 @@ public class PeerProtocolEngineTest extends AbstractProtocolEngineTest {
throws Exception { throws Exception {
JoinMessage invalidJoinMessage = JoinMessage invalidJoinMessage =
new JoinMessage(new MessageId(getRandomId()), contactGroupId, new JoinMessage(new MessageId(getRandomId()), contactGroupId,
privateGroupId, 0L, lastLocalMessageId); privateGroupId, 0L, lastLocalMessageId,
NO_AUTO_DELETE_TIMER);
PeerSession session = getDefaultSession(START); PeerSession session = getDefaultSession(START);
assertNotNull(invalidJoinMessage.getPreviousMessageId()); assertNotNull(invalidJoinMessage.getPreviousMessageId());
assertNotNull(session.getLastRemoteMessageId()); assertNotNull(session.getLastRemoteMessageId());
assertFalse(invalidJoinMessage.getPreviousMessageId() assertNotEquals(invalidJoinMessage.getPreviousMessageId(),
.equals(session.getLastRemoteMessageId())); session.getLastRemoteMessageId());
expectAbortWhenNotSubscribedToGroup(); expectAbortWhenNotSubscribedToGroup();
PeerSession newSession = PeerSession newSession =
@@ -379,8 +383,8 @@ public class PeerProtocolEngineTest extends AbstractProtocolEngineTest {
PeerSession session = getDefaultSession(START); PeerSession session = getDefaultSession(START);
assertNotNull(joinMessage.getPreviousMessageId()); assertNotNull(joinMessage.getPreviousMessageId());
assertNotNull(session.getLastRemoteMessageId()); assertNotNull(session.getLastRemoteMessageId());
assertTrue(joinMessage.getPreviousMessageId() assertEquals(joinMessage.getPreviousMessageId(),
.equals(session.getLastRemoteMessageId())); session.getLastRemoteMessageId());
PeerSession newSession = PeerSession newSession =
engine.onJoinMessage(txn, session, joinMessage); engine.onJoinMessage(txn, session, joinMessage);
@@ -399,12 +403,13 @@ public class PeerProtocolEngineTest extends AbstractProtocolEngineTest {
throws Exception { throws Exception {
JoinMessage invalidJoinMessage = JoinMessage invalidJoinMessage =
new JoinMessage(new MessageId(getRandomId()), contactGroupId, new JoinMessage(new MessageId(getRandomId()), contactGroupId,
privateGroupId, 0L, lastLocalMessageId); privateGroupId, 0L, lastLocalMessageId,
NO_AUTO_DELETE_TIMER);
PeerSession session = getDefaultSession(NEITHER_JOINED); PeerSession session = getDefaultSession(NEITHER_JOINED);
assertNotNull(invalidJoinMessage.getPreviousMessageId()); assertNotNull(invalidJoinMessage.getPreviousMessageId());
assertNotNull(session.getLastRemoteMessageId()); assertNotNull(session.getLastRemoteMessageId());
assertFalse(invalidJoinMessage.getPreviousMessageId() assertNotEquals(invalidJoinMessage.getPreviousMessageId(),
.equals(session.getLastRemoteMessageId())); session.getLastRemoteMessageId());
expectAbortWhenNotSubscribedToGroup(); expectAbortWhenNotSubscribedToGroup();
PeerSession newSession = PeerSession newSession =
@@ -417,10 +422,11 @@ public class PeerProtocolEngineTest extends AbstractProtocolEngineTest {
PeerSession session = getDefaultSession(NEITHER_JOINED); PeerSession session = getDefaultSession(NEITHER_JOINED);
assertNotNull(joinMessage.getPreviousMessageId()); assertNotNull(joinMessage.getPreviousMessageId());
assertNotNull(session.getLastRemoteMessageId()); assertNotNull(session.getLastRemoteMessageId());
assertTrue(joinMessage.getPreviousMessageId() assertEquals(joinMessage.getPreviousMessageId(),
.equals(session.getLastRemoteMessageId())); session.getLastRemoteMessageId());
JoinMessage myJoinMessage = new JoinMessage(messageId, contactGroupId, JoinMessage myJoinMessage = new JoinMessage(messageId, contactGroupId,
privateGroupId, messageTimestamp, lastRemoteMessageId); privateGroupId, messageTimestamp, lastRemoteMessageId,
NO_AUTO_DELETE_TIMER);
expectSendJoinMessage(myJoinMessage, false); expectSendJoinMessage(myJoinMessage, false);
expectSetPrivateGroupVisibility(SHARED); expectSetPrivateGroupVisibility(SHARED);
@@ -441,12 +447,13 @@ public class PeerProtocolEngineTest extends AbstractProtocolEngineTest {
throws Exception { throws Exception {
JoinMessage invalidJoinMessage = JoinMessage invalidJoinMessage =
new JoinMessage(new MessageId(getRandomId()), contactGroupId, new JoinMessage(new MessageId(getRandomId()), contactGroupId,
privateGroupId, 0L, lastLocalMessageId); privateGroupId, 0L, lastLocalMessageId,
NO_AUTO_DELETE_TIMER);
PeerSession session = getDefaultSession(LOCAL_JOINED); PeerSession session = getDefaultSession(LOCAL_JOINED);
assertNotNull(invalidJoinMessage.getPreviousMessageId()); assertNotNull(invalidJoinMessage.getPreviousMessageId());
assertNotNull(session.getLastRemoteMessageId()); assertNotNull(session.getLastRemoteMessageId());
assertFalse(invalidJoinMessage.getPreviousMessageId() assertNotEquals(invalidJoinMessage.getPreviousMessageId(),
.equals(session.getLastRemoteMessageId())); session.getLastRemoteMessageId());
expectAbortWhenNotSubscribedToGroup(); expectAbortWhenNotSubscribedToGroup();
PeerSession newSession = PeerSession newSession =
@@ -459,8 +466,8 @@ public class PeerProtocolEngineTest extends AbstractProtocolEngineTest {
PeerSession session = getDefaultSession(LOCAL_JOINED); PeerSession session = getDefaultSession(LOCAL_JOINED);
assertNotNull(joinMessage.getPreviousMessageId()); assertNotNull(joinMessage.getPreviousMessageId());
assertNotNull(session.getLastRemoteMessageId()); assertNotNull(session.getLastRemoteMessageId());
assertTrue(joinMessage.getPreviousMessageId() assertEquals(joinMessage.getPreviousMessageId(),
.equals(session.getLastRemoteMessageId())); session.getLastRemoteMessageId());
expectSetPrivateGroupVisibility(SHARED); expectSetPrivateGroupVisibility(SHARED);
expectRelationshipRevealed(false); expectRelationshipRevealed(false);
@@ -520,12 +527,13 @@ public class PeerProtocolEngineTest extends AbstractProtocolEngineTest {
throws Exception { throws Exception {
LeaveMessage invalidLeaveMessage = LeaveMessage invalidLeaveMessage =
new LeaveMessage(new MessageId(getRandomId()), contactGroupId, new LeaveMessage(new MessageId(getRandomId()), contactGroupId,
privateGroupId, 0L, lastLocalMessageId); privateGroupId, 0L, lastLocalMessageId,
NO_AUTO_DELETE_TIMER);
PeerSession session = getDefaultSession(AWAIT_MEMBER); PeerSession session = getDefaultSession(AWAIT_MEMBER);
assertNotNull(invalidLeaveMessage.getPreviousMessageId()); assertNotNull(invalidLeaveMessage.getPreviousMessageId());
assertNotNull(session.getLastRemoteMessageId()); assertNotNull(session.getLastRemoteMessageId());
assertFalse(invalidLeaveMessage.getPreviousMessageId() assertNotEquals(invalidLeaveMessage.getPreviousMessageId(),
.equals(session.getLastRemoteMessageId())); session.getLastRemoteMessageId());
expectAbortWhenSubscribedToGroup(); expectAbortWhenSubscribedToGroup();
PeerSession newSession = PeerSession newSession =
@@ -538,8 +546,8 @@ public class PeerProtocolEngineTest extends AbstractProtocolEngineTest {
PeerSession session = getDefaultSession(AWAIT_MEMBER); PeerSession session = getDefaultSession(AWAIT_MEMBER);
assertNotNull(leaveMessage.getPreviousMessageId()); assertNotNull(leaveMessage.getPreviousMessageId());
assertNotNull(session.getLastRemoteMessageId()); assertNotNull(session.getLastRemoteMessageId());
assertTrue(leaveMessage.getPreviousMessageId() assertEquals(leaveMessage.getPreviousMessageId(),
.equals(session.getLastRemoteMessageId())); session.getLastRemoteMessageId());
PeerSession newSession = PeerSession newSession =
engine.onLeaveMessage(txn, session, leaveMessage); engine.onLeaveMessage(txn, session, leaveMessage);
@@ -558,12 +566,13 @@ public class PeerProtocolEngineTest extends AbstractProtocolEngineTest {
throws Exception { throws Exception {
LeaveMessage invalidLeaveMessage = LeaveMessage invalidLeaveMessage =
new LeaveMessage(new MessageId(getRandomId()), contactGroupId, new LeaveMessage(new MessageId(getRandomId()), contactGroupId,
privateGroupId, 0L, lastLocalMessageId); privateGroupId, 0L, lastLocalMessageId,
NO_AUTO_DELETE_TIMER);
PeerSession session = getDefaultSession(LOCAL_LEFT); PeerSession session = getDefaultSession(LOCAL_LEFT);
assertNotNull(invalidLeaveMessage.getPreviousMessageId()); assertNotNull(invalidLeaveMessage.getPreviousMessageId());
assertNotNull(session.getLastRemoteMessageId()); assertNotNull(session.getLastRemoteMessageId());
assertFalse(invalidLeaveMessage.getPreviousMessageId() assertNotEquals(invalidLeaveMessage.getPreviousMessageId(),
.equals(session.getLastRemoteMessageId())); session.getLastRemoteMessageId());
expectAbortWhenSubscribedToGroup(); expectAbortWhenSubscribedToGroup();
PeerSession newSession = PeerSession newSession =
@@ -576,8 +585,8 @@ public class PeerProtocolEngineTest extends AbstractProtocolEngineTest {
PeerSession session = getDefaultSession(LOCAL_LEFT); PeerSession session = getDefaultSession(LOCAL_LEFT);
assertNotNull(leaveMessage.getPreviousMessageId()); assertNotNull(leaveMessage.getPreviousMessageId());
assertNotNull(session.getLastRemoteMessageId()); assertNotNull(session.getLastRemoteMessageId());
assertTrue(leaveMessage.getPreviousMessageId() assertEquals(leaveMessage.getPreviousMessageId(),
.equals(session.getLastRemoteMessageId())); session.getLastRemoteMessageId());
PeerSession newSession = PeerSession newSession =
engine.onLeaveMessage(txn, session, leaveMessage); engine.onLeaveMessage(txn, session, leaveMessage);
@@ -596,12 +605,13 @@ public class PeerProtocolEngineTest extends AbstractProtocolEngineTest {
throws Exception { throws Exception {
LeaveMessage invalidLeaveMessage = LeaveMessage invalidLeaveMessage =
new LeaveMessage(new MessageId(getRandomId()), contactGroupId, new LeaveMessage(new MessageId(getRandomId()), contactGroupId,
privateGroupId, 0L, lastLocalMessageId); privateGroupId, 0L, lastLocalMessageId,
NO_AUTO_DELETE_TIMER);
PeerSession session = getDefaultSession(BOTH_JOINED); PeerSession session = getDefaultSession(BOTH_JOINED);
assertNotNull(invalidLeaveMessage.getPreviousMessageId()); assertNotNull(invalidLeaveMessage.getPreviousMessageId());
assertNotNull(session.getLastRemoteMessageId()); assertNotNull(session.getLastRemoteMessageId());
assertFalse(invalidLeaveMessage.getPreviousMessageId() assertNotEquals(invalidLeaveMessage.getPreviousMessageId(),
.equals(session.getLastRemoteMessageId())); session.getLastRemoteMessageId());
expectAbortWhenSubscribedToGroup(); expectAbortWhenSubscribedToGroup();
PeerSession newSession = PeerSession newSession =
@@ -614,8 +624,8 @@ public class PeerProtocolEngineTest extends AbstractProtocolEngineTest {
PeerSession session = getDefaultSession(BOTH_JOINED); PeerSession session = getDefaultSession(BOTH_JOINED);
assertNotNull(leaveMessage.getPreviousMessageId()); assertNotNull(leaveMessage.getPreviousMessageId());
assertNotNull(session.getLastRemoteMessageId()); assertNotNull(session.getLastRemoteMessageId());
assertTrue(leaveMessage.getPreviousMessageId() assertEquals(leaveMessage.getPreviousMessageId(),
.equals(session.getLastRemoteMessageId())); session.getLastRemoteMessageId());
expectSetPrivateGroupVisibility(VISIBLE); // FIXME correct? expectSetPrivateGroupVisibility(VISIBLE); // FIXME correct?
PeerSession newSession = PeerSession newSession =
@@ -685,14 +695,14 @@ public class PeerProtocolEngineTest extends AbstractProtocolEngineTest {
} }
private void assertSessionAborted(PeerSession oldSession, private void assertSessionAborted(PeerSession oldSession,
PeerSession newSession) throws Exception { PeerSession newSession) {
assertEquals(ERROR, newSession.getState()); assertEquals(ERROR, newSession.getState());
assertSessionRecordedSentMessage(newSession); assertSessionRecordedSentMessage(newSession);
assertSessionConstantsUnchanged(oldSession, newSession); assertSessionConstantsUnchanged(oldSession, newSession);
} }
@Override @Override
protected void assertSessionRecordedSentMessage(Session s) { protected void assertSessionRecordedSentMessage(Session<?> s) {
assertEquals(messageId, s.getLastLocalMessageId()); assertEquals(messageId, s.getLastLocalMessageId());
assertEquals(lastRemoteMessageId, s.getLastRemoteMessageId()); assertEquals(lastRemoteMessageId, s.getLastRemoteMessageId());
assertEquals(messageTimestamp, s.getLocalTimestamp()); assertEquals(messageTimestamp, s.getLocalTimestamp());