Merge branch '1832-use-conversation-timestamp' into '804-self-destructing-messages'

Use latest conversation timestamp for all invitation/introduction messages

See merge request briar/briar!1310
This commit is contained in:
akwizgran
2020-12-03 17:32:33 +00:00
40 changed files with 639 additions and 453 deletions

View File

@@ -14,6 +14,7 @@ import org.briarproject.bramble.api.contact.ContactManager;
import org.briarproject.bramble.api.crypto.CryptoExecutor;
import org.briarproject.bramble.api.crypto.PasswordStrengthEstimator;
import org.briarproject.bramble.api.db.DatabaseExecutor;
import org.briarproject.bramble.api.db.TransactionManager;
import org.briarproject.bramble.api.event.EventBus;
import org.briarproject.bramble.api.identity.IdentityManager;
import org.briarproject.bramble.api.keyagreement.KeyAgreementTask;
@@ -39,6 +40,7 @@ import org.briarproject.briar.api.android.AndroidNotificationManager;
import org.briarproject.briar.api.android.DozeWatchdog;
import org.briarproject.briar.api.android.LockManager;
import org.briarproject.briar.api.android.ScreenFilterMonitor;
import org.briarproject.briar.api.autodelete.AutoDeleteManager;
import org.briarproject.briar.api.blog.BlogManager;
import org.briarproject.briar.api.blog.BlogPostFactory;
import org.briarproject.briar.api.blog.BlogSharingManager;
@@ -169,6 +171,10 @@ public interface AndroidComponent
AndroidWakeLockManager wakeLockManager();
TransactionManager transactionManager();
AutoDeleteManager autoDeleteManager();
void inject(SignInReminderReceiver briarService);
void inject(BriarService briarService);

View File

@@ -753,18 +753,10 @@ public class ConversationActivity extends BriarActivity
List<AttachmentHeader> attachmentHeaders) {
if (isNullOrEmpty(text) && attachmentHeaders.isEmpty())
throw new AssertionError();
long timestamp = System.currentTimeMillis();
timestamp = Math.max(timestamp, getMinTimestampForNewMessage());
viewModel.sendMessage(text, attachmentHeaders, timestamp);
viewModel.sendMessage(text, attachmentHeaders);
textInputView.clearText();
}
private long getMinTimestampForNewMessage() {
// Don't use an earlier timestamp than the newest message
ConversationItem item = adapter.getLastItem();
return item == null ? 0 : item.getTime() + 1;
}
private void onAddedPrivateMessage(@Nullable PrivateMessageHeader h) {
if (h == null) return;
addConversationItem(h.accept(visitor));
@@ -969,13 +961,11 @@ public class ConversationActivity extends BriarActivity
adapter.notifyItemChanged(position, item);
}
runOnDbThread(() -> {
long timestamp = System.currentTimeMillis();
timestamp = Math.max(timestamp, getMinTimestampForNewMessage());
try {
switch (item.getRequestType()) {
case INTRODUCTION:
respondToIntroductionRequest(item.getSessionId(),
accept, timestamp);
accept);
break;
case FORUM:
respondToForumRequest(item.getSessionId(), accept);
@@ -1051,9 +1041,8 @@ public class ConversationActivity extends BriarActivity
@DatabaseExecutor
private void respondToIntroductionRequest(SessionId sessionId,
boolean accept, long time) throws DbException {
introductionManager.respondToIntroduction(contactId, sessionId, time,
accept);
boolean accept) throws DbException {
introductionManager.respondToIntroduction(contactId, sessionId, accept);
}
@DatabaseExecutor

View File

@@ -30,6 +30,7 @@ import org.briarproject.briar.android.util.UiUtils;
import org.briarproject.briar.android.viewmodel.LiveEvent;
import org.briarproject.briar.android.viewmodel.MutableLiveEvent;
import org.briarproject.briar.api.autodelete.AutoDeleteManager;
import org.briarproject.briar.api.conversation.ConversationManager;
import org.briarproject.briar.api.messaging.AttachmentHeader;
import org.briarproject.briar.api.messaging.MessagingManager;
import org.briarproject.briar.api.messaging.PrivateMessage;
@@ -86,6 +87,7 @@ public class ConversationViewModel extends AndroidViewModel
private final AttachmentRetriever attachmentRetriever;
private final AttachmentCreator attachmentCreator;
private final AutoDeleteManager autoDeleteManager;
private final ConversationManager conversationManager;
@Nullable
private ContactId contactId = null;
@@ -119,7 +121,8 @@ public class ConversationViewModel extends AndroidViewModel
PrivateMessageFactory privateMessageFactory,
AttachmentRetriever attachmentRetriever,
AttachmentCreator attachmentCreator,
AutoDeleteManager autoDeleteManager) {
AutoDeleteManager autoDeleteManager,
ConversationManager conversationManager) {
super(application);
this.dbExecutor = dbExecutor;
this.db = db;
@@ -131,6 +134,7 @@ public class ConversationViewModel extends AndroidViewModel
this.attachmentRetriever = attachmentRetriever;
this.attachmentCreator = attachmentCreator;
this.autoDeleteManager = autoDeleteManager;
this.conversationManager = conversationManager;
messagingGroupId = Transformations
.map(contact, c -> messagingManager.getContactGroup(c).getId());
contactDeleted.setValue(false);
@@ -213,14 +217,13 @@ public class ConversationViewModel extends AndroidViewModel
}
@UiThread
void sendMessage(@Nullable String text,
List<AttachmentHeader> headers, long timestamp) {
void sendMessage(@Nullable String text, List<AttachmentHeader> headers) {
// messagingGroupId is loaded with the contact
observeForeverOnce(messagingGroupId, groupId -> {
requireNonNull(groupId);
observeForeverOnce(privateMessageFormat, format ->
storeMessage(requireNonNull(contactId), groupId, text,
headers, timestamp, format));
headers, format));
});
}
@@ -282,8 +285,10 @@ public class ConversationViewModel extends AndroidViewModel
private PrivateMessage createMessage(Transaction txn, ContactId c,
GroupId groupId, @Nullable String text,
List<AttachmentHeader> headers, long timestamp,
PrivateMessageFormat format) throws DbException {
List<AttachmentHeader> headers, PrivateMessageFormat format)
throws DbException {
long timestamp =
conversationManager.getTimestampForOutgoingMessage(txn, c);
try {
if (format == TEXT_ONLY) {
return privateMessageFactory.createLegacyPrivateMessage(
@@ -304,13 +309,13 @@ public class ConversationViewModel extends AndroidViewModel
@UiThread
private void storeMessage(ContactId c, GroupId groupId,
@Nullable String text, List<AttachmentHeader> headers,
long timestamp, PrivateMessageFormat format) {
PrivateMessageFormat format) {
dbExecutor.execute(() -> {
try {
db.transaction(false, txn -> {
long start = now();
PrivateMessage m = createMessage(txn, c, groupId, text,
headers, timestamp, format);
headers, format);
messagingManager.addLocalMessage(txn, m);
logDuration(LOG, "Storing message", start);
Message message = m.getMessage();

View File

@@ -211,8 +211,7 @@ public class IntroductionMessageFragment extends BaseFragment
introductionActivity.runOnDbThread(() -> {
// actually make the introduction
try {
long timestamp = System.currentTimeMillis();
introductionManager.makeIntroduction(c1, c2, text, timestamp);
introductionManager.makeIntroduction(c1, c2, text);
} catch (DbException e) {
logException(LOG, WARNING, e);
introductionError();

View File

@@ -7,6 +7,8 @@ import org.briarproject.bramble.api.crypto.CryptoExecutor;
import org.briarproject.bramble.api.db.DatabaseExecutor;
import org.briarproject.bramble.api.db.DbException;
import org.briarproject.bramble.api.db.NoSuchContactException;
import org.briarproject.bramble.api.db.Transaction;
import org.briarproject.bramble.api.db.TransactionManager;
import org.briarproject.bramble.api.identity.IdentityManager;
import org.briarproject.bramble.api.identity.LocalAuthor;
import org.briarproject.bramble.api.lifecycle.LifecycleManager;
@@ -15,6 +17,8 @@ import org.briarproject.bramble.api.sync.GroupId;
import org.briarproject.bramble.api.system.Clock;
import org.briarproject.briar.android.contactselection.ContactSelectorControllerImpl;
import org.briarproject.briar.android.controller.handler.ResultExceptionHandler;
import org.briarproject.briar.api.autodelete.AutoDeleteManager;
import org.briarproject.briar.api.conversation.ConversationManager;
import org.briarproject.briar.api.privategroup.GroupMessage;
import org.briarproject.briar.api.privategroup.GroupMessageFactory;
import org.briarproject.briar.api.privategroup.PrivateGroup;
@@ -35,6 +39,8 @@ import javax.inject.Inject;
import androidx.annotation.Nullable;
import static java.util.logging.Level.WARNING;
import static java.util.logging.Logger.getLogger;
import static org.briarproject.bramble.api.nullsafety.NullSafety.requireNonNull;
import static org.briarproject.bramble.util.LogUtils.logException;
@Immutable
@@ -43,9 +49,12 @@ class CreateGroupControllerImpl extends ContactSelectorControllerImpl
implements CreateGroupController {
private static final Logger LOG =
Logger.getLogger(CreateGroupControllerImpl.class.getName());
getLogger(CreateGroupControllerImpl.class.getName());
private final Executor cryptoExecutor;
private final TransactionManager db;
private final AutoDeleteManager autoDeleteManager;
private final ConversationManager conversationManager;
private final ContactManager contactManager;
private final IdentityManager identityManager;
private final PrivateGroupFactory groupFactory;
@@ -56,16 +65,26 @@ class CreateGroupControllerImpl extends ContactSelectorControllerImpl
private final Clock clock;
@Inject
CreateGroupControllerImpl(@DatabaseExecutor Executor dbExecutor,
CreateGroupControllerImpl(
@DatabaseExecutor Executor dbExecutor,
@CryptoExecutor Executor cryptoExecutor,
LifecycleManager lifecycleManager, ContactManager contactManager,
IdentityManager identityManager, PrivateGroupFactory groupFactory,
TransactionManager db,
AutoDeleteManager autoDeleteManager,
ConversationManager conversationManager,
LifecycleManager lifecycleManager,
ContactManager contactManager,
IdentityManager identityManager,
PrivateGroupFactory groupFactory,
GroupMessageFactory groupMessageFactory,
PrivateGroupManager groupManager,
GroupInvitationFactory groupInvitationFactory,
GroupInvitationManager groupInvitationManager, Clock clock) {
GroupInvitationManager groupInvitationManager,
Clock clock) {
super(dbExecutor, lifecycleManager, contactManager);
this.cryptoExecutor = cryptoExecutor;
this.db = db;
this.autoDeleteManager = autoDeleteManager;
this.conversationManager = conversationManager;
this.contactManager = contactManager;
this.identityManager = identityManager;
this.groupFactory = groupFactory;
@@ -129,16 +148,14 @@ class CreateGroupControllerImpl extends ContactSelectorControllerImpl
ResultExceptionHandler<Void, DbException> handler) {
runOnDbThread(() -> {
try {
LocalAuthor localAuthor = identityManager.getLocalAuthor();
List<Contact> contacts = new ArrayList<>();
for (ContactId c : contactIds) {
try {
contacts.add(contactManager.getContact(c));
} catch (NoSuchContactException e) {
// Continue
}
}
signInvitations(g, localAuthor, contacts, text, handler);
db.transaction(true, txn -> {
LocalAuthor localAuthor =
identityManager.getLocalAuthor(txn);
List<InvitationContext> contexts =
createInvitationContexts(txn, contactIds);
txn.attach(() -> signInvitations(g, localAuthor, contexts,
text, handler));
});
} catch (DbException e) {
logException(LOG, WARNING, e);
handler.onException(e);
@@ -146,17 +163,31 @@ class CreateGroupControllerImpl extends ContactSelectorControllerImpl
});
}
private List<InvitationContext> createInvitationContexts(Transaction txn,
Collection<ContactId> contactIds) throws DbException {
List<InvitationContext> contexts = new ArrayList<>();
for (ContactId c : contactIds) {
try {
Contact contact = contactManager.getContact(txn, c);
long timestamp = conversationManager
.getTimestampForOutgoingMessage(txn, c);
long timer = autoDeleteManager.getAutoDeleteTimer(txn, c);
contexts.add(new InvitationContext(contact, timestamp, timer));
} catch (NoSuchContactException e) {
// Continue
}
}
return contexts;
}
private void signInvitations(GroupId g, LocalAuthor localAuthor,
Collection<Contact> contacts, @Nullable String text,
List<InvitationContext> contexts, @Nullable String text,
ResultExceptionHandler<Void, DbException> handler) {
cryptoExecutor.execute(() -> {
long timestamp = clock.currentTimeMillis();
List<InvitationContext> contexts = new ArrayList<>();
for (Contact c : contacts) {
byte[] signature = groupInvitationFactory.signInvitation(c, g,
timestamp, localAuthor.getPrivateKey());
contexts.add(new InvitationContext(c.getId(), timestamp,
signature));
for (InvitationContext ctx : contexts) {
ctx.signature = groupInvitationFactory.signInvitation(
ctx.contact, g, ctx.timestamp,
localAuthor.getPrivateKey());
}
sendInvitations(g, contexts, text, handler);
});
@@ -167,16 +198,16 @@ class CreateGroupControllerImpl extends ContactSelectorControllerImpl
ResultExceptionHandler<Void, DbException> handler) {
runOnDbThread(() -> {
try {
for (InvitationContext context : contexts) {
for (InvitationContext ctx : contexts) {
try {
groupInvitationManager.sendInvitation(g,
context.contactId, text, context.timestamp,
context.signature);
ctx.contact.getId(), text, ctx.timestamp,
requireNonNull(ctx.signature),
ctx.autoDeleteTimer);
} catch (NoSuchContactException e) {
// Continue
}
}
//noinspection ConstantConditions
handler.onResult(null);
} catch (DbException e) {
logException(LOG, WARNING, e);
@@ -187,15 +218,16 @@ class CreateGroupControllerImpl extends ContactSelectorControllerImpl
private static class InvitationContext {
private final ContactId contactId;
private final long timestamp;
private final byte[] signature;
private final Contact contact;
private final long timestamp, autoDeleteTimer;
@Nullable
private byte[] signature = null;
private InvitationContext(ContactId contactId, long timestamp,
byte[] signature) {
this.contactId = contactId;
private InvitationContext(Contact contact, long timestamp,
long autoDeleteTimer) {
this.contact = contact;
this.timestamp = timestamp;
this.signature = signature;
this.autoDeleteTimer = autoDeleteTimer;
}
}
}

View File

@@ -10,11 +10,9 @@ import org.briarproject.bramble.api.db.NoSuchGroupException;
import org.briarproject.bramble.api.lifecycle.LifecycleManager;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import org.briarproject.bramble.api.sync.GroupId;
import org.briarproject.bramble.api.system.Clock;
import org.briarproject.briar.android.contactselection.ContactSelectorControllerImpl;
import org.briarproject.briar.android.controller.handler.ExceptionHandler;
import org.briarproject.briar.api.blog.BlogSharingManager;
import org.briarproject.briar.api.conversation.ConversationManager;
import java.util.Collection;
import java.util.concurrent.Executor;
@@ -25,6 +23,7 @@ import javax.annotation.concurrent.Immutable;
import javax.inject.Inject;
import static java.util.logging.Level.WARNING;
import static java.util.logging.Logger.getLogger;
import static org.briarproject.bramble.util.LogUtils.logException;
@Immutable
@@ -33,21 +32,16 @@ class ShareBlogControllerImpl extends ContactSelectorControllerImpl
implements ShareBlogController {
private final static Logger LOG =
Logger.getLogger(ShareBlogControllerImpl.class.getName());
getLogger(ShareBlogControllerImpl.class.getName());
private final ConversationManager conversationManager;
private final BlogSharingManager blogSharingManager;
private final Clock clock;
@Inject
ShareBlogControllerImpl(@DatabaseExecutor Executor dbExecutor,
LifecycleManager lifecycleManager, ContactManager contactManager,
ConversationManager conversationManager,
BlogSharingManager blogSharingManager, Clock clock) {
BlogSharingManager blogSharingManager) {
super(dbExecutor, lifecycleManager, contactManager);
this.conversationManager = conversationManager;
this.blogSharingManager = blogSharingManager;
this.clock = clock;
}
@Override
@@ -62,10 +56,7 @@ class ShareBlogControllerImpl extends ContactSelectorControllerImpl
try {
for (ContactId c : contacts) {
try {
long time = Math.max(clock.currentTimeMillis(),
conversationManager.getGroupCount(c)
.getLatestMsgTime() + 1);
blogSharingManager.sendInvitation(g, c, text, time);
blogSharingManager.sendInvitation(g, c, text);
} catch (NoSuchContactException | NoSuchGroupException e) {
logException(LOG, WARNING, e);
}

View File

@@ -10,10 +10,8 @@ import org.briarproject.bramble.api.db.NoSuchGroupException;
import org.briarproject.bramble.api.lifecycle.LifecycleManager;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import org.briarproject.bramble.api.sync.GroupId;
import org.briarproject.bramble.api.system.Clock;
import org.briarproject.briar.android.contactselection.ContactSelectorControllerImpl;
import org.briarproject.briar.android.controller.handler.ExceptionHandler;
import org.briarproject.briar.api.conversation.ConversationManager;
import org.briarproject.briar.api.forum.ForumSharingManager;
import java.util.Collection;
@@ -25,6 +23,7 @@ import javax.annotation.concurrent.Immutable;
import javax.inject.Inject;
import static java.util.logging.Level.WARNING;
import static java.util.logging.Logger.getLogger;
import static org.briarproject.bramble.util.LogUtils.logException;
@Immutable
@@ -33,21 +32,16 @@ class ShareForumControllerImpl extends ContactSelectorControllerImpl
implements ShareForumController {
private final static Logger LOG =
Logger.getLogger(ShareForumControllerImpl.class.getName());
getLogger(ShareForumControllerImpl.class.getName());
private final ConversationManager conversationManager;
private final ForumSharingManager forumSharingManager;
private final Clock clock;
@Inject
ShareForumControllerImpl(@DatabaseExecutor Executor dbExecutor,
LifecycleManager lifecycleManager, ContactManager contactManager,
ConversationManager conversationManager,
ForumSharingManager forumSharingManager, Clock clock) {
ForumSharingManager forumSharingManager) {
super(dbExecutor, lifecycleManager, contactManager);
this.conversationManager = conversationManager;
this.forumSharingManager = forumSharingManager;
this.clock = clock;
}
@Override
@@ -62,10 +56,7 @@ class ShareForumControllerImpl extends ContactSelectorControllerImpl
try {
for (ContactId c : contacts) {
try {
long time = Math.max(clock.currentTimeMillis(),
conversationManager.getGroupCount(c)
.getLatestMsgTime() + 1);
forumSharingManager.sendInvitation(g, c, text, time);
forumSharingManager.sendInvitation(g, c, text);
} catch (NoSuchContactException | NoSuchGroupException e) {
logException(LOG, WARNING, e);
}

View File

@@ -43,6 +43,18 @@ public interface ConversationManager {
*/
GroupCount getGroupCount(ContactId c) throws DbException;
/**
* Returns the unified group count for all private conversation messages.
*/
GroupCount getGroupCount(Transaction txn, ContactId c) throws DbException;
/**
* Returns a timestamp for an outgoing message, which is later than the
* timestamp of any message in the conversation with the given contact.
*/
long getTimestampForOutgoingMessage(Transaction txn, ContactId c)
throws DbException;
/**
* Deletes all messages exchanged with the given contact.
*/

View File

@@ -36,13 +36,13 @@ public interface IntroductionManager extends ConversationClient {
/**
* Sends two initial introduction messages.
*/
void makeIntroduction(Contact c1, Contact c2, @Nullable String text,
long timestamp) throws DbException;
void makeIntroduction(Contact c1, Contact c2, @Nullable String text)
throws DbException;
/**
* Responds to an introduction.
*/
void respondToIntroduction(ContactId contactId, SessionId sessionId,
long timestamp, boolean accept) throws DbException;
boolean accept) throws DbException;
}

View File

@@ -43,7 +43,8 @@ public interface GroupInvitationManager extends ConversationClient {
* pending.
*/
void sendInvitation(GroupId g, ContactId c, @Nullable String text,
long timestamp, byte[] signature) throws DbException;
long timestamp, byte[] signature, long autoDeleteTimer)
throws DbException;
/**
* Responds to a pending private group invitation from the given contact.

View File

@@ -21,7 +21,7 @@ public interface SharingManager<S extends Shareable>
* including optional text.
*/
void sendInvitation(GroupId shareableId, ContactId contactId,
@Nullable String text, long timestamp) throws DbException;
@Nullable String text) throws DbException;
/**
* Responds to a pending group invitation

View File

@@ -26,6 +26,7 @@ import org.briarproject.bramble.api.versioning.ClientVersioningManager;
import org.briarproject.briar.api.autodelete.AutoDeleteManager;
import org.briarproject.briar.api.client.MessageTracker;
import org.briarproject.briar.api.client.SessionId;
import org.briarproject.briar.api.conversation.ConversationManager;
import org.briarproject.briar.api.introduction.IntroductionResponse;
import org.briarproject.briar.api.introduction.event.IntroductionResponseReceivedEvent;
@@ -59,6 +60,7 @@ abstract class AbstractProtocolEngine<S extends Session<?>>
protected final MessageEncoder messageEncoder;
protected final ClientVersioningManager clientVersioningManager;
protected final AutoDeleteManager autoDeleteManager;
protected final ConversationManager conversationManager;
protected final Clock clock;
AbstractProtocolEngine(
@@ -72,6 +74,7 @@ abstract class AbstractProtocolEngine<S extends Session<?>>
MessageEncoder messageEncoder,
ClientVersioningManager clientVersioningManager,
AutoDeleteManager autoDeleteManager,
ConversationManager conversationManager,
Clock clock) {
this.db = db;
this.clientHelper = clientHelper;
@@ -83,6 +86,7 @@ abstract class AbstractProtocolEngine<S extends Session<?>>
this.messageEncoder = messageEncoder;
this.clientVersioningManager = clientVersioningManager;
this.autoDeleteManager = autoDeleteManager;
this.conversationManager = conversationManager;
this.clock = clock;
}
@@ -227,14 +231,10 @@ abstract class AbstractProtocolEngine<S extends Session<?>>
return !dependency.equals(lastRemoteMessageId);
}
long getLocalTimestamp(long localTimestamp, long requestTimestamp) {
return Math.max(
clock.currentTimeMillis(),
Math.max(
localTimestamp,
requestTimestamp
) + 1
);
long getTimestampForOutgoingMessage(Transaction txn, GroupId contactGroupId)
throws DbException {
ContactId c = getContactId(txn, contactGroupId);
return conversationManager.getTimestampForOutgoingMessage(txn, c);
}
private ContactId getContactId(Transaction txn, GroupId contactGroupId)

View File

@@ -31,6 +31,7 @@ import org.briarproject.briar.api.autodelete.AutoDeleteManager;
import org.briarproject.briar.api.client.MessageTracker;
import org.briarproject.briar.api.client.ProtocolStateException;
import org.briarproject.briar.api.client.SessionId;
import org.briarproject.briar.api.conversation.ConversationManager;
import org.briarproject.briar.api.introduction.IntroductionRequest;
import org.briarproject.briar.api.introduction.event.IntroductionAbortedEvent;
import org.briarproject.briar.api.introduction.event.IntroductionRequestReceivedEvent;
@@ -43,6 +44,7 @@ import javax.annotation.Nullable;
import javax.annotation.concurrent.Immutable;
import javax.inject.Inject;
import static java.lang.Math.max;
import static java.util.logging.Level.WARNING;
import static org.briarproject.bramble.util.LogUtils.logException;
import static org.briarproject.briar.introduction.IntroduceeState.AWAIT_AUTH;
@@ -75,15 +77,17 @@ class IntroduceeProtocolEngine
IdentityManager identityManager,
MessageParser messageParser,
MessageEncoder messageEncoder,
Clock clock,
IntroductionCrypto crypto,
KeyManager keyManager,
TransportPropertyManager transportPropertyManager,
ClientVersioningManager clientVersioningManager,
AutoDeleteManager autoDeleteManager) {
AutoDeleteManager autoDeleteManager,
ConversationManager conversationManager,
Clock clock) {
super(db, clientHelper, contactManager, contactGroupFactory,
messageTracker, identityManager, messageParser, messageEncoder,
clientVersioningManager, autoDeleteManager, clock);
clientVersioningManager, autoDeleteManager,
conversationManager, clock);
this.crypto = crypto;
this.keyManager = keyManager;
this.transportPropertyManager = transportPropertyManager;
@@ -91,18 +95,18 @@ class IntroduceeProtocolEngine
@Override
public IntroduceeSession onRequestAction(Transaction txn,
IntroduceeSession session, @Nullable String text, long timestamp) {
IntroduceeSession session, @Nullable String text) {
throw new UnsupportedOperationException(); // Invalid in this role
}
@Override
public IntroduceeSession onAcceptAction(Transaction txn,
IntroduceeSession session, long timestamp) throws DbException {
IntroduceeSession session) throws DbException {
switch (session.getState()) {
case AWAIT_RESPONSES:
case REMOTE_DECLINED:
case REMOTE_ACCEPTED:
return onLocalAccept(txn, session, timestamp);
return onLocalAccept(txn, session);
case START:
case LOCAL_DECLINED:
case LOCAL_ACCEPTED:
@@ -116,12 +120,12 @@ class IntroduceeProtocolEngine
@Override
public IntroduceeSession onDeclineAction(Transaction txn,
IntroduceeSession session, long timestamp) throws DbException {
IntroduceeSession session) throws DbException {
switch (session.getState()) {
case AWAIT_RESPONSES:
case REMOTE_DECLINED:
case REMOTE_ACCEPTED:
return onLocalDecline(txn, session, timestamp);
return onLocalDecline(txn, session);
case START:
case LOCAL_DECLINED:
case LOCAL_ACCEPTED:
@@ -272,7 +276,7 @@ class IntroduceeProtocolEngine
}
private IntroduceeSession onLocalAccept(Transaction txn,
IntroduceeSession s, long timestamp) throws DbException {
IntroduceeSession s) throws DbException {
// Mark the request message unavailable to answer
markRequestsUnavailableToAnswer(txn, s);
@@ -283,8 +287,8 @@ class IntroduceeProtocolEngine
Map<TransportId, TransportProperties> transportProperties =
transportPropertyManager.getLocalProperties(txn);
// Send a ACCEPT message
long localTimestamp = Math.max(timestamp + 1, getLocalTimestamp(s));
// Send an ACCEPT message
long localTimestamp = getTimestampForVisibleMessage(txn, s);
Message sent = sendAcceptMessage(txn, s, localTimestamp, publicKey,
localTimestamp, transportProperties, true);
// Track the message
@@ -309,12 +313,12 @@ class IntroduceeProtocolEngine
}
private IntroduceeSession onLocalDecline(Transaction txn,
IntroduceeSession s, long timestamp) throws DbException {
IntroduceeSession s) throws DbException {
// Mark the request message unavailable to answer
markRequestsUnavailableToAnswer(txn, s);
// Send a DECLINE message
long localTimestamp = Math.max(timestamp + 1, getLocalTimestamp(s));
long localTimestamp = getTimestampForVisibleMessage(txn, s);
Message sent = sendDeclineMessage(txn, s, localTimestamp, true);
// Track the message
@@ -412,8 +416,8 @@ class IntroduceeProtocolEngine
return abort(txn, s);
}
if (s.getState() != AWAIT_AUTH) throw new AssertionError();
Message sent = sendAuthMessage(txn, s, getLocalTimestamp(s), mac,
signature);
long localTimestamp = getTimestampForInvisibleMessage(s);
Message sent = sendAuthMessage(txn, s, localTimestamp, mac, signature);
return IntroduceeSession.addLocalAuth(s, AWAIT_AUTH, sent, masterKey,
aliceMacKey, bobMacKey);
}
@@ -464,7 +468,8 @@ class IntroduceeProtocolEngine
// send ACTIVATE message with a MAC
byte[] mac = crypto.activateMac(s);
Message sent = sendActivateMessage(txn, s, getLocalTimestamp(s), mac);
long localTimestamp = getTimestampForInvisibleMessage(s);
Message sent = sendActivateMessage(txn, s, localTimestamp, mac);
// Move to AWAIT_ACTIVATE state and clear key material from session
return IntroduceeSession.awaitActivate(s, m, sent, keys);
@@ -515,7 +520,8 @@ class IntroduceeProtocolEngine
markRequestsUnavailableToAnswer(txn, s);
// Send an ABORT message
Message sent = sendAbortMessage(txn, s, getLocalTimestamp(s));
long localTimestamp = getTimestampForInvisibleMessage(s);
Message sent = sendAbortMessage(txn, s, localTimestamp);
// Broadcast abort event for testing
txn.attach(new IntroductionAbortedEvent(s.getSessionId()));
@@ -530,9 +536,34 @@ class IntroduceeProtocolEngine
return isInvalidDependency(s.getLastRemoteMessageId(), dependency);
}
private long getLocalTimestamp(IntroduceeSession s) {
return getLocalTimestamp(s.getLocalTimestamp(),
s.getRequestTimestamp());
/**
* Returns a timestamp for a visible outgoing message. The timestamp is
* later than the timestamp of any message sent or received so far in the
* conversation, and later than the {@link
* #getSessionTimestamp(IntroduceeSession) session timestamp}.
*/
private long getTimestampForVisibleMessage(Transaction txn,
IntroduceeSession s) throws DbException {
long conversationTimestamp =
getTimestampForOutgoingMessage(txn, s.getContactGroupId());
return max(conversationTimestamp, getSessionTimestamp(s) + 1);
}
/**
* Returns a timestamp for an invisible outgoing message. The timestamp is
* later than the {@link #getSessionTimestamp(IntroduceeSession) session
* timestamp}.
*/
private long getTimestampForInvisibleMessage(IntroduceeSession s) {
return max(clock.currentTimeMillis(), getSessionTimestamp(s) + 1);
}
/**
* Returns the latest timestamp of any message sent so far in the session,
* and any request message received so far in the session.
*/
private long getSessionTimestamp(IntroduceeSession s) {
return max(s.getLocalTimestamp(), s.getRequestTimestamp());
}
private void addSessionId(Transaction txn, MessageId m, SessionId sessionId)

View File

@@ -17,6 +17,7 @@ import org.briarproject.bramble.api.versioning.ClientVersioningManager;
import org.briarproject.briar.api.autodelete.AutoDeleteManager;
import org.briarproject.briar.api.client.MessageTracker;
import org.briarproject.briar.api.client.ProtocolStateException;
import org.briarproject.briar.api.conversation.ConversationManager;
import org.briarproject.briar.api.introduction.event.IntroductionAbortedEvent;
import org.briarproject.briar.introduction.IntroducerSession.Introducee;
@@ -24,6 +25,7 @@ import javax.annotation.Nullable;
import javax.annotation.concurrent.Immutable;
import javax.inject.Inject;
import static java.lang.Math.max;
import static org.briarproject.briar.introduction.IntroducerState.AWAIT_ACTIVATES;
import static org.briarproject.briar.introduction.IntroducerState.AWAIT_ACTIVATE_A;
import static org.briarproject.briar.introduction.IntroducerState.AWAIT_ACTIVATE_B;
@@ -54,19 +56,21 @@ class IntroducerProtocolEngine
MessageEncoder messageEncoder,
ClientVersioningManager clientVersioningManager,
AutoDeleteManager autoDeleteManager,
ConversationManager conversationManager,
Clock clock) {
super(db, clientHelper, contactManager, contactGroupFactory,
messageTracker, identityManager, messageParser, messageEncoder,
clientVersioningManager, autoDeleteManager, clock);
clientVersioningManager, autoDeleteManager,
conversationManager, clock);
}
@Override
public IntroducerSession onRequestAction(Transaction txn,
IntroducerSession s, @Nullable String text, long timestamp)
IntroducerSession s, @Nullable String text)
throws DbException {
switch (s.getState()) {
case START:
return onLocalRequest(txn, s, text, timestamp);
return onLocalRequest(txn, s, text);
case AWAIT_RESPONSES:
case AWAIT_RESPONSE_A:
case AWAIT_RESPONSE_B:
@@ -86,37 +90,24 @@ class IntroducerProtocolEngine
@Override
public IntroducerSession onAcceptAction(Transaction txn,
IntroducerSession s, long timestamp) {
IntroducerSession s) {
throw new UnsupportedOperationException(); // Invalid in this role
}
@Override
public IntroducerSession onDeclineAction(Transaction txn,
IntroducerSession s, long timestamp) {
IntroducerSession s) {
throw new UnsupportedOperationException(); // Invalid in this role
}
IntroducerSession onIntroduceeRemoved(Transaction txn,
Introducee remainingIntroducee, IntroducerSession session)
throws DbException {
// abort session
IntroducerSession s = abort(txn, session);
// reset information for introducee that was removed
Introducee introduceeA, introduceeB;
if (remainingIntroducee.author.equals(s.getIntroduceeA().author)) {
introduceeA = s.getIntroduceeA();
introduceeB =
new Introducee(s.getSessionId(), s.getIntroduceeB().groupId,
s.getIntroduceeB().author);
} else if (remainingIntroducee.author
.equals(s.getIntroduceeB().author)) {
introduceeA =
new Introducee(s.getSessionId(), s.getIntroduceeA().groupId,
s.getIntroduceeA().author);
introduceeB = s.getIntroduceeB();
} else throw new DbException();
// abort session with remaining introducee
IntroducerSession s = abort(txn, session, remainingIntroducee);
return new IntroducerSession(s.getSessionId(), s.getState(),
s.getRequestTimestamp(), introduceeA, introduceeB);
s.getRequestTimestamp(), s.getIntroduceeA(),
s.getIntroduceeB());
}
@Override
@@ -226,13 +217,13 @@ class IntroducerProtocolEngine
}
private IntroducerSession onLocalRequest(Transaction txn,
IntroducerSession s, @Nullable String text, long timestamp)
throws DbException {
IntroducerSession s, @Nullable String text) throws DbException {
// Send REQUEST messages
long maxIntroduceeTimestamp =
Math.max(getLocalTimestamp(s, s.getIntroduceeA()),
getLocalTimestamp(s, s.getIntroduceeB()));
long localTimestamp = Math.max(timestamp, maxIntroduceeTimestamp);
long timestampA =
getTimestampForVisibleMessage(txn, s, s.getIntroduceeA());
long timestampB =
getTimestampForVisibleMessage(txn, s, s.getIntroduceeB());
long localTimestamp = max(timestampA, timestampB);
Message sentA = sendRequestMessage(txn, s.getIntroduceeA(),
localTimestamp, s.getIntroduceeB().author, text);
Message sentB = sendRequestMessage(txn, s.getIntroduceeB(),
@@ -272,11 +263,11 @@ class IntroducerProtocolEngine
// Forward ACCEPT message
Introducee i = getOtherIntroducee(s, m.getGroupId());
long timestamp = getLocalTimestamp(s, i);
Message sent =
sendAcceptMessage(txn, i, timestamp, m.getEphemeralPublicKey(),
m.getAcceptTimestamp(), m.getTransportProperties(),
false);
// The forwarded message will not be visible to the introducee
long localTimestamp = getTimestampForInvisibleMessage(s, i);
Message sent = sendAcceptMessage(txn, i, localTimestamp,
m.getEphemeralPublicKey(), m.getAcceptTimestamp(),
m.getTransportProperties(), false);
// Create the next state
IntroducerState state = AWAIT_AUTHS;
@@ -333,7 +324,9 @@ class IntroducerProtocolEngine
// Forward ACCEPT message
Introducee i = getOtherIntroducee(s, m.getGroupId());
Message sent = sendAcceptMessage(txn, i, getLocalTimestamp(s, i),
// The forwarded message will not be visible to the introducee
long localTimestamp = getTimestampForInvisibleMessage(s, i);
Message sent = sendAcceptMessage(txn, i, localTimestamp,
m.getEphemeralPublicKey(), m.getAcceptTimestamp(),
m.getTransportProperties(), false);
@@ -384,8 +377,9 @@ class IntroducerProtocolEngine
// Forward DECLINE message
Introducee i = getOtherIntroducee(s, m.getGroupId());
long timestamp = getLocalTimestamp(s, i);
Message sent = sendDeclineMessage(txn, i, timestamp, false);
// The forwarded message will be visible to the introducee
long localTimestamp = getTimestampForVisibleMessage(txn, s, i);
Message sent = sendDeclineMessage(txn, i, localTimestamp, false);
// Create the next state
IntroducerState state = START;
@@ -436,8 +430,9 @@ class IntroducerProtocolEngine
// Forward DECLINE message
Introducee i = getOtherIntroducee(s, m.getGroupId());
long timestamp = getLocalTimestamp(s, i);
Message sent = sendDeclineMessage(txn, i, timestamp, false);
// The forwarded message will be visible to the introducee
long localTimestamp = getTimestampForVisibleMessage(txn, s, i);
Message sent = sendDeclineMessage(txn, i, localTimestamp, false);
Introducee introduceeA, introduceeB;
Author sender, other;
@@ -477,8 +472,8 @@ class IntroducerProtocolEngine
// Forward AUTH message
Introducee i = getOtherIntroducee(s, m.getGroupId());
long timestamp = getLocalTimestamp(s, i);
Message sent = sendAuthMessage(txn, i, timestamp, m.getMac(),
long localTimestamp = getTimestampForInvisibleMessage(s, i);
Message sent = sendAuthMessage(txn, i, localTimestamp, m.getMac(),
m.getSignature());
// Move to the next state
@@ -513,8 +508,8 @@ class IntroducerProtocolEngine
// Forward ACTIVATE message
Introducee i = getOtherIntroducee(s, m.getGroupId());
long timestamp = getLocalTimestamp(s, i);
Message sent = sendActivateMessage(txn, i, timestamp, m.getMac());
long localTimestamp = getTimestampForInvisibleMessage(s, i);
Message sent = sendActivateMessage(txn, i, localTimestamp, m.getMac());
// Move to the next state
IntroducerState state = START;
@@ -536,8 +531,8 @@ class IntroducerProtocolEngine
IntroducerSession s, AbortMessage m) throws DbException {
// Forward ABORT message
Introducee i = getOtherIntroducee(s, m.getGroupId());
long timestamp = getLocalTimestamp(s, i);
Message sent = sendAbortMessage(txn, i, timestamp);
long localTimestamp = getTimestampForInvisibleMessage(s, i);
Message sent = sendAbortMessage(txn, i, localTimestamp);
// Broadcast abort event for testing
txn.attach(new IntroductionAbortedEvent(s.getSessionId()));
@@ -555,15 +550,45 @@ class IntroducerProtocolEngine
s.getRequestTimestamp(), introduceeA, introduceeB);
}
private IntroducerSession abort(Transaction txn,
IntroducerSession s) throws DbException {
private IntroducerSession abort(Transaction txn, IntroducerSession s,
Introducee remainingIntroducee) throws DbException {
// Broadcast abort event for testing
txn.attach(new IntroductionAbortedEvent(s.getSessionId()));
// Send an ABORT message to the remaining introducee
long localTimestamp =
getTimestampForInvisibleMessage(s, remainingIntroducee);
Message sent =
sendAbortMessage(txn, remainingIntroducee, localTimestamp);
// Reset the session back to initial state
Introducee introduceeA = s.getIntroduceeA();
Introducee introduceeB = s.getIntroduceeB();
if (remainingIntroducee.author.equals(introduceeA.author)) {
introduceeA = new Introducee(introduceeA, sent);
introduceeB = new Introducee(s.getSessionId(), introduceeB.groupId,
introduceeB.author);
} else if (remainingIntroducee.author.equals(introduceeB.author)) {
introduceeA = new Introducee(s.getSessionId(), introduceeA.groupId,
introduceeA.author);
introduceeB = new Introducee(introduceeB, sent);
} else {
throw new DbException();
}
return new IntroducerSession(s.getSessionId(), START,
s.getRequestTimestamp(), introduceeA, introduceeB);
}
private IntroducerSession abort(Transaction txn, IntroducerSession s)
throws DbException {
// Broadcast abort event for testing
txn.attach(new IntroductionAbortedEvent(s.getSessionId()));
// Send an ABORT message to both introducees
long timestampA = getLocalTimestamp(s, s.getIntroduceeA());
long timestampA =
getTimestampForInvisibleMessage(s, s.getIntroduceeA());
Message sentA = sendAbortMessage(txn, s.getIntroduceeA(), timestampA);
long timestampB = getLocalTimestamp(s, s.getIntroduceeB());
long timestampB =
getTimestampForInvisibleMessage(s, s.getIntroduceeB());
Message sentB = sendAbortMessage(txn, s.getIntroduceeB(), timestampB);
// Reset the session back to initial state
Introducee introduceeA = new Introducee(s.getIntroduceeA(), sentA);
@@ -593,9 +618,33 @@ class IntroducerProtocolEngine
return isInvalidDependency(expected, dependency);
}
private long getLocalTimestamp(IntroducerSession s, PeerSession p) {
return getLocalTimestamp(p.getLocalTimestamp(),
s.getRequestTimestamp());
/**
* Returns a timestamp for a visible outgoing message. The timestamp is
* later than the timestamp of any message sent or received so far in the
* conversation, and later than the {@link
* #getSessionTimestamp(IntroducerSession, PeerSession) session timestamp}.
*/
private long getTimestampForVisibleMessage(Transaction txn,
IntroducerSession s, PeerSession p) throws DbException {
long conversationTimestamp =
getTimestampForOutgoingMessage(txn, p.getContactGroupId());
return max(conversationTimestamp, getSessionTimestamp(s, p) + 1);
}
/**
* Returns a timestamp for an invisible outgoing message. The timestamp is
* later than the {@link #getSessionTimestamp(IntroducerSession, PeerSession)
* session timestamp}.
*/
private long getTimestampForInvisibleMessage(IntroducerSession s,
PeerSession p) {
return max(clock.currentTimeMillis(), getSessionTimestamp(s, p) + 1);
}
/**
* Returns the latest timestamp of any message sent so far in the session.
*/
private long getSessionTimestamp(IntroducerSession s, PeerSession p) {
return max(p.getLocalTimestamp(), s.getRequestTimestamp());
}
}

View File

@@ -311,8 +311,8 @@ class IntroductionManagerImpl extends ConversationClientImpl
}
@Override
public void makeIntroduction(Contact c1, Contact c2, @Nullable String text,
long timestamp) throws DbException {
public void makeIntroduction(Contact c1, Contact c2, @Nullable String text)
throws DbException {
Transaction txn = db.startTransaction(false);
try {
// Look up the session, if there is one
@@ -344,8 +344,7 @@ class IntroductionManagerImpl extends ConversationClientImpl
storageId = ss.storageId;
}
// Handle the request action
session = introducerEngine
.onRequestAction(txn, session, text, timestamp);
session = introducerEngine.onRequestAction(txn, session, text);
// Store the updated session
storeSession(txn, storageId, session);
db.commitTransaction(txn);
@@ -358,7 +357,7 @@ class IntroductionManagerImpl extends ConversationClientImpl
@Override
public void respondToIntroduction(ContactId contactId, SessionId sessionId,
long timestamp, boolean accept) throws DbException {
boolean accept) throws DbException {
Transaction txn = db.startTransaction(false);
try {
// Look up the session
@@ -376,11 +375,9 @@ class IntroductionManagerImpl extends ConversationClientImpl
.parseIntroduceeSession(contactGroupId, ss.bdfSession);
// Handle the join or leave action
if (accept) {
session = introduceeEngine
.onAcceptAction(txn, session, timestamp);
session = introduceeEngine.onAcceptAction(txn, session);
} else {
session = introduceeEngine
.onDeclineAction(txn, session, timestamp);
session = introduceeEngine.onDeclineAction(txn, session);
}
// Store the updated session
storeSession(txn, ss.storageId, session);

View File

@@ -8,16 +8,14 @@ import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import javax.annotation.Nullable;
@NotNullByDefault
interface ProtocolEngine<S extends Session> {
interface ProtocolEngine<S extends Session<?>> {
S onRequestAction(Transaction txn, S session, @Nullable String text,
long timestamp) throws DbException;
S onAcceptAction(Transaction txn, S session, long timestamp)
S onRequestAction(Transaction txn, S session, @Nullable String text)
throws DbException;
S onDeclineAction(Transaction txn, S session, long timestamp)
throws DbException;
S onAcceptAction(Transaction txn, S session) throws DbException;
S onDeclineAction(Transaction txn, S session) throws DbException;
S onRequestMessage(Transaction txn, S session, RequestMessage m)
throws DbException, FormatException;

View File

@@ -6,6 +6,7 @@ import org.briarproject.bramble.api.db.DbException;
import org.briarproject.bramble.api.db.Transaction;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import org.briarproject.bramble.api.sync.MessageId;
import org.briarproject.bramble.api.system.Clock;
import org.briarproject.briar.api.client.MessageTracker.GroupCount;
import org.briarproject.briar.api.conversation.ConversationManager;
import org.briarproject.briar.api.conversation.ConversationMessageHeader;
@@ -20,16 +21,20 @@ import java.util.concurrent.CopyOnWriteArraySet;
import javax.annotation.concurrent.ThreadSafe;
import javax.inject.Inject;
import static java.lang.Math.max;
@ThreadSafe
@NotNullByDefault
class ConversationManagerImpl implements ConversationManager {
private final DatabaseComponent db;
private final Clock clock;
private final Set<ConversationClient> clients;
@Inject
ConversationManagerImpl(DatabaseComponent db) {
ConversationManagerImpl(DatabaseComponent db, Clock clock) {
this.db = db;
this.clock = clock;
clients = new CopyOnWriteArraySet<>();
}
@@ -57,24 +62,33 @@ class ConversationManagerImpl implements ConversationManager {
@Override
public GroupCount getGroupCount(ContactId contactId) throws DbException {
return db.transactionWithResult(true, txn ->
getGroupCount(txn, contactId));
}
@Override
public GroupCount getGroupCount(Transaction txn, ContactId contactId)
throws DbException {
int msgCount = 0, unreadCount = 0;
long latestTime = 0;
Transaction txn = db.startTransaction(true);
try {
for (ConversationClient client : clients) {
GroupCount count = client.getGroupCount(txn, contactId);
msgCount += count.getMsgCount();
unreadCount += count.getUnreadCount();
if (count.getLatestMsgTime() > latestTime)
latestTime = count.getLatestMsgTime();
}
db.commitTransaction(txn);
} finally {
db.endTransaction(txn);
for (ConversationClient client : clients) {
GroupCount count = client.getGroupCount(txn, contactId);
msgCount += count.getMsgCount();
unreadCount += count.getUnreadCount();
if (count.getLatestMsgTime() > latestTime)
latestTime = count.getLatestMsgTime();
}
return new GroupCount(msgCount, unreadCount, latestTime);
}
@Override
public long getTimestampForOutgoingMessage(Transaction txn, ContactId c)
throws DbException {
long now = clock.currentTimeMillis();
GroupCount gc = getGroupCount(txn, c);
return max(now, gc.getLatestMsgTime() + 1);
}
@Override
public DeletionResult deleteAllMessages(ContactId c) throws DbException {
return db.transactionWithResult(false, txn -> {
@@ -87,8 +101,8 @@ class ConversationManagerImpl implements ConversationManager {
}
@Override
public DeletionResult deleteMessages(ContactId c, Collection<MessageId> toDelete)
throws DbException {
public DeletionResult deleteMessages(ContactId c,
Collection<MessageId> toDelete) throws DbException {
return db.transactionWithResult(false, txn -> {
DeletionResult result = new DeletionResult();
for (ConversationClient client : clients) {

View File

@@ -19,6 +19,7 @@ import org.briarproject.bramble.api.system.Clock;
import org.briarproject.bramble.api.versioning.ClientVersioningManager;
import org.briarproject.briar.api.autodelete.AutoDeleteManager;
import org.briarproject.briar.api.client.MessageTracker;
import org.briarproject.briar.api.conversation.ConversationManager;
import org.briarproject.briar.api.privategroup.GroupMessage;
import org.briarproject.briar.api.privategroup.GroupMessageFactory;
import org.briarproject.briar.api.privategroup.PrivateGroup;
@@ -31,6 +32,7 @@ import java.util.Map;
import javax.annotation.Nullable;
import javax.annotation.concurrent.Immutable;
import static java.lang.Math.max;
import static org.briarproject.briar.api.autodelete.AutoDeleteConstants.NO_AUTO_DELETE_TIMER;
import static org.briarproject.briar.privategroup.invitation.MessageType.ABORT;
import static org.briarproject.briar.privategroup.invitation.MessageType.INVITE;
@@ -54,6 +56,7 @@ abstract class AbstractProtocolEngine<S extends Session<?>>
private final MessageParser messageParser;
private final MessageEncoder messageEncoder;
private final AutoDeleteManager autoDeleteManager;
private final ConversationManager conversationManager;
private final Clock clock;
AbstractProtocolEngine(
@@ -68,6 +71,7 @@ abstract class AbstractProtocolEngine<S extends Session<?>>
MessageEncoder messageEncoder,
MessageTracker messageTracker,
AutoDeleteManager autoDeleteManager,
ConversationManager conversationManager,
Clock clock) {
this.db = db;
this.clientHelper = clientHelper;
@@ -80,6 +84,7 @@ abstract class AbstractProtocolEngine<S extends Session<?>>
this.messageEncoder = messageEncoder;
this.messageTracker = messageTracker;
this.autoDeleteManager = autoDeleteManager;
this.conversationManager = conversationManager;
this.clock = clock;
}
@@ -110,8 +115,8 @@ abstract class AbstractProtocolEngine<S extends Session<?>>
}
Message sendInviteMessage(Transaction txn, S s,
@Nullable String text, long timestamp, byte[] signature)
throws DbException {
@Nullable String text, long timestamp, byte[] signature,
long timer) throws DbException {
Group g = db.getGroup(txn, s.getPrivateGroupId());
PrivateGroup privateGroup;
try {
@@ -122,7 +127,6 @@ abstract class AbstractProtocolEngine<S extends Session<?>>
Message m;
ContactId c = getContactId(txn, s.getContactGroupId());
if (contactSupportsAutoDeletion(txn, c)) {
long timer = autoDeleteManager.getAutoDeleteTimer(txn, c);
m = messageEncoder.encodeInviteMessage(s.getContactGroupId(),
privateGroup.getId(), timestamp, privateGroup.getName(),
privateGroup.getCreator(), privateGroup.getSalt(), text,
@@ -142,6 +146,9 @@ abstract class AbstractProtocolEngine<S extends Session<?>>
Message sendJoinMessage(Transaction txn, S s, boolean visibleInUi)
throws DbException {
Message m;
long localTimestamp = visibleInUi
? getTimestampForVisibleMessage(txn, s)
: getTimestampForInvisibleMessage(s);
ContactId c = getContactId(txn, s.getContactGroupId());
if (contactSupportsAutoDeletion(txn, c)) {
// Set auto-delete timer if manually accepting an invitation
@@ -149,13 +156,13 @@ abstract class AbstractProtocolEngine<S extends Session<?>>
? autoDeleteManager.getAutoDeleteTimer(txn, c)
: NO_AUTO_DELETE_TIMER;
m = messageEncoder.encodeJoinMessage(s.getContactGroupId(),
s.getPrivateGroupId(), getLocalTimestamp(s),
s.getPrivateGroupId(), localTimestamp,
s.getLastLocalMessageId(), timer);
sendMessage(txn, m, JOIN, s.getPrivateGroupId(), visibleInUi,
timer);
} else {
m = messageEncoder.encodeJoinMessage(s.getContactGroupId(),
s.getPrivateGroupId(), getLocalTimestamp(s),
s.getPrivateGroupId(), localTimestamp,
s.getLastLocalMessageId());
sendMessage(txn, m, JOIN, s.getPrivateGroupId(), visibleInUi,
NO_AUTO_DELETE_TIMER);
@@ -166,6 +173,9 @@ abstract class AbstractProtocolEngine<S extends Session<?>>
Message sendLeaveMessage(Transaction txn, S s, boolean visibleInUi)
throws DbException {
Message m;
long localTimestamp = visibleInUi
? getTimestampForVisibleMessage(txn, s)
: getTimestampForInvisibleMessage(s);
ContactId c = getContactId(txn, s.getContactGroupId());
if (contactSupportsAutoDeletion(txn, c)) {
// Set auto-delete timer if manually accepting an invitation
@@ -173,13 +183,13 @@ abstract class AbstractProtocolEngine<S extends Session<?>>
? autoDeleteManager.getAutoDeleteTimer(txn, c)
: NO_AUTO_DELETE_TIMER;
m = messageEncoder.encodeLeaveMessage(s.getContactGroupId(),
s.getPrivateGroupId(), getLocalTimestamp(s),
s.getPrivateGroupId(), localTimestamp,
s.getLastLocalMessageId(), timer);
sendMessage(txn, m, LEAVE, s.getPrivateGroupId(), visibleInUi,
timer);
} else {
m = messageEncoder.encodeLeaveMessage(s.getContactGroupId(),
s.getPrivateGroupId(), getLocalTimestamp(s),
s.getPrivateGroupId(), localTimestamp,
s.getLastLocalMessageId());
sendMessage(txn, m, LEAVE, s.getPrivateGroupId(), visibleInUi,
NO_AUTO_DELETE_TIMER);
@@ -190,7 +200,7 @@ abstract class AbstractProtocolEngine<S extends Session<?>>
Message sendAbortMessage(Transaction txn, S session) throws DbException {
Message m = messageEncoder.encodeAbortMessage(
session.getContactGroupId(), session.getPrivateGroupId(),
getLocalTimestamp(session));
getTimestampForInvisibleMessage(session));
sendMessage(txn, m, ABORT, session.getPrivateGroupId(), false,
NO_AUTO_DELETE_TIMER);
return m;
@@ -246,7 +256,7 @@ abstract class AbstractProtocolEngine<S extends Session<?>>
PrivateGroup privateGroup = privateGroupFactory.createPrivateGroup(
invite.getGroupName(), invite.getCreator(), invite.getSalt());
long timestamp =
Math.max(clock.currentTimeMillis(), invite.getTimestamp() + 1);
max(clock.currentTimeMillis(), invite.getTimestamp() + 1);
// TODO: Create the join message on the crypto executor
LocalAuthor member = identityManager.getLocalAuthor(txn);
GroupMessage joinMessage = groupMessageFactory.createJoinMessage(
@@ -256,10 +266,34 @@ abstract class AbstractProtocolEngine<S extends Session<?>>
.addPrivateGroup(txn, privateGroup, joinMessage, false);
}
long getLocalTimestamp(S session) {
return Math.max(clock.currentTimeMillis(),
Math.max(session.getLocalTimestamp(),
session.getInviteTimestamp()) + 1);
/**
* Returns a timestamp for a visible outgoing message. The timestamp is
* later than the timestamp of any message sent or received so far in the
* conversation, and later than the {@link #getSessionTimestamp(Session)
* session timestamp}.
*/
long getTimestampForVisibleMessage(Transaction txn, S s)
throws DbException {
ContactId c = getContactId(txn, s.getContactGroupId());
long conversationTimestamp =
conversationManager.getTimestampForOutgoingMessage(txn, c);
return max(conversationTimestamp, getSessionTimestamp(s) + 1);
}
/**
* Returns a timestamp for an invisible outgoing message. The timestamp is
* later than the {@link #getSessionTimestamp(Session) session timestamp}.
*/
long getTimestampForInvisibleMessage(S s) {
return max(clock.currentTimeMillis(), getSessionTimestamp(s) + 1);
}
/**
* Returns the latest timestamp of any message sent so far in the session,
* and any invite message sent or received so far in the session.
*/
private long getSessionTimestamp(S s) {
return max(s.getLocalTimestamp(), s.getInviteTimestamp());
}
private void sendMessage(Transaction txn, Message m, MessageType type,

View File

@@ -15,6 +15,7 @@ import org.briarproject.briar.api.autodelete.AutoDeleteManager;
import org.briarproject.briar.api.client.MessageTracker;
import org.briarproject.briar.api.client.ProtocolStateException;
import org.briarproject.briar.api.client.SessionId;
import org.briarproject.briar.api.conversation.ConversationManager;
import org.briarproject.briar.api.privategroup.GroupMessageFactory;
import org.briarproject.briar.api.privategroup.PrivateGroupFactory;
import org.briarproject.briar.api.privategroup.PrivateGroupManager;
@@ -24,6 +25,7 @@ import org.briarproject.briar.api.privategroup.invitation.GroupInvitationRespons
import javax.annotation.Nullable;
import javax.annotation.concurrent.Immutable;
import static java.lang.Math.max;
import static org.briarproject.bramble.api.sync.Group.Visibility.INVISIBLE;
import static org.briarproject.bramble.api.sync.Group.Visibility.SHARED;
import static org.briarproject.briar.privategroup.invitation.CreatorState.DISSOLVED;
@@ -49,20 +51,22 @@ class CreatorProtocolEngine extends AbstractProtocolEngine<CreatorSession> {
MessageEncoder messageEncoder,
MessageTracker messageTracker,
AutoDeleteManager autoDeleteManager,
ConversationManager conversationManager,
Clock clock) {
super(db, clientHelper, clientVersioningManager, privateGroupManager,
privateGroupFactory, groupMessageFactory, identityManager,
messageParser, messageEncoder, messageTracker,
autoDeleteManager, clock);
autoDeleteManager, conversationManager, clock);
}
@Override
public CreatorSession onInviteAction(Transaction txn, CreatorSession s,
@Nullable String text, long timestamp, byte[] signature)
throws DbException {
@Nullable String text, long timestamp, byte[] signature,
long autoDeleteTimer) throws DbException {
switch (s.getState()) {
case START:
return onLocalInvite(txn, s, text, timestamp, signature);
return onLocalInvite(txn, s, text, timestamp, signature,
autoDeleteTimer);
case INVITED:
case JOINED:
case LEFT:
@@ -152,14 +156,16 @@ class CreatorProtocolEngine extends AbstractProtocolEngine<CreatorSession> {
}
private CreatorSession onLocalInvite(Transaction txn, CreatorSession s,
@Nullable String text, long timestamp, byte[] signature)
throws DbException {
@Nullable String text, long timestamp, byte[] signature,
long autoDeleteTimer) throws DbException {
// Send an INVITE message
Message sent = sendInviteMessage(txn, s, text, timestamp, signature);
Message sent = sendInviteMessage(txn, s, text, timestamp, signature,
autoDeleteTimer);
// Track the message
messageTracker.trackOutgoingMessage(txn, sent);
// Move to the INVITED state
long localTimestamp = Math.max(timestamp, getLocalTimestamp(s));
long localTimestamp =
max(timestamp, getTimestampForVisibleMessage(txn, s));
return new CreatorSession(s.getContactGroupId(), s.getPrivateGroupId(),
sent.getId(), s.getLastRemoteMessageId(), localTimestamp,
timestamp, INVITED);

View File

@@ -257,8 +257,8 @@ class GroupInvitationManagerImpl extends ConversationClientImpl
@Override
public void sendInvitation(GroupId privateGroupId, ContactId c,
@Nullable String text, long timestamp, byte[] signature)
throws DbException {
@Nullable String text, long timestamp, byte[] signature,
long autoDeleteTimer) throws DbException {
SessionId sessionId = getSessionId(privateGroupId);
Transaction txn = db.startTransaction(false);
try {
@@ -281,7 +281,7 @@ class GroupInvitationManagerImpl extends ConversationClientImpl
}
// Handle the invite action
session = creatorEngine.onInviteAction(txn, session, text,
timestamp, signature);
timestamp, signature, autoDeleteTimer);
// Store the updated session
storeSession(txn, storageId, session);
db.commitTransaction(txn);

View File

@@ -17,6 +17,7 @@ import org.briarproject.briar.api.autodelete.AutoDeleteManager;
import org.briarproject.briar.api.client.MessageTracker;
import org.briarproject.briar.api.client.ProtocolStateException;
import org.briarproject.briar.api.client.SessionId;
import org.briarproject.briar.api.conversation.ConversationManager;
import org.briarproject.briar.api.privategroup.GroupMessageFactory;
import org.briarproject.briar.api.privategroup.PrivateGroup;
import org.briarproject.briar.api.privategroup.PrivateGroupFactory;
@@ -42,7 +43,8 @@ import static org.briarproject.briar.privategroup.invitation.InviteeState.START;
@NotNullByDefault
class InviteeProtocolEngine extends AbstractProtocolEngine<InviteeSession> {
InviteeProtocolEngine(DatabaseComponent db,
InviteeProtocolEngine(
DatabaseComponent db,
ClientHelper clientHelper,
ClientVersioningManager clientVersioningManager,
PrivateGroupManager privateGroupManager,
@@ -53,16 +55,18 @@ class InviteeProtocolEngine extends AbstractProtocolEngine<InviteeSession> {
MessageEncoder messageEncoder,
MessageTracker messageTracker,
AutoDeleteManager autoDeleteManager,
ConversationManager conversationManager,
Clock clock) {
super(db, clientHelper, clientVersioningManager, privateGroupManager,
privateGroupFactory, groupMessageFactory, identityManager,
messageParser, messageEncoder, messageTracker,
autoDeleteManager, clock);
autoDeleteManager, conversationManager, clock);
}
@Override
public InviteeSession onInviteAction(Transaction txn, InviteeSession s,
@Nullable String text, long timestamp, byte[] signature) {
@Nullable String text, long timestamp, byte[] signature,
long autoDeleteTimer) {
throw new UnsupportedOperationException(); // Invalid in this role
}

View File

@@ -15,6 +15,7 @@ import org.briarproject.bramble.api.versioning.ClientVersioningManager;
import org.briarproject.briar.api.autodelete.AutoDeleteManager;
import org.briarproject.briar.api.client.MessageTracker;
import org.briarproject.briar.api.client.ProtocolStateException;
import org.briarproject.briar.api.conversation.ConversationManager;
import org.briarproject.briar.api.privategroup.GroupMessageFactory;
import org.briarproject.briar.api.privategroup.PrivateGroupFactory;
import org.briarproject.briar.api.privategroup.PrivateGroupManager;
@@ -49,16 +50,18 @@ class PeerProtocolEngine extends AbstractProtocolEngine<PeerSession> {
MessageEncoder messageEncoder,
MessageTracker messageTracker,
AutoDeleteManager autoDeleteManager,
ConversationManager conversationManager,
Clock clock) {
super(db, clientHelper, clientVersioningManager, privateGroupManager,
privateGroupFactory, groupMessageFactory, identityManager,
messageParser, messageEncoder, messageTracker,
autoDeleteManager, clock);
autoDeleteManager, conversationManager, clock);
}
@Override
public PeerSession onInviteAction(Transaction txn, PeerSession s,
@Nullable String text, long timestamp, byte[] signature) {
@Nullable String text, long timestamp, byte[] signature,
long autoDeleteTimer) {
throw new UnsupportedOperationException(); // Invalid in this role
}

View File

@@ -8,10 +8,11 @@ import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import javax.annotation.Nullable;
@NotNullByDefault
interface ProtocolEngine<S extends Session> {
interface ProtocolEngine<S extends Session<?>> {
S onInviteAction(Transaction txn, S session, @Nullable String text,
long timestamp, byte[] signature) throws DbException;
long timestamp, byte[] signature, long autoDeleteTimer)
throws DbException;
S onJoinAction(Transaction txn, S session) throws DbException;

View File

@@ -8,6 +8,7 @@ import org.briarproject.bramble.api.system.Clock;
import org.briarproject.bramble.api.versioning.ClientVersioningManager;
import org.briarproject.briar.api.autodelete.AutoDeleteManager;
import org.briarproject.briar.api.client.MessageTracker;
import org.briarproject.briar.api.conversation.ConversationManager;
import org.briarproject.briar.api.privategroup.GroupMessageFactory;
import org.briarproject.briar.api.privategroup.PrivateGroupFactory;
import org.briarproject.briar.api.privategroup.PrivateGroupManager;
@@ -30,6 +31,7 @@ class ProtocolEngineFactoryImpl implements ProtocolEngineFactory {
private final MessageEncoder messageEncoder;
private final MessageTracker messageTracker;
private final AutoDeleteManager autoDeleteManager;
private final ConversationManager conversationManager;
private final Clock clock;
@Inject
@@ -45,6 +47,7 @@ class ProtocolEngineFactoryImpl implements ProtocolEngineFactory {
MessageEncoder messageEncoder,
MessageTracker messageTracker,
AutoDeleteManager autoDeleteManager,
ConversationManager conversationManager,
Clock clock) {
this.db = db;
this.clientHelper = clientHelper;
@@ -57,6 +60,7 @@ class ProtocolEngineFactoryImpl implements ProtocolEngineFactory {
this.messageEncoder = messageEncoder;
this.messageTracker = messageTracker;
this.autoDeleteManager = autoDeleteManager;
this.conversationManager = conversationManager;
this.clock = clock;
}
@@ -66,7 +70,7 @@ class ProtocolEngineFactoryImpl implements ProtocolEngineFactory {
clientVersioningManager, privateGroupManager,
privateGroupFactory, groupMessageFactory, identityManager,
messageParser, messageEncoder, messageTracker,
autoDeleteManager, clock);
autoDeleteManager, conversationManager, clock);
}
@Override
@@ -75,7 +79,7 @@ class ProtocolEngineFactoryImpl implements ProtocolEngineFactory {
clientVersioningManager, privateGroupManager,
privateGroupFactory, groupMessageFactory, identityManager,
messageParser, messageEncoder, messageTracker,
autoDeleteManager, clock);
autoDeleteManager, conversationManager, clock);
}
@Override
@@ -84,6 +88,6 @@ class ProtocolEngineFactoryImpl implements ProtocolEngineFactory {
clientVersioningManager, privateGroupManager,
privateGroupFactory, groupMessageFactory, identityManager,
messageParser, messageEncoder, messageTracker,
autoDeleteManager, clock);
autoDeleteManager, conversationManager, clock);
}
}

View File

@@ -19,6 +19,7 @@ import org.briarproject.briar.api.blog.BlogSharingManager;
import org.briarproject.briar.api.blog.event.BlogInvitationRequestReceivedEvent;
import org.briarproject.briar.api.blog.event.BlogInvitationResponseReceivedEvent;
import org.briarproject.briar.api.client.MessageTracker;
import org.briarproject.briar.api.conversation.ConversationManager;
import org.briarproject.briar.api.conversation.ConversationRequest;
import javax.annotation.concurrent.Immutable;
@@ -41,13 +42,15 @@ class BlogProtocolEngineImpl extends ProtocolEngineImpl<Blog> {
MessageParser<Blog> messageParser,
MessageTracker messageTracker,
AutoDeleteManager autoDeleteManager,
ConversationManager conversationManager,
Clock clock,
BlogManager blogManager,
InvitationFactory<Blog, BlogInvitationResponse> invitationFactory) {
super(db, clientHelper, clientVersioningManager, messageEncoder,
messageParser, messageTracker, autoDeleteManager, clock,
BlogSharingManager.CLIENT_ID, BlogSharingManager.MAJOR_VERSION,
BlogManager.CLIENT_ID, BlogManager.MAJOR_VERSION);
messageParser, messageTracker, autoDeleteManager,
conversationManager, clock, BlogSharingManager.CLIENT_ID,
BlogSharingManager.MAJOR_VERSION, BlogManager.CLIENT_ID,
BlogManager.MAJOR_VERSION);
this.blogManager = blogManager;
this.invitationFactory = invitationFactory;
}

View File

@@ -13,6 +13,7 @@ import org.briarproject.bramble.api.system.Clock;
import org.briarproject.bramble.api.versioning.ClientVersioningManager;
import org.briarproject.briar.api.autodelete.AutoDeleteManager;
import org.briarproject.briar.api.client.MessageTracker;
import org.briarproject.briar.api.conversation.ConversationManager;
import org.briarproject.briar.api.conversation.ConversationRequest;
import org.briarproject.briar.api.forum.Forum;
import org.briarproject.briar.api.forum.ForumInvitationResponse;
@@ -41,14 +42,15 @@ class ForumProtocolEngineImpl extends ProtocolEngineImpl<Forum> {
MessageParser<Forum> messageParser,
MessageTracker messageTracker,
AutoDeleteManager autoDeleteManager,
ConversationManager conversationManager,
Clock clock,
ForumManager forumManager,
InvitationFactory<Forum, ForumInvitationResponse> invitationFactory) {
super(db, clientHelper, clientVersioningManager, messageEncoder,
messageParser, messageTracker, autoDeleteManager, clock,
ForumSharingManager.CLIENT_ID,
ForumSharingManager.MAJOR_VERSION,
ForumManager.CLIENT_ID, ForumManager.MAJOR_VERSION);
messageParser, messageTracker, autoDeleteManager,
conversationManager, clock, ForumSharingManager.CLIENT_ID,
ForumSharingManager.MAJOR_VERSION, ForumManager.CLIENT_ID,
ForumManager.MAJOR_VERSION);
this.forumManager = forumManager;
this.invitationFactory = invitationFactory;
}

View File

@@ -12,7 +12,7 @@ import javax.annotation.Nullable;
interface ProtocolEngine<S extends Shareable> {
Session onInviteAction(Transaction txn, Session session,
@Nullable String text, long timestamp) throws DbException;
@Nullable String text) throws DbException;
Session onAcceptAction(Transaction txn, Session session) throws DbException;

View File

@@ -21,6 +21,7 @@ import org.briarproject.bramble.api.versioning.ClientVersioningManager;
import org.briarproject.briar.api.autodelete.AutoDeleteManager;
import org.briarproject.briar.api.client.MessageTracker;
import org.briarproject.briar.api.client.ProtocolStateException;
import org.briarproject.briar.api.conversation.ConversationManager;
import org.briarproject.briar.api.sharing.Shareable;
import org.briarproject.briar.api.sharing.event.ContactLeftShareableEvent;
@@ -29,6 +30,7 @@ import java.util.Map;
import javax.annotation.Nullable;
import javax.annotation.concurrent.Immutable;
import static java.lang.Math.max;
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;
@@ -58,6 +60,7 @@ abstract class ProtocolEngineImpl<S extends Shareable>
private final MessageEncoder messageEncoder;
private final MessageTracker messageTracker;
private final AutoDeleteManager autoDeleteManager;
private final ConversationManager conversationManager;
private final Clock clock;
private final ClientId sharingClientId, shareableClientId;
private final int sharingClientMajorVersion, shareableClientMajorVersion;
@@ -70,6 +73,7 @@ abstract class ProtocolEngineImpl<S extends Shareable>
MessageParser<S> messageParser,
MessageTracker messageTracker,
AutoDeleteManager autoDeleteManager,
ConversationManager conversationManager,
Clock clock,
ClientId sharingClientId,
int sharingClientMajorVersion,
@@ -82,6 +86,7 @@ abstract class ProtocolEngineImpl<S extends Shareable>
this.messageParser = messageParser;
this.messageTracker = messageTracker;
this.autoDeleteManager = autoDeleteManager;
this.conversationManager = conversationManager;
this.clock = clock;
this.sharingClientId = sharingClientId;
this.sharingClientMajorVersion = sharingClientMajorVersion;
@@ -91,10 +96,10 @@ abstract class ProtocolEngineImpl<S extends Shareable>
@Override
public Session onInviteAction(Transaction txn, Session s,
@Nullable String text, long timestamp) throws DbException {
@Nullable String text) throws DbException {
switch (s.getState()) {
case START:
return onLocalInvite(txn, s, text, timestamp);
return onLocalInvite(txn, s, text);
case LOCAL_INVITED:
case REMOTE_INVITED:
case SHARING:
@@ -107,9 +112,9 @@ abstract class ProtocolEngineImpl<S extends Shareable>
}
private Session onLocalInvite(Transaction txn, Session s,
@Nullable String text, long timestamp) throws DbException {
@Nullable String text) throws DbException {
// Send an INVITE message
Message sent = sendInviteMessage(txn, s, text, timestamp);
Message sent = sendInviteMessage(txn, s, text);
// Track the message
messageTracker.trackOutgoingMessage(txn, sent);
// Make the shareable visible to the contact
@@ -125,7 +130,7 @@ abstract class ProtocolEngineImpl<S extends Shareable>
}
private Message sendInviteMessage(Transaction txn, Session s,
@Nullable String text, long timestamp) throws DbException {
@Nullable String text) throws DbException {
Group g = db.getGroup(txn, s.getShareableId());
BdfList descriptor;
try {
@@ -133,8 +138,8 @@ abstract class ProtocolEngineImpl<S extends Shareable>
} catch (FormatException e) {
throw new DbException(e); // Invalid group descriptor
}
long localTimestamp = Math.max(timestamp, getLocalTimestamp(s));
Message m;
long localTimestamp = getTimestampForVisibleMessage(txn, s);
ContactId c = getContactId(txn, s.getContactGroupId());
if (contactSupportsAutoDeletion(txn, c)) {
long timer = autoDeleteManager.getAutoDeleteTimer(txn, c);
@@ -201,16 +206,17 @@ abstract class ProtocolEngineImpl<S extends Shareable>
private Message sendAcceptMessage(Transaction txn, Session s)
throws DbException {
Message m;
long localTimestamp = getTimestampForVisibleMessage(txn, s);
ContactId c = getContactId(txn, s.getContactGroupId());
if (contactSupportsAutoDeletion(txn, c)) {
long timer = autoDeleteManager.getAutoDeleteTimer(txn, c);
m = messageEncoder.encodeAcceptMessage(s.getContactGroupId(),
s.getShareableId(), getLocalTimestamp(s),
s.getShareableId(), localTimestamp,
s.getLastLocalMessageId(), timer);
sendMessage(txn, m, ACCEPT, s.getShareableId(), true, timer);
} else {
m = messageEncoder.encodeAcceptMessage(s.getContactGroupId(),
s.getShareableId(), getLocalTimestamp(s),
s.getShareableId(), localTimestamp,
s.getLastLocalMessageId());
sendMessage(txn, m, ACCEPT, s.getShareableId(), true,
NO_AUTO_DELETE_TIMER);
@@ -254,16 +260,17 @@ abstract class ProtocolEngineImpl<S extends Shareable>
private Message sendDeclineMessage(Transaction txn, Session s)
throws DbException {
Message m;
long localTimestamp = getTimestampForVisibleMessage(txn, s);
ContactId c = getContactId(txn, s.getContactGroupId());
if (contactSupportsAutoDeletion(txn, c)) {
long timer = autoDeleteManager.getAutoDeleteTimer(txn, c);
m = messageEncoder.encodeDeclineMessage(s.getContactGroupId(),
s.getShareableId(), getLocalTimestamp(s),
s.getShareableId(), localTimestamp,
s.getLastLocalMessageId(), timer);
sendMessage(txn, m, DECLINE, s.getShareableId(), true, timer);
} else {
m = messageEncoder.encodeDeclineMessage(s.getContactGroupId(),
s.getShareableId(), getLocalTimestamp(s),
s.getShareableId(), localTimestamp,
s.getLastLocalMessageId());
sendMessage(txn, m, DECLINE, s.getShareableId(), true,
NO_AUTO_DELETE_TIMER);
@@ -307,9 +314,10 @@ abstract class ProtocolEngineImpl<S extends Shareable>
private Message sendLeaveMessage(Transaction txn, Session session)
throws DbException {
long localTimestamp = getTimestampForInvisibleMessage(session);
Message m = messageEncoder.encodeLeaveMessage(
session.getContactGroupId(), session.getShareableId(),
getLocalTimestamp(session), session.getLastLocalMessageId());
localTimestamp, session.getLastLocalMessageId());
sendMessage(txn, m, LEAVE, session.getShareableId(), false,
NO_AUTO_DELETE_TIMER);
return m;
@@ -605,9 +613,10 @@ abstract class ProtocolEngineImpl<S extends Shareable>
private Message sendAbortMessage(Transaction txn, Session session)
throws DbException {
long localTimestamp = getTimestampForInvisibleMessage(session);
Message m = messageEncoder.encodeAbortMessage(
session.getContactGroupId(), session.getShareableId(),
getLocalTimestamp(session), session.getLastLocalMessageId());
localTimestamp, session.getLastLocalMessageId());
sendMessage(txn, m, ABORT, session.getShareableId(), false,
NO_AUTO_DELETE_TIMER);
return m;
@@ -677,10 +686,34 @@ abstract class ProtocolEngineImpl<S extends Shareable>
return !dependency.equals(expected);
}
private long getLocalTimestamp(Session session) {
return Math.max(clock.currentTimeMillis(),
Math.max(session.getLocalTimestamp(),
session.getInviteTimestamp()) + 1);
/**
* Returns a timestamp for a visible outgoing message. The timestamp is
* later than the timestamp of any message sent or received so far in the
* conversation, and later than the {@link #getSessionTimestamp(Session)
* session timestamp}.
*/
private long getTimestampForVisibleMessage(Transaction txn, Session s)
throws DbException {
ContactId c = getContactId(txn, s.getContactGroupId());
long conversationTimestamp =
conversationManager.getTimestampForOutgoingMessage(txn, c);
return max(conversationTimestamp, getSessionTimestamp(s) + 1);
}
/**
* Returns a timestamp for an invisible outgoing message. The timestamp is
* later than the {@link #getSessionTimestamp(Session) session timestamp}.
*/
private long getTimestampForInvisibleMessage(Session s) {
return max(clock.currentTimeMillis(), getSessionTimestamp(s) + 1);
}
/**
* Returns the latest timestamp of any message sent so far in the session,
* and any invite message sent or received so far in the session.
*/
private long getSessionTimestamp(Session s) {
return max(s.getLocalTimestamp(), s.getInviteTimestamp());
}
private ContactId getContactId(Transaction txn, GroupId contactGroupId)

View File

@@ -248,7 +248,7 @@ abstract class SharingManagerImpl<S extends Shareable>
@Override
public void sendInvitation(GroupId shareableId, ContactId contactId,
@Nullable String text, long timestamp) throws DbException {
@Nullable String text) throws DbException {
SessionId sessionId = getSessionId(shareableId);
Transaction txn = db.startTransaction(false);
try {
@@ -273,7 +273,7 @@ abstract class SharingManagerImpl<S extends Shareable>
storageId = ss.storageId;
}
// Handle the invite action
session = engine.onInviteAction(txn, session, text, timestamp);
session = engine.onInviteAction(txn, session, text);
// Store the updated session
storeSession(txn, storageId, session);
db.commitTransaction(txn);

View File

@@ -45,8 +45,7 @@ public class ForumManagerTest
forum0 = forumManager0.addForum("Test Forum");
groupId0 = forum0.getId();
// share forum
forumSharingManager0.sendInvitation(groupId0, contactId1From0, null,
clock.currentTimeMillis());
forumSharingManager0.sendInvitation(groupId0, contactId1From0, null);
sync0To1(1, true);
forumSharingManager1.respondToInvitation(forum0, contact0From1, true);
sync1To0(1, true);
@@ -194,8 +193,7 @@ public class ForumManagerTest
// share a second forum
Forum forum1 = forumManager0.addForum("Test Forum1");
GroupId g1 = forum1.getId();
forumSharingManager0.sendInvitation(g1, contactId1From0, null,
clock.currentTimeMillis());
forumSharingManager0.sendInvitation(g1, contactId1From0, null);
sync0To1(1, true);
forumSharingManager1.respondToInvitation(forum1, contact0From1, true);
sync1To0(1, true);

View File

@@ -140,11 +140,9 @@ public class IntroductionIntegrationTest
addListeners(true, true);
// make introduction
long time = clock.currentTimeMillis();
Contact introducee1 = contact1From0;
Contact introducee2 = contact2From0;
introductionManager0
.makeIntroduction(introducee1, introducee2, "Hi!", time);
introductionManager0.makeIntroduction(introducee1, introducee2, "Hi!");
// check that messages are tracked properly
Group g1 = introductionManager0.getContactGroup(introducee1);
@@ -264,11 +262,9 @@ public class IntroductionIntegrationTest
addListeners(false, true);
// make introduction
long time = clock.currentTimeMillis();
Contact introducee1 = contact1From0;
Contact introducee2 = contact2From0;
introductionManager0
.makeIntroduction(introducee1, introducee2, null, time);
introductionManager0.makeIntroduction(introducee1, introducee2, null);
// sync request messages
sync0To1(1, true);
@@ -356,9 +352,8 @@ public class IntroductionIntegrationTest
addListeners(true, false);
// make introduction
long time = clock.currentTimeMillis();
introductionManager0
.makeIntroduction(contact1From0, contact2From0, null, time);
.makeIntroduction(contact1From0, contact2From0, null);
// sync request messages
sync0To1(1, true);
@@ -412,9 +407,8 @@ public class IntroductionIntegrationTest
addListeners(false, true);
// make introduction
long time = clock.currentTimeMillis();
introductionManager0
.makeIntroduction(contact1From0, contact2From0, null, time);
.makeIntroduction(contact1From0, contact2From0, null);
// sync request messages
sync0To1(1, true);
@@ -438,9 +432,8 @@ public class IntroductionIntegrationTest
assertFalse(listener1.aborted);
assertFalse(listener2.aborted);
time = clock.currentTimeMillis();
introductionManager0
.makeIntroduction(contact1From0, contact2From0, null, time);
.makeIntroduction(contact1From0, contact2From0, null);
// sync request messages
sync0To1(1, true);
@@ -457,9 +450,8 @@ public class IntroductionIntegrationTest
addListeners(true, true);
// make introduction
long time = clock.currentTimeMillis();
introductionManager0
.makeIntroduction(contact1From0, contact2From0, "Hi!", time);
.makeIntroduction(contact1From0, contact2From0, "Hi!");
// sync first request message
sync0To1(1, true);
@@ -482,7 +474,7 @@ public class IntroductionIntegrationTest
// answer request manually
introductionManager2.respondToIntroduction(contactId0From2,
listener2.sessionId, time, true);
listener2.sessionId, true);
// sync second response and AUTH
sync2To0(2, true);
@@ -518,11 +510,10 @@ public class IntroductionIntegrationTest
listener2.answerRequests = false;
// make introduction
long time = clock.currentTimeMillis();
Contact introducee1 = contact1From0;
Contact introducee2 = contact2From0;
introductionManager0
.makeIntroduction(introducee1, introducee2, null, time);
.makeIntroduction(introducee1, introducee2, null);
// sync request messages
sync0To1(1, true);
@@ -564,7 +555,7 @@ public class IntroductionIntegrationTest
// answer request manually
introductionManager2.respondToIntroduction(contactId0From2,
listener2.sessionId, time, false);
listener2.sessionId, false);
// now introducee2 should have returned to the START state
introduceeSession = getIntroduceeSession(c2);
@@ -611,9 +602,8 @@ public class IntroductionIntegrationTest
addListeners(true, false);
// make introduction
long time = clock.currentTimeMillis();
introductionManager0
.makeIntroduction(contact1From0, contact1From0, null, time);
.makeIntroduction(contact1From0, contact1From0, null);
// sync request messages
sync0To1(1, false);
@@ -637,9 +627,8 @@ public class IntroductionIntegrationTest
.canIntroduce(contact1From0, contact2From0));
// make the introduction
long time = clock.currentTimeMillis();
introductionManager0
.makeIntroduction(contact1From0, contact2From0, null, time);
.makeIntroduction(contact1From0, contact2From0, null);
// no more introduction allowed while the existing one is in progress
assertFalse(introductionManager0
@@ -647,7 +636,7 @@ public class IntroductionIntegrationTest
// try it anyway and fail
introductionManager0
.makeIntroduction(contact1From0, contact2From0, null, time);
.makeIntroduction(contact1From0, contact2From0, null);
}
@Test
@@ -661,9 +650,8 @@ public class IntroductionIntegrationTest
addListeners(true, true);
// make the introduction
long time = clock.currentTimeMillis();
introductionManager0
.makeIntroduction(contact1From0, contact2From0, null, time);
.makeIntroduction(contact1From0, contact2From0, null);
// sync REQUEST messages
sync0To1(1, true);
@@ -719,9 +707,8 @@ public class IntroductionIntegrationTest
addListeners(true, true);
// make the introduction
long time = clock.currentTimeMillis();
introductionManager0
.makeIntroduction(contact1From0, contact2From0, null, time);
.makeIntroduction(contact1From0, contact2From0, null);
// sync REQUEST messages
sync0To1(1, true);
@@ -766,9 +753,8 @@ public class IntroductionIntegrationTest
addListeners(true, true);
// make the introduction
long time = clock.currentTimeMillis();
introductionManager0
.makeIntroduction(contact1From0, contact2From0, null, time);
.makeIntroduction(contact1From0, contact2From0, null);
// sync REQUEST to introducee1
sync0To1(1, true);
@@ -803,9 +789,8 @@ public class IntroductionIntegrationTest
addListeners(true, true);
// make the introduction
long time = clock.currentTimeMillis();
introductionManager0
.makeIntroduction(contact1From0, contact2From0, null, time);
.makeIntroduction(contact1From0, contact2From0, null);
// sync REQUEST to introducee1
sync0To1(1, true);
@@ -838,9 +823,8 @@ public class IntroductionIntegrationTest
addListeners(false, true);
// make the introduction
long time = clock.currentTimeMillis();
introductionManager0
.makeIntroduction(contact1From0, contact2From0, null, time);
.makeIntroduction(contact1From0, contact2From0, null);
// sync REQUEST to introducee1
sync0To1(1, true);
@@ -873,9 +857,8 @@ public class IntroductionIntegrationTest
addListeners(true, true);
// make the introduction
long time = clock.currentTimeMillis();
introductionManager0
.makeIntroduction(contact1From0, contact2From0, null, time);
.makeIntroduction(contact1From0, contact2From0, null);
// sync REQUEST messages
sync0To1(1, true);
@@ -914,9 +897,8 @@ public class IntroductionIntegrationTest
addListeners(true, true);
// make introduction
long time = clock.currentTimeMillis();
introductionManager0
.makeIntroduction(contact1From0, contact2From0, "Hi!", time);
.makeIntroduction(contact1From0, contact2From0, "Hi!");
// sync first request message
sync0To1(1, true);
@@ -943,9 +925,8 @@ public class IntroductionIntegrationTest
addListeners(true, true);
// make introduction
long time = clock.currentTimeMillis();
introductionManager0
.makeIntroduction(contact1From0, contact2From0, "Hi!", time);
.makeIntroduction(contact1From0, contact2From0, "Hi!");
// sync first request message
sync0To1(1, true);
@@ -987,9 +968,8 @@ public class IntroductionIntegrationTest
@Test
public void testIntroductionAfterReAddingContacts() throws Exception {
// make introduction
long time = clock.currentTimeMillis();
introductionManager0
.makeIntroduction(contact1From0, contact2From0, null, time);
.makeIntroduction(contact1From0, contact2From0, null);
// 0 and 1 remove and re-add each other
contactManager0.removeContact(contactId1From0);
@@ -1016,9 +996,8 @@ public class IntroductionIntegrationTest
addListeners(true, true);
// make new introduction
time = clock.currentTimeMillis();
introductionManager0
.makeIntroduction(contact1From0, contact2From0, null, time);
.makeIntroduction(contact1From0, contact2From0, null);
// introduction should sync and not be INVALID or PENDING
sync0To1(1, true);
@@ -1032,9 +1011,8 @@ public class IntroductionIntegrationTest
addListeners(true, true);
// make introduction
long time = clock.currentTimeMillis();
introductionManager0
.makeIntroduction(contact1From0, contact2From0, "Hi!", time);
.makeIntroduction(contact1From0, contact2From0, "Hi!");
// sync request messages
sync0To1(1, true);
@@ -1147,9 +1125,8 @@ public class IntroductionIntegrationTest
addListeners(true, true);
// make introduction
long time = clock.currentTimeMillis();
introductionManager0
.makeIntroduction(contact1From0, contact2From0, "Hi!", time);
.makeIntroduction(contact1From0, contact2From0, "Hi!");
// sync first REQUEST message
sync0To1(1, true);
@@ -1292,7 +1269,7 @@ public class IntroductionIntegrationTest
assertTrue(introductionManager0
.canIntroduce(contact1From0, contact2From0));
introductionManager0
.makeIntroduction(contact1From0, contact2From0, "Ho!", time);
.makeIntroduction(contact1From0, contact2From0, "Ho!");
sync0To1(1, true);
sync0To2(1, true);
@@ -1332,9 +1309,8 @@ public class IntroductionIntegrationTest
addListeners(false, false);
// make introduction
long time = clock.currentTimeMillis();
introductionManager0
.makeIntroduction(contact1From0, contact2From0, "Hi!", time);
.makeIntroduction(contact1From0, contact2From0, "Hi!");
// sync REQUEST messages
sync0To1(1, true);
@@ -1399,9 +1375,8 @@ public class IntroductionIntegrationTest
// a new introduction is still possible
assertTrue(introductionManager0
.canIntroduce(contact1From0, contact2From0));
time = clock.currentTimeMillis();
introductionManager0
.makeIntroduction(contact1From0, contact2From0, "Ho!", time);
.makeIntroduction(contact1From0, contact2From0, "Ho!");
sync0To1(1, true);
sync0To2(1, true);
@@ -1428,9 +1403,8 @@ public class IntroductionIntegrationTest
addListeners(false, false);
// make introduction
long time = clock.currentTimeMillis();
introductionManager0
.makeIntroduction(contact1From0, contact2From0, "Hi!", time);
.makeIntroduction(contact1From0, contact2From0, "Hi!");
// sync REQUEST messages
sync0To1(1, true);
@@ -1458,9 +1432,8 @@ public class IntroductionIntegrationTest
// a new introduction is still possible
assertTrue(introductionManager0
.canIntroduce(contact1From0, contact2From0));
time = clock.currentTimeMillis();
introductionManager0
.makeIntroduction(contact1From0, contact2From0, "Ho!", time);
.makeIntroduction(contact1From0, contact2From0, "Ho!");
sync0To1(1, true);
sync0To2(1, true);
@@ -1496,9 +1469,8 @@ public class IntroductionIntegrationTest
addListeners(false, false);
// make introduction
long time = clock.currentTimeMillis();
introductionManager0.makeIntroduction(contact1From0, contact2From0,
"Hi!", time);
introductionManager0
.makeIntroduction(contact1From0, contact2From0, "Hi!");
// deleting the introduction for introducee1 will fail
Collection<ConversationMessageHeader> m1From0 = getMessages1From0();
@@ -1795,16 +1767,13 @@ public class IntroductionIntegrationTest
IntroductionRequest ir = introEvent.getMessageHeader();
ContactId contactId = introEvent.getContactId();
sessionId = ir.getSessionId();
long time = clock.currentTimeMillis();
try {
if (introducee == 1 && answerRequests) {
introductionManager1
.respondToIntroduction(contactId, sessionId,
time, accept);
introductionManager1.respondToIntroduction(contactId,
sessionId, accept);
} else if (introducee == 2 && answerRequests) {
introductionManager2
.respondToIntroduction(contactId, sessionId,
time, accept);
introductionManager2.respondToIntroduction(contactId,
sessionId, accept);
}
} catch (DbException exception) {
eventWaiter.rethrow(exception);

View File

@@ -25,6 +25,7 @@ import java.util.Collection;
import javax.annotation.Nullable;
import static org.briarproject.bramble.api.identity.AuthorInfo.Status.OURSELVES;
import static org.briarproject.briar.api.autodelete.AutoDeleteConstants.NO_AUTO_DELETE_TIMER;
import static org.briarproject.briar.api.privategroup.Visibility.INVISIBLE;
import static org.briarproject.briar.api.privategroup.Visibility.REVEALED_BY_CONTACT;
import static org.briarproject.briar.api.privategroup.Visibility.REVEALED_BY_US;
@@ -220,8 +221,8 @@ public class PrivateGroupIntegrationTest
byte[] signature = groupInvitationFactory
.signInvitation(contact, groupId0, timestamp,
author0.getPrivateKey());
groupInvitationManager0
.sendInvitation(groupId0, c, text, timestamp, signature);
groupInvitationManager0.sendInvitation(groupId0, c, text, timestamp,
signature, NO_AUTO_DELETE_TIMER);
}
private GroupMember getGroupMember(PrivateGroupManager groupManager,

View File

@@ -19,6 +19,7 @@ import org.briarproject.bramble.api.versioning.ClientVersioningManager;
import org.briarproject.bramble.test.BrambleMockTestCase;
import org.briarproject.briar.api.autodelete.AutoDeleteManager;
import org.briarproject.briar.api.client.MessageTracker;
import org.briarproject.briar.api.conversation.ConversationManager;
import org.briarproject.briar.api.privategroup.GroupMessageFactory;
import org.briarproject.briar.api.privategroup.PrivateGroup;
import org.briarproject.briar.api.privategroup.PrivateGroupFactory;
@@ -62,6 +63,8 @@ abstract class AbstractProtocolEngineTest extends BrambleMockTestCase {
final MessageTracker messageTracker = context.mock(MessageTracker.class);
final AutoDeleteManager autoDeleteManager =
context.mock(AutoDeleteManager.class);
final ConversationManager conversationManager =
context.mock(ConversationManager.class);
final Clock clock = context.mock(Clock.class);
final Transaction txn = new Transaction(null, false);
@@ -115,16 +118,26 @@ abstract class AbstractProtocolEngineTest extends BrambleMockTestCase {
assertEquals(inviteTimestamp, s.getInviteTimestamp());
}
void expectGetLocalTimestamp(long time) {
void expectGetTimestampForInvisibleMessage(long time) {
context.checking(new Expectations() {{
oneOf(clock).currentTimeMillis();
will(returnValue(time));
}});
}
void expectGetTimestampForVisibleMessage(long time) throws Exception {
context.checking(new Expectations() {{
oneOf(clientHelper).getContactId(txn, contactGroupId);
will(returnValue(contactId));
oneOf(conversationManager)
.getTimestampForOutgoingMessage(txn, contactId);
will(returnValue(time));
}});
}
void expectSendInviteMessage(String text) throws Exception {
expectCheckWhetherContactSupportsAutoDeletion(true);
expectGetLocalTimestamp(messageTimestamp);
expectGetTimestampForVisibleMessage(messageTimestamp);
expectCheckWhetherContactSupportsAutoDeletion();
context.checking(new Expectations() {{
oneOf(messageEncoder).encodeInviteMessage(contactGroupId,
privateGroupId, inviteTimestamp, privateGroup.getName(),
@@ -137,8 +150,10 @@ abstract class AbstractProtocolEngineTest extends BrambleMockTestCase {
void expectSendJoinMessage(JoinMessage m, boolean visible)
throws Exception {
expectCheckWhetherContactSupportsAutoDeletion(visible);
expectGetLocalTimestamp(messageTimestamp);
if (visible) expectGetTimestampForVisibleMessage(messageTimestamp);
else expectGetTimestampForInvisibleMessage(messageTimestamp);
expectCheckWhetherContactSupportsAutoDeletion();
if (visible) expectGetAutoDeleteTimer();
context.checking(new Expectations() {{
oneOf(messageEncoder).encodeJoinMessage(m.getContactGroupId(),
m.getPrivateGroupId(), m.getTimestamp(),
@@ -149,8 +164,10 @@ abstract class AbstractProtocolEngineTest extends BrambleMockTestCase {
}
void expectSendLeaveMessage(boolean visible) throws Exception {
expectCheckWhetherContactSupportsAutoDeletion(visible);
expectGetLocalTimestamp(messageTimestamp);
if (visible) expectGetTimestampForVisibleMessage(messageTimestamp);
else expectGetTimestampForInvisibleMessage(messageTimestamp);
expectCheckWhetherContactSupportsAutoDeletion();
if (visible) expectGetAutoDeleteTimer();
context.checking(new Expectations() {{
oneOf(messageEncoder).encodeLeaveMessage(contactGroupId,
privateGroupId, messageTimestamp, lastLocalMessageId,
@@ -161,7 +178,7 @@ abstract class AbstractProtocolEngineTest extends BrambleMockTestCase {
}
void expectSendAbortMessage() throws Exception {
expectGetLocalTimestamp(messageTimestamp);
expectGetTimestampForInvisibleMessage(messageTimestamp);
context.checking(new Expectations() {{
oneOf(messageEncoder)
.encodeAbortMessage(contactGroupId, privateGroupId,
@@ -226,8 +243,7 @@ abstract class AbstractProtocolEngineTest extends BrambleMockTestCase {
}});
}
void expectCheckWhetherContactSupportsAutoDeletion(boolean visible)
throws Exception {
void expectCheckWhetherContactSupportsAutoDeletion() throws Exception {
context.checking(new Expectations() {{
oneOf(clientHelper).getContactId(txn, contactGroupId);
will(returnValue(contactId));
@@ -235,10 +251,13 @@ abstract class AbstractProtocolEngineTest extends BrambleMockTestCase {
GroupInvitationManager.CLIENT_ID,
GroupInvitationManager.MAJOR_VERSION);
will(returnValue(GroupInvitationManager.MINOR_VERSION));
if (visible) {
oneOf(autoDeleteManager).getAutoDeleteTimer(txn, contactId);
will(returnValue(NO_AUTO_DELETE_TIMER));
}
}});
}
void expectGetAutoDeleteTimer() throws Exception {
context.checking(new Expectations() {{
oneOf(autoDeleteManager).getAutoDeleteTimer(txn, contactId);
will(returnValue(NO_AUTO_DELETE_TIMER));
}});
}
}

View File

@@ -24,7 +24,8 @@ public class CreatorProtocolEngineTest extends AbstractProtocolEngineTest {
new CreatorProtocolEngine(db, clientHelper, clientVersioningManager,
privateGroupManager, privateGroupFactory,
groupMessageFactory, identityManager, messageParser,
messageEncoder, messageTracker, autoDeleteManager, clock);
messageEncoder, messageTracker, autoDeleteManager,
conversationManager, clock);
private CreatorSession getDefaultSession(CreatorState state) {
return new CreatorSession(contactGroupId, privateGroupId,
@@ -43,7 +44,7 @@ public class CreatorProtocolEngineTest extends AbstractProtocolEngineTest {
expectOnLocalInvite(text);
CreatorSession newSession =
engine.onInviteAction(txn, session, text, inviteTimestamp,
signature);
signature, NO_AUTO_DELETE_TIMER);
assertEquals(INVITED, newSession.getState());
assertEquals(messageId, newSession.getLastLocalMessageId());
assertNull(newSession.getLastRemoteMessageId());
@@ -60,7 +61,7 @@ public class CreatorProtocolEngineTest extends AbstractProtocolEngineTest {
expectOnLocalInvite(null);
CreatorSession newSession =
engine.onInviteAction(txn, session, null, inviteTimestamp,
signature);
signature, NO_AUTO_DELETE_TIMER);
assertEquals(INVITED, newSession.getState());
assertEquals(messageId, newSession.getLastLocalMessageId());
assertNull(newSession.getLastRemoteMessageId());
@@ -83,31 +84,31 @@ public class CreatorProtocolEngineTest extends AbstractProtocolEngineTest {
@Test(expected = ProtocolStateException.class)
public void testOnInviteActionFromInvited() throws Exception {
engine.onInviteAction(txn, getDefaultSession(INVITED), null,
inviteTimestamp, signature);
inviteTimestamp, signature, NO_AUTO_DELETE_TIMER);
}
@Test(expected = ProtocolStateException.class)
public void testOnInviteActionFromJoined() throws Exception {
engine.onInviteAction(txn, getDefaultSession(JOINED), null,
inviteTimestamp, signature);
inviteTimestamp, signature, NO_AUTO_DELETE_TIMER);
}
@Test(expected = ProtocolStateException.class)
public void testOnInviteActionFromLeft() throws Exception {
engine.onInviteAction(txn, getDefaultSession(LEFT), null,
inviteTimestamp, signature);
inviteTimestamp, signature, NO_AUTO_DELETE_TIMER);
}
@Test(expected = ProtocolStateException.class)
public void testOnInviteActionFromDissolved() throws Exception {
engine.onInviteAction(txn, getDefaultSession(DISSOLVED), null,
inviteTimestamp, signature);
inviteTimestamp, signature, NO_AUTO_DELETE_TIMER);
}
@Test(expected = ProtocolStateException.class)
public void testOnInviteActionFromError() throws Exception {
engine.onInviteAction(txn, getDefaultSession(ERROR), null,
inviteTimestamp, signature);
inviteTimestamp, signature, NO_AUTO_DELETE_TIMER);
}
// onJoinAction

View File

@@ -27,6 +27,7 @@ import java.util.Set;
import javax.annotation.Nullable;
import static java.util.Collections.emptySet;
import static org.briarproject.briar.api.autodelete.AutoDeleteConstants.NO_AUTO_DELETE_TIMER;
import static org.briarproject.briar.test.BriarTestUtils.assertGroupCount;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
@@ -687,7 +688,8 @@ public class GroupInvitationIntegrationTest
byte[] signature = groupInvitationFactory.signInvitation(contact1From0,
privateGroup.getId(), timestamp, author0.getPrivateKey());
groupInvitationManager0.sendInvitation(privateGroup.getId(),
contactId1From0, text, timestamp, signature);
contactId1From0, text, timestamp, signature,
NO_AUTO_DELETE_TIMER);
}
}

View File

@@ -482,7 +482,7 @@ public class GroupInvitationManagerImplTest extends BrambleMockTestCase {
context.checking(new Expectations() {{
oneOf(creatorEngine).onInviteAction(with(txn),
with(any(CreatorSession.class)), with(text), with(time),
with(signature));
with(signature), with(NO_AUTO_DELETE_TIMER));
will(returnValue(creatorSession));
}});
expectStoreSession(creatorSession, storageMessage.getId());
@@ -491,7 +491,7 @@ public class GroupInvitationManagerImplTest extends BrambleMockTestCase {
oneOf(db).endTransaction(txn);
}});
groupInvitationManager.sendInvitation(privateGroup.getId(), contactId,
text, time, signature);
text, time, signature, NO_AUTO_DELETE_TIMER);
}
@Test
@@ -514,7 +514,7 @@ public class GroupInvitationManagerImplTest extends BrambleMockTestCase {
will(returnValue(creatorSession));
oneOf(creatorEngine).onInviteAction(with(txn),
with(any(CreatorSession.class)), with(text), with(time),
with(signature));
with(signature), with(NO_AUTO_DELETE_TIMER));
will(returnValue(creatorSession));
}});
expectStoreSession(creatorSession, storageMessage.getId());
@@ -523,7 +523,7 @@ public class GroupInvitationManagerImplTest extends BrambleMockTestCase {
oneOf(db).endTransaction(txn);
}});
groupInvitationManager.sendInvitation(privateGroup.getId(), contactId,
text, time, signature);
text, time, signature, NO_AUTO_DELETE_TIMER);
}
@Test(expected = IllegalArgumentException.class)

View File

@@ -43,7 +43,8 @@ public class InviteeProtocolEngineTest extends AbstractProtocolEngineTest {
new InviteeProtocolEngine(db, clientHelper, clientVersioningManager,
privateGroupManager, privateGroupFactory,
groupMessageFactory, identityManager, messageParser,
messageEncoder, messageTracker, autoDeleteManager, clock);
messageEncoder, messageTracker, autoDeleteManager,
conversationManager, clock);
private final LocalAuthor localAuthor = getLocalAuthor();
private InviteeSession getDefaultSession(InviteeState state) {
@@ -57,43 +58,43 @@ public class InviteeProtocolEngineTest extends AbstractProtocolEngineTest {
@Test(expected = UnsupportedOperationException.class)
public void testOnInviteActionFromStart() {
engine.onInviteAction(txn, getDefaultSession(START), null,
messageTimestamp, signature);
messageTimestamp, signature, NO_AUTO_DELETE_TIMER);
}
@Test(expected = UnsupportedOperationException.class)
public void testOnInviteActionFromLeft() {
engine.onInviteAction(txn, getDefaultSession(ACCEPTED), null,
messageTimestamp, signature);
messageTimestamp, signature, NO_AUTO_DELETE_TIMER);
}
@Test(expected = UnsupportedOperationException.class)
public void testOnInviteActionFromInvited() {
engine.onInviteAction(txn, getDefaultSession(INVITED), null,
messageTimestamp, signature);
messageTimestamp, signature, NO_AUTO_DELETE_TIMER);
}
@Test(expected = UnsupportedOperationException.class)
public void testOnInviteActionFromDissolved() {
engine.onInviteAction(txn, getDefaultSession(DISSOLVED), null,
messageTimestamp, signature);
messageTimestamp, signature, NO_AUTO_DELETE_TIMER);
}
@Test(expected = UnsupportedOperationException.class)
public void testOnInviteActionFromAccepted() {
engine.onInviteAction(txn, getDefaultSession(ACCEPTED), null,
messageTimestamp, signature);
messageTimestamp, signature, NO_AUTO_DELETE_TIMER);
}
@Test(expected = UnsupportedOperationException.class)
public void testOnInviteActionFromJoined() {
engine.onInviteAction(txn, getDefaultSession(JOINED), null,
messageTimestamp, signature);
messageTimestamp, signature, NO_AUTO_DELETE_TIMER);
}
@Test(expected = UnsupportedOperationException.class)
public void testOnInviteActionFromError() {
engine.onInviteAction(txn, getDefaultSession(ERROR), null,
messageTimestamp, signature);
messageTimestamp, signature, NO_AUTO_DELETE_TIMER);
}
// onJoinAction

View File

@@ -27,7 +27,8 @@ public class PeerProtocolEngineTest extends AbstractProtocolEngineTest {
new PeerProtocolEngine(db, clientHelper, clientVersioningManager,
privateGroupManager, privateGroupFactory,
groupMessageFactory, identityManager, messageParser,
messageEncoder, messageTracker, autoDeleteManager, clock);
messageEncoder, messageTracker, autoDeleteManager,
conversationManager, clock);
private PeerSession getDefaultSession(PeerState state) {
return new PeerSession(contactGroupId, privateGroupId,
@@ -39,43 +40,43 @@ public class PeerProtocolEngineTest extends AbstractProtocolEngineTest {
@Test(expected = UnsupportedOperationException.class)
public void testOnInviteActionFromStart() {
engine.onInviteAction(txn, getDefaultSession(START), null,
messageTimestamp, signature);
messageTimestamp, signature, NO_AUTO_DELETE_TIMER);
}
@Test(expected = UnsupportedOperationException.class)
public void testOnInviteActionFromAwaitMember() {
engine.onInviteAction(txn, getDefaultSession(AWAIT_MEMBER), null,
messageTimestamp, signature);
messageTimestamp, signature, NO_AUTO_DELETE_TIMER);
}
@Test(expected = UnsupportedOperationException.class)
public void testOnInviteActionFromNeitherJoined() {
engine.onInviteAction(txn, getDefaultSession(NEITHER_JOINED), null,
messageTimestamp, signature);
messageTimestamp, signature, NO_AUTO_DELETE_TIMER);
}
@Test(expected = UnsupportedOperationException.class)
public void testOnInviteActionFromLocalJoined() {
engine.onInviteAction(txn, getDefaultSession(LOCAL_JOINED), null,
messageTimestamp, signature);
messageTimestamp, signature, NO_AUTO_DELETE_TIMER);
}
@Test(expected = UnsupportedOperationException.class)
public void testOnInviteActionFromBothJoined() {
engine.onInviteAction(txn, getDefaultSession(BOTH_JOINED), null,
messageTimestamp, signature);
messageTimestamp, signature, NO_AUTO_DELETE_TIMER);
}
@Test(expected = UnsupportedOperationException.class)
public void testOnInviteActionFromLocalLeft() {
engine.onInviteAction(txn, getDefaultSession(LOCAL_LEFT), null,
messageTimestamp, signature);
messageTimestamp, signature, NO_AUTO_DELETE_TIMER);
}
@Test(expected = UnsupportedOperationException.class)
public void testOnInviteActionFromError() {
engine.onInviteAction(txn, getDefaultSession(ERROR), null,
messageTimestamp, signature);
messageTimestamp, signature, NO_AUTO_DELETE_TIMER);
}
// onJoinAction

View File

@@ -122,8 +122,7 @@ public class BlogSharingIntegrationTest
// send invitation
blogSharingManager0
.sendInvitation(blog2.getId(), contactId1From0, "Hi!",
clock.currentTimeMillis());
.sendInvitation(blog2.getId(), contactId1From0, "Hi!");
// invitee has own blog and that of the sharer
assertEquals(2, blogManager1.getBlogs().size());
@@ -213,8 +212,8 @@ public class BlogSharingIntegrationTest
blogManager0.addBlog(rssBlog);
// send invitation
blogSharingManager0.sendInvitation(rssBlog.getId(), contactId1From0,
"Hi!", clock.currentTimeMillis());
blogSharingManager0
.sendInvitation(rssBlog.getId(), contactId1From0, "Hi!");
// invitee has own blog and that of the sharer
assertEquals(2, blogManager1.getBlogs().size());
@@ -285,8 +284,7 @@ public class BlogSharingIntegrationTest
// send invitation
blogSharingManager0
.sendInvitation(blog2.getId(), contactId1From0, null,
clock.currentTimeMillis());
.sendInvitation(blog2.getId(), contactId1From0, null);
// sync first request message
sync0To1(1, true);
@@ -341,8 +339,7 @@ public class BlogSharingIntegrationTest
// send invitation
blogSharingManager0
.sendInvitation(blog2.getId(), contactId1From0, "Hi!",
clock.currentTimeMillis());
.sendInvitation(blog2.getId(), contactId1From0, "Hi!");
// sync first request message
sync0To1(1, true);
@@ -398,8 +395,7 @@ public class BlogSharingIntegrationTest
// sharer sends invitation for 2's blog to 1
blogSharingManager0
.sendInvitation(blog2.getId(), contactId1From0, "Hi!",
clock.currentTimeMillis());
.sendInvitation(blog2.getId(), contactId1From0, "Hi!");
// sync first request message
sync0To1(1, true);
@@ -436,8 +432,7 @@ public class BlogSharingIntegrationTest
// send invitation
blogSharingManager0
.sendInvitation(blog2.getId(), contactId1From0, "Hi!",
clock.currentTimeMillis());
.sendInvitation(blog2.getId(), contactId1From0, "Hi!");
// sync first request message
sync0To1(1, true);
@@ -515,8 +510,7 @@ public class BlogSharingIntegrationTest
// sharer sends invitation for 2's blog to 1
blogSharingManager0
.sendInvitation(blog2.getId(), contactId1From0, "Hi!",
clock.currentTimeMillis());
.sendInvitation(blog2.getId(), contactId1From0, "Hi!");
// sync first request message
sync0To1(1, true);

View File

@@ -126,8 +126,7 @@ public class ForumSharingIntegrationTest
public void testSuccessfulSharing() throws Exception {
// send invitation
forumSharingManager0
.sendInvitation(forum.getId(), contactId1From0, "Hi!",
clock.currentTimeMillis());
.sendInvitation(forum.getId(), contactId1From0, "Hi!");
// check that request message state is correct
Collection<ConversationMessageHeader> messages = getMessages1From0();
@@ -191,8 +190,8 @@ public class ForumSharingIntegrationTest
@Test
public void testDeclinedSharing() throws Exception {
// send invitation
forumSharingManager0.sendInvitation(forum.getId(), contactId1From0,
null, clock.currentTimeMillis());
forumSharingManager0
.sendInvitation(forum.getId(), contactId1From0, null);
// sync request message
sync0To1(1, true);
@@ -243,8 +242,8 @@ public class ForumSharingIntegrationTest
// send a new invitation again after re-adding the forum
db0.transaction(false, txn -> forumManager0.addForum(txn, forum));
forumSharingManager0.sendInvitation(forum.getId(), contactId1From0,
null, clock.currentTimeMillis());
forumSharingManager0
.sendInvitation(forum.getId(), contactId1From0, null);
// reset listener state for new request
listener1.requestReceived = false;
@@ -259,8 +258,8 @@ public class ForumSharingIntegrationTest
@Test
public void testInviteeLeavesAfterFinished() throws Exception {
// send invitation
forumSharingManager0.sendInvitation(forum.getId(), contactId1From0,
"Hi!", clock.currentTimeMillis());
forumSharingManager0
.sendInvitation(forum.getId(), contactId1From0, "Hi!");
// sync request message
sync0To1(1, true);
@@ -322,8 +321,8 @@ public class ForumSharingIntegrationTest
@Test
public void testSharerLeavesAfterFinished() throws Exception {
// send invitation
forumSharingManager0.sendInvitation(forum.getId(), contactId1From0,
null, clock.currentTimeMillis());
forumSharingManager0
.sendInvitation(forum.getId(), contactId1From0, null);
// sync request message
sync0To1(1, true);
@@ -383,8 +382,8 @@ public class ForumSharingIntegrationTest
// send a new invitation again after re-adding the forum
db0.transaction(false, txn -> forumManager0.addForum(txn, forum));
forumSharingManager0.sendInvitation(forum.getId(), contactId1From0,
null, clock.currentTimeMillis());
forumSharingManager0
.sendInvitation(forum.getId(), contactId1From0, null);
// reset listener state for new request
listener1.requestReceived = false;
@@ -399,8 +398,8 @@ public class ForumSharingIntegrationTest
@Test
public void testSharerLeavesBeforeResponse() throws Exception {
// send invitation
forumSharingManager0.sendInvitation(forum.getId(), contactId1From0,
null, clock.currentTimeMillis());
forumSharingManager0
.sendInvitation(forum.getId(), contactId1From0, null);
// sharer un-subscribes from forum
forumManager0.removeForum(forum);
@@ -420,8 +419,7 @@ public class ForumSharingIntegrationTest
// send invitation
forumSharingManager0
.sendInvitation(forum.getId(), contactId1From0, null,
clock.currentTimeMillis());
.sendInvitation(forum.getId(), contactId1From0, null);
// sync request message
sync0To1(1, true);
@@ -445,8 +443,8 @@ public class ForumSharingIntegrationTest
@Test
public void testSharingSameForumWithEachOther() throws Exception {
// send invitation
forumSharingManager0.sendInvitation(forum.getId(), contactId1From0,
"Hi!", clock.currentTimeMillis());
forumSharingManager0
.sendInvitation(forum.getId(), contactId1From0, "Hi!");
// sync request message
sync0To1(1, true);
@@ -471,10 +469,9 @@ public class ForumSharingIntegrationTest
assertEquals(1, forumManager1.getForums().size());
// invitee now shares same forum back
forumSharingManager1.sendInvitation(forum.getId(),
contactId0From1,
"I am re-sharing this forum with you.",
clock.currentTimeMillis());
forumSharingManager1
.sendInvitation(forum.getId(), contactId0From1,
"I am re-sharing this forum with you.");
// assert that the last invitation wasn't send
assertEquals(2, c1.getMessageTracker().getGroupCount(group.getId())
@@ -485,8 +482,8 @@ public class ForumSharingIntegrationTest
public void testSharingSameForumWithEachOtherBeforeAccept()
throws Exception {
// send invitation
forumSharingManager0.sendInvitation(forum.getId(), contactId1From0,
"Hi!", clock.currentTimeMillis());
forumSharingManager0
.sendInvitation(forum.getId(), contactId1From0, "Hi!");
sync0To1(1, true);
eventWaiter.await(TIMEOUT, 1);
assertRequestReceived(listener1, contactId0From1);
@@ -501,10 +498,9 @@ public class ForumSharingIntegrationTest
.getMsgCount());
// invitee now shares same forum back
forumSharingManager1.sendInvitation(forum.getId(),
contactId0From1,
"I am re-sharing this forum with you.",
clock.currentTimeMillis());
forumSharingManager1
.sendInvitation(forum.getId(), contactId0From1,
"I am re-sharing this forum with you.");
// assert that the last invitation wasn't send
assertEquals(1, c1.getMessageTracker().getGroupCount(group.getId())
@@ -518,13 +514,12 @@ public class ForumSharingIntegrationTest
// send invitation
forumSharingManager0
.sendInvitation(forum.getId(), contactId1From0, "Hi!",
clock.currentTimeMillis());
.sendInvitation(forum.getId(), contactId1From0, "Hi!");
// invitee now shares same forum back
forumSharingManager1.sendInvitation(forum.getId(),
contactId0From1, "I am re-sharing this forum with you.",
clock.currentTimeMillis());
forumSharingManager1
.sendInvitation(forum.getId(), contactId0From1,
"I am re-sharing this forum with you.");
// only now sync request message
sync0To1(1, true);
@@ -554,8 +549,8 @@ public class ForumSharingIntegrationTest
@Test
public void testContactRemoved() throws Exception {
// send invitation
forumSharingManager0.sendInvitation(forum.getId(), contactId1From0,
"Hi!", clock.currentTimeMillis());
forumSharingManager0
.sendInvitation(forum.getId(), contactId1From0, "Hi!");
// sync request message
sync0To1(1, true);
@@ -597,8 +592,7 @@ public class ForumSharingIntegrationTest
// send invitation
forumSharingManager0
.sendInvitation(forum.getId(), contactId1From0, "Hi!",
clock.currentTimeMillis());
.sendInvitation(forum.getId(), contactId1From0, "Hi!");
// sync request message
sync0To1(1, true);
@@ -626,8 +620,7 @@ public class ForumSharingIntegrationTest
// send invitation
forumSharingManager0
.sendInvitation(forum.getId(), contactId1From0, "Hi!",
clock.currentTimeMillis());
.sendInvitation(forum.getId(), contactId1From0, "Hi!");
// sync request message
sync0To1(1, true);
@@ -637,8 +630,7 @@ public class ForumSharingIntegrationTest
// second sharer sends invitation for same forum
assertNotNull(contactId1From2);
forumSharingManager2
.sendInvitation(forum.getId(), contactId1From2, null,
clock.currentTimeMillis());
.sendInvitation(forum.getId(), contactId1From2, null);
// sync second request message
sync2To1(1, true);
@@ -680,8 +672,8 @@ public class ForumSharingIntegrationTest
@Test
public void testSyncAfterReSharing() throws Exception {
// send invitation
forumSharingManager0.sendInvitation(forum.getId(), contactId1From0,
"Hi!", clock.currentTimeMillis());
forumSharingManager0
.sendInvitation(forum.getId(), contactId1From0, "Hi!");
// sync request message
sync0To1(1, true);
@@ -745,8 +737,7 @@ public class ForumSharingIntegrationTest
// send invitation again
forumSharingManager0
.sendInvitation(forum.getId(), contactId1From0, "Hi!",
clock.currentTimeMillis());
.sendInvitation(forum.getId(), contactId1From0, "Hi!");
// sync request message
sync0To1(1, true);
@@ -787,8 +778,8 @@ public class ForumSharingIntegrationTest
@Test
public void testSessionResetAfterAbort() throws Exception {
// send invitation
forumSharingManager0.sendInvitation(forum.getId(), contactId1From0,
"Hi!", clock.currentTimeMillis());
forumSharingManager0
.sendInvitation(forum.getId(), contactId1From0, "Hi!");
// sync request message
sync0To1(1, true);
@@ -836,8 +827,7 @@ public class ForumSharingIntegrationTest
// new invitation is possible now
forumSharingManager0
.sendInvitation(forum.getId(), contactId1From0, null,
clock.currentTimeMillis());
.sendInvitation(forum.getId(), contactId1From0, null);
sync0To1(1, true);
eventWaiter.await(TIMEOUT, 1);
assertRequestReceived(listener1, contactId0From1);
@@ -859,8 +849,8 @@ public class ForumSharingIntegrationTest
public void testDeletingAllMessagesWhenCompletingSession()
throws Exception {
// send invitation
forumSharingManager0.sendInvitation(forum.getId(), contactId1From0,
null, clock.currentTimeMillis());
forumSharingManager0
.sendInvitation(forum.getId(), contactId1From0, null);
sync0To1(1, true);
eventWaiter.await(TIMEOUT, 1);
@@ -909,8 +899,8 @@ public class ForumSharingIntegrationTest
sync1To0(1, true);
// sending invitation is possible again
forumSharingManager1.sendInvitation(forum.getId(), contactId0From1,
null, clock.currentTimeMillis());
forumSharingManager1
.sendInvitation(forum.getId(), contactId0From1, null);
sync1To0(1, true);
eventWaiter.await(TIMEOUT, 1);
@@ -944,8 +934,8 @@ public class ForumSharingIntegrationTest
public void testDeletingAllMessagesAfterDecline()
throws Exception {
// send invitation
forumSharingManager0.sendInvitation(forum.getId(), contactId1From0,
null, clock.currentTimeMillis());
forumSharingManager0
.sendInvitation(forum.getId(), contactId1From0, null);
sync0To1(1, true);
eventWaiter.await(TIMEOUT, 1);
@@ -969,8 +959,8 @@ public class ForumSharingIntegrationTest
assertEquals(0, getMessages0From1().size());
// re-sending invitation is possible
forumSharingManager0.sendInvitation(forum.getId(), contactId1From0,
null, clock.currentTimeMillis());
forumSharingManager0
.sendInvitation(forum.getId(), contactId1From0, null);
sync0To1(1, true);
eventWaiter.await(TIMEOUT, 1);
@@ -984,8 +974,8 @@ public class ForumSharingIntegrationTest
@Test
public void testDeletingSomeMessages() throws Exception {
// send invitation
forumSharingManager0.sendInvitation(forum.getId(), contactId1From0,
null, clock.currentTimeMillis());
forumSharingManager0
.sendInvitation(forum.getId(), contactId1From0, null);
sync0To1(1, true);
eventWaiter.await(TIMEOUT, 1);
@@ -996,7 +986,8 @@ public class ForumSharingIntegrationTest
Set<MessageId> toDelete = new HashSet<>();
toDelete.add(messageId);
assertFalse(deleteMessages1From0(toDelete).allDeleted());
assertTrue(deleteMessages1From0(toDelete).hasInvitationSessionInProgress());
assertTrue(deleteMessages1From0(toDelete)
.hasInvitationSessionInProgress());
// decline invitation
respondToRequest(contactId0From1, true);
@@ -1006,9 +997,11 @@ public class ForumSharingIntegrationTest
// both can still not delete the invitation,
// because the response was not selected for deletion as well
assertFalse(deleteMessages1From0(toDelete).allDeleted());
assertTrue(deleteMessages1From0(toDelete).hasNotAllInvitationSelected());
assertTrue(
deleteMessages1From0(toDelete).hasNotAllInvitationSelected());
assertFalse(deleteMessages0From1(toDelete).allDeleted());
assertTrue(deleteMessages0From1(toDelete).hasNotAllInvitationSelected());
assertTrue(
deleteMessages0From1(toDelete).hasNotAllInvitationSelected());
// after selecting response, both messages can be deleted
m0 = getMessages1From0();
@@ -1023,8 +1016,10 @@ public class ForumSharingIntegrationTest
// 1 can still not delete the messages, as last one has not been ACKed
assertFalse(deleteMessages0From1(toDelete).allDeleted());
assertFalse(deleteMessages0From1(toDelete).hasNotAllInvitationSelected());
assertTrue(deleteMessages0From1(toDelete).hasInvitationSessionInProgress());
assertFalse(
deleteMessages0From1(toDelete).hasNotAllInvitationSelected());
assertTrue(deleteMessages0From1(toDelete)
.hasInvitationSessionInProgress());
// 0 sends an ACK to their last message
sendAcks(c0, c1, contactId1From0, 1);