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.
*/
int MINOR_VERSION = 0;
int MINOR_VERSION = 1;
/**
* 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.concurrent.Immutable;
import static org.briarproject.bramble.api.autodelete.AutoDeleteConstants.NO_AUTO_DELETE_TIMER;
@Immutable
@NotNullByDefault
public class GroupInvitationRequest extends InvitationRequest<PrivateGroup> {
@@ -20,9 +18,10 @@ public class GroupInvitationRequest extends InvitationRequest<PrivateGroup> {
public GroupInvitationRequest(MessageId id, GroupId groupId, long time,
boolean local, boolean read, boolean sent, boolean seen,
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,
text, available, canBeOpened, NO_AUTO_DELETE_TIMER);
text, available, canBeOpened, autoDeleteTimer);
}
@Override

View File

@@ -9,17 +9,16 @@ import org.briarproject.briar.api.sharing.InvitationResponse;
import javax.annotation.concurrent.Immutable;
import static org.briarproject.bramble.api.autodelete.AutoDeleteConstants.NO_AUTO_DELETE_TIMER;
@Immutable
@NotNullByDefault
public class GroupInvitationResponse extends InvitationResponse {
public GroupInvitationResponse(MessageId id, GroupId groupId, long time,
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,
accept, shareableId, NO_AUTO_DELETE_TIMER);
accept, shareableId, autoDeleteTimer);
}
@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.PrivateGroupFactory;
import org.briarproject.briar.api.privategroup.PrivateGroupManager;
import org.briarproject.briar.api.privategroup.invitation.GroupInvitationManager;
import java.util.Map;
import javax.annotation.Nullable;
import javax.annotation.concurrent.Immutable;
import static org.briarproject.briar.api.privategroup.PrivateGroupManager.CLIENT_ID;
import static org.briarproject.briar.api.privategroup.PrivateGroupManager.MAJOR_VERSION;
import static org.briarproject.bramble.api.autodelete.AutoDeleteConstants.NO_AUTO_DELETE_TIMER;
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.INVITE;
@@ -39,7 +39,7 @@ import static org.briarproject.briar.privategroup.invitation.MessageType.LEAVE;
@Immutable
@NotNullByDefault
abstract class AbstractProtocolEngine<S extends Session>
abstract class AbstractProtocolEngine<S extends Session<?>>
implements ProtocolEngine<S> {
protected final DatabaseComponent db;
@@ -90,6 +90,7 @@ abstract class AbstractProtocolEngine<S extends Session>
return group.getClientId().equals(PrivateGroupManager.CLIENT_ID);
}
@SuppressWarnings("BooleanMethodIsAlwaysInverted")
boolean isValidDependency(S session, @Nullable MessageId dependency) {
MessageId expected = session.getLastRemoteMessageId();
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
ContactId contactId = getContactId(txn, session.getContactGroupId());
Visibility client = clientVersioningManager.getClientVisibility(txn,
contactId, CLIENT_ID, MAJOR_VERSION);
contactId, PrivateGroupManager.CLIENT_ID,
PrivateGroupManager.MAJOR_VERSION);
Visibility min = Visibility.min(preferred, client);
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)
throws DbException {
Group g = db.getGroup(txn, session.getPrivateGroupId());
Group g = db.getGroup(txn, s.getPrivateGroupId());
PrivateGroup privateGroup;
try {
privateGroup = privateGroupFactory.parsePrivateGroup(g);
} catch (FormatException e) {
throw new DbException(e); // Invalid group descriptor
}
Message m = messageEncoder.encodeInviteMessage(
session.getContactGroupId(), privateGroup.getId(),
timestamp, privateGroup.getName(), privateGroup.getCreator(),
privateGroup.getSalt(), text, signature);
sendMessage(txn, m, INVITE, privateGroup.getId(), true);
Message m;
if (contactSupportsAutoDeletion(txn, s.getContactGroupId())) {
// TODO: Look up the current auto-delete timer
long timer = NO_AUTO_DELETE_TIMER;
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;
}
Message sendJoinMessage(Transaction txn, S session, boolean visibleInUi)
Message sendJoinMessage(Transaction txn, S s, boolean visibleInUi)
throws DbException {
Message m = messageEncoder.encodeJoinMessage(
session.getContactGroupId(), session.getPrivateGroupId(),
getLocalTimestamp(session), session.getLastLocalMessageId());
sendMessage(txn, m, JOIN, session.getPrivateGroupId(), visibleInUi);
Message m;
if (contactSupportsAutoDeletion(txn, s.getContactGroupId())) {
// TODO: Look up the current auto-delete timer if the message is
// 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;
}
Message sendLeaveMessage(Transaction txn, S session, boolean visibleInUi)
Message sendLeaveMessage(Transaction txn, S s, boolean visibleInUi)
throws DbException {
Message m = messageEncoder.encodeLeaveMessage(
session.getContactGroupId(), session.getPrivateGroupId(),
getLocalTimestamp(session), session.getLastLocalMessageId());
sendMessage(txn, m, LEAVE, session.getPrivateGroupId(), visibleInUi);
Message m;
if (contactSupportsAutoDeletion(txn, s.getContactGroupId())) {
// TODO: Look up the current auto-delete timer if the message is
// 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;
}
@@ -146,7 +186,8 @@ abstract class AbstractProtocolEngine<S extends Session>
Message m = messageEncoder.encodeAbortMessage(
session.getContactGroupId(), session.getPrivateGroupId(),
getLocalTimestamp(session));
sendMessage(txn, m, ABORT, session.getPrivateGroupId(), false);
sendMessage(txn, m, ABORT, session.getPrivateGroupId(), false,
NO_AUTO_DELETE_TIMER);
return m;
}
@@ -217,11 +258,11 @@ abstract class AbstractProtocolEngine<S extends Session>
}
private void sendMessage(Transaction txn, Message m, MessageType type,
GroupId privateGroupId, boolean visibleInConversation)
throws DbException {
BdfDictionary meta = messageEncoder
.encodeMetadata(type, privateGroupId, m.getTimestamp(), true,
true, visibleInConversation, false, false);
GroupId privateGroupId, boolean visibleInConversation,
long autoDeleteTimer) throws DbException {
BdfDictionary meta = messageEncoder.encodeMetadata(type,
privateGroupId, m.getTimestamp(), true, true,
visibleInConversation, false, false, autoDeleteTimer);
try {
clientHelper.addLocalMessage(txn, m, meta, true, false);
} 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(
GroupInvitationMessage m, boolean accept) {
DeletableGroupInvitationMessage m, boolean accept) {
SessionId sessionId = new SessionId(m.getPrivateGroupId().getBytes());
return new GroupInvitationResponse(m.getId(), m.getContactGroupId(),
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_AVAILABLE_TO_ANSWER = "availableToAnswer";
String MSG_KEY_INVITATION_ACCEPTED = "invitationAccepted";
String MSG_KEY_AUTO_DELETE_TIMER = "autoDeleteTimer";
// Session keys
String SESSION_KEY_IS_SESSION = "isSession";

View File

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

View File

@@ -21,10 +21,15 @@ import org.briarproject.briar.api.privategroup.PrivateGroupFactory;
import java.security.GeneralSecurityException;
import java.util.Collections;
import javax.annotation.Nullable;
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.util.ValidationUtils.checkLength;
import static org.briarproject.bramble.util.ValidationUtils.checkRange;
import static org.briarproject.bramble.util.ValidationUtils.checkSize;
import static org.briarproject.briar.api.privategroup.PrivateGroupConstants.GROUP_SALT_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)
throws FormatException {
// Message type, creator, group name, salt, optional text, signature
checkSize(body, 6);
// 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.
checkSize(body, 6, 7);
BdfList creatorList = body.getList(1);
String groupName = body.getString(2);
checkLength(groupName, 1, MAX_GROUP_NAME_LENGTH);
@@ -82,6 +90,8 @@ class GroupInvitationValidator extends BdfMessageValidator {
checkLength(text, 1, MAX_GROUP_INVITATION_TEXT_LENGTH);
byte[] signature = body.getRaw(5);
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
Author creator = clientHelper.parseAndValidateAuthor(creatorList);
@@ -102,20 +112,27 @@ class GroupInvitationValidator extends BdfMessageValidator {
// Create the metadata
BdfDictionary meta = messageEncoder.encodeMetadata(INVITE,
privateGroup.getId(), m.getTimestamp(), false, false, false,
false, false);
false, false, timer);
return new BdfMessageContext(meta);
}
private BdfMessageContext validateJoinMessage(Message m, BdfList body)
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);
checkLength(privateGroupId, UniqueId.LENGTH);
byte[] previousMessageId = body.getOptionalRaw(2);
checkLength(previousMessageId, UniqueId.LENGTH);
long timer = NO_AUTO_DELETE_TIMER;
if (body.size() == 4) timer = validateTimer(body.getOptionalLong(3));
BdfDictionary meta = messageEncoder.encodeMetadata(JOIN,
new GroupId(privateGroupId), m.getTimestamp(), false, false,
false, false, false);
false, false, false, timer);
if (previousMessageId == null) {
return new BdfMessageContext(meta);
} else {
@@ -127,14 +144,21 @@ class GroupInvitationValidator extends BdfMessageValidator {
private BdfMessageContext validateLeaveMessage(Message m, BdfList body)
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);
checkLength(privateGroupId, UniqueId.LENGTH);
byte[] previousMessageId = body.getOptionalRaw(2);
checkLength(previousMessageId, UniqueId.LENGTH);
long timer = NO_AUTO_DELETE_TIMER;
if (body.size() == 4) timer = validateTimer(body.getOptionalLong(3));
BdfDictionary meta = messageEncoder.encodeMetadata(LEAVE,
new GroupId(privateGroupId), m.getTimestamp(), false, false,
false, false, false);
false, false, false, timer);
if (previousMessageId == null) {
return new BdfMessageContext(meta);
} else {
@@ -151,7 +175,13 @@ class GroupInvitationValidator extends BdfMessageValidator {
checkLength(privateGroupId, UniqueId.LENGTH);
BdfDictionary meta = messageEncoder.encodeMetadata(ABORT,
new GroupId(privateGroupId), m.getTimestamp(), false, false,
false, false, false);
false, false, false, NO_AUTO_DELETE_TIMER);
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
@NotNullByDefault
class InviteMessage extends GroupInvitationMessage {
class InviteMessage extends DeletableGroupInvitationMessage {
private final String groupName;
private final Author creator;
@@ -20,8 +20,8 @@ class InviteMessage extends GroupInvitationMessage {
InviteMessage(MessageId id, GroupId contactGroupId, GroupId privateGroupId,
long timestamp, String groupName, Author creator, byte[] salt,
@Nullable String text, byte[] signature) {
super(id, contactGroupId, privateGroupId, timestamp);
@Nullable String text, byte[] signature, long autoDeleteTimer) {
super(id, contactGroupId, privateGroupId, timestamp, autoDeleteTimer);
this.groupName = groupName;
this.creator = creator;
this.salt = salt;

View File

@@ -330,7 +330,7 @@ class InviteeProtocolEngine extends AbstractProtocolEngine<InviteeSession> {
SessionId sessionId = new SessionId(m.getPrivateGroupId().getBytes());
return new GroupInvitationRequest(m.getId(), m.getContactGroupId(),
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
@NotNullByDefault
class JoinMessage extends GroupInvitationMessage {
class JoinMessage extends DeletableGroupInvitationMessage {
@Nullable
private final MessageId previousMessageId;
JoinMessage(MessageId id, GroupId contactGroupId, GroupId privateGroupId,
long timestamp, @Nullable MessageId previousMessageId) {
super(id, contactGroupId, privateGroupId, timestamp);
long timestamp, @Nullable MessageId previousMessageId,
long autoDeleteTimer) {
super(id, contactGroupId, privateGroupId, timestamp, autoDeleteTimer);
this.previousMessageId = previousMessageId;
}

View File

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

View File

@@ -14,7 +14,7 @@ interface MessageEncoder {
BdfDictionary encodeMetadata(MessageType type, GroupId privateGroupId,
long timestamp, boolean local, boolean read, boolean visible,
boolean available, boolean accepted);
boolean available, boolean accepted, long autoDeleteTimer);
void setVisibleInUi(BdfDictionary meta, boolean visible);
@@ -22,16 +22,49 @@ interface MessageEncoder {
void setInvitationAccepted(BdfDictionary meta, boolean accepted);
/**
* Encodes an invite message without an auto-delete timer.
*/
Message encodeInviteMessage(GroupId contactGroupId, GroupId privateGroupId,
long timestamp, String groupName, Author creator, byte[] salt,
@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,
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,
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,
long timestamp);
}

View File

@@ -15,7 +15,9 @@ import javax.annotation.Nullable;
import javax.annotation.concurrent.Immutable;
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.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_INVITATION_ACCEPTED;
import static org.briarproject.briar.privategroup.invitation.GroupInvitationConstants.MSG_KEY_LOCAL;
@@ -45,7 +47,8 @@ class MessageEncoderImpl implements MessageEncoder {
@Override
public BdfDictionary encodeMetadata(MessageType type,
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();
meta.put(MSG_KEY_MESSAGE_TYPE, type.getValue());
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_AVAILABLE_TO_ANSWER, available);
meta.put(MSG_KEY_INVITATION_ACCEPTED, accepted);
if (autoDeleteTimer != NO_AUTO_DELETE_TIMER) {
meta.put(MSG_KEY_AUTO_DELETE_TIMER, autoDeleteTimer);
}
return meta;
}
@@ -87,12 +93,25 @@ class MessageEncoderImpl implements MessageEncoder {
text,
signature
);
try {
return messageFactory.createMessage(contactGroupId, timestamp,
clientHelper.toByteArray(body));
} catch (FormatException e) {
throw new AssertionError(e);
}
return createMessage(contactGroupId, timestamp, body);
}
@Override
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
@@ -104,12 +123,20 @@ class MessageEncoderImpl implements MessageEncoder {
privateGroupId,
previousMessageId
);
try {
return messageFactory.createMessage(contactGroupId, timestamp,
clientHelper.toByteArray(body));
} catch (FormatException e) {
throw new AssertionError(e);
}
return createMessage(contactGroupId, timestamp, body);
}
@Override
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
@@ -121,12 +148,20 @@ class MessageEncoderImpl implements MessageEncoder {
privateGroupId,
previousMessageId
);
try {
return messageFactory.createMessage(contactGroupId, timestamp,
clientHelper.toByteArray(body));
} catch (FormatException e) {
throw new AssertionError(e);
}
return createMessage(contactGroupId, timestamp, body);
}
@Override
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
@@ -136,6 +171,11 @@ class MessageEncoderImpl implements MessageEncoder {
ABORT.getValue(),
privateGroupId
);
return createMessage(contactGroupId, timestamp, body);
}
private Message createMessage(GroupId contactGroupId, long timestamp,
BdfList body) {
try {
return messageFactory.createMessage(contactGroupId, timestamp,
clientHelper.toByteArray(body));
@@ -143,4 +183,9 @@ class MessageEncoderImpl implements MessageEncoder {
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 GroupId privateGroupId;
private final long timestamp;
private final long timestamp, autoDeleteTimer;
private final boolean local, read, visible, available, accepted;
MessageMetadata(MessageType type, GroupId privateGroupId,
long timestamp, boolean local, boolean read, boolean visible,
boolean available, boolean accepted) {
boolean available, boolean accepted, long autoDeleteTimer) {
this.privateGroupId = privateGroupId;
this.type = type;
this.timestamp = timestamp;
@@ -25,6 +25,7 @@ class MessageMetadata {
this.visible = visible;
this.available = available;
this.accepted = accepted;
this.autoDeleteTimer = autoDeleteTimer;
}
MessageType getMessageType() {
@@ -64,4 +65,7 @@ class MessageMetadata {
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.Transaction;
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.sync.GroupId;
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.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.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_INVITATION_ACCEPTED;
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
class MessageParserImpl implements MessageParser {
private final AuthorFactory authorFactory;
private final PrivateGroupFactory privateGroupFactory;
private final ClientHelper clientHelper;
@Inject
MessageParserImpl(AuthorFactory authorFactory,
PrivateGroupFactory privateGroupFactory,
MessageParserImpl(PrivateGroupFactory privateGroupFactory,
ClientHelper clientHelper) {
this.authorFactory = authorFactory;
this.privateGroupFactory = privateGroupFactory;
this.clientHelper = clientHelper;
}
@@ -82,8 +80,10 @@ class MessageParserImpl implements MessageParser {
boolean visible = meta.getBoolean(MSG_KEY_VISIBLE_IN_UI, false);
boolean available = meta.getBoolean(MSG_KEY_AVAILABLE_TO_ANSWER, 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,
visible, available, accepted);
visible, available, accepted, timer);
}
@Override
@@ -97,39 +97,58 @@ class MessageParserImpl implements MessageParser {
@Override
public InviteMessage parseInviteMessage(Message m, BdfList body)
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);
String groupName = body.getString(2);
byte[] salt = body.getRaw(3);
String text = body.getOptionalString(4);
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);
PrivateGroup privateGroup = privateGroupFactory.createPrivateGroup(
groupName, creator, salt);
return new InviteMessage(m.getId(), m.getGroupId(),
privateGroup.getId(), m.getTimestamp(), groupName, creator,
salt, text, signature);
salt, text, signature, timer);
}
@Override
public JoinMessage parseJoinMessage(Message m, BdfList body)
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));
byte[] b = body.getOptionalRaw(2);
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,
m.getTimestamp(), previousMessageId);
m.getTimestamp(), previousMessageId, timer);
}
@Override
public LeaveMessage parseLeaveMessage(Message m, BdfList body)
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));
byte[] b = body.getOptionalRaw(2);
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,
m.getTimestamp(), previousMessageId);
m.getTimestamp(), previousMessageId, timer);
}
@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.PrivateGroupFactory;
import org.briarproject.briar.api.privategroup.PrivateGroupManager;
import org.briarproject.briar.api.privategroup.invitation.GroupInvitationManager;
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.sync.Group.Visibility.SHARED;
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.MAX_GROUP_INVITATION_TEXT_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.MessageType.ABORT;
import static org.briarproject.briar.privategroup.invitation.MessageType.INVITE;
@@ -67,7 +67,8 @@ abstract class AbstractProtocolEngineTest extends BrambleMockTestCase {
final ContactId contactId = contact.getId();
final Author author = contact.getAuthor();
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 PrivateGroup privateGroup = new PrivateGroup(privateGroupGroup,
getRandomString(MAX_GROUP_NAME_LENGTH), author,
@@ -80,30 +81,34 @@ abstract class AbstractProtocolEngineTest extends BrambleMockTestCase {
final long messageTimestamp = message.getTimestamp();
final long inviteTimestamp = messageTimestamp - 1;
final long localTimestamp = inviteTimestamp - 1;
final BdfDictionary groupMeta = BdfDictionary.of(
new BdfEntry(GROUP_KEY_CONTACT_ID, contactId.getInt()));
final InviteMessage inviteMessage =
new InviteMessage(new MessageId(getRandomId()), contactGroupId,
privateGroupId, 0L, privateGroup.getName(),
privateGroup.getCreator(), privateGroup.getSalt(),
getRandomString(MAX_GROUP_INVITATION_TEXT_LENGTH),
signature);
signature, NO_AUTO_DELETE_TIMER);
final JoinMessage joinMessage =
new JoinMessage(new MessageId(getRandomId()), contactGroupId,
privateGroupId, 0L, lastRemoteMessageId);
privateGroupId, 0L, lastRemoteMessageId,
NO_AUTO_DELETE_TIMER);
final LeaveMessage leaveMessage =
new LeaveMessage(new MessageId(getRandomId()), contactGroupId,
privateGroupId, 0L, lastRemoteMessageId);
privateGroupId, 0L, lastRemoteMessageId,
NO_AUTO_DELETE_TIMER);
final AbortMessage abortMessage =
new AbortMessage(messageId, contactGroupId, privateGroupId,
inviteTimestamp + 1);
void assertSessionConstantsUnchanged(Session s1, Session s2) {
void assertSessionConstantsUnchanged(Session<?> s1, Session<?> s2) {
assertEquals(s1.getRole(), s2.getRole());
assertEquals(s1.getContactGroupId(), s2.getContactGroupId());
assertEquals(s1.getPrivateGroupId(), s2.getPrivateGroupId());
}
void assertSessionRecordedSentMessage(Session s) {
void assertSessionRecordedSentMessage(Session<?> s) {
assertEquals(messageId, s.getLastLocalMessageId());
assertEquals(lastRemoteMessageId, s.getLastRemoteMessageId());
assertEquals(messageTimestamp, s.getLocalTimestamp());
@@ -118,11 +123,13 @@ abstract class AbstractProtocolEngineTest extends BrambleMockTestCase {
}
void expectSendInviteMessage(String text) throws Exception {
expectCheckWhetherContactSupportsAutoDeletion();
expectGetLocalTimestamp(messageTimestamp);
context.checking(new Expectations() {{
oneOf(messageEncoder)
.encodeInviteMessage(contactGroupId, privateGroupId,
inviteTimestamp, privateGroup.getName(), author,
privateGroup.getSalt(), text, signature);
oneOf(messageEncoder).encodeInviteMessage(contactGroupId,
privateGroupId, inviteTimestamp, privateGroup.getName(),
author, privateGroup.getSalt(), text, signature,
NO_AUTO_DELETE_TIMER);
will(returnValue(message));
}});
expectSendMessage(INVITE, true);
@@ -130,22 +137,24 @@ abstract class AbstractProtocolEngineTest extends BrambleMockTestCase {
void expectSendJoinMessage(JoinMessage m, boolean visible)
throws Exception {
expectCheckWhetherContactSupportsAutoDeletion();
expectGetLocalTimestamp(messageTimestamp);
context.checking(new Expectations() {{
oneOf(messageEncoder).encodeJoinMessage(m.getContactGroupId(),
m.getPrivateGroupId(), m.getTimestamp(),
lastLocalMessageId);
lastLocalMessageId, NO_AUTO_DELETE_TIMER);
will(returnValue(message));
}});
expectSendMessage(JOIN, visible);
}
void expectSendLeaveMessage(boolean visible) throws Exception {
expectCheckWhetherContactSupportsAutoDeletion();
expectGetLocalTimestamp(messageTimestamp);
context.checking(new Expectations() {{
oneOf(messageEncoder)
.encodeLeaveMessage(contactGroupId, privateGroupId,
messageTimestamp, lastLocalMessageId);
oneOf(messageEncoder).encodeLeaveMessage(contactGroupId,
privateGroupId, messageTimestamp, lastLocalMessageId,
NO_AUTO_DELETE_TIMER);
will(returnValue(message));
}});
expectSendMessage(LEAVE, visible);
@@ -167,7 +176,8 @@ abstract class AbstractProtocolEngineTest extends BrambleMockTestCase {
BdfDictionary meta = BdfDictionary.of(new BdfEntry("me", "ta"));
context.checking(new Expectations() {{
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));
oneOf(clientHelper).addLocalMessage(txn, message, meta, true,
false);
@@ -178,7 +188,8 @@ abstract class AbstractProtocolEngineTest extends BrambleMockTestCase {
expectGetContactId();
context.checking(new Expectations() {{
oneOf(clientVersioningManager).getClientVisibility(txn, contactId,
CLIENT_ID, MAJOR_VERSION);
PrivateGroupManager.CLIENT_ID,
PrivateGroupManager.MAJOR_VERSION);
will(returnValue(SHARED));
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.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.SHARED;
import static org.briarproject.bramble.test.TestUtils.getRandomId;
@@ -77,7 +78,6 @@ public class CreatorProtocolEngineTest extends AbstractProtocolEngineTest {
oneOf(messageTracker).trackOutgoingMessage(txn, message);
}});
expectSendInviteMessage(text);
expectGetLocalTimestamp(messageTimestamp);
}
@Test(expected = ProtocolStateException.class)
@@ -289,7 +289,7 @@ public class CreatorProtocolEngineTest extends AbstractProtocolEngineTest {
CreatorSession session = getDefaultSession(INVITED);
JoinMessage invalidJoinMessage =
new JoinMessage(messageId, contactGroupId, privateGroupId,
inviteTimestamp + 1, messageId);
inviteTimestamp + 1, messageId, NO_AUTO_DELETE_TIMER);
expectAbortWhenSubscribedToGroup();
CreatorSession newSession =
@@ -303,7 +303,7 @@ public class CreatorProtocolEngineTest extends AbstractProtocolEngineTest {
JoinMessage properJoinMessage =
new JoinMessage(new MessageId(getRandomId()), contactGroupId,
privateGroupId, inviteTimestamp + 1,
lastRemoteMessageId);
lastRemoteMessageId, NO_AUTO_DELETE_TIMER);
expectSendJoinMessage(properJoinMessage, false);
expectMarkMessageVisibleInUi(properJoinMessage.getId());
@@ -343,7 +343,8 @@ public class CreatorProtocolEngineTest extends AbstractProtocolEngineTest {
public void testOnLeaveMessageFromStart() throws Exception {
LeaveMessage leaveMessage =
new LeaveMessage(messageId, contactGroupId, privateGroupId,
inviteTimestamp, lastLocalMessageId);
inviteTimestamp, lastLocalMessageId,
NO_AUTO_DELETE_TIMER);
CreatorSession session = getDefaultSession(START);
expectAbortWhenSubscribedToGroup();
@@ -377,7 +378,8 @@ public class CreatorProtocolEngineTest extends AbstractProtocolEngineTest {
throws Exception {
LeaveMessage invalidLeaveMessage =
new LeaveMessage(messageId, contactGroupId, privateGroupId,
inviteTimestamp + 1, lastLocalMessageId);
inviteTimestamp + 1, lastLocalMessageId,
NO_AUTO_DELETE_TIMER);
CreatorSession session = getDefaultSession(INVITED);
expectAbortWhenSubscribedToGroup();
@@ -392,7 +394,7 @@ public class CreatorProtocolEngineTest extends AbstractProtocolEngineTest {
LeaveMessage properLeaveMessage =
new LeaveMessage(new MessageId(getRandomId()), contactGroupId,
privateGroupId, inviteTimestamp + 1,
lastRemoteMessageId);
lastRemoteMessageId, NO_AUTO_DELETE_TIMER);
CreatorSession session = getDefaultSession(INVITED);
expectMarkMessageVisibleInUi(properLeaveMessage.getId());

View File

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

View File

@@ -16,6 +16,11 @@ import org.junit.Test;
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.test.TestUtils.getAuthor;
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_NAME_LENGTH;
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.INVITE;
import static org.briarproject.briar.privategroup.invitation.MessageType.JOIN;
import static org.briarproject.briar.privategroup.invitation.MessageType.LEAVE;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
public class GroupInvitationValidatorTest extends ValidatorTestCase {
@@ -71,7 +76,7 @@ public class GroupInvitationValidatorTest extends ValidatorTestCase {
@Test(expected = FormatException.class)
public void testRejectsTooLongInviteMessage() throws Exception {
BdfList body = BdfList.of(INVITE.getValue(), creatorList, groupName,
salt, text, signature, "");
salt, text, signature, NO_AUTO_DELETE_TIMER, null);
validator.validateMessage(message, group, body);
}
@@ -182,8 +187,7 @@ public class GroupInvitationValidatorTest extends ValidatorTestCase {
public void testAcceptsInviteMessageWithNullText() throws Exception {
BdfList body = BdfList.of(INVITE.getValue(), creatorList, groupName,
salt, null, signature);
expectInviteMessage(false);
validator.validateMessage(message, group, body);
testAcceptsInviteMessage(body, NO_AUTO_DELETE_TIMER, meta);
}
@Test(expected = FormatException.class)
@@ -233,15 +237,73 @@ public class GroupInvitationValidatorTest extends ValidatorTestCase {
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
public void testAcceptsValidInviteMessage() throws Exception {
BdfList body = BdfList.of(INVITE.getValue(), creatorList, groupName,
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);
expectEncodeMetadata(INVITE, autoDeleteTimer, metadata);
BdfMessageContext messageContext =
validator.validateMessage(message, group, body);
assertTrue(messageContext.getDependencies().isEmpty());
assertEquals(meta, messageContext.getDictionary());
assertEquals(emptyList(), messageContext.getDependencies());
assertEquals(metadata, messageContext.getDictionary());
}
private void expectInviteMessage(boolean exception) throws Exception {
@@ -260,11 +322,6 @@ public class GroupInvitationValidatorTest extends ValidatorTestCase {
signed, creator.getPublicKey());
if (exception) {
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)
public void testRejectsTooLongJoinMessage() throws Exception {
BdfList body = BdfList.of(JOIN.getValue(), privateGroup.getId(),
previousMessageId, "");
previousMessageId, NO_AUTO_DELETE_TIMER, null);
validator.validateMessage(message, group, body);
}
@@ -339,14 +396,10 @@ public class GroupInvitationValidatorTest extends ValidatorTestCase {
public void testAcceptsJoinMessageWithNullPreviousMessageId()
throws Exception {
BdfList body = BdfList.of(JOIN.getValue(), privateGroup.getId(), null);
context.checking(new Expectations() {{
oneOf(messageEncoder).encodeMetadata(JOIN, message.getGroupId(),
message.getTimestamp(), false, false, false, false, false);
will(returnValue(meta));
}});
expectEncodeMetadata(JOIN, NO_AUTO_DELETE_TIMER, meta);
BdfMessageContext messageContext =
validator.validateMessage(message, group, body);
assertEquals(0, messageContext.getDependencies().size());
assertEquals(emptyList(), messageContext.getDependencies());
assertEquals(meta, messageContext.getDictionary());
}
@@ -354,17 +407,45 @@ public class GroupInvitationValidatorTest extends ValidatorTestCase {
public void testAcceptsValidJoinMessage() throws Exception {
BdfList body = BdfList.of(JOIN.getValue(), privateGroup.getId(),
previousMessageId);
context.checking(new Expectations() {{
oneOf(messageEncoder).encodeMetadata(JOIN, message.getGroupId(),
message.getTimestamp(), false, false, false, false, false);
will(returnValue(meta));
}});
testAcceptsJoinMessage(body, NO_AUTO_DELETE_TIMER, 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 =
validator.validateMessage(message, group, body);
assertEquals(1, messageContext.getDependencies().size());
assertEquals(previousMessageId,
messageContext.getDependencies().iterator().next());
assertEquals(meta, messageContext.getDictionary());
assertEquals(singletonList(previousMessageId),
messageContext.getDependencies());
assertEquals(metadata, messageContext.getDictionary());
}
// LEAVE message
@@ -437,32 +518,56 @@ public class GroupInvitationValidatorTest extends ValidatorTestCase {
public void testAcceptsLeaveMessageWithNullPreviousMessageId()
throws Exception {
BdfList body = BdfList.of(LEAVE.getValue(), privateGroup.getId(), null);
context.checking(new Expectations() {{
oneOf(messageEncoder).encodeMetadata(LEAVE, message.getGroupId(),
message.getTimestamp(), false, false, false, false, false);
will(returnValue(meta));
}});
expectEncodeMetadata(LEAVE, NO_AUTO_DELETE_TIMER, meta);
BdfMessageContext messageContext =
validator.validateMessage(message, group, body);
assertEquals(0, messageContext.getDependencies().size());
assertEquals(emptyList(), messageContext.getDependencies());
assertEquals(meta, messageContext.getDictionary());
}
@Test
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(),
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 =
validator.validateMessage(message, group, body);
assertEquals(1, messageContext.getDependencies().size());
assertEquals(previousMessageId,
messageContext.getDependencies().iterator().next());
assertEquals(meta, messageContext.getDictionary());
assertEquals(singletonList(previousMessageId),
messageContext.getDependencies());
assertEquals(metadata, messageContext.getDictionary());
}
// ABORT message
@@ -507,15 +612,11 @@ public class GroupInvitationValidatorTest extends ValidatorTestCase {
@Test
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());
expectEncodeMetadata(ABORT, NO_AUTO_DELETE_TIMER, meta);
BdfMessageContext messageContext =
validator.validateMessage(message, group, body);
assertEquals(0, messageContext.getDependencies().size());
assertEquals(emptyList(), messageContext.getDependencies());
assertEquals(meta, messageContext.getDictionary());
}
@@ -531,4 +632,13 @@ public class GroupInvitationValidatorTest extends ValidatorTestCase {
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.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.SHARED;
import static org.briarproject.bramble.api.sync.Group.Visibility.VISIBLE;
@@ -131,7 +132,8 @@ public class InviteeProtocolEngineTest extends AbstractProtocolEngineTest {
public void testOnJoinActionFromInvited() throws Exception {
JoinMessage properJoinMessage =
new JoinMessage(messageId, contactGroupId, privateGroupId,
messageTimestamp, lastRemoteMessageId);
messageTimestamp, lastRemoteMessageId,
NO_AUTO_DELETE_TIMER);
long timestamp = 0L;
GroupMessage joinGroupMessage =
new GroupMessage(message, null, localAuthor);
@@ -329,7 +331,7 @@ public class InviteeProtocolEngineTest extends AbstractProtocolEngineTest {
privateGroup.getName(), privateGroup.getCreator(),
privateGroup.getSalt(),
getRandomString(MAX_GROUP_INVITATION_TEXT_LENGTH),
signature);
signature, NO_AUTO_DELETE_TIMER);
Contact notCreatorContact = getContact(contactId, getAuthor(),
localAuthor.getId(), true);
@@ -352,7 +354,8 @@ public class InviteeProtocolEngineTest extends AbstractProtocolEngineTest {
new InviteMessage(new MessageId(getRandomId()), contactGroupId,
privateGroupId, session.getInviteTimestamp() + 1,
privateGroup.getName(), privateGroup.getCreator(),
privateGroup.getSalt(), "msg", signature);
privateGroup.getSalt(), "msg", signature,
NO_AUTO_DELETE_TIMER);
assertEquals(contact.getAuthor(), privateGroup.getCreator());
expectGetContactId();
@@ -505,7 +508,7 @@ public class InviteeProtocolEngineTest extends AbstractProtocolEngineTest {
JoinMessage invalidJoinMessage =
new JoinMessage(new MessageId(getRandomId()), contactGroupId,
privateGroupId, session.getInviteTimestamp() + 1,
lastLocalMessageId);
lastLocalMessageId, NO_AUTO_DELETE_TIMER);
assertFalse(invalidJoinMessage.getTimestamp() <=
session.getInviteTimestamp());
assertNotNull(session.getLastRemoteMessageId());
@@ -525,7 +528,7 @@ public class InviteeProtocolEngineTest extends AbstractProtocolEngineTest {
JoinMessage properJoinMessage =
new JoinMessage(new MessageId(getRandomId()), contactGroupId,
privateGroupId, session.getInviteTimestamp() + 1,
lastRemoteMessageId);
lastRemoteMessageId, NO_AUTO_DELETE_TIMER);
assertFalse(properJoinMessage.getTimestamp() <=
session.getInviteTimestamp());
assertNotNull(session.getLastRemoteMessageId());
@@ -607,7 +610,8 @@ public class InviteeProtocolEngineTest extends AbstractProtocolEngineTest {
InviteeSession session = getDefaultSession(INVITED);
LeaveMessage invalidLeaveMessage =
new LeaveMessage(new MessageId(getRandomId()), contactGroupId,
privateGroupId, session.getInviteTimestamp() + 1, null);
privateGroupId, session.getInviteTimestamp() + 1, null,
NO_AUTO_DELETE_TIMER);
assertFalse(invalidLeaveMessage.getTimestamp() <=
session.getInviteTimestamp());
assertNull(invalidLeaveMessage.getPreviousMessageId());
@@ -624,7 +628,8 @@ public class InviteeProtocolEngineTest extends AbstractProtocolEngineTest {
InviteeSession session = getDefaultSession(LEFT);
LeaveMessage invalidLeaveMessage =
new LeaveMessage(new MessageId(getRandomId()), contactGroupId,
privateGroupId, session.getInviteTimestamp() + 1, null);
privateGroupId, session.getInviteTimestamp() + 1, null,
NO_AUTO_DELETE_TIMER);
assertFalse(invalidLeaveMessage.getTimestamp() <=
session.getInviteTimestamp());
assertNull(invalidLeaveMessage.getPreviousMessageId());
@@ -641,7 +646,7 @@ public class InviteeProtocolEngineTest extends AbstractProtocolEngineTest {
LeaveMessage properLeaveMessage =
new LeaveMessage(new MessageId(getRandomId()), contactGroupId,
privateGroupId, session.getInviteTimestamp() + 1,
lastRemoteMessageId);
lastRemoteMessageId, NO_AUTO_DELETE_TIMER);
assertFalse(properLeaveMessage.getTimestamp() <=
session.getInviteTimestamp());
assertNotNull(session.getLastRemoteMessageId());
@@ -671,7 +676,7 @@ public class InviteeProtocolEngineTest extends AbstractProtocolEngineTest {
LeaveMessage properLeaveMessage =
new LeaveMessage(new MessageId(getRandomId()), contactGroupId,
privateGroupId, session.getInviteTimestamp() + 1,
lastRemoteMessageId);
lastRemoteMessageId, NO_AUTO_DELETE_TIMER);
assertFalse(properLeaveMessage.getTimestamp() <=
session.getInviteTimestamp());
assertNotNull(session.getLastRemoteMessageId());

View File

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