diff --git a/briar-android/src/main/java/org/briarproject/briar/android/AndroidComponent.java b/briar-android/src/main/java/org/briarproject/briar/android/AndroidComponent.java index fedf33ba3..21946799d 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/AndroidComponent.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/AndroidComponent.java @@ -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); diff --git a/briar-android/src/main/java/org/briarproject/briar/android/conversation/ConversationActivity.java b/briar-android/src/main/java/org/briarproject/briar/android/conversation/ConversationActivity.java index a741cf5bb..a91359cd3 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/conversation/ConversationActivity.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/conversation/ConversationActivity.java @@ -753,18 +753,10 @@ public class ConversationActivity extends BriarActivity List 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 diff --git a/briar-android/src/main/java/org/briarproject/briar/android/conversation/ConversationViewModel.java b/briar-android/src/main/java/org/briarproject/briar/android/conversation/ConversationViewModel.java index 62150773d..073005e16 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/conversation/ConversationViewModel.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/conversation/ConversationViewModel.java @@ -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 headers, long timestamp) { + void sendMessage(@Nullable String text, List 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 headers, long timestamp, - PrivateMessageFormat format) throws DbException { + List 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 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(); diff --git a/briar-android/src/main/java/org/briarproject/briar/android/introduction/IntroductionMessageFragment.java b/briar-android/src/main/java/org/briarproject/briar/android/introduction/IntroductionMessageFragment.java index e7d85dc91..2705af262 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/introduction/IntroductionMessageFragment.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/introduction/IntroductionMessageFragment.java @@ -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(); diff --git a/briar-android/src/main/java/org/briarproject/briar/android/privategroup/creation/CreateGroupControllerImpl.java b/briar-android/src/main/java/org/briarproject/briar/android/privategroup/creation/CreateGroupControllerImpl.java index 88355a63b..743644590 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/privategroup/creation/CreateGroupControllerImpl.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/privategroup/creation/CreateGroupControllerImpl.java @@ -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 handler) { runOnDbThread(() -> { try { - LocalAuthor localAuthor = identityManager.getLocalAuthor(); - List 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 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 createInvitationContexts(Transaction txn, + Collection contactIds) throws DbException { + List 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 contacts, @Nullable String text, + List contexts, @Nullable String text, ResultExceptionHandler handler) { cryptoExecutor.execute(() -> { - long timestamp = clock.currentTimeMillis(); - List 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 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; } } } diff --git a/briar-android/src/main/java/org/briarproject/briar/android/sharing/ShareBlogControllerImpl.java b/briar-android/src/main/java/org/briarproject/briar/android/sharing/ShareBlogControllerImpl.java index 26af4b3ca..65e36d4eb 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/sharing/ShareBlogControllerImpl.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/sharing/ShareBlogControllerImpl.java @@ -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); } diff --git a/briar-android/src/main/java/org/briarproject/briar/android/sharing/ShareForumControllerImpl.java b/briar-android/src/main/java/org/briarproject/briar/android/sharing/ShareForumControllerImpl.java index 9bbc6d3e7..7349ca00e 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/sharing/ShareForumControllerImpl.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/sharing/ShareForumControllerImpl.java @@ -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); } diff --git a/briar-api/src/main/java/org/briarproject/briar/api/conversation/ConversationManager.java b/briar-api/src/main/java/org/briarproject/briar/api/conversation/ConversationManager.java index 96823d45b..a8fae64a5 100644 --- a/briar-api/src/main/java/org/briarproject/briar/api/conversation/ConversationManager.java +++ b/briar-api/src/main/java/org/briarproject/briar/api/conversation/ConversationManager.java @@ -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. */ diff --git a/briar-api/src/main/java/org/briarproject/briar/api/introduction/IntroductionManager.java b/briar-api/src/main/java/org/briarproject/briar/api/introduction/IntroductionManager.java index 8eef68eea..71c28028f 100644 --- a/briar-api/src/main/java/org/briarproject/briar/api/introduction/IntroductionManager.java +++ b/briar-api/src/main/java/org/briarproject/briar/api/introduction/IntroductionManager.java @@ -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; } diff --git a/briar-api/src/main/java/org/briarproject/briar/api/privategroup/invitation/GroupInvitationManager.java b/briar-api/src/main/java/org/briarproject/briar/api/privategroup/invitation/GroupInvitationManager.java index 023d5b172..061064e9c 100644 --- a/briar-api/src/main/java/org/briarproject/briar/api/privategroup/invitation/GroupInvitationManager.java +++ b/briar-api/src/main/java/org/briarproject/briar/api/privategroup/invitation/GroupInvitationManager.java @@ -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. diff --git a/briar-api/src/main/java/org/briarproject/briar/api/sharing/SharingManager.java b/briar-api/src/main/java/org/briarproject/briar/api/sharing/SharingManager.java index 3e6adc2dc..de4817c56 100644 --- a/briar-api/src/main/java/org/briarproject/briar/api/sharing/SharingManager.java +++ b/briar-api/src/main/java/org/briarproject/briar/api/sharing/SharingManager.java @@ -21,7 +21,7 @@ public interface SharingManager * 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 diff --git a/briar-core/src/main/java/org/briarproject/briar/introduction/AbstractProtocolEngine.java b/briar-core/src/main/java/org/briarproject/briar/introduction/AbstractProtocolEngine.java index 1fc011fc2..9eb80ceb2 100644 --- a/briar-core/src/main/java/org/briarproject/briar/introduction/AbstractProtocolEngine.java +++ b/briar-core/src/main/java/org/briarproject/briar/introduction/AbstractProtocolEngine.java @@ -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> 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> MessageEncoder messageEncoder, ClientVersioningManager clientVersioningManager, AutoDeleteManager autoDeleteManager, + ConversationManager conversationManager, Clock clock) { this.db = db; this.clientHelper = clientHelper; @@ -83,6 +86,7 @@ abstract class AbstractProtocolEngine> this.messageEncoder = messageEncoder; this.clientVersioningManager = clientVersioningManager; this.autoDeleteManager = autoDeleteManager; + this.conversationManager = conversationManager; this.clock = clock; } @@ -227,14 +231,10 @@ abstract class AbstractProtocolEngine> 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) diff --git a/briar-core/src/main/java/org/briarproject/briar/introduction/IntroduceeProtocolEngine.java b/briar-core/src/main/java/org/briarproject/briar/introduction/IntroduceeProtocolEngine.java index 98e1883fc..0c6b51f7b 100644 --- a/briar-core/src/main/java/org/briarproject/briar/introduction/IntroduceeProtocolEngine.java +++ b/briar-core/src/main/java/org/briarproject/briar/introduction/IntroduceeProtocolEngine.java @@ -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 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) diff --git a/briar-core/src/main/java/org/briarproject/briar/introduction/IntroducerProtocolEngine.java b/briar-core/src/main/java/org/briarproject/briar/introduction/IntroducerProtocolEngine.java index ba632bb4b..a05b5807a 100644 --- a/briar-core/src/main/java/org/briarproject/briar/introduction/IntroducerProtocolEngine.java +++ b/briar-core/src/main/java/org/briarproject/briar/introduction/IntroducerProtocolEngine.java @@ -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()); + } } diff --git a/briar-core/src/main/java/org/briarproject/briar/introduction/IntroductionManagerImpl.java b/briar-core/src/main/java/org/briarproject/briar/introduction/IntroductionManagerImpl.java index 2050d1b65..3672d254e 100644 --- a/briar-core/src/main/java/org/briarproject/briar/introduction/IntroductionManagerImpl.java +++ b/briar-core/src/main/java/org/briarproject/briar/introduction/IntroductionManagerImpl.java @@ -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); diff --git a/briar-core/src/main/java/org/briarproject/briar/introduction/ProtocolEngine.java b/briar-core/src/main/java/org/briarproject/briar/introduction/ProtocolEngine.java index 855cce767..b9eb7aba3 100644 --- a/briar-core/src/main/java/org/briarproject/briar/introduction/ProtocolEngine.java +++ b/briar-core/src/main/java/org/briarproject/briar/introduction/ProtocolEngine.java @@ -8,16 +8,14 @@ import org.briarproject.bramble.api.nullsafety.NotNullByDefault; import javax.annotation.Nullable; @NotNullByDefault -interface ProtocolEngine { +interface ProtocolEngine> { - 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; diff --git a/briar-core/src/main/java/org/briarproject/briar/messaging/ConversationManagerImpl.java b/briar-core/src/main/java/org/briarproject/briar/messaging/ConversationManagerImpl.java index 7b991f3de..1a6434a5d 100644 --- a/briar-core/src/main/java/org/briarproject/briar/messaging/ConversationManagerImpl.java +++ b/briar-core/src/main/java/org/briarproject/briar/messaging/ConversationManagerImpl.java @@ -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 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 toDelete) - throws DbException { + public DeletionResult deleteMessages(ContactId c, + Collection toDelete) throws DbException { return db.transactionWithResult(false, txn -> { DeletionResult result = new DeletionResult(); for (ConversationClient client : clients) { diff --git a/briar-core/src/main/java/org/briarproject/briar/privategroup/invitation/AbstractProtocolEngine.java b/briar-core/src/main/java/org/briarproject/briar/privategroup/invitation/AbstractProtocolEngine.java index 396512594..a8d355005 100644 --- a/briar-core/src/main/java/org/briarproject/briar/privategroup/invitation/AbstractProtocolEngine.java +++ b/briar-core/src/main/java/org/briarproject/briar/privategroup/invitation/AbstractProtocolEngine.java @@ -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> 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> MessageEncoder messageEncoder, MessageTracker messageTracker, AutoDeleteManager autoDeleteManager, + ConversationManager conversationManager, Clock clock) { this.db = db; this.clientHelper = clientHelper; @@ -80,6 +84,7 @@ abstract class AbstractProtocolEngine> this.messageEncoder = messageEncoder; this.messageTracker = messageTracker; this.autoDeleteManager = autoDeleteManager; + this.conversationManager = conversationManager; this.clock = clock; } @@ -110,8 +115,8 @@ abstract class AbstractProtocolEngine> } 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> 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> 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> ? 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> 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> ? 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> 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> 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> .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, diff --git a/briar-core/src/main/java/org/briarproject/briar/privategroup/invitation/CreatorProtocolEngine.java b/briar-core/src/main/java/org/briarproject/briar/privategroup/invitation/CreatorProtocolEngine.java index a38967fdd..ac483b1d6 100644 --- a/briar-core/src/main/java/org/briarproject/briar/privategroup/invitation/CreatorProtocolEngine.java +++ b/briar-core/src/main/java/org/briarproject/briar/privategroup/invitation/CreatorProtocolEngine.java @@ -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 { 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 { } 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); diff --git a/briar-core/src/main/java/org/briarproject/briar/privategroup/invitation/GroupInvitationManagerImpl.java b/briar-core/src/main/java/org/briarproject/briar/privategroup/invitation/GroupInvitationManagerImpl.java index d89858a9e..b0243fa2f 100644 --- a/briar-core/src/main/java/org/briarproject/briar/privategroup/invitation/GroupInvitationManagerImpl.java +++ b/briar-core/src/main/java/org/briarproject/briar/privategroup/invitation/GroupInvitationManagerImpl.java @@ -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); diff --git a/briar-core/src/main/java/org/briarproject/briar/privategroup/invitation/InviteeProtocolEngine.java b/briar-core/src/main/java/org/briarproject/briar/privategroup/invitation/InviteeProtocolEngine.java index dbc17477f..87d82fdff 100644 --- a/briar-core/src/main/java/org/briarproject/briar/privategroup/invitation/InviteeProtocolEngine.java +++ b/briar-core/src/main/java/org/briarproject/briar/privategroup/invitation/InviteeProtocolEngine.java @@ -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 { - InviteeProtocolEngine(DatabaseComponent db, + InviteeProtocolEngine( + DatabaseComponent db, ClientHelper clientHelper, ClientVersioningManager clientVersioningManager, PrivateGroupManager privateGroupManager, @@ -53,16 +55,18 @@ class InviteeProtocolEngine extends AbstractProtocolEngine { 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 } diff --git a/briar-core/src/main/java/org/briarproject/briar/privategroup/invitation/PeerProtocolEngine.java b/briar-core/src/main/java/org/briarproject/briar/privategroup/invitation/PeerProtocolEngine.java index 21eef0053..a8c00fd25 100644 --- a/briar-core/src/main/java/org/briarproject/briar/privategroup/invitation/PeerProtocolEngine.java +++ b/briar-core/src/main/java/org/briarproject/briar/privategroup/invitation/PeerProtocolEngine.java @@ -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 { 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 } diff --git a/briar-core/src/main/java/org/briarproject/briar/privategroup/invitation/ProtocolEngine.java b/briar-core/src/main/java/org/briarproject/briar/privategroup/invitation/ProtocolEngine.java index 74fa35269..ec4010ff7 100644 --- a/briar-core/src/main/java/org/briarproject/briar/privategroup/invitation/ProtocolEngine.java +++ b/briar-core/src/main/java/org/briarproject/briar/privategroup/invitation/ProtocolEngine.java @@ -8,10 +8,11 @@ import org.briarproject.bramble.api.nullsafety.NotNullByDefault; import javax.annotation.Nullable; @NotNullByDefault -interface ProtocolEngine { +interface ProtocolEngine> { 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; diff --git a/briar-core/src/main/java/org/briarproject/briar/privategroup/invitation/ProtocolEngineFactoryImpl.java b/briar-core/src/main/java/org/briarproject/briar/privategroup/invitation/ProtocolEngineFactoryImpl.java index 089b06c66..210c4d27d 100644 --- a/briar-core/src/main/java/org/briarproject/briar/privategroup/invitation/ProtocolEngineFactoryImpl.java +++ b/briar-core/src/main/java/org/briarproject/briar/privategroup/invitation/ProtocolEngineFactoryImpl.java @@ -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); } } diff --git a/briar-core/src/main/java/org/briarproject/briar/sharing/BlogProtocolEngineImpl.java b/briar-core/src/main/java/org/briarproject/briar/sharing/BlogProtocolEngineImpl.java index 05fcc2eb0..6ebaa137f 100644 --- a/briar-core/src/main/java/org/briarproject/briar/sharing/BlogProtocolEngineImpl.java +++ b/briar-core/src/main/java/org/briarproject/briar/sharing/BlogProtocolEngineImpl.java @@ -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 { MessageParser messageParser, MessageTracker messageTracker, AutoDeleteManager autoDeleteManager, + ConversationManager conversationManager, Clock clock, BlogManager blogManager, InvitationFactory 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; } diff --git a/briar-core/src/main/java/org/briarproject/briar/sharing/ForumProtocolEngineImpl.java b/briar-core/src/main/java/org/briarproject/briar/sharing/ForumProtocolEngineImpl.java index 91757b463..8a1dabcc0 100644 --- a/briar-core/src/main/java/org/briarproject/briar/sharing/ForumProtocolEngineImpl.java +++ b/briar-core/src/main/java/org/briarproject/briar/sharing/ForumProtocolEngineImpl.java @@ -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 { MessageParser messageParser, MessageTracker messageTracker, AutoDeleteManager autoDeleteManager, + ConversationManager conversationManager, Clock clock, ForumManager forumManager, InvitationFactory 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; } diff --git a/briar-core/src/main/java/org/briarproject/briar/sharing/ProtocolEngine.java b/briar-core/src/main/java/org/briarproject/briar/sharing/ProtocolEngine.java index c0c94453c..637559648 100644 --- a/briar-core/src/main/java/org/briarproject/briar/sharing/ProtocolEngine.java +++ b/briar-core/src/main/java/org/briarproject/briar/sharing/ProtocolEngine.java @@ -12,7 +12,7 @@ import javax.annotation.Nullable; interface ProtocolEngine { 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; diff --git a/briar-core/src/main/java/org/briarproject/briar/sharing/ProtocolEngineImpl.java b/briar-core/src/main/java/org/briarproject/briar/sharing/ProtocolEngineImpl.java index 9e841bd44..37726ac70 100644 --- a/briar-core/src/main/java/org/briarproject/briar/sharing/ProtocolEngineImpl.java +++ b/briar-core/src/main/java/org/briarproject/briar/sharing/ProtocolEngineImpl.java @@ -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 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 MessageParser messageParser, MessageTracker messageTracker, AutoDeleteManager autoDeleteManager, + ConversationManager conversationManager, Clock clock, ClientId sharingClientId, int sharingClientMajorVersion, @@ -82,6 +86,7 @@ abstract class ProtocolEngineImpl 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 @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 } 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 } 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 } 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 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 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 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 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 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) diff --git a/briar-core/src/main/java/org/briarproject/briar/sharing/SharingManagerImpl.java b/briar-core/src/main/java/org/briarproject/briar/sharing/SharingManagerImpl.java index 462f3ae52..403f5a6a5 100644 --- a/briar-core/src/main/java/org/briarproject/briar/sharing/SharingManagerImpl.java +++ b/briar-core/src/main/java/org/briarproject/briar/sharing/SharingManagerImpl.java @@ -248,7 +248,7 @@ abstract class SharingManagerImpl @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 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); diff --git a/briar-core/src/test/java/org/briarproject/briar/forum/ForumManagerTest.java b/briar-core/src/test/java/org/briarproject/briar/forum/ForumManagerTest.java index c4655ce2e..65f80d282 100644 --- a/briar-core/src/test/java/org/briarproject/briar/forum/ForumManagerTest.java +++ b/briar-core/src/test/java/org/briarproject/briar/forum/ForumManagerTest.java @@ -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); diff --git a/briar-core/src/test/java/org/briarproject/briar/introduction/IntroductionIntegrationTest.java b/briar-core/src/test/java/org/briarproject/briar/introduction/IntroductionIntegrationTest.java index feb1e65ee..bbf2434ce 100644 --- a/briar-core/src/test/java/org/briarproject/briar/introduction/IntroductionIntegrationTest.java +++ b/briar-core/src/test/java/org/briarproject/briar/introduction/IntroductionIntegrationTest.java @@ -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 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); diff --git a/briar-core/src/test/java/org/briarproject/briar/privategroup/PrivateGroupIntegrationTest.java b/briar-core/src/test/java/org/briarproject/briar/privategroup/PrivateGroupIntegrationTest.java index de3ea5400..35d2253ec 100644 --- a/briar-core/src/test/java/org/briarproject/briar/privategroup/PrivateGroupIntegrationTest.java +++ b/briar-core/src/test/java/org/briarproject/briar/privategroup/PrivateGroupIntegrationTest.java @@ -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, diff --git a/briar-core/src/test/java/org/briarproject/briar/privategroup/invitation/AbstractProtocolEngineTest.java b/briar-core/src/test/java/org/briarproject/briar/privategroup/invitation/AbstractProtocolEngineTest.java index 1f2f85008..8eb16aa3c 100644 --- a/briar-core/src/test/java/org/briarproject/briar/privategroup/invitation/AbstractProtocolEngineTest.java +++ b/briar-core/src/test/java/org/briarproject/briar/privategroup/invitation/AbstractProtocolEngineTest.java @@ -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)); }}); } } diff --git a/briar-core/src/test/java/org/briarproject/briar/privategroup/invitation/CreatorProtocolEngineTest.java b/briar-core/src/test/java/org/briarproject/briar/privategroup/invitation/CreatorProtocolEngineTest.java index fde516717..6faaace02 100644 --- a/briar-core/src/test/java/org/briarproject/briar/privategroup/invitation/CreatorProtocolEngineTest.java +++ b/briar-core/src/test/java/org/briarproject/briar/privategroup/invitation/CreatorProtocolEngineTest.java @@ -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 diff --git a/briar-core/src/test/java/org/briarproject/briar/privategroup/invitation/GroupInvitationIntegrationTest.java b/briar-core/src/test/java/org/briarproject/briar/privategroup/invitation/GroupInvitationIntegrationTest.java index d2f608d75..9535b81f8 100644 --- a/briar-core/src/test/java/org/briarproject/briar/privategroup/invitation/GroupInvitationIntegrationTest.java +++ b/briar-core/src/test/java/org/briarproject/briar/privategroup/invitation/GroupInvitationIntegrationTest.java @@ -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); } } diff --git a/briar-core/src/test/java/org/briarproject/briar/privategroup/invitation/GroupInvitationManagerImplTest.java b/briar-core/src/test/java/org/briarproject/briar/privategroup/invitation/GroupInvitationManagerImplTest.java index 85df40b38..51c5c1592 100644 --- a/briar-core/src/test/java/org/briarproject/briar/privategroup/invitation/GroupInvitationManagerImplTest.java +++ b/briar-core/src/test/java/org/briarproject/briar/privategroup/invitation/GroupInvitationManagerImplTest.java @@ -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) diff --git a/briar-core/src/test/java/org/briarproject/briar/privategroup/invitation/InviteeProtocolEngineTest.java b/briar-core/src/test/java/org/briarproject/briar/privategroup/invitation/InviteeProtocolEngineTest.java index 56a984d6e..27c635d3c 100644 --- a/briar-core/src/test/java/org/briarproject/briar/privategroup/invitation/InviteeProtocolEngineTest.java +++ b/briar-core/src/test/java/org/briarproject/briar/privategroup/invitation/InviteeProtocolEngineTest.java @@ -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 diff --git a/briar-core/src/test/java/org/briarproject/briar/privategroup/invitation/PeerProtocolEngineTest.java b/briar-core/src/test/java/org/briarproject/briar/privategroup/invitation/PeerProtocolEngineTest.java index 35191e995..69383ba38 100644 --- a/briar-core/src/test/java/org/briarproject/briar/privategroup/invitation/PeerProtocolEngineTest.java +++ b/briar-core/src/test/java/org/briarproject/briar/privategroup/invitation/PeerProtocolEngineTest.java @@ -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 diff --git a/briar-core/src/test/java/org/briarproject/briar/sharing/BlogSharingIntegrationTest.java b/briar-core/src/test/java/org/briarproject/briar/sharing/BlogSharingIntegrationTest.java index 204883ba3..b2deb691c 100644 --- a/briar-core/src/test/java/org/briarproject/briar/sharing/BlogSharingIntegrationTest.java +++ b/briar-core/src/test/java/org/briarproject/briar/sharing/BlogSharingIntegrationTest.java @@ -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); diff --git a/briar-core/src/test/java/org/briarproject/briar/sharing/ForumSharingIntegrationTest.java b/briar-core/src/test/java/org/briarproject/briar/sharing/ForumSharingIntegrationTest.java index d52482b59..82efda25a 100644 --- a/briar-core/src/test/java/org/briarproject/briar/sharing/ForumSharingIntegrationTest.java +++ b/briar-core/src/test/java/org/briarproject/briar/sharing/ForumSharingIntegrationTest.java @@ -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 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 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);