From 3b6cc9c63349e6c1212c4c9355eedc02bee180e4 Mon Sep 17 00:00:00 2001 From: akwizgran Date: Thu, 19 Nov 2020 12:57:07 +0000 Subject: [PATCH 001/124] Add auto-deletion timer to private messages. --- .../api/autodelete/AutoDeleteConstants.java | 11 +++++ .../conversation/ConversationActivity.java | 19 ++++---- .../conversation/ConversationViewModel.java | 46 +++++++++++-------- .../briar/api/messaging/MessagingManager.java | 10 ++-- .../briar/api/messaging/PrivateMessage.java | 43 +++++++++++++---- .../api/messaging/PrivateMessageFactory.java | 3 ++ .../api/messaging/PrivateMessageFormat.java | 24 ++++++++++ .../api/messaging/PrivateMessageHeader.java | 10 +++- .../briar/messaging/MessagingConstants.java | 1 + .../briar/messaging/MessagingManagerImpl.java | 31 +++++++++---- .../messaging/PrivateMessageFactoryImpl.java | 33 ++++++++++--- .../messaging/PrivateMessageValidator.java | 17 ++++++- .../briar/test/TestDataCreatorImpl.java | 11 +++-- .../messaging/MessageSizeIntegrationTest.java | 5 +- .../MessagingManagerIntegrationTest.java | 3 +- .../SimplexMessagingIntegrationTest.java | 2 +- .../headless/event/WebSocketControllerTest.kt | 3 +- .../messaging/MessagingControllerImplTest.kt | 11 ++++- 18 files changed, 208 insertions(+), 75 deletions(-) create mode 100644 bramble-api/src/main/java/org/briarproject/bramble/api/autodelete/AutoDeleteConstants.java create mode 100644 briar-api/src/main/java/org/briarproject/briar/api/messaging/PrivateMessageFormat.java diff --git a/bramble-api/src/main/java/org/briarproject/bramble/api/autodelete/AutoDeleteConstants.java b/bramble-api/src/main/java/org/briarproject/bramble/api/autodelete/AutoDeleteConstants.java new file mode 100644 index 000000000..73db007ba --- /dev/null +++ b/bramble-api/src/main/java/org/briarproject/bramble/api/autodelete/AutoDeleteConstants.java @@ -0,0 +1,11 @@ +package org.briarproject.bramble.api.autodelete; + +import static java.util.concurrent.TimeUnit.DAYS; +import static java.util.concurrent.TimeUnit.MINUTES; + +public interface AutoDeleteConstants { + + long MIN_AUTO_DELETE_TIMER_MS = MINUTES.toMillis(1); + + long MAX_AUTO_DELETE_TIMER_MS = DAYS.toMillis(365); +} 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 01e0c1647..65b9f23d0 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 @@ -138,6 +138,7 @@ import static org.briarproject.briar.android.util.UiUtils.observeOnce; import static org.briarproject.briar.android.view.AuthorView.setAvatar; import static org.briarproject.briar.api.messaging.MessagingConstants.MAX_ATTACHMENTS_PER_MESSAGE; import static org.briarproject.briar.api.messaging.MessagingConstants.MAX_PRIVATE_MESSAGE_TEXT_LENGTH; +import static org.briarproject.briar.api.messaging.PrivateMessageFormat.TEXT; @MethodsNotNullByDefault @ParametersNotNullByDefault @@ -268,15 +269,11 @@ public class ConversationActivity extends BriarActivity ImagePreview imagePreview = findViewById(R.id.imagePreview); sendController = new TextAttachmentController(textInputView, imagePreview, this, viewModel); - viewModel.hasImageSupport().observe(this, new Observer() { - @Override - public void onChanged(@Nullable Boolean hasSupport) { - if (hasSupport != null && hasSupport) { - // TODO: remove cast when removing feature flag - ((TextAttachmentController) sendController) - .setImagesSupported(); - viewModel.hasImageSupport().removeObserver(this); - } + observeOnce(viewModel.getPrivateMessageFormat(), this, format -> { + if (format != null && format != TEXT) { + // TODO: remove cast when removing feature flag + ((TextAttachmentController) sendController) + .setImagesSupported(); } }); } else { @@ -640,8 +637,8 @@ public class ConversationActivity extends BriarActivity supportFinishAfterTransition(); } } else if (e instanceof ConversationMessageReceivedEvent) { - ConversationMessageReceivedEvent p = - (ConversationMessageReceivedEvent) e; + ConversationMessageReceivedEvent p = + (ConversationMessageReceivedEvent) e; if (p.getContactId().equals(contactId)) { LOG.info("Message received, adding"); onNewConversationMessage(p.getMessageHeader()); 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 2a7e23dc7..e499de6af 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 @@ -38,6 +38,7 @@ import org.briarproject.briar.api.identity.AuthorManager; import org.briarproject.briar.api.messaging.MessagingManager; import org.briarproject.briar.api.messaging.PrivateMessage; import org.briarproject.briar.api.messaging.PrivateMessageFactory; +import org.briarproject.briar.api.messaging.PrivateMessageFormat; import org.briarproject.briar.api.messaging.PrivateMessageHeader; import org.briarproject.briar.api.messaging.event.AttachmentReceivedEvent; @@ -57,11 +58,14 @@ import static androidx.lifecycle.Transformations.map; import static java.util.Objects.requireNonNull; import static java.util.logging.Level.WARNING; import static java.util.logging.Logger.getLogger; +import static org.briarproject.bramble.api.autodelete.AutoDeleteConstants.MIN_AUTO_DELETE_TIMER_MS; import static org.briarproject.bramble.util.LogUtils.logDuration; import static org.briarproject.bramble.util.LogUtils.logException; import static org.briarproject.bramble.util.LogUtils.now; import static org.briarproject.briar.android.settings.SettingsFragment.SETTINGS_NAMESPACE; import static org.briarproject.briar.android.util.UiUtils.observeForeverOnce; +import static org.briarproject.briar.api.messaging.PrivateMessageFormat.TEXT; +import static org.briarproject.briar.api.messaging.PrivateMessageFormat.TEXT_IMAGES; @NotNullByDefault public class ConversationViewModel extends DbViewModel @@ -92,7 +96,7 @@ public class ConversationViewModel extends DbViewModel private final LiveData contactName = map(contactItem, c -> UiUtils.getContactDisplayName(c.getContact())); private final LiveData messagingGroupId; - private final MutableLiveData imageSupport = + private final MutableLiveData privateMessageFormat = new MutableLiveData<>(); private final MutableLiveEvent showImageOnboarding = new MutableLiveEvent<>(); @@ -241,11 +245,11 @@ public class ConversationViewModel extends DbViewModel // messagingGroupId is loaded with the contact observeForeverOnce(messagingGroupId, groupId -> { requireNonNull(groupId); - observeForeverOnce(imageSupport, hasImageSupport -> { - requireNonNull(hasImageSupport); - createMessage(groupId, text, headers, timestamp, - hasImageSupport); - }); + // TODO: Use the timer duration that was fetched when checking the + // message format + observeForeverOnce(privateMessageFormat, format -> + createMessage(groupId, text, headers, timestamp, + format)); }); } @@ -275,10 +279,10 @@ public class ConversationViewModel extends DbViewModel @DatabaseExecutor private void checkFeaturesAndOnboarding(ContactId c) throws DbException { - // check if images are supported - boolean imagesSupported = db.transactionWithResult(true, txn -> - messagingManager.contactSupportsImages(txn, c)); - imageSupport.postValue(imagesSupported); + // check if images and auto-deletion are supported + PrivateMessageFormat format = db.transactionWithResult(true, txn -> + messagingManager.getContactMessageFormat(txn, c)); + privateMessageFormat.postValue(format); // check if introductions are supported Collection contacts = contactManager.getContacts(); @@ -287,7 +291,7 @@ public class ConversationViewModel extends DbViewModel // we only show one onboarding dialog at a time Settings settings = settingsManager.getSettings(SETTINGS_NAMESPACE); - if (imagesSupported && + if (format != TEXT && settings.getBoolean(SHOW_ONBOARDING_IMAGE, true)) { onOnboardingShown(SHOW_ONBOARDING_IMAGE); showImageOnboarding.postEvent(true); @@ -308,15 +312,20 @@ public class ConversationViewModel extends DbViewModel @UiThread private void createMessage(GroupId groupId, @Nullable String text, List headers, long timestamp, - boolean hasImageSupport) { + PrivateMessageFormat format) { + // TODO: Move this inside the DB transaction that stores the message + // so we can look up the timer duration (if needed) in the same txn try { PrivateMessage pm; - if (hasImageSupport) { + if (format == TEXT) { + pm = privateMessageFactory.createLegacyPrivateMessage( + groupId, timestamp, requireNonNull(text)); + } else if (format == TEXT_IMAGES) { pm = privateMessageFactory.createPrivateMessage(groupId, timestamp, text, headers); } else { - pm = privateMessageFactory.createLegacyPrivateMessage( - groupId, timestamp, requireNonNull(text)); + pm = privateMessageFactory.createPrivateMessage(groupId, + timestamp, text, headers, MIN_AUTO_DELETE_TIMER_MS); } storeMessage(pm); } catch (FormatException e) { @@ -336,7 +345,8 @@ public class ConversationViewModel extends DbViewModel PrivateMessageHeader h = new PrivateMessageHeader( message.getId(), message.getGroupId(), message.getTimestamp(), true, true, false, false, - m.hasText(), m.getAttachmentHeaders()); + m.hasText(), m.getAttachmentHeaders(), + m.getAutoDeleteTimer()); // TODO add text to cache when available here addedHeader.postEvent(h); } catch (DbException e) { @@ -357,8 +367,8 @@ public class ConversationViewModel extends DbViewModel return contactName; } - LiveData hasImageSupport() { - return imageSupport; + LiveData getPrivateMessageFormat() { + return privateMessageFormat; } LiveEvent showImageOnboarding() { diff --git a/briar-api/src/main/java/org/briarproject/briar/api/messaging/MessagingManager.java b/briar-api/src/main/java/org/briarproject/briar/api/messaging/MessagingManager.java index dfe18806a..1ea995c8e 100644 --- a/briar-api/src/main/java/org/briarproject/briar/api/messaging/MessagingManager.java +++ b/briar-api/src/main/java/org/briarproject/briar/api/messaging/MessagingManager.java @@ -32,7 +32,7 @@ public interface MessagingManager extends ConversationClient { /** * The current minor version of the messaging client. */ - int MINOR_VERSION = 2; + int MINOR_VERSION = 3; /** * Stores a local private message. @@ -70,12 +70,8 @@ public interface MessagingManager extends ConversationClient { String getMessageText(MessageId m) throws DbException; /** - * Returns true if the contact with the given {@link ContactId} does support - * image attachments. - *

- * Added: 2019-01-01 + * Returns the private message format supported by the given contact. */ - boolean contactSupportsImages(Transaction txn, ContactId c) + PrivateMessageFormat getContactMessageFormat(Transaction txn, ContactId c) throws DbException; - } diff --git a/briar-api/src/main/java/org/briarproject/briar/api/messaging/PrivateMessage.java b/briar-api/src/main/java/org/briarproject/briar/api/messaging/PrivateMessage.java index 188364444..b4bf1b859 100644 --- a/briar-api/src/main/java/org/briarproject/briar/api/messaging/PrivateMessage.java +++ b/briar-api/src/main/java/org/briarproject/briar/api/messaging/PrivateMessage.java @@ -9,44 +9,65 @@ import java.util.List; import javax.annotation.concurrent.Immutable; import static java.util.Collections.emptyList; +import static org.briarproject.briar.api.messaging.PrivateMessageFormat.TEXT; +import static org.briarproject.briar.api.messaging.PrivateMessageFormat.TEXT_IMAGES; +import static org.briarproject.briar.api.messaging.PrivateMessageFormat.TEXT_IMAGES_AUTO_DELETE; @Immutable @NotNullByDefault public class PrivateMessage { private final Message message; - private final boolean legacyFormat, hasText; + private final boolean hasText; private final List attachmentHeaders; + private final long autoDeleteTimer; + private final PrivateMessageFormat format; /** - * Constructor for private messages in the legacy format, which does not - * support attachments. + * Constructor for private messages in the + * {@link PrivateMessageFormat#TEXT TEXT} format. */ public PrivateMessage(Message message) { this.message = message; - legacyFormat = true; hasText = true; attachmentHeaders = emptyList(); + autoDeleteTimer = -1; + format = TEXT; } /** - * Constructor for private messages in the current format, which supports - * attachments. + * Constructor for private messages in the + * {@link PrivateMessageFormat#TEXT_IMAGES TEXT_IMAGES} format. */ public PrivateMessage(Message message, boolean hasText, List headers) { this.message = message; this.hasText = hasText; this.attachmentHeaders = headers; - legacyFormat = false; + autoDeleteTimer = -1; + format = TEXT_IMAGES; + } + + /** + * Constructor for private messages in the + * {@link PrivateMessageFormat#TEXT_IMAGES_AUTO_DELETE TEXT_IMAGES_AUTO_DELETE} + * format. + */ + public PrivateMessage(Message message, boolean hasText, + List headers, long autoDeleteTimer) { + this.message = message; + this.hasText = hasText; + this.attachmentHeaders = headers; + this.autoDeleteTimer = autoDeleteTimer; + format = TEXT_IMAGES_AUTO_DELETE; } public Message getMessage() { return message; } - public boolean isLegacyFormat() { - return legacyFormat; + public PrivateMessageFormat getFormat() { + return format; } public boolean hasText() { @@ -56,4 +77,8 @@ public class PrivateMessage { public List getAttachmentHeaders() { return attachmentHeaders; } + + public long getAutoDeleteTimer() { + return autoDeleteTimer; + } } diff --git a/briar-api/src/main/java/org/briarproject/briar/api/messaging/PrivateMessageFactory.java b/briar-api/src/main/java/org/briarproject/briar/api/messaging/PrivateMessageFactory.java index da4532015..90c43ccc5 100644 --- a/briar-api/src/main/java/org/briarproject/briar/api/messaging/PrivateMessageFactory.java +++ b/briar-api/src/main/java/org/briarproject/briar/api/messaging/PrivateMessageFactory.java @@ -19,4 +19,7 @@ public interface PrivateMessageFactory { @Nullable String text, List headers) throws FormatException; + PrivateMessage createPrivateMessage(GroupId groupId, long timestamp, + @Nullable String text, List headers, + long autoDeleteTimer) throws FormatException; } diff --git a/briar-api/src/main/java/org/briarproject/briar/api/messaging/PrivateMessageFormat.java b/briar-api/src/main/java/org/briarproject/briar/api/messaging/PrivateMessageFormat.java new file mode 100644 index 000000000..6982e0b31 --- /dev/null +++ b/briar-api/src/main/java/org/briarproject/briar/api/messaging/PrivateMessageFormat.java @@ -0,0 +1,24 @@ +package org.briarproject.briar.api.messaging; + +public enum PrivateMessageFormat { + + /** + * First version of the private message format, which doesn't support + * image attachments or auto-deletion. + */ + TEXT, + + /** + * Second version of the private message format, which supports image + * attachments but not auto-deletion. Support for this format was + * added in client version 0.1. + */ + TEXT_IMAGES, + + /** + * Third version of the private message format, which supports image + * attachments and auto-deletion. Support for this format was added + * in client version 0.3. + */ + TEXT_IMAGES_AUTO_DELETE +} diff --git a/briar-api/src/main/java/org/briarproject/briar/api/messaging/PrivateMessageHeader.java b/briar-api/src/main/java/org/briarproject/briar/api/messaging/PrivateMessageHeader.java index 9e17af615..369401982 100644 --- a/briar-api/src/main/java/org/briarproject/briar/api/messaging/PrivateMessageHeader.java +++ b/briar-api/src/main/java/org/briarproject/briar/api/messaging/PrivateMessageHeader.java @@ -17,13 +17,16 @@ public class PrivateMessageHeader extends ConversationMessageHeader { private final boolean hasText; private final List attachmentHeaders; + private final long autoDeleteTimer; public PrivateMessageHeader(MessageId id, GroupId groupId, long timestamp, boolean local, boolean read, boolean sent, boolean seen, - boolean hasText, List headers) { + boolean hasText, List headers, + long autoDeleteTimer) { super(id, groupId, timestamp, local, read, sent, seen); this.hasText = hasText; this.attachmentHeaders = headers; + this.autoDeleteTimer = autoDeleteTimer; } public boolean hasText() { @@ -34,9 +37,12 @@ public class PrivateMessageHeader extends ConversationMessageHeader { return attachmentHeaders; } + public long getAutoDeleteTimer() { + return autoDeleteTimer; + } + @Override public T accept(ConversationMessageVisitor v) { return v.visitPrivateMessageHeader(this); } - } diff --git a/briar-core/src/main/java/org/briarproject/briar/messaging/MessagingConstants.java b/briar-core/src/main/java/org/briarproject/briar/messaging/MessagingConstants.java index a280ba46a..d62fe2b4a 100644 --- a/briar-core/src/main/java/org/briarproject/briar/messaging/MessagingConstants.java +++ b/briar-core/src/main/java/org/briarproject/briar/messaging/MessagingConstants.java @@ -11,4 +11,5 @@ interface MessagingConstants { String MSG_KEY_MSG_TYPE = "messageType"; String MSG_KEY_HAS_TEXT = "hasText"; String MSG_KEY_ATTACHMENT_HEADERS = "attachmentHeaders"; + String MSG_KEY_AUTO_DELETE_TIMER = "autoDeleteTimer"; } diff --git a/briar-core/src/main/java/org/briarproject/briar/messaging/MessagingManagerImpl.java b/briar-core/src/main/java/org/briarproject/briar/messaging/MessagingManagerImpl.java index 0688ee14d..c70ff8196 100644 --- a/briar-core/src/main/java/org/briarproject/briar/messaging/MessagingManagerImpl.java +++ b/briar-core/src/main/java/org/briarproject/briar/messaging/MessagingManagerImpl.java @@ -36,6 +36,7 @@ import org.briarproject.briar.api.conversation.ConversationMessageHeader; import org.briarproject.briar.api.conversation.DeletionResult; import org.briarproject.briar.api.messaging.MessagingManager; import org.briarproject.briar.api.messaging.PrivateMessage; +import org.briarproject.briar.api.messaging.PrivateMessageFormat; import org.briarproject.briar.api.messaging.PrivateMessageHeader; import org.briarproject.briar.api.messaging.event.AttachmentReceivedEvent; import org.briarproject.briar.api.messaging.event.PrivateMessageReceivedEvent; @@ -59,11 +60,15 @@ import static org.briarproject.bramble.api.sync.validation.MessageState.DELIVERE import static org.briarproject.bramble.util.IoUtils.copyAndClose; import static org.briarproject.briar.api.attachment.MediaConstants.MSG_KEY_CONTENT_TYPE; import static org.briarproject.briar.api.attachment.MediaConstants.MSG_KEY_DESCRIPTOR_LENGTH; +import static org.briarproject.briar.api.messaging.PrivateMessageFormat.TEXT; +import static org.briarproject.briar.api.messaging.PrivateMessageFormat.TEXT_IMAGES; +import static org.briarproject.briar.api.messaging.PrivateMessageFormat.TEXT_IMAGES_AUTO_DELETE; import static org.briarproject.briar.client.MessageTrackerConstants.MSG_KEY_READ; import static org.briarproject.briar.messaging.MessageTypes.ATTACHMENT; import static org.briarproject.briar.messaging.MessageTypes.PRIVATE_MESSAGE; import static org.briarproject.briar.messaging.MessagingConstants.GROUP_KEY_CONTACT_ID; import static org.briarproject.briar.messaging.MessagingConstants.MSG_KEY_ATTACHMENT_HEADERS; +import static org.briarproject.briar.messaging.MessagingConstants.MSG_KEY_AUTO_DELETE_TIMER; import static org.briarproject.briar.messaging.MessagingConstants.MSG_KEY_HAS_TEXT; import static org.briarproject.briar.messaging.MessagingConstants.MSG_KEY_LOCAL; import static org.briarproject.briar.messaging.MessagingConstants.MSG_KEY_MSG_TYPE; @@ -193,9 +198,10 @@ class MessagingManagerImpl implements MessagingManager, IncomingMessageHook, long timestamp = meta.getLong(MSG_KEY_TIMESTAMP); boolean local = meta.getBoolean(MSG_KEY_LOCAL); boolean read = meta.getBoolean(MSG_KEY_READ); + long timer = meta.getLong(MSG_KEY_AUTO_DELETE_TIMER, -1L); PrivateMessageHeader header = new PrivateMessageHeader(m.getId(), groupId, timestamp, local, - read, false, false, hasText, headers); + read, false, false, hasText, headers, timer); ContactId contactId = getContactId(txn, groupId); PrivateMessageReceivedEvent event = new PrivateMessageReceivedEvent(header, contactId); @@ -204,8 +210,7 @@ class MessagingManagerImpl implements MessagingManager, IncomingMessageHook, } private List parseAttachmentHeaders(GroupId g, - BdfDictionary meta) - throws FormatException { + BdfDictionary meta) throws FormatException { BdfList attachmentHeaders = meta.getList(MSG_KEY_ATTACHMENT_HEADERS); int length = attachmentHeaders.size(); List headers = new ArrayList<>(length); @@ -232,7 +237,7 @@ class MessagingManagerImpl implements MessagingManager, IncomingMessageHook, meta.put(MSG_KEY_TIMESTAMP, m.getMessage().getTimestamp()); meta.put(MSG_KEY_LOCAL, true); meta.put(MSG_KEY_READ, true); - if (!m.isLegacyFormat()) { + if (m.getFormat() != TEXT) { meta.put(MSG_KEY_MSG_TYPE, PRIVATE_MESSAGE); meta.put(MSG_KEY_HAS_TEXT, m.hasText()); BdfList headers = new BdfList(); @@ -241,6 +246,10 @@ class MessagingManagerImpl implements MessagingManager, IncomingMessageHook, BdfList.of(a.getMessageId(), a.getContentType())); } meta.put(MSG_KEY_ATTACHMENT_HEADERS, headers); + if (m.getFormat() == TEXT_IMAGES_AUTO_DELETE) { + long timer = m.getAutoDeleteTimer(); + if (timer != -1) meta.put(MSG_KEY_AUTO_DELETE_TIMER, timer); + } } // Mark attachments as shared and permanent now we're ready to send for (AttachmentHeader a : m.getAttachmentHeaders()) { @@ -353,12 +362,13 @@ class MessagingManagerImpl implements MessagingManager, IncomingMessageHook, if (messageType == null) { headers.add(new PrivateMessageHeader(id, g, timestamp, local, read, s.isSent(), s.isSeen(), true, - emptyList())); + emptyList(), -1)); } else { boolean hasText = meta.getBoolean(MSG_KEY_HAS_TEXT); + long timer = meta.getLong(MSG_KEY_AUTO_DELETE_TIMER, -1L); headers.add(new PrivateMessageHeader(id, g, timestamp, local, read, s.isSent(), s.isSeen(), hasText, - parseAttachmentHeaders(g, meta))); + parseAttachmentHeaders(g, meta), timer)); } } catch (FormatException e) { throw new DbException(e); @@ -399,12 +409,13 @@ class MessagingManagerImpl implements MessagingManager, IncomingMessageHook, } @Override - public boolean contactSupportsImages(Transaction txn, ContactId c) - throws DbException { + public PrivateMessageFormat getContactMessageFormat(Transaction txn, + ContactId c) throws DbException { int minorVersion = clientVersioningManager .getClientMinorVersion(txn, c, CLIENT_ID, 0); - // support was added in 0.1 - return minorVersion > 0; + if (minorVersion >= 3) return TEXT_IMAGES_AUTO_DELETE; + else if (minorVersion >= 1) return TEXT_IMAGES; + else return TEXT; } @Override diff --git a/briar-core/src/main/java/org/briarproject/briar/messaging/PrivateMessageFactoryImpl.java b/briar-core/src/main/java/org/briarproject/briar/messaging/PrivateMessageFactoryImpl.java index c4b7f54f7..bf70b109b 100644 --- a/briar-core/src/main/java/org/briarproject/briar/messaging/PrivateMessageFactoryImpl.java +++ b/briar-core/src/main/java/org/briarproject/briar/messaging/PrivateMessageFactoryImpl.java @@ -47,21 +47,42 @@ class PrivateMessageFactoryImpl implements PrivateMessageFactory { public PrivateMessage createPrivateMessage(GroupId groupId, long timestamp, @Nullable String text, List headers) throws FormatException { - // Validate the arguments + validateTextAndAttachmentHeaders(text, headers); + BdfList attachmentList = serialiseAttachmentHeaders(headers); + // Serialise the message + BdfList body = BdfList.of(PRIVATE_MESSAGE, text, attachmentList); + Message m = clientHelper.createMessage(groupId, timestamp, body); + return new PrivateMessage(m, text != null, headers, -1); + } + + @Override + public PrivateMessage createPrivateMessage(GroupId groupId, long timestamp, + @Nullable String text, List headers, + long autoDeleteTimer) throws FormatException { + validateTextAndAttachmentHeaders(text, headers); + BdfList attachmentList = serialiseAttachmentHeaders(headers); + // Serialise the message + Long timer = autoDeleteTimer == -1 ? null : autoDeleteTimer; + BdfList body = BdfList.of(PRIVATE_MESSAGE, text, attachmentList, timer); + Message m = clientHelper.createMessage(groupId, timestamp, body); + return new PrivateMessage(m, text != null, headers, autoDeleteTimer); + } + + private void validateTextAndAttachmentHeaders(@Nullable String text, + List headers) { if (text == null) { if (headers.isEmpty()) throw new IllegalArgumentException(); } else if (utf8IsTooLong(text, MAX_PRIVATE_MESSAGE_TEXT_LENGTH)) { throw new IllegalArgumentException(); } - // Serialise the attachment headers + } + + private BdfList serialiseAttachmentHeaders(List headers) { BdfList attachmentList = new BdfList(); for (AttachmentHeader a : headers) { attachmentList.add( BdfList.of(a.getMessageId(), a.getContentType())); } - // Serialise the message - BdfList body = BdfList.of(PRIVATE_MESSAGE, text, attachmentList); - Message m = clientHelper.createMessage(groupId, timestamp, body); - return new PrivateMessage(m, text != null, headers); + return attachmentList; } } diff --git a/briar-core/src/main/java/org/briarproject/briar/messaging/PrivateMessageValidator.java b/briar-core/src/main/java/org/briarproject/briar/messaging/PrivateMessageValidator.java index 8a1541277..310692ae0 100644 --- a/briar-core/src/main/java/org/briarproject/briar/messaging/PrivateMessageValidator.java +++ b/briar-core/src/main/java/org/briarproject/briar/messaging/PrivateMessageValidator.java @@ -24,6 +24,8 @@ import java.io.InputStream; import javax.annotation.concurrent.Immutable; +import static org.briarproject.bramble.api.autodelete.AutoDeleteConstants.MAX_AUTO_DELETE_TIMER_MS; +import static org.briarproject.bramble.api.autodelete.AutoDeleteConstants.MIN_AUTO_DELETE_TIMER_MS; import static org.briarproject.bramble.api.sync.SyncConstants.MAX_MESSAGE_BODY_LENGTH; import static org.briarproject.bramble.api.transport.TransportConstants.MAX_CLOCK_DIFFERENCE; import static org.briarproject.bramble.util.ValidationUtils.checkLength; @@ -37,6 +39,7 @@ import static org.briarproject.briar.client.MessageTrackerConstants.MSG_KEY_READ import static org.briarproject.briar.messaging.MessageTypes.ATTACHMENT; import static org.briarproject.briar.messaging.MessageTypes.PRIVATE_MESSAGE; import static org.briarproject.briar.messaging.MessagingConstants.MSG_KEY_ATTACHMENT_HEADERS; +import static org.briarproject.briar.messaging.MessagingConstants.MSG_KEY_AUTO_DELETE_TIMER; import static org.briarproject.briar.messaging.MessagingConstants.MSG_KEY_HAS_TEXT; import static org.briarproject.briar.messaging.MessagingConstants.MSG_KEY_LOCAL; import static org.briarproject.briar.messaging.MessagingConstants.MSG_KEY_MSG_TYPE; @@ -114,8 +117,11 @@ class PrivateMessageValidator implements MessageValidator { private BdfMessageContext validatePrivateMessage(Message m, BdfList body) throws FormatException { - // Message type, optional private message text, attachment headers - checkSize(body, 3); + // Version 0.1: Message type, optional private message text, + // attachment headers. + // Version 0.2: Message type, optional private message text, + // attachment headers, optional auto-delete timer. + checkSize(body, 3, 4); String text = body.getOptionalString(1); checkLength(text, 0, MAX_PRIVATE_MESSAGE_INCOMING_TEXT_LENGTH); BdfList headers = body.getList(2); @@ -130,6 +136,12 @@ class PrivateMessageValidator implements MessageValidator { String contentType = header.getString(1); checkLength(contentType, 1, MAX_CONTENT_TYPE_BYTES); } + Long timer = null; + if (body.size() == 4) timer = body.getOptionalLong(3); + if (timer != null && (timer < MIN_AUTO_DELETE_TIMER_MS || + timer > MAX_AUTO_DELETE_TIMER_MS)) { + throw new FormatException(); + } // Return the metadata BdfDictionary meta = new BdfDictionary(); meta.put(MSG_KEY_TIMESTAMP, m.getTimestamp()); @@ -138,6 +150,7 @@ class PrivateMessageValidator implements MessageValidator { meta.put(MSG_KEY_MSG_TYPE, PRIVATE_MESSAGE); meta.put(MSG_KEY_HAS_TEXT, text != null); meta.put(MSG_KEY_ATTACHMENT_HEADERS, headers); + if (timer != null) meta.put(MSG_KEY_AUTO_DELETE_TIMER, timer); return new BdfMessageContext(meta); } diff --git a/briar-core/src/main/java/org/briarproject/briar/test/TestDataCreatorImpl.java b/briar-core/src/main/java/org/briarproject/briar/test/TestDataCreatorImpl.java index 987e4cc28..a10fd6382 100644 --- a/briar-core/src/main/java/org/briarproject/briar/test/TestDataCreatorImpl.java +++ b/briar-core/src/main/java/org/briarproject/briar/test/TestDataCreatorImpl.java @@ -58,6 +58,7 @@ import static java.util.Collections.emptyList; import static java.util.logging.Level.INFO; import static java.util.logging.Level.WARNING; import static java.util.logging.Logger.getLogger; +import static org.briarproject.bramble.api.autodelete.AutoDeleteConstants.MIN_AUTO_DELETE_TIMER_MS; import static org.briarproject.bramble.api.plugin.BluetoothConstants.UUID_BYTES; import static org.briarproject.bramble.api.sync.Group.Visibility.SHARED; import static org.briarproject.bramble.util.LogUtils.logException; @@ -352,14 +353,18 @@ public class TestDataCreatorImpl implements TestDataCreator { long timestamp = clock.currentTimeMillis() - num * 60 * 1000; String text = getRandomText(); boolean local = random.nextBoolean(); - createPrivateMessage(contactId, groupId, text, timestamp, local); + boolean autoDelete = random.nextBoolean(); + createPrivateMessage(contactId, groupId, text, timestamp, local, + autoDelete); } private void createPrivateMessage(ContactId contactId, GroupId groupId, - String text, long timestamp, boolean local) throws DbException { + String text, long timestamp, boolean local, boolean autoDelete) + throws DbException { + long timer = autoDelete ? MIN_AUTO_DELETE_TIMER_MS : -1; try { PrivateMessage m = privateMessageFactory.createPrivateMessage( - groupId, timestamp, text, emptyList()); + groupId, timestamp, text, emptyList(), timer); if (local) { messagingManager.addLocalMessage(m); } else { diff --git a/briar-core/src/test/java/org/briarproject/briar/messaging/MessageSizeIntegrationTest.java b/briar-core/src/test/java/org/briarproject/briar/messaging/MessageSizeIntegrationTest.java index 07c52a621..72bbf2c52 100644 --- a/briar-core/src/test/java/org/briarproject/briar/messaging/MessageSizeIntegrationTest.java +++ b/briar-core/src/test/java/org/briarproject/briar/messaging/MessageSizeIntegrationTest.java @@ -25,6 +25,7 @@ import java.util.List; import javax.inject.Inject; +import static org.briarproject.bramble.api.autodelete.AutoDeleteConstants.MAX_AUTO_DELETE_TIMER_MS; import static org.briarproject.bramble.api.identity.AuthorConstants.MAX_AUTHOR_NAME_LENGTH; import static org.briarproject.bramble.api.identity.AuthorConstants.MAX_PUBLIC_KEY_LENGTH; import static org.briarproject.bramble.api.record.Record.MAX_RECORD_PAYLOAD_BYTES; @@ -92,12 +93,12 @@ public class MessageSizeIntegrationTest extends BriarTestCase { getRandomString(MAX_CONTENT_TYPE_BYTES))); } PrivateMessage message = privateMessageFactory.createPrivateMessage( - groupId, timestamp, text, headers); + groupId, timestamp, text, headers, MAX_AUTO_DELETE_TIMER_MS); // Check the size of the serialised message int length = message.getMessage().getRawLength(); assertTrue(length > UniqueId.LENGTH + 8 + MAX_PRIVATE_MESSAGE_TEXT_LENGTH + MAX_ATTACHMENTS_PER_MESSAGE - * (UniqueId.LENGTH + MAX_CONTENT_TYPE_BYTES)); + * (UniqueId.LENGTH + MAX_CONTENT_TYPE_BYTES) + 4); assertTrue(length <= MAX_RECORD_PAYLOAD_BYTES); } diff --git a/briar-core/src/test/java/org/briarproject/briar/messaging/MessagingManagerIntegrationTest.java b/briar-core/src/test/java/org/briarproject/briar/messaging/MessagingManagerIntegrationTest.java index 30c0e1d8f..405381299 100644 --- a/briar-core/src/test/java/org/briarproject/briar/messaging/MessagingManagerIntegrationTest.java +++ b/briar-core/src/test/java/org/briarproject/briar/messaging/MessagingManagerIntegrationTest.java @@ -340,8 +340,9 @@ public class MessagingManagerIntegrationTest BriarIntegrationTestComponent to, @Nullable String text, List attachments) throws Exception { GroupId g = from.getMessagingManager().getConversationId(contactId); + // TODO: Add tests for auto-deletion timer PrivateMessage m = messageFactory.createPrivateMessage(g, - clock.currentTimeMillis(), text, attachments); + clock.currentTimeMillis(), text, attachments, -1); from.getMessagingManager().addLocalMessage(m); syncMessage(from, to, contactId, 1 + attachments.size(), true); return m; diff --git a/briar-core/src/test/java/org/briarproject/briar/messaging/SimplexMessagingIntegrationTest.java b/briar-core/src/test/java/org/briarproject/briar/messaging/SimplexMessagingIntegrationTest.java index 88f1530a3..3c8ee93c9 100644 --- a/briar-core/src/test/java/org/briarproject/briar/messaging/SimplexMessagingIntegrationTest.java +++ b/briar-core/src/test/java/org/briarproject/briar/messaging/SimplexMessagingIntegrationTest.java @@ -123,7 +123,7 @@ public class SimplexMessagingIntegrationTest extends BriarTestCase { PrivateMessageFactory privateMessageFactory = device.getPrivateMessageFactory(); PrivateMessage message = privateMessageFactory.createPrivateMessage( - groupId, timestamp, "Hi!", singletonList(attachmentHeader)); + groupId, timestamp, "Hi!", singletonList(attachmentHeader), -1); messagingManager.addLocalMessage(message); } diff --git a/briar-headless/src/test/java/org/briarproject/briar/headless/event/WebSocketControllerTest.kt b/briar-headless/src/test/java/org/briarproject/briar/headless/event/WebSocketControllerTest.kt index 221b95001..c9634d192 100644 --- a/briar-headless/src/test/java/org/briarproject/briar/headless/event/WebSocketControllerTest.kt +++ b/briar-headless/src/test/java/org/briarproject/briar/headless/event/WebSocketControllerTest.kt @@ -41,7 +41,8 @@ internal class WebSocketControllerTest : ControllerTest() { true, true, true, - emptyList() + emptyList(), + -1 ) private val event = PrivateMessageReceivedEvent(header, contact.id) private val outputEvent = OutputEvent(EVENT_CONVERSATION_MESSAGE, event.output(text)) diff --git a/briar-headless/src/test/java/org/briarproject/briar/headless/messaging/MessagingControllerImplTest.kt b/briar-headless/src/test/java/org/briarproject/briar/headless/messaging/MessagingControllerImplTest.kt index a3a9d49c4..8e20f9b1f 100644 --- a/briar-headless/src/test/java/org/briarproject/briar/headless/messaging/MessagingControllerImplTest.kt +++ b/briar-headless/src/test/java/org/briarproject/briar/headless/messaging/MessagingControllerImplTest.kt @@ -4,7 +4,13 @@ import io.javalin.http.BadRequestResponse import io.javalin.http.Context import io.javalin.http.NotFoundResponse import io.javalin.plugin.json.JavalinJson.toJson -import io.mockk.* +import io.mockk.CapturingSlot +import io.mockk.Runs +import io.mockk.every +import io.mockk.just +import io.mockk.mockk +import io.mockk.mockkStatic +import io.mockk.runs import org.briarproject.bramble.api.contact.ContactId import org.briarproject.bramble.api.db.NoSuchContactException import org.briarproject.briar.api.identity.AuthorInfo @@ -62,7 +68,8 @@ internal class MessagingControllerImplTest : ControllerTest() { true, true, true, - emptyList() + emptyList(), + -1 ) private val sessionId = SessionId(getRandomId()) private val privateMessage = PrivateMessage(message) From 9608b974ec6fec2aaf9ada789f94b8418e28e476 Mon Sep 17 00:00:00 2001 From: akwizgran Date: Thu, 19 Nov 2020 13:12:02 +0000 Subject: [PATCH 002/124] Add integration test for auto-delete timer in private messages. --- .../conversation/ConversationViewModel.java | 11 ++-- .../MessagingManagerIntegrationTest.java | 53 ++++++++++++++++--- 2 files changed, 50 insertions(+), 14 deletions(-) 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 e499de6af..ecc05e956 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 @@ -58,7 +58,6 @@ import static androidx.lifecycle.Transformations.map; import static java.util.Objects.requireNonNull; import static java.util.logging.Level.WARNING; import static java.util.logging.Logger.getLogger; -import static org.briarproject.bramble.api.autodelete.AutoDeleteConstants.MIN_AUTO_DELETE_TIMER_MS; import static org.briarproject.bramble.util.LogUtils.logDuration; import static org.briarproject.bramble.util.LogUtils.logException; import static org.briarproject.bramble.util.LogUtils.now; @@ -245,11 +244,8 @@ public class ConversationViewModel extends DbViewModel // messagingGroupId is loaded with the contact observeForeverOnce(messagingGroupId, groupId -> { requireNonNull(groupId); - // TODO: Use the timer duration that was fetched when checking the - // message format observeForeverOnce(privateMessageFormat, format -> - createMessage(groupId, text, headers, timestamp, - format)); + createMessage(groupId, text, headers, timestamp, format)); }); } @@ -313,8 +309,6 @@ public class ConversationViewModel extends DbViewModel private void createMessage(GroupId groupId, @Nullable String text, List headers, long timestamp, PrivateMessageFormat format) { - // TODO: Move this inside the DB transaction that stores the message - // so we can look up the timer duration (if needed) in the same txn try { PrivateMessage pm; if (format == TEXT) { @@ -324,8 +318,9 @@ public class ConversationViewModel extends DbViewModel pm = privateMessageFactory.createPrivateMessage(groupId, timestamp, text, headers); } else { + // TODO: Look up auto-delete timer pm = privateMessageFactory.createPrivateMessage(groupId, - timestamp, text, headers, MIN_AUTO_DELETE_TIMER_MS); + timestamp, text, headers, -1); } storeMessage(pm); } catch (FormatException e) { diff --git a/briar-core/src/test/java/org/briarproject/briar/messaging/MessagingManagerIntegrationTest.java b/briar-core/src/test/java/org/briarproject/briar/messaging/MessagingManagerIntegrationTest.java index 405381299..5e97cbd17 100644 --- a/briar-core/src/test/java/org/briarproject/briar/messaging/MessagingManagerIntegrationTest.java +++ b/briar-core/src/test/java/org/briarproject/briar/messaging/MessagingManagerIntegrationTest.java @@ -32,6 +32,7 @@ import static java.util.Collections.emptyList; import static java.util.Collections.emptySet; import static java.util.Collections.singleton; import static java.util.Collections.singletonList; +import static org.briarproject.bramble.api.autodelete.AutoDeleteConstants.MIN_AUTO_DELETE_TIMER_MS; import static org.briarproject.bramble.api.sync.validation.MessageState.DELIVERED; import static org.briarproject.bramble.api.sync.validation.MessageState.PENDING; import static org.briarproject.bramble.test.TestUtils.getRandomBytes; @@ -89,7 +90,7 @@ public class MessagingManagerIntegrationTest @Test public void testSimpleConversation() throws Exception { - // conversation start out empty + // conversation starts out empty Collection messages0 = getMessages(c0); Collection messages1 = getMessages(c1); assertEquals(0, messages0.size()); @@ -108,6 +109,10 @@ public class MessagingManagerIntegrationTest (PrivateMessageHeader) messages1.iterator().next(); assertTrue(m0.hasText()); assertTrue(m1.hasText()); + assertEquals(0, m0.getAttachmentHeaders().size()); + assertEquals(0, m1.getAttachmentHeaders().size()); + assertEquals(-1, m0.getAutoDeleteTimer()); + assertEquals(-1, m1.getAutoDeleteTimer()); assertTrue(m0.isRead()); assertFalse(m1.isRead()); assertGroupCounts(c0, 1, 0); @@ -143,13 +148,44 @@ public class MessagingManagerIntegrationTest assertFalse(m1.hasText()); assertEquals(1, m0.getAttachmentHeaders().size()); assertEquals(1, m1.getAttachmentHeaders().size()); + assertEquals(-1, m0.getAutoDeleteTimer()); + assertEquals(-1, m1.getAutoDeleteTimer()); + assertTrue(m0.isRead()); + assertFalse(m1.isRead()); + assertGroupCounts(c0, 1, 0); + assertGroupCounts(c1, 1, 1); + } + + @Test + public void testAutoDeleteTimer() throws Exception { + // send message with auto-delete timer + sendMessage(c0, c1, getRandomString(123), emptyList(), + MIN_AUTO_DELETE_TIMER_MS); + + // message with timer is sent/displayed properly + Collection messages0 = getMessages(c0); + Collection messages1 = getMessages(c1); + assertEquals(1, messages0.size()); + assertEquals(1, messages1.size()); + PrivateMessageHeader m0 = + (PrivateMessageHeader) messages0.iterator().next(); + PrivateMessageHeader m1 = + (PrivateMessageHeader) messages1.iterator().next(); + assertTrue(m0.hasText()); + assertTrue(m1.hasText()); + assertEquals(0, m0.getAttachmentHeaders().size()); + assertEquals(0, m1.getAttachmentHeaders().size()); + assertEquals(MIN_AUTO_DELETE_TIMER_MS, m0.getAutoDeleteTimer()); + assertEquals(MIN_AUTO_DELETE_TIMER_MS, m1.getAutoDeleteTimer()); + assertTrue(m0.isRead()); + assertFalse(m1.isRead()); assertGroupCounts(c0, 1, 0); assertGroupCounts(c1, 1, 1); } @Test public void testDeleteAll() throws Exception { - // send 3 message (1 with attachment) + // send 3 messages (1 with attachment) sendMessage(c0, c1, getRandomString(42)); sendMessage(c0, c1, getRandomString(23)); sendMessage(c0, c1, null, singletonList(addAttachment(c0))); @@ -331,18 +367,23 @@ public class MessagingManagerIntegrationTest } private PrivateMessage sendMessage(BriarIntegrationTestComponent from, - BriarIntegrationTestComponent to, String text) - throws Exception { + BriarIntegrationTestComponent to, String text) throws Exception { return sendMessage(from, to, text, emptyList()); } private PrivateMessage sendMessage(BriarIntegrationTestComponent from, BriarIntegrationTestComponent to, @Nullable String text, List attachments) throws Exception { + return sendMessage(from, to, text, attachments, -1); + } + + private PrivateMessage sendMessage(BriarIntegrationTestComponent from, + BriarIntegrationTestComponent to, @Nullable String text, + List attachments, long autoDeleteTimer) + throws Exception { GroupId g = from.getMessagingManager().getConversationId(contactId); - // TODO: Add tests for auto-deletion timer PrivateMessage m = messageFactory.createPrivateMessage(g, - clock.currentTimeMillis(), text, attachments, -1); + clock.currentTimeMillis(), text, attachments, autoDeleteTimer); from.getMessagingManager().addLocalMessage(m); syncMessage(from, to, contactId, 1 + attachments.size(), true); return m; From f10e3d756a381b809d54b4e049d10b6b388b20a2 Mon Sep 17 00:00:00 2001 From: akwizgran Date: Thu, 19 Nov 2020 13:29:57 +0000 Subject: [PATCH 003/124] Fix comments in PrivateMessageValidator. --- .../briar/messaging/PrivateMessageValidator.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/briar-core/src/main/java/org/briarproject/briar/messaging/PrivateMessageValidator.java b/briar-core/src/main/java/org/briarproject/briar/messaging/PrivateMessageValidator.java index 310692ae0..408752b88 100644 --- a/briar-core/src/main/java/org/briarproject/briar/messaging/PrivateMessageValidator.java +++ b/briar-core/src/main/java/org/briarproject/briar/messaging/PrivateMessageValidator.java @@ -103,7 +103,7 @@ class PrivateMessageValidator implements MessageValidator { private BdfMessageContext validateLegacyPrivateMessage(Message m, BdfList body) throws FormatException { - // Private message text + // Client version 0.0: Private message text checkSize(body, 1); String text = body.getString(0); checkLength(text, 0, MAX_PRIVATE_MESSAGE_INCOMING_TEXT_LENGTH); @@ -117,9 +117,9 @@ class PrivateMessageValidator implements MessageValidator { private BdfMessageContext validatePrivateMessage(Message m, BdfList body) throws FormatException { - // Version 0.1: Message type, optional private message text, - // attachment headers. - // Version 0.2: Message type, optional private message text, + // Client version 0.1 to 0.2: Message type, optional private message + // text, attachment headers. + // Client version 0.3: Message type, optional private message text, // attachment headers, optional auto-delete timer. checkSize(body, 3, 4); String text = body.getOptionalString(1); From b10ca5b77fd3e302d6cc902e45563018f68fe0a2 Mon Sep 17 00:00:00 2001 From: akwizgran Date: Thu, 19 Nov 2020 13:40:51 +0000 Subject: [PATCH 004/124] Add unit tests for private message validation. --- .../PrivateMessageValidatorTest.java | 45 +++++++++++++++++++ 1 file changed, 45 insertions(+) diff --git a/briar-core/src/test/java/org/briarproject/briar/messaging/PrivateMessageValidatorTest.java b/briar-core/src/test/java/org/briarproject/briar/messaging/PrivateMessageValidatorTest.java index cc42c0c87..114c58eeb 100644 --- a/briar-core/src/test/java/org/briarproject/briar/messaging/PrivateMessageValidatorTest.java +++ b/briar-core/src/test/java/org/briarproject/briar/messaging/PrivateMessageValidatorTest.java @@ -20,6 +20,8 @@ import org.junit.Test; import java.io.InputStream; +import static org.briarproject.bramble.api.autodelete.AutoDeleteConstants.MAX_AUTO_DELETE_TIMER_MS; +import static org.briarproject.bramble.api.autodelete.AutoDeleteConstants.MIN_AUTO_DELETE_TIMER_MS; import static org.briarproject.bramble.api.transport.TransportConstants.MAX_CLOCK_DIFFERENCE; import static org.briarproject.bramble.test.TestUtils.getClientId; import static org.briarproject.bramble.test.TestUtils.getGroup; @@ -36,6 +38,7 @@ import static org.briarproject.briar.client.MessageTrackerConstants.MSG_KEY_READ import static org.briarproject.briar.messaging.MessageTypes.ATTACHMENT; import static org.briarproject.briar.messaging.MessageTypes.PRIVATE_MESSAGE; import static org.briarproject.briar.messaging.MessagingConstants.MSG_KEY_ATTACHMENT_HEADERS; +import static org.briarproject.briar.messaging.MessagingConstants.MSG_KEY_AUTO_DELETE_TIMER; import static org.briarproject.briar.messaging.MessagingConstants.MSG_KEY_HAS_TEXT; import static org.briarproject.briar.messaging.MessagingConstants.MSG_KEY_LOCAL; import static org.briarproject.briar.messaging.MessagingConstants.MSG_KEY_MSG_TYPE; @@ -391,6 +394,48 @@ public class PrivateMessageValidatorTest extends BrambleMockTestCase { validator.validateMessage(message, group); } + @Test + public void testAcceptsNullTimerForPrivateMessage() throws Exception { + testAcceptsPrivateMessage(BdfList.of(PRIVATE_MESSAGE, text, + new BdfList(), null), noAttachmentsMeta); + } + + @Test(expected = InvalidMessageException.class) + public void testRejectsNonLongTimerForPrivateMessage() throws Exception { + testRejectsPrivateMessage(BdfList.of(PRIVATE_MESSAGE, text, + new BdfList(), "foo")); + } + + @Test(expected = InvalidMessageException.class) + public void testRejectsTooSmallTimerForPrivateMessage() throws Exception { + testRejectsPrivateMessage(BdfList.of(PRIVATE_MESSAGE, text, + new BdfList(), MIN_AUTO_DELETE_TIMER_MS - 1)); + } + + @Test(expected = InvalidMessageException.class) + public void testRejectsTooBigTimerForPrivateMessage() throws Exception { + testRejectsPrivateMessage(BdfList.of(PRIVATE_MESSAGE, text, + new BdfList(), MAX_AUTO_DELETE_TIMER_MS + 1)); + } + + @Test + public void testAcceptsMinTimerForPrivateMessage() throws Exception { + BdfDictionary minTimerMeta = new BdfDictionary(noAttachmentsMeta); + minTimerMeta.put(MSG_KEY_AUTO_DELETE_TIMER, MIN_AUTO_DELETE_TIMER_MS); + + testAcceptsPrivateMessage(BdfList.of(PRIVATE_MESSAGE, text, + new BdfList(), MIN_AUTO_DELETE_TIMER_MS), minTimerMeta); + } + + @Test + public void testAcceptsMaxTimerForPrivateMessage() throws Exception { + BdfDictionary maxTimerMeta = new BdfDictionary(noAttachmentsMeta); + maxTimerMeta.put(MSG_KEY_AUTO_DELETE_TIMER, MAX_AUTO_DELETE_TIMER_MS); + + testAcceptsPrivateMessage(BdfList.of(PRIVATE_MESSAGE, text, + new BdfList(), MAX_AUTO_DELETE_TIMER_MS), maxTimerMeta); + } + private void testRejectsLegacyMessage(BdfList body) throws Exception { expectCheckTimestamp(now); expectParseList(body); From 113120b3ab3aedcca2906bd1e8509afcf5ab285a Mon Sep 17 00:00:00 2001 From: akwizgran Date: Thu, 19 Nov 2020 15:58:33 +0000 Subject: [PATCH 005/124] Add constant for NO_AUTO_DELETE_TIMER, address review comments. --- .../api/autodelete/AutoDeleteConstants.java | 12 ++++++++++++ .../conversation/ConversationActivity.java | 4 ++-- .../conversation/ConversationViewModel.java | 9 +++++---- .../briar/api/messaging/PrivateMessage.java | 11 ++++++----- .../api/messaging/PrivateMessageFactory.java | 15 +++++++++++++++ .../api/messaging/PrivateMessageFormat.java | 2 +- .../briar/messaging/MessagingManagerImpl.java | 19 ++++++++++++------- .../messaging/PrivateMessageFactoryImpl.java | 6 ++++-- .../briar/test/TestDataCreatorImpl.java | 4 +++- .../MessagingManagerIntegrationTest.java | 11 ++++++----- .../SimplexMessagingIntegrationTest.java | 4 +++- .../headless/event/WebSocketControllerTest.kt | 7 ++++--- .../messaging/MessagingControllerImplTest.kt | 3 ++- 13 files changed, 75 insertions(+), 32 deletions(-) diff --git a/bramble-api/src/main/java/org/briarproject/bramble/api/autodelete/AutoDeleteConstants.java b/bramble-api/src/main/java/org/briarproject/bramble/api/autodelete/AutoDeleteConstants.java index 73db007ba..ca1aaaf8e 100644 --- a/bramble-api/src/main/java/org/briarproject/bramble/api/autodelete/AutoDeleteConstants.java +++ b/bramble-api/src/main/java/org/briarproject/bramble/api/autodelete/AutoDeleteConstants.java @@ -5,7 +5,19 @@ import static java.util.concurrent.TimeUnit.MINUTES; public interface AutoDeleteConstants { + /** + * The minimum valid auto-delete timer duration in milliseconds. + */ long MIN_AUTO_DELETE_TIMER_MS = MINUTES.toMillis(1); + /** + * The maximum valid auto-delete timer duration in milliseconds. + */ long MAX_AUTO_DELETE_TIMER_MS = DAYS.toMillis(365); + + /** + * Placeholder value indicating that a message has no auto-delete timer. + * This value should not be sent over the wire - send null instead. + */ + long NO_AUTO_DELETE_TIMER = -1; } 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 65b9f23d0..4b504cf28 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 @@ -138,7 +138,7 @@ import static org.briarproject.briar.android.util.UiUtils.observeOnce; import static org.briarproject.briar.android.view.AuthorView.setAvatar; import static org.briarproject.briar.api.messaging.MessagingConstants.MAX_ATTACHMENTS_PER_MESSAGE; import static org.briarproject.briar.api.messaging.MessagingConstants.MAX_PRIVATE_MESSAGE_TEXT_LENGTH; -import static org.briarproject.briar.api.messaging.PrivateMessageFormat.TEXT; +import static org.briarproject.briar.api.messaging.PrivateMessageFormat.TEXT_ONLY; @MethodsNotNullByDefault @ParametersNotNullByDefault @@ -270,7 +270,7 @@ public class ConversationActivity extends BriarActivity sendController = new TextAttachmentController(textInputView, imagePreview, this, viewModel); observeOnce(viewModel.getPrivateMessageFormat(), this, format -> { - if (format != null && format != TEXT) { + if (format != TEXT_ONLY) { // TODO: remove cast when removing feature flag ((TextAttachmentController) sendController) .setImagesSupported(); 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 ecc05e956..265b4bb8d 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 @@ -58,13 +58,14 @@ import static androidx.lifecycle.Transformations.map; import static java.util.Objects.requireNonNull; import static java.util.logging.Level.WARNING; import static java.util.logging.Logger.getLogger; +import static org.briarproject.bramble.api.autodelete.AutoDeleteConstants.NO_AUTO_DELETE_TIMER; import static org.briarproject.bramble.util.LogUtils.logDuration; import static org.briarproject.bramble.util.LogUtils.logException; import static org.briarproject.bramble.util.LogUtils.now; import static org.briarproject.briar.android.settings.SettingsFragment.SETTINGS_NAMESPACE; import static org.briarproject.briar.android.util.UiUtils.observeForeverOnce; -import static org.briarproject.briar.api.messaging.PrivateMessageFormat.TEXT; import static org.briarproject.briar.api.messaging.PrivateMessageFormat.TEXT_IMAGES; +import static org.briarproject.briar.api.messaging.PrivateMessageFormat.TEXT_ONLY; @NotNullByDefault public class ConversationViewModel extends DbViewModel @@ -287,7 +288,7 @@ public class ConversationViewModel extends DbViewModel // we only show one onboarding dialog at a time Settings settings = settingsManager.getSettings(SETTINGS_NAMESPACE); - if (format != TEXT && + if (format != TEXT_ONLY && settings.getBoolean(SHOW_ONBOARDING_IMAGE, true)) { onOnboardingShown(SHOW_ONBOARDING_IMAGE); showImageOnboarding.postEvent(true); @@ -311,7 +312,7 @@ public class ConversationViewModel extends DbViewModel PrivateMessageFormat format) { try { PrivateMessage pm; - if (format == TEXT) { + if (format == TEXT_ONLY) { pm = privateMessageFactory.createLegacyPrivateMessage( groupId, timestamp, requireNonNull(text)); } else if (format == TEXT_IMAGES) { @@ -320,7 +321,7 @@ public class ConversationViewModel extends DbViewModel } else { // TODO: Look up auto-delete timer pm = privateMessageFactory.createPrivateMessage(groupId, - timestamp, text, headers, -1); + timestamp, text, headers, NO_AUTO_DELETE_TIMER); } storeMessage(pm); } catch (FormatException e) { diff --git a/briar-api/src/main/java/org/briarproject/briar/api/messaging/PrivateMessage.java b/briar-api/src/main/java/org/briarproject/briar/api/messaging/PrivateMessage.java index b4bf1b859..6d7237970 100644 --- a/briar-api/src/main/java/org/briarproject/briar/api/messaging/PrivateMessage.java +++ b/briar-api/src/main/java/org/briarproject/briar/api/messaging/PrivateMessage.java @@ -9,9 +9,10 @@ import java.util.List; import javax.annotation.concurrent.Immutable; import static java.util.Collections.emptyList; -import static org.briarproject.briar.api.messaging.PrivateMessageFormat.TEXT; +import static org.briarproject.bramble.api.autodelete.AutoDeleteConstants.NO_AUTO_DELETE_TIMER; import static org.briarproject.briar.api.messaging.PrivateMessageFormat.TEXT_IMAGES; import static org.briarproject.briar.api.messaging.PrivateMessageFormat.TEXT_IMAGES_AUTO_DELETE; +import static org.briarproject.briar.api.messaging.PrivateMessageFormat.TEXT_ONLY; @Immutable @NotNullByDefault @@ -25,14 +26,14 @@ public class PrivateMessage { /** * Constructor for private messages in the - * {@link PrivateMessageFormat#TEXT TEXT} format. + * {@link PrivateMessageFormat#TEXT_ONLY TEXT_ONLY} format. */ public PrivateMessage(Message message) { this.message = message; hasText = true; attachmentHeaders = emptyList(); - autoDeleteTimer = -1; - format = TEXT; + autoDeleteTimer = NO_AUTO_DELETE_TIMER; + format = TEXT_ONLY; } /** @@ -44,7 +45,7 @@ public class PrivateMessage { this.message = message; this.hasText = hasText; this.attachmentHeaders = headers; - autoDeleteTimer = -1; + autoDeleteTimer = NO_AUTO_DELETE_TIMER; format = TEXT_IMAGES; } diff --git a/briar-api/src/main/java/org/briarproject/briar/api/messaging/PrivateMessageFactory.java b/briar-api/src/main/java/org/briarproject/briar/api/messaging/PrivateMessageFactory.java index 90c43ccc5..b3274a057 100644 --- a/briar-api/src/main/java/org/briarproject/briar/api/messaging/PrivateMessageFactory.java +++ b/briar-api/src/main/java/org/briarproject/briar/api/messaging/PrivateMessageFactory.java @@ -12,13 +12,28 @@ import javax.annotation.Nullable; @NotNullByDefault public interface PrivateMessageFactory { + /** + * Creates a private message in the + * {@link PrivateMessageFormat#TEXT_ONLY TEXT_ONLY} format. + */ PrivateMessage createLegacyPrivateMessage(GroupId groupId, long timestamp, String text) throws FormatException; + /** + * Creates a private message in the + * {@link PrivateMessageFormat#TEXT_IMAGES TEXT_IMAGES} format. This format + * requires the contact to support client version 0.1 or higher. + */ PrivateMessage createPrivateMessage(GroupId groupId, long timestamp, @Nullable String text, List headers) throws FormatException; + /** + * Creates a private message in the + * {@link PrivateMessageFormat#TEXT_IMAGES_AUTO_DELETE TEXT_IMAGES_AUTO_DELETE} + * format. This format requires the contact to support client version 0.3 + * or higher. + */ PrivateMessage createPrivateMessage(GroupId groupId, long timestamp, @Nullable String text, List headers, long autoDeleteTimer) throws FormatException; diff --git a/briar-api/src/main/java/org/briarproject/briar/api/messaging/PrivateMessageFormat.java b/briar-api/src/main/java/org/briarproject/briar/api/messaging/PrivateMessageFormat.java index 6982e0b31..b7f08b9f3 100644 --- a/briar-api/src/main/java/org/briarproject/briar/api/messaging/PrivateMessageFormat.java +++ b/briar-api/src/main/java/org/briarproject/briar/api/messaging/PrivateMessageFormat.java @@ -6,7 +6,7 @@ public enum PrivateMessageFormat { * First version of the private message format, which doesn't support * image attachments or auto-deletion. */ - TEXT, + TEXT_ONLY, /** * Second version of the private message format, which supports image diff --git a/briar-core/src/main/java/org/briarproject/briar/messaging/MessagingManagerImpl.java b/briar-core/src/main/java/org/briarproject/briar/messaging/MessagingManagerImpl.java index c70ff8196..bb2936ccc 100644 --- a/briar-core/src/main/java/org/briarproject/briar/messaging/MessagingManagerImpl.java +++ b/briar-core/src/main/java/org/briarproject/briar/messaging/MessagingManagerImpl.java @@ -55,14 +55,15 @@ import javax.annotation.concurrent.Immutable; import javax.inject.Inject; import static java.util.Collections.emptyList; +import static org.briarproject.bramble.api.autodelete.AutoDeleteConstants.NO_AUTO_DELETE_TIMER; import static org.briarproject.bramble.api.sync.SyncConstants.MAX_MESSAGE_BODY_LENGTH; import static org.briarproject.bramble.api.sync.validation.MessageState.DELIVERED; import static org.briarproject.bramble.util.IoUtils.copyAndClose; import static org.briarproject.briar.api.attachment.MediaConstants.MSG_KEY_CONTENT_TYPE; import static org.briarproject.briar.api.attachment.MediaConstants.MSG_KEY_DESCRIPTOR_LENGTH; -import static org.briarproject.briar.api.messaging.PrivateMessageFormat.TEXT; import static org.briarproject.briar.api.messaging.PrivateMessageFormat.TEXT_IMAGES; import static org.briarproject.briar.api.messaging.PrivateMessageFormat.TEXT_IMAGES_AUTO_DELETE; +import static org.briarproject.briar.api.messaging.PrivateMessageFormat.TEXT_ONLY; import static org.briarproject.briar.client.MessageTrackerConstants.MSG_KEY_READ; import static org.briarproject.briar.messaging.MessageTypes.ATTACHMENT; import static org.briarproject.briar.messaging.MessageTypes.PRIVATE_MESSAGE; @@ -198,7 +199,8 @@ class MessagingManagerImpl implements MessagingManager, IncomingMessageHook, long timestamp = meta.getLong(MSG_KEY_TIMESTAMP); boolean local = meta.getBoolean(MSG_KEY_LOCAL); boolean read = meta.getBoolean(MSG_KEY_READ); - long timer = meta.getLong(MSG_KEY_AUTO_DELETE_TIMER, -1L); + long timer = meta.getLong(MSG_KEY_AUTO_DELETE_TIMER, + NO_AUTO_DELETE_TIMER); PrivateMessageHeader header = new PrivateMessageHeader(m.getId(), groupId, timestamp, local, read, false, false, hasText, headers, timer); @@ -237,7 +239,7 @@ class MessagingManagerImpl implements MessagingManager, IncomingMessageHook, meta.put(MSG_KEY_TIMESTAMP, m.getMessage().getTimestamp()); meta.put(MSG_KEY_LOCAL, true); meta.put(MSG_KEY_READ, true); - if (m.getFormat() != TEXT) { + if (m.getFormat() != TEXT_ONLY) { meta.put(MSG_KEY_MSG_TYPE, PRIVATE_MESSAGE); meta.put(MSG_KEY_HAS_TEXT, m.hasText()); BdfList headers = new BdfList(); @@ -248,7 +250,9 @@ class MessagingManagerImpl implements MessagingManager, IncomingMessageHook, meta.put(MSG_KEY_ATTACHMENT_HEADERS, headers); if (m.getFormat() == TEXT_IMAGES_AUTO_DELETE) { long timer = m.getAutoDeleteTimer(); - if (timer != -1) meta.put(MSG_KEY_AUTO_DELETE_TIMER, timer); + if (timer != NO_AUTO_DELETE_TIMER) { + meta.put(MSG_KEY_AUTO_DELETE_TIMER, timer); + } } } // Mark attachments as shared and permanent now we're ready to send @@ -362,10 +366,11 @@ class MessagingManagerImpl implements MessagingManager, IncomingMessageHook, if (messageType == null) { headers.add(new PrivateMessageHeader(id, g, timestamp, local, read, s.isSent(), s.isSeen(), true, - emptyList(), -1)); + emptyList(), NO_AUTO_DELETE_TIMER)); } else { boolean hasText = meta.getBoolean(MSG_KEY_HAS_TEXT); - long timer = meta.getLong(MSG_KEY_AUTO_DELETE_TIMER, -1L); + long timer = meta.getLong(MSG_KEY_AUTO_DELETE_TIMER, + NO_AUTO_DELETE_TIMER); headers.add(new PrivateMessageHeader(id, g, timestamp, local, read, s.isSent(), s.isSeen(), hasText, parseAttachmentHeaders(g, meta), timer)); @@ -415,7 +420,7 @@ class MessagingManagerImpl implements MessagingManager, IncomingMessageHook, .getClientMinorVersion(txn, c, CLIENT_ID, 0); if (minorVersion >= 3) return TEXT_IMAGES_AUTO_DELETE; else if (minorVersion >= 1) return TEXT_IMAGES; - else return TEXT; + else return TEXT_ONLY; } @Override diff --git a/briar-core/src/main/java/org/briarproject/briar/messaging/PrivateMessageFactoryImpl.java b/briar-core/src/main/java/org/briarproject/briar/messaging/PrivateMessageFactoryImpl.java index bf70b109b..adae87dd3 100644 --- a/briar-core/src/main/java/org/briarproject/briar/messaging/PrivateMessageFactoryImpl.java +++ b/briar-core/src/main/java/org/briarproject/briar/messaging/PrivateMessageFactoryImpl.java @@ -16,6 +16,7 @@ import javax.annotation.Nullable; import javax.annotation.concurrent.Immutable; import javax.inject.Inject; +import static org.briarproject.bramble.api.autodelete.AutoDeleteConstants.NO_AUTO_DELETE_TIMER; import static org.briarproject.bramble.util.StringUtils.utf8IsTooLong; import static org.briarproject.briar.api.messaging.MessagingConstants.MAX_PRIVATE_MESSAGE_TEXT_LENGTH; import static org.briarproject.briar.messaging.MessageTypes.PRIVATE_MESSAGE; @@ -52,7 +53,7 @@ class PrivateMessageFactoryImpl implements PrivateMessageFactory { // Serialise the message BdfList body = BdfList.of(PRIVATE_MESSAGE, text, attachmentList); Message m = clientHelper.createMessage(groupId, timestamp, body); - return new PrivateMessage(m, text != null, headers, -1); + return new PrivateMessage(m, text != null, headers); } @Override @@ -62,7 +63,8 @@ class PrivateMessageFactoryImpl implements PrivateMessageFactory { validateTextAndAttachmentHeaders(text, headers); BdfList attachmentList = serialiseAttachmentHeaders(headers); // Serialise the message - Long timer = autoDeleteTimer == -1 ? null : autoDeleteTimer; + Long timer = autoDeleteTimer == NO_AUTO_DELETE_TIMER ? + null : autoDeleteTimer; BdfList body = BdfList.of(PRIVATE_MESSAGE, text, attachmentList, timer); Message m = clientHelper.createMessage(groupId, timestamp, body); return new PrivateMessage(m, text != null, headers, autoDeleteTimer); diff --git a/briar-core/src/main/java/org/briarproject/briar/test/TestDataCreatorImpl.java b/briar-core/src/main/java/org/briarproject/briar/test/TestDataCreatorImpl.java index a10fd6382..b207a7c9e 100644 --- a/briar-core/src/main/java/org/briarproject/briar/test/TestDataCreatorImpl.java +++ b/briar-core/src/main/java/org/briarproject/briar/test/TestDataCreatorImpl.java @@ -59,6 +59,7 @@ import static java.util.logging.Level.INFO; import static java.util.logging.Level.WARNING; import static java.util.logging.Logger.getLogger; import static org.briarproject.bramble.api.autodelete.AutoDeleteConstants.MIN_AUTO_DELETE_TIMER_MS; +import static org.briarproject.bramble.api.autodelete.AutoDeleteConstants.NO_AUTO_DELETE_TIMER; import static org.briarproject.bramble.api.plugin.BluetoothConstants.UUID_BYTES; import static org.briarproject.bramble.api.sync.Group.Visibility.SHARED; import static org.briarproject.bramble.util.LogUtils.logException; @@ -361,7 +362,8 @@ public class TestDataCreatorImpl implements TestDataCreator { private void createPrivateMessage(ContactId contactId, GroupId groupId, String text, long timestamp, boolean local, boolean autoDelete) throws DbException { - long timer = autoDelete ? MIN_AUTO_DELETE_TIMER_MS : -1; + long timer = autoDelete ? + MIN_AUTO_DELETE_TIMER_MS : NO_AUTO_DELETE_TIMER; try { PrivateMessage m = privateMessageFactory.createPrivateMessage( groupId, timestamp, text, emptyList(), timer); diff --git a/briar-core/src/test/java/org/briarproject/briar/messaging/MessagingManagerIntegrationTest.java b/briar-core/src/test/java/org/briarproject/briar/messaging/MessagingManagerIntegrationTest.java index 5e97cbd17..c0100cdef 100644 --- a/briar-core/src/test/java/org/briarproject/briar/messaging/MessagingManagerIntegrationTest.java +++ b/briar-core/src/test/java/org/briarproject/briar/messaging/MessagingManagerIntegrationTest.java @@ -33,6 +33,7 @@ import static java.util.Collections.emptySet; import static java.util.Collections.singleton; import static java.util.Collections.singletonList; import static org.briarproject.bramble.api.autodelete.AutoDeleteConstants.MIN_AUTO_DELETE_TIMER_MS; +import static org.briarproject.bramble.api.autodelete.AutoDeleteConstants.NO_AUTO_DELETE_TIMER; import static org.briarproject.bramble.api.sync.validation.MessageState.DELIVERED; import static org.briarproject.bramble.api.sync.validation.MessageState.PENDING; import static org.briarproject.bramble.test.TestUtils.getRandomBytes; @@ -111,8 +112,8 @@ public class MessagingManagerIntegrationTest assertTrue(m1.hasText()); assertEquals(0, m0.getAttachmentHeaders().size()); assertEquals(0, m1.getAttachmentHeaders().size()); - assertEquals(-1, m0.getAutoDeleteTimer()); - assertEquals(-1, m1.getAutoDeleteTimer()); + assertEquals(NO_AUTO_DELETE_TIMER, m0.getAutoDeleteTimer()); + assertEquals(NO_AUTO_DELETE_TIMER, m1.getAutoDeleteTimer()); assertTrue(m0.isRead()); assertFalse(m1.isRead()); assertGroupCounts(c0, 1, 0); @@ -148,8 +149,8 @@ public class MessagingManagerIntegrationTest assertFalse(m1.hasText()); assertEquals(1, m0.getAttachmentHeaders().size()); assertEquals(1, m1.getAttachmentHeaders().size()); - assertEquals(-1, m0.getAutoDeleteTimer()); - assertEquals(-1, m1.getAutoDeleteTimer()); + assertEquals(NO_AUTO_DELETE_TIMER, m0.getAutoDeleteTimer()); + assertEquals(NO_AUTO_DELETE_TIMER, m1.getAutoDeleteTimer()); assertTrue(m0.isRead()); assertFalse(m1.isRead()); assertGroupCounts(c0, 1, 0); @@ -374,7 +375,7 @@ public class MessagingManagerIntegrationTest private PrivateMessage sendMessage(BriarIntegrationTestComponent from, BriarIntegrationTestComponent to, @Nullable String text, List attachments) throws Exception { - return sendMessage(from, to, text, attachments, -1); + return sendMessage(from, to, text, attachments, NO_AUTO_DELETE_TIMER); } private PrivateMessage sendMessage(BriarIntegrationTestComponent from, diff --git a/briar-core/src/test/java/org/briarproject/briar/messaging/SimplexMessagingIntegrationTest.java b/briar-core/src/test/java/org/briarproject/briar/messaging/SimplexMessagingIntegrationTest.java index 3c8ee93c9..5902b9ea2 100644 --- a/briar-core/src/test/java/org/briarproject/briar/messaging/SimplexMessagingIntegrationTest.java +++ b/briar-core/src/test/java/org/briarproject/briar/messaging/SimplexMessagingIntegrationTest.java @@ -34,6 +34,7 @@ import java.util.concurrent.CountDownLatch; import static java.util.Collections.singletonList; import static java.util.concurrent.TimeUnit.MILLISECONDS; +import static org.briarproject.bramble.api.autodelete.AutoDeleteConstants.NO_AUTO_DELETE_TIMER; import static org.briarproject.bramble.api.sync.validation.MessageState.DELIVERED; import static org.briarproject.bramble.test.TestPluginConfigModule.SIMPLEX_TRANSPORT_ID; import static org.briarproject.bramble.test.TestUtils.deleteTestDirectory; @@ -123,7 +124,8 @@ public class SimplexMessagingIntegrationTest extends BriarTestCase { PrivateMessageFactory privateMessageFactory = device.getPrivateMessageFactory(); PrivateMessage message = privateMessageFactory.createPrivateMessage( - groupId, timestamp, "Hi!", singletonList(attachmentHeader), -1); + groupId, timestamp, "Hi!", singletonList(attachmentHeader), + NO_AUTO_DELETE_TIMER); messagingManager.addLocalMessage(message); } diff --git a/briar-headless/src/test/java/org/briarproject/briar/headless/event/WebSocketControllerTest.kt b/briar-headless/src/test/java/org/briarproject/briar/headless/event/WebSocketControllerTest.kt index c9634d192..3a9be9b39 100644 --- a/briar-headless/src/test/java/org/briarproject/briar/headless/event/WebSocketControllerTest.kt +++ b/briar-headless/src/test/java/org/briarproject/briar/headless/event/WebSocketControllerTest.kt @@ -6,11 +6,12 @@ import io.mockk.CapturingSlot import io.mockk.every import io.mockk.mockk import io.mockk.verify -import org.briarproject.briar.api.identity.AuthorInfo -import org.briarproject.briar.api.identity.AuthorInfo.Status.VERIFIED +import org.briarproject.bramble.api.autodelete.AutoDeleteConstants.NO_AUTO_DELETE_TIMER import org.briarproject.bramble.test.ImmediateExecutor import org.briarproject.bramble.test.TestUtils.getRandomId import org.briarproject.briar.api.client.SessionId +import org.briarproject.briar.api.identity.AuthorInfo +import org.briarproject.briar.api.identity.AuthorInfo.Status.VERIFIED import org.briarproject.briar.api.introduction.IntroductionRequest import org.briarproject.briar.api.introduction.event.IntroductionRequestReceivedEvent import org.briarproject.briar.api.messaging.PrivateMessageHeader @@ -42,7 +43,7 @@ internal class WebSocketControllerTest : ControllerTest() { true, true, emptyList(), - -1 + NO_AUTO_DELETE_TIMER ) private val event = PrivateMessageReceivedEvent(header, contact.id) private val outputEvent = OutputEvent(EVENT_CONVERSATION_MESSAGE, event.output(text)) diff --git a/briar-headless/src/test/java/org/briarproject/briar/headless/messaging/MessagingControllerImplTest.kt b/briar-headless/src/test/java/org/briarproject/briar/headless/messaging/MessagingControllerImplTest.kt index 8e20f9b1f..58685c6e4 100644 --- a/briar-headless/src/test/java/org/briarproject/briar/headless/messaging/MessagingControllerImplTest.kt +++ b/briar-headless/src/test/java/org/briarproject/briar/headless/messaging/MessagingControllerImplTest.kt @@ -11,6 +11,7 @@ import io.mockk.just import io.mockk.mockk import io.mockk.mockkStatic import io.mockk.runs +import org.briarproject.bramble.api.autodelete.AutoDeleteConstants.NO_AUTO_DELETE_TIMER import org.briarproject.bramble.api.contact.ContactId import org.briarproject.bramble.api.db.NoSuchContactException import org.briarproject.briar.api.identity.AuthorInfo @@ -69,7 +70,7 @@ internal class MessagingControllerImplTest : ControllerTest() { true, true, emptyList(), - -1 + NO_AUTO_DELETE_TIMER ) private val sessionId = SessionId(getRandomId()) private val privateMessage = PrivateMessage(message) From 3798ca1e174f65bacd5f693fc26c9dd294ab6900 Mon Sep 17 00:00:00 2001 From: akwizgran Date: Thu, 19 Nov 2020 15:35:13 +0000 Subject: [PATCH 006/124] Update introduction validator to support auto-delete timers. --- .../bramble/util/ValidationUtils.java | 5 + .../api/introduction/IntroductionManager.java | 2 +- .../introduction/AbstractProtocolEngine.java | 14 +- .../introduction/IntroductionConstants.java | 1 + .../introduction/IntroductionValidator.java | 83 ++++++- .../briar/introduction/MessageEncoder.java | 5 +- .../introduction/MessageEncoderImpl.java | 14 +- .../briar/introduction/MessageMetadata.java | 8 +- .../briar/introduction/MessageParserImpl.java | 5 +- .../messaging/PrivateMessageValidator.java | 9 +- .../IntroductionValidatorTest.java | 231 ++++++++++++++++-- .../MessageEncoderParserIntegrationTest.java | 8 +- 12 files changed, 333 insertions(+), 52 deletions(-) diff --git a/bramble-api/src/main/java/org/briarproject/bramble/util/ValidationUtils.java b/bramble-api/src/main/java/org/briarproject/bramble/util/ValidationUtils.java index fffacae0c..1bb56a799 100644 --- a/bramble-api/src/main/java/org/briarproject/bramble/util/ValidationUtils.java +++ b/bramble-api/src/main/java/org/briarproject/bramble/util/ValidationUtils.java @@ -64,4 +64,9 @@ public class ValidationUtils { if (dictionary != null && dictionary.size() != size) throw new FormatException(); } + + public static void checkRange(@Nullable Long l, long min, long max) + throws FormatException { + if (l != null && (l < min || l > max)) throw new FormatException(); + } } 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 49994c4b7..8eef68eea 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 @@ -31,7 +31,7 @@ public interface IntroductionManager extends ConversationClient { /** * The current minor version of the introduction client. */ - int MINOR_VERSION = 0; + int MINOR_VERSION = 1; /** * Sends two initial introduction messages. 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 37b84e516..9f7d5febe 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 @@ -31,6 +31,7 @@ import java.util.Map; import javax.annotation.Nullable; import javax.annotation.concurrent.Immutable; +import static org.briarproject.bramble.api.autodelete.AutoDeleteConstants.NO_AUTO_DELETE_TIMER; import static org.briarproject.briar.introduction.MessageType.ABORT; import static org.briarproject.briar.introduction.MessageType.ACCEPT; import static org.briarproject.briar.introduction.MessageType.ACTIVATE; @@ -40,7 +41,7 @@ import static org.briarproject.briar.introduction.MessageType.REQUEST; @Immutable @NotNullByDefault -abstract class AbstractProtocolEngine +abstract class AbstractProtocolEngine> implements ProtocolEngine { protected final DatabaseComponent db; @@ -140,9 +141,11 @@ abstract class AbstractProtocolEngine private void sendMessage(Transaction txn, MessageType type, SessionId sessionId, Message m, boolean visibleInConversation) throws DbException { + // TODO: If message is visible in conversation, look up current + // auto-delete timer and include it in message BdfDictionary meta = messageEncoder .encodeMetadata(type, sessionId, m.getTimestamp(), true, true, - visibleInConversation); + visibleInConversation, NO_AUTO_DELETE_TIMER); try { clientHelper.addLocalMessage(txn, m, meta, true, false); } catch (FormatException e) { @@ -150,9 +153,10 @@ abstract class AbstractProtocolEngine } } - void broadcastIntroductionResponseReceivedEvent(Transaction txn, Session s, - AuthorId sender, Author otherAuthor, AbstractIntroductionMessage m, - boolean canSucceed) throws DbException { + void broadcastIntroductionResponseReceivedEvent(Transaction txn, + Session s, AuthorId sender, Author otherAuthor, + AbstractIntroductionMessage m, boolean canSucceed) + throws DbException { AuthorId localAuthorId = identityManager.getLocalAuthor(txn).getId(); Contact c = contactManager.getContact(txn, sender, localAuthorId); AuthorInfo otherAuthorInfo = diff --git a/briar-core/src/main/java/org/briarproject/briar/introduction/IntroductionConstants.java b/briar-core/src/main/java/org/briarproject/briar/introduction/IntroductionConstants.java index 522759a55..16a09e93e 100644 --- a/briar-core/src/main/java/org/briarproject/briar/introduction/IntroductionConstants.java +++ b/briar-core/src/main/java/org/briarproject/briar/introduction/IntroductionConstants.java @@ -12,6 +12,7 @@ interface IntroductionConstants { String MSG_KEY_LOCAL = "local"; String MSG_KEY_VISIBLE_IN_UI = "visibleInUi"; String MSG_KEY_AVAILABLE_TO_ANSWER = "availableToAnswer"; + String MSG_KEY_AUTO_DELETE_TIMER = "autoDeleteTimer"; // Session Keys String SESSION_KEY_SESSION_ID = "sessionId"; diff --git a/briar-core/src/main/java/org/briarproject/briar/introduction/IntroductionValidator.java b/briar-core/src/main/java/org/briarproject/briar/introduction/IntroductionValidator.java index a4ac7a45d..7b78cbf47 100644 --- a/briar-core/src/main/java/org/briarproject/briar/introduction/IntroductionValidator.java +++ b/briar-core/src/main/java/org/briarproject/briar/introduction/IntroductionValidator.java @@ -18,10 +18,14 @@ import org.briarproject.briar.api.client.SessionId; import javax.annotation.concurrent.Immutable; import static java.util.Collections.singletonList; +import static org.briarproject.bramble.api.autodelete.AutoDeleteConstants.MAX_AUTO_DELETE_TIMER_MS; +import static org.briarproject.bramble.api.autodelete.AutoDeleteConstants.MIN_AUTO_DELETE_TIMER_MS; +import static org.briarproject.bramble.api.autodelete.AutoDeleteConstants.NO_AUTO_DELETE_TIMER; import static org.briarproject.bramble.api.crypto.CryptoConstants.MAC_BYTES; import static org.briarproject.bramble.api.crypto.CryptoConstants.MAX_SIGNATURE_BYTES; import static org.briarproject.bramble.api.identity.AuthorConstants.MAX_PUBLIC_KEY_LENGTH; import static org.briarproject.bramble.util.ValidationUtils.checkLength; +import static org.briarproject.bramble.util.ValidationUtils.checkRange; import static org.briarproject.bramble.util.ValidationUtils.checkSize; import static org.briarproject.briar.api.introduction.IntroductionConstants.MAX_INTRODUCTION_TEXT_LENGTH; import static org.briarproject.briar.introduction.MessageType.ACCEPT; @@ -52,13 +56,14 @@ class IntroductionValidator extends BdfMessageValidator { return validateRequestMessage(m, body); case ACCEPT: return validateAcceptMessage(m, body); + case DECLINE: + return validateDeclineMessage(type, m, body); case AUTH: return validateAuthMessage(m, body); case ACTIVATE: return validateActivateMessage(m, body); - case DECLINE: case ABORT: - return validateOtherMessage(type, m, body); + return validateAbortMessage(type, m, body); default: throw new FormatException(); } @@ -66,7 +71,11 @@ class IntroductionValidator extends BdfMessageValidator { private BdfMessageContext validateRequestMessage(Message m, BdfList body) throws FormatException { - checkSize(body, 4); + // Client version 0.0: Message type, optional previous message ID, + // author, optional text. + // Client version 0.1: Message type, optional previous message ID, + // author, optional text, optional auto-delete timer. + checkSize(body, 4, 5); byte[] previousMessageId = body.getOptionalRaw(1); checkLength(previousMessageId, UniqueId.LENGTH); @@ -77,8 +86,16 @@ class IntroductionValidator extends BdfMessageValidator { String text = body.getOptionalString(3); checkLength(text, 1, MAX_INTRODUCTION_TEXT_LENGTH); + Long timer = null; + if (body.size() == 5) { + timer = body.getOptionalLong(4); + checkRange(timer, MIN_AUTO_DELETE_TIMER_MS, + MAX_AUTO_DELETE_TIMER_MS); + } + if (timer == null) timer = NO_AUTO_DELETE_TIMER; + BdfDictionary meta = - messageEncoder.encodeRequestMetadata(m.getTimestamp()); + messageEncoder.encodeRequestMetadata(m.getTimestamp(), timer); if (previousMessageId == null) { return new BdfMessageContext(meta); } else { @@ -89,7 +106,12 @@ class IntroductionValidator extends BdfMessageValidator { private BdfMessageContext validateAcceptMessage(Message m, BdfList body) throws FormatException { - checkSize(body, 6); + // Client version 0.0: Message type, session ID, optional previous + // message ID, ephemeral public key, timestamp, transport properties. + // Client version 0.1: Message type, session ID, optional previous + // message ID, ephemeral public key, timestamp, transport properties, + // optional auto-delete timer. + checkSize(body, 6, 7); byte[] sessionIdBytes = body.getRaw(1); checkLength(sessionIdBytes, UniqueId.LENGTH); @@ -109,9 +131,50 @@ class IntroductionValidator extends BdfMessageValidator { clientHelper .parseAndValidateTransportPropertiesMap(transportProperties); + Long timer = null; + if (body.size() == 7) { + timer = body.getOptionalLong(6); + checkRange(timer, MIN_AUTO_DELETE_TIMER_MS, + MAX_AUTO_DELETE_TIMER_MS); + } + if (timer == null) timer = NO_AUTO_DELETE_TIMER; + SessionId sessionId = new SessionId(sessionIdBytes); BdfDictionary meta = messageEncoder.encodeMetadata(ACCEPT, sessionId, - m.getTimestamp(), false, false, false); + m.getTimestamp(), false, false, false, timer); + if (previousMessageId == null) { + return new BdfMessageContext(meta); + } else { + MessageId dependency = new MessageId(previousMessageId); + return new BdfMessageContext(meta, singletonList(dependency)); + } + } + + private BdfMessageContext validateDeclineMessage(MessageType type, + Message m, BdfList body) throws FormatException { + // Client version 0.0: Message type, session ID, optional previous + // message ID. + // Client version 0.1: Message type, session ID, optional previous + // message ID, optional auto-delete timer. + checkSize(body, 3, 4); + + byte[] sessionIdBytes = body.getRaw(1); + checkLength(sessionIdBytes, UniqueId.LENGTH); + + byte[] previousMessageId = body.getOptionalRaw(2); + checkLength(previousMessageId, UniqueId.LENGTH); + + Long timer = null; + if (body.size() == 4) { + timer = body.getOptionalLong(3); + checkRange(timer, MIN_AUTO_DELETE_TIMER_MS, + MAX_AUTO_DELETE_TIMER_MS); + } + if (timer == null) timer = NO_AUTO_DELETE_TIMER; + + SessionId sessionId = new SessionId(sessionIdBytes); + BdfDictionary meta = messageEncoder.encodeMetadata(type, sessionId, + m.getTimestamp(), false, false, false, timer); if (previousMessageId == null) { return new BdfMessageContext(meta); } else { @@ -138,7 +201,7 @@ class IntroductionValidator extends BdfMessageValidator { SessionId sessionId = new SessionId(sessionIdBytes); BdfDictionary meta = messageEncoder.encodeMetadata(AUTH, sessionId, - m.getTimestamp(), false, false, false); + m.getTimestamp(), false, false, false, NO_AUTO_DELETE_TIMER); MessageId dependency = new MessageId(previousMessageId); return new BdfMessageContext(meta, singletonList(dependency)); } @@ -158,7 +221,7 @@ class IntroductionValidator extends BdfMessageValidator { SessionId sessionId = new SessionId(sessionIdBytes); BdfDictionary meta = messageEncoder.encodeMetadata(ACTIVATE, sessionId, - m.getTimestamp(), false, false, false); + m.getTimestamp(), false, false, false, NO_AUTO_DELETE_TIMER); if (previousMessageId == null) { return new BdfMessageContext(meta); } else { @@ -167,7 +230,7 @@ class IntroductionValidator extends BdfMessageValidator { } } - private BdfMessageContext validateOtherMessage(MessageType type, + private BdfMessageContext validateAbortMessage(MessageType type, Message m, BdfList body) throws FormatException { checkSize(body, 3); @@ -179,7 +242,7 @@ class IntroductionValidator extends BdfMessageValidator { SessionId sessionId = new SessionId(sessionIdBytes); BdfDictionary meta = messageEncoder.encodeMetadata(type, sessionId, - m.getTimestamp(), false, false, false); + m.getTimestamp(), false, false, false, NO_AUTO_DELETE_TIMER); if (previousMessageId == null) { return new BdfMessageContext(meta); } else { diff --git a/briar-core/src/main/java/org/briarproject/briar/introduction/MessageEncoder.java b/briar-core/src/main/java/org/briarproject/briar/introduction/MessageEncoder.java index 38a4841ea..2357f7277 100644 --- a/briar-core/src/main/java/org/briarproject/briar/introduction/MessageEncoder.java +++ b/briar-core/src/main/java/org/briarproject/briar/introduction/MessageEncoder.java @@ -18,11 +18,12 @@ import javax.annotation.Nullable; @NotNullByDefault interface MessageEncoder { - BdfDictionary encodeRequestMetadata(long timestamp); + BdfDictionary encodeRequestMetadata(long timestamp, + long autoDeleteTimer); BdfDictionary encodeMetadata(MessageType type, @Nullable SessionId sessionId, long timestamp, boolean local, - boolean read, boolean visible); + boolean read, boolean visible, long autoDeleteTimer); void addSessionId(BdfDictionary meta, SessionId sessionId); diff --git a/briar-core/src/main/java/org/briarproject/briar/introduction/MessageEncoderImpl.java b/briar-core/src/main/java/org/briarproject/briar/introduction/MessageEncoderImpl.java index e11d6ecd3..901b37cd7 100644 --- a/briar-core/src/main/java/org/briarproject/briar/introduction/MessageEncoderImpl.java +++ b/briar-core/src/main/java/org/briarproject/briar/introduction/MessageEncoderImpl.java @@ -20,7 +20,9 @@ import java.util.Map; import javax.annotation.Nullable; import javax.inject.Inject; +import static org.briarproject.bramble.api.autodelete.AutoDeleteConstants.NO_AUTO_DELETE_TIMER; import static org.briarproject.briar.client.MessageTrackerConstants.MSG_KEY_READ; +import static org.briarproject.briar.introduction.IntroductionConstants.MSG_KEY_AUTO_DELETE_TIMER; import static org.briarproject.briar.introduction.IntroductionConstants.MSG_KEY_AVAILABLE_TO_ANSWER; import static org.briarproject.briar.introduction.IntroductionConstants.MSG_KEY_LOCAL; import static org.briarproject.briar.introduction.IntroductionConstants.MSG_KEY_MESSAGE_TYPE; @@ -48,9 +50,10 @@ class MessageEncoderImpl implements MessageEncoder { } @Override - public BdfDictionary encodeRequestMetadata(long timestamp) { - BdfDictionary meta = - encodeMetadata(REQUEST, null, timestamp, false, false, false); + public BdfDictionary encodeRequestMetadata(long timestamp, + long autoDeleteTimer) { + BdfDictionary meta = encodeMetadata(REQUEST, null, timestamp, + false, false, false, autoDeleteTimer); meta.put(MSG_KEY_AVAILABLE_TO_ANSWER, false); return meta; } @@ -58,7 +61,7 @@ class MessageEncoderImpl implements MessageEncoder { @Override public BdfDictionary encodeMetadata(MessageType type, @Nullable SessionId sessionId, long timestamp, boolean local, - boolean read, boolean visible) { + boolean read, boolean visible, long autoDeleteTimer) { BdfDictionary meta = new BdfDictionary(); meta.put(MSG_KEY_MESSAGE_TYPE, type.getValue()); if (sessionId != null) @@ -69,6 +72,9 @@ class MessageEncoderImpl implements MessageEncoder { meta.put(MSG_KEY_LOCAL, local); meta.put(MSG_KEY_READ, read); meta.put(MSG_KEY_VISIBLE_IN_UI, visible); + if (autoDeleteTimer != NO_AUTO_DELETE_TIMER) { + meta.put(MSG_KEY_AUTO_DELETE_TIMER, autoDeleteTimer); + } return meta; } diff --git a/briar-core/src/main/java/org/briarproject/briar/introduction/MessageMetadata.java b/briar-core/src/main/java/org/briarproject/briar/introduction/MessageMetadata.java index 102d72bfc..2ae4e8daa 100644 --- a/briar-core/src/main/java/org/briarproject/briar/introduction/MessageMetadata.java +++ b/briar-core/src/main/java/org/briarproject/briar/introduction/MessageMetadata.java @@ -13,12 +13,12 @@ class MessageMetadata { private final MessageType type; @Nullable private final SessionId sessionId; - private final long timestamp; + private final long timestamp, autoDeleteTimer; private final boolean local, read, visible, available; MessageMetadata(MessageType type, @Nullable SessionId sessionId, long timestamp, boolean local, boolean read, boolean visible, - boolean available) { + boolean available, long autoDeleteTimer) { this.type = type; this.sessionId = sessionId; this.timestamp = timestamp; @@ -26,6 +26,7 @@ class MessageMetadata { this.read = read; this.visible = visible; this.available = available; + this.autoDeleteTimer = autoDeleteTimer; } MessageType getMessageType() { @@ -57,4 +58,7 @@ class MessageMetadata { return available; } + public long getAutoDeleteTimer() { + return autoDeleteTimer; + } } diff --git a/briar-core/src/main/java/org/briarproject/briar/introduction/MessageParserImpl.java b/briar-core/src/main/java/org/briarproject/briar/introduction/MessageParserImpl.java index fb727c0b4..1e6808c06 100644 --- a/briar-core/src/main/java/org/briarproject/briar/introduction/MessageParserImpl.java +++ b/briar-core/src/main/java/org/briarproject/briar/introduction/MessageParserImpl.java @@ -19,7 +19,9 @@ import java.util.Map; import javax.inject.Inject; +import static org.briarproject.bramble.api.autodelete.AutoDeleteConstants.NO_AUTO_DELETE_TIMER; import static org.briarproject.briar.client.MessageTrackerConstants.MSG_KEY_READ; +import static org.briarproject.briar.introduction.IntroductionConstants.MSG_KEY_AUTO_DELETE_TIMER; import static org.briarproject.briar.introduction.IntroductionConstants.MSG_KEY_AVAILABLE_TO_ANSWER; import static org.briarproject.briar.introduction.IntroductionConstants.MSG_KEY_LOCAL; import static org.briarproject.briar.introduction.IntroductionConstants.MSG_KEY_MESSAGE_TYPE; @@ -65,8 +67,9 @@ class MessageParserImpl implements MessageParser { boolean read = d.getBoolean(MSG_KEY_READ); boolean visible = d.getBoolean(MSG_KEY_VISIBLE_IN_UI); boolean available = d.getBoolean(MSG_KEY_AVAILABLE_TO_ANSWER, false); + long timer = d.getLong(MSG_KEY_AUTO_DELETE_TIMER, NO_AUTO_DELETE_TIMER); return new MessageMetadata(type, sessionId, timestamp, local, read, - visible, available); + visible, available, timer); } @Override diff --git a/briar-core/src/main/java/org/briarproject/briar/messaging/PrivateMessageValidator.java b/briar-core/src/main/java/org/briarproject/briar/messaging/PrivateMessageValidator.java index 408752b88..761e27842 100644 --- a/briar-core/src/main/java/org/briarproject/briar/messaging/PrivateMessageValidator.java +++ b/briar-core/src/main/java/org/briarproject/briar/messaging/PrivateMessageValidator.java @@ -29,6 +29,7 @@ import static org.briarproject.bramble.api.autodelete.AutoDeleteConstants.MIN_AU import static org.briarproject.bramble.api.sync.SyncConstants.MAX_MESSAGE_BODY_LENGTH; import static org.briarproject.bramble.api.transport.TransportConstants.MAX_CLOCK_DIFFERENCE; import static org.briarproject.bramble.util.ValidationUtils.checkLength; +import static org.briarproject.bramble.util.ValidationUtils.checkRange; import static org.briarproject.bramble.util.ValidationUtils.checkSize; import static org.briarproject.briar.api.attachment.MediaConstants.MAX_CONTENT_TYPE_BYTES; import static org.briarproject.briar.api.attachment.MediaConstants.MSG_KEY_CONTENT_TYPE; @@ -137,10 +138,10 @@ class PrivateMessageValidator implements MessageValidator { checkLength(contentType, 1, MAX_CONTENT_TYPE_BYTES); } Long timer = null; - if (body.size() == 4) timer = body.getOptionalLong(3); - if (timer != null && (timer < MIN_AUTO_DELETE_TIMER_MS || - timer > MAX_AUTO_DELETE_TIMER_MS)) { - throw new FormatException(); + if (body.size() == 4) { + timer = body.getOptionalLong(3); + checkRange(timer, MIN_AUTO_DELETE_TIMER_MS, + MAX_AUTO_DELETE_TIMER_MS); } // Return the metadata BdfDictionary meta = new BdfDictionary(); diff --git a/briar-core/src/test/java/org/briarproject/briar/introduction/IntroductionValidatorTest.java b/briar-core/src/test/java/org/briarproject/briar/introduction/IntroductionValidatorTest.java index 249ba8852..7cd82468a 100644 --- a/briar-core/src/test/java/org/briarproject/briar/introduction/IntroductionValidatorTest.java +++ b/briar-core/src/test/java/org/briarproject/briar/introduction/IntroductionValidatorTest.java @@ -6,20 +6,29 @@ import org.briarproject.bramble.api.crypto.PublicKey; import org.briarproject.bramble.api.data.BdfDictionary; import org.briarproject.bramble.api.data.BdfEntry; import org.briarproject.bramble.api.data.BdfList; +import org.briarproject.bramble.api.plugin.TransportId; +import org.briarproject.bramble.api.properties.TransportProperties; import org.briarproject.bramble.api.sync.MessageId; import org.briarproject.bramble.test.ValidatorTestCase; import org.briarproject.briar.api.client.SessionId; import org.jmock.Expectations; import org.junit.Test; +import java.util.Map; + import javax.annotation.Nullable; +import static java.util.Collections.singletonMap; +import static org.briarproject.bramble.api.autodelete.AutoDeleteConstants.MAX_AUTO_DELETE_TIMER_MS; +import static org.briarproject.bramble.api.autodelete.AutoDeleteConstants.MIN_AUTO_DELETE_TIMER_MS; +import static org.briarproject.bramble.api.autodelete.AutoDeleteConstants.NO_AUTO_DELETE_TIMER; import static org.briarproject.bramble.api.crypto.CryptoConstants.MAC_BYTES; import static org.briarproject.bramble.api.crypto.CryptoConstants.MAX_AGREEMENT_PUBLIC_KEY_BYTES; import static org.briarproject.bramble.api.crypto.CryptoConstants.MAX_SIGNATURE_BYTES; import static org.briarproject.bramble.test.TestUtils.getAgreementPublicKey; import static org.briarproject.bramble.test.TestUtils.getRandomBytes; import static org.briarproject.bramble.test.TestUtils.getRandomId; +import static org.briarproject.bramble.test.TestUtils.getTransportId; import static org.briarproject.bramble.util.StringUtils.getRandomString; import static org.briarproject.briar.api.introduction.IntroductionConstants.MAX_INTRODUCTION_TEXT_LENGTH; import static org.briarproject.briar.introduction.MessageType.ABORT; @@ -44,9 +53,12 @@ public class IntroductionValidatorTest extends ValidatorTestCase { private final BdfDictionary meta = new BdfDictionary(); private final PublicKey ephemeralPublicKey = getAgreementPublicKey(); private final long acceptTimestamp = 42; + private final TransportId transportId = getTransportId(); private final BdfDictionary transportProperties = BdfDictionary.of( - new BdfEntry("transportId", new BdfDictionary()) + new BdfEntry(transportId.getString(), new BdfDictionary()) ); + private final Map transportPropertiesMap = + singletonMap(transportId, new TransportProperties()); private final byte[] mac = getRandomBytes(MAC_BYTES); private final byte[] signature = getRandomBytes(MAX_SIGNATURE_BYTES); @@ -60,7 +72,7 @@ public class IntroductionValidatorTest extends ValidatorTestCase { authorList, text); expectParseAuthor(authorList, author); - expectEncodeRequestMetadata(); + expectEncodeRequestMetadata(NO_AUTO_DELETE_TIMER); BdfMessageContext messageContext = validator.validateMessage(message, group, body); @@ -72,7 +84,7 @@ public class IntroductionValidatorTest extends ValidatorTestCase { BdfList body = BdfList.of(REQUEST.getValue(), null, authorList, text); expectParseAuthor(authorList, author); - expectEncodeRequestMetadata(); + expectEncodeRequestMetadata(NO_AUTO_DELETE_TIMER); BdfMessageContext messageContext = validator.validateMessage(message, group, body); @@ -84,13 +96,42 @@ public class IntroductionValidatorTest extends ValidatorTestCase { BdfList body = BdfList.of(REQUEST.getValue(), null, authorList, null); expectParseAuthor(authorList, author); - expectEncodeRequestMetadata(); + expectEncodeRequestMetadata(NO_AUTO_DELETE_TIMER); BdfMessageContext messageContext = validator.validateMessage(message, group, body); assertExpectedContext(messageContext, null); } + @Test + public void testAcceptsRequestWithNullAutoDeleteTimer() throws Exception { + testAcceptsRequestWithAutoDeleteTimer(null); + } + + @Test + public void testAcceptsRequestWithMinAutoDeleteTimer() throws Exception { + testAcceptsRequestWithAutoDeleteTimer(MIN_AUTO_DELETE_TIMER_MS); + } + + @Test + public void testAcceptsRequestWithMaxAutoDeleteTimer() throws Exception { + testAcceptsRequestWithAutoDeleteTimer(MAX_AUTO_DELETE_TIMER_MS); + } + + private void testAcceptsRequestWithAutoDeleteTimer(@Nullable Long timer) + throws Exception { + BdfList body = BdfList.of(REQUEST.getValue(), previousMsgId.getBytes(), + authorList, text, timer); + + expectParseAuthor(authorList, author); + long autoDeleteTimer = timer == null ? NO_AUTO_DELETE_TIMER : timer; + expectEncodeRequestMetadata(autoDeleteTimer); + BdfMessageContext messageContext = + validator.validateMessage(message, group, body); + + assertExpectedContext(messageContext, previousMsgId); + } + @Test(expected = FormatException.class) public void testRejectsTooShortBodyForRequest() throws Exception { BdfList body = BdfList.of(REQUEST.getValue(), null, authorList); @@ -99,8 +140,8 @@ public class IntroductionValidatorTest extends ValidatorTestCase { @Test(expected = FormatException.class) public void testRejectsTooLongBodyForRequest() throws Exception { - BdfList body = - BdfList.of(REQUEST.getValue(), null, authorList, text, null); + BdfList body = BdfList.of(REQUEST.getValue(), null, authorList, text, + null, null); validator.validateMessage(message, group, body); } @@ -119,6 +160,32 @@ public class IntroductionValidatorTest extends ValidatorTestCase { validator.validateMessage(message, group, body); } + @Test(expected = FormatException.class) + public void testRejectsRequestWithNonLongAutoDeleteTimer() + throws Exception { + BdfList body = BdfList.of(REQUEST.getValue(), previousMsgId.getBytes(), + authorList, text, "foo"); + expectParseAuthor(authorList, author); + validator.validateMessage(message, group, body); + } + + @Test(expected = FormatException.class) + public void testRejectsRequestWithTooSmallAutoDeleteTimer() + throws Exception { + BdfList body = BdfList.of(REQUEST.getValue(), previousMsgId.getBytes(), + authorList, text, MIN_AUTO_DELETE_TIMER_MS - 1); + expectParseAuthor(authorList, author); + validator.validateMessage(message, group, body); + } + + @Test(expected = FormatException.class) + public void testRejectsRequestWithTooBigAutoDeleteTimer() throws Exception { + BdfList body = BdfList.of(REQUEST.getValue(), previousMsgId.getBytes(), + authorList, text, MAX_AUTO_DELETE_TIMER_MS + 1); + expectParseAuthor(authorList, author); + validator.validateMessage(message, group, body); + } + // // Introduction ACCEPT // @@ -129,11 +196,38 @@ public class IntroductionValidatorTest extends ValidatorTestCase { previousMsgId.getBytes(), ephemeralPublicKey.getEncoded(), acceptTimestamp, transportProperties); expectParsePublicKey(); - context.checking(new Expectations() {{ - oneOf(clientHelper).parseAndValidateTransportPropertiesMap( - transportProperties); - }}); - expectEncodeMetadata(ACCEPT); + expectParseTransportProperties(); + expectEncodeMetadata(ACCEPT, NO_AUTO_DELETE_TIMER); + BdfMessageContext messageContext = + validator.validateMessage(message, group, body); + + assertExpectedContext(messageContext, previousMsgId); + } + + @Test + public void testAcceptsAcceptWithNullAutoDeleteTimer() throws Exception { + testAcceptsAcceptWithAutoDeleteTimer(null); + } + + @Test + public void testAcceptsAcceptWithMinAutoDeleteTimer() throws Exception { + testAcceptsAcceptWithAutoDeleteTimer(MIN_AUTO_DELETE_TIMER_MS); + } + + @Test + public void testAcceptsAcceptWithMaxAutoDeleteTimer() throws Exception { + testAcceptsAcceptWithAutoDeleteTimer(MAX_AUTO_DELETE_TIMER_MS); + } + + private void testAcceptsAcceptWithAutoDeleteTimer(@Nullable Long timer) + throws Exception { + BdfList body = BdfList.of(ACCEPT.getValue(), sessionId.getBytes(), + previousMsgId.getBytes(), ephemeralPublicKey.getEncoded(), + acceptTimestamp, transportProperties, timer); + expectParsePublicKey(); + expectParseTransportProperties(); + long autoDeleteTimer = timer == null ? NO_AUTO_DELETE_TIMER : timer; + expectEncodeMetadata(ACCEPT, autoDeleteTimer); BdfMessageContext messageContext = validator.validateMessage(message, group, body); @@ -152,7 +246,7 @@ public class IntroductionValidatorTest extends ValidatorTestCase { public void testRejectsTooLongBodyForAccept() throws Exception { BdfList body = BdfList.of(ACCEPT.getValue(), sessionId.getBytes(), previousMsgId.getBytes(), ephemeralPublicKey.getEncoded(), - acceptTimestamp, transportProperties, null); + acceptTimestamp, transportProperties, null, null); validator.validateMessage(message, group, body); } @@ -200,6 +294,40 @@ public class IntroductionValidatorTest extends ValidatorTestCase { validator.validateMessage(message, group, body); } + @Test(expected = FormatException.class) + public void testRejectsAcceptWithNonLongAutoDeleteTimer() + throws Exception { + BdfList body = BdfList.of(ACCEPT.getValue(), sessionId.getBytes(), + previousMsgId.getBytes(), ephemeralPublicKey.getEncoded(), + acceptTimestamp, transportProperties, "foo"); + expectParsePublicKey(); + expectParseTransportProperties(); + validator.validateMessage(message, group, body); + } + + @Test(expected = FormatException.class) + public void testRejectsAcceptWithTooSmallAutoDeleteTimer() + throws Exception { + BdfList body = BdfList.of(ACCEPT.getValue(), sessionId.getBytes(), + previousMsgId.getBytes(), ephemeralPublicKey.getEncoded(), + acceptTimestamp, transportProperties, + MIN_AUTO_DELETE_TIMER_MS - 1); + expectParsePublicKey(); + expectParseTransportProperties(); + validator.validateMessage(message, group, body); + } + + @Test(expected = FormatException.class) + public void testRejectsAcceptWithTooBigAutoDeleteTimer() throws Exception { + BdfList body = BdfList.of(ACCEPT.getValue(), sessionId.getBytes(), + previousMsgId.getBytes(), ephemeralPublicKey.getEncoded(), + acceptTimestamp, transportProperties, + MAX_AUTO_DELETE_TIMER_MS + 1); + expectParsePublicKey(); + expectParseTransportProperties(); + validator.validateMessage(message, group, body); + } + // // Introduction DECLINE // @@ -209,7 +337,35 @@ public class IntroductionValidatorTest extends ValidatorTestCase { BdfList body = BdfList.of(DECLINE.getValue(), sessionId.getBytes(), previousMsgId.getBytes()); - expectEncodeMetadata(DECLINE); + expectEncodeMetadata(DECLINE, NO_AUTO_DELETE_TIMER); + BdfMessageContext messageContext = + validator.validateMessage(message, group, body); + + assertExpectedContext(messageContext, previousMsgId); + } + + @Test + public void testAcceptsDeclineWithNullAutoDeleteTimer() throws Exception { + testAcceptsDeclineWithAutoDeleteTimer(null); + } + + @Test + public void testAcceptsDeclineWithMinAutoDeleteTimer() throws Exception { + testAcceptsDeclineWithAutoDeleteTimer(MIN_AUTO_DELETE_TIMER_MS); + } + + @Test + public void testAcceptsDeclineWithMaxAutoDeleteTimer() throws Exception { + testAcceptsDeclineWithAutoDeleteTimer(MAX_AUTO_DELETE_TIMER_MS); + } + + private void testAcceptsDeclineWithAutoDeleteTimer(@Nullable Long timer) + throws Exception { + BdfList body = BdfList.of(DECLINE.getValue(), sessionId.getBytes(), + previousMsgId.getBytes(), timer); + + long autoDeleteTimer = timer == null ? NO_AUTO_DELETE_TIMER : timer; + expectEncodeMetadata(DECLINE, autoDeleteTimer); BdfMessageContext messageContext = validator.validateMessage(message, group, body); @@ -225,7 +381,7 @@ public class IntroductionValidatorTest extends ValidatorTestCase { @Test(expected = FormatException.class) public void testRejectsTooLongBodyForDecline() throws Exception { BdfList body = BdfList.of(DECLINE.getValue(), sessionId.getBytes(), - previousMsgId.getBytes(), null); + previousMsgId.getBytes(), null, null); validator.validateMessage(message, group, body); } @@ -242,6 +398,28 @@ public class IntroductionValidatorTest extends ValidatorTestCase { validator.validateMessage(message, group, body); } + @Test(expected = FormatException.class) + public void testRejectsNonLongAutoDeleteTimerForDecline() throws Exception { + BdfList body = BdfList.of(DECLINE.getValue(), sessionId.getBytes(), + previousMsgId.getBytes(), "foo"); + validator.validateMessage(message, group, body); + } + + @Test(expected = FormatException.class) + public void testRejectsTooSmallAutoDeleteTimerForDecline() + throws Exception { + BdfList body = BdfList.of(DECLINE.getValue(), sessionId.getBytes(), + previousMsgId.getBytes(), MIN_AUTO_DELETE_TIMER_MS - 1); + validator.validateMessage(message, group, body); + } + + @Test(expected = FormatException.class) + public void testRejectsTooBigAutoDeleteTimerForDecline() throws Exception { + BdfList body = BdfList.of(DECLINE.getValue(), sessionId.getBytes(), + previousMsgId.getBytes(), MAX_AUTO_DELETE_TIMER_MS + 1); + validator.validateMessage(message, group, body); + } + // // Introduction AUTH // @@ -251,7 +429,7 @@ public class IntroductionValidatorTest extends ValidatorTestCase { BdfList body = BdfList.of(AUTH.getValue(), sessionId.getBytes(), previousMsgId.getBytes(), mac, signature); - expectEncodeMetadata(AUTH); + expectEncodeMetadata(AUTH, NO_AUTO_DELETE_TIMER); BdfMessageContext messageContext = validator.validateMessage(message, group, body); @@ -340,7 +518,7 @@ public class IntroductionValidatorTest extends ValidatorTestCase { BdfList body = BdfList.of(ACTIVATE.getValue(), sessionId.getBytes(), previousMsgId.getBytes(), mac); - expectEncodeMetadata(ACTIVATE); + expectEncodeMetadata(ACTIVATE, NO_AUTO_DELETE_TIMER); BdfMessageContext messageContext = validator.validateMessage(message, group, body); @@ -398,7 +576,7 @@ public class IntroductionValidatorTest extends ValidatorTestCase { BdfList body = BdfList.of(ABORT.getValue(), sessionId.getBytes(), previousMsgId.getBytes()); - expectEncodeMetadata(ABORT); + expectEncodeMetadata(ABORT, NO_AUTO_DELETE_TIMER); BdfMessageContext messageContext = validator.validateMessage(message, group, body); @@ -442,17 +620,28 @@ public class IntroductionValidatorTest extends ValidatorTestCase { will(returnValue(ephemeralPublicKey)); }}); } - private void expectEncodeRequestMetadata() { + + private void expectParseTransportProperties() throws Exception { context.checking(new Expectations() {{ - oneOf(messageEncoder).encodeRequestMetadata(message.getTimestamp()); + oneOf(clientHelper).parseAndValidateTransportPropertiesMap( + transportProperties); + will(returnValue(transportPropertiesMap)); + }}); + } + + private void expectEncodeRequestMetadata(long autoDeleteTimer) { + context.checking(new Expectations() {{ + oneOf(messageEncoder).encodeRequestMetadata(message.getTimestamp(), + autoDeleteTimer); will(returnValue(meta)); }}); } - private void expectEncodeMetadata(MessageType type) { + private void expectEncodeMetadata(MessageType type, long autoDeleteTimer) { context.checking(new Expectations() {{ oneOf(messageEncoder).encodeMetadata(type, sessionId, - message.getTimestamp(), false, false, false); + message.getTimestamp(), false, false, false, + autoDeleteTimer); will(returnValue(meta)); }}); } diff --git a/briar-core/src/test/java/org/briarproject/briar/introduction/MessageEncoderParserIntegrationTest.java b/briar-core/src/test/java/org/briarproject/briar/introduction/MessageEncoderParserIntegrationTest.java index 21ea8024c..6ee624333 100644 --- a/briar-core/src/test/java/org/briarproject/briar/introduction/MessageEncoderParserIntegrationTest.java +++ b/briar-core/src/test/java/org/briarproject/briar/introduction/MessageEncoderParserIntegrationTest.java @@ -23,6 +23,8 @@ import java.util.Map; import javax.inject.Inject; +import static org.briarproject.bramble.api.autodelete.AutoDeleteConstants.MAX_AUTO_DELETE_TIMER_MS; +import static org.briarproject.bramble.api.autodelete.AutoDeleteConstants.MIN_AUTO_DELETE_TIMER_MS; import static org.briarproject.bramble.api.crypto.CryptoConstants.MAC_BYTES; import static org.briarproject.bramble.api.crypto.CryptoConstants.MAX_SIGNATURE_BYTES; import static org.briarproject.bramble.test.TestUtils.getAgreementPublicKey; @@ -88,7 +90,7 @@ public class MessageEncoderParserIntegrationTest extends BrambleTestCase { @Test public void testRequestMessageMetadata() throws FormatException { BdfDictionary d = messageEncoder - .encodeRequestMetadata(timestamp); + .encodeRequestMetadata(timestamp, MIN_AUTO_DELETE_TIMER_MS); MessageMetadata meta = messageParser.parseMetadata(d); assertEquals(REQUEST, meta.getMessageType()); @@ -98,13 +100,14 @@ public class MessageEncoderParserIntegrationTest extends BrambleTestCase { assertFalse(meta.isRead()); assertFalse(meta.isVisibleInConversation()); assertFalse(meta.isAvailableToAnswer()); + assertEquals(MIN_AUTO_DELETE_TIMER_MS, meta.getAutoDeleteTimer()); } @Test public void testMessageMetadata() throws FormatException { BdfDictionary d = messageEncoder .encodeMetadata(ABORT, sessionId, timestamp, false, true, - false); + false, MAX_AUTO_DELETE_TIMER_MS); MessageMetadata meta = messageParser.parseMetadata(d); assertEquals(ABORT, meta.getMessageType()); @@ -114,6 +117,7 @@ public class MessageEncoderParserIntegrationTest extends BrambleTestCase { assertTrue(meta.isRead()); assertFalse(meta.isVisibleInConversation()); assertFalse(meta.isAvailableToAnswer()); + assertEquals(MAX_AUTO_DELETE_TIMER_MS, meta.getAutoDeleteTimer()); } @Test From a427624e8dd3c7f382adffabe71fc3eb124b9af4 Mon Sep 17 00:00:00 2001 From: akwizgran Date: Thu, 19 Nov 2020 17:26:52 +0000 Subject: [PATCH 007/124] Update message parsing and encoding to include auto-delete timer. --- .../ConversationMessageHeader.java | 16 ++- .../api/conversation/ConversationRequest.java | 11 +- .../conversation/ConversationResponse.java | 4 +- .../api/introduction/IntroductionRequest.java | 8 +- .../introduction/IntroductionResponse.java | 5 +- .../api/messaging/PrivateMessageHeader.java | 8 +- .../briar/api/sharing/InvitationRequest.java | 4 +- .../briar/api/sharing/InvitationResponse.java | 5 +- .../briar/introduction/AbortMessage.java | 5 +- .../AbstractIntroductionMessage.java | 8 +- .../introduction/AbstractProtocolEngine.java | 105 ++++++++++---- .../briar/introduction/AcceptMessage.java | 6 +- .../briar/introduction/ActivateMessage.java | 5 +- .../briar/introduction/AuthMessage.java | 5 +- .../briar/introduction/DeclineMessage.java | 5 +- .../IntroduceeProtocolEngine.java | 8 +- .../IntroducerProtocolEngine.java | 4 +- .../introduction/IntroductionManagerImpl.java | 5 +- .../introduction/IntroductionValidator.java | 33 ++--- .../briar/introduction/MessageEncoder.java | 35 +++++ .../introduction/MessageEncoderImpl.java | 69 +++++++-- .../briar/introduction/MessageParserImpl.java | 12 +- .../briar/introduction/RequestMessage.java | 5 +- .../IntroductionIntegrationTest.java | 77 ++++++---- .../MessageEncoderParserIntegrationTest.java | 135 +++++++++++++++++- .../headless/event/WebSocketControllerTest.kt | 3 +- .../messaging/MessagingControllerImplTest.kt | 4 +- 27 files changed, 454 insertions(+), 136 deletions(-) diff --git a/briar-api/src/main/java/org/briarproject/briar/api/conversation/ConversationMessageHeader.java b/briar-api/src/main/java/org/briarproject/briar/api/conversation/ConversationMessageHeader.java index 58d4c2d54..e648869bb 100644 --- a/briar-api/src/main/java/org/briarproject/briar/api/conversation/ConversationMessageHeader.java +++ b/briar-api/src/main/java/org/briarproject/briar/api/conversation/ConversationMessageHeader.java @@ -12,18 +12,20 @@ public abstract class ConversationMessageHeader { private final MessageId id; private final GroupId groupId; - private final long timestamp; - private final boolean local, sent, seen, read; + private final long timestamp, autoDeleteTimer; + private final boolean local, read, sent, seen; - public ConversationMessageHeader(MessageId id, GroupId groupId, long timestamp, - boolean local, boolean read, boolean sent, boolean seen) { + public ConversationMessageHeader(MessageId id, GroupId groupId, + long timestamp, boolean local, boolean read, boolean sent, + boolean seen, long autoDeleteTimer) { this.id = id; this.groupId = groupId; this.timestamp = timestamp; this.local = local; + this.read = read; this.sent = sent; this.seen = seen; - this.read = read; + this.autoDeleteTimer = autoDeleteTimer; } public MessageId getId() { @@ -55,4 +57,8 @@ public abstract class ConversationMessageHeader { } public abstract T accept(ConversationMessageVisitor v); + + public long getAutoDeleteTimer() { + return autoDeleteTimer; + } } diff --git a/briar-api/src/main/java/org/briarproject/briar/api/conversation/ConversationRequest.java b/briar-api/src/main/java/org/briarproject/briar/api/conversation/ConversationRequest.java index 214d0d1d4..62d33ca46 100644 --- a/briar-api/src/main/java/org/briarproject/briar/api/conversation/ConversationRequest.java +++ b/briar-api/src/main/java/org/briarproject/briar/api/conversation/ConversationRequest.java @@ -20,11 +20,12 @@ public abstract class ConversationRequest private final String text; private final boolean answered; - public ConversationRequest(MessageId messageId, GroupId groupId, long time, - boolean local, boolean read, boolean sent, boolean seen, - SessionId sessionId, N nameable, @Nullable String text, - boolean answered) { - super(messageId, groupId, time, local, read, sent, seen); + public ConversationRequest(MessageId messageId, GroupId groupId, + long timestamp, boolean local, boolean read, boolean sent, + boolean seen, SessionId sessionId, N nameable, + @Nullable String text, boolean answered, long autoDeleteTimer) { + super(messageId, groupId, timestamp, local, read, sent, seen, + autoDeleteTimer); this.sessionId = sessionId; this.nameable = nameable; this.text = text; diff --git a/briar-api/src/main/java/org/briarproject/briar/api/conversation/ConversationResponse.java b/briar-api/src/main/java/org/briarproject/briar/api/conversation/ConversationResponse.java index cf6c879f0..974d87c4e 100644 --- a/briar-api/src/main/java/org/briarproject/briar/api/conversation/ConversationResponse.java +++ b/briar-api/src/main/java/org/briarproject/briar/api/conversation/ConversationResponse.java @@ -16,8 +16,8 @@ public abstract class ConversationResponse extends ConversationMessageHeader { public ConversationResponse(MessageId id, GroupId groupId, long time, boolean local, boolean read, boolean sent, boolean seen, - SessionId sessionId, boolean accepted) { - super(id, groupId, time, local, read, sent, seen); + SessionId sessionId, boolean accepted, long autoDeleteTimer) { + super(id, groupId, time, local, read, sent, seen, autoDeleteTimer); this.sessionId = sessionId; this.accepted = accepted; } diff --git a/briar-api/src/main/java/org/briarproject/briar/api/introduction/IntroductionRequest.java b/briar-api/src/main/java/org/briarproject/briar/api/introduction/IntroductionRequest.java index c6a5db547..bc342596e 100644 --- a/briar-api/src/main/java/org/briarproject/briar/api/introduction/IntroductionRequest.java +++ b/briar-api/src/main/java/org/briarproject/briar/api/introduction/IntroductionRequest.java @@ -18,12 +18,12 @@ public class IntroductionRequest extends ConversationRequest { private final AuthorInfo authorInfo; - public IntroductionRequest(MessageId messageId, GroupId groupId, - long time, boolean local, boolean read, boolean sent, boolean seen, + public IntroductionRequest(MessageId messageId, GroupId groupId, long time, + boolean local, boolean read, boolean sent, boolean seen, SessionId sessionId, Author author, @Nullable String text, - boolean answered, AuthorInfo authorInfo) { + boolean answered, AuthorInfo authorInfo, long autoDeleteTimer) { super(messageId, groupId, time, local, read, sent, seen, sessionId, - author, text, answered); + author, text, answered, autoDeleteTimer); this.authorInfo = authorInfo; } diff --git a/briar-api/src/main/java/org/briarproject/briar/api/introduction/IntroductionResponse.java b/briar-api/src/main/java/org/briarproject/briar/api/introduction/IntroductionResponse.java index 4b1777611..705b10a24 100644 --- a/briar-api/src/main/java/org/briarproject/briar/api/introduction/IntroductionResponse.java +++ b/briar-api/src/main/java/org/briarproject/briar/api/introduction/IntroductionResponse.java @@ -25,9 +25,10 @@ public class IntroductionResponse extends ConversationResponse { public IntroductionResponse(MessageId messageId, GroupId groupId, long time, boolean local, boolean read, boolean sent, boolean seen, SessionId sessionId, boolean accepted, Author author, - AuthorInfo introducedAuthorInfo, Role role, boolean canSucceed) { + AuthorInfo introducedAuthorInfo, Role role, boolean canSucceed, + long autoDeleteTimer) { super(messageId, groupId, time, local, read, sent, seen, sessionId, - accepted); + accepted, autoDeleteTimer); this.introducedAuthor = author; this.introducedAuthorInfo = introducedAuthorInfo; this.ourRole = role; diff --git a/briar-api/src/main/java/org/briarproject/briar/api/messaging/PrivateMessageHeader.java b/briar-api/src/main/java/org/briarproject/briar/api/messaging/PrivateMessageHeader.java index 369401982..afe3638b1 100644 --- a/briar-api/src/main/java/org/briarproject/briar/api/messaging/PrivateMessageHeader.java +++ b/briar-api/src/main/java/org/briarproject/briar/api/messaging/PrivateMessageHeader.java @@ -17,16 +17,14 @@ public class PrivateMessageHeader extends ConversationMessageHeader { private final boolean hasText; private final List attachmentHeaders; - private final long autoDeleteTimer; public PrivateMessageHeader(MessageId id, GroupId groupId, long timestamp, boolean local, boolean read, boolean sent, boolean seen, boolean hasText, List headers, long autoDeleteTimer) { - super(id, groupId, timestamp, local, read, sent, seen); + super(id, groupId, timestamp, local, read, sent, seen, autoDeleteTimer); this.hasText = hasText; this.attachmentHeaders = headers; - this.autoDeleteTimer = autoDeleteTimer; } public boolean hasText() { @@ -37,10 +35,6 @@ public class PrivateMessageHeader extends ConversationMessageHeader { return attachmentHeaders; } - public long getAutoDeleteTimer() { - return autoDeleteTimer; - } - @Override public T accept(ConversationMessageVisitor v) { return v.visitPrivateMessageHeader(this); diff --git a/briar-api/src/main/java/org/briarproject/briar/api/sharing/InvitationRequest.java b/briar-api/src/main/java/org/briarproject/briar/api/sharing/InvitationRequest.java index d122c8aea..432d71cf5 100644 --- a/briar-api/src/main/java/org/briarproject/briar/api/sharing/InvitationRequest.java +++ b/briar-api/src/main/java/org/briarproject/briar/api/sharing/InvitationRequest.java @@ -7,6 +7,8 @@ import org.briarproject.briar.api.conversation.ConversationRequest; import javax.annotation.Nullable; +import static org.briarproject.bramble.api.autodelete.AutoDeleteConstants.NO_AUTO_DELETE_TIMER; + public abstract class InvitationRequest extends ConversationRequest { @@ -17,7 +19,7 @@ public abstract class InvitationRequest extends SessionId sessionId, S object, @Nullable String text, boolean available, boolean canBeOpened) { super(messageId, groupId, time, local, read, sent, seen, sessionId, - object, text, !available); + object, text, !available, NO_AUTO_DELETE_TIMER); this.canBeOpened = canBeOpened; } diff --git a/briar-api/src/main/java/org/briarproject/briar/api/sharing/InvitationResponse.java b/briar-api/src/main/java/org/briarproject/briar/api/sharing/InvitationResponse.java index c5ae5c4d6..6a305cf7c 100644 --- a/briar-api/src/main/java/org/briarproject/briar/api/sharing/InvitationResponse.java +++ b/briar-api/src/main/java/org/briarproject/briar/api/sharing/InvitationResponse.java @@ -5,6 +5,8 @@ import org.briarproject.bramble.api.sync.MessageId; import org.briarproject.briar.api.client.SessionId; import org.briarproject.briar.api.conversation.ConversationResponse; +import static org.briarproject.bramble.api.autodelete.AutoDeleteConstants.NO_AUTO_DELETE_TIMER; + public abstract class InvitationResponse extends ConversationResponse { private final GroupId shareableId; @@ -12,7 +14,8 @@ public abstract class InvitationResponse extends ConversationResponse { public InvitationResponse(MessageId id, GroupId groupId, long time, boolean local, boolean read, boolean sent, boolean seen, SessionId sessionId, boolean accepted, GroupId shareableId) { - super(id, groupId, time, local, read, sent, seen, sessionId, accepted); + super(id, groupId, time, local, read, sent, seen, sessionId, accepted, + NO_AUTO_DELETE_TIMER); this.shareableId = shareableId; } diff --git a/briar-core/src/main/java/org/briarproject/briar/introduction/AbortMessage.java b/briar-core/src/main/java/org/briarproject/briar/introduction/AbortMessage.java index e9a2d1233..af98a1da2 100644 --- a/briar-core/src/main/java/org/briarproject/briar/introduction/AbortMessage.java +++ b/briar-core/src/main/java/org/briarproject/briar/introduction/AbortMessage.java @@ -8,6 +8,8 @@ import org.briarproject.briar.api.client.SessionId; import javax.annotation.Nullable; import javax.annotation.concurrent.Immutable; +import static org.briarproject.bramble.api.autodelete.AutoDeleteConstants.NO_AUTO_DELETE_TIMER; + @Immutable @NotNullByDefault class AbortMessage extends AbstractIntroductionMessage { @@ -16,7 +18,8 @@ class AbortMessage extends AbstractIntroductionMessage { protected AbortMessage(MessageId messageId, GroupId groupId, long timestamp, @Nullable MessageId previousMessageId, SessionId sessionId) { - super(messageId, groupId, timestamp, previousMessageId); + super(messageId, groupId, timestamp, previousMessageId, + NO_AUTO_DELETE_TIMER); this.sessionId = sessionId; } diff --git a/briar-core/src/main/java/org/briarproject/briar/introduction/AbstractIntroductionMessage.java b/briar-core/src/main/java/org/briarproject/briar/introduction/AbstractIntroductionMessage.java index 240b5ddec..d72130337 100644 --- a/briar-core/src/main/java/org/briarproject/briar/introduction/AbstractIntroductionMessage.java +++ b/briar-core/src/main/java/org/briarproject/briar/introduction/AbstractIntroductionMessage.java @@ -16,13 +16,16 @@ abstract class AbstractIntroductionMessage { private final long timestamp; @Nullable private final MessageId previousMessageId; + private final long autoDeleteTimer; AbstractIntroductionMessage(MessageId messageId, GroupId groupId, - long timestamp, @Nullable MessageId previousMessageId) { + long timestamp, @Nullable MessageId previousMessageId, + long autoDeleteTimer) { this.messageId = messageId; this.groupId = groupId; this.timestamp = timestamp; this.previousMessageId = previousMessageId; + this.autoDeleteTimer = autoDeleteTimer; } MessageId getMessageId() { @@ -42,4 +45,7 @@ abstract class AbstractIntroductionMessage { return previousMessageId; } + public long getAutoDeleteTimer() { + return autoDeleteTimer; + } } 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 9f7d5febe..89885a12a 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 @@ -4,6 +4,7 @@ import org.briarproject.bramble.api.FormatException; import org.briarproject.bramble.api.client.ClientHelper; import org.briarproject.bramble.api.client.ContactGroupFactory; import org.briarproject.bramble.api.contact.Contact; +import org.briarproject.bramble.api.contact.ContactId; import org.briarproject.bramble.api.contact.ContactManager; import org.briarproject.bramble.api.crypto.PublicKey; import org.briarproject.bramble.api.data.BdfDictionary; @@ -16,9 +17,11 @@ import org.briarproject.bramble.api.identity.IdentityManager; import org.briarproject.bramble.api.nullsafety.NotNullByDefault; import org.briarproject.bramble.api.plugin.TransportId; import org.briarproject.bramble.api.properties.TransportProperties; +import org.briarproject.bramble.api.sync.GroupId; import org.briarproject.bramble.api.sync.Message; import org.briarproject.bramble.api.sync.MessageId; import org.briarproject.bramble.api.system.Clock; +import org.briarproject.bramble.api.versioning.ClientVersioningManager; import org.briarproject.briar.api.client.MessageTracker; import org.briarproject.briar.api.client.SessionId; import org.briarproject.briar.api.identity.AuthorInfo; @@ -32,6 +35,9 @@ import javax.annotation.Nullable; import javax.annotation.concurrent.Immutable; import static org.briarproject.bramble.api.autodelete.AutoDeleteConstants.NO_AUTO_DELETE_TIMER; +import static org.briarproject.briar.api.introduction.IntroductionManager.CLIENT_ID; +import static org.briarproject.briar.api.introduction.IntroductionManager.MAJOR_VERSION; +import static org.briarproject.briar.introduction.IntroductionConstants.GROUP_KEY_CONTACT_ID; import static org.briarproject.briar.introduction.MessageType.ABORT; import static org.briarproject.briar.introduction.MessageType.ACCEPT; import static org.briarproject.briar.introduction.MessageType.ACTIVATE; @@ -53,6 +59,7 @@ abstract class AbstractProtocolEngine> protected final AuthorManager authorManager; protected final MessageParser messageParser; protected final MessageEncoder messageEncoder; + protected final ClientVersioningManager clientVersioningManager; protected final Clock clock; AbstractProtocolEngine( @@ -65,6 +72,7 @@ abstract class AbstractProtocolEngine> AuthorManager authorManager, MessageParser messageParser, MessageEncoder messageEncoder, + ClientVersioningManager clientVersioningManager, Clock clock) { this.db = db; this.clientHelper = clientHelper; @@ -75,16 +83,26 @@ abstract class AbstractProtocolEngine> this.authorManager = authorManager; this.messageParser = messageParser; this.messageEncoder = messageEncoder; + this.clientVersioningManager = clientVersioningManager; this.clock = clock; } Message sendRequestMessage(Transaction txn, PeerSession s, long timestamp, Author author, @Nullable String text) throws DbException { - Message m = messageEncoder - .encodeRequestMessage(s.getContactGroupId(), timestamp, - s.getLastLocalMessageId(), author, text); - sendMessage(txn, REQUEST, s.getSessionId(), m, true); + Message m; + if (contactSupportsAutoDeletion(txn, s.getContactGroupId())) { + // TODO: Look up the current auto-delete timer + long timer = NO_AUTO_DELETE_TIMER; + m = messageEncoder.encodeRequestMessage(s.getContactGroupId(), + timestamp, s.getLastLocalMessageId(), author, text, timer); + sendMessage(txn, REQUEST, s.getSessionId(), m, true, timer); + } else { + m = messageEncoder.encodeRequestMessage(s.getContactGroupId(), + timestamp, s.getLastLocalMessageId(), author, text); + sendMessage(txn, REQUEST, s.getSessionId(), m, true, + NO_AUTO_DELETE_TIMER); + } return m; } @@ -92,21 +110,41 @@ abstract class AbstractProtocolEngine> PublicKey ephemeralPublicKey, long acceptTimestamp, Map transportProperties, boolean visible) throws DbException { - Message m = messageEncoder - .encodeAcceptMessage(s.getContactGroupId(), timestamp, - s.getLastLocalMessageId(), s.getSessionId(), - ephemeralPublicKey, acceptTimestamp, - transportProperties); - sendMessage(txn, ACCEPT, s.getSessionId(), m, visible); + Message m; + if (contactSupportsAutoDeletion(txn, s.getContactGroupId())) { + // TODO: Look up the current auto-delete timer + long timer = NO_AUTO_DELETE_TIMER; + m = messageEncoder.encodeAcceptMessage(s.getContactGroupId(), + timestamp, s.getLastLocalMessageId(), s.getSessionId(), + ephemeralPublicKey, acceptTimestamp, transportProperties, + timer); + sendMessage(txn, ACCEPT, s.getSessionId(), m, visible, timer); + } else { + m = messageEncoder.encodeAcceptMessage(s.getContactGroupId(), + timestamp, s.getLastLocalMessageId(), s.getSessionId(), + ephemeralPublicKey, acceptTimestamp, transportProperties); + sendMessage(txn, ACCEPT, s.getSessionId(), m, visible, + NO_AUTO_DELETE_TIMER); + } return m; } Message sendDeclineMessage(Transaction txn, PeerSession s, long timestamp, boolean visible) throws DbException { - Message m = messageEncoder - .encodeDeclineMessage(s.getContactGroupId(), timestamp, - s.getLastLocalMessageId(), s.getSessionId()); - sendMessage(txn, DECLINE, s.getSessionId(), m, visible); + Message m; + if (contactSupportsAutoDeletion(txn, s.getContactGroupId())) { + // TODO: Look up the current auto-delete timer + long timer = NO_AUTO_DELETE_TIMER; + m = messageEncoder.encodeDeclineMessage(s.getContactGroupId(), + timestamp, s.getLastLocalMessageId(), s.getSessionId(), + timer); + sendMessage(txn, DECLINE, s.getSessionId(), m, visible, timer); + } else { + m = messageEncoder.encodeDeclineMessage(s.getContactGroupId(), + timestamp, s.getLastLocalMessageId(), s.getSessionId()); + sendMessage(txn, DECLINE, s.getSessionId(), m, visible, + NO_AUTO_DELETE_TIMER); + } return m; } @@ -116,7 +154,8 @@ abstract class AbstractProtocolEngine> .encodeAuthMessage(s.getContactGroupId(), timestamp, s.getLastLocalMessageId(), s.getSessionId(), mac, signature); - sendMessage(txn, AUTH, s.getSessionId(), m, false); + sendMessage(txn, AUTH, s.getSessionId(), m, false, + NO_AUTO_DELETE_TIMER); return m; } @@ -125,7 +164,8 @@ abstract class AbstractProtocolEngine> Message m = messageEncoder .encodeActivateMessage(s.getContactGroupId(), timestamp, s.getLastLocalMessageId(), s.getSessionId(), mac); - sendMessage(txn, ACTIVATE, s.getSessionId(), m, false); + sendMessage(txn, ACTIVATE, s.getSessionId(), m, false, + NO_AUTO_DELETE_TIMER); return m; } @@ -134,18 +174,17 @@ abstract class AbstractProtocolEngine> Message m = messageEncoder .encodeAbortMessage(s.getContactGroupId(), timestamp, s.getLastLocalMessageId(), s.getSessionId()); - sendMessage(txn, ABORT, s.getSessionId(), m, false); + sendMessage(txn, ABORT, s.getSessionId(), m, false, + NO_AUTO_DELETE_TIMER); return m; } private void sendMessage(Transaction txn, MessageType type, - SessionId sessionId, Message m, boolean visibleInConversation) - throws DbException { - // TODO: If message is visible in conversation, look up current - // auto-delete timer and include it in message - BdfDictionary meta = messageEncoder - .encodeMetadata(type, sessionId, m.getTimestamp(), true, true, - visibleInConversation, NO_AUTO_DELETE_TIMER); + SessionId sessionId, Message m, boolean visibleInConversation, + long autoDeleteTimer) throws DbException { + BdfDictionary meta = messageEncoder.encodeMetadata(type, sessionId, + m.getTimestamp(), true, true, visibleInConversation, + autoDeleteTimer); try { clientHelper.addLocalMessage(txn, m, meta, true, false); } catch (FormatException e) { @@ -165,7 +204,8 @@ abstract class AbstractProtocolEngine> new IntroductionResponse(m.getMessageId(), m.getGroupId(), m.getTimestamp(), false, false, false, false, s.getSessionId(), m instanceof AcceptMessage, - otherAuthor, otherAuthorInfo, s.getRole(), canSucceed); + otherAuthor, otherAuthorInfo, s.getRole(), canSucceed, + m.getAutoDeleteTimer()); IntroductionResponseReceivedEvent e = new IntroductionResponseReceivedEvent(response, c.getId()); txn.attach(e); @@ -198,4 +238,19 @@ abstract class AbstractProtocolEngine> ); } + boolean contactSupportsAutoDeletion(Transaction txn, GroupId contactGroupId) + throws DbException { + try { + BdfDictionary meta = clientHelper + .getGroupMetadataAsDictionary(txn, contactGroupId); + int contactId = meta.getLong(GROUP_KEY_CONTACT_ID).intValue(); + ContactId c = new ContactId(contactId); + int minorVersion = clientVersioningManager + .getClientMinorVersion(txn, c, CLIENT_ID, MAJOR_VERSION); + // Auto-delete was added in client version 0.1 + return minorVersion >= 1; + } catch (FormatException e) { + throw new DbException(e); + } + } } diff --git a/briar-core/src/main/java/org/briarproject/briar/introduction/AcceptMessage.java b/briar-core/src/main/java/org/briarproject/briar/introduction/AcceptMessage.java index d76957616..e021ff7f8 100644 --- a/briar-core/src/main/java/org/briarproject/briar/introduction/AcceptMessage.java +++ b/briar-core/src/main/java/org/briarproject/briar/introduction/AcceptMessage.java @@ -26,8 +26,10 @@ class AcceptMessage extends AbstractIntroductionMessage { long timestamp, @Nullable MessageId previousMessageId, SessionId sessionId, PublicKey ephemeralPublicKey, long acceptTimestamp, - Map transportProperties) { - super(messageId, groupId, timestamp, previousMessageId); + Map transportProperties, + long autoDeleteTimer) { + super(messageId, groupId, timestamp, previousMessageId, + autoDeleteTimer); this.sessionId = sessionId; this.ephemeralPublicKey = ephemeralPublicKey; this.acceptTimestamp = acceptTimestamp; diff --git a/briar-core/src/main/java/org/briarproject/briar/introduction/ActivateMessage.java b/briar-core/src/main/java/org/briarproject/briar/introduction/ActivateMessage.java index 5f767737d..5c2f25375 100644 --- a/briar-core/src/main/java/org/briarproject/briar/introduction/ActivateMessage.java +++ b/briar-core/src/main/java/org/briarproject/briar/introduction/ActivateMessage.java @@ -7,6 +7,8 @@ import org.briarproject.briar.api.client.SessionId; import javax.annotation.concurrent.Immutable; +import static org.briarproject.bramble.api.autodelete.AutoDeleteConstants.NO_AUTO_DELETE_TIMER; + @Immutable @NotNullByDefault class ActivateMessage extends AbstractIntroductionMessage { @@ -17,7 +19,8 @@ class ActivateMessage extends AbstractIntroductionMessage { protected ActivateMessage(MessageId messageId, GroupId groupId, long timestamp, MessageId previousMessageId, SessionId sessionId, byte[] mac) { - super(messageId, groupId, timestamp, previousMessageId); + super(messageId, groupId, timestamp, previousMessageId, + NO_AUTO_DELETE_TIMER); this.sessionId = sessionId; this.mac = mac; } diff --git a/briar-core/src/main/java/org/briarproject/briar/introduction/AuthMessage.java b/briar-core/src/main/java/org/briarproject/briar/introduction/AuthMessage.java index 1de1a4eb5..01bdcae33 100644 --- a/briar-core/src/main/java/org/briarproject/briar/introduction/AuthMessage.java +++ b/briar-core/src/main/java/org/briarproject/briar/introduction/AuthMessage.java @@ -7,6 +7,8 @@ import org.briarproject.briar.api.client.SessionId; import javax.annotation.concurrent.Immutable; +import static org.briarproject.bramble.api.autodelete.AutoDeleteConstants.NO_AUTO_DELETE_TIMER; + @Immutable @NotNullByDefault class AuthMessage extends AbstractIntroductionMessage { @@ -17,7 +19,8 @@ class AuthMessage extends AbstractIntroductionMessage { protected AuthMessage(MessageId messageId, GroupId groupId, long timestamp, MessageId previousMessageId, SessionId sessionId, byte[] mac, byte[] signature) { - super(messageId, groupId, timestamp, previousMessageId); + super(messageId, groupId, timestamp, previousMessageId, + NO_AUTO_DELETE_TIMER); this.sessionId = sessionId; this.mac = mac; this.signature = signature; diff --git a/briar-core/src/main/java/org/briarproject/briar/introduction/DeclineMessage.java b/briar-core/src/main/java/org/briarproject/briar/introduction/DeclineMessage.java index 27386b905..631312019 100644 --- a/briar-core/src/main/java/org/briarproject/briar/introduction/DeclineMessage.java +++ b/briar-core/src/main/java/org/briarproject/briar/introduction/DeclineMessage.java @@ -16,8 +16,9 @@ class DeclineMessage extends AbstractIntroductionMessage { protected DeclineMessage(MessageId messageId, GroupId groupId, long timestamp, @Nullable MessageId previousMessageId, - SessionId sessionId) { - super(messageId, groupId, timestamp, previousMessageId); + SessionId sessionId, long autoDeleteTimer) { + super(messageId, groupId, timestamp, previousMessageId, + autoDeleteTimer); this.sessionId = sessionId; } 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 8d7dd4a46..4beba3fb5 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 @@ -25,6 +25,7 @@ import org.briarproject.bramble.api.sync.MessageId; import org.briarproject.bramble.api.system.Clock; import org.briarproject.bramble.api.transport.KeyManager; import org.briarproject.bramble.api.transport.KeySetId; +import org.briarproject.bramble.api.versioning.ClientVersioningManager; import org.briarproject.briar.api.client.MessageTracker; import org.briarproject.briar.api.client.ProtocolStateException; import org.briarproject.briar.api.client.SessionId; @@ -78,10 +79,11 @@ class IntroduceeProtocolEngine Clock clock, IntroductionCrypto crypto, KeyManager keyManager, - TransportPropertyManager transportPropertyManager) { + TransportPropertyManager transportPropertyManager, + ClientVersioningManager clientVersioningManager) { super(db, clientHelper, contactManager, contactGroupFactory, messageTracker, identityManager, authorManager, messageParser, - messageEncoder, clock); + messageEncoder, clientVersioningManager, clock); this.crypto = crypto; this.keyManager = keyManager; this.transportPropertyManager = transportPropertyManager; @@ -260,7 +262,7 @@ class IntroduceeProtocolEngine IntroductionRequest request = new IntroductionRequest(m.getMessageId(), m.getGroupId(), m.getTimestamp(), false, false, false, false, s.getSessionId(), m.getAuthor(), m.getText(), false, - authorInfo); + authorInfo, m.getAutoDeleteTimer()); IntroductionRequestReceivedEvent e = new IntroductionRequestReceivedEvent(request, c.getId()); txn.attach(e); 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 39f2faf5a..8978c917a 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 @@ -13,6 +13,7 @@ import org.briarproject.bramble.api.sync.GroupId; import org.briarproject.bramble.api.sync.Message; import org.briarproject.bramble.api.sync.MessageId; import org.briarproject.bramble.api.system.Clock; +import org.briarproject.bramble.api.versioning.ClientVersioningManager; import org.briarproject.briar.api.client.MessageTracker; import org.briarproject.briar.api.client.ProtocolStateException; import org.briarproject.briar.api.identity.AuthorManager; @@ -52,10 +53,11 @@ class IntroducerProtocolEngine AuthorManager authorManager, MessageParser messageParser, MessageEncoder messageEncoder, + ClientVersioningManager clientVersioningManager, Clock clock) { super(db, clientHelper, contactManager, contactGroupFactory, messageTracker, identityManager, authorManager, messageParser, - messageEncoder, clock); + messageEncoder, clientVersioningManager, clock); } @Override 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 dd88159c8..70eee9b45 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 @@ -465,7 +465,7 @@ class IntroductionManagerImpl extends ConversationClientImpl return new IntroductionRequest(m, contactGroupId, meta.getTimestamp(), meta.isLocal(), meta.isRead(), status.isSent(), status.isSeen(), sessionId, author, text, !meta.isAvailableToAnswer(), - authorInfo); + authorInfo, rm.getAutoDeleteTimer()); } private IntroductionResponse parseInvitationResponse(Transaction txn, @@ -503,7 +503,8 @@ class IntroductionManagerImpl extends ConversationClientImpl } return new IntroductionResponse(m, contactGroupId, meta.getTimestamp(), meta.isLocal(), meta.isRead(), status.isSent(), status.isSeen(), - sessionId, accept, author, authorInfo, role, canSucceed); + sessionId, accept, author, authorInfo, role, canSucceed, + meta.getAutoDeleteTimer()); } private void removeSessionWithIntroducer(Transaction txn, diff --git a/briar-core/src/main/java/org/briarproject/briar/introduction/IntroductionValidator.java b/briar-core/src/main/java/org/briarproject/briar/introduction/IntroductionValidator.java index 7b78cbf47..0112b4a23 100644 --- a/briar-core/src/main/java/org/briarproject/briar/introduction/IntroductionValidator.java +++ b/briar-core/src/main/java/org/briarproject/briar/introduction/IntroductionValidator.java @@ -15,6 +15,7 @@ import org.briarproject.bramble.api.sync.MessageId; import org.briarproject.bramble.api.system.Clock; import org.briarproject.briar.api.client.SessionId; +import javax.annotation.Nullable; import javax.annotation.concurrent.Immutable; import static java.util.Collections.singletonList; @@ -86,13 +87,8 @@ class IntroductionValidator extends BdfMessageValidator { String text = body.getOptionalString(3); checkLength(text, 1, MAX_INTRODUCTION_TEXT_LENGTH); - Long timer = null; - if (body.size() == 5) { - timer = body.getOptionalLong(4); - checkRange(timer, MIN_AUTO_DELETE_TIMER_MS, - MAX_AUTO_DELETE_TIMER_MS); - } - if (timer == null) timer = NO_AUTO_DELETE_TIMER; + long timer = NO_AUTO_DELETE_TIMER; + if (body.size() == 5) timer = validateTimer(body.getOptionalLong(4)); BdfDictionary meta = messageEncoder.encodeRequestMetadata(m.getTimestamp(), timer); @@ -131,13 +127,8 @@ class IntroductionValidator extends BdfMessageValidator { clientHelper .parseAndValidateTransportPropertiesMap(transportProperties); - Long timer = null; - if (body.size() == 7) { - timer = body.getOptionalLong(6); - checkRange(timer, MIN_AUTO_DELETE_TIMER_MS, - MAX_AUTO_DELETE_TIMER_MS); - } - if (timer == null) timer = NO_AUTO_DELETE_TIMER; + long timer = NO_AUTO_DELETE_TIMER; + if (body.size() == 7) timer = validateTimer(body.getOptionalLong(6)); SessionId sessionId = new SessionId(sessionIdBytes); BdfDictionary meta = messageEncoder.encodeMetadata(ACCEPT, sessionId, @@ -164,13 +155,8 @@ class IntroductionValidator extends BdfMessageValidator { byte[] previousMessageId = body.getOptionalRaw(2); checkLength(previousMessageId, UniqueId.LENGTH); - Long timer = null; - if (body.size() == 4) { - timer = body.getOptionalLong(3); - checkRange(timer, MIN_AUTO_DELETE_TIMER_MS, - MAX_AUTO_DELETE_TIMER_MS); - } - if (timer == null) timer = NO_AUTO_DELETE_TIMER; + long timer = NO_AUTO_DELETE_TIMER; + if (body.size() == 4) timer = validateTimer(body.getOptionalLong(3)); SessionId sessionId = new SessionId(sessionIdBytes); BdfDictionary meta = messageEncoder.encodeMetadata(type, sessionId, @@ -251,4 +237,9 @@ class IntroductionValidator extends BdfMessageValidator { } } + private long validateTimer(@Nullable Long timer) throws FormatException { + if (timer == null) return NO_AUTO_DELETE_TIMER; + checkRange(timer, MIN_AUTO_DELETE_TIMER_MS, MAX_AUTO_DELETE_TIMER_MS); + return timer; + } } diff --git a/briar-core/src/main/java/org/briarproject/briar/introduction/MessageEncoder.java b/briar-core/src/main/java/org/briarproject/briar/introduction/MessageEncoder.java index 2357f7277..85fa4d4aa 100644 --- a/briar-core/src/main/java/org/briarproject/briar/introduction/MessageEncoder.java +++ b/briar-core/src/main/java/org/briarproject/briar/introduction/MessageEncoder.java @@ -31,18 +31,53 @@ interface MessageEncoder { void setAvailableToAnswer(BdfDictionary meta, boolean available); + /** + * Encodes a request message without an auto-delete timer. + */ Message encodeRequestMessage(GroupId contactGroupId, long timestamp, @Nullable MessageId previousMessageId, Author author, @Nullable String text); + /** + * Encodes a request message with an optional auto-delete timer. This + * requires the contact to support client version 0.1 or higher. + */ + Message encodeRequestMessage(GroupId contactGroupId, long timestamp, + @Nullable MessageId previousMessageId, Author author, + @Nullable String text, long autoDeleteTimer); + + /** + * Encodes an accept message without an auto-delete timer. + */ Message encodeAcceptMessage(GroupId contactGroupId, long timestamp, @Nullable MessageId previousMessageId, SessionId sessionId, PublicKey ephemeralPublicKey, long acceptTimestamp, Map transportProperties); + /** + * Encodes an accept message with an optional auto-delete timer. This + * requires the contact to support client version 0.1 or higher. + */ + Message encodeAcceptMessage(GroupId contactGroupId, long timestamp, + @Nullable MessageId previousMessageId, SessionId sessionId, + PublicKey ephemeralPublicKey, long acceptTimestamp, + Map transportProperties, + long autoDeleteTimer); + + /** + * Encodes a decline message without an auto-delete timer. + */ Message encodeDeclineMessage(GroupId contactGroupId, long timestamp, @Nullable MessageId previousMessageId, SessionId sessionId); + /** + * Encodes a decline message with an optional auto-delete timer. This + * requires the contact to support client version 0.1 or higher. + */ + Message encodeDeclineMessage(GroupId contactGroupId, long timestamp, + @Nullable MessageId previousMessageId, SessionId sessionId, + long autoDeleteTimer); + Message encodeAuthMessage(GroupId contactGroupId, long timestamp, @Nullable MessageId previousMessageId, SessionId sessionId, byte[] mac, byte[] signature); diff --git a/briar-core/src/main/java/org/briarproject/briar/introduction/MessageEncoderImpl.java b/briar-core/src/main/java/org/briarproject/briar/introduction/MessageEncoderImpl.java index 901b37cd7..ecb5dbccb 100644 --- a/briar-core/src/main/java/org/briarproject/briar/introduction/MessageEncoderImpl.java +++ b/briar-core/src/main/java/org/briarproject/briar/introduction/MessageEncoderImpl.java @@ -109,6 +109,23 @@ class MessageEncoderImpl implements MessageEncoder { return createMessage(contactGroupId, timestamp, body); } + @Override + public Message encodeRequestMessage(GroupId contactGroupId, long timestamp, + @Nullable MessageId previousMessageId, Author author, + @Nullable String text, long autoDeleteTimer) { + if (text != null && text.isEmpty()) { + throw new IllegalArgumentException(); + } + BdfList body = BdfList.of( + REQUEST.getValue(), + previousMessageId, + clientHelper.toList(author), + text, + encodeTimer(autoDeleteTimer) + ); + return createMessage(contactGroupId, timestamp, body); + } + @Override public Message encodeAcceptMessage(GroupId contactGroupId, long timestamp, @Nullable MessageId previousMessageId, SessionId sessionId, @@ -125,11 +142,46 @@ class MessageEncoderImpl implements MessageEncoder { return createMessage(contactGroupId, timestamp, body); } + @Override + public Message encodeAcceptMessage(GroupId contactGroupId, long timestamp, + @Nullable MessageId previousMessageId, SessionId sessionId, + PublicKey ephemeralPublicKey, long acceptTimestamp, + Map transportProperties, + long autoDeleteTimer) { + BdfList body = BdfList.of( + ACCEPT.getValue(), + sessionId, + previousMessageId, + ephemeralPublicKey.getEncoded(), + acceptTimestamp, + clientHelper.toDictionary(transportProperties), + encodeTimer(autoDeleteTimer) + ); + return createMessage(contactGroupId, timestamp, body); + } + @Override public Message encodeDeclineMessage(GroupId contactGroupId, long timestamp, @Nullable MessageId previousMessageId, SessionId sessionId) { - return encodeMessage(DECLINE, contactGroupId, sessionId, timestamp, - previousMessageId); + BdfList body = BdfList.of( + DECLINE.getValue(), + sessionId, + previousMessageId + ); + return createMessage(contactGroupId, timestamp, body); + } + + @Override + public Message encodeDeclineMessage(GroupId contactGroupId, long timestamp, + @Nullable MessageId previousMessageId, SessionId sessionId, + long autoDeleteTimer) { + BdfList body = BdfList.of( + DECLINE.getValue(), + sessionId, + previousMessageId, + encodeTimer(autoDeleteTimer) + ); + return createMessage(contactGroupId, timestamp, body); } @Override @@ -162,15 +214,8 @@ class MessageEncoderImpl implements MessageEncoder { @Override public Message encodeAbortMessage(GroupId contactGroupId, long timestamp, @Nullable MessageId previousMessageId, SessionId sessionId) { - return encodeMessage(ABORT, contactGroupId, sessionId, timestamp, - previousMessageId); - } - - private Message encodeMessage(MessageType type, GroupId contactGroupId, - SessionId sessionId, long timestamp, - @Nullable MessageId previousMessageId) { BdfList body = BdfList.of( - type.getValue(), + ABORT.getValue(), sessionId, previousMessageId ); @@ -187,4 +232,8 @@ class MessageEncoderImpl implements MessageEncoder { } } + @Nullable + private Long encodeTimer(long autoDeleteTimer) { + return autoDeleteTimer == NO_AUTO_DELETE_TIMER ? null : autoDeleteTimer; + } } diff --git a/briar-core/src/main/java/org/briarproject/briar/introduction/MessageParserImpl.java b/briar-core/src/main/java/org/briarproject/briar/introduction/MessageParserImpl.java index 1e6808c06..bc4160d1e 100644 --- a/briar-core/src/main/java/org/briarproject/briar/introduction/MessageParserImpl.java +++ b/briar-core/src/main/java/org/briarproject/briar/introduction/MessageParserImpl.java @@ -80,8 +80,10 @@ class MessageParserImpl implements MessageParser { new MessageId(previousMsgBytes)); Author author = clientHelper.parseAndValidateAuthor(body.getList(2)); String text = body.getOptionalString(3); + long timer = NO_AUTO_DELETE_TIMER; + if (body.size() == 5) timer = body.getLong(4, NO_AUTO_DELETE_TIMER); return new RequestMessage(m.getId(), m.getGroupId(), - m.getTimestamp(), previousMessageId, author, text); + m.getTimestamp(), previousMessageId, author, text, timer); } @Override @@ -95,9 +97,11 @@ class MessageParserImpl implements MessageParser { long acceptTimestamp = body.getLong(4); Map transportProperties = clientHelper .parseAndValidateTransportPropertiesMap(body.getDictionary(5)); + long timer = NO_AUTO_DELETE_TIMER; + if (body.size() == 7) timer = body.getLong(6, NO_AUTO_DELETE_TIMER); return new AcceptMessage(m.getId(), m.getGroupId(), m.getTimestamp(), previousMessageId, sessionId, ephemeralPublicKey, - acceptTimestamp, transportProperties); + acceptTimestamp, transportProperties, timer); } @Override @@ -107,8 +111,10 @@ class MessageParserImpl implements MessageParser { byte[] previousMsgBytes = body.getOptionalRaw(2); MessageId previousMessageId = (previousMsgBytes == null ? null : new MessageId(previousMsgBytes)); + long timer = NO_AUTO_DELETE_TIMER; + if (body.size() == 4) timer = body.getLong(3, NO_AUTO_DELETE_TIMER); return new DeclineMessage(m.getId(), m.getGroupId(), m.getTimestamp(), - previousMessageId, sessionId); + previousMessageId, sessionId, timer); } @Override diff --git a/briar-core/src/main/java/org/briarproject/briar/introduction/RequestMessage.java b/briar-core/src/main/java/org/briarproject/briar/introduction/RequestMessage.java index f6d8d4870..b192f5e78 100644 --- a/briar-core/src/main/java/org/briarproject/briar/introduction/RequestMessage.java +++ b/briar-core/src/main/java/org/briarproject/briar/introduction/RequestMessage.java @@ -18,8 +18,9 @@ class RequestMessage extends AbstractIntroductionMessage { RequestMessage(MessageId messageId, GroupId groupId, long timestamp, @Nullable MessageId previousMessageId, Author author, - @Nullable String text) { - super(messageId, groupId, timestamp, previousMessageId); + @Nullable String text, long autoDeleteTimer) { + super(messageId, groupId, timestamp, previousMessageId, + autoDeleteTimer); this.author = author; this.text = text; } 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 cee9a8bba..e13aa0aee 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 @@ -45,6 +45,7 @@ import java.util.Map; import java.util.Set; import static java.util.Collections.emptySet; +import static org.briarproject.bramble.api.autodelete.AutoDeleteConstants.NO_AUTO_DELETE_TIMER; import static org.briarproject.bramble.test.TestPluginConfigModule.SIMPLEX_TRANSPORT_ID; import static org.briarproject.bramble.test.TestUtils.getAgreementPublicKey; import static org.briarproject.bramble.test.TestUtils.getSecretKey; @@ -1114,7 +1115,7 @@ public class IntroductionIntegrationTest m.getTimestamp(), m.getPreviousMessageId(), m.getSessionId(), m.getEphemeralPublicKey(), m.getAcceptTimestamp(), - getTransportPropertiesMap(2)) + getTransportPropertiesMap(2), NO_AUTO_DELETE_TIMER) ); } @@ -1125,7 +1126,7 @@ public class IntroductionIntegrationTest m.getTimestamp(), m.getPreviousMessageId(), m.getSessionId(), m.getEphemeralPublicKey(), clock.currentTimeMillis(), - m.getTransportProperties()) + m.getTransportProperties(), NO_AUTO_DELETE_TIMER) ); } @@ -1135,7 +1136,8 @@ public class IntroductionIntegrationTest m -> new AcceptMessage(m.getMessageId(), m.getGroupId(), m.getTimestamp(), m.getPreviousMessageId(), m.getSessionId(), getAgreementPublicKey(), - m.getAcceptTimestamp(), m.getTransportProperties()) + m.getAcceptTimestamp(), m.getTransportProperties(), + NO_AUTO_DELETE_TIMER) ); } @@ -1155,10 +1157,12 @@ public class IntroductionIntegrationTest // introducer can not yet remove messages assertFalse(deleteAllMessages1From0().allDeleted()); - assertTrue(deleteAllMessages1From0().hasIntroductionSessionInProgress()); + assertTrue( + deleteAllMessages1From0().hasIntroductionSessionInProgress()); // introducee1 can not yet remove messages assertFalse(deleteAllMessages0From1().allDeleted()); - assertTrue(deleteAllMessages0From1().hasIntroductionSessionInProgress()); + assertTrue( + deleteAllMessages0From1().hasIntroductionSessionInProgress()); // sync second REQUEST message sync0To2(1, true); @@ -1166,10 +1170,12 @@ public class IntroductionIntegrationTest // introducer can not yet remove messages assertFalse(deleteAllMessages2From0().allDeleted()); - assertTrue(deleteAllMessages2From0().hasIntroductionSessionInProgress()); + assertTrue( + deleteAllMessages2From0().hasIntroductionSessionInProgress()); // introducee2 can not yet remove messages assertFalse(deleteAllMessages0From2().allDeleted()); - assertTrue(deleteAllMessages0From2().hasIntroductionSessionInProgress()); + assertTrue( + deleteAllMessages0From2().hasIntroductionSessionInProgress()); // sync first ACCEPT message sync1To0(1, true); @@ -1177,7 +1183,8 @@ public class IntroductionIntegrationTest // introducer can not yet remove messages assertFalse(deleteAllMessages1From0().allDeleted()); - assertTrue(deleteAllMessages1From0().hasIntroductionSessionInProgress()); + assertTrue( + deleteAllMessages1From0().hasIntroductionSessionInProgress()); // sync second ACCEPT message sync2To0(1, true); @@ -1185,7 +1192,8 @@ public class IntroductionIntegrationTest // introducer can not yet remove messages assertFalse(deleteAllMessages2From0().allDeleted()); - assertTrue(deleteAllMessages2From0().hasIntroductionSessionInProgress()); + assertTrue( + deleteAllMessages2From0().hasIntroductionSessionInProgress()); // sync forwarded ACCEPT messages to introducees sync0To1(1, true); @@ -1193,10 +1201,12 @@ public class IntroductionIntegrationTest // introducee1 can not yet remove messages assertFalse(deleteAllMessages0From1().allDeleted()); - assertTrue(deleteAllMessages0From1().hasIntroductionSessionInProgress()); + assertTrue( + deleteAllMessages0From1().hasIntroductionSessionInProgress()); // introducee2 can not yet remove messages assertFalse(deleteAllMessages0From2().allDeleted()); - assertTrue(deleteAllMessages0From2().hasIntroductionSessionInProgress()); + assertTrue( + deleteAllMessages0From2().hasIntroductionSessionInProgress()); // sync first AUTH and its forward sync1To0(1, true); @@ -1204,12 +1214,15 @@ public class IntroductionIntegrationTest // introducer can not yet remove messages assertFalse(deleteAllMessages1From0().allDeleted()); - assertTrue(deleteAllMessages1From0().hasIntroductionSessionInProgress()); + assertTrue( + deleteAllMessages1From0().hasIntroductionSessionInProgress()); assertFalse(deleteAllMessages2From0().allDeleted()); - assertTrue(deleteAllMessages2From0().hasIntroductionSessionInProgress()); + assertTrue( + deleteAllMessages2From0().hasIntroductionSessionInProgress()); // introducee2 can not yet remove messages assertFalse(deleteAllMessages0From2().allDeleted()); - assertTrue(deleteAllMessages0From2().hasIntroductionSessionInProgress()); + assertTrue( + deleteAllMessages0From2().hasIntroductionSessionInProgress()); // sync second AUTH and its forward as well as the following ACTIVATE sync2To0(2, true); @@ -1217,12 +1230,15 @@ public class IntroductionIntegrationTest // introducer can not yet remove messages assertFalse(deleteAllMessages1From0().allDeleted()); - assertTrue(deleteAllMessages1From0().hasIntroductionSessionInProgress()); + assertTrue( + deleteAllMessages1From0().hasIntroductionSessionInProgress()); assertFalse(deleteAllMessages2From0().allDeleted()); - assertTrue(deleteAllMessages2From0().hasIntroductionSessionInProgress()); + assertTrue( + deleteAllMessages2From0().hasIntroductionSessionInProgress()); // introducee1 can not yet remove messages assertFalse(deleteAllMessages0From1().allDeleted()); - assertTrue(deleteAllMessages0From1().hasIntroductionSessionInProgress()); + assertTrue( + deleteAllMessages0From1().hasIntroductionSessionInProgress()); // sync second ACTIVATE and its forward sync1To0(1, true); @@ -1458,14 +1474,16 @@ public class IntroductionIntegrationTest sendAcks(c1, c0, contactId0From1, 1); assertTrue(deleteAllMessages1From0().allDeleted()); assertEquals(0, getMessages1From0().size()); - assertTrue(deleteAllMessages1From0().allDeleted()); // a second time nothing happens + assertTrue(deleteAllMessages1From0() + .allDeleted()); // a second time nothing happens // introducer can remove messages after getting ACK from introducee2 // if this succeeds, we still had the session object after delete above sendAcks(c2, c0, contactId0From2, 1); assertTrue(deleteAllMessages2From0().allDeleted()); assertEquals(0, getMessages2From0().size()); - assertTrue(deleteAllMessages2From0().allDeleted()); // a second time nothing happens + assertTrue(deleteAllMessages2From0() + .allDeleted()); // a second time nothing happens // no one should have aborted assertFalse(listener0.aborted); @@ -1489,7 +1507,8 @@ public class IntroductionIntegrationTest Set toDelete1 = new HashSet<>(); toDelete1.add(messageId1); assertFalse(deleteMessages1From0(toDelete1).allDeleted()); - assertTrue(deleteMessages1From0(toDelete1).hasIntroductionSessionInProgress()); + assertTrue(deleteMessages1From0(toDelete1) + .hasIntroductionSessionInProgress()); // deleting the introduction for introducee2 will fail as well Collection m2From0 = getMessages2From0(); @@ -1498,7 +1517,8 @@ public class IntroductionIntegrationTest Set toDelete2 = new HashSet<>(); toDelete2.add(messageId2); assertFalse(deleteMessages2From0(toDelete2).allDeleted()); - assertTrue(deleteMessages2From0(toDelete2).hasIntroductionSessionInProgress()); + assertTrue(deleteMessages2From0(toDelete2) + .hasIntroductionSessionInProgress()); // sync REQUEST messages sync0To1(1, true); @@ -1508,9 +1528,11 @@ public class IntroductionIntegrationTest // deleting introduction fails, because responses did not arrive assertFalse(deleteMessages0From1(toDelete1).allDeleted()); - assertTrue(deleteMessages0From1(toDelete1).hasIntroductionSessionInProgress()); + assertTrue(deleteMessages0From1(toDelete1) + .hasIntroductionSessionInProgress()); assertFalse(deleteMessages0From2(toDelete2).allDeleted()); - assertTrue(deleteMessages0From2(toDelete2).hasIntroductionSessionInProgress()); + assertTrue(deleteMessages0From2(toDelete2) + .hasIntroductionSessionInProgress()); // remember response of introducee1 for future deletion Collection m0From1 = getMessages0From1(); @@ -1570,7 +1592,8 @@ public class IntroductionIntegrationTest // deleting introduction fails for introducee 2, // because response is not yet selected for deletion assertFalse(deleteMessages0From2(toDelete2).allDeleted()); - assertTrue(deleteMessages0From2(toDelete2).hasNotAllIntroductionSelected()); + assertTrue(deleteMessages0From2(toDelete2) + .hasNotAllIntroductionSelected()); // add response to be deleted as well toDelete2.add(response2); @@ -1588,7 +1611,8 @@ public class IntroductionIntegrationTest // deleting introduction fails for introducee 1, // because response is not yet selected for deletion assertFalse(deleteMessages0From1(toDelete1).allDeleted()); - assertTrue(deleteMessages0From1(toDelete1).hasNotAllIntroductionSelected()); + assertTrue(deleteMessages0From1(toDelete1) + .hasNotAllIntroductionSelected()); // add response to be deleted as well toDelete1.add(response1); @@ -1730,7 +1754,8 @@ public class IntroductionIntegrationTest @MethodsNotNullByDefault @ParametersNotNullByDefault - private abstract class IntroductionListener implements EventListener { + private abstract static class IntroductionListener + implements EventListener { volatile boolean aborted = false; volatile Event latestEvent; diff --git a/briar-core/src/test/java/org/briarproject/briar/introduction/MessageEncoderParserIntegrationTest.java b/briar-core/src/test/java/org/briarproject/briar/introduction/MessageEncoderParserIntegrationTest.java index 6ee624333..808ca3454 100644 --- a/briar-core/src/test/java/org/briarproject/briar/introduction/MessageEncoderParserIntegrationTest.java +++ b/briar-core/src/test/java/org/briarproject/briar/introduction/MessageEncoderParserIntegrationTest.java @@ -25,6 +25,7 @@ import javax.inject.Inject; import static org.briarproject.bramble.api.autodelete.AutoDeleteConstants.MAX_AUTO_DELETE_TIMER_MS; import static org.briarproject.bramble.api.autodelete.AutoDeleteConstants.MIN_AUTO_DELETE_TIMER_MS; +import static org.briarproject.bramble.api.autodelete.AutoDeleteConstants.NO_AUTO_DELETE_TIMER; import static org.briarproject.bramble.api.crypto.CryptoConstants.MAC_BYTES; import static org.briarproject.bramble.api.crypto.CryptoConstants.MAX_SIGNATURE_BYTES; import static org.briarproject.bramble.test.TestUtils.getAgreementPublicKey; @@ -89,8 +90,8 @@ public class MessageEncoderParserIntegrationTest extends BrambleTestCase { @Test public void testRequestMessageMetadata() throws FormatException { - BdfDictionary d = messageEncoder - .encodeRequestMetadata(timestamp, MIN_AUTO_DELETE_TIMER_MS); + BdfDictionary d = messageEncoder.encodeRequestMetadata(timestamp, + MIN_AUTO_DELETE_TIMER_MS); MessageMetadata meta = messageParser.parseMetadata(d); assertEquals(REQUEST, meta.getMessageType()); @@ -105,9 +106,8 @@ public class MessageEncoderParserIntegrationTest extends BrambleTestCase { @Test public void testMessageMetadata() throws FormatException { - BdfDictionary d = messageEncoder - .encodeMetadata(ABORT, sessionId, timestamp, false, true, - false, MAX_AUTO_DELETE_TIMER_MS); + BdfDictionary d = messageEncoder.encodeMetadata(ABORT, sessionId, + timestamp, false, true, false, MAX_AUTO_DELETE_TIMER_MS); MessageMetadata meta = messageParser.parseMetadata(d); assertEquals(ABORT, meta.getMessageType()); @@ -135,6 +135,42 @@ public class MessageEncoderParserIntegrationTest extends BrambleTestCase { assertEquals(previousMsgId, rm.getPreviousMessageId()); assertEquals(author, rm.getAuthor()); assertEquals(text, rm.getText()); + assertEquals(NO_AUTO_DELETE_TIMER, rm.getAutoDeleteTimer()); + } + + @Test + public void testRequestMessageWithAutoDeleteTimer() throws FormatException { + Message m = messageEncoder.encodeRequestMessage(groupId, timestamp, + previousMsgId, author, text, MIN_AUTO_DELETE_TIMER_MS); + validator.validateMessage(m, group, clientHelper.toList(m)); + RequestMessage rm = + messageParser.parseRequestMessage(m, clientHelper.toList(m)); + + assertEquals(m.getId(), rm.getMessageId()); + assertEquals(m.getGroupId(), rm.getGroupId()); + assertEquals(m.getTimestamp(), rm.getTimestamp()); + assertEquals(previousMsgId, rm.getPreviousMessageId()); + assertEquals(author, rm.getAuthor()); + assertEquals(text, rm.getText()); + assertEquals(MIN_AUTO_DELETE_TIMER_MS, rm.getAutoDeleteTimer()); + } + + @Test + public void testRequestMessageWithoutAutoDeleteTimer() + throws FormatException { + Message m = messageEncoder.encodeRequestMessage(groupId, timestamp, + previousMsgId, author, text, NO_AUTO_DELETE_TIMER); + validator.validateMessage(m, group, clientHelper.toList(m)); + RequestMessage rm = + messageParser.parseRequestMessage(m, clientHelper.toList(m)); + + assertEquals(m.getId(), rm.getMessageId()); + assertEquals(m.getGroupId(), rm.getGroupId()); + assertEquals(m.getTimestamp(), rm.getTimestamp()); + assertEquals(previousMsgId, rm.getPreviousMessageId()); + assertEquals(author, rm.getAuthor()); + assertEquals(text, rm.getText()); + assertEquals(NO_AUTO_DELETE_TIMER, rm.getAutoDeleteTimer()); } @Test @@ -146,6 +182,7 @@ public class MessageEncoderParserIntegrationTest extends BrambleTestCase { messageParser.parseRequestMessage(m, clientHelper.toList(m)); assertNull(rm.getPreviousMessageId()); + assertEquals(NO_AUTO_DELETE_TIMER, rm.getAutoDeleteTimer()); } @Test @@ -158,6 +195,7 @@ public class MessageEncoderParserIntegrationTest extends BrambleTestCase { messageParser.parseRequestMessage(m, clientHelper.toList(m)); assertNull(rm.getText()); + assertEquals(NO_AUTO_DELETE_TIMER, rm.getAutoDeleteTimer()); } @Test @@ -183,6 +221,57 @@ public class MessageEncoderParserIntegrationTest extends BrambleTestCase { am.getEphemeralPublicKey().getEncoded()); assertEquals(acceptTimestamp, am.getAcceptTimestamp()); assertEquals(transportProperties, am.getTransportProperties()); + assertEquals(NO_AUTO_DELETE_TIMER, am.getAutoDeleteTimer()); + } + + @Test + public void testAcceptMessageWithAutoDeleteTimer() throws Exception { + Map transportProperties = + getTransportPropertiesMap(2); + + long acceptTimestamp = 1337L; + Message m = messageEncoder.encodeAcceptMessage(groupId, timestamp, + previousMsgId, sessionId, ephemeralPublicKey, + acceptTimestamp, transportProperties, MAX_AUTO_DELETE_TIMER_MS); + validator.validateMessage(m, group, clientHelper.toList(m)); + AcceptMessage am = + messageParser.parseAcceptMessage(m, clientHelper.toList(m)); + + assertEquals(m.getId(), am.getMessageId()); + assertEquals(m.getGroupId(), am.getGroupId()); + assertEquals(m.getTimestamp(), am.getTimestamp()); + assertEquals(previousMsgId, am.getPreviousMessageId()); + assertEquals(sessionId, am.getSessionId()); + assertArrayEquals(ephemeralPublicKey.getEncoded(), + am.getEphemeralPublicKey().getEncoded()); + assertEquals(acceptTimestamp, am.getAcceptTimestamp()); + assertEquals(transportProperties, am.getTransportProperties()); + assertEquals(MAX_AUTO_DELETE_TIMER_MS, am.getAutoDeleteTimer()); + } + + @Test + public void testAcceptMessageWithoutAutoDeleteTimer() throws Exception { + Map transportProperties = + getTransportPropertiesMap(2); + + long acceptTimestamp = 1337L; + Message m = messageEncoder.encodeAcceptMessage(groupId, timestamp, + previousMsgId, sessionId, ephemeralPublicKey, + acceptTimestamp, transportProperties, NO_AUTO_DELETE_TIMER); + validator.validateMessage(m, group, clientHelper.toList(m)); + AcceptMessage am = + messageParser.parseAcceptMessage(m, clientHelper.toList(m)); + + assertEquals(m.getId(), am.getMessageId()); + assertEquals(m.getGroupId(), am.getGroupId()); + assertEquals(m.getTimestamp(), am.getTimestamp()); + assertEquals(previousMsgId, am.getPreviousMessageId()); + assertEquals(sessionId, am.getSessionId()); + assertArrayEquals(ephemeralPublicKey.getEncoded(), + am.getEphemeralPublicKey().getEncoded()); + assertEquals(acceptTimestamp, am.getAcceptTimestamp()); + assertEquals(transportProperties, am.getTransportProperties()); + assertEquals(NO_AUTO_DELETE_TIMER, am.getAutoDeleteTimer()); } @Test @@ -199,6 +288,39 @@ public class MessageEncoderParserIntegrationTest extends BrambleTestCase { assertEquals(m.getTimestamp(), dm.getTimestamp()); assertEquals(previousMsgId, dm.getPreviousMessageId()); assertEquals(sessionId, dm.getSessionId()); + assertEquals(NO_AUTO_DELETE_TIMER, dm.getAutoDeleteTimer()); + } + + @Test + public void testDeclineMessageWithAutoDeleteTimer() throws Exception { + Message m = messageEncoder.encodeDeclineMessage(groupId, timestamp, + previousMsgId, sessionId, MIN_AUTO_DELETE_TIMER_MS); + validator.validateMessage(m, group, clientHelper.toList(m)); + DeclineMessage dm = + messageParser.parseDeclineMessage(m, clientHelper.toList(m)); + + assertEquals(m.getId(), dm.getMessageId()); + assertEquals(m.getGroupId(), dm.getGroupId()); + assertEquals(m.getTimestamp(), dm.getTimestamp()); + assertEquals(previousMsgId, dm.getPreviousMessageId()); + assertEquals(sessionId, dm.getSessionId()); + assertEquals(MIN_AUTO_DELETE_TIMER_MS, dm.getAutoDeleteTimer()); + } + + @Test + public void testDeclineMessageWithoutAutoDeleteTimer() throws Exception { + Message m = messageEncoder.encodeDeclineMessage(groupId, timestamp, + previousMsgId, sessionId, NO_AUTO_DELETE_TIMER); + validator.validateMessage(m, group, clientHelper.toList(m)); + DeclineMessage dm = + messageParser.parseDeclineMessage(m, clientHelper.toList(m)); + + assertEquals(m.getId(), dm.getMessageId()); + assertEquals(m.getGroupId(), dm.getGroupId()); + assertEquals(m.getTimestamp(), dm.getTimestamp()); + assertEquals(previousMsgId, dm.getPreviousMessageId()); + assertEquals(sessionId, dm.getSessionId()); + assertEquals(NO_AUTO_DELETE_TIMER, dm.getAutoDeleteTimer()); } @Test @@ -217,6 +339,7 @@ public class MessageEncoderParserIntegrationTest extends BrambleTestCase { assertEquals(sessionId, am.getSessionId()); assertArrayEquals(mac, am.getMac()); assertArrayEquals(signature, am.getSignature()); + assertEquals(NO_AUTO_DELETE_TIMER, am.getAutoDeleteTimer()); } @Test @@ -234,6 +357,7 @@ public class MessageEncoderParserIntegrationTest extends BrambleTestCase { assertEquals(previousMsgId, am.getPreviousMessageId()); assertEquals(sessionId, am.getSessionId()); assertArrayEquals(mac, am.getMac()); + assertEquals(NO_AUTO_DELETE_TIMER, am.getAutoDeleteTimer()); } @Test @@ -250,5 +374,6 @@ public class MessageEncoderParserIntegrationTest extends BrambleTestCase { assertEquals(m.getTimestamp(), am.getTimestamp()); assertEquals(previousMsgId, am.getPreviousMessageId()); assertEquals(sessionId, am.getSessionId()); + assertEquals(NO_AUTO_DELETE_TIMER, am.getAutoDeleteTimer()); } } diff --git a/briar-headless/src/test/java/org/briarproject/briar/headless/event/WebSocketControllerTest.kt b/briar-headless/src/test/java/org/briarproject/briar/headless/event/WebSocketControllerTest.kt index 3a9be9b39..58d9e48d0 100644 --- a/briar-headless/src/test/java/org/briarproject/briar/headless/event/WebSocketControllerTest.kt +++ b/briar-headless/src/test/java/org/briarproject/briar/headless/event/WebSocketControllerTest.kt @@ -97,7 +97,8 @@ internal class WebSocketControllerTest : ControllerTest() { author, text, false, - AuthorInfo(VERIFIED) + AuthorInfo(VERIFIED), + NO_AUTO_DELETE_TIMER ) val introductionRequestEvent = IntroductionRequestReceivedEvent(introductionRequest, contact.id) diff --git a/briar-headless/src/test/java/org/briarproject/briar/headless/messaging/MessagingControllerImplTest.kt b/briar-headless/src/test/java/org/briarproject/briar/headless/messaging/MessagingControllerImplTest.kt index 58685c6e4..91441efdf 100644 --- a/briar-headless/src/test/java/org/briarproject/briar/headless/messaging/MessagingControllerImplTest.kt +++ b/briar-headless/src/test/java/org/briarproject/briar/headless/messaging/MessagingControllerImplTest.kt @@ -89,7 +89,7 @@ internal class MessagingControllerImplTest : ControllerTest() { fun listIntroductionRequest() { val request = IntroductionRequest( message.id, group.id, timestamp, true, true, true, false, sessionId, author, text, - false, AuthorInfo(UNVERIFIED) + false, AuthorInfo(UNVERIFIED), NO_AUTO_DELETE_TIMER ) expectGetContact() @@ -330,7 +330,7 @@ internal class MessagingControllerImplTest : ControllerTest() { fun testIntroductionRequestWithNullText() { val request = IntroductionRequest( message.id, group.id, timestamp, true, true, true, false, sessionId, author, null, - false, AuthorInfo(VERIFIED) + false, AuthorInfo(VERIFIED), NO_AUTO_DELETE_TIMER ) val json = """ { From fa745410ccf77e1eebda1ed79eeee4c692dc6454 Mon Sep 17 00:00:00 2001 From: akwizgran Date: Fri, 20 Nov 2020 17:08:55 +0000 Subject: [PATCH 008/124] Update blog and forum sharing clients to include self-destruct timers. --- .../briar/api/blog/BlogInvitationRequest.java | 4 +- .../api/blog/BlogInvitationResponse.java | 5 +- .../briar/api/blog/BlogSharingManager.java | 2 +- .../api/forum/ForumInvitationRequest.java | 4 +- .../api/forum/ForumInvitationResponse.java | 5 +- .../briar/api/forum/ForumSharingManager.java | 2 +- .../invitation/GroupInvitationRequest.java | 4 +- .../invitation/GroupInvitationResponse.java | 4 +- .../briar/api/sharing/InvitationRequest.java | 6 +- .../briar/api/sharing/InvitationResponse.java | 7 +- .../briar/sharing/AcceptMessage.java | 8 +- .../sharing/BlogInvitationFactoryImpl.java | 12 +- .../briar/sharing/BlogProtocolEngineImpl.java | 22 ++-- .../briar/sharing/DeclineMessage.java | 7 +- .../sharing/DeletableSharingMessage.java | 22 ++++ .../sharing/ForumInvitationFactoryImpl.java | 12 +- .../sharing/ForumProtocolEngineImpl.java | 26 ++--- .../briar/sharing/InvitationFactory.java | 4 +- .../briar/sharing/InviteMessage.java | 6 +- .../briar/sharing/MessageEncoder.java | 35 +++++- .../briar/sharing/MessageEncoderImpl.java | 66 ++++++++++- .../briar/sharing/MessageMetadata.java | 8 +- .../briar/sharing/MessageParserImpl.java | 18 ++- .../briar/sharing/ProtocolEngineImpl.java | 110 +++++++++++++----- .../briar/sharing/SharingConstants.java | 1 + .../briar/sharing/SharingManagerImpl.java | 6 +- .../briar/sharing/SharingValidator.java | 70 ++++++++--- .../sharing/BlogSharingValidatorTest.java | 64 +++++++++- .../sharing/ForumSharingValidatorTest.java | 64 +++++++++- .../briar/sharing/SharingValidatorTest.java | 100 ++++++++++++++-- 30 files changed, 562 insertions(+), 142 deletions(-) create mode 100644 briar-core/src/main/java/org/briarproject/briar/sharing/DeletableSharingMessage.java diff --git a/briar-api/src/main/java/org/briarproject/briar/api/blog/BlogInvitationRequest.java b/briar-api/src/main/java/org/briarproject/briar/api/blog/BlogInvitationRequest.java index 8250dbc71..2f2db1da8 100644 --- a/briar-api/src/main/java/org/briarproject/briar/api/blog/BlogInvitationRequest.java +++ b/briar-api/src/main/java/org/briarproject/briar/api/blog/BlogInvitationRequest.java @@ -15,9 +15,9 @@ public class BlogInvitationRequest extends InvitationRequest { public BlogInvitationRequest(MessageId id, GroupId groupId, long time, boolean local, boolean read, boolean sent, boolean seen, SessionId sessionId, Blog blog, @Nullable String text, - boolean available, boolean canBeOpened) { + boolean available, boolean canBeOpened, long autoDeleteTimer) { super(id, groupId, time, local, read, sent, seen, sessionId, blog, - text, available, canBeOpened); + text, available, canBeOpened, autoDeleteTimer); } @Override diff --git a/briar-api/src/main/java/org/briarproject/briar/api/blog/BlogInvitationResponse.java b/briar-api/src/main/java/org/briarproject/briar/api/blog/BlogInvitationResponse.java index 29b3553f9..37cfef49a 100644 --- a/briar-api/src/main/java/org/briarproject/briar/api/blog/BlogInvitationResponse.java +++ b/briar-api/src/main/java/org/briarproject/briar/api/blog/BlogInvitationResponse.java @@ -12,9 +12,10 @@ public class BlogInvitationResponse extends InvitationResponse { public BlogInvitationResponse(MessageId id, GroupId groupId, long time, boolean local, boolean read, boolean sent, boolean seen, - SessionId sessionId, boolean accept, GroupId shareableId) { + SessionId sessionId, boolean accept, GroupId shareableId, + long autoDeleteTimer) { super(id, groupId, time, local, read, sent, seen, sessionId, - accept, shareableId); + accept, shareableId, autoDeleteTimer); } @Override diff --git a/briar-api/src/main/java/org/briarproject/briar/api/blog/BlogSharingManager.java b/briar-api/src/main/java/org/briarproject/briar/api/blog/BlogSharingManager.java index f2f04afc5..cf03267b1 100644 --- a/briar-api/src/main/java/org/briarproject/briar/api/blog/BlogSharingManager.java +++ b/briar-api/src/main/java/org/briarproject/briar/api/blog/BlogSharingManager.java @@ -18,5 +18,5 @@ public interface BlogSharingManager extends SharingManager { /** * The current minor version of the blog sharing client. */ - int MINOR_VERSION = 0; + int MINOR_VERSION = 1; } diff --git a/briar-api/src/main/java/org/briarproject/briar/api/forum/ForumInvitationRequest.java b/briar-api/src/main/java/org/briarproject/briar/api/forum/ForumInvitationRequest.java index 26d0e94c9..954e344bf 100644 --- a/briar-api/src/main/java/org/briarproject/briar/api/forum/ForumInvitationRequest.java +++ b/briar-api/src/main/java/org/briarproject/briar/api/forum/ForumInvitationRequest.java @@ -17,9 +17,9 @@ public class ForumInvitationRequest extends InvitationRequest { public ForumInvitationRequest(MessageId id, GroupId groupId, long time, boolean local, boolean read, boolean sent, boolean seen, SessionId sessionId, Forum forum, @Nullable String text, - boolean available, boolean canBeOpened) { + boolean available, boolean canBeOpened, long autoDeleteTimer) { super(id, groupId, time, local, read, sent, seen, sessionId, forum, - text, available, canBeOpened); + text, available, canBeOpened, autoDeleteTimer); } @Override diff --git a/briar-api/src/main/java/org/briarproject/briar/api/forum/ForumInvitationResponse.java b/briar-api/src/main/java/org/briarproject/briar/api/forum/ForumInvitationResponse.java index edaeb2cf0..be3757e35 100644 --- a/briar-api/src/main/java/org/briarproject/briar/api/forum/ForumInvitationResponse.java +++ b/briar-api/src/main/java/org/briarproject/briar/api/forum/ForumInvitationResponse.java @@ -15,9 +15,10 @@ public class ForumInvitationResponse extends InvitationResponse { public ForumInvitationResponse(MessageId id, GroupId groupId, long time, boolean local, boolean read, boolean sent, boolean seen, - SessionId sessionId, boolean accept, GroupId shareableId) { + SessionId sessionId, boolean accept, GroupId shareableId, + long autoDeleteTimer) { super(id, groupId, time, local, read, sent, seen, sessionId, - accept, shareableId); + accept, shareableId, autoDeleteTimer); } @Override diff --git a/briar-api/src/main/java/org/briarproject/briar/api/forum/ForumSharingManager.java b/briar-api/src/main/java/org/briarproject/briar/api/forum/ForumSharingManager.java index 29b2468d0..1ff441326 100644 --- a/briar-api/src/main/java/org/briarproject/briar/api/forum/ForumSharingManager.java +++ b/briar-api/src/main/java/org/briarproject/briar/api/forum/ForumSharingManager.java @@ -18,5 +18,5 @@ public interface ForumSharingManager extends SharingManager { /** * The current minor version of the forum sharing client. */ - int MINOR_VERSION = 0; + int MINOR_VERSION = 1; } diff --git a/briar-api/src/main/java/org/briarproject/briar/api/privategroup/invitation/GroupInvitationRequest.java b/briar-api/src/main/java/org/briarproject/briar/api/privategroup/invitation/GroupInvitationRequest.java index caab08faf..6f6abb93b 100644 --- a/briar-api/src/main/java/org/briarproject/briar/api/privategroup/invitation/GroupInvitationRequest.java +++ b/briar-api/src/main/java/org/briarproject/briar/api/privategroup/invitation/GroupInvitationRequest.java @@ -11,6 +11,8 @@ import org.briarproject.briar.api.sharing.InvitationRequest; import javax.annotation.Nullable; import javax.annotation.concurrent.Immutable; +import static org.briarproject.bramble.api.autodelete.AutoDeleteConstants.NO_AUTO_DELETE_TIMER; + @Immutable @NotNullByDefault public class GroupInvitationRequest extends InvitationRequest { @@ -20,7 +22,7 @@ public class GroupInvitationRequest extends InvitationRequest { SessionId sessionId, PrivateGroup shareable, @Nullable String text, boolean available, boolean canBeOpened) { super(id, groupId, time, local, read, sent, seen, sessionId, shareable, - text, available, canBeOpened); + text, available, canBeOpened, NO_AUTO_DELETE_TIMER); } @Override diff --git a/briar-api/src/main/java/org/briarproject/briar/api/privategroup/invitation/GroupInvitationResponse.java b/briar-api/src/main/java/org/briarproject/briar/api/privategroup/invitation/GroupInvitationResponse.java index a6d72ae0a..0c6b79e34 100644 --- a/briar-api/src/main/java/org/briarproject/briar/api/privategroup/invitation/GroupInvitationResponse.java +++ b/briar-api/src/main/java/org/briarproject/briar/api/privategroup/invitation/GroupInvitationResponse.java @@ -9,6 +9,8 @@ import org.briarproject.briar.api.sharing.InvitationResponse; import javax.annotation.concurrent.Immutable; +import static org.briarproject.bramble.api.autodelete.AutoDeleteConstants.NO_AUTO_DELETE_TIMER; + @Immutable @NotNullByDefault public class GroupInvitationResponse extends InvitationResponse { @@ -17,7 +19,7 @@ public class GroupInvitationResponse extends InvitationResponse { boolean local, boolean read, boolean sent, boolean seen, SessionId sessionId, boolean accept, GroupId shareableId) { super(id, groupId, time, local, read, sent, seen, sessionId, - accept, shareableId); + accept, shareableId, NO_AUTO_DELETE_TIMER); } @Override diff --git a/briar-api/src/main/java/org/briarproject/briar/api/sharing/InvitationRequest.java b/briar-api/src/main/java/org/briarproject/briar/api/sharing/InvitationRequest.java index 432d71cf5..80a6f881a 100644 --- a/briar-api/src/main/java/org/briarproject/briar/api/sharing/InvitationRequest.java +++ b/briar-api/src/main/java/org/briarproject/briar/api/sharing/InvitationRequest.java @@ -7,8 +7,6 @@ import org.briarproject.briar.api.conversation.ConversationRequest; import javax.annotation.Nullable; -import static org.briarproject.bramble.api.autodelete.AutoDeleteConstants.NO_AUTO_DELETE_TIMER; - public abstract class InvitationRequest extends ConversationRequest { @@ -17,9 +15,9 @@ public abstract class InvitationRequest extends public InvitationRequest(MessageId messageId, GroupId groupId, long time, boolean local, boolean read, boolean sent, boolean seen, SessionId sessionId, S object, @Nullable String text, - boolean available, boolean canBeOpened) { + boolean available, boolean canBeOpened, long autoDeleteTimer) { super(messageId, groupId, time, local, read, sent, seen, sessionId, - object, text, !available, NO_AUTO_DELETE_TIMER); + object, text, !available, autoDeleteTimer); this.canBeOpened = canBeOpened; } diff --git a/briar-api/src/main/java/org/briarproject/briar/api/sharing/InvitationResponse.java b/briar-api/src/main/java/org/briarproject/briar/api/sharing/InvitationResponse.java index 6a305cf7c..fd14fa051 100644 --- a/briar-api/src/main/java/org/briarproject/briar/api/sharing/InvitationResponse.java +++ b/briar-api/src/main/java/org/briarproject/briar/api/sharing/InvitationResponse.java @@ -5,17 +5,16 @@ import org.briarproject.bramble.api.sync.MessageId; import org.briarproject.briar.api.client.SessionId; import org.briarproject.briar.api.conversation.ConversationResponse; -import static org.briarproject.bramble.api.autodelete.AutoDeleteConstants.NO_AUTO_DELETE_TIMER; - public abstract class InvitationResponse extends ConversationResponse { private final GroupId shareableId; public InvitationResponse(MessageId id, GroupId groupId, long time, boolean local, boolean read, boolean sent, boolean seen, - SessionId sessionId, boolean accepted, GroupId shareableId) { + SessionId sessionId, boolean accepted, GroupId shareableId, + long autoDeleteTimer) { super(id, groupId, time, local, read, sent, seen, sessionId, accepted, - NO_AUTO_DELETE_TIMER); + autoDeleteTimer); this.shareableId = shareableId; } diff --git a/briar-core/src/main/java/org/briarproject/briar/sharing/AcceptMessage.java b/briar-core/src/main/java/org/briarproject/briar/sharing/AcceptMessage.java index 0a440a5cd..33644cb63 100644 --- a/briar-core/src/main/java/org/briarproject/briar/sharing/AcceptMessage.java +++ b/briar-core/src/main/java/org/briarproject/briar/sharing/AcceptMessage.java @@ -9,11 +9,13 @@ import javax.annotation.concurrent.Immutable; @Immutable @NotNullByDefault -class AcceptMessage extends SharingMessage { +class AcceptMessage extends DeletableSharingMessage { AcceptMessage(MessageId id, @Nullable MessageId previousMessageId, - GroupId contactGroupId, GroupId shareableId, long timestamp) { - super(id, contactGroupId, shareableId, timestamp, previousMessageId); + GroupId contactGroupId, GroupId shareableId, long timestamp, + long autoDeleteTimer) { + super(id, contactGroupId, shareableId, timestamp, previousMessageId, + autoDeleteTimer); } } diff --git a/briar-core/src/main/java/org/briarproject/briar/sharing/BlogInvitationFactoryImpl.java b/briar-core/src/main/java/org/briarproject/briar/sharing/BlogInvitationFactoryImpl.java index 10f4d1e31..afa8f4046 100644 --- a/briar-core/src/main/java/org/briarproject/briar/sharing/BlogInvitationFactoryImpl.java +++ b/briar-core/src/main/java/org/briarproject/briar/sharing/BlogInvitationFactoryImpl.java @@ -20,20 +20,24 @@ public class BlogInvitationFactoryImpl @Override public BlogInvitationRequest createInvitationRequest(boolean local, boolean sent, boolean seen, boolean read, InviteMessage m, - ContactId c, boolean available, boolean canBeOpened) { + ContactId c, boolean available, boolean canBeOpened, + long autoDeleteTimer) { SessionId sessionId = new SessionId(m.getShareableId().getBytes()); return new BlogInvitationRequest(m.getId(), m.getContactGroupId(), m.getTimestamp(), local, read, sent, seen, sessionId, - m.getShareable(), m.getText(), available, canBeOpened); + m.getShareable(), m.getText(), available, canBeOpened, + autoDeleteTimer); } @Override public BlogInvitationResponse createInvitationResponse(MessageId id, GroupId contactGroupId, long time, boolean local, boolean sent, - boolean seen, boolean read, boolean accept, GroupId shareableId) { + boolean seen, boolean read, boolean accept, GroupId shareableId, + long autoDeleteTimer) { SessionId sessionId = new SessionId(shareableId.getBytes()); return new BlogInvitationResponse(id, contactGroupId, time, local, read, - sent, seen, sessionId, accept, shareableId); + sent, seen, sessionId, accept, shareableId, + autoDeleteTimer); } } 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 d9454f0b8..79dfaaa42 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 @@ -8,13 +8,13 @@ import org.briarproject.bramble.api.db.DbException; import org.briarproject.bramble.api.db.Transaction; import org.briarproject.bramble.api.event.Event; import org.briarproject.bramble.api.nullsafety.NotNullByDefault; -import org.briarproject.bramble.api.sync.ClientId; import org.briarproject.bramble.api.sync.MessageId; import org.briarproject.bramble.api.system.Clock; import org.briarproject.bramble.api.versioning.ClientVersioningManager; import org.briarproject.briar.api.blog.Blog; import org.briarproject.briar.api.blog.BlogInvitationResponse; import org.briarproject.briar.api.blog.BlogManager; +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; @@ -23,9 +23,6 @@ import org.briarproject.briar.api.conversation.ConversationRequest; import javax.annotation.concurrent.Immutable; import javax.inject.Inject; -import static org.briarproject.briar.api.blog.BlogManager.CLIENT_ID; -import static org.briarproject.briar.api.blog.BlogManager.MAJOR_VERSION; - @Immutable @NotNullByDefault class BlogProtocolEngineImpl extends ProtocolEngineImpl { @@ -41,8 +38,9 @@ class BlogProtocolEngineImpl extends ProtocolEngineImpl { MessageTracker messageTracker, Clock clock, BlogManager blogManager, InvitationFactory invitationFactory) { super(db, clientHelper, clientVersioningManager, messageEncoder, - messageParser, messageTracker, clock, CLIENT_ID, - MAJOR_VERSION); + messageParser, messageTracker, clock, + BlogSharingManager.CLIENT_ID, BlogSharingManager.MAJOR_VERSION, + BlogManager.CLIENT_ID, BlogManager.MAJOR_VERSION); this.blogManager = blogManager; this.invitationFactory = invitationFactory; } @@ -52,7 +50,8 @@ class BlogProtocolEngineImpl extends ProtocolEngineImpl { ContactId contactId, boolean available, boolean canBeOpened) { ConversationRequest request = invitationFactory .createInvitationRequest(false, false, true, false, m, - contactId, available, canBeOpened); + contactId, available, canBeOpened, + m.getAutoDeleteTimer()); return new BlogInvitationRequestReceivedEvent(request, contactId); } @@ -62,7 +61,7 @@ class BlogProtocolEngineImpl extends ProtocolEngineImpl { BlogInvitationResponse response = invitationFactory .createInvitationResponse(m.getId(), m.getContactGroupId(), m.getTimestamp(), false, false, false, false, - true, m.getShareableId()); + true, m.getShareableId(), m.getAutoDeleteTimer()); return new BlogInvitationResponseReceivedEvent(response, contactId); } @@ -72,15 +71,10 @@ class BlogProtocolEngineImpl extends ProtocolEngineImpl { BlogInvitationResponse response = invitationFactory .createInvitationResponse(m.getId(), m.getContactGroupId(), m.getTimestamp(), false, false, false, false, - false, m.getShareableId()); + false, m.getShareableId(), m.getAutoDeleteTimer()); return new BlogInvitationResponseReceivedEvent(response, contactId); } - @Override - protected ClientId getShareableClientId() { - return CLIENT_ID; - } - @Override protected void addShareable(Transaction txn, MessageId inviteId) throws DbException, FormatException { diff --git a/briar-core/src/main/java/org/briarproject/briar/sharing/DeclineMessage.java b/briar-core/src/main/java/org/briarproject/briar/sharing/DeclineMessage.java index 65f9a9fe1..e392ef701 100644 --- a/briar-core/src/main/java/org/briarproject/briar/sharing/DeclineMessage.java +++ b/briar-core/src/main/java/org/briarproject/briar/sharing/DeclineMessage.java @@ -9,12 +9,13 @@ import javax.annotation.concurrent.Immutable; @Immutable @NotNullByDefault -class DeclineMessage extends SharingMessage { +class DeclineMessage extends DeletableSharingMessage { DeclineMessage(MessageId id, GroupId contactGroupId, GroupId shareableId, long timestamp, - @Nullable MessageId previousMessageId) { - super(id, contactGroupId, shareableId, timestamp, previousMessageId); + @Nullable MessageId previousMessageId, long autoDeleteTimer) { + super(id, contactGroupId, shareableId, timestamp, previousMessageId, + autoDeleteTimer); } } diff --git a/briar-core/src/main/java/org/briarproject/briar/sharing/DeletableSharingMessage.java b/briar-core/src/main/java/org/briarproject/briar/sharing/DeletableSharingMessage.java new file mode 100644 index 000000000..c4dca6f87 --- /dev/null +++ b/briar-core/src/main/java/org/briarproject/briar/sharing/DeletableSharingMessage.java @@ -0,0 +1,22 @@ +package org.briarproject.briar.sharing; + +import org.briarproject.bramble.api.sync.GroupId; +import org.briarproject.bramble.api.sync.MessageId; + +import javax.annotation.Nullable; + +abstract class DeletableSharingMessage extends SharingMessage { + + private final long autoDeleteTimer; + + DeletableSharingMessage(MessageId id, GroupId contactGroupId, + GroupId shareableId, long timestamp, + @Nullable MessageId previousMessageId, long autoDeleteTimer) { + super(id, contactGroupId, shareableId, timestamp, previousMessageId); + this.autoDeleteTimer = autoDeleteTimer; + } + + public long getAutoDeleteTimer() { + return autoDeleteTimer; + } +} diff --git a/briar-core/src/main/java/org/briarproject/briar/sharing/ForumInvitationFactoryImpl.java b/briar-core/src/main/java/org/briarproject/briar/sharing/ForumInvitationFactoryImpl.java index 09fcd9896..a83b37102 100644 --- a/briar-core/src/main/java/org/briarproject/briar/sharing/ForumInvitationFactoryImpl.java +++ b/briar-core/src/main/java/org/briarproject/briar/sharing/ForumInvitationFactoryImpl.java @@ -20,20 +20,24 @@ public class ForumInvitationFactoryImpl @Override public ForumInvitationRequest createInvitationRequest(boolean local, boolean sent, boolean seen, boolean read, InviteMessage m, - ContactId c, boolean available, boolean canBeOpened) { + ContactId c, boolean available, boolean canBeOpened, + long autoDeleteTimer) { SessionId sessionId = new SessionId(m.getShareableId().getBytes()); return new ForumInvitationRequest(m.getId(), m.getContactGroupId(), m.getTimestamp(), local, read, sent, seen, sessionId, - m.getShareable(), m.getText(), available, canBeOpened); + m.getShareable(), m.getText(), available, canBeOpened, + autoDeleteTimer); } @Override public ForumInvitationResponse createInvitationResponse(MessageId id, GroupId contactGroupId, long time, boolean local, boolean sent, - boolean seen, boolean read, boolean accept, GroupId shareableId) { + boolean seen, boolean read, boolean accept, GroupId shareableId, + long autoDeleteTimer) { SessionId sessionId = new SessionId(shareableId.getBytes()); return new ForumInvitationResponse(id, contactGroupId, time, local, - read, sent, seen, sessionId, accept, shareableId); + read, sent, seen, sessionId, accept, shareableId, + autoDeleteTimer); } } 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 22acc4231..e6df8fc48 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 @@ -8,7 +8,6 @@ import org.briarproject.bramble.api.db.DbException; import org.briarproject.bramble.api.db.Transaction; import org.briarproject.bramble.api.event.Event; import org.briarproject.bramble.api.nullsafety.NotNullByDefault; -import org.briarproject.bramble.api.sync.ClientId; import org.briarproject.bramble.api.sync.MessageId; import org.briarproject.bramble.api.system.Clock; import org.briarproject.bramble.api.versioning.ClientVersioningManager; @@ -17,21 +16,20 @@ import org.briarproject.briar.api.conversation.ConversationRequest; import org.briarproject.briar.api.forum.Forum; import org.briarproject.briar.api.forum.ForumInvitationResponse; import org.briarproject.briar.api.forum.ForumManager; +import org.briarproject.briar.api.forum.ForumSharingManager; import org.briarproject.briar.api.forum.event.ForumInvitationRequestReceivedEvent; import org.briarproject.briar.api.forum.event.ForumInvitationResponseReceivedEvent; import javax.annotation.concurrent.Immutable; import javax.inject.Inject; -import static org.briarproject.briar.api.forum.ForumManager.CLIENT_ID; -import static org.briarproject.briar.api.forum.ForumManager.MAJOR_VERSION; - @Immutable @NotNullByDefault class ForumProtocolEngineImpl extends ProtocolEngineImpl { private final ForumManager forumManager; - private final InvitationFactory invitationFactory; + private final InvitationFactory + invitationFactory; @Inject ForumProtocolEngineImpl(DatabaseComponent db, @@ -42,8 +40,10 @@ class ForumProtocolEngineImpl extends ProtocolEngineImpl { ForumManager forumManager, InvitationFactory invitationFactory) { super(db, clientHelper, clientVersioningManager, messageEncoder, - messageParser, messageTracker, clock, CLIENT_ID, - MAJOR_VERSION); + messageParser, messageTracker, clock, + ForumSharingManager.CLIENT_ID, + ForumSharingManager.MAJOR_VERSION, + ForumManager.CLIENT_ID, ForumManager.MAJOR_VERSION); this.forumManager = forumManager; this.invitationFactory = invitationFactory; } @@ -53,7 +53,8 @@ class ForumProtocolEngineImpl extends ProtocolEngineImpl { ContactId contactId, boolean available, boolean canBeOpened) { ConversationRequest request = invitationFactory .createInvitationRequest(false, false, true, false, m, - contactId, available, canBeOpened); + contactId, available, canBeOpened, + m.getAutoDeleteTimer()); return new ForumInvitationRequestReceivedEvent(request, contactId); } @@ -63,7 +64,7 @@ class ForumProtocolEngineImpl extends ProtocolEngineImpl { ForumInvitationResponse response = invitationFactory .createInvitationResponse(m.getId(), m.getContactGroupId(), m.getTimestamp(), false, false, true, false, - true, m.getShareableId()); + true, m.getShareableId(), m.getAutoDeleteTimer()); return new ForumInvitationResponseReceivedEvent(response, contactId); } @@ -73,15 +74,10 @@ class ForumProtocolEngineImpl extends ProtocolEngineImpl { ForumInvitationResponse response = invitationFactory .createInvitationResponse(m.getId(), m.getContactGroupId(), m.getTimestamp(), false, false, true, false, - false, m.getShareableId()); + false, m.getShareableId(), m.getAutoDeleteTimer()); return new ForumInvitationResponseReceivedEvent(response, contactId); } - @Override - protected ClientId getShareableClientId() { - return CLIENT_ID; - } - @Override protected void addShareable(Transaction txn, MessageId inviteId) throws DbException, FormatException { diff --git a/briar-core/src/main/java/org/briarproject/briar/sharing/InvitationFactory.java b/briar-core/src/main/java/org/briarproject/briar/sharing/InvitationFactory.java index 6c7287649..c156df0e2 100644 --- a/briar-core/src/main/java/org/briarproject/briar/sharing/InvitationFactory.java +++ b/briar-core/src/main/java/org/briarproject/briar/sharing/InvitationFactory.java @@ -11,10 +11,10 @@ public interface InvitationFactory createInvitationRequest(boolean local, boolean sent, boolean seen, boolean read, InviteMessage m, ContactId c, - boolean available, boolean canBeOpened); + boolean available, boolean canBeOpened, long autoDeleteTimer); R createInvitationResponse(MessageId id, GroupId contactGroupId, long time, boolean local, boolean sent, boolean seen, boolean read, - boolean accept, GroupId shareableId); + boolean accept, GroupId shareableId, long autoDeleteTimer); } diff --git a/briar-core/src/main/java/org/briarproject/briar/sharing/InviteMessage.java b/briar-core/src/main/java/org/briarproject/briar/sharing/InviteMessage.java index d94fe4f60..d83a3a3f7 100644 --- a/briar-core/src/main/java/org/briarproject/briar/sharing/InviteMessage.java +++ b/briar-core/src/main/java/org/briarproject/briar/sharing/InviteMessage.java @@ -10,7 +10,7 @@ import javax.annotation.concurrent.Immutable; @Immutable @NotNullByDefault -class InviteMessage extends SharingMessage { +class InviteMessage extends DeletableSharingMessage { private final S shareable; @Nullable @@ -18,9 +18,9 @@ class InviteMessage extends SharingMessage { InviteMessage(MessageId id, @Nullable MessageId previousMessageId, GroupId contactGroupId, S shareable, @Nullable String text, - long timestamp) { + long timestamp, long autoDeleteTimer) { super(id, contactGroupId, shareable.getId(), timestamp, - previousMessageId); + previousMessageId, autoDeleteTimer); if (text != null && text.isEmpty()) throw new IllegalArgumentException(); this.shareable = shareable; diff --git a/briar-core/src/main/java/org/briarproject/briar/sharing/MessageEncoder.java b/briar-core/src/main/java/org/briarproject/briar/sharing/MessageEncoder.java index 6723ea0bb..a7d823531 100644 --- a/briar-core/src/main/java/org/briarproject/briar/sharing/MessageEncoder.java +++ b/briar-core/src/main/java/org/briarproject/briar/sharing/MessageEncoder.java @@ -14,7 +14,7 @@ interface MessageEncoder { BdfDictionary encodeMetadata(MessageType type, GroupId shareableId, long timestamp, boolean local, boolean read, boolean visible, - boolean available, boolean accepted); + boolean available, boolean accepted, long autoDeleteTimer); void setVisibleInUi(BdfDictionary meta, boolean visible); @@ -22,16 +22,49 @@ interface MessageEncoder { void setInvitationAccepted(BdfDictionary meta, boolean accepted); + /** + * Encodes an invite message without an auto-delete timer. + */ Message encodeInviteMessage(GroupId contactGroupId, long timestamp, @Nullable MessageId previousMessageId, BdfList descriptor, @Nullable String text); + /** + * Encodes an invite message with an optional auto-delete timer. This + * requires the contact to support client version 0.1 or higher. + */ + Message encodeInviteMessage(GroupId contactGroupId, long timestamp, + @Nullable MessageId previousMessageId, BdfList descriptor, + @Nullable String text, long autoDeleteTimer); + + /** + * Encodes an accept message without an auto-delete timer. + */ Message encodeAcceptMessage(GroupId contactGroupId, GroupId shareableId, long timestamp, @Nullable MessageId previousMessageId); + /** + * Encodes an accept message with an optional auto-delete timer. This + * requires the contact to support client version 0.1 or higher. + */ + Message encodeAcceptMessage(GroupId contactGroupId, GroupId shareableId, + long timestamp, @Nullable MessageId previousMessageId, + long autoDeleteTimer); + + /** + * Encodes a decline message without an auto-delete timer. + */ Message encodeDeclineMessage(GroupId contactGroupId, GroupId shareableId, long timestamp, @Nullable MessageId previousMessageId); + /** + * Encodes a decline message with an optional auto-delete timer. This + * requires the contact to support client version 0.1 or higher. + */ + Message encodeDeclineMessage(GroupId contactGroupId, GroupId shareableId, + long timestamp, @Nullable MessageId previousMessageId, + long autoDeleteTimer); + Message encodeLeaveMessage(GroupId contactGroupId, GroupId shareableId, long timestamp, @Nullable MessageId previousMessageId); diff --git a/briar-core/src/main/java/org/briarproject/briar/sharing/MessageEncoderImpl.java b/briar-core/src/main/java/org/briarproject/briar/sharing/MessageEncoderImpl.java index 295fcf871..42d5985d8 100644 --- a/briar-core/src/main/java/org/briarproject/briar/sharing/MessageEncoderImpl.java +++ b/briar-core/src/main/java/org/briarproject/briar/sharing/MessageEncoderImpl.java @@ -14,11 +14,13 @@ import javax.annotation.Nullable; import javax.annotation.concurrent.Immutable; import javax.inject.Inject; +import static org.briarproject.bramble.api.autodelete.AutoDeleteConstants.NO_AUTO_DELETE_TIMER; import static org.briarproject.briar.sharing.MessageType.ABORT; import static org.briarproject.briar.sharing.MessageType.ACCEPT; import static org.briarproject.briar.sharing.MessageType.DECLINE; import static org.briarproject.briar.sharing.MessageType.INVITE; import static org.briarproject.briar.sharing.MessageType.LEAVE; +import static org.briarproject.briar.sharing.SharingConstants.MSG_KEY_AUTO_DELETE_TIMER; import static org.briarproject.briar.sharing.SharingConstants.MSG_KEY_AVAILABLE_TO_ANSWER; import static org.briarproject.briar.sharing.SharingConstants.MSG_KEY_INVITATION_ACCEPTED; import static org.briarproject.briar.sharing.SharingConstants.MSG_KEY_LOCAL; @@ -45,7 +47,8 @@ class MessageEncoderImpl implements MessageEncoder { @Override public BdfDictionary encodeMetadata(MessageType type, GroupId shareableId, long timestamp, boolean local, boolean read, - boolean visible, boolean available, boolean accepted) { + boolean visible, boolean available, boolean accepted, + long autoDeleteTimer) { BdfDictionary meta = new BdfDictionary(); meta.put(MSG_KEY_MESSAGE_TYPE, type.getValue()); meta.put(MSG_KEY_SHAREABLE_ID, shareableId); @@ -55,6 +58,9 @@ class MessageEncoderImpl implements MessageEncoder { meta.put(MSG_KEY_VISIBLE_IN_UI, visible); meta.put(MSG_KEY_AVAILABLE_TO_ANSWER, available); meta.put(MSG_KEY_INVITATION_ACCEPTED, accepted); + if (autoDeleteTimer != NO_AUTO_DELETE_TIMER) { + meta.put(MSG_KEY_AUTO_DELETE_TIMER, autoDeleteTimer); + } return meta; } @@ -93,6 +99,27 @@ class MessageEncoderImpl implements MessageEncoder { } } + @Override + public Message encodeInviteMessage(GroupId contactGroupId, long timestamp, + @Nullable MessageId previousMessageId, BdfList descriptor, + @Nullable String text, long autoDeleteTimer) { + if (text != null && text.isEmpty()) + throw new IllegalArgumentException(); + BdfList body = BdfList.of( + INVITE.getValue(), + previousMessageId, + descriptor, + text, + encodeTimer(autoDeleteTimer) + ); + try { + return messageFactory.createMessage(contactGroupId, timestamp, + clientHelper.toByteArray(body)); + } catch (FormatException e) { + throw new AssertionError(e); + } + } + @Override public Message encodeAcceptMessage(GroupId contactGroupId, GroupId shareableId, long timestamp, @@ -101,6 +128,14 @@ class MessageEncoderImpl implements MessageEncoder { previousMessageId); } + @Override + public Message encodeAcceptMessage(GroupId contactGroupId, + GroupId shareableId, long timestamp, + @Nullable MessageId previousMessageId, long autoDeleteTimer) { + return encodeMessage(ACCEPT, contactGroupId, shareableId, timestamp, + previousMessageId, autoDeleteTimer); + } + @Override public Message encodeDeclineMessage(GroupId contactGroupId, GroupId shareableId, long timestamp, @@ -109,6 +144,14 @@ class MessageEncoderImpl implements MessageEncoder { previousMessageId); } + @Override + public Message encodeDeclineMessage(GroupId contactGroupId, + GroupId shareableId, long timestamp, + @Nullable MessageId previousMessageId, long autoDeleteTimer) { + return encodeMessage(DECLINE, contactGroupId, shareableId, timestamp, + previousMessageId, autoDeleteTimer); + } + @Override public Message encodeLeaveMessage(GroupId contactGroupId, GroupId shareableId, long timestamp, @@ -141,4 +184,25 @@ class MessageEncoderImpl implements MessageEncoder { } } + private Message encodeMessage(MessageType type, GroupId contactGroupId, + GroupId shareableId, long timestamp, + @Nullable MessageId previousMessageId, long autoDeleteTimer) { + BdfList body = BdfList.of( + type.getValue(), + shareableId, + previousMessageId, + encodeTimer(autoDeleteTimer) + ); + try { + return messageFactory.createMessage(contactGroupId, timestamp, + clientHelper.toByteArray(body)); + } catch (FormatException e) { + throw new AssertionError(e); + } + } + + @Nullable + private Long encodeTimer(long autoDeleteTimer) { + return autoDeleteTimer == NO_AUTO_DELETE_TIMER ? null : autoDeleteTimer; + } } diff --git a/briar-core/src/main/java/org/briarproject/briar/sharing/MessageMetadata.java b/briar-core/src/main/java/org/briarproject/briar/sharing/MessageMetadata.java index a9f1662d5..34f096b8b 100644 --- a/briar-core/src/main/java/org/briarproject/briar/sharing/MessageMetadata.java +++ b/briar-core/src/main/java/org/briarproject/briar/sharing/MessageMetadata.java @@ -11,12 +11,12 @@ class MessageMetadata { private final MessageType type; private final GroupId shareableId; - private final long timestamp; + private final long timestamp, autoDeleteTimer; private final boolean local, read, visible, available, accepted; MessageMetadata(MessageType type, GroupId shareableId, long timestamp, boolean local, boolean read, boolean visible, boolean available, - boolean accepted) { + boolean accepted, long autoDeleteTimer) { this.shareableId = shareableId; this.type = type; this.timestamp = timestamp; @@ -25,6 +25,7 @@ class MessageMetadata { this.visible = visible; this.available = available; this.accepted = accepted; + this.autoDeleteTimer = autoDeleteTimer; } MessageType getMessageType() { @@ -64,4 +65,7 @@ class MessageMetadata { return accepted; } + public long getAutoDeleteTimer() { + return autoDeleteTimer; + } } diff --git a/briar-core/src/main/java/org/briarproject/briar/sharing/MessageParserImpl.java b/briar-core/src/main/java/org/briarproject/briar/sharing/MessageParserImpl.java index 48a001c4a..2cadda417 100644 --- a/briar-core/src/main/java/org/briarproject/briar/sharing/MessageParserImpl.java +++ b/briar-core/src/main/java/org/briarproject/briar/sharing/MessageParserImpl.java @@ -15,7 +15,9 @@ import org.briarproject.briar.api.sharing.Shareable; import javax.annotation.concurrent.Immutable; +import static org.briarproject.bramble.api.autodelete.AutoDeleteConstants.NO_AUTO_DELETE_TIMER; import static org.briarproject.briar.sharing.MessageType.INVITE; +import static org.briarproject.briar.sharing.SharingConstants.MSG_KEY_AUTO_DELETE_TIMER; import static org.briarproject.briar.sharing.SharingConstants.MSG_KEY_AVAILABLE_TO_ANSWER; import static org.briarproject.briar.sharing.SharingConstants.MSG_KEY_INVITATION_ACCEPTED; import static org.briarproject.briar.sharing.SharingConstants.MSG_KEY_LOCAL; @@ -70,8 +72,10 @@ abstract class MessageParserImpl boolean visible = meta.getBoolean(MSG_KEY_VISIBLE_IN_UI, false); boolean available = meta.getBoolean(MSG_KEY_AVAILABLE_TO_ANSWER, false); boolean accepted = meta.getBoolean(MSG_KEY_INVITATION_ACCEPTED, false); + long timer = meta.getLong(MSG_KEY_AUTO_DELETE_TIMER, + NO_AUTO_DELETE_TIMER); return new MessageMetadata(type, shareableId, timestamp, local, read, - visible, available, accepted); + visible, available, accepted, timer); } @Override @@ -90,8 +94,10 @@ abstract class MessageParserImpl BdfList descriptor = body.getList(2); S shareable = createShareable(descriptor); String text = body.getOptionalString(3); + long timer = NO_AUTO_DELETE_TIMER; + if (body.size() == 5) timer = body.getLong(4, NO_AUTO_DELETE_TIMER); return new InviteMessage<>(m.getId(), previousMessageId, - m.getGroupId(), shareable, text, m.getTimestamp()); + m.getGroupId(), shareable, text, m.getTimestamp(), timer); } @Override @@ -100,8 +106,10 @@ abstract class MessageParserImpl GroupId shareableId = new GroupId(body.getRaw(1)); byte[] b = body.getOptionalRaw(2); MessageId previousMessageId = (b == null ? null : new MessageId(b)); + long timer = NO_AUTO_DELETE_TIMER; + if (body.size() == 4) timer = body.getLong(3, NO_AUTO_DELETE_TIMER); return new AcceptMessage(m.getId(), previousMessageId, m.getGroupId(), - shareableId, m.getTimestamp()); + shareableId, m.getTimestamp(), timer); } @Override @@ -110,8 +118,10 @@ abstract class MessageParserImpl GroupId shareableId = new GroupId(body.getRaw(1)); byte[] b = body.getOptionalRaw(2); MessageId previousMessageId = (b == null ? null : new MessageId(b)); + long timer = NO_AUTO_DELETE_TIMER; + if (body.size() == 4) timer = body.getLong(3, NO_AUTO_DELETE_TIMER); return new DeclineMessage(m.getId(), m.getGroupId(), shareableId, - m.getTimestamp(), previousMessageId); + m.getTimestamp(), previousMessageId, timer); } @Override 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 8e151e0cc..9d47cf327 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 @@ -28,6 +28,7 @@ import java.util.Map; import javax.annotation.Nullable; import javax.annotation.concurrent.Immutable; +import static org.briarproject.bramble.api.autodelete.AutoDeleteConstants.NO_AUTO_DELETE_TIMER; import static org.briarproject.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; @@ -57,14 +58,15 @@ abstract class ProtocolEngineImpl private final MessageEncoder messageEncoder; private final MessageTracker messageTracker; private final Clock clock; - private final ClientId shareableClientId; - private final int shareableClientVersion; + private final ClientId sharingClientId, shareableClientId; + private final int sharingClientMajorVersion, shareableClientMajorVersion; ProtocolEngineImpl(DatabaseComponent db, ClientHelper clientHelper, ClientVersioningManager clientVersioningManager, MessageEncoder messageEncoder, MessageParser messageParser, MessageTracker messageTracker, Clock clock, - ClientId shareableClientId, int shareableClientVersion) { + ClientId sharingClientId, int sharingClientMajorVersion, + ClientId shareableClientId, int shareableClientMajorVersion) { this.db = db; this.clientHelper = clientHelper; this.clientVersioningManager = clientVersioningManager; @@ -72,8 +74,10 @@ abstract class ProtocolEngineImpl this.messageParser = messageParser; this.messageTracker = messageTracker; this.clock = clock; + this.sharingClientId = sharingClientId; + this.sharingClientMajorVersion = sharingClientMajorVersion; this.shareableClientId = shareableClientId; - this.shareableClientVersion = shareableClientVersion; + this.shareableClientMajorVersion = shareableClientMajorVersion; } @Override @@ -121,9 +125,21 @@ abstract class ProtocolEngineImpl throw new DbException(e); // Invalid group descriptor } long localTimestamp = Math.max(timestamp, getLocalTimestamp(s)); - Message m = messageEncoder.encodeInviteMessage(s.getContactGroupId(), - localTimestamp, s.getLastLocalMessageId(), descriptor, text); - sendMessage(txn, m, INVITE, s.getShareableId(), true); + Message m; + if (contactSupportsAutoDeletion(txn, s.getContactGroupId())) { + // TODO: Look up the current auto-delete timer + long timer = NO_AUTO_DELETE_TIMER; + m = messageEncoder.encodeInviteMessage(s.getContactGroupId(), + localTimestamp, s.getLastLocalMessageId(), descriptor, + text, timer); + sendMessage(txn, m, INVITE, s.getShareableId(), true, timer); + } else { + m = messageEncoder.encodeInviteMessage(s.getContactGroupId(), + localTimestamp, s.getLastLocalMessageId(), descriptor, + text); + sendMessage(txn, m, INVITE, s.getShareableId(), true, + NO_AUTO_DELETE_TIMER); + } return m; } @@ -173,12 +189,23 @@ abstract class ProtocolEngineImpl protected abstract void addShareable(Transaction txn, MessageId inviteId) throws DbException, FormatException; - private Message sendAcceptMessage(Transaction txn, Session session) + private Message sendAcceptMessage(Transaction txn, Session s) throws DbException { - Message m = messageEncoder.encodeAcceptMessage( - session.getContactGroupId(), session.getShareableId(), - getLocalTimestamp(session), session.getLastLocalMessageId()); - sendMessage(txn, m, ACCEPT, session.getShareableId(), true); + Message m; + if (contactSupportsAutoDeletion(txn, s.getContactGroupId())) { + // TODO: Look up the current auto-delete timer + long timer = NO_AUTO_DELETE_TIMER; + m = messageEncoder.encodeAcceptMessage(s.getContactGroupId(), + s.getShareableId(), getLocalTimestamp(s), + s.getLastLocalMessageId(), timer); + sendMessage(txn, m, ACCEPT, s.getShareableId(), true, timer); + } else { + m = messageEncoder.encodeAcceptMessage(s.getContactGroupId(), + s.getShareableId(), getLocalTimestamp(s), + s.getLastLocalMessageId()); + sendMessage(txn, m, ACCEPT, s.getShareableId(), true, + NO_AUTO_DELETE_TIMER); + } return m; } @@ -215,12 +242,23 @@ abstract class ProtocolEngineImpl s.getInviteTimestamp()); } - private Message sendDeclineMessage(Transaction txn, Session session) + private Message sendDeclineMessage(Transaction txn, Session s) throws DbException { - Message m = messageEncoder.encodeDeclineMessage( - session.getContactGroupId(), session.getShareableId(), - getLocalTimestamp(session), session.getLastLocalMessageId()); - sendMessage(txn, m, DECLINE, session.getShareableId(), true); + Message m; + if (contactSupportsAutoDeletion(txn, s.getContactGroupId())) { + // TODO: Look up the current auto-delete timer + long timer = NO_AUTO_DELETE_TIMER; + m = messageEncoder.encodeDeclineMessage(s.getContactGroupId(), + s.getShareableId(), getLocalTimestamp(s), + s.getLastLocalMessageId(), timer); + sendMessage(txn, m, DECLINE, s.getShareableId(), true, timer); + } else { + m = messageEncoder.encodeDeclineMessage(s.getContactGroupId(), + s.getShareableId(), getLocalTimestamp(s), + s.getLastLocalMessageId()); + sendMessage(txn, m, DECLINE, s.getShareableId(), true, + NO_AUTO_DELETE_TIMER); + } return m; } @@ -263,7 +301,8 @@ abstract class ProtocolEngineImpl Message m = messageEncoder.encodeLeaveMessage( session.getContactGroupId(), session.getShareableId(), getLocalTimestamp(session), session.getLastLocalMessageId()); - sendMessage(txn, m, LEAVE, session.getShareableId(), false); + sendMessage(txn, m, LEAVE, session.getShareableId(), false, + NO_AUTO_DELETE_TIMER); return m; } @@ -547,26 +586,25 @@ abstract class ProtocolEngineImpl throws DbException { if (!db.containsGroup(txn, g)) return false; Group group = db.getGroup(txn, g); - return group.getClientId().equals(getShareableClientId()); + return group.getClientId().equals(shareableClientId); } - protected abstract ClientId getShareableClientId(); - private Message sendAbortMessage(Transaction txn, Session session) throws DbException { Message m = messageEncoder.encodeAbortMessage( session.getContactGroupId(), session.getShareableId(), getLocalTimestamp(session), session.getLastLocalMessageId()); - sendMessage(txn, m, ABORT, session.getShareableId(), false); + sendMessage(txn, m, ABORT, session.getShareableId(), false, + NO_AUTO_DELETE_TIMER); return m; } private void sendMessage(Transaction txn, Message m, MessageType type, - GroupId shareableId, boolean visibleInConversation) - throws DbException { - BdfDictionary meta = messageEncoder - .encodeMetadata(type, shareableId, m.getTimestamp(), true, true, - visibleInConversation, false, false); + GroupId shareableId, boolean visibleInConversation, + long autoDeleteTimer) throws DbException { + BdfDictionary meta = messageEncoder.encodeMetadata(type, shareableId, + m.getTimestamp(), true, true, visibleInConversation, false, + false, autoDeleteTimer); try { clientHelper.addLocalMessage(txn, m, meta, true, false); } catch (FormatException e) { @@ -612,7 +650,7 @@ abstract class ProtocolEngineImpl // Apply min of preferred visibility and client's visibility ContactId contactId = getContactId(txn, session.getContactGroupId()); Visibility client = clientVersioningManager.getClientVisibility(txn, - contactId, shareableClientId, shareableClientVersion); + contactId, shareableClientId, shareableClientMajorVersion); Visibility min = Visibility.min(preferred, client); db.setGroupVisibility(txn, contactId, session.getShareableId(), min); } @@ -637,4 +675,20 @@ abstract class ProtocolEngineImpl session.getInviteTimestamp()) + 1); } + boolean contactSupportsAutoDeletion(Transaction txn, GroupId contactGroupId) + throws DbException { + try { + BdfDictionary meta = clientHelper + .getGroupMetadataAsDictionary(txn, contactGroupId); + int contactId = meta.getLong(GROUP_KEY_CONTACT_ID).intValue(); + ContactId c = new ContactId(contactId); + int minorVersion = clientVersioningManager + .getClientMinorVersion(txn, c, sharingClientId, + sharingClientMajorVersion); + // Auto-delete was added in client version 0.1 + return minorVersion >= 1; + } catch (FormatException e) { + throw new DbException(e); + } + } } diff --git a/briar-core/src/main/java/org/briarproject/briar/sharing/SharingConstants.java b/briar-core/src/main/java/org/briarproject/briar/sharing/SharingConstants.java index f2522d1a9..9d45467a5 100644 --- a/briar-core/src/main/java/org/briarproject/briar/sharing/SharingConstants.java +++ b/briar-core/src/main/java/org/briarproject/briar/sharing/SharingConstants.java @@ -16,6 +16,7 @@ interface SharingConstants { String MSG_KEY_VISIBLE_IN_UI = "visibleInUi"; String MSG_KEY_AVAILABLE_TO_ANSWER = "availableToAnswer"; String MSG_KEY_INVITATION_ACCEPTED = "invitationAccepted"; + String MSG_KEY_AUTO_DELETE_TIMER = "autoDeleteTimer"; // Session keys String SESSION_KEY_IS_SESSION = "isSession"; 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 4a24ece90..82f2a0d9a 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 @@ -368,7 +368,8 @@ abstract class SharingManagerImpl return invitationFactory .createInvitationRequest(meta.isLocal(), status.isSent(), status.isSeen(), meta.isRead(), invite, c, - meta.isAvailableToAnswer(), canBeOpened); + meta.isAvailableToAnswer(), canBeOpened, + meta.getAutoDeleteTimer()); } private InvitationResponse parseInvitationResponse(GroupId contactGroupId, @@ -376,7 +377,8 @@ abstract class SharingManagerImpl boolean accept) { return invitationFactory.createInvitationResponse(m, contactGroupId, meta.getTimestamp(), meta.isLocal(), status.isSent(), - status.isSeen(), meta.isRead(), accept, meta.getShareableId()); + status.isSeen(), meta.isRead(), accept, meta.getShareableId(), + meta.getAutoDeleteTimer()); } @Override diff --git a/briar-core/src/main/java/org/briarproject/briar/sharing/SharingValidator.java b/briar-core/src/main/java/org/briarproject/briar/sharing/SharingValidator.java index dcf38bf7b..f8cd581ea 100644 --- a/briar-core/src/main/java/org/briarproject/briar/sharing/SharingValidator.java +++ b/briar-core/src/main/java/org/briarproject/briar/sharing/SharingValidator.java @@ -15,11 +15,15 @@ import org.briarproject.bramble.api.sync.Message; import org.briarproject.bramble.api.sync.MessageId; import org.briarproject.bramble.api.system.Clock; -import java.util.Collections; - +import javax.annotation.Nullable; import javax.annotation.concurrent.Immutable; +import static java.util.Collections.singletonList; +import static org.briarproject.bramble.api.autodelete.AutoDeleteConstants.MAX_AUTO_DELETE_TIMER_MS; +import static org.briarproject.bramble.api.autodelete.AutoDeleteConstants.MIN_AUTO_DELETE_TIMER_MS; +import static org.briarproject.bramble.api.autodelete.AutoDeleteConstants.NO_AUTO_DELETE_TIMER; import static org.briarproject.bramble.util.ValidationUtils.checkLength; +import static org.briarproject.bramble.util.ValidationUtils.checkRange; import static org.briarproject.bramble.util.ValidationUtils.checkSize; import static org.briarproject.briar.api.sharing.SharingConstants.MAX_INVITATION_TEXT_LENGTH; import static org.briarproject.briar.sharing.MessageType.INVITE; @@ -45,9 +49,10 @@ abstract class SharingValidator extends BdfMessageValidator { return validateInviteMessage(m, body); case ACCEPT: case DECLINE: + return validateNonInviteMessageWithOptionalTimer(type, m, body); case LEAVE: case ABORT: - return validateNonInviteMessage(type, m, body); + return validateNonInviteMessageWithoutTimer(type, m, body); default: throw new FormatException(); } @@ -55,47 +60,80 @@ abstract class SharingValidator extends BdfMessageValidator { private BdfMessageContext validateInviteMessage(Message m, BdfList body) throws FormatException { - checkSize(body, 4); + // Client version 0.0: Message type, optional previous message ID, + // descriptor, optional text. + // Client version 0.1: Message type, optional previous message ID, + // descriptor, optional text, optional auto-delete timer. + checkSize(body, 4, 5); byte[] previousMessageId = body.getOptionalRaw(1); checkLength(previousMessageId, UniqueId.LENGTH); BdfList descriptor = body.getList(2); GroupId shareableId = validateDescriptor(descriptor); String text = body.getOptionalString(3); checkLength(text, 1, MAX_INVITATION_TEXT_LENGTH); + long timer = NO_AUTO_DELETE_TIMER; + if (body.size() == 5) timer = validateTimer(body.getOptionalLong(4)); - BdfDictionary meta = messageEncoder - .encodeMetadata(INVITE, shareableId, m.getTimestamp(), false, - false, false, false, false); + BdfDictionary meta = messageEncoder.encodeMetadata(INVITE, shareableId, + m.getTimestamp(), false, false, false, false, false, timer); if (previousMessageId == null) { return new BdfMessageContext(meta); } else { MessageId dependency = new MessageId(previousMessageId); - return new BdfMessageContext(meta, - Collections.singletonList(dependency)); + return new BdfMessageContext(meta, singletonList(dependency)); } } protected abstract GroupId validateDescriptor(BdfList descriptor) throws FormatException; - private BdfMessageContext validateNonInviteMessage(MessageType type, - Message m, BdfList body) throws FormatException { + private BdfMessageContext validateNonInviteMessageWithoutTimer( + MessageType type, Message m, BdfList body) throws FormatException { checkSize(body, 3); byte[] shareableId = body.getRaw(1); checkLength(shareableId, UniqueId.LENGTH); byte[] previousMessageId = body.getOptionalRaw(2); checkLength(previousMessageId, UniqueId.LENGTH); - BdfDictionary meta = messageEncoder - .encodeMetadata(type, new GroupId(shareableId), - m.getTimestamp(), false, false, false, false, false); + BdfDictionary meta = messageEncoder.encodeMetadata(type, + new GroupId(shareableId), m.getTimestamp(), false, false, + false, false, false, NO_AUTO_DELETE_TIMER); if (previousMessageId == null) { return new BdfMessageContext(meta); } else { MessageId dependency = new MessageId(previousMessageId); - return new BdfMessageContext(meta, - Collections.singletonList(dependency)); + return new BdfMessageContext(meta, singletonList(dependency)); } } + private BdfMessageContext validateNonInviteMessageWithOptionalTimer( + MessageType type, Message m, BdfList body) throws FormatException { + // Client version 0.0: Message type, shareable ID, optional previous + // message ID. + // Client version 0.1: Message type, shareable ID, optional previous + // message ID, optional auto-delete timer. + checkSize(body, 3, 4); + byte[] shareableId = body.getRaw(1); + checkLength(shareableId, UniqueId.LENGTH); + byte[] previousMessageId = body.getOptionalRaw(2); + checkLength(previousMessageId, UniqueId.LENGTH); + long timer = NO_AUTO_DELETE_TIMER; + if (body.size() == 4) timer = validateTimer(body.getOptionalLong(3)); + + BdfDictionary meta = messageEncoder.encodeMetadata(type, + new GroupId(shareableId), m.getTimestamp(), false, false, + false, false, false, timer); + if (previousMessageId == null) { + return new BdfMessageContext(meta); + } else { + MessageId dependency = new MessageId(previousMessageId); + return new BdfMessageContext(meta, singletonList(dependency)); + } + } + + private long validateTimer(@Nullable Long timer) throws FormatException { + if (timer == null) return NO_AUTO_DELETE_TIMER; + checkRange(timer, MIN_AUTO_DELETE_TIMER_MS, MAX_AUTO_DELETE_TIMER_MS); + return timer; + } } diff --git a/briar-core/src/test/java/org/briarproject/briar/sharing/BlogSharingValidatorTest.java b/briar-core/src/test/java/org/briarproject/briar/sharing/BlogSharingValidatorTest.java index 01b0ffd2a..8ce003360 100644 --- a/briar-core/src/test/java/org/briarproject/briar/sharing/BlogSharingValidatorTest.java +++ b/briar-core/src/test/java/org/briarproject/briar/sharing/BlogSharingValidatorTest.java @@ -8,10 +8,16 @@ import org.briarproject.briar.api.blog.Blog; import org.jmock.Expectations; import org.junit.Test; +import javax.annotation.Nullable; + +import static org.briarproject.bramble.api.autodelete.AutoDeleteConstants.MAX_AUTO_DELETE_TIMER_MS; +import static org.briarproject.bramble.api.autodelete.AutoDeleteConstants.MIN_AUTO_DELETE_TIMER_MS; +import static org.briarproject.bramble.api.autodelete.AutoDeleteConstants.NO_AUTO_DELETE_TIMER; import static org.briarproject.bramble.test.TestUtils.getAuthor; import static org.briarproject.bramble.util.StringUtils.getRandomString; import static org.briarproject.briar.api.sharing.SharingConstants.MAX_INVITATION_TEXT_LENGTH; import static org.briarproject.briar.sharing.MessageType.INVITE; +import static org.junit.Assert.fail; public class BlogSharingValidatorTest extends SharingValidatorTest { @@ -31,7 +37,7 @@ public class BlogSharingValidatorTest extends SharingValidatorTest { @Test public void testAcceptsInvitationWithText() throws Exception { expectCreateBlog(); - expectEncodeMetadata(INVITE); + expectEncodeMetadata(INVITE, NO_AUTO_DELETE_TIMER); BdfMessageContext context = validator.validateMessage(message, group, BdfList.of(INVITE.getValue(), previousMsgId, descriptor, text)); assertExpectedContext(context, previousMsgId); @@ -40,7 +46,7 @@ public class BlogSharingValidatorTest extends SharingValidatorTest { @Test public void testAcceptsInvitationWithNullText() throws Exception { expectCreateBlog(); - expectEncodeMetadata(INVITE); + expectEncodeMetadata(INVITE, NO_AUTO_DELETE_TIMER); BdfMessageContext context = validator.validateMessage(message, group, BdfList.of(INVITE.getValue(), previousMsgId, descriptor, null)); assertExpectedContext(context, previousMsgId); @@ -49,16 +55,64 @@ public class BlogSharingValidatorTest extends SharingValidatorTest { @Test public void testAcceptsInvitationWithNullPreviousMsgId() throws Exception { expectCreateBlog(); - expectEncodeMetadata(INVITE); + expectEncodeMetadata(INVITE, NO_AUTO_DELETE_TIMER); BdfMessageContext context = validator.validateMessage(message, group, BdfList.of(INVITE.getValue(), null, descriptor, text)); assertExpectedContext(context, null); } + @Test + public void testAcceptsInvitationWithMinAutoDeleteTimer() throws Exception { + testAcceptsInvitationWithAutoDeleteTimer(MIN_AUTO_DELETE_TIMER_MS); + } + + @Test + public void testAcceptsInvitationWithMaxAutoDeleteTimer() throws Exception { + testAcceptsInvitationWithAutoDeleteTimer(MAX_AUTO_DELETE_TIMER_MS); + } + + @Test + public void testAcceptsInvitationWithNullAutoDeleteTimer() + throws Exception { + testAcceptsInvitationWithAutoDeleteTimer(null); + } + + private void testAcceptsInvitationWithAutoDeleteTimer(@Nullable Long timer) + throws Exception { + expectCreateBlog(); + expectEncodeMetadata(INVITE, + timer == null ? NO_AUTO_DELETE_TIMER : timer); + BdfMessageContext context = validator.validateMessage(message, group, + BdfList.of(INVITE.getValue(), previousMsgId, descriptor, text, + timer)); + assertExpectedContext(context, previousMsgId); + } + + @Test(expected = FormatException.class) + public void testRejectsInvitationWithTooBigAutoDeleteTimer() + throws Exception { + testRejectsInvitationWithAutoDeleteTimer(MAX_AUTO_DELETE_TIMER_MS + 1); + } + + @Test(expected = FormatException.class) + public void testRejectsInvitationWithTooSmallAutoDeleteTimer() + throws Exception { + testRejectsInvitationWithAutoDeleteTimer(MIN_AUTO_DELETE_TIMER_MS - 1); + } + + private void testRejectsInvitationWithAutoDeleteTimer(Long timer) + throws Exception { + expectCreateBlog(); + validator.validateMessage(message, group, + BdfList.of(INVITE.getValue(), previousMsgId, descriptor, text, + timer)); + fail(); + } + @Test public void testAcceptsInvitationForRssBlog() throws Exception { expectCreateRssBlog(); - expectEncodeMetadata(INVITE); + expectEncodeMetadata(INVITE, NO_AUTO_DELETE_TIMER); BdfList rssDescriptor = BdfList.of(authorList, true); BdfMessageContext context = validator.validateMessage(message, group, BdfList.of(INVITE.getValue(), previousMsgId, rssDescriptor, @@ -93,7 +147,7 @@ public class BlogSharingValidatorTest extends SharingValidatorTest { public void testAcceptsMinLengthText() throws Exception { String shortText = getRandomString(1); expectCreateBlog(); - expectEncodeMetadata(INVITE); + expectEncodeMetadata(INVITE, NO_AUTO_DELETE_TIMER); BdfMessageContext context = validator.validateMessage(message, group, BdfList.of(INVITE.getValue(), previousMsgId, descriptor, shortText)); diff --git a/briar-core/src/test/java/org/briarproject/briar/sharing/ForumSharingValidatorTest.java b/briar-core/src/test/java/org/briarproject/briar/sharing/ForumSharingValidatorTest.java index 69e626d24..c42a3b7f3 100644 --- a/briar-core/src/test/java/org/briarproject/briar/sharing/ForumSharingValidatorTest.java +++ b/briar-core/src/test/java/org/briarproject/briar/sharing/ForumSharingValidatorTest.java @@ -7,12 +7,18 @@ import org.briarproject.briar.api.forum.Forum; import org.jmock.Expectations; import org.junit.Test; +import javax.annotation.Nullable; + +import static org.briarproject.bramble.api.autodelete.AutoDeleteConstants.MAX_AUTO_DELETE_TIMER_MS; +import static org.briarproject.bramble.api.autodelete.AutoDeleteConstants.MIN_AUTO_DELETE_TIMER_MS; +import static org.briarproject.bramble.api.autodelete.AutoDeleteConstants.NO_AUTO_DELETE_TIMER; import static org.briarproject.bramble.test.TestUtils.getRandomBytes; import static org.briarproject.bramble.util.StringUtils.getRandomString; import static org.briarproject.briar.api.forum.ForumConstants.FORUM_SALT_LENGTH; import static org.briarproject.briar.api.forum.ForumConstants.MAX_FORUM_NAME_LENGTH; import static org.briarproject.briar.api.sharing.SharingConstants.MAX_INVITATION_TEXT_LENGTH; import static org.briarproject.briar.sharing.MessageType.INVITE; +import static org.junit.Assert.fail; public class ForumSharingValidatorTest extends SharingValidatorTest { @@ -31,7 +37,7 @@ public class ForumSharingValidatorTest extends SharingValidatorTest { @Test public void testAcceptsInvitationWithText() throws Exception { expectCreateForum(forumName); - expectEncodeMetadata(INVITE); + expectEncodeMetadata(INVITE, NO_AUTO_DELETE_TIMER); BdfMessageContext context = validator.validateMessage(message, group, BdfList.of(INVITE.getValue(), previousMsgId, descriptor, text)); assertExpectedContext(context, previousMsgId); @@ -40,7 +46,7 @@ public class ForumSharingValidatorTest extends SharingValidatorTest { @Test public void testAcceptsInvitationWithNullText() throws Exception { expectCreateForum(forumName); - expectEncodeMetadata(INVITE); + expectEncodeMetadata(INVITE, NO_AUTO_DELETE_TIMER); BdfMessageContext context = validator.validateMessage(message, group, BdfList.of(INVITE.getValue(), previousMsgId, descriptor, null)); assertExpectedContext(context, previousMsgId); @@ -49,12 +55,60 @@ public class ForumSharingValidatorTest extends SharingValidatorTest { @Test public void testAcceptsInvitationWithNullPreviousMsgId() throws Exception { expectCreateForum(forumName); - expectEncodeMetadata(INVITE); + expectEncodeMetadata(INVITE, NO_AUTO_DELETE_TIMER); BdfMessageContext context = validator.validateMessage(message, group, BdfList.of(INVITE.getValue(), null, descriptor, null)); assertExpectedContext(context, null); } + @Test + public void testAcceptsInvitationWithMinAutoDeleteTimer() throws Exception { + testAcceptsInvitationWithAutoDeleteTimer(MIN_AUTO_DELETE_TIMER_MS); + } + + @Test + public void testAcceptsInvitationWithMaxAutoDeleteTimer() throws Exception { + testAcceptsInvitationWithAutoDeleteTimer(MAX_AUTO_DELETE_TIMER_MS); + } + + @Test + public void testAcceptsInvitationWithNullAutoDeleteTimer() + throws Exception { + testAcceptsInvitationWithAutoDeleteTimer(null); + } + + private void testAcceptsInvitationWithAutoDeleteTimer(@Nullable Long timer) + throws Exception { + expectCreateForum(forumName); + expectEncodeMetadata(INVITE, + timer == null ? NO_AUTO_DELETE_TIMER : timer); + BdfMessageContext context = validator.validateMessage(message, group, + BdfList.of(INVITE.getValue(), previousMsgId, descriptor, text, + timer)); + assertExpectedContext(context, previousMsgId); + } + + @Test(expected = FormatException.class) + public void testRejectsInvitationWithTooBigAutoDeleteTimer() + throws Exception { + testRejectsInvitationWithAutoDeleteTimer(MAX_AUTO_DELETE_TIMER_MS + 1); + } + + @Test(expected = FormatException.class) + public void testRejectsInvitationWithTooSmallAutoDeleteTimer() + throws Exception { + testRejectsInvitationWithAutoDeleteTimer(MIN_AUTO_DELETE_TIMER_MS - 1); + } + + private void testRejectsInvitationWithAutoDeleteTimer(long timer) + throws FormatException { + expectCreateForum(forumName); + validator.validateMessage(message, group, + BdfList.of(INVITE.getValue(), previousMsgId, descriptor, text, + timer)); + fail(); + } + @Test(expected = FormatException.class) public void testRejectsNullForumName() throws Exception { BdfList invalidDescriptor = BdfList.of(null, salt); @@ -84,7 +138,7 @@ public class ForumSharingValidatorTest extends SharingValidatorTest { String shortForumName = getRandomString(1); BdfList validDescriptor = BdfList.of(shortForumName, salt); expectCreateForum(shortForumName); - expectEncodeMetadata(INVITE); + expectEncodeMetadata(INVITE, NO_AUTO_DELETE_TIMER); BdfMessageContext context = validator.validateMessage(message, group, BdfList.of(INVITE.getValue(), previousMsgId, validDescriptor, null)); @@ -144,7 +198,7 @@ public class ForumSharingValidatorTest extends SharingValidatorTest { @Test public void testAcceptsMinLengthText() throws Exception { expectCreateForum(forumName); - expectEncodeMetadata(INVITE); + expectEncodeMetadata(INVITE, NO_AUTO_DELETE_TIMER); BdfMessageContext context = validator.validateMessage(message, group, BdfList.of(INVITE.getValue(), previousMsgId, descriptor, "1")); assertExpectedContext(context, previousMsgId); diff --git a/briar-core/src/test/java/org/briarproject/briar/sharing/SharingValidatorTest.java b/briar-core/src/test/java/org/briarproject/briar/sharing/SharingValidatorTest.java index f001fb680..c5c6349e0 100644 --- a/briar-core/src/test/java/org/briarproject/briar/sharing/SharingValidatorTest.java +++ b/briar-core/src/test/java/org/briarproject/briar/sharing/SharingValidatorTest.java @@ -16,6 +16,11 @@ import java.util.Collection; import javax.annotation.Nullable; +import static java.util.Collections.emptyList; +import static java.util.Collections.singletonList; +import static org.briarproject.bramble.api.autodelete.AutoDeleteConstants.MAX_AUTO_DELETE_TIMER_MS; +import static org.briarproject.bramble.api.autodelete.AutoDeleteConstants.MIN_AUTO_DELETE_TIMER_MS; +import static org.briarproject.bramble.api.autodelete.AutoDeleteConstants.NO_AUTO_DELETE_TIMER; import static org.briarproject.bramble.test.TestUtils.getRandomBytes; import static org.briarproject.bramble.test.TestUtils.getRandomId; import static org.briarproject.briar.sharing.MessageType.ABORT; @@ -24,7 +29,7 @@ import static org.briarproject.briar.sharing.MessageType.DECLINE; import static org.briarproject.briar.sharing.MessageType.INVITE; import static org.briarproject.briar.sharing.MessageType.LEAVE; import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; public abstract class SharingValidatorTest extends ValidatorTestCase { @@ -54,23 +59,84 @@ public abstract class SharingValidatorTest extends ValidatorTestCase { @Test public void testAcceptsAccept() throws Exception { - expectEncodeMetadata(ACCEPT); + expectEncodeMetadata(ACCEPT, NO_AUTO_DELETE_TIMER); BdfMessageContext context = validator.validateMessage(message, group, BdfList.of(ACCEPT.getValue(), groupId, previousMsgId)); assertExpectedContext(context, previousMsgId); } + @Test + public void testAcceptsAcceptWithMinAutoDeleteTimer() throws Exception { + testAcceptsResponseWithAutoDeleteTimer(ACCEPT, + MIN_AUTO_DELETE_TIMER_MS); + } + + @Test + public void testAcceptsAcceptWithMaxAutoDeleteTimer() throws Exception { + testAcceptsResponseWithAutoDeleteTimer(ACCEPT, + MAX_AUTO_DELETE_TIMER_MS); + } + + @Test + public void testAcceptsAcceptWithNullAutoDeleteTimer() throws Exception { + testAcceptsResponseWithAutoDeleteTimer(ACCEPT, null); + } + + @Test(expected = FormatException.class) + public void testRejectsAcceptWithTooBigAutoDeleteTimer() throws Exception { + testRejectsResponseWithAutoDeleteTimer(ACCEPT, + MAX_AUTO_DELETE_TIMER_MS + 1); + } + + @Test(expected = FormatException.class) + public void testRejectsAcceptWithTooSmallAutoDeleteTimer() + throws Exception { + testRejectsResponseWithAutoDeleteTimer(ACCEPT, + MIN_AUTO_DELETE_TIMER_MS - 1); + } + @Test public void testAcceptsDecline() throws Exception { - expectEncodeMetadata(DECLINE); + expectEncodeMetadata(DECLINE, NO_AUTO_DELETE_TIMER); BdfMessageContext context = validator.validateMessage(message, group, BdfList.of(DECLINE.getValue(), groupId, previousMsgId)); assertExpectedContext(context, previousMsgId); } + @Test + public void testAcceptsDeclineWithMinAutoDeleteTimer() throws Exception { + testAcceptsResponseWithAutoDeleteTimer(DECLINE, + MIN_AUTO_DELETE_TIMER_MS); + } + + @Test + public void testAcceptsDeclineWithMaxAutoDeleteTimer() throws Exception { + testAcceptsResponseWithAutoDeleteTimer(DECLINE, + MAX_AUTO_DELETE_TIMER_MS); + } + + @Test + public void testAcceptsDeclineWithNullAutoDeleteTimer() throws Exception { + testAcceptsResponseWithAutoDeleteTimer(DECLINE, null); + } + + @Test(expected = FormatException.class) + public void testRejectsDeclineWithTooBigAutoDeleteTimer() + throws Exception { + testRejectsResponseWithAutoDeleteTimer(DECLINE, + MAX_AUTO_DELETE_TIMER_MS + 1); + } + + @Test(expected = FormatException.class) + public void testRejectsDeclineWithTooSmallAutoDeleteTimer() + throws Exception { + testRejectsResponseWithAutoDeleteTimer(DECLINE, + MIN_AUTO_DELETE_TIMER_MS - 1); + } + @Test public void testAcceptsLeave() throws Exception { - expectEncodeMetadata(LEAVE); + expectEncodeMetadata(LEAVE, NO_AUTO_DELETE_TIMER); BdfMessageContext context = validator.validateMessage(message, group, BdfList.of(LEAVE.getValue(), groupId, previousMsgId)); assertExpectedContext(context, previousMsgId); @@ -78,7 +144,7 @@ public abstract class SharingValidatorTest extends ValidatorTestCase { @Test public void testAcceptsAbort() throws Exception { - expectEncodeMetadata(ABORT); + expectEncodeMetadata(ABORT, NO_AUTO_DELETE_TIMER); BdfMessageContext context = validator.validateMessage(message, group, BdfList.of(ABORT.getValue(), groupId, previousMsgId)); assertExpectedContext(context, previousMsgId); @@ -141,10 +207,10 @@ public abstract class SharingValidatorTest extends ValidatorTestCase { BdfList.of(ABORT.getValue(), groupId, previousMsgId, 123)); } - void expectEncodeMetadata(MessageType type) { + void expectEncodeMetadata(MessageType type, long autoDeleteTimer) { context.checking(new Expectations() {{ oneOf(messageEncoder).encodeMetadata(type, groupId, timestamp, - false, false, false, false, false); + false, false, false, false, false, autoDeleteTimer); will(returnValue(meta)); }}); } @@ -153,12 +219,26 @@ public abstract class SharingValidatorTest extends ValidatorTestCase { @Nullable MessageId previousMsgId) { Collection dependencies = messageContext.getDependencies(); if (previousMsgId == null) { - assertTrue(dependencies.isEmpty()); + assertEquals(emptyList(), dependencies); } else { - assertEquals(1, dependencies.size()); - assertTrue(dependencies.contains(previousMsgId)); + assertEquals(singletonList(previousMsgId), dependencies); } assertEquals(meta, messageContext.getDictionary()); } + private void testAcceptsResponseWithAutoDeleteTimer(MessageType type, + @Nullable Long timer) throws Exception { + expectEncodeMetadata(type, + timer == null ? NO_AUTO_DELETE_TIMER : timer); + BdfMessageContext context = validator.validateMessage(message, group, + BdfList.of(type.getValue(), groupId, previousMsgId, timer)); + assertExpectedContext(context, previousMsgId); + } + + private void testRejectsResponseWithAutoDeleteTimer(MessageType type, + long timer) throws FormatException { + validator.validateMessage(message, group, + BdfList.of(type.getValue(), groupId, previousMsgId, timer)); + fail(); + } } From 3e1c2df4b11545d419052e82ff80f9528a425f66 Mon Sep 17 00:00:00 2001 From: akwizgran Date: Mon, 23 Nov 2020 15:42:39 +0000 Subject: [PATCH 009/124] Update private group invitation client to include self-destruct timers. --- .../invitation/GroupInvitationManager.java | 2 +- .../invitation/GroupInvitationRequest.java | 7 +- .../invitation/GroupInvitationResponse.java | 7 +- .../invitation/AbstractProtocolEngine.java | 110 +++++++++++++----- .../invitation/CreatorProtocolEngine.java | 4 +- .../DeletableGroupInvitationMessage.java | 24 ++++ .../invitation/GroupInvitationConstants.java | 1 + .../GroupInvitationManagerImpl.java | 29 ++--- .../invitation/GroupInvitationValidator.java | 46 ++++++-- .../invitation/InviteMessage.java | 6 +- .../invitation/InviteeProtocolEngine.java | 2 +- .../privategroup/invitation/JoinMessage.java | 7 +- .../privategroup/invitation/LeaveMessage.java | 7 +- .../invitation/MessageEncoder.java | 35 +++++- .../invitation/MessageEncoderImpl.java | 83 ++++++++++--- .../invitation/MessageMetadata.java | 8 +- .../invitation/MessageParserImpl.java | 39 +++++-- .../AbstractProtocolEngineTest.java | 58 ++++++--- .../invitation/CreatorProtocolEngineTest.java | 14 ++- .../GroupInvitationManagerImplTest.java | 29 ++--- .../GroupInvitationValidatorTest.java | 18 ++- .../invitation/InviteeProtocolEngineTest.java | 23 ++-- .../invitation/PeerProtocolEngineTest.java | 100 +++++++++------- 23 files changed, 460 insertions(+), 199 deletions(-) create mode 100644 briar-core/src/main/java/org/briarproject/briar/privategroup/invitation/DeletableGroupInvitationMessage.java 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 b9f44e2bc..023d5b172 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 @@ -32,7 +32,7 @@ public interface GroupInvitationManager extends ConversationClient { /** * The current minor version of the private group invitation client. */ - int MINOR_VERSION = 0; + int MINOR_VERSION = 1; /** * Sends an invitation to share the given private group with the given diff --git a/briar-api/src/main/java/org/briarproject/briar/api/privategroup/invitation/GroupInvitationRequest.java b/briar-api/src/main/java/org/briarproject/briar/api/privategroup/invitation/GroupInvitationRequest.java index 6f6abb93b..0282145f2 100644 --- a/briar-api/src/main/java/org/briarproject/briar/api/privategroup/invitation/GroupInvitationRequest.java +++ b/briar-api/src/main/java/org/briarproject/briar/api/privategroup/invitation/GroupInvitationRequest.java @@ -11,8 +11,6 @@ import org.briarproject.briar.api.sharing.InvitationRequest; import javax.annotation.Nullable; import javax.annotation.concurrent.Immutable; -import static org.briarproject.bramble.api.autodelete.AutoDeleteConstants.NO_AUTO_DELETE_TIMER; - @Immutable @NotNullByDefault public class GroupInvitationRequest extends InvitationRequest { @@ -20,9 +18,10 @@ public class GroupInvitationRequest extends InvitationRequest { public GroupInvitationRequest(MessageId id, GroupId groupId, long time, boolean local, boolean read, boolean sent, boolean seen, SessionId sessionId, PrivateGroup shareable, - @Nullable String text, boolean available, boolean canBeOpened) { + @Nullable String text, boolean available, boolean canBeOpened, + long autoDeleteTimer) { super(id, groupId, time, local, read, sent, seen, sessionId, shareable, - text, available, canBeOpened, NO_AUTO_DELETE_TIMER); + text, available, canBeOpened, autoDeleteTimer); } @Override diff --git a/briar-api/src/main/java/org/briarproject/briar/api/privategroup/invitation/GroupInvitationResponse.java b/briar-api/src/main/java/org/briarproject/briar/api/privategroup/invitation/GroupInvitationResponse.java index 0c6b79e34..b461d9dc1 100644 --- a/briar-api/src/main/java/org/briarproject/briar/api/privategroup/invitation/GroupInvitationResponse.java +++ b/briar-api/src/main/java/org/briarproject/briar/api/privategroup/invitation/GroupInvitationResponse.java @@ -9,17 +9,16 @@ import org.briarproject.briar.api.sharing.InvitationResponse; import javax.annotation.concurrent.Immutable; -import static org.briarproject.bramble.api.autodelete.AutoDeleteConstants.NO_AUTO_DELETE_TIMER; - @Immutable @NotNullByDefault public class GroupInvitationResponse extends InvitationResponse { public GroupInvitationResponse(MessageId id, GroupId groupId, long time, boolean local, boolean read, boolean sent, boolean seen, - SessionId sessionId, boolean accept, GroupId shareableId) { + SessionId sessionId, boolean accept, GroupId shareableId, + long autoDeleteTimer) { super(id, groupId, time, local, read, sent, seen, sessionId, - accept, shareableId, NO_AUTO_DELETE_TIMER); + accept, shareableId, autoDeleteTimer); } @Override 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 3e5a9842a..44165dcf4 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 @@ -23,14 +23,14 @@ import org.briarproject.briar.api.privategroup.GroupMessageFactory; import org.briarproject.briar.api.privategroup.PrivateGroup; import org.briarproject.briar.api.privategroup.PrivateGroupFactory; import org.briarproject.briar.api.privategroup.PrivateGroupManager; +import org.briarproject.briar.api.privategroup.invitation.GroupInvitationManager; import java.util.Map; import javax.annotation.Nullable; import javax.annotation.concurrent.Immutable; -import static org.briarproject.briar.api.privategroup.PrivateGroupManager.CLIENT_ID; -import static org.briarproject.briar.api.privategroup.PrivateGroupManager.MAJOR_VERSION; +import static org.briarproject.bramble.api.autodelete.AutoDeleteConstants.NO_AUTO_DELETE_TIMER; import static org.briarproject.briar.privategroup.invitation.GroupInvitationConstants.GROUP_KEY_CONTACT_ID; import static org.briarproject.briar.privategroup.invitation.MessageType.ABORT; import static org.briarproject.briar.privategroup.invitation.MessageType.INVITE; @@ -39,7 +39,7 @@ import static org.briarproject.briar.privategroup.invitation.MessageType.LEAVE; @Immutable @NotNullByDefault -abstract class AbstractProtocolEngine +abstract class AbstractProtocolEngine> implements ProtocolEngine { protected final DatabaseComponent db; @@ -90,6 +90,7 @@ abstract class AbstractProtocolEngine return group.getClientId().equals(PrivateGroupManager.CLIENT_ID); } + @SuppressWarnings("BooleanMethodIsAlwaysInverted") boolean isValidDependency(S session, @Nullable MessageId dependency) { MessageId expected = session.getLastRemoteMessageId(); if (dependency == null) return expected == null; @@ -101,44 +102,81 @@ abstract class AbstractProtocolEngine // Apply min of preferred visibility and client's visibility ContactId contactId = getContactId(txn, session.getContactGroupId()); Visibility client = clientVersioningManager.getClientVisibility(txn, - contactId, CLIENT_ID, MAJOR_VERSION); + contactId, PrivateGroupManager.CLIENT_ID, + PrivateGroupManager.MAJOR_VERSION); Visibility min = Visibility.min(preferred, client); db.setGroupVisibility(txn, contactId, session.getPrivateGroupId(), min); } - Message sendInviteMessage(Transaction txn, S session, + Message sendInviteMessage(Transaction txn, S s, @Nullable String text, long timestamp, byte[] signature) throws DbException { - Group g = db.getGroup(txn, session.getPrivateGroupId()); + Group g = db.getGroup(txn, s.getPrivateGroupId()); PrivateGroup privateGroup; try { privateGroup = privateGroupFactory.parsePrivateGroup(g); } catch (FormatException e) { throw new DbException(e); // Invalid group descriptor } - Message m = messageEncoder.encodeInviteMessage( - session.getContactGroupId(), privateGroup.getId(), - timestamp, privateGroup.getName(), privateGroup.getCreator(), - privateGroup.getSalt(), text, signature); - sendMessage(txn, m, INVITE, privateGroup.getId(), true); + Message m; + if (contactSupportsAutoDeletion(txn, s.getContactGroupId())) { + // TODO: Look up the current auto-delete timer + long timer = NO_AUTO_DELETE_TIMER; + m = messageEncoder.encodeInviteMessage(s.getContactGroupId(), + privateGroup.getId(), timestamp, privateGroup.getName(), + privateGroup.getCreator(), privateGroup.getSalt(), text, + signature, timer); + sendMessage(txn, m, INVITE, privateGroup.getId(), true, timer); + } else { + m = messageEncoder.encodeInviteMessage(s.getContactGroupId(), + privateGroup.getId(), timestamp, privateGroup.getName(), + privateGroup.getCreator(), privateGroup.getSalt(), text, + signature); + sendMessage(txn, m, INVITE, privateGroup.getId(), true, + NO_AUTO_DELETE_TIMER); + } return m; } - Message sendJoinMessage(Transaction txn, S session, boolean visibleInUi) + Message sendJoinMessage(Transaction txn, S s, boolean visibleInUi) throws DbException { - Message m = messageEncoder.encodeJoinMessage( - session.getContactGroupId(), session.getPrivateGroupId(), - getLocalTimestamp(session), session.getLastLocalMessageId()); - sendMessage(txn, m, JOIN, session.getPrivateGroupId(), visibleInUi); + Message m; + if (contactSupportsAutoDeletion(txn, s.getContactGroupId())) { + // TODO: Look up the current auto-delete timer + long timer = NO_AUTO_DELETE_TIMER; + m = messageEncoder.encodeJoinMessage(s.getContactGroupId(), + s.getPrivateGroupId(), getLocalTimestamp(s), + s.getLastLocalMessageId(), timer); + sendMessage(txn, m, JOIN, s.getPrivateGroupId(), visibleInUi, + timer); + } else { + m = messageEncoder.encodeJoinMessage(s.getContactGroupId(), + s.getPrivateGroupId(), getLocalTimestamp(s), + s.getLastLocalMessageId()); + sendMessage(txn, m, JOIN, s.getPrivateGroupId(), visibleInUi, + NO_AUTO_DELETE_TIMER); + } return m; } - Message sendLeaveMessage(Transaction txn, S session, boolean visibleInUi) + Message sendLeaveMessage(Transaction txn, S s, boolean visibleInUi) throws DbException { - Message m = messageEncoder.encodeLeaveMessage( - session.getContactGroupId(), session.getPrivateGroupId(), - getLocalTimestamp(session), session.getLastLocalMessageId()); - sendMessage(txn, m, LEAVE, session.getPrivateGroupId(), visibleInUi); + Message m; + if (contactSupportsAutoDeletion(txn, s.getContactGroupId())) { + // TODO: Look up the current auto-delete timer + long timer = NO_AUTO_DELETE_TIMER; + m = messageEncoder.encodeLeaveMessage(s.getContactGroupId(), + s.getPrivateGroupId(), getLocalTimestamp(s), + s.getLastLocalMessageId(), timer); + sendMessage(txn, m, LEAVE, s.getPrivateGroupId(), visibleInUi, + timer); + } else { + m = messageEncoder.encodeLeaveMessage(s.getContactGroupId(), + s.getPrivateGroupId(), getLocalTimestamp(s), + s.getLastLocalMessageId()); + sendMessage(txn, m, LEAVE, s.getPrivateGroupId(), visibleInUi, + NO_AUTO_DELETE_TIMER); + } return m; } @@ -146,7 +184,8 @@ abstract class AbstractProtocolEngine Message m = messageEncoder.encodeAbortMessage( session.getContactGroupId(), session.getPrivateGroupId(), getLocalTimestamp(session)); - sendMessage(txn, m, ABORT, session.getPrivateGroupId(), false); + sendMessage(txn, m, ABORT, session.getPrivateGroupId(), false, + NO_AUTO_DELETE_TIMER); return m; } @@ -217,11 +256,11 @@ abstract class AbstractProtocolEngine } private void sendMessage(Transaction txn, Message m, MessageType type, - GroupId privateGroupId, boolean visibleInConversation) - throws DbException { - BdfDictionary meta = messageEncoder - .encodeMetadata(type, privateGroupId, m.getTimestamp(), true, - true, visibleInConversation, false, false); + GroupId privateGroupId, boolean visibleInConversation, + long autoDeleteTimer) throws DbException { + BdfDictionary meta = messageEncoder.encodeMetadata(type, + privateGroupId, m.getTimestamp(), true, true, + visibleInConversation, false, false, autoDeleteTimer); try { clientHelper.addLocalMessage(txn, m, meta, true, false); } catch (FormatException e) { @@ -229,4 +268,21 @@ abstract class AbstractProtocolEngine } } + boolean contactSupportsAutoDeletion(Transaction txn, GroupId contactGroupId) + throws DbException { + try { + BdfDictionary meta = clientHelper + .getGroupMetadataAsDictionary(txn, contactGroupId); + int contactId = meta.getLong(GROUP_KEY_CONTACT_ID).intValue(); + ContactId c = new ContactId(contactId); + int minorVersion = clientVersioningManager + .getClientMinorVersion(txn, c, + GroupInvitationManager.CLIENT_ID, + GroupInvitationManager.MAJOR_VERSION); + // Auto-delete was added in client version 0.1 + return minorVersion >= 1; + } catch (FormatException e) { + throw new DbException(e); + } + } } 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 2830db2a2..9709f265a 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 @@ -253,10 +253,10 @@ class CreatorProtocolEngine extends AbstractProtocolEngine { } private GroupInvitationResponse createInvitationResponse( - GroupInvitationMessage m, boolean accept) { + DeletableGroupInvitationMessage m, boolean accept) { SessionId sessionId = new SessionId(m.getPrivateGroupId().getBytes()); return new GroupInvitationResponse(m.getId(), m.getContactGroupId(), m.getTimestamp(), false, false, false, false, sessionId, - accept, m.getPrivateGroupId()); + accept, m.getPrivateGroupId(), m.getAutoDeleteTimer()); } } diff --git a/briar-core/src/main/java/org/briarproject/briar/privategroup/invitation/DeletableGroupInvitationMessage.java b/briar-core/src/main/java/org/briarproject/briar/privategroup/invitation/DeletableGroupInvitationMessage.java new file mode 100644 index 000000000..328180b3f --- /dev/null +++ b/briar-core/src/main/java/org/briarproject/briar/privategroup/invitation/DeletableGroupInvitationMessage.java @@ -0,0 +1,24 @@ +package org.briarproject.briar.privategroup.invitation; + +import org.briarproject.bramble.api.nullsafety.NotNullByDefault; +import org.briarproject.bramble.api.sync.GroupId; +import org.briarproject.bramble.api.sync.MessageId; + +import javax.annotation.concurrent.Immutable; + +@Immutable +@NotNullByDefault +abstract class DeletableGroupInvitationMessage extends GroupInvitationMessage { + + private final long autoDeleteTimer; + + DeletableGroupInvitationMessage(MessageId id, GroupId contactGroupId, + GroupId privateGroupId, long timestamp, long autoDeleteTimer) { + super(id, contactGroupId, privateGroupId, timestamp); + this.autoDeleteTimer = autoDeleteTimer; + } + + public long getAutoDeleteTimer() { + return autoDeleteTimer; + } +} diff --git a/briar-core/src/main/java/org/briarproject/briar/privategroup/invitation/GroupInvitationConstants.java b/briar-core/src/main/java/org/briarproject/briar/privategroup/invitation/GroupInvitationConstants.java index 90c0fcd29..dd4f0ef35 100644 --- a/briar-core/src/main/java/org/briarproject/briar/privategroup/invitation/GroupInvitationConstants.java +++ b/briar-core/src/main/java/org/briarproject/briar/privategroup/invitation/GroupInvitationConstants.java @@ -13,6 +13,7 @@ interface GroupInvitationConstants { String MSG_KEY_VISIBLE_IN_UI = "visibleInUi"; String MSG_KEY_AVAILABLE_TO_ANSWER = "availableToAnswer"; String MSG_KEY_INVITATION_ACCEPTED = "invitationAccepted"; + String MSG_KEY_AUTO_DELETE_TIMER = "autoDeleteTimer"; // Session keys String SESSION_KEY_IS_SESSION = "isSession"; 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 8d61d5763..53e6fa838 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 @@ -159,7 +159,7 @@ class GroupInvitationManagerImpl extends ConversationClientImpl SessionId sessionId = getSessionId(meta.getPrivateGroupId()); StoredSession ss = getSession(txn, m.getGroupId(), sessionId); // Handle the message - Session session; + Session session; MessageId storageId; if (ss == null) { session = handleFirstMessage(txn, m, body, meta); @@ -189,7 +189,7 @@ class GroupInvitationManagerImpl extends ConversationClientImpl results.values().iterator().next()); } - private Session handleFirstMessage(Transaction txn, Message m, BdfList body, + private Session handleFirstMessage(Transaction txn, Message m, BdfList body, MessageMetadata meta) throws DbException, FormatException { GroupId privateGroupId = meta.getPrivateGroupId(); MessageType type = meta.getMessageType(); @@ -206,7 +206,7 @@ class GroupInvitationManagerImpl extends ConversationClientImpl } } - private Session handleMessage(Transaction txn, Message m, BdfList body, + private Session handleMessage(Transaction txn, Message m, BdfList body, MessageMetadata meta, BdfDictionary bdfSession) throws DbException, FormatException { MessageType type = meta.getMessageType(); @@ -228,7 +228,7 @@ class GroupInvitationManagerImpl extends ConversationClientImpl } } - private S handleMessage(Transaction txn, Message m, + private > S handleMessage(Transaction txn, Message m, BdfList body, MessageType type, S session, ProtocolEngine engine) throws DbException, FormatException { if (type == INVITE) { @@ -256,7 +256,7 @@ class GroupInvitationManagerImpl extends ConversationClientImpl } private void storeSession(Transaction txn, MessageId storageId, - Session session) throws DbException, FormatException { + Session session) throws DbException, FormatException { BdfDictionary d = sessionEncoder.encodeSession(session); clientHelper.mergeMessageMetadata(txn, storageId, d); } @@ -354,7 +354,7 @@ class GroupInvitationManagerImpl extends ConversationClientImpl } } - private S handleAction(Transaction txn, + private > S handleAction(Transaction txn, LocalAction type, S session, ProtocolEngine engine) throws DbException { if (type == LocalAction.INVITE) { @@ -420,7 +420,8 @@ class GroupInvitationManagerImpl extends ConversationClientImpl return new GroupInvitationRequest(m, contactGroupId, meta.getTimestamp(), meta.isLocal(), meta.isRead(), status.isSent(), status.isSeen(), sessionId, pg, - invite.getText(), meta.isAvailableToAnswer(), canBeOpened); + invite.getText(), meta.isAvailableToAnswer(), canBeOpened, + invite.getAutoDeleteTimer()); } private GroupInvitationResponse parseInvitationResponse( @@ -430,7 +431,7 @@ class GroupInvitationManagerImpl extends ConversationClientImpl return new GroupInvitationResponse(m, contactGroupId, meta.getTimestamp(), meta.isLocal(), meta.isRead(), status.isSent(), status.isSeen(), sessionId, accept, - meta.getPrivateGroupId()); + meta.getPrivateGroupId(), meta.getAutoDeleteTimer()); } @Override @@ -508,7 +509,7 @@ class GroupInvitationManagerImpl extends ConversationClientImpl SessionId sessionId = getSessionId(privateGroupId); StoredSession ss = getSession(txn, contactGroupId, sessionId); // Create or parse the session - Session session; + Session session; MessageId storageId; if (ss == null) { // If there's no session the contact must be a peer, @@ -543,7 +544,7 @@ class GroupInvitationManagerImpl extends ConversationClientImpl StoredSession ss = getSession(txn, contactGroupId, sessionId); if (ss == null) continue; // No session for this contact // Handle the action - Session session = handleAction(txn, LocalAction.LEAVE, + Session session = handleAction(txn, LocalAction.LEAVE, contactGroupId, ss.bdfSession); // Store the updated session storeSession(txn, ss.storageId, session); @@ -553,7 +554,7 @@ class GroupInvitationManagerImpl extends ConversationClientImpl } } - private Session handleAction(Transaction txn, LocalAction a, + private Session handleAction(Transaction txn, LocalAction a, GroupId contactGroupId, BdfDictionary bdfSession) throws DbException, FormatException { Role role = sessionParser.getRole(bdfSession); @@ -613,7 +614,7 @@ class GroupInvitationManagerImpl extends ConversationClientImpl .getMessageMetadataAsDictionary(txn, contactGroupId, query); Map m = new HashMap<>(); for (BdfDictionary d : results.values()) { - Session s = sessionParser.parseSession(contactGroupId, d); + Session s = sessionParser.parseSession(contactGroupId, d); m.put(s.getPrivateGroupId(), s.getState().getVisibility()); } return m; @@ -644,7 +645,7 @@ class GroupInvitationManagerImpl extends ConversationClientImpl Map sessions = new HashMap<>(); for (BdfDictionary d : metadata.values()) { if (!sessionParser.isSession(d)) continue; - Session session; + Session session; try { session = sessionParser.parseSession(g, d); } catch (FormatException e) { @@ -673,7 +674,7 @@ class GroupInvitationManagerImpl extends ConversationClientImpl getSessionId(messageMetadata.getPrivateGroupId()); StoredSession ss = getSession(txn1, g, sessionId); if (ss == null) throw new DbException(); - Session session = sessionParser + Session session = sessionParser .parseSession(g, metadata.get(ss.storageId)); sessions.put(session.getPrivateGroupId(), new DeletableSession(session.getState())); diff --git a/briar-core/src/main/java/org/briarproject/briar/privategroup/invitation/GroupInvitationValidator.java b/briar-core/src/main/java/org/briarproject/briar/privategroup/invitation/GroupInvitationValidator.java index 8e0505759..0896ea6ac 100644 --- a/briar-core/src/main/java/org/briarproject/briar/privategroup/invitation/GroupInvitationValidator.java +++ b/briar-core/src/main/java/org/briarproject/briar/privategroup/invitation/GroupInvitationValidator.java @@ -21,10 +21,15 @@ import org.briarproject.briar.api.privategroup.PrivateGroupFactory; import java.security.GeneralSecurityException; import java.util.Collections; +import javax.annotation.Nullable; import javax.annotation.concurrent.Immutable; +import static org.briarproject.bramble.api.autodelete.AutoDeleteConstants.MAX_AUTO_DELETE_TIMER_MS; +import static org.briarproject.bramble.api.autodelete.AutoDeleteConstants.MIN_AUTO_DELETE_TIMER_MS; +import static org.briarproject.bramble.api.autodelete.AutoDeleteConstants.NO_AUTO_DELETE_TIMER; import static org.briarproject.bramble.api.identity.AuthorConstants.MAX_SIGNATURE_LENGTH; import static org.briarproject.bramble.util.ValidationUtils.checkLength; +import static org.briarproject.bramble.util.ValidationUtils.checkRange; import static org.briarproject.bramble.util.ValidationUtils.checkSize; import static org.briarproject.briar.api.privategroup.PrivateGroupConstants.GROUP_SALT_LENGTH; import static org.briarproject.briar.api.privategroup.PrivateGroupConstants.MAX_GROUP_INVITATION_TEXT_LENGTH; @@ -71,8 +76,11 @@ class GroupInvitationValidator extends BdfMessageValidator { private BdfMessageContext validateInviteMessage(Message m, BdfList body) throws FormatException { - // Message type, creator, group name, salt, optional text, signature - checkSize(body, 6); + // Client version 0.0: Message type, creator, group name, salt, + // optional text, signature. + // Client version 0.1: Message type, creator, group name, salt, + // optional text, signature, optional auto-delete timer. + checkSize(body, 6, 7); BdfList creatorList = body.getList(1); String groupName = body.getString(2); checkLength(groupName, 1, MAX_GROUP_NAME_LENGTH); @@ -82,6 +90,8 @@ class GroupInvitationValidator extends BdfMessageValidator { checkLength(text, 1, MAX_GROUP_INVITATION_TEXT_LENGTH); byte[] signature = body.getRaw(5); checkLength(signature, 1, MAX_SIGNATURE_LENGTH); + long timer = NO_AUTO_DELETE_TIMER; + if (body.size() == 7) timer = validateTimer(body.getOptionalLong(6)); // Validate the creator and create the private group Author creator = clientHelper.parseAndValidateAuthor(creatorList); @@ -102,20 +112,27 @@ class GroupInvitationValidator extends BdfMessageValidator { // Create the metadata BdfDictionary meta = messageEncoder.encodeMetadata(INVITE, privateGroup.getId(), m.getTimestamp(), false, false, false, - false, false); + false, false, timer); return new BdfMessageContext(meta); } private BdfMessageContext validateJoinMessage(Message m, BdfList body) throws FormatException { - checkSize(body, 3); + // Client version 0.0: Message type, private group ID, optional + // previous message ID. + // Client version 0.1: Message type, private group ID, optional + // previous message ID, optional auto-delete timer. + checkSize(body, 3, 4); byte[] privateGroupId = body.getRaw(1); checkLength(privateGroupId, UniqueId.LENGTH); byte[] previousMessageId = body.getOptionalRaw(2); checkLength(previousMessageId, UniqueId.LENGTH); + long timer = NO_AUTO_DELETE_TIMER; + if (body.size() == 4) timer = validateTimer(body.getOptionalLong(3)); + BdfDictionary meta = messageEncoder.encodeMetadata(JOIN, new GroupId(privateGroupId), m.getTimestamp(), false, false, - false, false, false); + false, false, false, timer); if (previousMessageId == null) { return new BdfMessageContext(meta); } else { @@ -127,14 +144,21 @@ class GroupInvitationValidator extends BdfMessageValidator { private BdfMessageContext validateLeaveMessage(Message m, BdfList body) throws FormatException { - checkSize(body, 3); + // Client version 0.0: Message type, private group ID, optional + // previous message ID. + // Client version 0.1: Message type, private group ID, optional + // previous message ID, optional auto-delete timer. + checkSize(body, 3, 4); byte[] privateGroupId = body.getRaw(1); checkLength(privateGroupId, UniqueId.LENGTH); byte[] previousMessageId = body.getOptionalRaw(2); checkLength(previousMessageId, UniqueId.LENGTH); + long timer = NO_AUTO_DELETE_TIMER; + if (body.size() == 4) timer = validateTimer(body.getOptionalLong(3)); + BdfDictionary meta = messageEncoder.encodeMetadata(LEAVE, new GroupId(privateGroupId), m.getTimestamp(), false, false, - false, false, false); + false, false, false, timer); if (previousMessageId == null) { return new BdfMessageContext(meta); } else { @@ -151,7 +175,13 @@ class GroupInvitationValidator extends BdfMessageValidator { checkLength(privateGroupId, UniqueId.LENGTH); BdfDictionary meta = messageEncoder.encodeMetadata(ABORT, new GroupId(privateGroupId), m.getTimestamp(), false, false, - false, false, false); + false, false, false, NO_AUTO_DELETE_TIMER); return new BdfMessageContext(meta); } + + private long validateTimer(@Nullable Long timer) throws FormatException { + if (timer == null) return NO_AUTO_DELETE_TIMER; + checkRange(timer, MIN_AUTO_DELETE_TIMER_MS, MAX_AUTO_DELETE_TIMER_MS); + return timer; + } } diff --git a/briar-core/src/main/java/org/briarproject/briar/privategroup/invitation/InviteMessage.java b/briar-core/src/main/java/org/briarproject/briar/privategroup/invitation/InviteMessage.java index 5d97e3f7e..a9dc59329 100644 --- a/briar-core/src/main/java/org/briarproject/briar/privategroup/invitation/InviteMessage.java +++ b/briar-core/src/main/java/org/briarproject/briar/privategroup/invitation/InviteMessage.java @@ -10,7 +10,7 @@ import javax.annotation.concurrent.Immutable; @Immutable @NotNullByDefault -class InviteMessage extends GroupInvitationMessage { +class InviteMessage extends DeletableGroupInvitationMessage { private final String groupName; private final Author creator; @@ -20,8 +20,8 @@ class InviteMessage extends GroupInvitationMessage { InviteMessage(MessageId id, GroupId contactGroupId, GroupId privateGroupId, long timestamp, String groupName, Author creator, byte[] salt, - @Nullable String text, byte[] signature) { - super(id, contactGroupId, privateGroupId, timestamp); + @Nullable String text, byte[] signature, long autoDeleteTimer) { + super(id, contactGroupId, privateGroupId, timestamp, autoDeleteTimer); this.groupName = groupName; this.creator = creator; this.salt = salt; 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 abf489ac6..b4a7665fd 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 @@ -330,7 +330,7 @@ class InviteeProtocolEngine extends AbstractProtocolEngine { SessionId sessionId = new SessionId(m.getPrivateGroupId().getBytes()); return new GroupInvitationRequest(m.getId(), m.getContactGroupId(), m.getTimestamp(), false, false, false, false, sessionId, pg, - m.getText(), true, false); + m.getText(), true, false, m.getAutoDeleteTimer()); } } diff --git a/briar-core/src/main/java/org/briarproject/briar/privategroup/invitation/JoinMessage.java b/briar-core/src/main/java/org/briarproject/briar/privategroup/invitation/JoinMessage.java index 77d6e3eef..4b4c2b0eb 100644 --- a/briar-core/src/main/java/org/briarproject/briar/privategroup/invitation/JoinMessage.java +++ b/briar-core/src/main/java/org/briarproject/briar/privategroup/invitation/JoinMessage.java @@ -9,14 +9,15 @@ import javax.annotation.concurrent.Immutable; @Immutable @NotNullByDefault -class JoinMessage extends GroupInvitationMessage { +class JoinMessage extends DeletableGroupInvitationMessage { @Nullable private final MessageId previousMessageId; JoinMessage(MessageId id, GroupId contactGroupId, GroupId privateGroupId, - long timestamp, @Nullable MessageId previousMessageId) { - super(id, contactGroupId, privateGroupId, timestamp); + long timestamp, @Nullable MessageId previousMessageId, + long autoDeleteTimer) { + super(id, contactGroupId, privateGroupId, timestamp, autoDeleteTimer); this.previousMessageId = previousMessageId; } diff --git a/briar-core/src/main/java/org/briarproject/briar/privategroup/invitation/LeaveMessage.java b/briar-core/src/main/java/org/briarproject/briar/privategroup/invitation/LeaveMessage.java index cf323fe81..a442ba894 100644 --- a/briar-core/src/main/java/org/briarproject/briar/privategroup/invitation/LeaveMessage.java +++ b/briar-core/src/main/java/org/briarproject/briar/privategroup/invitation/LeaveMessage.java @@ -9,14 +9,15 @@ import javax.annotation.concurrent.Immutable; @Immutable @NotNullByDefault -class LeaveMessage extends GroupInvitationMessage { +class LeaveMessage extends DeletableGroupInvitationMessage { @Nullable private final MessageId previousMessageId; LeaveMessage(MessageId id, GroupId contactGroupId, GroupId privateGroupId, - long timestamp, @Nullable MessageId previousMessageId) { - super(id, contactGroupId, privateGroupId, timestamp); + long timestamp, @Nullable MessageId previousMessageId, + long autoDeleteTimer) { + super(id, contactGroupId, privateGroupId, timestamp, autoDeleteTimer); this.previousMessageId = previousMessageId; } diff --git a/briar-core/src/main/java/org/briarproject/briar/privategroup/invitation/MessageEncoder.java b/briar-core/src/main/java/org/briarproject/briar/privategroup/invitation/MessageEncoder.java index 8ba1caaa7..7f65a8c42 100644 --- a/briar-core/src/main/java/org/briarproject/briar/privategroup/invitation/MessageEncoder.java +++ b/briar-core/src/main/java/org/briarproject/briar/privategroup/invitation/MessageEncoder.java @@ -14,7 +14,7 @@ interface MessageEncoder { BdfDictionary encodeMetadata(MessageType type, GroupId privateGroupId, long timestamp, boolean local, boolean read, boolean visible, - boolean available, boolean accepted); + boolean available, boolean accepted, long autoDeleteTimer); void setVisibleInUi(BdfDictionary meta, boolean visible); @@ -22,16 +22,49 @@ interface MessageEncoder { void setInvitationAccepted(BdfDictionary meta, boolean accepted); + /** + * Encodes an invite message without an auto-delete timer. + */ Message encodeInviteMessage(GroupId contactGroupId, GroupId privateGroupId, long timestamp, String groupName, Author creator, byte[] salt, @Nullable String text, byte[] signature); + /** + * Encodes an invite message with an optional auto-delete timer. This + * requires the contact to support client version 0.1 or higher. + */ + Message encodeInviteMessage(GroupId contactGroupId, GroupId privateGroupId, + long timestamp, String groupName, Author creator, byte[] salt, + @Nullable String text, byte[] signature, long autoDeleteTimer); + + /** + * Encodes a join message without an auto-delete timer. + */ Message encodeJoinMessage(GroupId contactGroupId, GroupId privateGroupId, long timestamp, @Nullable MessageId previousMessageId); + /** + * Encodes a join message with an optional auto-delete timer. This + * requires the contact to support client version 0.1 or higher. + */ + Message encodeJoinMessage(GroupId contactGroupId, GroupId privateGroupId, + long timestamp, @Nullable MessageId previousMessageId, + long autoDeleteTimer); + + /** + * Encodes a leave message without an auto-delete timer. + */ Message encodeLeaveMessage(GroupId contactGroupId, GroupId privateGroupId, long timestamp, @Nullable MessageId previousMessageId); + /** + * Encodes a leave message with an optional auto-delete timer. This + * requires the contact to support client version 0.1 or higher. + */ + Message encodeLeaveMessage(GroupId contactGroupId, GroupId privateGroupId, + long timestamp, @Nullable MessageId previousMessageId, + long autoDeleteTimer); + Message encodeAbortMessage(GroupId contactGroupId, GroupId privateGroupId, long timestamp); } diff --git a/briar-core/src/main/java/org/briarproject/briar/privategroup/invitation/MessageEncoderImpl.java b/briar-core/src/main/java/org/briarproject/briar/privategroup/invitation/MessageEncoderImpl.java index 43f208a94..b326a61b4 100644 --- a/briar-core/src/main/java/org/briarproject/briar/privategroup/invitation/MessageEncoderImpl.java +++ b/briar-core/src/main/java/org/briarproject/briar/privategroup/invitation/MessageEncoderImpl.java @@ -15,7 +15,9 @@ import javax.annotation.Nullable; import javax.annotation.concurrent.Immutable; import javax.inject.Inject; +import static org.briarproject.bramble.api.autodelete.AutoDeleteConstants.NO_AUTO_DELETE_TIMER; import static org.briarproject.briar.client.MessageTrackerConstants.MSG_KEY_READ; +import static org.briarproject.briar.privategroup.invitation.GroupInvitationConstants.MSG_KEY_AUTO_DELETE_TIMER; import static org.briarproject.briar.privategroup.invitation.GroupInvitationConstants.MSG_KEY_AVAILABLE_TO_ANSWER; import static org.briarproject.briar.privategroup.invitation.GroupInvitationConstants.MSG_KEY_INVITATION_ACCEPTED; import static org.briarproject.briar.privategroup.invitation.GroupInvitationConstants.MSG_KEY_LOCAL; @@ -45,7 +47,8 @@ class MessageEncoderImpl implements MessageEncoder { @Override public BdfDictionary encodeMetadata(MessageType type, GroupId privateGroupId, long timestamp, boolean local, boolean read, - boolean visible, boolean available, boolean accepted) { + boolean visible, boolean available, boolean accepted, + long autoDeleteTimer) { BdfDictionary meta = new BdfDictionary(); meta.put(MSG_KEY_MESSAGE_TYPE, type.getValue()); meta.put(MSG_KEY_PRIVATE_GROUP_ID, privateGroupId); @@ -55,6 +58,9 @@ class MessageEncoderImpl implements MessageEncoder { meta.put(MSG_KEY_VISIBLE_IN_UI, visible); meta.put(MSG_KEY_AVAILABLE_TO_ANSWER, available); meta.put(MSG_KEY_INVITATION_ACCEPTED, accepted); + if (autoDeleteTimer != NO_AUTO_DELETE_TIMER) { + meta.put(MSG_KEY_AUTO_DELETE_TIMER, autoDeleteTimer); + } return meta; } @@ -87,12 +93,25 @@ class MessageEncoderImpl implements MessageEncoder { text, signature ); - try { - return messageFactory.createMessage(contactGroupId, timestamp, - clientHelper.toByteArray(body)); - } catch (FormatException e) { - throw new AssertionError(e); - } + return createMessage(contactGroupId, timestamp, body); + } + + @Override + public Message encodeInviteMessage(GroupId contactGroupId, + GroupId privateGroupId, long timestamp, String groupName, + Author creator, byte[] salt, @Nullable String text, + byte[] signature, long autoDeleteTimer) { + BdfList creatorList = clientHelper.toList(creator); + BdfList body = BdfList.of( + INVITE.getValue(), + creatorList, + groupName, + salt, + text, + signature, + encodeTimer(autoDeleteTimer) + ); + return createMessage(contactGroupId, timestamp, body); } @Override @@ -104,12 +123,20 @@ class MessageEncoderImpl implements MessageEncoder { privateGroupId, previousMessageId ); - try { - return messageFactory.createMessage(contactGroupId, timestamp, - clientHelper.toByteArray(body)); - } catch (FormatException e) { - throw new AssertionError(e); - } + return createMessage(contactGroupId, timestamp, body); + } + + @Override + public Message encodeJoinMessage(GroupId contactGroupId, + GroupId privateGroupId, long timestamp, + @Nullable MessageId previousMessageId, long autoDeleteTimer) { + BdfList body = BdfList.of( + JOIN.getValue(), + privateGroupId, + previousMessageId, + encodeTimer(autoDeleteTimer) + ); + return createMessage(contactGroupId, timestamp, body); } @Override @@ -121,12 +148,20 @@ class MessageEncoderImpl implements MessageEncoder { privateGroupId, previousMessageId ); - try { - return messageFactory.createMessage(contactGroupId, timestamp, - clientHelper.toByteArray(body)); - } catch (FormatException e) { - throw new AssertionError(e); - } + return createMessage(contactGroupId, timestamp, body); + } + + @Override + public Message encodeLeaveMessage(GroupId contactGroupId, + GroupId privateGroupId, long timestamp, + @Nullable MessageId previousMessageId, long autoDeleteTimer) { + BdfList body = BdfList.of( + LEAVE.getValue(), + privateGroupId, + previousMessageId, + encodeTimer(autoDeleteTimer) + ); + return createMessage(contactGroupId, timestamp, body); } @Override @@ -136,6 +171,11 @@ class MessageEncoderImpl implements MessageEncoder { ABORT.getValue(), privateGroupId ); + return createMessage(contactGroupId, timestamp, body); + } + + private Message createMessage(GroupId contactGroupId, long timestamp, + BdfList body) { try { return messageFactory.createMessage(contactGroupId, timestamp, clientHelper.toByteArray(body)); @@ -143,4 +183,9 @@ class MessageEncoderImpl implements MessageEncoder { throw new AssertionError(e); } } + + @Nullable + private Long encodeTimer(long autoDeleteTimer) { + return autoDeleteTimer == NO_AUTO_DELETE_TIMER ? null : autoDeleteTimer; + } } diff --git a/briar-core/src/main/java/org/briarproject/briar/privategroup/invitation/MessageMetadata.java b/briar-core/src/main/java/org/briarproject/briar/privategroup/invitation/MessageMetadata.java index c4490641d..f847a98fd 100644 --- a/briar-core/src/main/java/org/briarproject/briar/privategroup/invitation/MessageMetadata.java +++ b/briar-core/src/main/java/org/briarproject/briar/privategroup/invitation/MessageMetadata.java @@ -11,12 +11,12 @@ class MessageMetadata { private final MessageType type; private final GroupId privateGroupId; - private final long timestamp; + private final long timestamp, autoDeleteTimer; private final boolean local, read, visible, available, accepted; MessageMetadata(MessageType type, GroupId privateGroupId, long timestamp, boolean local, boolean read, boolean visible, - boolean available, boolean accepted) { + boolean available, boolean accepted, long autoDeleteTimer) { this.privateGroupId = privateGroupId; this.type = type; this.timestamp = timestamp; @@ -25,6 +25,7 @@ class MessageMetadata { this.visible = visible; this.available = available; this.accepted = accepted; + this.autoDeleteTimer = autoDeleteTimer; } MessageType getMessageType() { @@ -64,4 +65,7 @@ class MessageMetadata { return accepted; } + public long getAutoDeleteTimer() { + return autoDeleteTimer; + } } diff --git a/briar-core/src/main/java/org/briarproject/briar/privategroup/invitation/MessageParserImpl.java b/briar-core/src/main/java/org/briarproject/briar/privategroup/invitation/MessageParserImpl.java index cd850f949..4249b7952 100644 --- a/briar-core/src/main/java/org/briarproject/briar/privategroup/invitation/MessageParserImpl.java +++ b/briar-core/src/main/java/org/briarproject/briar/privategroup/invitation/MessageParserImpl.java @@ -8,7 +8,6 @@ import org.briarproject.bramble.api.data.BdfList; import org.briarproject.bramble.api.db.DbException; import org.briarproject.bramble.api.db.Transaction; import org.briarproject.bramble.api.identity.Author; -import org.briarproject.bramble.api.identity.AuthorFactory; import org.briarproject.bramble.api.nullsafety.NotNullByDefault; import org.briarproject.bramble.api.sync.GroupId; import org.briarproject.bramble.api.sync.Message; @@ -19,7 +18,9 @@ import org.briarproject.briar.api.privategroup.PrivateGroupFactory; import javax.annotation.concurrent.Immutable; import javax.inject.Inject; +import static org.briarproject.bramble.api.autodelete.AutoDeleteConstants.NO_AUTO_DELETE_TIMER; import static org.briarproject.briar.client.MessageTrackerConstants.MSG_KEY_READ; +import static org.briarproject.briar.privategroup.invitation.GroupInvitationConstants.MSG_KEY_AUTO_DELETE_TIMER; import static org.briarproject.briar.privategroup.invitation.GroupInvitationConstants.MSG_KEY_AVAILABLE_TO_ANSWER; import static org.briarproject.briar.privategroup.invitation.GroupInvitationConstants.MSG_KEY_INVITATION_ACCEPTED; import static org.briarproject.briar.privategroup.invitation.GroupInvitationConstants.MSG_KEY_LOCAL; @@ -33,15 +34,12 @@ import static org.briarproject.briar.privategroup.invitation.MessageType.INVITE; @NotNullByDefault class MessageParserImpl implements MessageParser { - private final AuthorFactory authorFactory; private final PrivateGroupFactory privateGroupFactory; private final ClientHelper clientHelper; @Inject - MessageParserImpl(AuthorFactory authorFactory, - PrivateGroupFactory privateGroupFactory, + MessageParserImpl(PrivateGroupFactory privateGroupFactory, ClientHelper clientHelper) { - this.authorFactory = authorFactory; this.privateGroupFactory = privateGroupFactory; this.clientHelper = clientHelper; } @@ -82,8 +80,10 @@ class MessageParserImpl implements MessageParser { boolean visible = meta.getBoolean(MSG_KEY_VISIBLE_IN_UI, false); boolean available = meta.getBoolean(MSG_KEY_AVAILABLE_TO_ANSWER, false); boolean accepted = meta.getBoolean(MSG_KEY_INVITATION_ACCEPTED, false); + long timer = meta.getLong(MSG_KEY_AUTO_DELETE_TIMER, + NO_AUTO_DELETE_TIMER); return new MessageMetadata(type, privateGroupId, timestamp, local, read, - visible, available, accepted); + visible, available, accepted, timer); } @Override @@ -97,39 +97,58 @@ class MessageParserImpl implements MessageParser { @Override public InviteMessage parseInviteMessage(Message m, BdfList body) throws FormatException { - // Message type, creator, group name, salt, optional text, signature + // Client version 0.0: Message type, creator, group name, salt, + // optional text, signature. + // Client version 0.1: Message type, creator, group name, salt, + // optional text, signature, optional auto-delete timer. BdfList creatorList = body.getList(1); String groupName = body.getString(2); byte[] salt = body.getRaw(3); String text = body.getOptionalString(4); byte[] signature = body.getRaw(5); + long timer = NO_AUTO_DELETE_TIMER; + if (body.size() == 7) timer = body.getLong(6, NO_AUTO_DELETE_TIMER); Author creator = clientHelper.parseAndValidateAuthor(creatorList); PrivateGroup privateGroup = privateGroupFactory.createPrivateGroup( groupName, creator, salt); return new InviteMessage(m.getId(), m.getGroupId(), privateGroup.getId(), m.getTimestamp(), groupName, creator, - salt, text, signature); + salt, text, signature, timer); } @Override public JoinMessage parseJoinMessage(Message m, BdfList body) throws FormatException { + // Client version 0.0: Message type, private group ID, optional + // previous message ID. + // Client version 0.1: Message type, private group ID, optional + // previous message ID, optional auto-delete timer. GroupId privateGroupId = new GroupId(body.getRaw(1)); byte[] b = body.getOptionalRaw(2); MessageId previousMessageId = b == null ? null : new MessageId(b); + long timer = NO_AUTO_DELETE_TIMER; + if (body.size() == 4) timer = body.getLong(3, NO_AUTO_DELETE_TIMER); + return new JoinMessage(m.getId(), m.getGroupId(), privateGroupId, - m.getTimestamp(), previousMessageId); + m.getTimestamp(), previousMessageId, timer); } @Override public LeaveMessage parseLeaveMessage(Message m, BdfList body) throws FormatException { + // Client version 0.0: Message type, private group ID, optional + // previous message ID. + // Client version 0.1: Message type, private group ID, optional + // previous message ID, optional auto-delete timer. GroupId privateGroupId = new GroupId(body.getRaw(1)); byte[] b = body.getOptionalRaw(2); MessageId previousMessageId = b == null ? null : new MessageId(b); + long timer = NO_AUTO_DELETE_TIMER; + if (body.size() == 4) timer = body.getLong(3, NO_AUTO_DELETE_TIMER); + return new LeaveMessage(m.getId(), m.getGroupId(), privateGroupId, - m.getTimestamp(), previousMessageId); + m.getTimestamp(), previousMessageId, timer); } @Override 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 262327aa2..a003e34a7 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 @@ -22,8 +22,10 @@ import org.briarproject.briar.api.privategroup.GroupMessageFactory; import org.briarproject.briar.api.privategroup.PrivateGroup; import org.briarproject.briar.api.privategroup.PrivateGroupFactory; import org.briarproject.briar.api.privategroup.PrivateGroupManager; +import org.briarproject.briar.api.privategroup.invitation.GroupInvitationManager; import org.jmock.Expectations; +import static org.briarproject.bramble.api.autodelete.AutoDeleteConstants.NO_AUTO_DELETE_TIMER; import static org.briarproject.bramble.api.identity.AuthorConstants.MAX_SIGNATURE_LENGTH; import static org.briarproject.bramble.api.sync.Group.Visibility.SHARED; import static org.briarproject.bramble.test.TestUtils.getContact; @@ -35,8 +37,6 @@ import static org.briarproject.bramble.util.StringUtils.getRandomString; import static org.briarproject.briar.api.privategroup.PrivateGroupConstants.GROUP_SALT_LENGTH; import static org.briarproject.briar.api.privategroup.PrivateGroupConstants.MAX_GROUP_INVITATION_TEXT_LENGTH; import static org.briarproject.briar.api.privategroup.PrivateGroupConstants.MAX_GROUP_NAME_LENGTH; -import static org.briarproject.briar.api.privategroup.PrivateGroupManager.CLIENT_ID; -import static org.briarproject.briar.api.privategroup.PrivateGroupManager.MAJOR_VERSION; import static org.briarproject.briar.privategroup.invitation.GroupInvitationConstants.GROUP_KEY_CONTACT_ID; import static org.briarproject.briar.privategroup.invitation.MessageType.ABORT; import static org.briarproject.briar.privategroup.invitation.MessageType.INVITE; @@ -67,7 +67,8 @@ abstract class AbstractProtocolEngineTest extends BrambleMockTestCase { final ContactId contactId = contact.getId(); final Author author = contact.getAuthor(); final GroupId contactGroupId = new GroupId(getRandomId()); - final Group privateGroupGroup = getGroup(CLIENT_ID, MAJOR_VERSION); + final Group privateGroupGroup = getGroup(PrivateGroupManager.CLIENT_ID, + PrivateGroupManager.MAJOR_VERSION); final GroupId privateGroupId = privateGroupGroup.getId(); final PrivateGroup privateGroup = new PrivateGroup(privateGroupGroup, getRandomString(MAX_GROUP_NAME_LENGTH), author, @@ -80,30 +81,34 @@ abstract class AbstractProtocolEngineTest extends BrambleMockTestCase { final long messageTimestamp = message.getTimestamp(); final long inviteTimestamp = messageTimestamp - 1; final long localTimestamp = inviteTimestamp - 1; + final BdfDictionary groupMeta = BdfDictionary.of( + new BdfEntry(GROUP_KEY_CONTACT_ID, contactId.getInt())); final InviteMessage inviteMessage = new InviteMessage(new MessageId(getRandomId()), contactGroupId, privateGroupId, 0L, privateGroup.getName(), privateGroup.getCreator(), privateGroup.getSalt(), getRandomString(MAX_GROUP_INVITATION_TEXT_LENGTH), - signature); + signature, NO_AUTO_DELETE_TIMER); final JoinMessage joinMessage = new JoinMessage(new MessageId(getRandomId()), contactGroupId, - privateGroupId, 0L, lastRemoteMessageId); + privateGroupId, 0L, lastRemoteMessageId, + NO_AUTO_DELETE_TIMER); final LeaveMessage leaveMessage = new LeaveMessage(new MessageId(getRandomId()), contactGroupId, - privateGroupId, 0L, lastRemoteMessageId); + privateGroupId, 0L, lastRemoteMessageId, + NO_AUTO_DELETE_TIMER); final AbortMessage abortMessage = new AbortMessage(messageId, contactGroupId, privateGroupId, inviteTimestamp + 1); - void assertSessionConstantsUnchanged(Session s1, Session s2) { + void assertSessionConstantsUnchanged(Session s1, Session s2) { assertEquals(s1.getRole(), s2.getRole()); assertEquals(s1.getContactGroupId(), s2.getContactGroupId()); assertEquals(s1.getPrivateGroupId(), s2.getPrivateGroupId()); } - void assertSessionRecordedSentMessage(Session s) { + void assertSessionRecordedSentMessage(Session s) { assertEquals(messageId, s.getLastLocalMessageId()); assertEquals(lastRemoteMessageId, s.getLastRemoteMessageId()); assertEquals(messageTimestamp, s.getLocalTimestamp()); @@ -118,11 +123,13 @@ abstract class AbstractProtocolEngineTest extends BrambleMockTestCase { } void expectSendInviteMessage(String text) throws Exception { + expectCheckWhetherContactSupportsAutoDeletion(); + expectGetLocalTimestamp(messageTimestamp); context.checking(new Expectations() {{ - oneOf(messageEncoder) - .encodeInviteMessage(contactGroupId, privateGroupId, - inviteTimestamp, privateGroup.getName(), author, - privateGroup.getSalt(), text, signature); + oneOf(messageEncoder).encodeInviteMessage(contactGroupId, + privateGroupId, inviteTimestamp, privateGroup.getName(), + author, privateGroup.getSalt(), text, signature, + NO_AUTO_DELETE_TIMER); will(returnValue(message)); }}); expectSendMessage(INVITE, true); @@ -130,22 +137,24 @@ abstract class AbstractProtocolEngineTest extends BrambleMockTestCase { void expectSendJoinMessage(JoinMessage m, boolean visible) throws Exception { + expectCheckWhetherContactSupportsAutoDeletion(); expectGetLocalTimestamp(messageTimestamp); context.checking(new Expectations() {{ oneOf(messageEncoder).encodeJoinMessage(m.getContactGroupId(), m.getPrivateGroupId(), m.getTimestamp(), - lastLocalMessageId); + lastLocalMessageId, NO_AUTO_DELETE_TIMER); will(returnValue(message)); }}); expectSendMessage(JOIN, visible); } void expectSendLeaveMessage(boolean visible) throws Exception { + expectCheckWhetherContactSupportsAutoDeletion(); expectGetLocalTimestamp(messageTimestamp); context.checking(new Expectations() {{ - oneOf(messageEncoder) - .encodeLeaveMessage(contactGroupId, privateGroupId, - messageTimestamp, lastLocalMessageId); + oneOf(messageEncoder).encodeLeaveMessage(contactGroupId, + privateGroupId, messageTimestamp, lastLocalMessageId, + NO_AUTO_DELETE_TIMER); will(returnValue(message)); }}); expectSendMessage(LEAVE, visible); @@ -167,7 +176,8 @@ abstract class AbstractProtocolEngineTest extends BrambleMockTestCase { BdfDictionary meta = BdfDictionary.of(new BdfEntry("me", "ta")); context.checking(new Expectations() {{ oneOf(messageEncoder).encodeMetadata(type, privateGroupId, - message.getTimestamp(), true, true, visible, false, false); + message.getTimestamp(), true, true, visible, false, false, + NO_AUTO_DELETE_TIMER); will(returnValue(meta)); oneOf(clientHelper).addLocalMessage(txn, message, meta, true, false); @@ -178,7 +188,8 @@ abstract class AbstractProtocolEngineTest extends BrambleMockTestCase { expectGetContactId(); context.checking(new Expectations() {{ oneOf(clientVersioningManager).getClientVisibility(txn, contactId, - CLIENT_ID, MAJOR_VERSION); + PrivateGroupManager.CLIENT_ID, + PrivateGroupManager.MAJOR_VERSION); will(returnValue(SHARED)); oneOf(db).setGroupVisibility(txn, contactId, privateGroupId, v); }}); @@ -218,4 +229,15 @@ abstract class AbstractProtocolEngineTest extends BrambleMockTestCase { }}); } + void expectCheckWhetherContactSupportsAutoDeletion() throws Exception { + context.checking(new Expectations() {{ + oneOf(clientHelper).getGroupMetadataAsDictionary(txn, + contactGroupId); + will(returnValue(groupMeta)); + oneOf(clientVersioningManager).getClientMinorVersion(txn, contactId, + GroupInvitationManager.CLIENT_ID, + GroupInvitationManager.MAJOR_VERSION); + will(returnValue(GroupInvitationManager.MINOR_VERSION)); + }}); + } } 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 9495b19ec..559a6de93 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 @@ -5,6 +5,7 @@ import org.briarproject.briar.api.client.ProtocolStateException; import org.jmock.Expectations; import org.junit.Test; +import static org.briarproject.bramble.api.autodelete.AutoDeleteConstants.NO_AUTO_DELETE_TIMER; import static org.briarproject.bramble.api.sync.Group.Visibility.INVISIBLE; import static org.briarproject.bramble.api.sync.Group.Visibility.SHARED; import static org.briarproject.bramble.test.TestUtils.getRandomId; @@ -77,7 +78,6 @@ public class CreatorProtocolEngineTest extends AbstractProtocolEngineTest { oneOf(messageTracker).trackOutgoingMessage(txn, message); }}); expectSendInviteMessage(text); - expectGetLocalTimestamp(messageTimestamp); } @Test(expected = ProtocolStateException.class) @@ -289,7 +289,7 @@ public class CreatorProtocolEngineTest extends AbstractProtocolEngineTest { CreatorSession session = getDefaultSession(INVITED); JoinMessage invalidJoinMessage = new JoinMessage(messageId, contactGroupId, privateGroupId, - inviteTimestamp + 1, messageId); + inviteTimestamp + 1, messageId, NO_AUTO_DELETE_TIMER); expectAbortWhenSubscribedToGroup(); CreatorSession newSession = @@ -303,7 +303,7 @@ public class CreatorProtocolEngineTest extends AbstractProtocolEngineTest { JoinMessage properJoinMessage = new JoinMessage(new MessageId(getRandomId()), contactGroupId, privateGroupId, inviteTimestamp + 1, - lastRemoteMessageId); + lastRemoteMessageId, NO_AUTO_DELETE_TIMER); expectSendJoinMessage(properJoinMessage, false); expectMarkMessageVisibleInUi(properJoinMessage.getId()); @@ -343,7 +343,8 @@ public class CreatorProtocolEngineTest extends AbstractProtocolEngineTest { public void testOnLeaveMessageFromStart() throws Exception { LeaveMessage leaveMessage = new LeaveMessage(messageId, contactGroupId, privateGroupId, - inviteTimestamp, lastLocalMessageId); + inviteTimestamp, lastLocalMessageId, + NO_AUTO_DELETE_TIMER); CreatorSession session = getDefaultSession(START); expectAbortWhenSubscribedToGroup(); @@ -377,7 +378,8 @@ public class CreatorProtocolEngineTest extends AbstractProtocolEngineTest { throws Exception { LeaveMessage invalidLeaveMessage = new LeaveMessage(messageId, contactGroupId, privateGroupId, - inviteTimestamp + 1, lastLocalMessageId); + inviteTimestamp + 1, lastLocalMessageId, + NO_AUTO_DELETE_TIMER); CreatorSession session = getDefaultSession(INVITED); expectAbortWhenSubscribedToGroup(); @@ -392,7 +394,7 @@ public class CreatorProtocolEngineTest extends AbstractProtocolEngineTest { LeaveMessage properLeaveMessage = new LeaveMessage(new MessageId(getRandomId()), contactGroupId, privateGroupId, inviteTimestamp + 1, - lastRemoteMessageId); + lastRemoteMessageId, NO_AUTO_DELETE_TIMER); CreatorSession session = getDefaultSession(INVITED); expectMarkMessageVisibleInUi(properLeaveMessage.getId()); 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 58df14e7c..60d0e3758 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 @@ -45,6 +45,7 @@ import javax.annotation.Nullable; import static java.util.Arrays.asList; import static junit.framework.TestCase.fail; +import static org.briarproject.bramble.api.autodelete.AutoDeleteConstants.NO_AUTO_DELETE_TIMER; import static org.briarproject.bramble.api.sync.Group.Visibility.SHARED; import static org.briarproject.bramble.test.TestUtils.getAuthor; import static org.briarproject.bramble.test.TestUtils.getContact; @@ -230,7 +231,7 @@ public class GroupInvitationManagerImplTest extends BrambleMockTestCase { }}); } - private void expectStoreSession(Session session, MessageId storageId) + private void expectStoreSession(Session session, MessageId storageId) throws Exception { context.checking(new Expectations() {{ oneOf(sessionEncoder).encodeSession(session); @@ -320,7 +321,8 @@ public class GroupInvitationManagerImplTest extends BrambleMockTestCase { throws Exception { expectParseMessageMetadata(); expectGetSession(noResults, sessionId, contactGroup.getId()); - Session session = expectHandleFirstMessage(role, messageMetadata, type); + Session session = + expectHandleFirstMessage(role, messageMetadata, type); if (session != null) { expectCreateStorageId(); expectStoreSession(session, storageMessage.getId()); @@ -347,13 +349,13 @@ public class GroupInvitationManagerImplTest extends BrambleMockTestCase { BdfDictionary bdfSession) throws Exception { expectParseMessageMetadata(); expectGetSession(oneResult, sessionId, contactGroup.getId()); - Session session = expectHandleMessage(role, messageMetadata, bdfSession, - type); + Session session = + expectHandleMessage(role, messageMetadata, bdfSession, type); expectStoreSession(session, storageMessage.getId()); } @Nullable - private Session expectHandleFirstMessage(Role role, + private Session expectHandleFirstMessage(Role role, MessageMetadata messageMetadata, MessageType type) throws Exception { context.checking(new Expectations() {{ @@ -382,7 +384,7 @@ public class GroupInvitationManagerImplTest extends BrambleMockTestCase { } @Nullable - private Session expectHandleMessage(Role role, + private Session expectHandleMessage(Role role, MessageMetadata messageMetadata, BdfDictionary state, MessageType type) throws Exception { context.checking(new Expectations() {{ @@ -420,8 +422,9 @@ public class GroupInvitationManagerImplTest extends BrambleMockTestCase { } } - private void expectIndividualMessage(MessageType type, - ProtocolEngine engine, S session) throws Exception { + private > void expectIndividualMessage( + MessageType type, ProtocolEngine engine, S session) + throws Exception { if (type == INVITE) { InviteMessage msg = context.mock(InviteMessage.class); context.checking(new Expectations() {{ @@ -657,14 +660,14 @@ public class GroupInvitationManagerImplTest extends BrambleMockTestCase { long time1 = 1L, time2 = 2L; MessageMetadata messageMetadata1 = new MessageMetadata(INVITE, privateGroup.getId(), time1, true, - true, true, false, true); + true, true, false, true, NO_AUTO_DELETE_TIMER); MessageMetadata messageMetadata2 = new MessageMetadata(JOIN, privateGroup.getId(), time2, true, - true, true, true, false); + true, true, true, false, NO_AUTO_DELETE_TIMER); InviteMessage invite = new InviteMessage(message.getId(), contactGroup.getId(), privateGroup.getId(), time1, "name", author, - new byte[0], null, new byte[0]); + new byte[0], null, new byte[0], NO_AUTO_DELETE_TIMER); PrivateGroup pg = new PrivateGroup(privateGroup, invite.getGroupName(), invite.getCreator(), invite.getSalt()); @@ -731,11 +734,11 @@ public class GroupInvitationManagerImplTest extends BrambleMockTestCase { InviteMessage inviteMessage1 = new InviteMessage(message.getId(), contactGroup.getId(), privateGroup.getId(), time1, groupName, author, salt, - null, getRandomBytes(5)); + null, getRandomBytes(5), NO_AUTO_DELETE_TIMER); InviteMessage inviteMessage2 = new InviteMessage(message2.getId(), contactGroup.getId(), privateGroup.getId(), time2, groupName, author, salt, - null, getRandomBytes(5)); + null, getRandomBytes(5), NO_AUTO_DELETE_TIMER); PrivateGroup pg = new PrivateGroup(privateGroup, groupName, author, salt); diff --git a/briar-core/src/test/java/org/briarproject/briar/privategroup/invitation/GroupInvitationValidatorTest.java b/briar-core/src/test/java/org/briarproject/briar/privategroup/invitation/GroupInvitationValidatorTest.java index 386c35448..d8e7c0600 100644 --- a/briar-core/src/test/java/org/briarproject/briar/privategroup/invitation/GroupInvitationValidatorTest.java +++ b/briar-core/src/test/java/org/briarproject/briar/privategroup/invitation/GroupInvitationValidatorTest.java @@ -16,6 +16,7 @@ import org.junit.Test; import java.security.GeneralSecurityException; +import static org.briarproject.bramble.api.autodelete.AutoDeleteConstants.NO_AUTO_DELETE_TIMER; import static org.briarproject.bramble.api.identity.AuthorConstants.MAX_SIGNATURE_LENGTH; import static org.briarproject.bramble.test.TestUtils.getAuthor; import static org.briarproject.bramble.test.TestUtils.getRandomBytes; @@ -263,7 +264,7 @@ public class GroupInvitationValidatorTest extends ValidatorTestCase { } else { oneOf(messageEncoder).encodeMetadata(INVITE, message.getGroupId(), message.getTimestamp(), false, - false, false, false, false); + false, false, false, false, NO_AUTO_DELETE_TIMER); will(returnValue(meta)); } }}); @@ -341,7 +342,8 @@ public class GroupInvitationValidatorTest extends ValidatorTestCase { BdfList body = BdfList.of(JOIN.getValue(), privateGroup.getId(), null); context.checking(new Expectations() {{ oneOf(messageEncoder).encodeMetadata(JOIN, message.getGroupId(), - message.getTimestamp(), false, false, false, false, false); + message.getTimestamp(), false, false, false, false, false, + NO_AUTO_DELETE_TIMER); will(returnValue(meta)); }}); BdfMessageContext messageContext = @@ -356,7 +358,8 @@ public class GroupInvitationValidatorTest extends ValidatorTestCase { previousMessageId); context.checking(new Expectations() {{ oneOf(messageEncoder).encodeMetadata(JOIN, message.getGroupId(), - message.getTimestamp(), false, false, false, false, false); + message.getTimestamp(), false, false, false, false, false, + NO_AUTO_DELETE_TIMER); will(returnValue(meta)); }}); BdfMessageContext messageContext = @@ -439,7 +442,8 @@ public class GroupInvitationValidatorTest extends ValidatorTestCase { BdfList body = BdfList.of(LEAVE.getValue(), privateGroup.getId(), null); context.checking(new Expectations() {{ oneOf(messageEncoder).encodeMetadata(LEAVE, message.getGroupId(), - message.getTimestamp(), false, false, false, false, false); + message.getTimestamp(), false, false, false, false, false, + NO_AUTO_DELETE_TIMER); will(returnValue(meta)); }}); BdfMessageContext messageContext = @@ -452,7 +456,8 @@ public class GroupInvitationValidatorTest extends ValidatorTestCase { public void testAcceptsValidLeaveMessage() throws Exception { context.checking(new Expectations() {{ oneOf(messageEncoder).encodeMetadata(LEAVE, message.getGroupId(), - message.getTimestamp(), false, false, false, false, false); + message.getTimestamp(), false, false, false, false, false, + NO_AUTO_DELETE_TIMER); will(returnValue(meta)); }}); BdfList body = BdfList.of(LEAVE.getValue(), privateGroup.getId(), @@ -509,7 +514,8 @@ public class GroupInvitationValidatorTest extends ValidatorTestCase { public void testAcceptsValidAbortMessage() throws Exception { context.checking(new Expectations() {{ oneOf(messageEncoder).encodeMetadata(ABORT, message.getGroupId(), - message.getTimestamp(), false, false, false, false, false); + message.getTimestamp(), false, false, false, false, false, + NO_AUTO_DELETE_TIMER); will(returnValue(meta)); }}); BdfList body = BdfList.of(ABORT.getValue(), privateGroup.getId()); 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 e4464c389..fee724bb8 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 @@ -13,6 +13,7 @@ import org.junit.Test; import java.util.Collections; import java.util.Map; +import static org.briarproject.bramble.api.autodelete.AutoDeleteConstants.NO_AUTO_DELETE_TIMER; import static org.briarproject.bramble.api.sync.Group.Visibility.INVISIBLE; import static org.briarproject.bramble.api.sync.Group.Visibility.SHARED; import static org.briarproject.bramble.api.sync.Group.Visibility.VISIBLE; @@ -131,7 +132,8 @@ public class InviteeProtocolEngineTest extends AbstractProtocolEngineTest { public void testOnJoinActionFromInvited() throws Exception { JoinMessage properJoinMessage = new JoinMessage(messageId, contactGroupId, privateGroupId, - messageTimestamp, lastRemoteMessageId); + messageTimestamp, lastRemoteMessageId, + NO_AUTO_DELETE_TIMER); long timestamp = 0L; GroupMessage joinGroupMessage = new GroupMessage(message, null, localAuthor); @@ -329,7 +331,7 @@ public class InviteeProtocolEngineTest extends AbstractProtocolEngineTest { privateGroup.getName(), privateGroup.getCreator(), privateGroup.getSalt(), getRandomString(MAX_GROUP_INVITATION_TEXT_LENGTH), - signature); + signature, NO_AUTO_DELETE_TIMER); Contact notCreatorContact = getContact(contactId, getAuthor(), localAuthor.getId(), true); @@ -352,7 +354,8 @@ public class InviteeProtocolEngineTest extends AbstractProtocolEngineTest { new InviteMessage(new MessageId(getRandomId()), contactGroupId, privateGroupId, session.getInviteTimestamp() + 1, privateGroup.getName(), privateGroup.getCreator(), - privateGroup.getSalt(), "msg", signature); + privateGroup.getSalt(), "msg", signature, + NO_AUTO_DELETE_TIMER); assertEquals(contact.getAuthor(), privateGroup.getCreator()); expectGetContactId(); @@ -505,7 +508,7 @@ public class InviteeProtocolEngineTest extends AbstractProtocolEngineTest { JoinMessage invalidJoinMessage = new JoinMessage(new MessageId(getRandomId()), contactGroupId, privateGroupId, session.getInviteTimestamp() + 1, - lastLocalMessageId); + lastLocalMessageId, NO_AUTO_DELETE_TIMER); assertFalse(invalidJoinMessage.getTimestamp() <= session.getInviteTimestamp()); assertNotNull(session.getLastRemoteMessageId()); @@ -525,7 +528,7 @@ public class InviteeProtocolEngineTest extends AbstractProtocolEngineTest { JoinMessage properJoinMessage = new JoinMessage(new MessageId(getRandomId()), contactGroupId, privateGroupId, session.getInviteTimestamp() + 1, - lastRemoteMessageId); + lastRemoteMessageId, NO_AUTO_DELETE_TIMER); assertFalse(properJoinMessage.getTimestamp() <= session.getInviteTimestamp()); assertNotNull(session.getLastRemoteMessageId()); @@ -607,7 +610,8 @@ public class InviteeProtocolEngineTest extends AbstractProtocolEngineTest { InviteeSession session = getDefaultSession(INVITED); LeaveMessage invalidLeaveMessage = new LeaveMessage(new MessageId(getRandomId()), contactGroupId, - privateGroupId, session.getInviteTimestamp() + 1, null); + privateGroupId, session.getInviteTimestamp() + 1, null, + NO_AUTO_DELETE_TIMER); assertFalse(invalidLeaveMessage.getTimestamp() <= session.getInviteTimestamp()); assertNull(invalidLeaveMessage.getPreviousMessageId()); @@ -624,7 +628,8 @@ public class InviteeProtocolEngineTest extends AbstractProtocolEngineTest { InviteeSession session = getDefaultSession(LEFT); LeaveMessage invalidLeaveMessage = new LeaveMessage(new MessageId(getRandomId()), contactGroupId, - privateGroupId, session.getInviteTimestamp() + 1, null); + privateGroupId, session.getInviteTimestamp() + 1, null, + NO_AUTO_DELETE_TIMER); assertFalse(invalidLeaveMessage.getTimestamp() <= session.getInviteTimestamp()); assertNull(invalidLeaveMessage.getPreviousMessageId()); @@ -641,7 +646,7 @@ public class InviteeProtocolEngineTest extends AbstractProtocolEngineTest { LeaveMessage properLeaveMessage = new LeaveMessage(new MessageId(getRandomId()), contactGroupId, privateGroupId, session.getInviteTimestamp() + 1, - lastRemoteMessageId); + lastRemoteMessageId, NO_AUTO_DELETE_TIMER); assertFalse(properLeaveMessage.getTimestamp() <= session.getInviteTimestamp()); assertNotNull(session.getLastRemoteMessageId()); @@ -671,7 +676,7 @@ public class InviteeProtocolEngineTest extends AbstractProtocolEngineTest { LeaveMessage properLeaveMessage = new LeaveMessage(new MessageId(getRandomId()), contactGroupId, privateGroupId, session.getInviteTimestamp() + 1, - lastRemoteMessageId); + lastRemoteMessageId, NO_AUTO_DELETE_TIMER); assertFalse(properLeaveMessage.getTimestamp() <= session.getInviteTimestamp()); assertNotNull(session.getLastRemoteMessageId()); 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 05c0920c5..2be8c0a94 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 @@ -5,6 +5,7 @@ import org.briarproject.briar.api.client.ProtocolStateException; import org.jmock.Expectations; import org.junit.Test; +import static org.briarproject.bramble.api.autodelete.AutoDeleteConstants.NO_AUTO_DELETE_TIMER; import static org.briarproject.bramble.api.sync.Group.Visibility.INVISIBLE; import static org.briarproject.bramble.api.sync.Group.Visibility.SHARED; import static org.briarproject.bramble.api.sync.Group.Visibility.VISIBLE; @@ -17,9 +18,8 @@ import static org.briarproject.briar.privategroup.invitation.PeerState.LOCAL_LEF import static org.briarproject.briar.privategroup.invitation.PeerState.NEITHER_JOINED; import static org.briarproject.briar.privategroup.invitation.PeerState.START; import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotEquals; import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertTrue; public class PeerProtocolEngineTest extends AbstractProtocolEngineTest { @@ -37,43 +37,43 @@ public class PeerProtocolEngineTest extends AbstractProtocolEngineTest { // onInviteAction @Test(expected = UnsupportedOperationException.class) - public void testOnInviteActionFromStart() throws Exception { + public void testOnInviteActionFromStart() { engine.onInviteAction(txn, getDefaultSession(START), null, messageTimestamp, signature); } @Test(expected = UnsupportedOperationException.class) - public void testOnInviteActionFromAwaitMember() throws Exception { + public void testOnInviteActionFromAwaitMember() { engine.onInviteAction(txn, getDefaultSession(AWAIT_MEMBER), null, messageTimestamp, signature); } @Test(expected = UnsupportedOperationException.class) - public void testOnInviteActionFromNeitherJoined() throws Exception { + public void testOnInviteActionFromNeitherJoined() { engine.onInviteAction(txn, getDefaultSession(NEITHER_JOINED), null, messageTimestamp, signature); } @Test(expected = UnsupportedOperationException.class) - public void testOnInviteActionFromLocalJoined() throws Exception { + public void testOnInviteActionFromLocalJoined() { engine.onInviteAction(txn, getDefaultSession(LOCAL_JOINED), null, messageTimestamp, signature); } @Test(expected = UnsupportedOperationException.class) - public void testOnInviteActionFromBothJoined() throws Exception { + public void testOnInviteActionFromBothJoined() { engine.onInviteAction(txn, getDefaultSession(BOTH_JOINED), null, messageTimestamp, signature); } @Test(expected = UnsupportedOperationException.class) - public void testOnInviteActionFromLocalLeft() throws Exception { + public void testOnInviteActionFromLocalLeft() { engine.onInviteAction(txn, getDefaultSession(LOCAL_LEFT), null, messageTimestamp, signature); } @Test(expected = UnsupportedOperationException.class) - public void testOnInviteActionFromError() throws Exception { + public void testOnInviteActionFromError() { engine.onInviteAction(txn, getDefaultSession(ERROR), null, messageTimestamp, signature); } @@ -109,7 +109,8 @@ public class PeerProtocolEngineTest extends AbstractProtocolEngineTest { public void testOnJoinActionFromNeitherJoined() throws Exception { JoinMessage joinMessage = new JoinMessage(messageId, contactGroupId, - privateGroupId, messageTimestamp, lastRemoteMessageId); + privateGroupId, messageTimestamp, lastRemoteMessageId, + NO_AUTO_DELETE_TIMER); PeerSession session = getDefaultSession(NEITHER_JOINED); expectSendJoinMessage(joinMessage, false); @@ -125,7 +126,8 @@ public class PeerProtocolEngineTest extends AbstractProtocolEngineTest { public void testOnJoinActionFromLocalLeft() throws Exception { JoinMessage joinMessage = new JoinMessage(messageId, contactGroupId, - privateGroupId, messageTimestamp, lastRemoteMessageId); + privateGroupId, messageTimestamp, lastRemoteMessageId, + NO_AUTO_DELETE_TIMER); PeerSession session = getDefaultSession(LOCAL_LEFT); expectSendJoinMessage(joinMessage, false); @@ -216,7 +218,8 @@ public class PeerProtocolEngineTest extends AbstractProtocolEngineTest { public void testOnMemberAddedFromAwaitMember() throws Exception { JoinMessage joinMessage = new JoinMessage(messageId, contactGroupId, - privateGroupId, messageTimestamp, lastRemoteMessageId); + privateGroupId, messageTimestamp, lastRemoteMessageId, + NO_AUTO_DELETE_TIMER); PeerSession session = getDefaultSession(AWAIT_MEMBER); expectSendJoinMessage(joinMessage, false); @@ -361,12 +364,13 @@ public class PeerProtocolEngineTest extends AbstractProtocolEngineTest { throws Exception { JoinMessage invalidJoinMessage = new JoinMessage(new MessageId(getRandomId()), contactGroupId, - privateGroupId, 0L, lastLocalMessageId); + privateGroupId, 0L, lastLocalMessageId, + NO_AUTO_DELETE_TIMER); PeerSession session = getDefaultSession(START); assertNotNull(invalidJoinMessage.getPreviousMessageId()); assertNotNull(session.getLastRemoteMessageId()); - assertFalse(invalidJoinMessage.getPreviousMessageId() - .equals(session.getLastRemoteMessageId())); + assertNotEquals(invalidJoinMessage.getPreviousMessageId(), + session.getLastRemoteMessageId()); expectAbortWhenNotSubscribedToGroup(); PeerSession newSession = @@ -379,8 +383,8 @@ public class PeerProtocolEngineTest extends AbstractProtocolEngineTest { PeerSession session = getDefaultSession(START); assertNotNull(joinMessage.getPreviousMessageId()); assertNotNull(session.getLastRemoteMessageId()); - assertTrue(joinMessage.getPreviousMessageId() - .equals(session.getLastRemoteMessageId())); + assertEquals(joinMessage.getPreviousMessageId(), + session.getLastRemoteMessageId()); PeerSession newSession = engine.onJoinMessage(txn, session, joinMessage); @@ -399,12 +403,13 @@ public class PeerProtocolEngineTest extends AbstractProtocolEngineTest { throws Exception { JoinMessage invalidJoinMessage = new JoinMessage(new MessageId(getRandomId()), contactGroupId, - privateGroupId, 0L, lastLocalMessageId); + privateGroupId, 0L, lastLocalMessageId, + NO_AUTO_DELETE_TIMER); PeerSession session = getDefaultSession(NEITHER_JOINED); assertNotNull(invalidJoinMessage.getPreviousMessageId()); assertNotNull(session.getLastRemoteMessageId()); - assertFalse(invalidJoinMessage.getPreviousMessageId() - .equals(session.getLastRemoteMessageId())); + assertNotEquals(invalidJoinMessage.getPreviousMessageId(), + session.getLastRemoteMessageId()); expectAbortWhenNotSubscribedToGroup(); PeerSession newSession = @@ -417,10 +422,11 @@ public class PeerProtocolEngineTest extends AbstractProtocolEngineTest { PeerSession session = getDefaultSession(NEITHER_JOINED); assertNotNull(joinMessage.getPreviousMessageId()); assertNotNull(session.getLastRemoteMessageId()); - assertTrue(joinMessage.getPreviousMessageId() - .equals(session.getLastRemoteMessageId())); + assertEquals(joinMessage.getPreviousMessageId(), + session.getLastRemoteMessageId()); JoinMessage myJoinMessage = new JoinMessage(messageId, contactGroupId, - privateGroupId, messageTimestamp, lastRemoteMessageId); + privateGroupId, messageTimestamp, lastRemoteMessageId, + NO_AUTO_DELETE_TIMER); expectSendJoinMessage(myJoinMessage, false); expectSetPrivateGroupVisibility(SHARED); @@ -441,12 +447,13 @@ public class PeerProtocolEngineTest extends AbstractProtocolEngineTest { throws Exception { JoinMessage invalidJoinMessage = new JoinMessage(new MessageId(getRandomId()), contactGroupId, - privateGroupId, 0L, lastLocalMessageId); + privateGroupId, 0L, lastLocalMessageId, + NO_AUTO_DELETE_TIMER); PeerSession session = getDefaultSession(LOCAL_JOINED); assertNotNull(invalidJoinMessage.getPreviousMessageId()); assertNotNull(session.getLastRemoteMessageId()); - assertFalse(invalidJoinMessage.getPreviousMessageId() - .equals(session.getLastRemoteMessageId())); + assertNotEquals(invalidJoinMessage.getPreviousMessageId(), + session.getLastRemoteMessageId()); expectAbortWhenNotSubscribedToGroup(); PeerSession newSession = @@ -459,8 +466,8 @@ public class PeerProtocolEngineTest extends AbstractProtocolEngineTest { PeerSession session = getDefaultSession(LOCAL_JOINED); assertNotNull(joinMessage.getPreviousMessageId()); assertNotNull(session.getLastRemoteMessageId()); - assertTrue(joinMessage.getPreviousMessageId() - .equals(session.getLastRemoteMessageId())); + assertEquals(joinMessage.getPreviousMessageId(), + session.getLastRemoteMessageId()); expectSetPrivateGroupVisibility(SHARED); expectRelationshipRevealed(false); @@ -520,12 +527,13 @@ public class PeerProtocolEngineTest extends AbstractProtocolEngineTest { throws Exception { LeaveMessage invalidLeaveMessage = new LeaveMessage(new MessageId(getRandomId()), contactGroupId, - privateGroupId, 0L, lastLocalMessageId); + privateGroupId, 0L, lastLocalMessageId, + NO_AUTO_DELETE_TIMER); PeerSession session = getDefaultSession(AWAIT_MEMBER); assertNotNull(invalidLeaveMessage.getPreviousMessageId()); assertNotNull(session.getLastRemoteMessageId()); - assertFalse(invalidLeaveMessage.getPreviousMessageId() - .equals(session.getLastRemoteMessageId())); + assertNotEquals(invalidLeaveMessage.getPreviousMessageId(), + session.getLastRemoteMessageId()); expectAbortWhenSubscribedToGroup(); PeerSession newSession = @@ -538,8 +546,8 @@ public class PeerProtocolEngineTest extends AbstractProtocolEngineTest { PeerSession session = getDefaultSession(AWAIT_MEMBER); assertNotNull(leaveMessage.getPreviousMessageId()); assertNotNull(session.getLastRemoteMessageId()); - assertTrue(leaveMessage.getPreviousMessageId() - .equals(session.getLastRemoteMessageId())); + assertEquals(leaveMessage.getPreviousMessageId(), + session.getLastRemoteMessageId()); PeerSession newSession = engine.onLeaveMessage(txn, session, leaveMessage); @@ -558,12 +566,13 @@ public class PeerProtocolEngineTest extends AbstractProtocolEngineTest { throws Exception { LeaveMessage invalidLeaveMessage = new LeaveMessage(new MessageId(getRandomId()), contactGroupId, - privateGroupId, 0L, lastLocalMessageId); + privateGroupId, 0L, lastLocalMessageId, + NO_AUTO_DELETE_TIMER); PeerSession session = getDefaultSession(LOCAL_LEFT); assertNotNull(invalidLeaveMessage.getPreviousMessageId()); assertNotNull(session.getLastRemoteMessageId()); - assertFalse(invalidLeaveMessage.getPreviousMessageId() - .equals(session.getLastRemoteMessageId())); + assertNotEquals(invalidLeaveMessage.getPreviousMessageId(), + session.getLastRemoteMessageId()); expectAbortWhenSubscribedToGroup(); PeerSession newSession = @@ -576,8 +585,8 @@ public class PeerProtocolEngineTest extends AbstractProtocolEngineTest { PeerSession session = getDefaultSession(LOCAL_LEFT); assertNotNull(leaveMessage.getPreviousMessageId()); assertNotNull(session.getLastRemoteMessageId()); - assertTrue(leaveMessage.getPreviousMessageId() - .equals(session.getLastRemoteMessageId())); + assertEquals(leaveMessage.getPreviousMessageId(), + session.getLastRemoteMessageId()); PeerSession newSession = engine.onLeaveMessage(txn, session, leaveMessage); @@ -596,12 +605,13 @@ public class PeerProtocolEngineTest extends AbstractProtocolEngineTest { throws Exception { LeaveMessage invalidLeaveMessage = new LeaveMessage(new MessageId(getRandomId()), contactGroupId, - privateGroupId, 0L, lastLocalMessageId); + privateGroupId, 0L, lastLocalMessageId, + NO_AUTO_DELETE_TIMER); PeerSession session = getDefaultSession(BOTH_JOINED); assertNotNull(invalidLeaveMessage.getPreviousMessageId()); assertNotNull(session.getLastRemoteMessageId()); - assertFalse(invalidLeaveMessage.getPreviousMessageId() - .equals(session.getLastRemoteMessageId())); + assertNotEquals(invalidLeaveMessage.getPreviousMessageId(), + session.getLastRemoteMessageId()); expectAbortWhenSubscribedToGroup(); PeerSession newSession = @@ -614,8 +624,8 @@ public class PeerProtocolEngineTest extends AbstractProtocolEngineTest { PeerSession session = getDefaultSession(BOTH_JOINED); assertNotNull(leaveMessage.getPreviousMessageId()); assertNotNull(session.getLastRemoteMessageId()); - assertTrue(leaveMessage.getPreviousMessageId() - .equals(session.getLastRemoteMessageId())); + assertEquals(leaveMessage.getPreviousMessageId(), + session.getLastRemoteMessageId()); expectSetPrivateGroupVisibility(VISIBLE); // FIXME correct? PeerSession newSession = @@ -685,14 +695,14 @@ public class PeerProtocolEngineTest extends AbstractProtocolEngineTest { } private void assertSessionAborted(PeerSession oldSession, - PeerSession newSession) throws Exception { + PeerSession newSession) { assertEquals(ERROR, newSession.getState()); assertSessionRecordedSentMessage(newSession); assertSessionConstantsUnchanged(oldSession, newSession); } @Override - protected void assertSessionRecordedSentMessage(Session s) { + protected void assertSessionRecordedSentMessage(Session s) { assertEquals(messageId, s.getLastLocalMessageId()); assertEquals(lastRemoteMessageId, s.getLastRemoteMessageId()); assertEquals(messageTimestamp, s.getLocalTimestamp()); From 9b0b80ef049848859b261cab4fc4f752c74cf8f9 Mon Sep 17 00:00:00 2001 From: akwizgran Date: Mon, 23 Nov 2020 16:12:48 +0000 Subject: [PATCH 010/124] Add unit tests for validating auto-delete timer. --- .../GroupInvitationValidatorTest.java | 210 +++++++++++++----- 1 file changed, 157 insertions(+), 53 deletions(-) diff --git a/briar-core/src/test/java/org/briarproject/briar/privategroup/invitation/GroupInvitationValidatorTest.java b/briar-core/src/test/java/org/briarproject/briar/privategroup/invitation/GroupInvitationValidatorTest.java index d8e7c0600..fe9ced797 100644 --- a/briar-core/src/test/java/org/briarproject/briar/privategroup/invitation/GroupInvitationValidatorTest.java +++ b/briar-core/src/test/java/org/briarproject/briar/privategroup/invitation/GroupInvitationValidatorTest.java @@ -16,6 +16,10 @@ import org.junit.Test; import java.security.GeneralSecurityException; +import static java.util.Collections.emptyList; +import static java.util.Collections.singletonList; +import static org.briarproject.bramble.api.autodelete.AutoDeleteConstants.MAX_AUTO_DELETE_TIMER_MS; +import static org.briarproject.bramble.api.autodelete.AutoDeleteConstants.MIN_AUTO_DELETE_TIMER_MS; import static org.briarproject.bramble.api.autodelete.AutoDeleteConstants.NO_AUTO_DELETE_TIMER; import static org.briarproject.bramble.api.identity.AuthorConstants.MAX_SIGNATURE_LENGTH; import static org.briarproject.bramble.test.TestUtils.getAuthor; @@ -26,12 +30,12 @@ import static org.briarproject.briar.api.privategroup.PrivateGroupConstants.GROU import static org.briarproject.briar.api.privategroup.PrivateGroupConstants.MAX_GROUP_INVITATION_TEXT_LENGTH; import static org.briarproject.briar.api.privategroup.PrivateGroupConstants.MAX_GROUP_NAME_LENGTH; import static org.briarproject.briar.api.privategroup.invitation.GroupInvitationFactory.SIGNING_LABEL_INVITE; +import static org.briarproject.briar.privategroup.invitation.GroupInvitationConstants.MSG_KEY_AUTO_DELETE_TIMER; import static org.briarproject.briar.privategroup.invitation.MessageType.ABORT; import static org.briarproject.briar.privategroup.invitation.MessageType.INVITE; import static org.briarproject.briar.privategroup.invitation.MessageType.JOIN; import static org.briarproject.briar.privategroup.invitation.MessageType.LEAVE; import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; public class GroupInvitationValidatorTest extends ValidatorTestCase { @@ -72,7 +76,7 @@ public class GroupInvitationValidatorTest extends ValidatorTestCase { @Test(expected = FormatException.class) public void testRejectsTooLongInviteMessage() throws Exception { BdfList body = BdfList.of(INVITE.getValue(), creatorList, groupName, - salt, text, signature, ""); + salt, text, signature, NO_AUTO_DELETE_TIMER, null); validator.validateMessage(message, group, body); } @@ -183,8 +187,7 @@ public class GroupInvitationValidatorTest extends ValidatorTestCase { public void testAcceptsInviteMessageWithNullText() throws Exception { BdfList body = BdfList.of(INVITE.getValue(), creatorList, groupName, salt, null, signature); - expectInviteMessage(false); - validator.validateMessage(message, group, body); + testAcceptsInviteMessage(body, NO_AUTO_DELETE_TIMER, meta); } @Test(expected = FormatException.class) @@ -234,15 +237,73 @@ public class GroupInvitationValidatorTest extends ValidatorTestCase { validator.validateMessage(message, group, body); } + @Test(expected = FormatException.class) + public void testRejectsInviteMessageWithTooBigAutoDeleteTimer() + throws Exception { + BdfList body = BdfList.of(INVITE.getValue(), creatorList, groupName, + salt, text, signature, MAX_AUTO_DELETE_TIMER_MS + 1); + validator.validateMessage(message, group, body); + } + + @Test(expected = FormatException.class) + public void testRejectsInviteMessageWithTooSmallAutoDeleteTimer() + throws Exception { + BdfList body = BdfList.of(INVITE.getValue(), creatorList, groupName, + salt, text, signature, MIN_AUTO_DELETE_TIMER_MS - 1); + validator.validateMessage(message, group, body); + } + + @Test(expected = FormatException.class) + public void testRejectsInviteMessageWithNonLongAutoDeleteTimer() + throws Exception { + BdfList body = BdfList.of(INVITE.getValue(), creatorList, groupName, + salt, text, signature, "foo"); + validator.validateMessage(message, group, body); + } + @Test public void testAcceptsValidInviteMessage() throws Exception { BdfList body = BdfList.of(INVITE.getValue(), creatorList, groupName, salt, text, signature); + testAcceptsInviteMessage(body, NO_AUTO_DELETE_TIMER, meta); + } + + @Test + public void testAcceptsInviteMessageWithNullAutoDeleteTimer() + throws Exception { + BdfList body = BdfList.of(INVITE.getValue(), creatorList, groupName, + salt, text, signature, null); + testAcceptsInviteMessage(body, NO_AUTO_DELETE_TIMER, meta); + } + + @Test + public void testAcceptsInviteMessageWithMinAutoDeleteTimer() + throws Exception { + BdfList body = BdfList.of(INVITE.getValue(), creatorList, groupName, + salt, text, signature, MIN_AUTO_DELETE_TIMER_MS); + BdfDictionary metadata = new BdfDictionary(meta); + metadata.put(MSG_KEY_AUTO_DELETE_TIMER, MIN_AUTO_DELETE_TIMER_MS); + testAcceptsInviteMessage(body, MIN_AUTO_DELETE_TIMER_MS, metadata); + } + + @Test + public void testAcceptsInviteMessageWithMaxAutoDeleteTimer() + throws Exception { + BdfList body = BdfList.of(INVITE.getValue(), creatorList, groupName, + salt, text, signature, MAX_AUTO_DELETE_TIMER_MS); + BdfDictionary metadata = new BdfDictionary(meta); + metadata.put(MSG_KEY_AUTO_DELETE_TIMER, MAX_AUTO_DELETE_TIMER_MS); + testAcceptsInviteMessage(body, MAX_AUTO_DELETE_TIMER_MS, metadata); + } + + private void testAcceptsInviteMessage(BdfList body, long autoDeleteTimer, + BdfDictionary metadata) throws Exception { expectInviteMessage(false); + expectEncodeMetadata(INVITE, autoDeleteTimer, metadata); BdfMessageContext messageContext = validator.validateMessage(message, group, body); - assertTrue(messageContext.getDependencies().isEmpty()); - assertEquals(meta, messageContext.getDictionary()); + assertEquals(emptyList(), messageContext.getDependencies()); + assertEquals(metadata, messageContext.getDictionary()); } private void expectInviteMessage(boolean exception) throws Exception { @@ -261,11 +322,6 @@ public class GroupInvitationValidatorTest extends ValidatorTestCase { signed, creator.getPublicKey()); if (exception) { will(throwException(new GeneralSecurityException())); - } else { - oneOf(messageEncoder).encodeMetadata(INVITE, - message.getGroupId(), message.getTimestamp(), false, - false, false, false, false, NO_AUTO_DELETE_TIMER); - will(returnValue(meta)); } }}); } @@ -281,7 +337,7 @@ public class GroupInvitationValidatorTest extends ValidatorTestCase { @Test(expected = FormatException.class) public void testRejectsTooLongJoinMessage() throws Exception { BdfList body = BdfList.of(JOIN.getValue(), privateGroup.getId(), - previousMessageId, ""); + previousMessageId, NO_AUTO_DELETE_TIMER, null); validator.validateMessage(message, group, body); } @@ -340,15 +396,10 @@ public class GroupInvitationValidatorTest extends ValidatorTestCase { public void testAcceptsJoinMessageWithNullPreviousMessageId() throws Exception { BdfList body = BdfList.of(JOIN.getValue(), privateGroup.getId(), null); - context.checking(new Expectations() {{ - oneOf(messageEncoder).encodeMetadata(JOIN, message.getGroupId(), - message.getTimestamp(), false, false, false, false, false, - NO_AUTO_DELETE_TIMER); - will(returnValue(meta)); - }}); + expectEncodeMetadata(JOIN, NO_AUTO_DELETE_TIMER, meta); BdfMessageContext messageContext = validator.validateMessage(message, group, body); - assertEquals(0, messageContext.getDependencies().size()); + assertEquals(emptyList(), messageContext.getDependencies()); assertEquals(meta, messageContext.getDictionary()); } @@ -356,18 +407,45 @@ public class GroupInvitationValidatorTest extends ValidatorTestCase { public void testAcceptsValidJoinMessage() throws Exception { BdfList body = BdfList.of(JOIN.getValue(), privateGroup.getId(), previousMessageId); - context.checking(new Expectations() {{ - oneOf(messageEncoder).encodeMetadata(JOIN, message.getGroupId(), - message.getTimestamp(), false, false, false, false, false, - NO_AUTO_DELETE_TIMER); - will(returnValue(meta)); - }}); + testAcceptsJoinMessage(body, NO_AUTO_DELETE_TIMER, meta); + } + + @Test + public void testAcceptsJoinMessageWithNullAutoDeleteTimer() + throws Exception { + BdfList body = BdfList.of(JOIN.getValue(), privateGroup.getId(), + previousMessageId, null); + testAcceptsJoinMessage(body, NO_AUTO_DELETE_TIMER, meta); + } + + @Test + public void testAcceptsJoinMessageWitMinAutoDeleteTimer() + throws Exception { + BdfList body = BdfList.of(JOIN.getValue(), privateGroup.getId(), + previousMessageId, MIN_AUTO_DELETE_TIMER_MS); + BdfDictionary metadata = new BdfDictionary(meta); + metadata.put(MSG_KEY_AUTO_DELETE_TIMER, MIN_AUTO_DELETE_TIMER_MS); + testAcceptsJoinMessage(body, MIN_AUTO_DELETE_TIMER_MS, metadata); + } + + @Test + public void testAcceptsJoinMessageWitMaxAutoDeleteTimer() + throws Exception { + BdfList body = BdfList.of(JOIN.getValue(), privateGroup.getId(), + previousMessageId, MAX_AUTO_DELETE_TIMER_MS); + BdfDictionary metadata = new BdfDictionary(meta); + metadata.put(MSG_KEY_AUTO_DELETE_TIMER, MAX_AUTO_DELETE_TIMER_MS); + testAcceptsJoinMessage(body, MAX_AUTO_DELETE_TIMER_MS, metadata); + } + + private void testAcceptsJoinMessage(BdfList body, long autoDeleteTimer, + BdfDictionary metadata) throws Exception { + expectEncodeMetadata(JOIN, autoDeleteTimer, metadata); BdfMessageContext messageContext = validator.validateMessage(message, group, body); - assertEquals(1, messageContext.getDependencies().size()); - assertEquals(previousMessageId, - messageContext.getDependencies().iterator().next()); - assertEquals(meta, messageContext.getDictionary()); + assertEquals(singletonList(previousMessageId), + messageContext.getDependencies()); + assertEquals(metadata, messageContext.getDictionary()); } // LEAVE message @@ -440,34 +518,56 @@ public class GroupInvitationValidatorTest extends ValidatorTestCase { public void testAcceptsLeaveMessageWithNullPreviousMessageId() throws Exception { BdfList body = BdfList.of(LEAVE.getValue(), privateGroup.getId(), null); - context.checking(new Expectations() {{ - oneOf(messageEncoder).encodeMetadata(LEAVE, message.getGroupId(), - message.getTimestamp(), false, false, false, false, false, - NO_AUTO_DELETE_TIMER); - will(returnValue(meta)); - }}); + expectEncodeMetadata(LEAVE, NO_AUTO_DELETE_TIMER, meta); BdfMessageContext messageContext = validator.validateMessage(message, group, body); - assertEquals(0, messageContext.getDependencies().size()); + assertEquals(emptyList(), messageContext.getDependencies()); assertEquals(meta, messageContext.getDictionary()); } @Test public void testAcceptsValidLeaveMessage() throws Exception { - context.checking(new Expectations() {{ - oneOf(messageEncoder).encodeMetadata(LEAVE, message.getGroupId(), - message.getTimestamp(), false, false, false, false, false, - NO_AUTO_DELETE_TIMER); - will(returnValue(meta)); - }}); BdfList body = BdfList.of(LEAVE.getValue(), privateGroup.getId(), previousMessageId); + testAcceptsLeaveMessage(body, NO_AUTO_DELETE_TIMER, meta); + } + + @Test + public void testAcceptsLeaveMessageWithNullAutoDeleteTimer() + throws Exception { + BdfList body = BdfList.of(LEAVE.getValue(), privateGroup.getId(), + previousMessageId, null); + testAcceptsLeaveMessage(body, NO_AUTO_DELETE_TIMER, meta); + } + + @Test + public void testAcceptsLeaveMessageWithMinAutoDeleteTimer() + throws Exception { + BdfList body = BdfList.of(LEAVE.getValue(), privateGroup.getId(), + previousMessageId, MIN_AUTO_DELETE_TIMER_MS); + BdfDictionary metadata = new BdfDictionary(meta); + metadata.put(MSG_KEY_AUTO_DELETE_TIMER, MIN_AUTO_DELETE_TIMER_MS); + testAcceptsLeaveMessage(body, MIN_AUTO_DELETE_TIMER_MS, metadata); + } + + @Test + public void testAcceptsLeaveMessageWithMaxAutoDeleteTimer() + throws Exception { + BdfList body = BdfList.of(LEAVE.getValue(), privateGroup.getId(), + previousMessageId, MAX_AUTO_DELETE_TIMER_MS); + BdfDictionary metadata = new BdfDictionary(meta); + metadata.put(MSG_KEY_AUTO_DELETE_TIMER, MAX_AUTO_DELETE_TIMER_MS); + testAcceptsLeaveMessage(body, MAX_AUTO_DELETE_TIMER_MS, metadata); + } + + private void testAcceptsLeaveMessage(BdfList body, long autoDeleteTimer, + BdfDictionary metadata) throws Exception { + expectEncodeMetadata(LEAVE, autoDeleteTimer, metadata); BdfMessageContext messageContext = validator.validateMessage(message, group, body); - assertEquals(1, messageContext.getDependencies().size()); - assertEquals(previousMessageId, - messageContext.getDependencies().iterator().next()); - assertEquals(meta, messageContext.getDictionary()); + assertEquals(singletonList(previousMessageId), + messageContext.getDependencies()); + assertEquals(metadata, messageContext.getDictionary()); } // ABORT message @@ -512,16 +612,11 @@ public class GroupInvitationValidatorTest extends ValidatorTestCase { @Test public void testAcceptsValidAbortMessage() throws Exception { - context.checking(new Expectations() {{ - oneOf(messageEncoder).encodeMetadata(ABORT, message.getGroupId(), - message.getTimestamp(), false, false, false, false, false, - NO_AUTO_DELETE_TIMER); - will(returnValue(meta)); - }}); BdfList body = BdfList.of(ABORT.getValue(), privateGroup.getId()); + expectEncodeMetadata(ABORT, NO_AUTO_DELETE_TIMER, meta); BdfMessageContext messageContext = validator.validateMessage(message, group, body); - assertEquals(0, messageContext.getDependencies().size()); + assertEquals(emptyList(), messageContext.getDependencies()); assertEquals(meta, messageContext.getDictionary()); } @@ -537,4 +632,13 @@ public class GroupInvitationValidatorTest extends ValidatorTestCase { validator.validateMessage(message, group, body); } + private void expectEncodeMetadata(MessageType type, + long autoDeleteTimer, BdfDictionary metadata) { + context.checking(new Expectations() {{ + oneOf(messageEncoder).encodeMetadata(type, message.getGroupId(), + message.getTimestamp(), false, false, false, false, false, + autoDeleteTimer); + will(returnValue(metadata)); + }}); + } } From 27893f9cdd48615c3c1bd8b4dfe84a54524e95e7 Mon Sep 17 00:00:00 2001 From: akwizgran Date: Mon, 23 Nov 2020 16:29:06 +0000 Subject: [PATCH 011/124] Update comments. --- .../privategroup/invitation/AbstractProtocolEngine.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) 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 44165dcf4..26da12b2e 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 @@ -142,7 +142,8 @@ abstract class AbstractProtocolEngine> throws DbException { Message m; if (contactSupportsAutoDeletion(txn, s.getContactGroupId())) { - // TODO: Look up the current auto-delete timer + // TODO: Look up the current auto-delete timer if the message is + // visible in the UI (accepting an invitation) long timer = NO_AUTO_DELETE_TIMER; m = messageEncoder.encodeJoinMessage(s.getContactGroupId(), s.getPrivateGroupId(), getLocalTimestamp(s), @@ -163,7 +164,8 @@ abstract class AbstractProtocolEngine> throws DbException { Message m; if (contactSupportsAutoDeletion(txn, s.getContactGroupId())) { - // TODO: Look up the current auto-delete timer + // TODO: Look up the current auto-delete timer if the message is + // visible in the UI (declining an invitation) long timer = NO_AUTO_DELETE_TIMER; m = messageEncoder.encodeLeaveMessage(s.getContactGroupId(), s.getPrivateGroupId(), getLocalTimestamp(s), From 61718192ee3b9d357f7ae86db5ca085776efd2df Mon Sep 17 00:00:00 2001 From: akwizgran Date: Mon, 23 Nov 2020 16:42:45 +0000 Subject: [PATCH 012/124] Factor out method for validating auto-delete timers. --- .../bramble/util/ValidationUtils.java | 11 +++++++ .../introduction/IntroductionValidator.java | 23 ++++++-------- .../messaging/PrivateMessageValidator.java | 15 +++++---- .../invitation/GroupInvitationValidator.java | 23 ++++++-------- .../briar/sharing/SharingValidator.java | 31 ++++++++----------- 5 files changed, 51 insertions(+), 52 deletions(-) diff --git a/bramble-api/src/main/java/org/briarproject/bramble/util/ValidationUtils.java b/bramble-api/src/main/java/org/briarproject/bramble/util/ValidationUtils.java index 1bb56a799..bc44a04d5 100644 --- a/bramble-api/src/main/java/org/briarproject/bramble/util/ValidationUtils.java +++ b/bramble-api/src/main/java/org/briarproject/bramble/util/ValidationUtils.java @@ -7,6 +7,10 @@ import org.briarproject.bramble.api.nullsafety.NotNullByDefault; import javax.annotation.Nullable; +import static org.briarproject.bramble.api.autodelete.AutoDeleteConstants.MAX_AUTO_DELETE_TIMER_MS; +import static org.briarproject.bramble.api.autodelete.AutoDeleteConstants.MIN_AUTO_DELETE_TIMER_MS; +import static org.briarproject.bramble.api.autodelete.AutoDeleteConstants.NO_AUTO_DELETE_TIMER; + @NotNullByDefault public class ValidationUtils { @@ -69,4 +73,11 @@ public class ValidationUtils { throws FormatException { if (l != null && (l < min || l > max)) throw new FormatException(); } + + public static long validateAutoDeleteTimer(@Nullable Long timer) + throws FormatException { + if (timer == null) return NO_AUTO_DELETE_TIMER; + checkRange(timer, MIN_AUTO_DELETE_TIMER_MS, MAX_AUTO_DELETE_TIMER_MS); + return timer; + } } diff --git a/briar-core/src/main/java/org/briarproject/briar/introduction/IntroductionValidator.java b/briar-core/src/main/java/org/briarproject/briar/introduction/IntroductionValidator.java index 0112b4a23..a4c460bb5 100644 --- a/briar-core/src/main/java/org/briarproject/briar/introduction/IntroductionValidator.java +++ b/briar-core/src/main/java/org/briarproject/briar/introduction/IntroductionValidator.java @@ -15,19 +15,16 @@ import org.briarproject.bramble.api.sync.MessageId; import org.briarproject.bramble.api.system.Clock; import org.briarproject.briar.api.client.SessionId; -import javax.annotation.Nullable; import javax.annotation.concurrent.Immutable; import static java.util.Collections.singletonList; -import static org.briarproject.bramble.api.autodelete.AutoDeleteConstants.MAX_AUTO_DELETE_TIMER_MS; -import static org.briarproject.bramble.api.autodelete.AutoDeleteConstants.MIN_AUTO_DELETE_TIMER_MS; import static org.briarproject.bramble.api.autodelete.AutoDeleteConstants.NO_AUTO_DELETE_TIMER; import static org.briarproject.bramble.api.crypto.CryptoConstants.MAC_BYTES; import static org.briarproject.bramble.api.crypto.CryptoConstants.MAX_SIGNATURE_BYTES; import static org.briarproject.bramble.api.identity.AuthorConstants.MAX_PUBLIC_KEY_LENGTH; import static org.briarproject.bramble.util.ValidationUtils.checkLength; -import static org.briarproject.bramble.util.ValidationUtils.checkRange; import static org.briarproject.bramble.util.ValidationUtils.checkSize; +import static org.briarproject.bramble.util.ValidationUtils.validateAutoDeleteTimer; import static org.briarproject.briar.api.introduction.IntroductionConstants.MAX_INTRODUCTION_TEXT_LENGTH; import static org.briarproject.briar.introduction.MessageType.ACCEPT; import static org.briarproject.briar.introduction.MessageType.ACTIVATE; @@ -88,7 +85,9 @@ class IntroductionValidator extends BdfMessageValidator { checkLength(text, 1, MAX_INTRODUCTION_TEXT_LENGTH); long timer = NO_AUTO_DELETE_TIMER; - if (body.size() == 5) timer = validateTimer(body.getOptionalLong(4)); + if (body.size() == 5) { + timer = validateAutoDeleteTimer(body.getOptionalLong(4)); + } BdfDictionary meta = messageEncoder.encodeRequestMetadata(m.getTimestamp(), timer); @@ -128,7 +127,9 @@ class IntroductionValidator extends BdfMessageValidator { .parseAndValidateTransportPropertiesMap(transportProperties); long timer = NO_AUTO_DELETE_TIMER; - if (body.size() == 7) timer = validateTimer(body.getOptionalLong(6)); + if (body.size() == 7) { + timer = validateAutoDeleteTimer(body.getOptionalLong(6)); + } SessionId sessionId = new SessionId(sessionIdBytes); BdfDictionary meta = messageEncoder.encodeMetadata(ACCEPT, sessionId, @@ -156,7 +157,9 @@ class IntroductionValidator extends BdfMessageValidator { checkLength(previousMessageId, UniqueId.LENGTH); long timer = NO_AUTO_DELETE_TIMER; - if (body.size() == 4) timer = validateTimer(body.getOptionalLong(3)); + if (body.size() == 4) { + timer = validateAutoDeleteTimer(body.getOptionalLong(3)); + } SessionId sessionId = new SessionId(sessionIdBytes); BdfDictionary meta = messageEncoder.encodeMetadata(type, sessionId, @@ -236,10 +239,4 @@ class IntroductionValidator extends BdfMessageValidator { return new BdfMessageContext(meta, singletonList(dependency)); } } - - private long validateTimer(@Nullable Long timer) throws FormatException { - if (timer == null) return NO_AUTO_DELETE_TIMER; - checkRange(timer, MIN_AUTO_DELETE_TIMER_MS, MAX_AUTO_DELETE_TIMER_MS); - return timer; - } } diff --git a/briar-core/src/main/java/org/briarproject/briar/messaging/PrivateMessageValidator.java b/briar-core/src/main/java/org/briarproject/briar/messaging/PrivateMessageValidator.java index 761e27842..14581eeb8 100644 --- a/briar-core/src/main/java/org/briarproject/briar/messaging/PrivateMessageValidator.java +++ b/briar-core/src/main/java/org/briarproject/briar/messaging/PrivateMessageValidator.java @@ -24,13 +24,12 @@ import java.io.InputStream; import javax.annotation.concurrent.Immutable; -import static org.briarproject.bramble.api.autodelete.AutoDeleteConstants.MAX_AUTO_DELETE_TIMER_MS; -import static org.briarproject.bramble.api.autodelete.AutoDeleteConstants.MIN_AUTO_DELETE_TIMER_MS; +import static org.briarproject.bramble.api.autodelete.AutoDeleteConstants.NO_AUTO_DELETE_TIMER; import static org.briarproject.bramble.api.sync.SyncConstants.MAX_MESSAGE_BODY_LENGTH; import static org.briarproject.bramble.api.transport.TransportConstants.MAX_CLOCK_DIFFERENCE; import static org.briarproject.bramble.util.ValidationUtils.checkLength; -import static org.briarproject.bramble.util.ValidationUtils.checkRange; import static org.briarproject.bramble.util.ValidationUtils.checkSize; +import static org.briarproject.bramble.util.ValidationUtils.validateAutoDeleteTimer; import static org.briarproject.briar.api.attachment.MediaConstants.MAX_CONTENT_TYPE_BYTES; import static org.briarproject.briar.api.attachment.MediaConstants.MSG_KEY_CONTENT_TYPE; import static org.briarproject.briar.api.attachment.MediaConstants.MSG_KEY_DESCRIPTOR_LENGTH; @@ -137,11 +136,9 @@ class PrivateMessageValidator implements MessageValidator { String contentType = header.getString(1); checkLength(contentType, 1, MAX_CONTENT_TYPE_BYTES); } - Long timer = null; + long timer = NO_AUTO_DELETE_TIMER; if (body.size() == 4) { - timer = body.getOptionalLong(3); - checkRange(timer, MIN_AUTO_DELETE_TIMER_MS, - MAX_AUTO_DELETE_TIMER_MS); + timer = validateAutoDeleteTimer(body.getOptionalLong(3)); } // Return the metadata BdfDictionary meta = new BdfDictionary(); @@ -151,7 +148,9 @@ class PrivateMessageValidator implements MessageValidator { meta.put(MSG_KEY_MSG_TYPE, PRIVATE_MESSAGE); meta.put(MSG_KEY_HAS_TEXT, text != null); meta.put(MSG_KEY_ATTACHMENT_HEADERS, headers); - if (timer != null) meta.put(MSG_KEY_AUTO_DELETE_TIMER, timer); + if (timer != NO_AUTO_DELETE_TIMER) { + meta.put(MSG_KEY_AUTO_DELETE_TIMER, timer); + } return new BdfMessageContext(meta); } diff --git a/briar-core/src/main/java/org/briarproject/briar/privategroup/invitation/GroupInvitationValidator.java b/briar-core/src/main/java/org/briarproject/briar/privategroup/invitation/GroupInvitationValidator.java index 0896ea6ac..7e3a6fb76 100644 --- a/briar-core/src/main/java/org/briarproject/briar/privategroup/invitation/GroupInvitationValidator.java +++ b/briar-core/src/main/java/org/briarproject/briar/privategroup/invitation/GroupInvitationValidator.java @@ -21,16 +21,13 @@ import org.briarproject.briar.api.privategroup.PrivateGroupFactory; import java.security.GeneralSecurityException; import java.util.Collections; -import javax.annotation.Nullable; import javax.annotation.concurrent.Immutable; -import static org.briarproject.bramble.api.autodelete.AutoDeleteConstants.MAX_AUTO_DELETE_TIMER_MS; -import static org.briarproject.bramble.api.autodelete.AutoDeleteConstants.MIN_AUTO_DELETE_TIMER_MS; import static org.briarproject.bramble.api.autodelete.AutoDeleteConstants.NO_AUTO_DELETE_TIMER; import static org.briarproject.bramble.api.identity.AuthorConstants.MAX_SIGNATURE_LENGTH; import static org.briarproject.bramble.util.ValidationUtils.checkLength; -import static org.briarproject.bramble.util.ValidationUtils.checkRange; import static org.briarproject.bramble.util.ValidationUtils.checkSize; +import static org.briarproject.bramble.util.ValidationUtils.validateAutoDeleteTimer; import static org.briarproject.briar.api.privategroup.PrivateGroupConstants.GROUP_SALT_LENGTH; import static org.briarproject.briar.api.privategroup.PrivateGroupConstants.MAX_GROUP_INVITATION_TEXT_LENGTH; import static org.briarproject.briar.api.privategroup.PrivateGroupConstants.MAX_GROUP_NAME_LENGTH; @@ -91,7 +88,9 @@ class GroupInvitationValidator extends BdfMessageValidator { byte[] signature = body.getRaw(5); checkLength(signature, 1, MAX_SIGNATURE_LENGTH); long timer = NO_AUTO_DELETE_TIMER; - if (body.size() == 7) timer = validateTimer(body.getOptionalLong(6)); + if (body.size() == 7) { + timer = validateAutoDeleteTimer(body.getOptionalLong(6)); + } // Validate the creator and create the private group Author creator = clientHelper.parseAndValidateAuthor(creatorList); @@ -128,7 +127,9 @@ class GroupInvitationValidator extends BdfMessageValidator { byte[] previousMessageId = body.getOptionalRaw(2); checkLength(previousMessageId, UniqueId.LENGTH); long timer = NO_AUTO_DELETE_TIMER; - if (body.size() == 4) timer = validateTimer(body.getOptionalLong(3)); + if (body.size() == 4) { + timer = validateAutoDeleteTimer(body.getOptionalLong(3)); + } BdfDictionary meta = messageEncoder.encodeMetadata(JOIN, new GroupId(privateGroupId), m.getTimestamp(), false, false, @@ -154,7 +155,9 @@ class GroupInvitationValidator extends BdfMessageValidator { byte[] previousMessageId = body.getOptionalRaw(2); checkLength(previousMessageId, UniqueId.LENGTH); long timer = NO_AUTO_DELETE_TIMER; - if (body.size() == 4) timer = validateTimer(body.getOptionalLong(3)); + if (body.size() == 4) { + timer = validateAutoDeleteTimer(body.getOptionalLong(3)); + } BdfDictionary meta = messageEncoder.encodeMetadata(LEAVE, new GroupId(privateGroupId), m.getTimestamp(), false, false, @@ -178,10 +181,4 @@ class GroupInvitationValidator extends BdfMessageValidator { false, false, false, NO_AUTO_DELETE_TIMER); return new BdfMessageContext(meta); } - - private long validateTimer(@Nullable Long timer) throws FormatException { - if (timer == null) return NO_AUTO_DELETE_TIMER; - checkRange(timer, MIN_AUTO_DELETE_TIMER_MS, MAX_AUTO_DELETE_TIMER_MS); - return timer; - } } diff --git a/briar-core/src/main/java/org/briarproject/briar/sharing/SharingValidator.java b/briar-core/src/main/java/org/briarproject/briar/sharing/SharingValidator.java index f8cd581ea..76dc51118 100644 --- a/briar-core/src/main/java/org/briarproject/briar/sharing/SharingValidator.java +++ b/briar-core/src/main/java/org/briarproject/briar/sharing/SharingValidator.java @@ -15,16 +15,13 @@ import org.briarproject.bramble.api.sync.Message; import org.briarproject.bramble.api.sync.MessageId; import org.briarproject.bramble.api.system.Clock; -import javax.annotation.Nullable; import javax.annotation.concurrent.Immutable; import static java.util.Collections.singletonList; -import static org.briarproject.bramble.api.autodelete.AutoDeleteConstants.MAX_AUTO_DELETE_TIMER_MS; -import static org.briarproject.bramble.api.autodelete.AutoDeleteConstants.MIN_AUTO_DELETE_TIMER_MS; import static org.briarproject.bramble.api.autodelete.AutoDeleteConstants.NO_AUTO_DELETE_TIMER; import static org.briarproject.bramble.util.ValidationUtils.checkLength; -import static org.briarproject.bramble.util.ValidationUtils.checkRange; import static org.briarproject.bramble.util.ValidationUtils.checkSize; +import static org.briarproject.bramble.util.ValidationUtils.validateAutoDeleteTimer; import static org.briarproject.briar.api.sharing.SharingConstants.MAX_INVITATION_TEXT_LENGTH; import static org.briarproject.briar.sharing.MessageType.INVITE; @@ -49,10 +46,10 @@ abstract class SharingValidator extends BdfMessageValidator { return validateInviteMessage(m, body); case ACCEPT: case DECLINE: - return validateNonInviteMessageWithOptionalTimer(type, m, body); + return validateAcceptOrDeclineMessage(type, m, body); case LEAVE: case ABORT: - return validateNonInviteMessageWithoutTimer(type, m, body); + return validateLeaveOrAbortMessage(type, m, body); default: throw new FormatException(); } @@ -72,7 +69,9 @@ abstract class SharingValidator extends BdfMessageValidator { String text = body.getOptionalString(3); checkLength(text, 1, MAX_INVITATION_TEXT_LENGTH); long timer = NO_AUTO_DELETE_TIMER; - if (body.size() == 5) timer = validateTimer(body.getOptionalLong(4)); + if (body.size() == 5) { + timer = validateAutoDeleteTimer(body.getOptionalLong(4)); + } BdfDictionary meta = messageEncoder.encodeMetadata(INVITE, shareableId, m.getTimestamp(), false, false, false, false, false, timer); @@ -87,8 +86,8 @@ abstract class SharingValidator extends BdfMessageValidator { protected abstract GroupId validateDescriptor(BdfList descriptor) throws FormatException; - private BdfMessageContext validateNonInviteMessageWithoutTimer( - MessageType type, Message m, BdfList body) throws FormatException { + private BdfMessageContext validateLeaveOrAbortMessage(MessageType type, + Message m, BdfList body) throws FormatException { checkSize(body, 3); byte[] shareableId = body.getRaw(1); checkLength(shareableId, UniqueId.LENGTH); @@ -106,8 +105,8 @@ abstract class SharingValidator extends BdfMessageValidator { } } - private BdfMessageContext validateNonInviteMessageWithOptionalTimer( - MessageType type, Message m, BdfList body) throws FormatException { + private BdfMessageContext validateAcceptOrDeclineMessage(MessageType type, + Message m, BdfList body) throws FormatException { // Client version 0.0: Message type, shareable ID, optional previous // message ID. // Client version 0.1: Message type, shareable ID, optional previous @@ -118,7 +117,9 @@ abstract class SharingValidator extends BdfMessageValidator { byte[] previousMessageId = body.getOptionalRaw(2); checkLength(previousMessageId, UniqueId.LENGTH); long timer = NO_AUTO_DELETE_TIMER; - if (body.size() == 4) timer = validateTimer(body.getOptionalLong(3)); + if (body.size() == 4) { + timer = validateAutoDeleteTimer(body.getOptionalLong(3)); + } BdfDictionary meta = messageEncoder.encodeMetadata(type, new GroupId(shareableId), m.getTimestamp(), false, false, @@ -130,10 +131,4 @@ abstract class SharingValidator extends BdfMessageValidator { return new BdfMessageContext(meta, singletonList(dependency)); } } - - private long validateTimer(@Nullable Long timer) throws FormatException { - if (timer == null) return NO_AUTO_DELETE_TIMER; - checkRange(timer, MIN_AUTO_DELETE_TIMER_MS, MAX_AUTO_DELETE_TIMER_MS); - return timer; - } } From f9f260bbc1960793722d538a0521e1f3b9a6f40c Mon Sep 17 00:00:00 2001 From: akwizgran Date: Mon, 23 Nov 2020 17:15:57 +0000 Subject: [PATCH 013/124] Factor out methods for storing and retrieving contact ID. --- .../bramble/api/client/ClientHelper.java | 14 ++++++++ .../api/client/ContactGroupConstants.java | 9 +++++ .../bramble/client/ClientHelperImpl.java | 26 +++++++++++++++ .../versioning/ClientVersioningConstants.java | 1 - .../ClientVersioningManagerImpl.java | 22 ++----------- .../ClientVersioningManagerImplTest.java | 33 +++++++------------ .../introduction/AbstractProtocolEngine.java | 6 +--- .../introduction/IntroductionConstants.java | 3 -- .../introduction/IntroductionManagerImpl.java | 26 ++++----------- .../briar/messaging/MessagingConstants.java | 3 -- .../briar/messaging/MessagingManagerImpl.java | 10 ++---- .../invitation/AbstractProtocolEngine.java | 16 ++------- .../invitation/CreatorProtocolEngine.java | 6 ++-- .../invitation/GroupInvitationConstants.java | 3 -- .../GroupInvitationManagerImpl.java | 12 ++----- .../invitation/InviteeProtocolEngine.java | 3 +- .../invitation/PeerProtocolEngine.java | 3 +- .../briar/sharing/ProtocolEngineImpl.java | 31 ++++++++--------- .../briar/sharing/SharingConstants.java | 3 -- .../briar/sharing/SharingManagerImpl.java | 9 +---- .../AbstractProtocolEngineTest.java | 15 +++------ .../GroupInvitationManagerImplTest.java | 6 +--- .../sharing/BlogSharingManagerImplTest.java | 6 +--- 23 files changed, 105 insertions(+), 161 deletions(-) create mode 100644 bramble-api/src/main/java/org/briarproject/bramble/api/client/ContactGroupConstants.java diff --git a/bramble-api/src/main/java/org/briarproject/bramble/api/client/ClientHelper.java b/bramble-api/src/main/java/org/briarproject/bramble/api/client/ClientHelper.java index df68d7933..c4fb1b41f 100644 --- a/bramble-api/src/main/java/org/briarproject/bramble/api/client/ClientHelper.java +++ b/bramble-api/src/main/java/org/briarproject/bramble/api/client/ClientHelper.java @@ -1,6 +1,7 @@ package org.briarproject.bramble.api.client; import org.briarproject.bramble.api.FormatException; +import org.briarproject.bramble.api.contact.ContactId; import org.briarproject.bramble.api.crypto.PrivateKey; import org.briarproject.bramble.api.crypto.PublicKey; import org.briarproject.bramble.api.data.BdfDictionary; @@ -119,4 +120,17 @@ public interface ClientHelper { Map parseAndValidateTransportPropertiesMap( BdfDictionary properties) throws FormatException; + /** + * Retrieves the contact ID from the group metadata of the given contact + * group. + */ + ContactId getContactId(Transaction txn, GroupId contactGroupId) + throws DbException, FormatException; + + /** + * Stores the given contact ID in the group metadata of the given contact + * group. + */ + void setContactId(Transaction txn, GroupId contactGroupId, ContactId c) + throws DbException; } diff --git a/bramble-api/src/main/java/org/briarproject/bramble/api/client/ContactGroupConstants.java b/bramble-api/src/main/java/org/briarproject/bramble/api/client/ContactGroupConstants.java new file mode 100644 index 000000000..4c556bbe7 --- /dev/null +++ b/bramble-api/src/main/java/org/briarproject/bramble/api/client/ContactGroupConstants.java @@ -0,0 +1,9 @@ +package org.briarproject.bramble.api.client; + +public interface ContactGroupConstants { + + /** + * Group metadata key for associating a contact ID with a contact group. + */ + String GROUP_KEY_CONTACT_ID = "contactId"; +} diff --git a/bramble-core/src/main/java/org/briarproject/bramble/client/ClientHelperImpl.java b/bramble-core/src/main/java/org/briarproject/bramble/client/ClientHelperImpl.java index 604570aee..a92aecde5 100644 --- a/bramble-core/src/main/java/org/briarproject/bramble/client/ClientHelperImpl.java +++ b/bramble-core/src/main/java/org/briarproject/bramble/client/ClientHelperImpl.java @@ -2,11 +2,13 @@ package org.briarproject.bramble.client; import org.briarproject.bramble.api.FormatException; import org.briarproject.bramble.api.client.ClientHelper; +import org.briarproject.bramble.api.contact.ContactId; import org.briarproject.bramble.api.crypto.CryptoComponent; import org.briarproject.bramble.api.crypto.KeyParser; import org.briarproject.bramble.api.crypto.PrivateKey; import org.briarproject.bramble.api.crypto.PublicKey; import org.briarproject.bramble.api.data.BdfDictionary; +import org.briarproject.bramble.api.data.BdfEntry; import org.briarproject.bramble.api.data.BdfList; import org.briarproject.bramble.api.data.BdfReader; import org.briarproject.bramble.api.data.BdfReaderFactory; @@ -39,6 +41,7 @@ import java.util.Map.Entry; import javax.annotation.concurrent.Immutable; import javax.inject.Inject; +import static org.briarproject.bramble.api.client.ContactGroupConstants.GROUP_KEY_CONTACT_ID; import static org.briarproject.bramble.api.identity.Author.FORMAT_VERSION; import static org.briarproject.bramble.api.identity.AuthorConstants.MAX_AUTHOR_NAME_LENGTH; import static org.briarproject.bramble.api.identity.AuthorConstants.MAX_PUBLIC_KEY_LENGTH; @@ -389,4 +392,27 @@ class ClientHelperImpl implements ClientHelper { return tpMap; } + @Override + public ContactId getContactId(Transaction txn, GroupId contactGroupId) + throws DbException { + try { + BdfDictionary meta = + getGroupMetadataAsDictionary(txn, contactGroupId); + return new ContactId(meta.getLong(GROUP_KEY_CONTACT_ID).intValue()); + } catch (FormatException e) { + throw new DbException(e); // Invalid group metadata + } + } + + @Override + public void setContactId(Transaction txn, GroupId contactGroupId, + ContactId c) throws DbException { + BdfDictionary meta = BdfDictionary.of( + new BdfEntry(GROUP_KEY_CONTACT_ID, c.getInt())); + try { + mergeGroupMetadata(txn, contactGroupId, meta); + } catch (FormatException e) { + throw new AssertionError(e); + } + } } diff --git a/bramble-core/src/main/java/org/briarproject/bramble/versioning/ClientVersioningConstants.java b/bramble-core/src/main/java/org/briarproject/bramble/versioning/ClientVersioningConstants.java index e68ecc468..d3822a23c 100644 --- a/bramble-core/src/main/java/org/briarproject/bramble/versioning/ClientVersioningConstants.java +++ b/bramble-core/src/main/java/org/briarproject/bramble/versioning/ClientVersioningConstants.java @@ -5,6 +5,5 @@ interface ClientVersioningConstants { // Metadata keys String MSG_KEY_UPDATE_VERSION = "version"; String MSG_KEY_LOCAL = "local"; - String GROUP_KEY_CONTACT_ID = "contactId"; } diff --git a/bramble-core/src/main/java/org/briarproject/bramble/versioning/ClientVersioningManagerImpl.java b/bramble-core/src/main/java/org/briarproject/bramble/versioning/ClientVersioningManagerImpl.java index b334f3bea..6aadf889a 100644 --- a/bramble-core/src/main/java/org/briarproject/bramble/versioning/ClientVersioningManagerImpl.java +++ b/bramble-core/src/main/java/org/briarproject/bramble/versioning/ClientVersioningManagerImpl.java @@ -50,7 +50,6 @@ import static java.util.Collections.emptyList; 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; -import static org.briarproject.bramble.versioning.ClientVersioningConstants.GROUP_KEY_CONTACT_ID; import static org.briarproject.bramble.versioning.ClientVersioningConstants.MSG_KEY_LOCAL; import static org.briarproject.bramble.versioning.ClientVersioningConstants.MSG_KEY_UPDATE_VERSION; @@ -161,13 +160,7 @@ class ClientVersioningManagerImpl implements ClientVersioningManager, db.addGroup(txn, g); db.setGroupVisibility(txn, c.getId(), g.getId(), SHARED); // Attach the contact ID to the group - BdfDictionary meta = new BdfDictionary(); - meta.put(GROUP_KEY_CONTACT_ID, c.getId().getInt()); - try { - clientHelper.mergeGroupMetadata(txn, g.getId(), meta); - } catch (FormatException e) { - throw new AssertionError(e); - } + clientHelper.setContactId(txn, g.getId(), c.getId()); // Create and store the first local update List versions = new ArrayList<>(clients); Collections.sort(versions); @@ -229,7 +222,7 @@ class ClientVersioningManagerImpl implements ClientVersioningManager, Map after = getVisibilities(newLocalStates, newRemoteStates); // Call hooks for any visibilities that have changed - ContactId c = getContactId(txn, m.getGroupId()); + ContactId c = clientHelper.getContactId(txn, m.getGroupId()); if (!before.equals(after)) { Contact contact = db.getContact(txn, c); callVisibilityHooks(txn, contact, before, after); @@ -521,17 +514,6 @@ class ClientVersioningManagerImpl implements ClientVersioningManager, storeUpdate(txn, g, states, 1); } - private ContactId getContactId(Transaction txn, GroupId g) - throws DbException { - try { - BdfDictionary meta = - clientHelper.getGroupMetadataAsDictionary(txn, g); - return new ContactId(meta.getLong(GROUP_KEY_CONTACT_ID).intValue()); - } catch (FormatException e) { - throw new DbException(e); - } - } - private List updateStatesFromRemoteStates( List oldLocalStates, List remoteStates) { Set remoteSet = new HashSet<>(); diff --git a/bramble-core/src/test/java/org/briarproject/bramble/versioning/ClientVersioningManagerImplTest.java b/bramble-core/src/test/java/org/briarproject/bramble/versioning/ClientVersioningManagerImplTest.java index 93cf97dcc..17d23087b 100644 --- a/bramble-core/src/test/java/org/briarproject/bramble/versioning/ClientVersioningManagerImplTest.java +++ b/bramble-core/src/test/java/org/briarproject/bramble/versioning/ClientVersioningManagerImplTest.java @@ -38,7 +38,6 @@ import static org.briarproject.bramble.test.TestUtils.getContact; import static org.briarproject.bramble.test.TestUtils.getGroup; import static org.briarproject.bramble.test.TestUtils.getMessage; import static org.briarproject.bramble.test.TestUtils.getRandomId; -import static org.briarproject.bramble.versioning.ClientVersioningConstants.GROUP_KEY_CONTACT_ID; import static org.briarproject.bramble.versioning.ClientVersioningConstants.MSG_KEY_LOCAL; import static org.briarproject.bramble.versioning.ClientVersioningConstants.MSG_KEY_UPDATE_VERSION; import static org.junit.Assert.assertEquals; @@ -60,8 +59,6 @@ public class ClientVersioningManagerImplTest extends BrambleMockTestCase { private final ClientId clientId = getClientId(); private final long now = System.currentTimeMillis(); private final Transaction txn = new Transaction(null, false); - private final BdfDictionary groupMeta = BdfDictionary.of( - new BdfEntry(GROUP_KEY_CONTACT_ID, contact.getId().getInt())); private ClientVersioningManagerImpl createInstance() { context.checking(new Expectations() {{ @@ -123,8 +120,8 @@ public class ClientVersioningManagerImplTest extends BrambleMockTestCase { oneOf(db).addGroup(txn, contactGroup); oneOf(db).setGroupVisibility(txn, contact.getId(), contactGroup.getId(), SHARED); - oneOf(clientHelper).mergeGroupMetadata(txn, contactGroup.getId(), - groupMeta); + oneOf(clientHelper).setContactId(txn, contactGroup.getId(), + contact.getId()); oneOf(clock).currentTimeMillis(); will(returnValue(now)); oneOf(clientHelper).createMessage(contactGroup.getId(), now, @@ -460,9 +457,8 @@ public class ClientVersioningManagerImplTest extends BrambleMockTestCase { oneOf(db).deleteMessage(txn, oldRemoteUpdateId); oneOf(db).deleteMessageMetadata(txn, oldRemoteUpdateId); // Get contact ID - oneOf(clientHelper).getGroupMetadataAsDictionary(txn, - contactGroup.getId()); - will(returnValue(groupMeta)); + oneOf(clientHelper).getContactId(txn, contactGroup.getId()); + will(returnValue(contact.getId())); // No states or visibilities have changed }}); @@ -492,10 +488,9 @@ public class ClientVersioningManagerImplTest extends BrambleMockTestCase { // Load the latest local update oneOf(clientHelper).getMessageAsList(txn, oldLocalUpdateId); will(returnValue(oldLocalUpdateBody)); - // Get client ID - oneOf(clientHelper).getGroupMetadataAsDictionary(txn, - contactGroup.getId()); - will(returnValue(groupMeta)); + // Get contact ID + oneOf(clientHelper).getContactId(txn, contactGroup.getId()); + will(returnValue(contact.getId())); // No states or visibilities have changed }}); @@ -546,8 +541,6 @@ public class ClientVersioningManagerImplTest extends BrambleMockTestCase { BdfDictionary newLocalUpdateMeta = BdfDictionary.of( new BdfEntry(MSG_KEY_UPDATE_VERSION, 2L), new BdfEntry(MSG_KEY_LOCAL, true)); - BdfDictionary groupMeta = BdfDictionary.of( - new BdfEntry(GROUP_KEY_CONTACT_ID, contact.getId().getInt())); context.checking(new Expectations() {{ oneOf(clientHelper).toList(newRemoteUpdate); @@ -577,9 +570,8 @@ public class ClientVersioningManagerImplTest extends BrambleMockTestCase { oneOf(clientHelper).addLocalMessage(txn, newLocalUpdate, newLocalUpdateMeta, true, false); // The client's visibility has changed - oneOf(clientHelper).getGroupMetadataAsDictionary(txn, - contactGroup.getId()); - will(returnValue(groupMeta)); + oneOf(clientHelper).getContactId(txn, contactGroup.getId()); + will(returnValue(contact.getId())); oneOf(db).getContact(txn, contact.getId()); will(returnValue(contact)); oneOf(hook).onClientVisibilityChanging(txn, contact, visibility); @@ -619,8 +611,6 @@ public class ClientVersioningManagerImplTest extends BrambleMockTestCase { BdfDictionary newLocalUpdateMeta = BdfDictionary.of( new BdfEntry(MSG_KEY_UPDATE_VERSION, 2L), new BdfEntry(MSG_KEY_LOCAL, true)); - BdfDictionary groupMeta = BdfDictionary.of( - new BdfEntry(GROUP_KEY_CONTACT_ID, contact.getId().getInt())); context.checking(new Expectations() {{ oneOf(clientHelper).toList(newRemoteUpdate); @@ -650,9 +640,8 @@ public class ClientVersioningManagerImplTest extends BrambleMockTestCase { oneOf(clientHelper).addLocalMessage(txn, newLocalUpdate, newLocalUpdateMeta, true, false); // The client's visibility has changed - oneOf(clientHelper).getGroupMetadataAsDictionary(txn, - contactGroup.getId()); - will(returnValue(groupMeta)); + oneOf(clientHelper).getContactId(txn, contactGroup.getId()); + will(returnValue(contact.getId())); oneOf(db).getContact(txn, contact.getId()); will(returnValue(contact)); oneOf(hook).onClientVisibilityChanging(txn, contact, INVISIBLE); 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 89885a12a..fa6bed7a6 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 @@ -37,7 +37,6 @@ import javax.annotation.concurrent.Immutable; import static org.briarproject.bramble.api.autodelete.AutoDeleteConstants.NO_AUTO_DELETE_TIMER; import static org.briarproject.briar.api.introduction.IntroductionManager.CLIENT_ID; import static org.briarproject.briar.api.introduction.IntroductionManager.MAJOR_VERSION; -import static org.briarproject.briar.introduction.IntroductionConstants.GROUP_KEY_CONTACT_ID; import static org.briarproject.briar.introduction.MessageType.ABORT; import static org.briarproject.briar.introduction.MessageType.ACCEPT; import static org.briarproject.briar.introduction.MessageType.ACTIVATE; @@ -241,10 +240,7 @@ abstract class AbstractProtocolEngine> boolean contactSupportsAutoDeletion(Transaction txn, GroupId contactGroupId) throws DbException { try { - BdfDictionary meta = clientHelper - .getGroupMetadataAsDictionary(txn, contactGroupId); - int contactId = meta.getLong(GROUP_KEY_CONTACT_ID).intValue(); - ContactId c = new ContactId(contactId); + ContactId c = clientHelper.getContactId(txn, contactGroupId); int minorVersion = clientVersioningManager .getClientMinorVersion(txn, c, CLIENT_ID, MAJOR_VERSION); // Auto-delete was added in client version 0.1 diff --git a/briar-core/src/main/java/org/briarproject/briar/introduction/IntroductionConstants.java b/briar-core/src/main/java/org/briarproject/briar/introduction/IntroductionConstants.java index 16a09e93e..72a5066d7 100644 --- a/briar-core/src/main/java/org/briarproject/briar/introduction/IntroductionConstants.java +++ b/briar-core/src/main/java/org/briarproject/briar/introduction/IntroductionConstants.java @@ -2,9 +2,6 @@ package org.briarproject.briar.introduction; interface IntroductionConstants { - // Group metadata keys - String GROUP_KEY_CONTACT_ID = "contactId"; - // Message metadata keys String MSG_KEY_MESSAGE_TYPE = "messageType"; String MSG_KEY_SESSION_ID = "sessionId"; 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 70eee9b45..48eb1df7a 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 @@ -60,7 +60,6 @@ import static org.briarproject.briar.introduction.IntroduceeState.REMOTE_DECLINE import static org.briarproject.briar.introduction.IntroducerState.A_DECLINED; import static org.briarproject.briar.introduction.IntroducerState.B_DECLINED; import static org.briarproject.briar.introduction.IntroducerState.START; -import static org.briarproject.briar.introduction.IntroductionConstants.GROUP_KEY_CONTACT_ID; import static org.briarproject.briar.introduction.MessageType.ABORT; import static org.briarproject.briar.introduction.MessageType.ACCEPT; import static org.briarproject.briar.introduction.MessageType.ACTIVATE; @@ -140,13 +139,7 @@ class IntroductionManagerImpl extends ConversationClientImpl c.getId(), CLIENT_ID, MAJOR_VERSION); db.setGroupVisibility(txn, c.getId(), g.getId(), client); // Attach the contact ID to the group - BdfDictionary meta = new BdfDictionary(); - meta.put(GROUP_KEY_CONTACT_ID, c.getId().getInt()); - try { - clientHelper.mergeGroupMetadata(txn, g.getId(), meta); - } catch (FormatException e) { - throw new AssertionError(e); - } + clientHelper.setContactId(txn, g.getId(), c.getId()); } @Override @@ -187,7 +180,7 @@ class IntroductionManagerImpl extends ConversationClientImpl } StoredSession ss = getSession(txn, sessionId); // Handle the message - Session session; + Session session; MessageId storageId; if (ss == null) { if (meta.getMessageType() != REQUEST) throw new FormatException(); @@ -215,7 +208,7 @@ class IntroductionManagerImpl extends ConversationClientImpl private IntroduceeSession createNewIntroduceeSession(Transaction txn, Message m, BdfList body) throws DbException, FormatException { - ContactId introducerId = getContactId(txn, m.getGroupId()); + ContactId introducerId = clientHelper.getContactId(txn, m.getGroupId()); Author introducer = db.getContact(txn, introducerId).getAuthor(); Author local = identityManager.getLocalAuthor(txn); Author remote = messageParser.parseRequestMessage(m, body).getAuthor(); @@ -227,7 +220,7 @@ class IntroductionManagerImpl extends ConversationClientImpl remote); } - private S handleMessage(Transaction txn, Message m, + private > S handleMessage(Transaction txn, Message m, BdfList body, MessageType type, S session, ProtocolEngine engine) throws DbException, FormatException { if (type == REQUEST) { @@ -267,13 +260,6 @@ class IntroductionManagerImpl extends ConversationClientImpl results.values().iterator().next()); } - private ContactId getContactId(Transaction txn, GroupId contactGroupId) - throws DbException, FormatException { - BdfDictionary meta = - clientHelper.getGroupMetadataAsDictionary(txn, contactGroupId); - return new ContactId(meta.getLong(GROUP_KEY_CONTACT_ID).intValue()); - } - private MessageId createStorageId(Transaction txn) throws DbException { Message m = clientHelper .createMessageForStoringMetadata(localGroup.getId()); @@ -282,7 +268,7 @@ class IntroductionManagerImpl extends ConversationClientImpl } private void storeSession(Transaction txn, MessageId storageId, - Session session) throws DbException { + Session session) throws DbException { BdfDictionary d; if (session.getRole() == INTRODUCER) { d = sessionEncoder @@ -670,7 +656,7 @@ class IntroductionManagerImpl extends ConversationClientImpl try { StoredSession ss = getSession(txn, sessionId); if (ss == null) throw new AssertionError(); - Session s; + Session s; Role role = sessionParser.getRole(ss.bdfSession); if (role == INTRODUCER) { s = sessionParser.parseIntroducerSession(ss.bdfSession); diff --git a/briar-core/src/main/java/org/briarproject/briar/messaging/MessagingConstants.java b/briar-core/src/main/java/org/briarproject/briar/messaging/MessagingConstants.java index d62fe2b4a..88d0a4b5a 100644 --- a/briar-core/src/main/java/org/briarproject/briar/messaging/MessagingConstants.java +++ b/briar-core/src/main/java/org/briarproject/briar/messaging/MessagingConstants.java @@ -2,9 +2,6 @@ package org.briarproject.briar.messaging; interface MessagingConstants { - // Metadata keys for groups - String GROUP_KEY_CONTACT_ID = "contactId"; - // Metadata keys for messages String MSG_KEY_TIMESTAMP = "timestamp"; String MSG_KEY_LOCAL = "local"; diff --git a/briar-core/src/main/java/org/briarproject/briar/messaging/MessagingManagerImpl.java b/briar-core/src/main/java/org/briarproject/briar/messaging/MessagingManagerImpl.java index bb2936ccc..3eeeafb44 100644 --- a/briar-core/src/main/java/org/briarproject/briar/messaging/MessagingManagerImpl.java +++ b/briar-core/src/main/java/org/briarproject/briar/messaging/MessagingManagerImpl.java @@ -56,6 +56,7 @@ import javax.inject.Inject; import static java.util.Collections.emptyList; import static org.briarproject.bramble.api.autodelete.AutoDeleteConstants.NO_AUTO_DELETE_TIMER; +import static org.briarproject.bramble.api.client.ContactGroupConstants.GROUP_KEY_CONTACT_ID; import static org.briarproject.bramble.api.sync.SyncConstants.MAX_MESSAGE_BODY_LENGTH; import static org.briarproject.bramble.api.sync.validation.MessageState.DELIVERED; import static org.briarproject.bramble.util.IoUtils.copyAndClose; @@ -67,7 +68,6 @@ import static org.briarproject.briar.api.messaging.PrivateMessageFormat.TEXT_ONL import static org.briarproject.briar.client.MessageTrackerConstants.MSG_KEY_READ; import static org.briarproject.briar.messaging.MessageTypes.ATTACHMENT; import static org.briarproject.briar.messaging.MessageTypes.PRIVATE_MESSAGE; -import static org.briarproject.briar.messaging.MessagingConstants.GROUP_KEY_CONTACT_ID; import static org.briarproject.briar.messaging.MessagingConstants.MSG_KEY_ATTACHMENT_HEADERS; import static org.briarproject.briar.messaging.MessagingConstants.MSG_KEY_AUTO_DELETE_TIMER; import static org.briarproject.briar.messaging.MessagingConstants.MSG_KEY_HAS_TEXT; @@ -136,13 +136,7 @@ class MessagingManagerImpl implements MessagingManager, IncomingMessageHook, c.getId(), CLIENT_ID, MAJOR_VERSION); db.setGroupVisibility(txn, c.getId(), g.getId(), client); // Attach the contact ID to the group - BdfDictionary d = new BdfDictionary(); - d.put(GROUP_KEY_CONTACT_ID, c.getId().getInt()); - try { - clientHelper.mergeGroupMetadata(txn, g.getId(), d); - } catch (FormatException e) { - throw new AssertionError(e); - } + clientHelper.setContactId(txn, g.getId(), c.getId()); // Initialize the group count with current time messageTracker.initializeGroupCount(txn, g.getId()); } 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 26da12b2e..af62d3661 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 @@ -31,7 +31,6 @@ import javax.annotation.Nullable; import javax.annotation.concurrent.Immutable; import static org.briarproject.bramble.api.autodelete.AutoDeleteConstants.NO_AUTO_DELETE_TIMER; -import static org.briarproject.briar.privategroup.invitation.GroupInvitationConstants.GROUP_KEY_CONTACT_ID; import static org.briarproject.briar.privategroup.invitation.MessageType.ABORT; import static org.briarproject.briar.privategroup.invitation.MessageType.INVITE; import static org.briarproject.briar.privategroup.invitation.MessageType.JOIN; @@ -76,13 +75,6 @@ abstract class AbstractProtocolEngine> this.clock = clock; } - ContactId getContactId(Transaction txn, GroupId contactGroupId) - throws DbException, FormatException { - BdfDictionary meta = clientHelper.getGroupMetadataAsDictionary(txn, - contactGroupId); - return new ContactId(meta.getLong(GROUP_KEY_CONTACT_ID).intValue()); - } - boolean isSubscribedPrivateGroup(Transaction txn, GroupId g) throws DbException { if (!db.containsGroup(txn, g)) return false; @@ -100,7 +92,8 @@ abstract class AbstractProtocolEngine> void setPrivateGroupVisibility(Transaction txn, S session, Visibility preferred) throws DbException, FormatException { // Apply min of preferred visibility and client's visibility - ContactId contactId = getContactId(txn, session.getContactGroupId()); + ContactId contactId = + clientHelper.getContactId(txn, session.getContactGroupId()); Visibility client = clientVersioningManager.getClientVisibility(txn, contactId, PrivateGroupManager.CLIENT_ID, PrivateGroupManager.MAJOR_VERSION); @@ -273,10 +266,7 @@ abstract class AbstractProtocolEngine> boolean contactSupportsAutoDeletion(Transaction txn, GroupId contactGroupId) throws DbException { try { - BdfDictionary meta = clientHelper - .getGroupMetadataAsDictionary(txn, contactGroupId); - int contactId = meta.getLong(GROUP_KEY_CONTACT_ID).intValue(); - ContactId c = new ContactId(contactId); + ContactId c = clientHelper.getContactId(txn, contactGroupId); int minorVersion = clientVersioningManager .getClientMinorVersion(txn, c, GroupInvitationManager.CLIENT_ID, 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 9709f265a..519d6cb6d 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 @@ -191,7 +191,8 @@ class CreatorProtocolEngine extends AbstractProtocolEngine { // Share the private group with the contact setPrivateGroupVisibility(txn, s, SHARED); // Broadcast an event - ContactId contactId = getContactId(txn, m.getContactGroupId()); + ContactId contactId = + clientHelper.getContactId(txn, m.getContactGroupId()); txn.attach(new GroupInvitationResponseReceivedEvent( createInvitationResponse(m, true), contactId)); // Move to the JOINED state @@ -213,7 +214,8 @@ class CreatorProtocolEngine extends AbstractProtocolEngine { messageTracker.trackMessage(txn, m.getContactGroupId(), m.getTimestamp(), false); // Broadcast an event - ContactId contactId = getContactId(txn, m.getContactGroupId()); + ContactId contactId = + clientHelper.getContactId(txn, m.getContactGroupId()); txn.attach(new GroupInvitationResponseReceivedEvent( createInvitationResponse(m, false), contactId)); // Move to the START state diff --git a/briar-core/src/main/java/org/briarproject/briar/privategroup/invitation/GroupInvitationConstants.java b/briar-core/src/main/java/org/briarproject/briar/privategroup/invitation/GroupInvitationConstants.java index dd4f0ef35..82efba05f 100644 --- a/briar-core/src/main/java/org/briarproject/briar/privategroup/invitation/GroupInvitationConstants.java +++ b/briar-core/src/main/java/org/briarproject/briar/privategroup/invitation/GroupInvitationConstants.java @@ -2,9 +2,6 @@ package org.briarproject.briar.privategroup.invitation; interface GroupInvitationConstants { - // Group metadata keys - String GROUP_KEY_CONTACT_ID = "contactId"; - // Message metadata keys String MSG_KEY_MESSAGE_TYPE = "messageType"; String MSG_KEY_PRIVATE_GROUP_ID = "privateGroupId"; 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 53e6fa838..c988793df 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 @@ -53,7 +53,6 @@ import javax.inject.Inject; import static org.briarproject.bramble.api.sync.Group.Visibility.SHARED; import static org.briarproject.briar.privategroup.invitation.CreatorState.START; -import static org.briarproject.briar.privategroup.invitation.GroupInvitationConstants.GROUP_KEY_CONTACT_ID; import static org.briarproject.briar.privategroup.invitation.MessageType.ABORT; import static org.briarproject.briar.privategroup.invitation.MessageType.INVITE; import static org.briarproject.briar.privategroup.invitation.MessageType.JOIN; @@ -123,13 +122,7 @@ class GroupInvitationManagerImpl extends ConversationClientImpl c.getId(), CLIENT_ID, MAJOR_VERSION); db.setGroupVisibility(txn, c.getId(), g.getId(), client); // Attach the contact ID to the group - BdfDictionary meta = new BdfDictionary(); - meta.put(GROUP_KEY_CONTACT_ID, c.getId().getInt()); - try { - clientHelper.mergeGroupMetadata(txn, g.getId(), meta); - } catch (FormatException e) { - throw new AssertionError(e); - } + clientHelper.setContactId(txn, g.getId(), c.getId()); // If the contact belongs to any private groups, create a peer session for (Group pg : db.getGroups(txn, PrivateGroupManager.CLIENT_ID, PrivateGroupManager.MAJOR_VERSION)) { @@ -189,7 +182,8 @@ class GroupInvitationManagerImpl extends ConversationClientImpl results.values().iterator().next()); } - private Session handleFirstMessage(Transaction txn, Message m, BdfList body, + private Session handleFirstMessage(Transaction txn, Message m, + BdfList body, MessageMetadata meta) throws DbException, FormatException { GroupId privateGroupId = meta.getPrivateGroupId(); MessageType type = meta.getMessageType(); 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 b4a7665fd..cdb597a5e 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 @@ -230,7 +230,8 @@ class InviteeProtocolEngine extends AbstractProtocolEngine { // The timestamp must be higher than the last invite message, if any if (m.getTimestamp() <= s.getInviteTimestamp()) return abort(txn, s); // Check that the contact is the creator - ContactId contactId = getContactId(txn, s.getContactGroupId()); + ContactId contactId = + clientHelper.getContactId(txn, s.getContactGroupId()); Author contact = db.getContact(txn, contactId).getAuthor(); if (!contact.getId().equals(m.getCreator().getId())) return abort(txn, s); 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 b7eb293f5..de0a96fc6 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 @@ -355,7 +355,8 @@ class PeerProtocolEngine extends AbstractProtocolEngine { private void relationshipRevealed(Transaction txn, PeerSession s, boolean byContact) throws DbException, FormatException { - ContactId contactId = getContactId(txn, s.getContactGroupId()); + ContactId contactId = + clientHelper.getContactId(txn, s.getContactGroupId()); Contact contact = db.getContact(txn, contactId); privateGroupManager.relationshipRevealed(txn, s.getPrivateGroupId(), contact.getAuthor().getId(), byContact); 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 9d47cf327..612e9f3aa 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 @@ -37,7 +37,6 @@ import static org.briarproject.briar.sharing.MessageType.ACCEPT; import static org.briarproject.briar.sharing.MessageType.DECLINE; import static org.briarproject.briar.sharing.MessageType.INVITE; import static org.briarproject.briar.sharing.MessageType.LEAVE; -import static org.briarproject.briar.sharing.SharingConstants.GROUP_KEY_CONTACT_ID; import static org.briarproject.briar.sharing.State.LOCAL_INVITED; import static org.briarproject.briar.sharing.State.LOCAL_LEFT; import static org.briarproject.briar.sharing.State.REMOTE_HANGING; @@ -341,7 +340,8 @@ abstract class ProtocolEngineImpl messageTracker.trackMessage(txn, m.getContactGroupId(), m.getTimestamp(), false); // Broadcast an event - ContactId contactId = getContactId(txn, s.getContactGroupId()); + ContactId contactId = + clientHelper.getContactId(txn, s.getContactGroupId()); txn.attach(getInvitationRequestReceivedEvent(m, contactId, available, false)); // Move to the next state @@ -367,7 +367,8 @@ abstract class ProtocolEngineImpl // Share the shareable with the contact setShareableVisibility(txn, s, SHARED); // Broadcast an event - ContactId contactId = getContactId(txn, s.getContactGroupId()); + ContactId contactId = + clientHelper.getContactId(txn, s.getContactGroupId()); txn.attach( getInvitationRequestReceivedEvent(m, contactId, false, true)); // Move to the next state @@ -411,7 +412,8 @@ abstract class ProtocolEngineImpl messageTracker.trackMessage(txn, m.getContactGroupId(), m.getTimestamp(), false); // Broadcast an event - ContactId contactId = getContactId(txn, m.getContactGroupId()); + ContactId contactId = + clientHelper.getContactId(txn, m.getContactGroupId()); txn.attach(getInvitationResponseReceivedEvent(m, contactId)); // Move to the next state return new Session(nextState, s.getContactGroupId(), s.getShareableId(), @@ -469,7 +471,8 @@ abstract class ProtocolEngineImpl throw new DbException(e); // Invalid group metadata } // Broadcast an event - ContactId contactId = getContactId(txn, m.getContactGroupId()); + ContactId contactId = + clientHelper.getContactId(txn, m.getContactGroupId()); txn.attach(getInvitationResponseReceivedEvent(m, contactId)); // Move to the next state return new Session(START, s.getContactGroupId(), s.getShareableId(), @@ -529,7 +532,8 @@ abstract class ProtocolEngineImpl if (isInvalidDependency(s, m.getPreviousMessageId())) return abortWithMessage(txn, s); // Broadcast event informing that contact left - ContactId contactId = getContactId(txn, s.getContactGroupId()); + ContactId contactId = + clientHelper.getContactId(txn, s.getContactGroupId()); ContactLeftShareableEvent e = new ContactLeftShareableEvent( s.getShareableId(), contactId); txn.attach(e); @@ -648,20 +652,14 @@ abstract class ProtocolEngineImpl private void setShareableVisibility(Transaction txn, Session session, Visibility preferred) throws DbException, FormatException { // Apply min of preferred visibility and client's visibility - ContactId contactId = getContactId(txn, session.getContactGroupId()); + ContactId contactId = + clientHelper.getContactId(txn, session.getContactGroupId()); Visibility client = clientVersioningManager.getClientVisibility(txn, contactId, shareableClientId, shareableClientMajorVersion); Visibility min = Visibility.min(preferred, client); db.setGroupVisibility(txn, contactId, session.getShareableId(), min); } - private ContactId getContactId(Transaction txn, GroupId contactGroupId) - throws DbException, FormatException { - BdfDictionary meta = clientHelper.getGroupMetadataAsDictionary(txn, - contactGroupId); - return new ContactId(meta.getLong(GROUP_KEY_CONTACT_ID).intValue()); - } - private boolean isInvalidDependency(Session session, @Nullable MessageId dependency) { MessageId expected = session.getLastRemoteMessageId(); @@ -678,10 +676,7 @@ abstract class ProtocolEngineImpl boolean contactSupportsAutoDeletion(Transaction txn, GroupId contactGroupId) throws DbException { try { - BdfDictionary meta = clientHelper - .getGroupMetadataAsDictionary(txn, contactGroupId); - int contactId = meta.getLong(GROUP_KEY_CONTACT_ID).intValue(); - ContactId c = new ContactId(contactId); + ContactId c = clientHelper.getContactId(txn, contactGroupId); int minorVersion = clientVersioningManager .getClientMinorVersion(txn, c, sharingClientId, sharingClientMajorVersion); diff --git a/briar-core/src/main/java/org/briarproject/briar/sharing/SharingConstants.java b/briar-core/src/main/java/org/briarproject/briar/sharing/SharingConstants.java index 9d45467a5..4ebf1d790 100644 --- a/briar-core/src/main/java/org/briarproject/briar/sharing/SharingConstants.java +++ b/briar-core/src/main/java/org/briarproject/briar/sharing/SharingConstants.java @@ -4,9 +4,6 @@ import org.briarproject.briar.client.MessageTrackerConstants; interface SharingConstants { - // Group metadata keys - String GROUP_KEY_CONTACT_ID = "contactId"; - // Message metadata keys String MSG_KEY_MESSAGE_TYPE = "messageType"; String MSG_KEY_SHAREABLE_ID = "shareableId"; 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 82f2a0d9a..ae1980ef4 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 @@ -52,7 +52,6 @@ import static org.briarproject.briar.sharing.MessageType.ACCEPT; import static org.briarproject.briar.sharing.MessageType.DECLINE; import static org.briarproject.briar.sharing.MessageType.INVITE; import static org.briarproject.briar.sharing.MessageType.LEAVE; -import static org.briarproject.briar.sharing.SharingConstants.GROUP_KEY_CONTACT_ID; import static org.briarproject.briar.sharing.State.SHARING; @NotNullByDefault @@ -114,13 +113,7 @@ abstract class SharingManagerImpl c.getId(), getClientId(), getMajorVersion()); db.setGroupVisibility(txn, c.getId(), g.getId(), client); // Attach the contact ID to the group - BdfDictionary meta = new BdfDictionary(); - meta.put(GROUP_KEY_CONTACT_ID, c.getId().getInt()); - try { - clientHelper.mergeGroupMetadata(txn, g.getId(), meta); - } catch (FormatException e) { - throw new AssertionError(e); - } + clientHelper.setContactId(txn, g.getId(), c.getId()); } @Override 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 a003e34a7..f7cff5186 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 @@ -37,7 +37,6 @@ import static org.briarproject.bramble.util.StringUtils.getRandomString; import static org.briarproject.briar.api.privategroup.PrivateGroupConstants.GROUP_SALT_LENGTH; import static org.briarproject.briar.api.privategroup.PrivateGroupConstants.MAX_GROUP_INVITATION_TEXT_LENGTH; import static org.briarproject.briar.api.privategroup.PrivateGroupConstants.MAX_GROUP_NAME_LENGTH; -import static org.briarproject.briar.privategroup.invitation.GroupInvitationConstants.GROUP_KEY_CONTACT_ID; import static org.briarproject.briar.privategroup.invitation.MessageType.ABORT; import static org.briarproject.briar.privategroup.invitation.MessageType.INVITE; import static org.briarproject.briar.privategroup.invitation.MessageType.JOIN; @@ -81,8 +80,6 @@ abstract class AbstractProtocolEngineTest extends BrambleMockTestCase { final long messageTimestamp = message.getTimestamp(); final long inviteTimestamp = messageTimestamp - 1; final long localTimestamp = inviteTimestamp - 1; - final BdfDictionary groupMeta = BdfDictionary.of( - new BdfEntry(GROUP_KEY_CONTACT_ID, contactId.getInt())); final InviteMessage inviteMessage = new InviteMessage(new MessageId(getRandomId()), contactGroupId, @@ -196,12 +193,9 @@ abstract class AbstractProtocolEngineTest extends BrambleMockTestCase { } void expectGetContactId() throws Exception { - BdfDictionary groupMeta = BdfDictionary - .of(new BdfEntry(GROUP_KEY_CONTACT_ID, contactId.getInt())); context.checking(new Expectations() {{ - oneOf(clientHelper) - .getGroupMetadataAsDictionary(txn, contactGroupId); - will(returnValue(groupMeta)); + oneOf(clientHelper).getContactId(txn, contactGroupId); + will(returnValue(contactId)); }}); } @@ -231,9 +225,8 @@ abstract class AbstractProtocolEngineTest extends BrambleMockTestCase { void expectCheckWhetherContactSupportsAutoDeletion() throws Exception { context.checking(new Expectations() {{ - oneOf(clientHelper).getGroupMetadataAsDictionary(txn, - contactGroupId); - will(returnValue(groupMeta)); + oneOf(clientHelper).getContactId(txn, contactGroupId); + will(returnValue(contactId)); oneOf(clientVersioningManager).getClientMinorVersion(txn, contactId, GroupInvitationManager.CLIENT_ID, GroupInvitationManager.MAJOR_VERSION); 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 60d0e3758..d533cacf9 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 @@ -58,7 +58,6 @@ import static org.briarproject.briar.api.privategroup.PrivateGroupConstants.GROU import static org.briarproject.briar.api.privategroup.PrivateGroupConstants.MAX_GROUP_NAME_LENGTH; import static org.briarproject.briar.api.privategroup.invitation.GroupInvitationManager.CLIENT_ID; import static org.briarproject.briar.api.privategroup.invitation.GroupInvitationManager.MAJOR_VERSION; -import static org.briarproject.briar.privategroup.invitation.GroupInvitationConstants.GROUP_KEY_CONTACT_ID; import static org.briarproject.briar.privategroup.invitation.MessageType.ABORT; import static org.briarproject.briar.privategroup.invitation.MessageType.INVITE; import static org.briarproject.briar.privategroup.invitation.MessageType.JOIN; @@ -178,9 +177,6 @@ public class GroupInvitationManagerImplTest extends BrambleMockTestCase { } private void expectAddingContact(Contact c) throws Exception { - BdfDictionary meta = BdfDictionary - .of(new BdfEntry(GROUP_KEY_CONTACT_ID, c.getId().getInt())); - context.checking(new Expectations() {{ oneOf(contactGroupFactory).createContactGroup(CLIENT_ID, MAJOR_VERSION, c); @@ -192,7 +188,7 @@ public class GroupInvitationManagerImplTest extends BrambleMockTestCase { oneOf(db).setGroupVisibility(txn, c.getId(), contactGroup.getId(), SHARED); oneOf(clientHelper) - .mergeGroupMetadata(txn, contactGroup.getId(), meta); + .setContactId(txn, contactGroup.getId(), contactId); oneOf(db).getGroups(txn, PrivateGroupManager.CLIENT_ID, PrivateGroupManager.MAJOR_VERSION); will(returnValue(Collections.singletonList(privateGroup))); diff --git a/briar-core/src/test/java/org/briarproject/briar/sharing/BlogSharingManagerImplTest.java b/briar-core/src/test/java/org/briarproject/briar/sharing/BlogSharingManagerImplTest.java index 41cf72502..78ec37f1f 100644 --- a/briar-core/src/test/java/org/briarproject/briar/sharing/BlogSharingManagerImplTest.java +++ b/briar-core/src/test/java/org/briarproject/briar/sharing/BlogSharingManagerImplTest.java @@ -5,7 +5,6 @@ import org.briarproject.bramble.api.client.ContactGroupFactory; import org.briarproject.bramble.api.contact.Contact; import org.briarproject.bramble.api.contact.ContactId; import org.briarproject.bramble.api.data.BdfDictionary; -import org.briarproject.bramble.api.data.BdfEntry; import org.briarproject.bramble.api.data.MetadataParser; import org.briarproject.bramble.api.db.DatabaseComponent; import org.briarproject.bramble.api.db.DbException; @@ -41,7 +40,6 @@ import static org.briarproject.bramble.test.TestUtils.getMessage; import static org.briarproject.bramble.test.TestUtils.getRandomId; import static org.briarproject.briar.api.blog.BlogSharingManager.CLIENT_ID; import static org.briarproject.briar.api.blog.BlogSharingManager.MAJOR_VERSION; -import static org.briarproject.briar.sharing.SharingConstants.GROUP_KEY_CONTACT_ID; public class BlogSharingManagerImplTest extends BrambleMockTestCase { @@ -117,8 +115,6 @@ public class BlogSharingManagerImplTest extends BrambleMockTestCase { } private void expectAddingContact(Transaction txn) throws Exception { - BdfDictionary meta = BdfDictionary.of( - new BdfEntry(GROUP_KEY_CONTACT_ID, contactId.getInt())); Map sessions = Collections.emptyMap(); context.checking(new Expectations() {{ @@ -134,7 +130,7 @@ public class BlogSharingManagerImplTest extends BrambleMockTestCase { SHARED); // Attach the contact ID to the group oneOf(clientHelper) - .mergeGroupMetadata(txn, contactGroup.getId(), meta); + .setContactId(txn, contactGroup.getId(), contactId); // Get our blog and the contact's blog oneOf(identityManager).getLocalAuthor(txn); will(returnValue(localAuthor)); From fee2e503bd82bb9872dd1362701d8b54af0e5f1a Mon Sep 17 00:00:00 2001 From: akwizgran Date: Tue, 24 Nov 2020 10:51:19 +0000 Subject: [PATCH 014/124] Rewrap lines. --- .../privategroup/invitation/GroupInvitationManagerImpl.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) 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 c988793df..d89858a9e 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 @@ -183,8 +183,8 @@ class GroupInvitationManagerImpl extends ConversationClientImpl } private Session handleFirstMessage(Transaction txn, Message m, - BdfList body, - MessageMetadata meta) throws DbException, FormatException { + BdfList body, MessageMetadata meta) + throws DbException, FormatException { GroupId privateGroupId = meta.getPrivateGroupId(); MessageType type = meta.getMessageType(); if (type == INVITE) { From 07f20e1e0d3cb02ff42ff3317a1000d1a288fe37 Mon Sep 17 00:00:00 2001 From: akwizgran Date: Thu, 26 Nov 2020 11:20:31 +0000 Subject: [PATCH 015/124] Refactor auto-delete code from Bramble to Briar. --- .../bramble/util/ValidationUtils.java | 13 ++-------- .../conversation/ConversationViewModel.java | 2 +- .../api/autodelete/AutoDeleteConstants.java | 2 +- .../briar/api/messaging/PrivateMessage.java | 2 +- .../briar/introduction/AbortMessage.java | 2 +- .../introduction/AbstractProtocolEngine.java | 2 +- .../briar/introduction/ActivateMessage.java | 2 +- .../briar/introduction/AuthMessage.java | 2 +- .../introduction/IntroductionValidator.java | 4 ++-- .../introduction/MessageEncoderImpl.java | 2 +- .../briar/introduction/MessageParserImpl.java | 2 +- .../briar/messaging/MessagingManagerImpl.java | 2 +- .../messaging/PrivateMessageFactoryImpl.java | 2 +- .../messaging/PrivateMessageValidator.java | 4 ++-- .../invitation/AbstractProtocolEngine.java | 2 +- .../invitation/GroupInvitationValidator.java | 4 ++-- .../invitation/MessageEncoderImpl.java | 2 +- .../invitation/MessageParserImpl.java | 2 +- .../briar/sharing/MessageEncoderImpl.java | 2 +- .../briar/sharing/MessageParserImpl.java | 2 +- .../briar/sharing/ProtocolEngineImpl.java | 2 +- .../briar/sharing/SharingValidator.java | 4 ++-- .../briar/test/TestDataCreatorImpl.java | 4 ++-- .../briar/util/ValidationUtils.java | 24 +++++++++++++++++++ .../IntroductionIntegrationTest.java | 2 +- .../IntroductionValidatorTest.java | 6 ++--- .../MessageEncoderParserIntegrationTest.java | 6 ++--- .../messaging/MessageSizeIntegrationTest.java | 2 +- .../MessagingManagerIntegrationTest.java | 4 ++-- .../PrivateMessageValidatorTest.java | 4 ++-- .../SimplexMessagingIntegrationTest.java | 2 +- .../AbstractProtocolEngineTest.java | 2 +- .../invitation/CreatorProtocolEngineTest.java | 2 +- .../GroupInvitationManagerImplTest.java | 2 +- .../GroupInvitationValidatorTest.java | 6 ++--- .../invitation/InviteeProtocolEngineTest.java | 2 +- .../invitation/PeerProtocolEngineTest.java | 2 +- .../sharing/BlogSharingValidatorTest.java | 6 ++--- .../sharing/ForumSharingValidatorTest.java | 6 ++--- .../briar/sharing/SharingValidatorTest.java | 6 ++--- .../headless/event/WebSocketControllerTest.kt | 2 +- .../messaging/MessagingControllerImplTest.kt | 2 +- 42 files changed, 85 insertions(+), 70 deletions(-) rename {bramble-api/src/main/java/org/briarproject/bramble => briar-api/src/main/java/org/briarproject/briar}/api/autodelete/AutoDeleteConstants.java (92%) create mode 100644 briar-core/src/main/java/org/briarproject/briar/util/ValidationUtils.java diff --git a/bramble-api/src/main/java/org/briarproject/bramble/util/ValidationUtils.java b/bramble-api/src/main/java/org/briarproject/bramble/util/ValidationUtils.java index bc44a04d5..346edc1f7 100644 --- a/bramble-api/src/main/java/org/briarproject/bramble/util/ValidationUtils.java +++ b/bramble-api/src/main/java/org/briarproject/bramble/util/ValidationUtils.java @@ -6,11 +6,9 @@ import org.briarproject.bramble.api.data.BdfList; import org.briarproject.bramble.api.nullsafety.NotNullByDefault; import javax.annotation.Nullable; +import javax.annotation.concurrent.Immutable; -import static org.briarproject.bramble.api.autodelete.AutoDeleteConstants.MAX_AUTO_DELETE_TIMER_MS; -import static org.briarproject.bramble.api.autodelete.AutoDeleteConstants.MIN_AUTO_DELETE_TIMER_MS; -import static org.briarproject.bramble.api.autodelete.AutoDeleteConstants.NO_AUTO_DELETE_TIMER; - +@Immutable @NotNullByDefault public class ValidationUtils { @@ -73,11 +71,4 @@ public class ValidationUtils { throws FormatException { if (l != null && (l < min || l > max)) throw new FormatException(); } - - public static long validateAutoDeleteTimer(@Nullable Long timer) - throws FormatException { - if (timer == null) return NO_AUTO_DELETE_TIMER; - checkRange(timer, MIN_AUTO_DELETE_TIMER_MS, MAX_AUTO_DELETE_TIMER_MS); - return timer; - } } 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 265b4bb8d..0bf21d2d5 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 @@ -58,12 +58,12 @@ import static androidx.lifecycle.Transformations.map; import static java.util.Objects.requireNonNull; import static java.util.logging.Level.WARNING; import static java.util.logging.Logger.getLogger; -import static org.briarproject.bramble.api.autodelete.AutoDeleteConstants.NO_AUTO_DELETE_TIMER; import static org.briarproject.bramble.util.LogUtils.logDuration; import static org.briarproject.bramble.util.LogUtils.logException; import static org.briarproject.bramble.util.LogUtils.now; import static org.briarproject.briar.android.settings.SettingsFragment.SETTINGS_NAMESPACE; import static org.briarproject.briar.android.util.UiUtils.observeForeverOnce; +import static org.briarproject.briar.api.autodelete.AutoDeleteConstants.NO_AUTO_DELETE_TIMER; import static org.briarproject.briar.api.messaging.PrivateMessageFormat.TEXT_IMAGES; import static org.briarproject.briar.api.messaging.PrivateMessageFormat.TEXT_ONLY; diff --git a/bramble-api/src/main/java/org/briarproject/bramble/api/autodelete/AutoDeleteConstants.java b/briar-api/src/main/java/org/briarproject/briar/api/autodelete/AutoDeleteConstants.java similarity index 92% rename from bramble-api/src/main/java/org/briarproject/bramble/api/autodelete/AutoDeleteConstants.java rename to briar-api/src/main/java/org/briarproject/briar/api/autodelete/AutoDeleteConstants.java index ca1aaaf8e..f0c6da350 100644 --- a/bramble-api/src/main/java/org/briarproject/bramble/api/autodelete/AutoDeleteConstants.java +++ b/briar-api/src/main/java/org/briarproject/briar/api/autodelete/AutoDeleteConstants.java @@ -1,4 +1,4 @@ -package org.briarproject.bramble.api.autodelete; +package org.briarproject.briar.api.autodelete; import static java.util.concurrent.TimeUnit.DAYS; import static java.util.concurrent.TimeUnit.MINUTES; diff --git a/briar-api/src/main/java/org/briarproject/briar/api/messaging/PrivateMessage.java b/briar-api/src/main/java/org/briarproject/briar/api/messaging/PrivateMessage.java index 6d7237970..23bc39dde 100644 --- a/briar-api/src/main/java/org/briarproject/briar/api/messaging/PrivateMessage.java +++ b/briar-api/src/main/java/org/briarproject/briar/api/messaging/PrivateMessage.java @@ -9,7 +9,7 @@ import java.util.List; import javax.annotation.concurrent.Immutable; import static java.util.Collections.emptyList; -import static org.briarproject.bramble.api.autodelete.AutoDeleteConstants.NO_AUTO_DELETE_TIMER; +import static org.briarproject.briar.api.autodelete.AutoDeleteConstants.NO_AUTO_DELETE_TIMER; import static org.briarproject.briar.api.messaging.PrivateMessageFormat.TEXT_IMAGES; import static org.briarproject.briar.api.messaging.PrivateMessageFormat.TEXT_IMAGES_AUTO_DELETE; import static org.briarproject.briar.api.messaging.PrivateMessageFormat.TEXT_ONLY; diff --git a/briar-core/src/main/java/org/briarproject/briar/introduction/AbortMessage.java b/briar-core/src/main/java/org/briarproject/briar/introduction/AbortMessage.java index af98a1da2..fe90afa3c 100644 --- a/briar-core/src/main/java/org/briarproject/briar/introduction/AbortMessage.java +++ b/briar-core/src/main/java/org/briarproject/briar/introduction/AbortMessage.java @@ -8,7 +8,7 @@ import org.briarproject.briar.api.client.SessionId; import javax.annotation.Nullable; import javax.annotation.concurrent.Immutable; -import static org.briarproject.bramble.api.autodelete.AutoDeleteConstants.NO_AUTO_DELETE_TIMER; +import static org.briarproject.briar.api.autodelete.AutoDeleteConstants.NO_AUTO_DELETE_TIMER; @Immutable @NotNullByDefault 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 fa6bed7a6..0e74825d5 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 @@ -34,7 +34,7 @@ import java.util.Map; import javax.annotation.Nullable; import javax.annotation.concurrent.Immutable; -import static org.briarproject.bramble.api.autodelete.AutoDeleteConstants.NO_AUTO_DELETE_TIMER; +import static org.briarproject.briar.api.autodelete.AutoDeleteConstants.NO_AUTO_DELETE_TIMER; import static org.briarproject.briar.api.introduction.IntroductionManager.CLIENT_ID; import static org.briarproject.briar.api.introduction.IntroductionManager.MAJOR_VERSION; import static org.briarproject.briar.introduction.MessageType.ABORT; diff --git a/briar-core/src/main/java/org/briarproject/briar/introduction/ActivateMessage.java b/briar-core/src/main/java/org/briarproject/briar/introduction/ActivateMessage.java index 5c2f25375..4f53f2c32 100644 --- a/briar-core/src/main/java/org/briarproject/briar/introduction/ActivateMessage.java +++ b/briar-core/src/main/java/org/briarproject/briar/introduction/ActivateMessage.java @@ -7,7 +7,7 @@ import org.briarproject.briar.api.client.SessionId; import javax.annotation.concurrent.Immutable; -import static org.briarproject.bramble.api.autodelete.AutoDeleteConstants.NO_AUTO_DELETE_TIMER; +import static org.briarproject.briar.api.autodelete.AutoDeleteConstants.NO_AUTO_DELETE_TIMER; @Immutable @NotNullByDefault diff --git a/briar-core/src/main/java/org/briarproject/briar/introduction/AuthMessage.java b/briar-core/src/main/java/org/briarproject/briar/introduction/AuthMessage.java index 01bdcae33..09c09c35b 100644 --- a/briar-core/src/main/java/org/briarproject/briar/introduction/AuthMessage.java +++ b/briar-core/src/main/java/org/briarproject/briar/introduction/AuthMessage.java @@ -7,7 +7,7 @@ import org.briarproject.briar.api.client.SessionId; import javax.annotation.concurrent.Immutable; -import static org.briarproject.bramble.api.autodelete.AutoDeleteConstants.NO_AUTO_DELETE_TIMER; +import static org.briarproject.briar.api.autodelete.AutoDeleteConstants.NO_AUTO_DELETE_TIMER; @Immutable @NotNullByDefault diff --git a/briar-core/src/main/java/org/briarproject/briar/introduction/IntroductionValidator.java b/briar-core/src/main/java/org/briarproject/briar/introduction/IntroductionValidator.java index a4c460bb5..604bee0d4 100644 --- a/briar-core/src/main/java/org/briarproject/briar/introduction/IntroductionValidator.java +++ b/briar-core/src/main/java/org/briarproject/briar/introduction/IntroductionValidator.java @@ -18,17 +18,17 @@ import org.briarproject.briar.api.client.SessionId; import javax.annotation.concurrent.Immutable; import static java.util.Collections.singletonList; -import static org.briarproject.bramble.api.autodelete.AutoDeleteConstants.NO_AUTO_DELETE_TIMER; import static org.briarproject.bramble.api.crypto.CryptoConstants.MAC_BYTES; import static org.briarproject.bramble.api.crypto.CryptoConstants.MAX_SIGNATURE_BYTES; import static org.briarproject.bramble.api.identity.AuthorConstants.MAX_PUBLIC_KEY_LENGTH; import static org.briarproject.bramble.util.ValidationUtils.checkLength; import static org.briarproject.bramble.util.ValidationUtils.checkSize; -import static org.briarproject.bramble.util.ValidationUtils.validateAutoDeleteTimer; +import static org.briarproject.briar.api.autodelete.AutoDeleteConstants.NO_AUTO_DELETE_TIMER; import static org.briarproject.briar.api.introduction.IntroductionConstants.MAX_INTRODUCTION_TEXT_LENGTH; import static org.briarproject.briar.introduction.MessageType.ACCEPT; import static org.briarproject.briar.introduction.MessageType.ACTIVATE; import static org.briarproject.briar.introduction.MessageType.AUTH; +import static org.briarproject.briar.util.ValidationUtils.validateAutoDeleteTimer; @Immutable diff --git a/briar-core/src/main/java/org/briarproject/briar/introduction/MessageEncoderImpl.java b/briar-core/src/main/java/org/briarproject/briar/introduction/MessageEncoderImpl.java index ecb5dbccb..6b56089f8 100644 --- a/briar-core/src/main/java/org/briarproject/briar/introduction/MessageEncoderImpl.java +++ b/briar-core/src/main/java/org/briarproject/briar/introduction/MessageEncoderImpl.java @@ -20,7 +20,7 @@ import java.util.Map; import javax.annotation.Nullable; import javax.inject.Inject; -import static org.briarproject.bramble.api.autodelete.AutoDeleteConstants.NO_AUTO_DELETE_TIMER; +import static org.briarproject.briar.api.autodelete.AutoDeleteConstants.NO_AUTO_DELETE_TIMER; import static org.briarproject.briar.client.MessageTrackerConstants.MSG_KEY_READ; import static org.briarproject.briar.introduction.IntroductionConstants.MSG_KEY_AUTO_DELETE_TIMER; import static org.briarproject.briar.introduction.IntroductionConstants.MSG_KEY_AVAILABLE_TO_ANSWER; diff --git a/briar-core/src/main/java/org/briarproject/briar/introduction/MessageParserImpl.java b/briar-core/src/main/java/org/briarproject/briar/introduction/MessageParserImpl.java index bc4160d1e..97d665ca1 100644 --- a/briar-core/src/main/java/org/briarproject/briar/introduction/MessageParserImpl.java +++ b/briar-core/src/main/java/org/briarproject/briar/introduction/MessageParserImpl.java @@ -19,7 +19,7 @@ import java.util.Map; import javax.inject.Inject; -import static org.briarproject.bramble.api.autodelete.AutoDeleteConstants.NO_AUTO_DELETE_TIMER; +import static org.briarproject.briar.api.autodelete.AutoDeleteConstants.NO_AUTO_DELETE_TIMER; import static org.briarproject.briar.client.MessageTrackerConstants.MSG_KEY_READ; import static org.briarproject.briar.introduction.IntroductionConstants.MSG_KEY_AUTO_DELETE_TIMER; import static org.briarproject.briar.introduction.IntroductionConstants.MSG_KEY_AVAILABLE_TO_ANSWER; diff --git a/briar-core/src/main/java/org/briarproject/briar/messaging/MessagingManagerImpl.java b/briar-core/src/main/java/org/briarproject/briar/messaging/MessagingManagerImpl.java index 3eeeafb44..9297365c9 100644 --- a/briar-core/src/main/java/org/briarproject/briar/messaging/MessagingManagerImpl.java +++ b/briar-core/src/main/java/org/briarproject/briar/messaging/MessagingManagerImpl.java @@ -55,13 +55,13 @@ import javax.annotation.concurrent.Immutable; import javax.inject.Inject; import static java.util.Collections.emptyList; -import static org.briarproject.bramble.api.autodelete.AutoDeleteConstants.NO_AUTO_DELETE_TIMER; import static org.briarproject.bramble.api.client.ContactGroupConstants.GROUP_KEY_CONTACT_ID; import static org.briarproject.bramble.api.sync.SyncConstants.MAX_MESSAGE_BODY_LENGTH; import static org.briarproject.bramble.api.sync.validation.MessageState.DELIVERED; import static org.briarproject.bramble.util.IoUtils.copyAndClose; import static org.briarproject.briar.api.attachment.MediaConstants.MSG_KEY_CONTENT_TYPE; import static org.briarproject.briar.api.attachment.MediaConstants.MSG_KEY_DESCRIPTOR_LENGTH; +import static org.briarproject.briar.api.autodelete.AutoDeleteConstants.NO_AUTO_DELETE_TIMER; import static org.briarproject.briar.api.messaging.PrivateMessageFormat.TEXT_IMAGES; import static org.briarproject.briar.api.messaging.PrivateMessageFormat.TEXT_IMAGES_AUTO_DELETE; import static org.briarproject.briar.api.messaging.PrivateMessageFormat.TEXT_ONLY; diff --git a/briar-core/src/main/java/org/briarproject/briar/messaging/PrivateMessageFactoryImpl.java b/briar-core/src/main/java/org/briarproject/briar/messaging/PrivateMessageFactoryImpl.java index adae87dd3..a598ce718 100644 --- a/briar-core/src/main/java/org/briarproject/briar/messaging/PrivateMessageFactoryImpl.java +++ b/briar-core/src/main/java/org/briarproject/briar/messaging/PrivateMessageFactoryImpl.java @@ -16,8 +16,8 @@ import javax.annotation.Nullable; import javax.annotation.concurrent.Immutable; import javax.inject.Inject; -import static org.briarproject.bramble.api.autodelete.AutoDeleteConstants.NO_AUTO_DELETE_TIMER; import static org.briarproject.bramble.util.StringUtils.utf8IsTooLong; +import static org.briarproject.briar.api.autodelete.AutoDeleteConstants.NO_AUTO_DELETE_TIMER; import static org.briarproject.briar.api.messaging.MessagingConstants.MAX_PRIVATE_MESSAGE_TEXT_LENGTH; import static org.briarproject.briar.messaging.MessageTypes.PRIVATE_MESSAGE; diff --git a/briar-core/src/main/java/org/briarproject/briar/messaging/PrivateMessageValidator.java b/briar-core/src/main/java/org/briarproject/briar/messaging/PrivateMessageValidator.java index 14581eeb8..6cefd59c0 100644 --- a/briar-core/src/main/java/org/briarproject/briar/messaging/PrivateMessageValidator.java +++ b/briar-core/src/main/java/org/briarproject/briar/messaging/PrivateMessageValidator.java @@ -24,15 +24,14 @@ import java.io.InputStream; import javax.annotation.concurrent.Immutable; -import static org.briarproject.bramble.api.autodelete.AutoDeleteConstants.NO_AUTO_DELETE_TIMER; import static org.briarproject.bramble.api.sync.SyncConstants.MAX_MESSAGE_BODY_LENGTH; import static org.briarproject.bramble.api.transport.TransportConstants.MAX_CLOCK_DIFFERENCE; import static org.briarproject.bramble.util.ValidationUtils.checkLength; import static org.briarproject.bramble.util.ValidationUtils.checkSize; -import static org.briarproject.bramble.util.ValidationUtils.validateAutoDeleteTimer; import static org.briarproject.briar.api.attachment.MediaConstants.MAX_CONTENT_TYPE_BYTES; import static org.briarproject.briar.api.attachment.MediaConstants.MSG_KEY_CONTENT_TYPE; import static org.briarproject.briar.api.attachment.MediaConstants.MSG_KEY_DESCRIPTOR_LENGTH; +import static org.briarproject.briar.api.autodelete.AutoDeleteConstants.NO_AUTO_DELETE_TIMER; import static org.briarproject.briar.api.messaging.MessagingConstants.MAX_ATTACHMENTS_PER_MESSAGE; import static org.briarproject.briar.api.messaging.MessagingConstants.MAX_PRIVATE_MESSAGE_INCOMING_TEXT_LENGTH; import static org.briarproject.briar.client.MessageTrackerConstants.MSG_KEY_READ; @@ -44,6 +43,7 @@ import static org.briarproject.briar.messaging.MessagingConstants.MSG_KEY_HAS_TE import static org.briarproject.briar.messaging.MessagingConstants.MSG_KEY_LOCAL; import static org.briarproject.briar.messaging.MessagingConstants.MSG_KEY_MSG_TYPE; import static org.briarproject.briar.messaging.MessagingConstants.MSG_KEY_TIMESTAMP; +import static org.briarproject.briar.util.ValidationUtils.validateAutoDeleteTimer; @Immutable @NotNullByDefault 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 af62d3661..8d453c06d 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 @@ -30,7 +30,7 @@ import java.util.Map; import javax.annotation.Nullable; import javax.annotation.concurrent.Immutable; -import static org.briarproject.bramble.api.autodelete.AutoDeleteConstants.NO_AUTO_DELETE_TIMER; +import static org.briarproject.briar.api.autodelete.AutoDeleteConstants.NO_AUTO_DELETE_TIMER; import static org.briarproject.briar.privategroup.invitation.MessageType.ABORT; import static org.briarproject.briar.privategroup.invitation.MessageType.INVITE; import static org.briarproject.briar.privategroup.invitation.MessageType.JOIN; diff --git a/briar-core/src/main/java/org/briarproject/briar/privategroup/invitation/GroupInvitationValidator.java b/briar-core/src/main/java/org/briarproject/briar/privategroup/invitation/GroupInvitationValidator.java index 7e3a6fb76..9b9661ea9 100644 --- a/briar-core/src/main/java/org/briarproject/briar/privategroup/invitation/GroupInvitationValidator.java +++ b/briar-core/src/main/java/org/briarproject/briar/privategroup/invitation/GroupInvitationValidator.java @@ -23,11 +23,10 @@ import java.util.Collections; import javax.annotation.concurrent.Immutable; -import static org.briarproject.bramble.api.autodelete.AutoDeleteConstants.NO_AUTO_DELETE_TIMER; import static org.briarproject.bramble.api.identity.AuthorConstants.MAX_SIGNATURE_LENGTH; import static org.briarproject.bramble.util.ValidationUtils.checkLength; import static org.briarproject.bramble.util.ValidationUtils.checkSize; -import static org.briarproject.bramble.util.ValidationUtils.validateAutoDeleteTimer; +import static org.briarproject.briar.api.autodelete.AutoDeleteConstants.NO_AUTO_DELETE_TIMER; import static org.briarproject.briar.api.privategroup.PrivateGroupConstants.GROUP_SALT_LENGTH; import static org.briarproject.briar.api.privategroup.PrivateGroupConstants.MAX_GROUP_INVITATION_TEXT_LENGTH; import static org.briarproject.briar.api.privategroup.PrivateGroupConstants.MAX_GROUP_NAME_LENGTH; @@ -36,6 +35,7 @@ import static org.briarproject.briar.privategroup.invitation.MessageType.ABORT; import static org.briarproject.briar.privategroup.invitation.MessageType.INVITE; import static org.briarproject.briar.privategroup.invitation.MessageType.JOIN; import static org.briarproject.briar.privategroup.invitation.MessageType.LEAVE; +import static org.briarproject.briar.util.ValidationUtils.validateAutoDeleteTimer; @Immutable @NotNullByDefault diff --git a/briar-core/src/main/java/org/briarproject/briar/privategroup/invitation/MessageEncoderImpl.java b/briar-core/src/main/java/org/briarproject/briar/privategroup/invitation/MessageEncoderImpl.java index b326a61b4..8027ebf07 100644 --- a/briar-core/src/main/java/org/briarproject/briar/privategroup/invitation/MessageEncoderImpl.java +++ b/briar-core/src/main/java/org/briarproject/briar/privategroup/invitation/MessageEncoderImpl.java @@ -15,7 +15,7 @@ import javax.annotation.Nullable; import javax.annotation.concurrent.Immutable; import javax.inject.Inject; -import static org.briarproject.bramble.api.autodelete.AutoDeleteConstants.NO_AUTO_DELETE_TIMER; +import static org.briarproject.briar.api.autodelete.AutoDeleteConstants.NO_AUTO_DELETE_TIMER; import static org.briarproject.briar.client.MessageTrackerConstants.MSG_KEY_READ; import static org.briarproject.briar.privategroup.invitation.GroupInvitationConstants.MSG_KEY_AUTO_DELETE_TIMER; import static org.briarproject.briar.privategroup.invitation.GroupInvitationConstants.MSG_KEY_AVAILABLE_TO_ANSWER; diff --git a/briar-core/src/main/java/org/briarproject/briar/privategroup/invitation/MessageParserImpl.java b/briar-core/src/main/java/org/briarproject/briar/privategroup/invitation/MessageParserImpl.java index 4249b7952..0fdc19c8b 100644 --- a/briar-core/src/main/java/org/briarproject/briar/privategroup/invitation/MessageParserImpl.java +++ b/briar-core/src/main/java/org/briarproject/briar/privategroup/invitation/MessageParserImpl.java @@ -18,7 +18,7 @@ import org.briarproject.briar.api.privategroup.PrivateGroupFactory; import javax.annotation.concurrent.Immutable; import javax.inject.Inject; -import static org.briarproject.bramble.api.autodelete.AutoDeleteConstants.NO_AUTO_DELETE_TIMER; +import static org.briarproject.briar.api.autodelete.AutoDeleteConstants.NO_AUTO_DELETE_TIMER; import static org.briarproject.briar.client.MessageTrackerConstants.MSG_KEY_READ; import static org.briarproject.briar.privategroup.invitation.GroupInvitationConstants.MSG_KEY_AUTO_DELETE_TIMER; import static org.briarproject.briar.privategroup.invitation.GroupInvitationConstants.MSG_KEY_AVAILABLE_TO_ANSWER; diff --git a/briar-core/src/main/java/org/briarproject/briar/sharing/MessageEncoderImpl.java b/briar-core/src/main/java/org/briarproject/briar/sharing/MessageEncoderImpl.java index 42d5985d8..90d694d58 100644 --- a/briar-core/src/main/java/org/briarproject/briar/sharing/MessageEncoderImpl.java +++ b/briar-core/src/main/java/org/briarproject/briar/sharing/MessageEncoderImpl.java @@ -14,7 +14,7 @@ import javax.annotation.Nullable; import javax.annotation.concurrent.Immutable; import javax.inject.Inject; -import static org.briarproject.bramble.api.autodelete.AutoDeleteConstants.NO_AUTO_DELETE_TIMER; +import static org.briarproject.briar.api.autodelete.AutoDeleteConstants.NO_AUTO_DELETE_TIMER; import static org.briarproject.briar.sharing.MessageType.ABORT; import static org.briarproject.briar.sharing.MessageType.ACCEPT; import static org.briarproject.briar.sharing.MessageType.DECLINE; diff --git a/briar-core/src/main/java/org/briarproject/briar/sharing/MessageParserImpl.java b/briar-core/src/main/java/org/briarproject/briar/sharing/MessageParserImpl.java index 2cadda417..11e76cf6c 100644 --- a/briar-core/src/main/java/org/briarproject/briar/sharing/MessageParserImpl.java +++ b/briar-core/src/main/java/org/briarproject/briar/sharing/MessageParserImpl.java @@ -15,7 +15,7 @@ import org.briarproject.briar.api.sharing.Shareable; import javax.annotation.concurrent.Immutable; -import static org.briarproject.bramble.api.autodelete.AutoDeleteConstants.NO_AUTO_DELETE_TIMER; +import static org.briarproject.briar.api.autodelete.AutoDeleteConstants.NO_AUTO_DELETE_TIMER; import static org.briarproject.briar.sharing.MessageType.INVITE; import static org.briarproject.briar.sharing.SharingConstants.MSG_KEY_AUTO_DELETE_TIMER; import static org.briarproject.briar.sharing.SharingConstants.MSG_KEY_AVAILABLE_TO_ANSWER; 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 612e9f3aa..cd6f8e221 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 @@ -28,10 +28,10 @@ import java.util.Map; import javax.annotation.Nullable; import javax.annotation.concurrent.Immutable; -import static org.briarproject.bramble.api.autodelete.AutoDeleteConstants.NO_AUTO_DELETE_TIMER; import static org.briarproject.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; +import static org.briarproject.briar.api.autodelete.AutoDeleteConstants.NO_AUTO_DELETE_TIMER; import static org.briarproject.briar.sharing.MessageType.ABORT; import static org.briarproject.briar.sharing.MessageType.ACCEPT; import static org.briarproject.briar.sharing.MessageType.DECLINE; diff --git a/briar-core/src/main/java/org/briarproject/briar/sharing/SharingValidator.java b/briar-core/src/main/java/org/briarproject/briar/sharing/SharingValidator.java index 76dc51118..73e34be0c 100644 --- a/briar-core/src/main/java/org/briarproject/briar/sharing/SharingValidator.java +++ b/briar-core/src/main/java/org/briarproject/briar/sharing/SharingValidator.java @@ -18,12 +18,12 @@ import org.briarproject.bramble.api.system.Clock; import javax.annotation.concurrent.Immutable; import static java.util.Collections.singletonList; -import static org.briarproject.bramble.api.autodelete.AutoDeleteConstants.NO_AUTO_DELETE_TIMER; import static org.briarproject.bramble.util.ValidationUtils.checkLength; import static org.briarproject.bramble.util.ValidationUtils.checkSize; -import static org.briarproject.bramble.util.ValidationUtils.validateAutoDeleteTimer; +import static org.briarproject.briar.api.autodelete.AutoDeleteConstants.NO_AUTO_DELETE_TIMER; import static org.briarproject.briar.api.sharing.SharingConstants.MAX_INVITATION_TEXT_LENGTH; import static org.briarproject.briar.sharing.MessageType.INVITE; +import static org.briarproject.briar.util.ValidationUtils.validateAutoDeleteTimer; @Immutable @NotNullByDefault diff --git a/briar-core/src/main/java/org/briarproject/briar/test/TestDataCreatorImpl.java b/briar-core/src/main/java/org/briarproject/briar/test/TestDataCreatorImpl.java index b207a7c9e..fa401edb4 100644 --- a/briar-core/src/main/java/org/briarproject/briar/test/TestDataCreatorImpl.java +++ b/briar-core/src/main/java/org/briarproject/briar/test/TestDataCreatorImpl.java @@ -58,12 +58,12 @@ import static java.util.Collections.emptyList; import static java.util.logging.Level.INFO; import static java.util.logging.Level.WARNING; import static java.util.logging.Logger.getLogger; -import static org.briarproject.bramble.api.autodelete.AutoDeleteConstants.MIN_AUTO_DELETE_TIMER_MS; -import static org.briarproject.bramble.api.autodelete.AutoDeleteConstants.NO_AUTO_DELETE_TIMER; import static org.briarproject.bramble.api.plugin.BluetoothConstants.UUID_BYTES; import static org.briarproject.bramble.api.sync.Group.Visibility.SHARED; import static org.briarproject.bramble.util.LogUtils.logException; import static org.briarproject.bramble.util.StringUtils.getRandomString; +import static org.briarproject.briar.api.autodelete.AutoDeleteConstants.MIN_AUTO_DELETE_TIMER_MS; +import static org.briarproject.briar.api.autodelete.AutoDeleteConstants.NO_AUTO_DELETE_TIMER; import static org.briarproject.briar.test.TestData.AUTHOR_NAMES; import static org.briarproject.briar.test.TestData.GROUP_NAMES; diff --git a/briar-core/src/main/java/org/briarproject/briar/util/ValidationUtils.java b/briar-core/src/main/java/org/briarproject/briar/util/ValidationUtils.java new file mode 100644 index 000000000..58b8ddf6c --- /dev/null +++ b/briar-core/src/main/java/org/briarproject/briar/util/ValidationUtils.java @@ -0,0 +1,24 @@ +package org.briarproject.briar.util; + +import org.briarproject.bramble.api.FormatException; +import org.briarproject.bramble.api.nullsafety.NotNullByDefault; + +import javax.annotation.Nullable; +import javax.annotation.concurrent.Immutable; + +import static org.briarproject.bramble.util.ValidationUtils.checkRange; +import static org.briarproject.briar.api.autodelete.AutoDeleteConstants.MAX_AUTO_DELETE_TIMER_MS; +import static org.briarproject.briar.api.autodelete.AutoDeleteConstants.MIN_AUTO_DELETE_TIMER_MS; +import static org.briarproject.briar.api.autodelete.AutoDeleteConstants.NO_AUTO_DELETE_TIMER; + +@Immutable +@NotNullByDefault +public class ValidationUtils { + + public static long validateAutoDeleteTimer(@Nullable Long timer) + throws FormatException { + if (timer == null) return NO_AUTO_DELETE_TIMER; + checkRange(timer, MIN_AUTO_DELETE_TIMER_MS, MAX_AUTO_DELETE_TIMER_MS); + return timer; + } +} 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 e13aa0aee..feb1e65ee 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 @@ -45,12 +45,12 @@ import java.util.Map; import java.util.Set; import static java.util.Collections.emptySet; -import static org.briarproject.bramble.api.autodelete.AutoDeleteConstants.NO_AUTO_DELETE_TIMER; import static org.briarproject.bramble.test.TestPluginConfigModule.SIMPLEX_TRANSPORT_ID; import static org.briarproject.bramble.test.TestUtils.getAgreementPublicKey; import static org.briarproject.bramble.test.TestUtils.getSecretKey; import static org.briarproject.bramble.test.TestUtils.getTransportProperties; import static org.briarproject.bramble.test.TestUtils.getTransportPropertiesMap; +import static org.briarproject.briar.api.autodelete.AutoDeleteConstants.NO_AUTO_DELETE_TIMER; import static org.briarproject.briar.api.introduction.IntroductionManager.CLIENT_ID; import static org.briarproject.briar.api.introduction.IntroductionManager.MAJOR_VERSION; import static org.briarproject.briar.introduction.IntroduceeState.AWAIT_RESPONSES; diff --git a/briar-core/src/test/java/org/briarproject/briar/introduction/IntroductionValidatorTest.java b/briar-core/src/test/java/org/briarproject/briar/introduction/IntroductionValidatorTest.java index 7cd82468a..d73c1f5d6 100644 --- a/briar-core/src/test/java/org/briarproject/briar/introduction/IntroductionValidatorTest.java +++ b/briar-core/src/test/java/org/briarproject/briar/introduction/IntroductionValidatorTest.java @@ -19,9 +19,6 @@ import java.util.Map; import javax.annotation.Nullable; import static java.util.Collections.singletonMap; -import static org.briarproject.bramble.api.autodelete.AutoDeleteConstants.MAX_AUTO_DELETE_TIMER_MS; -import static org.briarproject.bramble.api.autodelete.AutoDeleteConstants.MIN_AUTO_DELETE_TIMER_MS; -import static org.briarproject.bramble.api.autodelete.AutoDeleteConstants.NO_AUTO_DELETE_TIMER; import static org.briarproject.bramble.api.crypto.CryptoConstants.MAC_BYTES; import static org.briarproject.bramble.api.crypto.CryptoConstants.MAX_AGREEMENT_PUBLIC_KEY_BYTES; import static org.briarproject.bramble.api.crypto.CryptoConstants.MAX_SIGNATURE_BYTES; @@ -30,6 +27,9 @@ import static org.briarproject.bramble.test.TestUtils.getRandomBytes; import static org.briarproject.bramble.test.TestUtils.getRandomId; import static org.briarproject.bramble.test.TestUtils.getTransportId; import static org.briarproject.bramble.util.StringUtils.getRandomString; +import static org.briarproject.briar.api.autodelete.AutoDeleteConstants.MAX_AUTO_DELETE_TIMER_MS; +import static org.briarproject.briar.api.autodelete.AutoDeleteConstants.MIN_AUTO_DELETE_TIMER_MS; +import static org.briarproject.briar.api.autodelete.AutoDeleteConstants.NO_AUTO_DELETE_TIMER; import static org.briarproject.briar.api.introduction.IntroductionConstants.MAX_INTRODUCTION_TEXT_LENGTH; import static org.briarproject.briar.introduction.MessageType.ABORT; import static org.briarproject.briar.introduction.MessageType.ACCEPT; diff --git a/briar-core/src/test/java/org/briarproject/briar/introduction/MessageEncoderParserIntegrationTest.java b/briar-core/src/test/java/org/briarproject/briar/introduction/MessageEncoderParserIntegrationTest.java index 808ca3454..15a872292 100644 --- a/briar-core/src/test/java/org/briarproject/briar/introduction/MessageEncoderParserIntegrationTest.java +++ b/briar-core/src/test/java/org/briarproject/briar/introduction/MessageEncoderParserIntegrationTest.java @@ -23,9 +23,6 @@ import java.util.Map; import javax.inject.Inject; -import static org.briarproject.bramble.api.autodelete.AutoDeleteConstants.MAX_AUTO_DELETE_TIMER_MS; -import static org.briarproject.bramble.api.autodelete.AutoDeleteConstants.MIN_AUTO_DELETE_TIMER_MS; -import static org.briarproject.bramble.api.autodelete.AutoDeleteConstants.NO_AUTO_DELETE_TIMER; import static org.briarproject.bramble.api.crypto.CryptoConstants.MAC_BYTES; import static org.briarproject.bramble.api.crypto.CryptoConstants.MAX_SIGNATURE_BYTES; import static org.briarproject.bramble.test.TestUtils.getAgreementPublicKey; @@ -34,6 +31,9 @@ import static org.briarproject.bramble.test.TestUtils.getRandomBytes; import static org.briarproject.bramble.test.TestUtils.getRandomId; import static org.briarproject.bramble.test.TestUtils.getTransportPropertiesMap; import static org.briarproject.bramble.util.StringUtils.getRandomString; +import static org.briarproject.briar.api.autodelete.AutoDeleteConstants.MAX_AUTO_DELETE_TIMER_MS; +import static org.briarproject.briar.api.autodelete.AutoDeleteConstants.MIN_AUTO_DELETE_TIMER_MS; +import static org.briarproject.briar.api.autodelete.AutoDeleteConstants.NO_AUTO_DELETE_TIMER; import static org.briarproject.briar.api.introduction.IntroductionConstants.MAX_INTRODUCTION_TEXT_LENGTH; import static org.briarproject.briar.api.introduction.IntroductionManager.CLIENT_ID; import static org.briarproject.briar.api.introduction.IntroductionManager.MAJOR_VERSION; diff --git a/briar-core/src/test/java/org/briarproject/briar/messaging/MessageSizeIntegrationTest.java b/briar-core/src/test/java/org/briarproject/briar/messaging/MessageSizeIntegrationTest.java index 72bbf2c52..979d8b23b 100644 --- a/briar-core/src/test/java/org/briarproject/briar/messaging/MessageSizeIntegrationTest.java +++ b/briar-core/src/test/java/org/briarproject/briar/messaging/MessageSizeIntegrationTest.java @@ -25,7 +25,6 @@ import java.util.List; import javax.inject.Inject; -import static org.briarproject.bramble.api.autodelete.AutoDeleteConstants.MAX_AUTO_DELETE_TIMER_MS; import static org.briarproject.bramble.api.identity.AuthorConstants.MAX_AUTHOR_NAME_LENGTH; import static org.briarproject.bramble.api.identity.AuthorConstants.MAX_PUBLIC_KEY_LENGTH; import static org.briarproject.bramble.api.record.Record.MAX_RECORD_PAYLOAD_BYTES; @@ -35,6 +34,7 @@ import static org.briarproject.bramble.util.IoUtils.copyAndClose; import static org.briarproject.bramble.util.StringUtils.getRandomString; import static org.briarproject.briar.api.attachment.MediaConstants.MAX_CONTENT_TYPE_BYTES; import static org.briarproject.briar.api.attachment.MediaConstants.MAX_IMAGE_SIZE; +import static org.briarproject.briar.api.autodelete.AutoDeleteConstants.MAX_AUTO_DELETE_TIMER_MS; import static org.briarproject.briar.api.forum.ForumConstants.MAX_FORUM_POST_TEXT_LENGTH; import static org.briarproject.briar.api.messaging.MessagingConstants.MAX_ATTACHMENTS_PER_MESSAGE; import static org.briarproject.briar.api.messaging.MessagingConstants.MAX_PRIVATE_MESSAGE_TEXT_LENGTH; diff --git a/briar-core/src/test/java/org/briarproject/briar/messaging/MessagingManagerIntegrationTest.java b/briar-core/src/test/java/org/briarproject/briar/messaging/MessagingManagerIntegrationTest.java index c0100cdef..ccf1bf72a 100644 --- a/briar-core/src/test/java/org/briarproject/briar/messaging/MessagingManagerIntegrationTest.java +++ b/briar-core/src/test/java/org/briarproject/briar/messaging/MessagingManagerIntegrationTest.java @@ -32,12 +32,12 @@ import static java.util.Collections.emptyList; import static java.util.Collections.emptySet; import static java.util.Collections.singleton; import static java.util.Collections.singletonList; -import static org.briarproject.bramble.api.autodelete.AutoDeleteConstants.MIN_AUTO_DELETE_TIMER_MS; -import static org.briarproject.bramble.api.autodelete.AutoDeleteConstants.NO_AUTO_DELETE_TIMER; import static org.briarproject.bramble.api.sync.validation.MessageState.DELIVERED; import static org.briarproject.bramble.api.sync.validation.MessageState.PENDING; import static org.briarproject.bramble.test.TestUtils.getRandomBytes; import static org.briarproject.bramble.util.StringUtils.getRandomString; +import static org.briarproject.briar.api.autodelete.AutoDeleteConstants.MIN_AUTO_DELETE_TIMER_MS; +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; diff --git a/briar-core/src/test/java/org/briarproject/briar/messaging/PrivateMessageValidatorTest.java b/briar-core/src/test/java/org/briarproject/briar/messaging/PrivateMessageValidatorTest.java index 114c58eeb..7463553b8 100644 --- a/briar-core/src/test/java/org/briarproject/briar/messaging/PrivateMessageValidatorTest.java +++ b/briar-core/src/test/java/org/briarproject/briar/messaging/PrivateMessageValidatorTest.java @@ -20,8 +20,6 @@ import org.junit.Test; import java.io.InputStream; -import static org.briarproject.bramble.api.autodelete.AutoDeleteConstants.MAX_AUTO_DELETE_TIMER_MS; -import static org.briarproject.bramble.api.autodelete.AutoDeleteConstants.MIN_AUTO_DELETE_TIMER_MS; import static org.briarproject.bramble.api.transport.TransportConstants.MAX_CLOCK_DIFFERENCE; import static org.briarproject.bramble.test.TestUtils.getClientId; import static org.briarproject.bramble.test.TestUtils.getGroup; @@ -32,6 +30,8 @@ import static org.briarproject.bramble.util.StringUtils.getRandomString; import static org.briarproject.briar.api.attachment.MediaConstants.MAX_CONTENT_TYPE_BYTES; import static org.briarproject.briar.api.attachment.MediaConstants.MSG_KEY_CONTENT_TYPE; import static org.briarproject.briar.api.attachment.MediaConstants.MSG_KEY_DESCRIPTOR_LENGTH; +import static org.briarproject.briar.api.autodelete.AutoDeleteConstants.MAX_AUTO_DELETE_TIMER_MS; +import static org.briarproject.briar.api.autodelete.AutoDeleteConstants.MIN_AUTO_DELETE_TIMER_MS; import static org.briarproject.briar.api.messaging.MessagingConstants.MAX_ATTACHMENTS_PER_MESSAGE; import static org.briarproject.briar.api.messaging.MessagingConstants.MAX_PRIVATE_MESSAGE_INCOMING_TEXT_LENGTH; import static org.briarproject.briar.client.MessageTrackerConstants.MSG_KEY_READ; diff --git a/briar-core/src/test/java/org/briarproject/briar/messaging/SimplexMessagingIntegrationTest.java b/briar-core/src/test/java/org/briarproject/briar/messaging/SimplexMessagingIntegrationTest.java index 5902b9ea2..faa27b3f3 100644 --- a/briar-core/src/test/java/org/briarproject/briar/messaging/SimplexMessagingIntegrationTest.java +++ b/briar-core/src/test/java/org/briarproject/briar/messaging/SimplexMessagingIntegrationTest.java @@ -34,12 +34,12 @@ import java.util.concurrent.CountDownLatch; import static java.util.Collections.singletonList; import static java.util.concurrent.TimeUnit.MILLISECONDS; -import static org.briarproject.bramble.api.autodelete.AutoDeleteConstants.NO_AUTO_DELETE_TIMER; import static org.briarproject.bramble.api.sync.validation.MessageState.DELIVERED; import static org.briarproject.bramble.test.TestPluginConfigModule.SIMPLEX_TRANSPORT_ID; import static org.briarproject.bramble.test.TestUtils.deleteTestDirectory; import static org.briarproject.bramble.test.TestUtils.getSecretKey; import static org.briarproject.bramble.test.TestUtils.getTestDirectory; +import static org.briarproject.briar.api.autodelete.AutoDeleteConstants.NO_AUTO_DELETE_TIMER; import static org.junit.Assert.assertTrue; public class SimplexMessagingIntegrationTest extends BriarTestCase { 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 f7cff5186..b7df73946 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 @@ -25,7 +25,6 @@ import org.briarproject.briar.api.privategroup.PrivateGroupManager; import org.briarproject.briar.api.privategroup.invitation.GroupInvitationManager; import org.jmock.Expectations; -import static org.briarproject.bramble.api.autodelete.AutoDeleteConstants.NO_AUTO_DELETE_TIMER; import static org.briarproject.bramble.api.identity.AuthorConstants.MAX_SIGNATURE_LENGTH; import static org.briarproject.bramble.api.sync.Group.Visibility.SHARED; import static org.briarproject.bramble.test.TestUtils.getContact; @@ -34,6 +33,7 @@ import static org.briarproject.bramble.test.TestUtils.getMessage; import static org.briarproject.bramble.test.TestUtils.getRandomBytes; import static org.briarproject.bramble.test.TestUtils.getRandomId; import static org.briarproject.bramble.util.StringUtils.getRandomString; +import static org.briarproject.briar.api.autodelete.AutoDeleteConstants.NO_AUTO_DELETE_TIMER; import static org.briarproject.briar.api.privategroup.PrivateGroupConstants.GROUP_SALT_LENGTH; import static org.briarproject.briar.api.privategroup.PrivateGroupConstants.MAX_GROUP_INVITATION_TEXT_LENGTH; import static org.briarproject.briar.api.privategroup.PrivateGroupConstants.MAX_GROUP_NAME_LENGTH; 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 559a6de93..f74054ddb 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 @@ -5,10 +5,10 @@ import org.briarproject.briar.api.client.ProtocolStateException; import org.jmock.Expectations; import org.junit.Test; -import static org.briarproject.bramble.api.autodelete.AutoDeleteConstants.NO_AUTO_DELETE_TIMER; import static org.briarproject.bramble.api.sync.Group.Visibility.INVISIBLE; import static org.briarproject.bramble.api.sync.Group.Visibility.SHARED; import static org.briarproject.bramble.test.TestUtils.getRandomId; +import static org.briarproject.briar.api.autodelete.AutoDeleteConstants.NO_AUTO_DELETE_TIMER; import static org.briarproject.briar.privategroup.invitation.CreatorState.DISSOLVED; import static org.briarproject.briar.privategroup.invitation.CreatorState.ERROR; import static org.briarproject.briar.privategroup.invitation.CreatorState.INVITED; 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 d533cacf9..85df40b38 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 @@ -45,7 +45,6 @@ import javax.annotation.Nullable; import static java.util.Arrays.asList; import static junit.framework.TestCase.fail; -import static org.briarproject.bramble.api.autodelete.AutoDeleteConstants.NO_AUTO_DELETE_TIMER; import static org.briarproject.bramble.api.sync.Group.Visibility.SHARED; import static org.briarproject.bramble.test.TestUtils.getAuthor; import static org.briarproject.bramble.test.TestUtils.getContact; @@ -54,6 +53,7 @@ import static org.briarproject.bramble.test.TestUtils.getMessage; import static org.briarproject.bramble.test.TestUtils.getRandomBytes; import static org.briarproject.bramble.test.TestUtils.getRandomId; import static org.briarproject.bramble.util.StringUtils.getRandomString; +import static org.briarproject.briar.api.autodelete.AutoDeleteConstants.NO_AUTO_DELETE_TIMER; import static org.briarproject.briar.api.privategroup.PrivateGroupConstants.GROUP_SALT_LENGTH; import static org.briarproject.briar.api.privategroup.PrivateGroupConstants.MAX_GROUP_NAME_LENGTH; import static org.briarproject.briar.api.privategroup.invitation.GroupInvitationManager.CLIENT_ID; diff --git a/briar-core/src/test/java/org/briarproject/briar/privategroup/invitation/GroupInvitationValidatorTest.java b/briar-core/src/test/java/org/briarproject/briar/privategroup/invitation/GroupInvitationValidatorTest.java index fe9ced797..fd5ccbe1d 100644 --- a/briar-core/src/test/java/org/briarproject/briar/privategroup/invitation/GroupInvitationValidatorTest.java +++ b/briar-core/src/test/java/org/briarproject/briar/privategroup/invitation/GroupInvitationValidatorTest.java @@ -18,14 +18,14 @@ import java.security.GeneralSecurityException; import static java.util.Collections.emptyList; import static java.util.Collections.singletonList; -import static org.briarproject.bramble.api.autodelete.AutoDeleteConstants.MAX_AUTO_DELETE_TIMER_MS; -import static org.briarproject.bramble.api.autodelete.AutoDeleteConstants.MIN_AUTO_DELETE_TIMER_MS; -import static org.briarproject.bramble.api.autodelete.AutoDeleteConstants.NO_AUTO_DELETE_TIMER; import static org.briarproject.bramble.api.identity.AuthorConstants.MAX_SIGNATURE_LENGTH; import static org.briarproject.bramble.test.TestUtils.getAuthor; import static org.briarproject.bramble.test.TestUtils.getRandomBytes; import static org.briarproject.bramble.test.TestUtils.getRandomId; import static org.briarproject.bramble.util.StringUtils.getRandomString; +import static org.briarproject.briar.api.autodelete.AutoDeleteConstants.MAX_AUTO_DELETE_TIMER_MS; +import static org.briarproject.briar.api.autodelete.AutoDeleteConstants.MIN_AUTO_DELETE_TIMER_MS; +import static org.briarproject.briar.api.autodelete.AutoDeleteConstants.NO_AUTO_DELETE_TIMER; import static org.briarproject.briar.api.privategroup.PrivateGroupConstants.GROUP_SALT_LENGTH; import static org.briarproject.briar.api.privategroup.PrivateGroupConstants.MAX_GROUP_INVITATION_TEXT_LENGTH; import static org.briarproject.briar.api.privategroup.PrivateGroupConstants.MAX_GROUP_NAME_LENGTH; 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 fee724bb8..d32277223 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 @@ -13,7 +13,6 @@ import org.junit.Test; import java.util.Collections; import java.util.Map; -import static org.briarproject.bramble.api.autodelete.AutoDeleteConstants.NO_AUTO_DELETE_TIMER; import static org.briarproject.bramble.api.sync.Group.Visibility.INVISIBLE; import static org.briarproject.bramble.api.sync.Group.Visibility.SHARED; import static org.briarproject.bramble.api.sync.Group.Visibility.VISIBLE; @@ -22,6 +21,7 @@ import static org.briarproject.bramble.test.TestUtils.getContact; import static org.briarproject.bramble.test.TestUtils.getLocalAuthor; import static org.briarproject.bramble.test.TestUtils.getRandomId; import static org.briarproject.bramble.util.StringUtils.getRandomString; +import static org.briarproject.briar.api.autodelete.AutoDeleteConstants.NO_AUTO_DELETE_TIMER; import static org.briarproject.briar.api.privategroup.PrivateGroupConstants.MAX_GROUP_INVITATION_TEXT_LENGTH; import static org.briarproject.briar.privategroup.invitation.InviteeState.ACCEPTED; import static org.briarproject.briar.privategroup.invitation.InviteeState.DISSOLVED; 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 2be8c0a94..0c64a4965 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 @@ -5,11 +5,11 @@ import org.briarproject.briar.api.client.ProtocolStateException; import org.jmock.Expectations; import org.junit.Test; -import static org.briarproject.bramble.api.autodelete.AutoDeleteConstants.NO_AUTO_DELETE_TIMER; import static org.briarproject.bramble.api.sync.Group.Visibility.INVISIBLE; import static org.briarproject.bramble.api.sync.Group.Visibility.SHARED; import static org.briarproject.bramble.api.sync.Group.Visibility.VISIBLE; import static org.briarproject.bramble.test.TestUtils.getRandomId; +import static org.briarproject.briar.api.autodelete.AutoDeleteConstants.NO_AUTO_DELETE_TIMER; import static org.briarproject.briar.privategroup.invitation.PeerState.AWAIT_MEMBER; import static org.briarproject.briar.privategroup.invitation.PeerState.BOTH_JOINED; import static org.briarproject.briar.privategroup.invitation.PeerState.ERROR; diff --git a/briar-core/src/test/java/org/briarproject/briar/sharing/BlogSharingValidatorTest.java b/briar-core/src/test/java/org/briarproject/briar/sharing/BlogSharingValidatorTest.java index 8ce003360..6b9f21183 100644 --- a/briar-core/src/test/java/org/briarproject/briar/sharing/BlogSharingValidatorTest.java +++ b/briar-core/src/test/java/org/briarproject/briar/sharing/BlogSharingValidatorTest.java @@ -10,11 +10,11 @@ import org.junit.Test; import javax.annotation.Nullable; -import static org.briarproject.bramble.api.autodelete.AutoDeleteConstants.MAX_AUTO_DELETE_TIMER_MS; -import static org.briarproject.bramble.api.autodelete.AutoDeleteConstants.MIN_AUTO_DELETE_TIMER_MS; -import static org.briarproject.bramble.api.autodelete.AutoDeleteConstants.NO_AUTO_DELETE_TIMER; import static org.briarproject.bramble.test.TestUtils.getAuthor; import static org.briarproject.bramble.util.StringUtils.getRandomString; +import static org.briarproject.briar.api.autodelete.AutoDeleteConstants.MAX_AUTO_DELETE_TIMER_MS; +import static org.briarproject.briar.api.autodelete.AutoDeleteConstants.MIN_AUTO_DELETE_TIMER_MS; +import static org.briarproject.briar.api.autodelete.AutoDeleteConstants.NO_AUTO_DELETE_TIMER; import static org.briarproject.briar.api.sharing.SharingConstants.MAX_INVITATION_TEXT_LENGTH; import static org.briarproject.briar.sharing.MessageType.INVITE; import static org.junit.Assert.fail; diff --git a/briar-core/src/test/java/org/briarproject/briar/sharing/ForumSharingValidatorTest.java b/briar-core/src/test/java/org/briarproject/briar/sharing/ForumSharingValidatorTest.java index c42a3b7f3..7844f190b 100644 --- a/briar-core/src/test/java/org/briarproject/briar/sharing/ForumSharingValidatorTest.java +++ b/briar-core/src/test/java/org/briarproject/briar/sharing/ForumSharingValidatorTest.java @@ -9,11 +9,11 @@ import org.junit.Test; import javax.annotation.Nullable; -import static org.briarproject.bramble.api.autodelete.AutoDeleteConstants.MAX_AUTO_DELETE_TIMER_MS; -import static org.briarproject.bramble.api.autodelete.AutoDeleteConstants.MIN_AUTO_DELETE_TIMER_MS; -import static org.briarproject.bramble.api.autodelete.AutoDeleteConstants.NO_AUTO_DELETE_TIMER; import static org.briarproject.bramble.test.TestUtils.getRandomBytes; import static org.briarproject.bramble.util.StringUtils.getRandomString; +import static org.briarproject.briar.api.autodelete.AutoDeleteConstants.MAX_AUTO_DELETE_TIMER_MS; +import static org.briarproject.briar.api.autodelete.AutoDeleteConstants.MIN_AUTO_DELETE_TIMER_MS; +import static org.briarproject.briar.api.autodelete.AutoDeleteConstants.NO_AUTO_DELETE_TIMER; import static org.briarproject.briar.api.forum.ForumConstants.FORUM_SALT_LENGTH; import static org.briarproject.briar.api.forum.ForumConstants.MAX_FORUM_NAME_LENGTH; import static org.briarproject.briar.api.sharing.SharingConstants.MAX_INVITATION_TEXT_LENGTH; diff --git a/briar-core/src/test/java/org/briarproject/briar/sharing/SharingValidatorTest.java b/briar-core/src/test/java/org/briarproject/briar/sharing/SharingValidatorTest.java index c5c6349e0..11eb4a603 100644 --- a/briar-core/src/test/java/org/briarproject/briar/sharing/SharingValidatorTest.java +++ b/briar-core/src/test/java/org/briarproject/briar/sharing/SharingValidatorTest.java @@ -18,11 +18,11 @@ import javax.annotation.Nullable; import static java.util.Collections.emptyList; import static java.util.Collections.singletonList; -import static org.briarproject.bramble.api.autodelete.AutoDeleteConstants.MAX_AUTO_DELETE_TIMER_MS; -import static org.briarproject.bramble.api.autodelete.AutoDeleteConstants.MIN_AUTO_DELETE_TIMER_MS; -import static org.briarproject.bramble.api.autodelete.AutoDeleteConstants.NO_AUTO_DELETE_TIMER; import static org.briarproject.bramble.test.TestUtils.getRandomBytes; import static org.briarproject.bramble.test.TestUtils.getRandomId; +import static org.briarproject.briar.api.autodelete.AutoDeleteConstants.MAX_AUTO_DELETE_TIMER_MS; +import static org.briarproject.briar.api.autodelete.AutoDeleteConstants.MIN_AUTO_DELETE_TIMER_MS; +import static org.briarproject.briar.api.autodelete.AutoDeleteConstants.NO_AUTO_DELETE_TIMER; import static org.briarproject.briar.sharing.MessageType.ABORT; import static org.briarproject.briar.sharing.MessageType.ACCEPT; import static org.briarproject.briar.sharing.MessageType.DECLINE; diff --git a/briar-headless/src/test/java/org/briarproject/briar/headless/event/WebSocketControllerTest.kt b/briar-headless/src/test/java/org/briarproject/briar/headless/event/WebSocketControllerTest.kt index 58d9e48d0..62163d8e0 100644 --- a/briar-headless/src/test/java/org/briarproject/briar/headless/event/WebSocketControllerTest.kt +++ b/briar-headless/src/test/java/org/briarproject/briar/headless/event/WebSocketControllerTest.kt @@ -6,9 +6,9 @@ import io.mockk.CapturingSlot import io.mockk.every import io.mockk.mockk import io.mockk.verify -import org.briarproject.bramble.api.autodelete.AutoDeleteConstants.NO_AUTO_DELETE_TIMER import org.briarproject.bramble.test.ImmediateExecutor import org.briarproject.bramble.test.TestUtils.getRandomId +import org.briarproject.briar.api.autodelete.AutoDeleteConstants.NO_AUTO_DELETE_TIMER import org.briarproject.briar.api.client.SessionId import org.briarproject.briar.api.identity.AuthorInfo import org.briarproject.briar.api.identity.AuthorInfo.Status.VERIFIED diff --git a/briar-headless/src/test/java/org/briarproject/briar/headless/messaging/MessagingControllerImplTest.kt b/briar-headless/src/test/java/org/briarproject/briar/headless/messaging/MessagingControllerImplTest.kt index 91441efdf..d3e2a1213 100644 --- a/briar-headless/src/test/java/org/briarproject/briar/headless/messaging/MessagingControllerImplTest.kt +++ b/briar-headless/src/test/java/org/briarproject/briar/headless/messaging/MessagingControllerImplTest.kt @@ -11,7 +11,6 @@ import io.mockk.just import io.mockk.mockk import io.mockk.mockkStatic import io.mockk.runs -import org.briarproject.bramble.api.autodelete.AutoDeleteConstants.NO_AUTO_DELETE_TIMER import org.briarproject.bramble.api.contact.ContactId import org.briarproject.bramble.api.db.NoSuchContactException import org.briarproject.briar.api.identity.AuthorInfo @@ -23,6 +22,7 @@ import org.briarproject.bramble.api.sync.event.MessagesSentEvent import org.briarproject.bramble.test.ImmediateExecutor import org.briarproject.bramble.test.TestUtils.getRandomId import org.briarproject.bramble.util.StringUtils.getRandomString +import org.briarproject.briar.api.autodelete.AutoDeleteConstants.NO_AUTO_DELETE_TIMER import org.briarproject.briar.api.client.SessionId import org.briarproject.briar.api.conversation.DeletionResult import org.briarproject.briar.api.introduction.IntroductionRequest From 96debcd61667b8701ca7c90efb0ca32f10e84394 Mon Sep 17 00:00:00 2001 From: akwizgran Date: Thu, 26 Nov 2020 12:16:34 +0000 Subject: [PATCH 016/124] Add dummy implementation of AutoDeleteManager. --- .../conversation/ConversationViewModel.java | 62 +++++++++++-------- .../api/autodelete/AutoDeleteManager.java | 14 +++++ .../briar/api/messaging/MessagingManager.java | 5 ++ .../briarproject/briar/BriarCoreModule.java | 4 +- .../autodelete/AutoDeleteManagerImpl.java | 33 ++++++++++ .../briar/autodelete/AutoDeleteModule.java | 16 +++++ .../introduction/AbstractProtocolEngine.java | 38 +++++++----- .../IntroduceeProtocolEngine.java | 7 ++- .../IntroducerProtocolEngine.java | 5 +- .../briar/messaging/MessagingManagerImpl.java | 10 +-- .../invitation/AbstractProtocolEngine.java | 59 +++++++++++------- .../invitation/CreatorProtocolEngine.java | 15 +++-- .../invitation/InviteeProtocolEngine.java | 14 +++-- .../invitation/PeerProtocolEngine.java | 15 +++-- .../invitation/ProtocolEngineFactoryImpl.java | 23 +++++-- .../briar/sharing/BlogProtocolEngineImpl.java | 15 +++-- .../sharing/ForumProtocolEngineImpl.java | 13 ++-- .../briar/sharing/ProtocolEngineImpl.java | 55 +++++++++------- .../IntroductionIntegrationTestComponent.java | 4 +- .../AbstractProtocolEngineTest.java | 16 +++-- .../invitation/CreatorProtocolEngineTest.java | 2 +- .../invitation/InviteeProtocolEngineTest.java | 2 +- .../invitation/PeerProtocolEngineTest.java | 2 +- .../test/BriarIntegrationTestComponent.java | 4 +- 24 files changed, 306 insertions(+), 127 deletions(-) create mode 100644 briar-api/src/main/java/org/briarproject/briar/api/autodelete/AutoDeleteManager.java create mode 100644 briar-core/src/main/java/org/briarproject/briar/autodelete/AutoDeleteManagerImpl.java create mode 100644 briar-core/src/main/java/org/briarproject/briar/autodelete/AutoDeleteModule.java 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 0bf21d2d5..0e2c4a60a 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 @@ -10,6 +10,7 @@ import org.briarproject.bramble.api.contact.ContactManager; 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.event.Event; import org.briarproject.bramble.api.event.EventBus; @@ -32,6 +33,7 @@ import org.briarproject.briar.android.viewmodel.DbViewModel; import org.briarproject.briar.android.viewmodel.LiveEvent; import org.briarproject.briar.android.viewmodel.MutableLiveEvent; import org.briarproject.briar.api.attachment.AttachmentHeader; +import org.briarproject.briar.api.autodelete.AutoDeleteManager; import org.briarproject.briar.api.avatar.event.AvatarUpdatedEvent; import org.briarproject.briar.api.identity.AuthorInfo; import org.briarproject.briar.api.identity.AuthorManager; @@ -63,7 +65,6 @@ import static org.briarproject.bramble.util.LogUtils.logException; import static org.briarproject.bramble.util.LogUtils.now; import static org.briarproject.briar.android.settings.SettingsFragment.SETTINGS_NAMESPACE; import static org.briarproject.briar.android.util.UiUtils.observeForeverOnce; -import static org.briarproject.briar.api.autodelete.AutoDeleteConstants.NO_AUTO_DELETE_TIMER; import static org.briarproject.briar.api.messaging.PrivateMessageFormat.TEXT_IMAGES; import static org.briarproject.briar.api.messaging.PrivateMessageFormat.TEXT_ONLY; @@ -88,6 +89,7 @@ public class ConversationViewModel extends DbViewModel private final PrivateMessageFactory privateMessageFactory; private final AttachmentRetriever attachmentRetriever; private final AttachmentCreator attachmentCreator; + private final AutoDeleteManager autoDeleteManager; @Nullable private ContactId contactId = null; @@ -122,7 +124,8 @@ public class ConversationViewModel extends DbViewModel SettingsManager settingsManager, PrivateMessageFactory privateMessageFactory, AttachmentRetriever attachmentRetriever, - AttachmentCreator attachmentCreator) { + AttachmentCreator attachmentCreator, + AutoDeleteManager autoDeleteManager) { super(application, dbExecutor, lifecycleManager, db, androidExecutor); this.db = db; this.eventBus = eventBus; @@ -133,6 +136,7 @@ public class ConversationViewModel extends DbViewModel this.privateMessageFactory = privateMessageFactory; this.attachmentRetriever = attachmentRetriever; this.attachmentCreator = attachmentCreator; + this.autoDeleteManager = autoDeleteManager; messagingGroupId = map(contactItem, c -> messagingManager.getContactGroup(c.getContact()).getId()); contactDeleted.setValue(false); @@ -246,7 +250,8 @@ public class ConversationViewModel extends DbViewModel observeForeverOnce(messagingGroupId, groupId -> { requireNonNull(groupId); observeForeverOnce(privateMessageFormat, format -> - createMessage(groupId, text, headers, timestamp, format)); + storeMessage(requireNonNull(contactId), groupId, text, + headers, timestamp, format)); }); } @@ -306,45 +311,50 @@ public class ConversationViewModel extends DbViewModel settingsManager.mergeSettings(settings, SETTINGS_NAMESPACE); } - @UiThread - private void createMessage(GroupId groupId, @Nullable String text, + private PrivateMessage createMessage(Transaction txn, ContactId c, + GroupId groupId, @Nullable String text, List headers, long timestamp, - PrivateMessageFormat format) { + PrivateMessageFormat format) throws DbException { try { - PrivateMessage pm; if (format == TEXT_ONLY) { - pm = privateMessageFactory.createLegacyPrivateMessage( + return privateMessageFactory.createLegacyPrivateMessage( groupId, timestamp, requireNonNull(text)); } else if (format == TEXT_IMAGES) { - pm = privateMessageFactory.createPrivateMessage(groupId, + return privateMessageFactory.createPrivateMessage(groupId, timestamp, text, headers); } else { - // TODO: Look up auto-delete timer - pm = privateMessageFactory.createPrivateMessage(groupId, - timestamp, text, headers, NO_AUTO_DELETE_TIMER); + long timer = autoDeleteManager.getAutoDeleteTimer(txn, c); + return privateMessageFactory.createPrivateMessage(groupId, + timestamp, text, headers, timer); } - storeMessage(pm); } catch (FormatException e) { throw new AssertionError(e); } } @UiThread - private void storeMessage(PrivateMessage m) { - attachmentCreator.onAttachmentsSent(m.getMessage().getId()); + private void storeMessage(ContactId c, GroupId groupId, + @Nullable String text, List headers, + long timestamp, PrivateMessageFormat format) { runOnDbThread(() -> { try { - long start = now(); - messagingManager.addLocalMessage(m); - logDuration(LOG, "Storing message", start); - Message message = m.getMessage(); - PrivateMessageHeader h = new PrivateMessageHeader( - message.getId(), message.getGroupId(), - message.getTimestamp(), true, true, false, false, - m.hasText(), m.getAttachmentHeaders(), - m.getAutoDeleteTimer()); - // TODO add text to cache when available here - addedHeader.postEvent(h); + db.transaction(false, txn -> { + long start = now(); + PrivateMessage m = createMessage(txn, c, groupId, text, + headers, timestamp, format); + messagingManager.addLocalMessage(txn, m); + logDuration(LOG, "Storing message", start); + Message message = m.getMessage(); + PrivateMessageHeader h = new PrivateMessageHeader( + message.getId(), message.getGroupId(), + message.getTimestamp(), true, true, false, false, + m.hasText(), m.getAttachmentHeaders(), + m.getAutoDeleteTimer()); + // TODO add text to cache when available here + MessageId id = message.getId(); + txn.attach(() -> attachmentCreator.onAttachmentsSent(id)); + addedHeader.postEvent(h); + }); } catch (DbException e) { logException(LOG, WARNING, e); } diff --git a/briar-api/src/main/java/org/briarproject/briar/api/autodelete/AutoDeleteManager.java b/briar-api/src/main/java/org/briarproject/briar/api/autodelete/AutoDeleteManager.java new file mode 100644 index 000000000..621929634 --- /dev/null +++ b/briar-api/src/main/java/org/briarproject/briar/api/autodelete/AutoDeleteManager.java @@ -0,0 +1,14 @@ +package org.briarproject.briar.api.autodelete; + +import org.briarproject.bramble.api.contact.ContactId; +import org.briarproject.bramble.api.db.DbException; +import org.briarproject.bramble.api.db.Transaction; +import org.briarproject.bramble.api.nullsafety.NotNullByDefault; + +@NotNullByDefault +public interface AutoDeleteManager { + + long getAutoDeleteTimer(Transaction txn, ContactId c) throws DbException; + + void setAutoDeleteTimer(Transaction txn, ContactId c) throws DbException; +} diff --git a/briar-api/src/main/java/org/briarproject/briar/api/messaging/MessagingManager.java b/briar-api/src/main/java/org/briarproject/briar/api/messaging/MessagingManager.java index 1ea995c8e..ac5b1acc3 100644 --- a/briar-api/src/main/java/org/briarproject/briar/api/messaging/MessagingManager.java +++ b/briar-api/src/main/java/org/briarproject/briar/api/messaging/MessagingManager.java @@ -39,6 +39,11 @@ public interface MessagingManager extends ConversationClient { */ void addLocalMessage(PrivateMessage m) throws DbException; + /** + * Stores a local private message. + */ + void addLocalMessage(Transaction txn, PrivateMessage m) throws DbException; + /** * Stores a local attachment message. * diff --git a/briar-core/src/main/java/org/briarproject/briar/BriarCoreModule.java b/briar-core/src/main/java/org/briarproject/briar/BriarCoreModule.java index 222e41a96..65d8a3c9a 100644 --- a/briar-core/src/main/java/org/briarproject/briar/BriarCoreModule.java +++ b/briar-core/src/main/java/org/briarproject/briar/BriarCoreModule.java @@ -1,6 +1,7 @@ package org.briarproject.briar; import org.briarproject.briar.attachment.AttachmentModule; +import org.briarproject.briar.autodelete.AutoDeleteModule; import org.briarproject.briar.avatar.AvatarModule; import org.briarproject.briar.blog.BlogModule; import org.briarproject.briar.client.BriarClientModule; @@ -18,6 +19,8 @@ import org.briarproject.briar.test.TestModule; import dagger.Module; @Module(includes = { + AttachmentModule.class, + AutoDeleteModule.class, AvatarModule.class, BlogModule.class, BriarClientModule.class, @@ -27,7 +30,6 @@ import dagger.Module; GroupInvitationModule.class, IdentityModule.class, IntroductionModule.class, - AttachmentModule.class, MessagingModule.class, PrivateGroupModule.class, SharingModule.class, diff --git a/briar-core/src/main/java/org/briarproject/briar/autodelete/AutoDeleteManagerImpl.java b/briar-core/src/main/java/org/briarproject/briar/autodelete/AutoDeleteManagerImpl.java new file mode 100644 index 000000000..4324aeea5 --- /dev/null +++ b/briar-core/src/main/java/org/briarproject/briar/autodelete/AutoDeleteManagerImpl.java @@ -0,0 +1,33 @@ +package org.briarproject.briar.autodelete; + +import org.briarproject.bramble.api.contact.ContactId; +import org.briarproject.bramble.api.db.DbException; +import org.briarproject.bramble.api.db.Transaction; +import org.briarproject.bramble.api.nullsafety.NotNullByDefault; +import org.briarproject.briar.api.autodelete.AutoDeleteManager; + +import javax.annotation.concurrent.Immutable; +import javax.inject.Inject; + +import static org.briarproject.briar.api.autodelete.AutoDeleteConstants.NO_AUTO_DELETE_TIMER; + +@Immutable +@NotNullByDefault +class AutoDeleteManagerImpl implements AutoDeleteManager { + + @Inject + AutoDeleteManagerImpl() { + } + + @Override + public long getAutoDeleteTimer(Transaction txn, ContactId c) + throws DbException { + return NO_AUTO_DELETE_TIMER; + } + + @Override + public void setAutoDeleteTimer(Transaction txn, ContactId c) + throws DbException { + // Mmm hmm, yup, I'll bear that in mind + } +} diff --git a/briar-core/src/main/java/org/briarproject/briar/autodelete/AutoDeleteModule.java b/briar-core/src/main/java/org/briarproject/briar/autodelete/AutoDeleteModule.java new file mode 100644 index 000000000..f423d223a --- /dev/null +++ b/briar-core/src/main/java/org/briarproject/briar/autodelete/AutoDeleteModule.java @@ -0,0 +1,16 @@ +package org.briarproject.briar.autodelete; + +import org.briarproject.briar.api.autodelete.AutoDeleteManager; + +import dagger.Module; +import dagger.Provides; + +@Module +public class AutoDeleteModule { + + @Provides + AutoDeleteManager provideAutoDeleteManager( + AutoDeleteManagerImpl autoDeleteManager) { + return autoDeleteManager; + } +} 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 0e74825d5..0444a5e15 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 @@ -22,6 +22,7 @@ import org.briarproject.bramble.api.sync.Message; import org.briarproject.bramble.api.sync.MessageId; import org.briarproject.bramble.api.system.Clock; import org.briarproject.bramble.api.versioning.ClientVersioningManager; +import org.briarproject.briar.api.autodelete.AutoDeleteManager; import org.briarproject.briar.api.client.MessageTracker; import org.briarproject.briar.api.client.SessionId; import org.briarproject.briar.api.identity.AuthorInfo; @@ -59,6 +60,7 @@ abstract class AbstractProtocolEngine> protected final MessageParser messageParser; protected final MessageEncoder messageEncoder; protected final ClientVersioningManager clientVersioningManager; + protected final AutoDeleteManager autoDeleteManager; protected final Clock clock; AbstractProtocolEngine( @@ -72,6 +74,7 @@ abstract class AbstractProtocolEngine> MessageParser messageParser, MessageEncoder messageEncoder, ClientVersioningManager clientVersioningManager, + AutoDeleteManager autoDeleteManager, Clock clock) { this.db = db; this.clientHelper = clientHelper; @@ -83,6 +86,7 @@ abstract class AbstractProtocolEngine> this.messageParser = messageParser; this.messageEncoder = messageEncoder; this.clientVersioningManager = clientVersioningManager; + this.autoDeleteManager = autoDeleteManager; this.clock = clock; } @@ -90,9 +94,9 @@ abstract class AbstractProtocolEngine> long timestamp, Author author, @Nullable String text) throws DbException { Message m; - if (contactSupportsAutoDeletion(txn, s.getContactGroupId())) { - // TODO: Look up the current auto-delete timer - long timer = NO_AUTO_DELETE_TIMER; + ContactId c = getContactId(txn, s.getContactGroupId()); + if (contactSupportsAutoDeletion(txn, c)) { + long timer = autoDeleteManager.getAutoDeleteTimer(txn, c); m = messageEncoder.encodeRequestMessage(s.getContactGroupId(), timestamp, s.getLastLocalMessageId(), author, text, timer); sendMessage(txn, REQUEST, s.getSessionId(), m, true, timer); @@ -110,9 +114,9 @@ abstract class AbstractProtocolEngine> Map transportProperties, boolean visible) throws DbException { Message m; - if (contactSupportsAutoDeletion(txn, s.getContactGroupId())) { - // TODO: Look up the current auto-delete timer - long timer = NO_AUTO_DELETE_TIMER; + ContactId c = getContactId(txn, s.getContactGroupId()); + if (contactSupportsAutoDeletion(txn, c)) { + long timer = autoDeleteManager.getAutoDeleteTimer(txn, c); m = messageEncoder.encodeAcceptMessage(s.getContactGroupId(), timestamp, s.getLastLocalMessageId(), s.getSessionId(), ephemeralPublicKey, acceptTimestamp, transportProperties, @@ -131,9 +135,9 @@ abstract class AbstractProtocolEngine> Message sendDeclineMessage(Transaction txn, PeerSession s, long timestamp, boolean visible) throws DbException { Message m; - if (contactSupportsAutoDeletion(txn, s.getContactGroupId())) { - // TODO: Look up the current auto-delete timer - long timer = NO_AUTO_DELETE_TIMER; + ContactId c = getContactId(txn, s.getContactGroupId()); + if (contactSupportsAutoDeletion(txn, c)) { + long timer = autoDeleteManager.getAutoDeleteTimer(txn, c); m = messageEncoder.encodeDeclineMessage(s.getContactGroupId(), timestamp, s.getLastLocalMessageId(), s.getSessionId(), timer); @@ -237,16 +241,20 @@ abstract class AbstractProtocolEngine> ); } - boolean contactSupportsAutoDeletion(Transaction txn, GroupId contactGroupId) + private ContactId getContactId(Transaction txn, GroupId contactGroupId) throws DbException { try { - ContactId c = clientHelper.getContactId(txn, contactGroupId); - int minorVersion = clientVersioningManager - .getClientMinorVersion(txn, c, CLIENT_ID, MAJOR_VERSION); - // Auto-delete was added in client version 0.1 - return minorVersion >= 1; + return clientHelper.getContactId(txn, contactGroupId); } catch (FormatException e) { throw new DbException(e); } } + + private boolean contactSupportsAutoDeletion(Transaction txn, ContactId c) + throws DbException { + int minorVersion = clientVersioningManager.getClientMinorVersion(txn, c, + CLIENT_ID, MAJOR_VERSION); + // Auto-delete was added in client version 0.1 + return minorVersion >= 1; + } } 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 4beba3fb5..99e20927f 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 @@ -26,6 +26,7 @@ import org.briarproject.bramble.api.system.Clock; import org.briarproject.bramble.api.transport.KeyManager; import org.briarproject.bramble.api.transport.KeySetId; import org.briarproject.bramble.api.versioning.ClientVersioningManager; +import org.briarproject.briar.api.autodelete.AutoDeleteManager; import org.briarproject.briar.api.client.MessageTracker; import org.briarproject.briar.api.client.ProtocolStateException; import org.briarproject.briar.api.client.SessionId; @@ -80,10 +81,12 @@ class IntroduceeProtocolEngine IntroductionCrypto crypto, KeyManager keyManager, TransportPropertyManager transportPropertyManager, - ClientVersioningManager clientVersioningManager) { + ClientVersioningManager clientVersioningManager, + AutoDeleteManager autoDeleteManager) { super(db, clientHelper, contactManager, contactGroupFactory, messageTracker, identityManager, authorManager, messageParser, - messageEncoder, clientVersioningManager, clock); + messageEncoder, clientVersioningManager, autoDeleteManager, + clock); this.crypto = crypto; this.keyManager = keyManager; this.transportPropertyManager = transportPropertyManager; 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 8978c917a..bd784c0b1 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 @@ -14,6 +14,7 @@ import org.briarproject.bramble.api.sync.Message; import org.briarproject.bramble.api.sync.MessageId; import org.briarproject.bramble.api.system.Clock; import org.briarproject.bramble.api.versioning.ClientVersioningManager; +import org.briarproject.briar.api.autodelete.AutoDeleteManager; import org.briarproject.briar.api.client.MessageTracker; import org.briarproject.briar.api.client.ProtocolStateException; import org.briarproject.briar.api.identity.AuthorManager; @@ -54,10 +55,12 @@ class IntroducerProtocolEngine MessageParser messageParser, MessageEncoder messageEncoder, ClientVersioningManager clientVersioningManager, + AutoDeleteManager autoDeleteManager, Clock clock) { super(db, clientHelper, contactManager, contactGroupFactory, messageTracker, identityManager, authorManager, messageParser, - messageEncoder, clientVersioningManager, clock); + messageEncoder, clientVersioningManager, autoDeleteManager, + clock); } @Override diff --git a/briar-core/src/main/java/org/briarproject/briar/messaging/MessagingManagerImpl.java b/briar-core/src/main/java/org/briarproject/briar/messaging/MessagingManagerImpl.java index 9297365c9..a79a91574 100644 --- a/briar-core/src/main/java/org/briarproject/briar/messaging/MessagingManagerImpl.java +++ b/briar-core/src/main/java/org/briarproject/briar/messaging/MessagingManagerImpl.java @@ -227,7 +227,12 @@ class MessagingManagerImpl implements MessagingManager, IncomingMessageHook, @Override public void addLocalMessage(PrivateMessage m) throws DbException { - Transaction txn = db.startTransaction(false); + db.transaction(false, txn -> addLocalMessage(txn, m)); + } + + @Override + public void addLocalMessage(Transaction txn, PrivateMessage m) + throws DbException { try { BdfDictionary meta = new BdfDictionary(); meta.put(MSG_KEY_TIMESTAMP, m.getMessage().getTimestamp()); @@ -257,11 +262,8 @@ class MessagingManagerImpl implements MessagingManager, IncomingMessageHook, clientHelper.addLocalMessage(txn, m.getMessage(), meta, true, false); messageTracker.trackOutgoingMessage(txn, m.getMessage()); - db.commitTransaction(txn); } catch (FormatException e) { throw new AssertionError(e); - } finally { - db.endTransaction(txn); } } 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 8d453c06d..396512594 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 @@ -17,6 +17,7 @@ import org.briarproject.bramble.api.sync.Message; import org.briarproject.bramble.api.sync.MessageId; import org.briarproject.bramble.api.system.Clock; import org.briarproject.bramble.api.versioning.ClientVersioningManager; +import org.briarproject.briar.api.autodelete.AutoDeleteManager; import org.briarproject.briar.api.client.MessageTracker; import org.briarproject.briar.api.privategroup.GroupMessage; import org.briarproject.briar.api.privategroup.GroupMessageFactory; @@ -52,15 +53,21 @@ abstract class AbstractProtocolEngine> private final IdentityManager identityManager; private final MessageParser messageParser; private final MessageEncoder messageEncoder; + private final AutoDeleteManager autoDeleteManager; private final Clock clock; - AbstractProtocolEngine(DatabaseComponent db, ClientHelper clientHelper, + AbstractProtocolEngine( + DatabaseComponent db, + ClientHelper clientHelper, ClientVersioningManager clientVersioningManager, PrivateGroupManager privateGroupManager, PrivateGroupFactory privateGroupFactory, GroupMessageFactory groupMessageFactory, - IdentityManager identityManager, MessageParser messageParser, - MessageEncoder messageEncoder, MessageTracker messageTracker, + IdentityManager identityManager, + MessageParser messageParser, + MessageEncoder messageEncoder, + MessageTracker messageTracker, + AutoDeleteManager autoDeleteManager, Clock clock) { this.db = db; this.clientHelper = clientHelper; @@ -72,6 +79,7 @@ abstract class AbstractProtocolEngine> this.messageParser = messageParser; this.messageEncoder = messageEncoder; this.messageTracker = messageTracker; + this.autoDeleteManager = autoDeleteManager; this.clock = clock; } @@ -112,9 +120,9 @@ abstract class AbstractProtocolEngine> throw new DbException(e); // Invalid group descriptor } Message m; - if (contactSupportsAutoDeletion(txn, s.getContactGroupId())) { - // TODO: Look up the current auto-delete timer - long timer = NO_AUTO_DELETE_TIMER; + 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, @@ -134,10 +142,12 @@ abstract class AbstractProtocolEngine> Message sendJoinMessage(Transaction txn, S s, boolean visibleInUi) throws DbException { Message m; - if (contactSupportsAutoDeletion(txn, s.getContactGroupId())) { - // TODO: Look up the current auto-delete timer if the message is - // visible in the UI (accepting an invitation) - long timer = NO_AUTO_DELETE_TIMER; + ContactId c = getContactId(txn, s.getContactGroupId()); + if (contactSupportsAutoDeletion(txn, c)) { + // Set auto-delete timer if manually accepting an invitation + long timer = visibleInUi + ? autoDeleteManager.getAutoDeleteTimer(txn, c) + : NO_AUTO_DELETE_TIMER; m = messageEncoder.encodeJoinMessage(s.getContactGroupId(), s.getPrivateGroupId(), getLocalTimestamp(s), s.getLastLocalMessageId(), timer); @@ -156,10 +166,12 @@ abstract class AbstractProtocolEngine> Message sendLeaveMessage(Transaction txn, S s, boolean visibleInUi) throws DbException { Message m; - if (contactSupportsAutoDeletion(txn, s.getContactGroupId())) { - // TODO: Look up the current auto-delete timer if the message is - // visible in the UI (declining an invitation) - long timer = NO_AUTO_DELETE_TIMER; + ContactId c = getContactId(txn, s.getContactGroupId()); + if (contactSupportsAutoDeletion(txn, c)) { + // Set auto-delete timer if manually accepting an invitation + long timer = visibleInUi + ? autoDeleteManager.getAutoDeleteTimer(txn, c) + : NO_AUTO_DELETE_TIMER; m = messageEncoder.encodeLeaveMessage(s.getContactGroupId(), s.getPrivateGroupId(), getLocalTimestamp(s), s.getLastLocalMessageId(), timer); @@ -263,18 +275,21 @@ abstract class AbstractProtocolEngine> } } - boolean contactSupportsAutoDeletion(Transaction txn, GroupId contactGroupId) + private ContactId getContactId(Transaction txn, GroupId contactGroupId) throws DbException { try { - ContactId c = clientHelper.getContactId(txn, contactGroupId); - int minorVersion = clientVersioningManager - .getClientMinorVersion(txn, c, - GroupInvitationManager.CLIENT_ID, - GroupInvitationManager.MAJOR_VERSION); - // Auto-delete was added in client version 0.1 - return minorVersion >= 1; + return clientHelper.getContactId(txn, contactGroupId); } catch (FormatException e) { throw new DbException(e); } } + + private boolean contactSupportsAutoDeletion(Transaction txn, ContactId c) + throws DbException { + int minorVersion = clientVersioningManager.getClientMinorVersion(txn, c, + GroupInvitationManager.CLIENT_ID, + GroupInvitationManager.MAJOR_VERSION); + // Auto-delete was added in client version 0.1 + return minorVersion >= 1; + } } 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 519d6cb6d..a38967fdd 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 @@ -11,6 +11,7 @@ import org.briarproject.bramble.api.nullsafety.NotNullByDefault; import org.briarproject.bramble.api.sync.Message; 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.client.ProtocolStateException; import org.briarproject.briar.api.client.SessionId; @@ -36,17 +37,23 @@ import static org.briarproject.briar.privategroup.invitation.CreatorState.START; @NotNullByDefault class CreatorProtocolEngine extends AbstractProtocolEngine { - CreatorProtocolEngine(DatabaseComponent db, ClientHelper clientHelper, + CreatorProtocolEngine( + DatabaseComponent db, + ClientHelper clientHelper, ClientVersioningManager clientVersioningManager, PrivateGroupManager privateGroupManager, PrivateGroupFactory privateGroupFactory, GroupMessageFactory groupMessageFactory, - IdentityManager identityManager, MessageParser messageParser, - MessageEncoder messageEncoder, MessageTracker messageTracker, + IdentityManager identityManager, + MessageParser messageParser, + MessageEncoder messageEncoder, + MessageTracker messageTracker, + AutoDeleteManager autoDeleteManager, Clock clock) { super(db, clientHelper, clientVersioningManager, privateGroupManager, privateGroupFactory, groupMessageFactory, identityManager, - messageParser, messageEncoder, messageTracker, clock); + messageParser, messageEncoder, messageTracker, + autoDeleteManager, clock); } @Override 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 cdb597a5e..dbc17477f 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 @@ -13,6 +13,7 @@ import org.briarproject.bramble.api.sync.Message; import org.briarproject.bramble.api.sync.MessageId; import org.briarproject.bramble.api.system.Clock; import org.briarproject.bramble.api.versioning.ClientVersioningManager; +import org.briarproject.briar.api.autodelete.AutoDeleteManager; import org.briarproject.briar.api.client.MessageTracker; import org.briarproject.briar.api.client.ProtocolStateException; import org.briarproject.briar.api.client.SessionId; @@ -41,17 +42,22 @@ import static org.briarproject.briar.privategroup.invitation.InviteeState.START; @NotNullByDefault class InviteeProtocolEngine extends AbstractProtocolEngine { - InviteeProtocolEngine(DatabaseComponent db, ClientHelper clientHelper, + InviteeProtocolEngine(DatabaseComponent db, + ClientHelper clientHelper, ClientVersioningManager clientVersioningManager, PrivateGroupManager privateGroupManager, PrivateGroupFactory privateGroupFactory, GroupMessageFactory groupMessageFactory, - IdentityManager identityManager, MessageParser messageParser, - MessageEncoder messageEncoder, MessageTracker messageTracker, + IdentityManager identityManager, + MessageParser messageParser, + MessageEncoder messageEncoder, + MessageTracker messageTracker, + AutoDeleteManager autoDeleteManager, Clock clock) { super(db, clientHelper, clientVersioningManager, privateGroupManager, privateGroupFactory, groupMessageFactory, identityManager, - messageParser, messageEncoder, messageTracker, clock); + messageParser, messageEncoder, messageTracker, + autoDeleteManager, clock); } @Override 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 de0a96fc6..21eef0053 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 @@ -12,6 +12,7 @@ import org.briarproject.bramble.api.nullsafety.NotNullByDefault; import org.briarproject.bramble.api.sync.Message; 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.client.ProtocolStateException; import org.briarproject.briar.api.privategroup.GroupMessageFactory; @@ -36,17 +37,23 @@ import static org.briarproject.briar.privategroup.invitation.PeerState.START; @NotNullByDefault class PeerProtocolEngine extends AbstractProtocolEngine { - PeerProtocolEngine(DatabaseComponent db, ClientHelper clientHelper, + PeerProtocolEngine( + DatabaseComponent db, + ClientHelper clientHelper, ClientVersioningManager clientVersioningManager, PrivateGroupManager privateGroupManager, PrivateGroupFactory privateGroupFactory, GroupMessageFactory groupMessageFactory, - IdentityManager identityManager, MessageParser messageParser, - MessageEncoder messageEncoder, MessageTracker messageTracker, + IdentityManager identityManager, + MessageParser messageParser, + MessageEncoder messageEncoder, + MessageTracker messageTracker, + AutoDeleteManager autoDeleteManager, Clock clock) { super(db, clientHelper, clientVersioningManager, privateGroupManager, privateGroupFactory, groupMessageFactory, identityManager, - messageParser, messageEncoder, messageTracker, clock); + messageParser, messageEncoder, messageTracker, + autoDeleteManager, clock); } @Override 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 d54031029..089b06c66 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 @@ -6,6 +6,7 @@ import org.briarproject.bramble.api.identity.IdentityManager; import org.briarproject.bramble.api.nullsafety.NotNullByDefault; 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.privategroup.GroupMessageFactory; import org.briarproject.briar.api.privategroup.PrivateGroupFactory; @@ -28,16 +29,22 @@ class ProtocolEngineFactoryImpl implements ProtocolEngineFactory { private final MessageParser messageParser; private final MessageEncoder messageEncoder; private final MessageTracker messageTracker; + private final AutoDeleteManager autoDeleteManager; private final Clock clock; @Inject - ProtocolEngineFactoryImpl(DatabaseComponent db, ClientHelper clientHelper, + ProtocolEngineFactoryImpl( + DatabaseComponent db, + ClientHelper clientHelper, ClientVersioningManager clientVersioningManager, PrivateGroupManager privateGroupManager, PrivateGroupFactory privateGroupFactory, GroupMessageFactory groupMessageFactory, - IdentityManager identityManager, MessageParser messageParser, - MessageEncoder messageEncoder, MessageTracker messageTracker, + IdentityManager identityManager, + MessageParser messageParser, + MessageEncoder messageEncoder, + MessageTracker messageTracker, + AutoDeleteManager autoDeleteManager, Clock clock) { this.db = db; this.clientHelper = clientHelper; @@ -49,6 +56,7 @@ class ProtocolEngineFactoryImpl implements ProtocolEngineFactory { this.messageParser = messageParser; this.messageEncoder = messageEncoder; this.messageTracker = messageTracker; + this.autoDeleteManager = autoDeleteManager; this.clock = clock; } @@ -57,7 +65,8 @@ class ProtocolEngineFactoryImpl implements ProtocolEngineFactory { return new CreatorProtocolEngine(db, clientHelper, clientVersioningManager, privateGroupManager, privateGroupFactory, groupMessageFactory, identityManager, - messageParser, messageEncoder, messageTracker, clock); + messageParser, messageEncoder, messageTracker, + autoDeleteManager, clock); } @Override @@ -65,7 +74,8 @@ class ProtocolEngineFactoryImpl implements ProtocolEngineFactory { return new InviteeProtocolEngine(db, clientHelper, clientVersioningManager, privateGroupManager, privateGroupFactory, groupMessageFactory, identityManager, - messageParser, messageEncoder, messageTracker, clock); + messageParser, messageEncoder, messageTracker, + autoDeleteManager, clock); } @Override @@ -73,6 +83,7 @@ class ProtocolEngineFactoryImpl implements ProtocolEngineFactory { return new PeerProtocolEngine(db, clientHelper, clientVersioningManager, privateGroupManager, privateGroupFactory, groupMessageFactory, identityManager, - messageParser, messageEncoder, messageTracker, clock); + messageParser, messageEncoder, messageTracker, + autoDeleteManager, 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 79dfaaa42..05fcc2eb0 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 @@ -11,6 +11,7 @@ import org.briarproject.bramble.api.nullsafety.NotNullByDefault; import org.briarproject.bramble.api.sync.MessageId; import org.briarproject.bramble.api.system.Clock; import org.briarproject.bramble.api.versioning.ClientVersioningManager; +import org.briarproject.briar.api.autodelete.AutoDeleteManager; import org.briarproject.briar.api.blog.Blog; import org.briarproject.briar.api.blog.BlogInvitationResponse; import org.briarproject.briar.api.blog.BlogManager; @@ -32,13 +33,19 @@ class BlogProtocolEngineImpl extends ProtocolEngineImpl { invitationFactory; @Inject - BlogProtocolEngineImpl(DatabaseComponent db, ClientHelper clientHelper, + BlogProtocolEngineImpl( + DatabaseComponent db, + ClientHelper clientHelper, ClientVersioningManager clientVersioningManager, - MessageEncoder messageEncoder, MessageParser messageParser, - MessageTracker messageTracker, Clock clock, BlogManager blogManager, + MessageEncoder messageEncoder, + MessageParser messageParser, + MessageTracker messageTracker, + AutoDeleteManager autoDeleteManager, + Clock clock, + BlogManager blogManager, InvitationFactory invitationFactory) { super(db, clientHelper, clientVersioningManager, messageEncoder, - messageParser, messageTracker, clock, + messageParser, messageTracker, autoDeleteManager, clock, BlogSharingManager.CLIENT_ID, BlogSharingManager.MAJOR_VERSION, BlogManager.CLIENT_ID, BlogManager.MAJOR_VERSION); this.blogManager = blogManager; 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 e6df8fc48..91757b463 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 @@ -11,6 +11,7 @@ import org.briarproject.bramble.api.nullsafety.NotNullByDefault; import org.briarproject.bramble.api.sync.MessageId; import org.briarproject.bramble.api.system.Clock; import org.briarproject.bramble.api.versioning.ClientVersioningManager; +import org.briarproject.briar.api.autodelete.AutoDeleteManager; import org.briarproject.briar.api.client.MessageTracker; import org.briarproject.briar.api.conversation.ConversationRequest; import org.briarproject.briar.api.forum.Forum; @@ -32,15 +33,19 @@ class ForumProtocolEngineImpl extends ProtocolEngineImpl { invitationFactory; @Inject - ForumProtocolEngineImpl(DatabaseComponent db, + ForumProtocolEngineImpl( + DatabaseComponent db, ClientHelper clientHelper, ClientVersioningManager clientVersioningManager, - MessageEncoder messageEncoder, MessageParser messageParser, - MessageTracker messageTracker, Clock clock, + MessageEncoder messageEncoder, + MessageParser messageParser, + MessageTracker messageTracker, + AutoDeleteManager autoDeleteManager, + Clock clock, ForumManager forumManager, InvitationFactory invitationFactory) { super(db, clientHelper, clientVersioningManager, messageEncoder, - messageParser, messageTracker, clock, + messageParser, messageTracker, autoDeleteManager, clock, ForumSharingManager.CLIENT_ID, ForumSharingManager.MAJOR_VERSION, ForumManager.CLIENT_ID, ForumManager.MAJOR_VERSION); 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 cd6f8e221..9e841bd44 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 @@ -18,6 +18,7 @@ import org.briarproject.bramble.api.sync.Message; import org.briarproject.bramble.api.sync.MessageId; import org.briarproject.bramble.api.system.Clock; import org.briarproject.bramble.api.versioning.ClientVersioningManager; +import org.briarproject.briar.api.autodelete.AutoDeleteManager; import org.briarproject.briar.api.client.MessageTracker; import org.briarproject.briar.api.client.ProtocolStateException; import org.briarproject.briar.api.sharing.Shareable; @@ -56,22 +57,31 @@ abstract class ProtocolEngineImpl private final ClientVersioningManager clientVersioningManager; private final MessageEncoder messageEncoder; private final MessageTracker messageTracker; + private final AutoDeleteManager autoDeleteManager; private final Clock clock; private final ClientId sharingClientId, shareableClientId; private final int sharingClientMajorVersion, shareableClientMajorVersion; - ProtocolEngineImpl(DatabaseComponent db, ClientHelper clientHelper, + ProtocolEngineImpl( + DatabaseComponent db, + ClientHelper clientHelper, ClientVersioningManager clientVersioningManager, - MessageEncoder messageEncoder, MessageParser messageParser, - MessageTracker messageTracker, Clock clock, - ClientId sharingClientId, int sharingClientMajorVersion, - ClientId shareableClientId, int shareableClientMajorVersion) { + MessageEncoder messageEncoder, + MessageParser messageParser, + MessageTracker messageTracker, + AutoDeleteManager autoDeleteManager, + Clock clock, + ClientId sharingClientId, + int sharingClientMajorVersion, + ClientId shareableClientId, + int shareableClientMajorVersion) { this.db = db; this.clientHelper = clientHelper; this.clientVersioningManager = clientVersioningManager; this.messageEncoder = messageEncoder; this.messageParser = messageParser; this.messageTracker = messageTracker; + this.autoDeleteManager = autoDeleteManager; this.clock = clock; this.sharingClientId = sharingClientId; this.sharingClientMajorVersion = sharingClientMajorVersion; @@ -125,9 +135,9 @@ abstract class ProtocolEngineImpl } long localTimestamp = Math.max(timestamp, getLocalTimestamp(s)); Message m; - if (contactSupportsAutoDeletion(txn, s.getContactGroupId())) { - // TODO: Look up the current auto-delete timer - long timer = NO_AUTO_DELETE_TIMER; + ContactId c = getContactId(txn, s.getContactGroupId()); + if (contactSupportsAutoDeletion(txn, c)) { + long timer = autoDeleteManager.getAutoDeleteTimer(txn, c); m = messageEncoder.encodeInviteMessage(s.getContactGroupId(), localTimestamp, s.getLastLocalMessageId(), descriptor, text, timer); @@ -191,9 +201,9 @@ abstract class ProtocolEngineImpl private Message sendAcceptMessage(Transaction txn, Session s) throws DbException { Message m; - if (contactSupportsAutoDeletion(txn, s.getContactGroupId())) { - // TODO: Look up the current auto-delete timer - long timer = NO_AUTO_DELETE_TIMER; + 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.getLastLocalMessageId(), timer); @@ -244,9 +254,9 @@ abstract class ProtocolEngineImpl private Message sendDeclineMessage(Transaction txn, Session s) throws DbException { Message m; - if (contactSupportsAutoDeletion(txn, s.getContactGroupId())) { - // TODO: Look up the current auto-delete timer - long timer = NO_AUTO_DELETE_TIMER; + 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.getLastLocalMessageId(), timer); @@ -673,17 +683,20 @@ abstract class ProtocolEngineImpl session.getInviteTimestamp()) + 1); } - boolean contactSupportsAutoDeletion(Transaction txn, GroupId contactGroupId) + private ContactId getContactId(Transaction txn, GroupId contactGroupId) throws DbException { try { - ContactId c = clientHelper.getContactId(txn, contactGroupId); - int minorVersion = clientVersioningManager - .getClientMinorVersion(txn, c, sharingClientId, - sharingClientMajorVersion); - // Auto-delete was added in client version 0.1 - return minorVersion >= 1; + return clientHelper.getContactId(txn, contactGroupId); } catch (FormatException e) { throw new DbException(e); } } + + private boolean contactSupportsAutoDeletion(Transaction txn, ContactId c) + throws DbException { + int minorVersion = clientVersioningManager.getClientMinorVersion(txn, c, + sharingClientId, sharingClientMajorVersion); + // Auto-delete was added in client version 0.1 + return minorVersion >= 1; + } } diff --git a/briar-core/src/test/java/org/briarproject/briar/introduction/IntroductionIntegrationTestComponent.java b/briar-core/src/test/java/org/briarproject/briar/introduction/IntroductionIntegrationTestComponent.java index ce4e455e4..eb48a7d9d 100644 --- a/briar-core/src/test/java/org/briarproject/briar/introduction/IntroductionIntegrationTestComponent.java +++ b/briar-core/src/test/java/org/briarproject/briar/introduction/IntroductionIntegrationTestComponent.java @@ -3,6 +3,7 @@ package org.briarproject.briar.introduction; import org.briarproject.bramble.BrambleCoreModule; import org.briarproject.bramble.test.BrambleCoreIntegrationTestModule; import org.briarproject.briar.attachment.AttachmentModule; +import org.briarproject.briar.autodelete.AutoDeleteModule; import org.briarproject.briar.avatar.AvatarModule; import org.briarproject.briar.blog.BlogModule; import org.briarproject.briar.client.BriarClientModule; @@ -22,6 +23,8 @@ import dagger.Component; @Component(modules = { BrambleCoreIntegrationTestModule.class, BrambleCoreModule.class, + AttachmentModule.class, + AutoDeleteModule.class, AvatarModule.class, BlogModule.class, BriarClientModule.class, @@ -29,7 +32,6 @@ import dagger.Component; GroupInvitationModule.class, IdentityModule.class, IntroductionModule.class, - AttachmentModule.class, MessagingModule.class, PrivateGroupModule.class, SharingModule.class 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 b7df73946..1f2f85008 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 @@ -17,6 +17,7 @@ import org.briarproject.bramble.api.sync.MessageId; import org.briarproject.bramble.api.system.Clock; 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.privategroup.GroupMessageFactory; import org.briarproject.briar.api.privategroup.PrivateGroup; @@ -59,6 +60,8 @@ abstract class AbstractProtocolEngineTest extends BrambleMockTestCase { final IdentityManager identityManager = context.mock(IdentityManager.class); final MessageEncoder messageEncoder = context.mock(MessageEncoder.class); final MessageTracker messageTracker = context.mock(MessageTracker.class); + final AutoDeleteManager autoDeleteManager = + context.mock(AutoDeleteManager.class); final Clock clock = context.mock(Clock.class); final Transaction txn = new Transaction(null, false); @@ -120,7 +123,7 @@ abstract class AbstractProtocolEngineTest extends BrambleMockTestCase { } void expectSendInviteMessage(String text) throws Exception { - expectCheckWhetherContactSupportsAutoDeletion(); + expectCheckWhetherContactSupportsAutoDeletion(true); expectGetLocalTimestamp(messageTimestamp); context.checking(new Expectations() {{ oneOf(messageEncoder).encodeInviteMessage(contactGroupId, @@ -134,7 +137,7 @@ abstract class AbstractProtocolEngineTest extends BrambleMockTestCase { void expectSendJoinMessage(JoinMessage m, boolean visible) throws Exception { - expectCheckWhetherContactSupportsAutoDeletion(); + expectCheckWhetherContactSupportsAutoDeletion(visible); expectGetLocalTimestamp(messageTimestamp); context.checking(new Expectations() {{ oneOf(messageEncoder).encodeJoinMessage(m.getContactGroupId(), @@ -146,7 +149,7 @@ abstract class AbstractProtocolEngineTest extends BrambleMockTestCase { } void expectSendLeaveMessage(boolean visible) throws Exception { - expectCheckWhetherContactSupportsAutoDeletion(); + expectCheckWhetherContactSupportsAutoDeletion(visible); expectGetLocalTimestamp(messageTimestamp); context.checking(new Expectations() {{ oneOf(messageEncoder).encodeLeaveMessage(contactGroupId, @@ -223,7 +226,8 @@ abstract class AbstractProtocolEngineTest extends BrambleMockTestCase { }}); } - void expectCheckWhetherContactSupportsAutoDeletion() throws Exception { + void expectCheckWhetherContactSupportsAutoDeletion(boolean visible) + throws Exception { context.checking(new Expectations() {{ oneOf(clientHelper).getContactId(txn, contactGroupId); will(returnValue(contactId)); @@ -231,6 +235,10 @@ 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)); + } }}); } } 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 f74054ddb..fde516717 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,7 @@ public class CreatorProtocolEngineTest extends AbstractProtocolEngineTest { new CreatorProtocolEngine(db, clientHelper, clientVersioningManager, privateGroupManager, privateGroupFactory, groupMessageFactory, identityManager, messageParser, - messageEncoder, messageTracker, clock); + messageEncoder, messageTracker, autoDeleteManager, clock); private CreatorSession getDefaultSession(CreatorState state) { return new CreatorSession(contactGroupId, privateGroupId, 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 d32277223..56a984d6e 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,7 @@ public class InviteeProtocolEngineTest extends AbstractProtocolEngineTest { new InviteeProtocolEngine(db, clientHelper, clientVersioningManager, privateGroupManager, privateGroupFactory, groupMessageFactory, identityManager, messageParser, - messageEncoder, messageTracker, clock); + messageEncoder, messageTracker, autoDeleteManager, clock); private final LocalAuthor localAuthor = getLocalAuthor(); private InviteeSession getDefaultSession(InviteeState state) { 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 0c64a4965..35191e995 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,7 @@ public class PeerProtocolEngineTest extends AbstractProtocolEngineTest { new PeerProtocolEngine(db, clientHelper, clientVersioningManager, privateGroupManager, privateGroupFactory, groupMessageFactory, identityManager, messageParser, - messageEncoder, messageTracker, clock); + messageEncoder, messageTracker, autoDeleteManager, clock); private PeerSession getDefaultSession(PeerState state) { return new PeerSession(contactGroupId, privateGroupId, diff --git a/briar-core/src/test/java/org/briarproject/briar/test/BriarIntegrationTestComponent.java b/briar-core/src/test/java/org/briarproject/briar/test/BriarIntegrationTestComponent.java index f28cb8ef0..d0b5bf1d4 100644 --- a/briar-core/src/test/java/org/briarproject/briar/test/BriarIntegrationTestComponent.java +++ b/briar-core/src/test/java/org/briarproject/briar/test/BriarIntegrationTestComponent.java @@ -27,6 +27,7 @@ import org.briarproject.briar.api.messaging.PrivateMessageFactory; import org.briarproject.briar.api.privategroup.PrivateGroupManager; import org.briarproject.briar.api.privategroup.invitation.GroupInvitationManager; import org.briarproject.briar.attachment.AttachmentModule; +import org.briarproject.briar.autodelete.AutoDeleteModule; import org.briarproject.briar.avatar.AvatarModule; import org.briarproject.briar.blog.BlogModule; import org.briarproject.briar.client.BriarClientModule; @@ -46,6 +47,8 @@ import dagger.Component; @Component(modules = { BrambleCoreIntegrationTestModule.class, BrambleCoreModule.class, + AttachmentModule.class, + AutoDeleteModule.class, AvatarModule.class, BlogModule.class, BriarClientModule.class, @@ -53,7 +56,6 @@ import dagger.Component; GroupInvitationModule.class, IdentityModule.class, IntroductionModule.class, - AttachmentModule.class, MessagingModule.class, PrivateGroupModule.class, SharingModule.class From 706f4e1c4c2d6cd5d9dc33a73a2346a4bfa34410 Mon Sep 17 00:00:00 2001 From: akwizgran Date: Thu, 26 Nov 2020 13:15:01 +0000 Subject: [PATCH 017/124] Implement AutoDeleteManager. --- .../api/autodelete/AutoDeleteManager.java | 19 ++++- .../briar/BriarCoreEagerSingletons.java | 4 + .../briar/autodelete/AutoDeleteConstants.java | 7 ++ .../autodelete/AutoDeleteManagerImpl.java | 77 +++++++++++++++++-- .../briar/autodelete/AutoDeleteModule.java | 16 ++++ .../test/BriarIntegrationTestComponent.java | 3 + 6 files changed, 120 insertions(+), 6 deletions(-) create mode 100644 briar-core/src/main/java/org/briarproject/briar/autodelete/AutoDeleteConstants.java diff --git a/briar-api/src/main/java/org/briarproject/briar/api/autodelete/AutoDeleteManager.java b/briar-api/src/main/java/org/briarproject/briar/api/autodelete/AutoDeleteManager.java index 621929634..251178817 100644 --- a/briar-api/src/main/java/org/briarproject/briar/api/autodelete/AutoDeleteManager.java +++ b/briar-api/src/main/java/org/briarproject/briar/api/autodelete/AutoDeleteManager.java @@ -4,11 +4,28 @@ import org.briarproject.bramble.api.contact.ContactId; 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.ClientId; @NotNullByDefault public interface AutoDeleteManager { + /** + * The unique ID of the auto-delete client. + */ + ClientId CLIENT_ID = new ClientId("org.briarproject.briar.autodelete"); + + /** + * The current major version of the auto-delete client. + */ + int MAJOR_VERSION = 0; + + /** + * The current minor version of the auto-delete client. + */ + int MINOR_VERSION = 0; + long getAutoDeleteTimer(Transaction txn, ContactId c) throws DbException; - void setAutoDeleteTimer(Transaction txn, ContactId c) throws DbException; + void setAutoDeleteTimer(Transaction txn, ContactId c, long timer) + throws DbException; } diff --git a/briar-core/src/main/java/org/briarproject/briar/BriarCoreEagerSingletons.java b/briar-core/src/main/java/org/briarproject/briar/BriarCoreEagerSingletons.java index 72c5cf603..cffe834fa 100644 --- a/briar-core/src/main/java/org/briarproject/briar/BriarCoreEagerSingletons.java +++ b/briar-core/src/main/java/org/briarproject/briar/BriarCoreEagerSingletons.java @@ -1,5 +1,6 @@ package org.briarproject.briar; +import org.briarproject.briar.autodelete.AutoDeleteModule; import org.briarproject.briar.avatar.AvatarModule; import org.briarproject.briar.blog.BlogModule; import org.briarproject.briar.feed.FeedModule; @@ -13,6 +14,8 @@ import org.briarproject.briar.sharing.SharingModule; public interface BriarCoreEagerSingletons { + void inject(AutoDeleteModule.EagerSingletons init); + void inject(AvatarModule.EagerSingletons init); void inject(BlogModule.EagerSingletons init); @@ -36,6 +39,7 @@ public interface BriarCoreEagerSingletons { class Helper { public static void injectEagerSingletons(BriarCoreEagerSingletons c) { + c.inject(new AutoDeleteModule.EagerSingletons()); c.inject(new AvatarModule.EagerSingletons()); c.inject(new BlogModule.EagerSingletons()); c.inject(new FeedModule.EagerSingletons()); diff --git a/briar-core/src/main/java/org/briarproject/briar/autodelete/AutoDeleteConstants.java b/briar-core/src/main/java/org/briarproject/briar/autodelete/AutoDeleteConstants.java new file mode 100644 index 000000000..7dc94eced --- /dev/null +++ b/briar-core/src/main/java/org/briarproject/briar/autodelete/AutoDeleteConstants.java @@ -0,0 +1,7 @@ +package org.briarproject.briar.autodelete; + +interface AutoDeleteConstants { + + // Group metadata key for storing the auto-delete timer + String GROUP_KEY_AUTO_DELETE_TIMER = "autoDeleteTimer"; +} diff --git a/briar-core/src/main/java/org/briarproject/briar/autodelete/AutoDeleteManagerImpl.java b/briar-core/src/main/java/org/briarproject/briar/autodelete/AutoDeleteManagerImpl.java index 4324aeea5..d00b515a8 100644 --- a/briar-core/src/main/java/org/briarproject/briar/autodelete/AutoDeleteManagerImpl.java +++ b/briar-core/src/main/java/org/briarproject/briar/autodelete/AutoDeleteManagerImpl.java @@ -1,33 +1,100 @@ package org.briarproject.briar.autodelete; +import org.briarproject.bramble.api.FormatException; +import org.briarproject.bramble.api.client.ClientHelper; +import org.briarproject.bramble.api.client.ContactGroupFactory; +import org.briarproject.bramble.api.contact.Contact; import org.briarproject.bramble.api.contact.ContactId; +import org.briarproject.bramble.api.contact.ContactManager.ContactHook; +import org.briarproject.bramble.api.data.BdfDictionary; +import org.briarproject.bramble.api.data.BdfEntry; +import org.briarproject.bramble.api.db.DatabaseComponent; import org.briarproject.bramble.api.db.DbException; import org.briarproject.bramble.api.db.Transaction; +import org.briarproject.bramble.api.lifecycle.LifecycleManager.OpenDatabaseHook; import org.briarproject.bramble.api.nullsafety.NotNullByDefault; +import org.briarproject.bramble.api.sync.Group; +import org.briarproject.bramble.api.sync.GroupFactory; import org.briarproject.briar.api.autodelete.AutoDeleteManager; import javax.annotation.concurrent.Immutable; import javax.inject.Inject; import static org.briarproject.briar.api.autodelete.AutoDeleteConstants.NO_AUTO_DELETE_TIMER; +import static org.briarproject.briar.autodelete.AutoDeleteConstants.GROUP_KEY_AUTO_DELETE_TIMER; @Immutable @NotNullByDefault -class AutoDeleteManagerImpl implements AutoDeleteManager { +class AutoDeleteManagerImpl + implements AutoDeleteManager, OpenDatabaseHook, ContactHook { + + private final DatabaseComponent db; + private final ClientHelper clientHelper; + private final GroupFactory groupFactory; + private final Group localGroup; @Inject - AutoDeleteManagerImpl() { + AutoDeleteManagerImpl( + DatabaseComponent db, + ClientHelper clientHelper, + GroupFactory groupFactory, + ContactGroupFactory contactGroupFactory) { + this.db = db; + this.clientHelper = clientHelper; + this.groupFactory = groupFactory; + localGroup = contactGroupFactory.createLocalGroup(CLIENT_ID, + MAJOR_VERSION); + } + + @Override + public void onDatabaseOpened(Transaction txn) throws DbException { + if (db.containsGroup(txn, localGroup.getId())) return; + db.addGroup(txn, localGroup); + // Set things up for any pre-existing contacts + for (Contact c : db.getContacts(txn)) addingContact(txn, c); + } + + @Override + public void addingContact(Transaction txn, Contact c) throws DbException { + Group g = getGroup(c); + db.addGroup(txn, g); + clientHelper.setContactId(txn, g.getId(), c.getId()); + } + + @Override + public void removingContact(Transaction txn, Contact c) throws DbException { + db.removeGroup(txn, getGroup(c)); } @Override public long getAutoDeleteTimer(Transaction txn, ContactId c) throws DbException { - return NO_AUTO_DELETE_TIMER; + try { + Group g = getGroup(db.getContact(txn, c)); + BdfDictionary meta = + clientHelper.getGroupMetadataAsDictionary(txn, g.getId()); + return meta.getLong(GROUP_KEY_AUTO_DELETE_TIMER, + NO_AUTO_DELETE_TIMER); + } catch (FormatException e) { + throw new DbException(e); + } } @Override - public void setAutoDeleteTimer(Transaction txn, ContactId c) + public void setAutoDeleteTimer(Transaction txn, ContactId c, long timer) throws DbException { - // Mmm hmm, yup, I'll bear that in mind + try { + Group g = getGroup(db.getContact(txn, c)); + BdfDictionary meta = BdfDictionary.of( + new BdfEntry(GROUP_KEY_AUTO_DELETE_TIMER, timer)); + clientHelper.mergeGroupMetadata(txn, g.getId(), meta); + } catch (FormatException e) { + throw new AssertionError(e); + } + } + + private Group getGroup(Contact c) { + byte[] descriptor = c.getAuthor().getId().getBytes(); + return groupFactory.createGroup(CLIENT_ID, MAJOR_VERSION, descriptor); } } diff --git a/briar-core/src/main/java/org/briarproject/briar/autodelete/AutoDeleteModule.java b/briar-core/src/main/java/org/briarproject/briar/autodelete/AutoDeleteModule.java index f423d223a..dbe63c611 100644 --- a/briar-core/src/main/java/org/briarproject/briar/autodelete/AutoDeleteModule.java +++ b/briar-core/src/main/java/org/briarproject/briar/autodelete/AutoDeleteModule.java @@ -1,16 +1,32 @@ package org.briarproject.briar.autodelete; +import org.briarproject.bramble.api.contact.ContactManager; +import org.briarproject.bramble.api.lifecycle.LifecycleManager; import org.briarproject.briar.api.autodelete.AutoDeleteManager; +import javax.inject.Inject; +import javax.inject.Singleton; + import dagger.Module; import dagger.Provides; @Module public class AutoDeleteModule { + public static class EagerSingletons { + @Inject + AutoDeleteManager autoDeleteManager; + } + @Provides + @Singleton AutoDeleteManager provideAutoDeleteManager( + LifecycleManager lifecycleManager, ContactManager contactManager, AutoDeleteManagerImpl autoDeleteManager) { + lifecycleManager.registerOpenDatabaseHook(autoDeleteManager); + contactManager.registerContactHook(autoDeleteManager); + // Don't need to register with the client versioning manager as this + // client's groups aren't shared with contacts return autoDeleteManager; } } diff --git a/briar-core/src/test/java/org/briarproject/briar/test/BriarIntegrationTestComponent.java b/briar-core/src/test/java/org/briarproject/briar/test/BriarIntegrationTestComponent.java index d0b5bf1d4..750275f78 100644 --- a/briar-core/src/test/java/org/briarproject/briar/test/BriarIntegrationTestComponent.java +++ b/briar-core/src/test/java/org/briarproject/briar/test/BriarIntegrationTestComponent.java @@ -65,6 +65,8 @@ public interface BriarIntegrationTestComponent void inject(BriarIntegrationTest init); + void inject(AutoDeleteModule.EagerSingletons init); + void inject(AvatarModule.EagerSingletons init); void inject(BlogModule.EagerSingletons init); @@ -135,6 +137,7 @@ public interface BriarIntegrationTestComponent BriarIntegrationTestComponent c) { BrambleCoreIntegrationTestEagerSingletons.Helper .injectEagerSingletons(c); + c.inject(new AutoDeleteModule.EagerSingletons()); c.inject(new AvatarModule.EagerSingletons()); c.inject(new BlogModule.EagerSingletons()); c.inject(new ForumModule.EagerSingletons()); From 9256c66fcca7a946be8b6f7e4f35833cd4912a42 Mon Sep 17 00:00:00 2001 From: akwizgran Date: Thu, 26 Nov 2020 13:45:41 +0000 Subject: [PATCH 018/124] Add unit tests for AutoDeleteManagerImpl. --- .../autodelete/AutoDeleteManagerImplTest.java | 182 ++++++++++++++++++ 1 file changed, 182 insertions(+) create mode 100644 briar-core/src/test/java/org/briarproject/briar/autodelete/AutoDeleteManagerImplTest.java diff --git a/briar-core/src/test/java/org/briarproject/briar/autodelete/AutoDeleteManagerImplTest.java b/briar-core/src/test/java/org/briarproject/briar/autodelete/AutoDeleteManagerImplTest.java new file mode 100644 index 000000000..ef2e83f77 --- /dev/null +++ b/briar-core/src/test/java/org/briarproject/briar/autodelete/AutoDeleteManagerImplTest.java @@ -0,0 +1,182 @@ +package org.briarproject.briar.autodelete; + +import org.briarproject.bramble.api.client.ClientHelper; +import org.briarproject.bramble.api.client.ContactGroupFactory; +import org.briarproject.bramble.api.contact.Contact; +import org.briarproject.bramble.api.data.BdfDictionary; +import org.briarproject.bramble.api.data.BdfEntry; +import org.briarproject.bramble.api.db.DatabaseComponent; +import org.briarproject.bramble.api.db.Transaction; +import org.briarproject.bramble.api.sync.Group; +import org.briarproject.bramble.api.sync.GroupFactory; +import org.briarproject.bramble.test.BrambleMockTestCase; +import org.jmock.Expectations; +import org.junit.Test; + +import static java.util.Collections.singletonList; +import static org.briarproject.bramble.api.client.ContactGroupConstants.GROUP_KEY_CONTACT_ID; +import static org.briarproject.bramble.test.TestUtils.getContact; +import static org.briarproject.bramble.test.TestUtils.getGroup; +import static org.briarproject.briar.api.autodelete.AutoDeleteConstants.MAX_AUTO_DELETE_TIMER_MS; +import static org.briarproject.briar.api.autodelete.AutoDeleteConstants.NO_AUTO_DELETE_TIMER; +import static org.briarproject.briar.api.autodelete.AutoDeleteManager.CLIENT_ID; +import static org.briarproject.briar.api.autodelete.AutoDeleteManager.MAJOR_VERSION; +import static org.briarproject.briar.autodelete.AutoDeleteConstants.GROUP_KEY_AUTO_DELETE_TIMER; +import static org.junit.Assert.assertEquals; + +public class AutoDeleteManagerImplTest extends BrambleMockTestCase { + + private final DatabaseComponent db = context.mock(DatabaseComponent.class); + private final ClientHelper clientHelper = context.mock(ClientHelper.class); + private final GroupFactory groupFactory = context.mock(GroupFactory.class); + private final ContactGroupFactory contactGroupFactory = + context.mock(ContactGroupFactory.class); + + private final Group localGroup = getGroup(CLIENT_ID, MAJOR_VERSION); + private final Group contactGroup = getGroup(CLIENT_ID, MAJOR_VERSION); + private final Contact contact = getContact(); + + private final AutoDeleteManagerImpl autoDeleteManager; + + public AutoDeleteManagerImplTest() { + context.checking(new Expectations() {{ + oneOf(contactGroupFactory) + .createLocalGroup(CLIENT_ID, MAJOR_VERSION); + will(returnValue(localGroup)); + }}); + autoDeleteManager = new AutoDeleteManagerImpl(db, clientHelper, + groupFactory, contactGroupFactory); + context.assertIsSatisfied(); + } + + @Test + public void testDoesNotAddContactGroupsAtStartupIfLocalGroupExists() + throws Exception { + Transaction txn = new Transaction(null, false); + + context.checking(new Expectations() {{ + oneOf(db).containsGroup(txn, localGroup.getId()); + will(returnValue(true)); + }}); + + autoDeleteManager.onDatabaseOpened(txn); + } + + @Test + public void testAddsContactGroupsAtStartupIfLocalGroupDoesNotExist() + throws Exception { + Transaction txn = new Transaction(null, false); + + context.checking(new Expectations() {{ + oneOf(db).containsGroup(txn, localGroup.getId()); + will(returnValue(false)); + oneOf(db).addGroup(txn, localGroup); + oneOf(db).getContacts(txn); + will(returnValue(singletonList(contact))); + }}); + expectGetContactGroup(); + context.checking(new Expectations() {{ + oneOf(db).addGroup(txn, contactGroup); + oneOf(clientHelper).setContactId(txn, contactGroup.getId(), + contact.getId()); + }}); + + autoDeleteManager.onDatabaseOpened(txn); + } + + @Test + public void testAddsContactGroupWhenContactIsAdded() throws Exception { + Transaction txn = new Transaction(null, false); + + expectGetContactGroup(); + context.checking(new Expectations() {{ + oneOf(db).addGroup(txn, contactGroup); + oneOf(clientHelper).setContactId(txn, contactGroup.getId(), + contact.getId()); + }}); + + autoDeleteManager.addingContact(txn, contact); + } + + @Test + public void testRemovesContactGroupWhenContactIsRemoved() throws Exception { + Transaction txn = new Transaction(null, false); + + expectGetContactGroup(); + context.checking(new Expectations() {{ + oneOf(db).removeGroup(txn, contactGroup); + }}); + + autoDeleteManager.removingContact(txn, contact); + } + + @Test + public void testStoresTimer() throws Exception { + Transaction txn = new Transaction(null, false); + long timer = MAX_AUTO_DELETE_TIMER_MS; + BdfDictionary meta = BdfDictionary.of( + new BdfEntry(GROUP_KEY_AUTO_DELETE_TIMER, timer)); + + expectGetContact(txn); + expectGetContactGroup(); + context.checking(new Expectations() {{ + oneOf(clientHelper).mergeGroupMetadata(txn, + contactGroup.getId(), meta); + }}); + + autoDeleteManager.setAutoDeleteTimer(txn, contact.getId(), timer); + } + + @Test + public void testRetrievesTimer() throws Exception { + Transaction txn = new Transaction(null, false); + long timer = MAX_AUTO_DELETE_TIMER_MS; + BdfDictionary meta = BdfDictionary.of( + new BdfEntry(GROUP_KEY_CONTACT_ID, contact.getId().getInt()), + new BdfEntry(GROUP_KEY_AUTO_DELETE_TIMER, timer)); + + expectGetContact(txn); + expectGetContactGroup(); + context.checking(new Expectations() {{ + oneOf(clientHelper).getGroupMetadataAsDictionary(txn, + contactGroup.getId()); + will(returnValue(meta)); + }}); + + assertEquals(timer, + autoDeleteManager.getAutoDeleteTimer(txn, contact.getId())); + } + + @Test + public void testReturnsConstantIfNoTimerIsStored() throws Exception { + Transaction txn = new Transaction(null, false); + BdfDictionary meta = BdfDictionary.of( + new BdfEntry(GROUP_KEY_CONTACT_ID, contact.getId().getInt())); + + expectGetContact(txn); + expectGetContactGroup(); + context.checking(new Expectations() {{ + oneOf(clientHelper).getGroupMetadataAsDictionary(txn, + contactGroup.getId()); + will(returnValue(meta)); + }}); + + assertEquals(NO_AUTO_DELETE_TIMER, + autoDeleteManager.getAutoDeleteTimer(txn, contact.getId())); + } + + private void expectGetContact(Transaction txn) throws Exception { + context.checking(new Expectations() {{ + oneOf(db).getContact(txn, contact.getId()); + will(returnValue(contact)); + }}); + } + + private void expectGetContactGroup() { + context.checking(new Expectations() {{ + oneOf(groupFactory).createGroup(CLIENT_ID, MAJOR_VERSION, + contact.getAuthor().getId().getBytes()); + will(returnValue(contactGroup)); + }}); + } +} From 0427b12d52aeca9c0725ce3a49a6e85f36acf57e Mon Sep 17 00:00:00 2001 From: akwizgran Date: Thu, 26 Nov 2020 13:45:58 +0000 Subject: [PATCH 019/124] Check that timer argument is legal before storing. --- .../briar/autodelete/AutoDeleteManagerImpl.java | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/briar-core/src/main/java/org/briarproject/briar/autodelete/AutoDeleteManagerImpl.java b/briar-core/src/main/java/org/briarproject/briar/autodelete/AutoDeleteManagerImpl.java index d00b515a8..ce83a3085 100644 --- a/briar-core/src/main/java/org/briarproject/briar/autodelete/AutoDeleteManagerImpl.java +++ b/briar-core/src/main/java/org/briarproject/briar/autodelete/AutoDeleteManagerImpl.java @@ -20,6 +20,8 @@ import org.briarproject.briar.api.autodelete.AutoDeleteManager; import javax.annotation.concurrent.Immutable; import javax.inject.Inject; +import static org.briarproject.briar.api.autodelete.AutoDeleteConstants.MAX_AUTO_DELETE_TIMER_MS; +import static org.briarproject.briar.api.autodelete.AutoDeleteConstants.MIN_AUTO_DELETE_TIMER_MS; import static org.briarproject.briar.api.autodelete.AutoDeleteConstants.NO_AUTO_DELETE_TIMER; import static org.briarproject.briar.autodelete.AutoDeleteConstants.GROUP_KEY_AUTO_DELETE_TIMER; @@ -83,6 +85,11 @@ class AutoDeleteManagerImpl @Override public void setAutoDeleteTimer(Transaction txn, ContactId c, long timer) throws DbException { + if (timer != NO_AUTO_DELETE_TIMER && + (timer < MIN_AUTO_DELETE_TIMER_MS || + timer > MAX_AUTO_DELETE_TIMER_MS)) { + throw new IllegalArgumentException(); + } try { Group g = getGroup(db.getContact(txn, c)); BdfDictionary meta = BdfDictionary.of( From 0dcf510466be21ed2341bbc0042d859ff328c33a Mon Sep 17 00:00:00 2001 From: Torsten Grote Date: Thu, 3 Dec 2020 10:21:08 -0300 Subject: [PATCH 020/124] Show bomb icon for messages with auto-destruct timer --- .../conversation/ConversationItem.java | 7 +++++- .../ConversationItemViewHolder.java | 8 +++++++ .../src/main/res/drawable/ic_bomb.xml | 9 ++++++++ .../list_item_conversation_msg_image.xml | 10 +++++++++ .../list_item_conversation_msg_image_text.xml | 10 +++++++++ .../list_item_conversation_msg_in_content.xml | 11 ++++++++++ .../layout/list_item_conversation_msg_out.xml | 13 +++++++++-- .../list_item_conversation_notice_in.xml | 22 +++++++++++++++++-- .../list_item_conversation_notice_out.xml | 18 ++++++++++++--- .../layout/list_item_conversation_request.xml | 21 ++++++++++++++++-- 10 files changed, 119 insertions(+), 10 deletions(-) create mode 100644 briar-android/src/main/res/drawable/ic_bomb.xml diff --git a/briar-android/src/main/java/org/briarproject/briar/android/conversation/ConversationItem.java b/briar-android/src/main/java/org/briarproject/briar/android/conversation/ConversationItem.java index a0cd5d54b..470a5fd2c 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/conversation/ConversationItem.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/conversation/ConversationItem.java @@ -22,7 +22,7 @@ abstract class ConversationItem { protected String text; private final MessageId id; private final GroupId groupId; - private final long time; + private final long time, autoDeleteTimer; private final boolean isIncoming; private boolean read, sent, seen; @@ -32,6 +32,7 @@ abstract class ConversationItem { this.id = h.getId(); this.groupId = h.getGroupId(); this.time = h.getTimestamp(); + this.autoDeleteTimer = h.getAutoDeleteTimer(); this.read = h.isRead(); this.sent = h.isSent(); this.seen = h.isSeen(); @@ -68,6 +69,10 @@ abstract class ConversationItem { return time; } + public long getAutoDeleteTimer() { + return autoDeleteTimer; + } + /** * Only useful for incoming messages. */ diff --git a/briar-android/src/main/java/org/briarproject/briar/android/conversation/ConversationItemViewHolder.java b/briar-android/src/main/java/org/briarproject/briar/android/conversation/ConversationItemViewHolder.java index 6a54584b4..7e9cd582d 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/conversation/ConversationItemViewHolder.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/conversation/ConversationItemViewHolder.java @@ -12,8 +12,11 @@ import androidx.annotation.UiThread; import androidx.constraintlayout.widget.ConstraintLayout; import androidx.recyclerview.widget.RecyclerView.ViewHolder; +import static android.view.View.GONE; +import static android.view.View.VISIBLE; import static org.briarproject.bramble.util.StringUtils.trim; import static org.briarproject.briar.android.util.UiUtils.formatDate; +import static org.briarproject.briar.api.autodelete.AutoDeleteConstants.NO_AUTO_DELETE_TIMER; @UiThread @NotNullByDefault @@ -26,6 +29,7 @@ abstract class ConversationItemViewHolder extends ViewHolder { private final OutItemViewHolder outViewHolder; private final TextView text; protected final TextView time; + private final View bomb; @Nullable private String itemKey = null; @@ -38,6 +42,7 @@ abstract class ConversationItemViewHolder extends ViewHolder { layout = v.findViewById(R.id.layout); text = v.findViewById(R.id.text); time = v.findViewById(R.id.time); + bomb = v.findViewById(R.id.bomb); } @CallSuper @@ -52,6 +57,9 @@ abstract class ConversationItemViewHolder extends ViewHolder { long timestamp = item.getTime(); time.setText(formatDate(time.getContext(), timestamp)); + boolean showBomb = item.getAutoDeleteTimer() != NO_AUTO_DELETE_TIMER; + bomb.setVisibility(showBomb ? VISIBLE : GONE); + if (outViewHolder != null) outViewHolder.bind(item); } diff --git a/briar-android/src/main/res/drawable/ic_bomb.xml b/briar-android/src/main/res/drawable/ic_bomb.xml new file mode 100644 index 000000000..c874afd02 --- /dev/null +++ b/briar-android/src/main/res/drawable/ic_bomb.xml @@ -0,0 +1,9 @@ + + + \ No newline at end of file diff --git a/briar-android/src/main/res/layout/list_item_conversation_msg_image.xml b/briar-android/src/main/res/layout/list_item_conversation_msg_image.xml index 020bca4b3..4e23ec880 100644 --- a/briar-android/src/main/res/layout/list_item_conversation_msg_image.xml +++ b/briar-android/src/main/res/layout/list_item_conversation_msg_image.xml @@ -68,6 +68,16 @@ android:layout_height="wrap_content" tools:text="Dec 24, 13:37" /> + + diff --git a/briar-android/src/main/res/layout/list_item_conversation_msg_image_text.xml b/briar-android/src/main/res/layout/list_item_conversation_msg_image_text.xml index 27056a3da..855a3ea54 100644 --- a/briar-android/src/main/res/layout/list_item_conversation_msg_image_text.xml +++ b/briar-android/src/main/res/layout/list_item_conversation_msg_image_text.xml @@ -67,6 +67,16 @@ android:layout_height="wrap_content" tools:text="Dec 24, 13:37" /> + + diff --git a/briar-android/src/main/res/layout/list_item_conversation_msg_in_content.xml b/briar-android/src/main/res/layout/list_item_conversation_msg_in_content.xml index a92cf249c..c691819b2 100644 --- a/briar-android/src/main/res/layout/list_item_conversation_msg_in_content.xml +++ b/briar-android/src/main/res/layout/list_item_conversation_msg_in_content.xml @@ -68,6 +68,17 @@ android:layout_height="wrap_content" tools:text="Dec 24, 13:37" /> + + diff --git a/briar-android/src/main/res/layout/list_item_conversation_msg_out.xml b/briar-android/src/main/res/layout/list_item_conversation_msg_out.xml index 6ac5ef61a..230d0d6e9 100644 --- a/briar-android/src/main/res/layout/list_item_conversation_msg_out.xml +++ b/briar-android/src/main/res/layout/list_item_conversation_msg_out.xml @@ -73,11 +73,20 @@ style="@style/TextMessage.Timestamp" android:layout_width="wrap_content" android:layout_height="wrap_content" - android:layout_marginEnd="6dp" - android:layout_marginRight="6dp" + android:layout_marginEnd="4dp" + android:layout_marginRight="4dp" android:textColor="@color/private_message_date_inverse" tools:text="Dec 24, 13:37" /> + + + + - \ No newline at end of file + diff --git a/briar-android/src/main/res/layout/list_item_conversation_notice_out.xml b/briar-android/src/main/res/layout/list_item_conversation_notice_out.xml index d99ae0ce6..31ac5be43 100644 --- a/briar-android/src/main/res/layout/list_item_conversation_notice_out.xml +++ b/briar-android/src/main/res/layout/list_item_conversation_notice_out.xml @@ -55,14 +55,26 @@ app:layout_constraintTop_toBottomOf="@+id/text" tools:text="Dec 24, 13:37" /> + + diff --git a/briar-android/src/main/res/layout/list_item_conversation_request.xml b/briar-android/src/main/res/layout/list_item_conversation_request.xml index 902d10fc3..f991c1634 100644 --- a/briar-android/src/main/res/layout/list_item_conversation_request.xml +++ b/briar-android/src/main/res/layout/list_item_conversation_request.xml @@ -68,10 +68,27 @@ style="@style/TextMessage.Timestamp" android:layout_width="wrap_content" android:layout_height="wrap_content" - app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintEnd_toStartOf="@+id/bomb" + app:layout_constraintHorizontal_bias="1.0" + app:layout_constraintHorizontal_chainStyle="packed" + app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@+id/acceptButton" tools:text="Dec 24, 13:37" /> + + - \ No newline at end of file + From 96a7e3c425fc92ccf580b662836594c3c62fac5d Mon Sep 17 00:00:00 2001 From: akwizgran Date: Thu, 3 Dec 2020 14:15:12 +0000 Subject: [PATCH 021/124] Send current minor version of messaging client to contacts. --- .../briarproject/briar/messaging/MessagingModule.java | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/briar-core/src/main/java/org/briarproject/briar/messaging/MessagingModule.java b/briar-core/src/main/java/org/briarproject/briar/messaging/MessagingModule.java index 945142ef6..c9a55cff8 100644 --- a/briar-core/src/main/java/org/briarproject/briar/messaging/MessagingModule.java +++ b/briar-core/src/main/java/org/briarproject/briar/messaging/MessagingModule.java @@ -1,6 +1,5 @@ package org.briarproject.briar.messaging; -import org.briarproject.bramble.api.FeatureFlags; import org.briarproject.bramble.api.contact.ContactManager; import org.briarproject.bramble.api.data.BdfReaderFactory; import org.briarproject.bramble.api.data.MetadataEncoder; @@ -20,6 +19,7 @@ import dagger.Provides; import static org.briarproject.briar.api.messaging.MessagingManager.CLIENT_ID; import static org.briarproject.briar.api.messaging.MessagingManager.MAJOR_VERSION; +import static org.briarproject.briar.api.messaging.MessagingManager.MINOR_VERSION; @Module public class MessagingModule { @@ -57,17 +57,14 @@ public class MessagingModule { ContactManager contactManager, ValidationManager validationManager, ConversationManager conversationManager, ClientVersioningManager clientVersioningManager, - FeatureFlags featureFlags, MessagingManagerImpl messagingManager) { + MessagingManagerImpl messagingManager) { lifecycleManager.registerOpenDatabaseHook(messagingManager); contactManager.registerContactHook(messagingManager); validationManager.registerIncomingMessageHook(CLIENT_ID, MAJOR_VERSION, messagingManager); conversationManager.registerConversationClient(messagingManager); - // Advertise the current or previous minor version depending on the - // feature flag - int minorVersion = featureFlags.shouldEnableImageAttachments() ? 2 : 0; clientVersioningManager.registerClient(CLIENT_ID, MAJOR_VERSION, - minorVersion, messagingManager); + MINOR_VERSION, messagingManager); return messagingManager; } From 8488499da6267f04b1f7117fa2db3fa22444043a Mon Sep 17 00:00:00 2001 From: akwizgran Date: Mon, 30 Nov 2020 09:48:37 +0000 Subject: [PATCH 022/124] Add transactional variant of getGroupCount(). --- .../briarproject/briar/messaging/ConversationManagerImpl.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) 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 1ae846725..7d06d5efa 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 @@ -89,8 +89,7 @@ class ConversationManagerImpl implements ConversationManager { @Override public DeletionResult deleteMessages(ContactId c, - Collection toDelete) - throws DbException { + Collection toDelete) throws DbException { return db.transactionWithResult(false, txn -> { DeletionResult result = new DeletionResult(); for (ConversationClient client : clients) { From 751c5a32459bc419faff83f4cff766768adf0ae6 Mon Sep 17 00:00:00 2001 From: akwizgran Date: Tue, 1 Dec 2020 15:55:37 +0000 Subject: [PATCH 023/124] Move lookup of latest conversation timestamp to core. --- .../conversation/ConversationActivity.java | 19 +-- .../conversation/ConversationViewModel.java | 21 +-- .../introduction/IntroductionViewModel.java | 3 +- .../api/conversation/ConversationManager.java | 7 + .../api/introduction/IntroductionManager.java | 6 +- .../introduction/AbstractProtocolEngine.java | 20 ++- .../IntroduceeProtocolEngine.java | 52 ++++--- .../IntroducerProtocolEngine.java | 130 ++++++++++-------- .../introduction/IntroductionManagerImpl.java | 15 +- .../briar/introduction/ProtocolEngine.java | 12 +- .../messaging/ConversationManagerImpl.java | 15 +- .../IntroductionIntegrationTest.java | 101 +++++--------- 12 files changed, 204 insertions(+), 197 deletions(-) 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 4b504cf28..692a46a28 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 @@ -736,18 +736,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)); @@ -955,13 +947,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); @@ -1037,9 +1027,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 0e2c4a60a..d81f72958 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 @@ -35,6 +35,7 @@ import org.briarproject.briar.android.viewmodel.MutableLiveEvent; import org.briarproject.briar.api.attachment.AttachmentHeader; import org.briarproject.briar.api.autodelete.AutoDeleteManager; import org.briarproject.briar.api.avatar.event.AvatarUpdatedEvent; +import org.briarproject.briar.api.conversation.ConversationManager; import org.briarproject.briar.api.identity.AuthorInfo; import org.briarproject.briar.api.identity.AuthorManager; import org.briarproject.briar.api.messaging.MessagingManager; @@ -90,6 +91,7 @@ public class ConversationViewModel extends DbViewModel private final AttachmentRetriever attachmentRetriever; private final AttachmentCreator attachmentCreator; private final AutoDeleteManager autoDeleteManager; + private final ConversationManager conversationManager; @Nullable private ContactId contactId = null; @@ -125,7 +127,8 @@ public class ConversationViewModel extends DbViewModel PrivateMessageFactory privateMessageFactory, AttachmentRetriever attachmentRetriever, AttachmentCreator attachmentCreator, - AutoDeleteManager autoDeleteManager) { + AutoDeleteManager autoDeleteManager, + ConversationManager conversationManager) { super(application, dbExecutor, lifecycleManager, db, androidExecutor); this.db = db; this.eventBus = eventBus; @@ -137,6 +140,7 @@ public class ConversationViewModel extends DbViewModel this.attachmentRetriever = attachmentRetriever; this.attachmentCreator = attachmentCreator; this.autoDeleteManager = autoDeleteManager; + this.conversationManager = conversationManager; messagingGroupId = map(contactItem, c -> messagingManager.getContactGroup(c.getContact()).getId()); contactDeleted.setValue(false); @@ -244,14 +248,13 @@ public class ConversationViewModel extends DbViewModel } @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)); }); } @@ -313,8 +316,10 @@ public class ConversationViewModel extends DbViewModel 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( @@ -335,13 +340,13 @@ public class ConversationViewModel extends DbViewModel @UiThread private void storeMessage(ContactId c, GroupId groupId, @Nullable String text, List headers, - long timestamp, PrivateMessageFormat format) { + PrivateMessageFormat format) { runOnDbThread(() -> { 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/IntroductionViewModel.java b/briar-android/src/main/java/org/briarproject/briar/android/introduction/IntroductionViewModel.java index 94ea3a4f3..399c4f64d 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/introduction/IntroductionViewModel.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/introduction/IntroductionViewModel.java @@ -165,10 +165,9 @@ class IntroductionViewModel extends ContactsViewModel { runOnDbThread(() -> { // actually make the introduction try { - long timestamp = System.currentTimeMillis(); introductionManager.makeIntroduction( info.getContact1().getContact(), - info.getContact2().getContact(), text, timestamp); + info.getContact2().getContact(), text); } catch (DbException e) { logException(LOG, WARNING, e); androidExecutor.runOnUiThread(() -> Toast.makeText( 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 e44adbd7d..cecbe7a36 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 @@ -48,6 +48,13 @@ public interface ConversationManager { */ GroupCount getGroupCount(Transaction txn, ContactId c) throws DbException; + /** + * Returns a timestamp for an outgoing message, which is later than the + * timestamp of any visible message sent or received so far. + */ + 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-core/src/main/java/org/briarproject/briar/introduction/AbstractProtocolEngine.java b/briar-core/src/main/java/org/briarproject/briar/introduction/AbstractProtocolEngine.java index 0444a5e15..95e500e94 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 @@ -20,11 +20,11 @@ import org.briarproject.bramble.api.properties.TransportProperties; import org.briarproject.bramble.api.sync.GroupId; import org.briarproject.bramble.api.sync.Message; import org.briarproject.bramble.api.sync.MessageId; -import org.briarproject.bramble.api.system.Clock; import org.briarproject.bramble.api.versioning.ClientVersioningManager; import org.briarproject.briar.api.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.identity.AuthorInfo; import org.briarproject.briar.api.identity.AuthorManager; import org.briarproject.briar.api.introduction.IntroductionResponse; @@ -61,7 +61,7 @@ abstract class AbstractProtocolEngine> protected final MessageEncoder messageEncoder; protected final ClientVersioningManager clientVersioningManager; protected final AutoDeleteManager autoDeleteManager; - protected final Clock clock; + protected final ConversationManager conversationManager; AbstractProtocolEngine( DatabaseComponent db, @@ -75,7 +75,7 @@ abstract class AbstractProtocolEngine> MessageEncoder messageEncoder, ClientVersioningManager clientVersioningManager, AutoDeleteManager autoDeleteManager, - Clock clock) { + ConversationManager conversationManager) { this.db = db; this.clientHelper = clientHelper; this.contactManager = contactManager; @@ -87,7 +87,7 @@ abstract class AbstractProtocolEngine> this.messageEncoder = messageEncoder; this.clientVersioningManager = clientVersioningManager; this.autoDeleteManager = autoDeleteManager; - this.clock = clock; + this.conversationManager = conversationManager; } Message sendRequestMessage(Transaction txn, PeerSession s, @@ -231,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 99e20927f..8031115fe 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 @@ -22,7 +22,6 @@ import org.briarproject.bramble.api.properties.TransportProperties; import org.briarproject.bramble.api.properties.TransportPropertyManager; import org.briarproject.bramble.api.sync.Message; import org.briarproject.bramble.api.sync.MessageId; -import org.briarproject.bramble.api.system.Clock; import org.briarproject.bramble.api.transport.KeyManager; import org.briarproject.bramble.api.transport.KeySetId; import org.briarproject.bramble.api.versioning.ClientVersioningManager; @@ -30,6 +29,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.identity.AuthorInfo; import org.briarproject.briar.api.identity.AuthorManager; import org.briarproject.briar.api.introduction.IntroductionRequest; @@ -44,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; @@ -77,16 +78,16 @@ class IntroduceeProtocolEngine AuthorManager authorManager, MessageParser messageParser, MessageEncoder messageEncoder, - Clock clock, IntroductionCrypto crypto, KeyManager keyManager, TransportPropertyManager transportPropertyManager, ClientVersioningManager clientVersioningManager, - AutoDeleteManager autoDeleteManager) { + AutoDeleteManager autoDeleteManager, + ConversationManager conversationManager) { super(db, clientHelper, contactManager, contactGroupFactory, messageTracker, identityManager, authorManager, messageParser, messageEncoder, clientVersioningManager, autoDeleteManager, - clock); + conversationManager); this.crypto = crypto; this.keyManager = keyManager; this.transportPropertyManager = transportPropertyManager; @@ -94,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: @@ -119,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: @@ -275,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); @@ -287,7 +288,7 @@ class IntroduceeProtocolEngine transportPropertyManager.getLocalProperties(txn); // Send a ACCEPT message - long localTimestamp = Math.max(timestamp + 1, getLocalTimestamp(s)); + long localTimestamp = getLocalTimestamp(txn, s); Message sent = sendAcceptMessage(txn, s, localTimestamp, publicKey, localTimestamp, transportProperties, true); // Track the message @@ -312,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 = getLocalTimestamp(txn, s); Message sent = sendDeclineMessage(txn, s, localTimestamp, true); // Track the message @@ -415,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 = getLocalTimestamp(txn, s); + Message sent = sendAuthMessage(txn, s, localTimestamp, mac, signature); return IntroduceeSession.addLocalAuth(s, AWAIT_AUTH, sent, masterKey, aliceMacKey, bobMacKey); } @@ -465,7 +466,8 @@ class IntroduceeProtocolEngine // send ACTIVATE message with a MAC byte[] mac = crypto.activateMac(s); - Message sent = sendActivateMessage(txn, s, getLocalTimestamp(s), mac); + long localTimestamp = getLocalTimestamp(txn, 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); @@ -516,7 +518,8 @@ class IntroduceeProtocolEngine markRequestsUnavailableToAnswer(txn, s); // Send an ABORT message - Message sent = sendAbortMessage(txn, s, getLocalTimestamp(s)); + long localTimestamp = getLocalTimestamp(txn, s); + Message sent = sendAbortMessage(txn, s, localTimestamp); // Broadcast abort event for testing txn.attach(new IntroductionAbortedEvent(s.getSessionId())); @@ -531,9 +534,18 @@ class IntroduceeProtocolEngine return isInvalidDependency(s.getLastRemoteMessageId(), dependency); } - private long getLocalTimestamp(IntroduceeSession s) { - return getLocalTimestamp(s.getLocalTimestamp(), - s.getRequestTimestamp()); + /** + * Returns a timestamp for an outgoing message, which is later than the + * timestamp of any message sent or received so far in the conversation + * or the session. + */ + private long getLocalTimestamp(Transaction txn, IntroduceeSession s) + throws DbException { + long conversationTimestamp = + getTimestampForOutgoingMessage(txn, s.getContactGroupId()); + long sessionTimestamp = + max(s.getLocalTimestamp(), s.getRequestTimestamp()) + 1; + return max(conversationTimestamp, sessionTimestamp); } 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 bd784c0b1..fc4040d1f 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 @@ -12,11 +12,11 @@ import org.briarproject.bramble.api.nullsafety.NotNullByDefault; import org.briarproject.bramble.api.sync.GroupId; import org.briarproject.bramble.api.sync.Message; import org.briarproject.bramble.api.sync.MessageId; -import org.briarproject.bramble.api.system.Clock; import org.briarproject.bramble.api.versioning.ClientVersioningManager; import org.briarproject.briar.api.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.identity.AuthorManager; import org.briarproject.briar.api.introduction.event.IntroductionAbortedEvent; import org.briarproject.briar.introduction.IntroducerSession.Introducee; @@ -25,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; @@ -56,20 +57,20 @@ class IntroducerProtocolEngine MessageEncoder messageEncoder, ClientVersioningManager clientVersioningManager, AutoDeleteManager autoDeleteManager, - Clock clock) { + ConversationManager conversationManager) { super(db, clientHelper, contactManager, contactGroupFactory, messageTracker, identityManager, authorManager, messageParser, messageEncoder, clientVersioningManager, autoDeleteManager, - clock); + conversationManager); } @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: @@ -89,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 @@ -229,13 +217,11 @@ 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 = getLocalTimestamp(txn, s, s.getIntroduceeA()); + long timestampB = getLocalTimestamp(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(), @@ -275,11 +261,10 @@ 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); + long localTimestamp = getLocalTimestamp(txn, s, i); + Message sent = sendAcceptMessage(txn, i, localTimestamp, + m.getEphemeralPublicKey(), m.getAcceptTimestamp(), + m.getTransportProperties(), false); // Create the next state IntroducerState state = AWAIT_AUTHS; @@ -336,7 +321,8 @@ class IntroducerProtocolEngine // Forward ACCEPT message Introducee i = getOtherIntroducee(s, m.getGroupId()); - Message sent = sendAcceptMessage(txn, i, getLocalTimestamp(s, i), + long localTimestamp = getLocalTimestamp(txn, s, i); + Message sent = sendAcceptMessage(txn, i, localTimestamp, m.getEphemeralPublicKey(), m.getAcceptTimestamp(), m.getTransportProperties(), false); @@ -387,8 +373,8 @@ class IntroducerProtocolEngine // Forward DECLINE message Introducee i = getOtherIntroducee(s, m.getGroupId()); - long timestamp = getLocalTimestamp(s, i); - Message sent = sendDeclineMessage(txn, i, timestamp, false); + long localTimestamp = getLocalTimestamp(txn, s, i); + Message sent = sendDeclineMessage(txn, i, localTimestamp, false); // Create the next state IntroducerState state = START; @@ -439,8 +425,8 @@ class IntroducerProtocolEngine // Forward DECLINE message Introducee i = getOtherIntroducee(s, m.getGroupId()); - long timestamp = getLocalTimestamp(s, i); - Message sent = sendDeclineMessage(txn, i, timestamp, false); + long localTimestamp = getLocalTimestamp(txn, s, i); + Message sent = sendDeclineMessage(txn, i, localTimestamp, false); Introducee introduceeA, introduceeB; Author sender, other; @@ -480,8 +466,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 = getLocalTimestamp(txn, s, i); + Message sent = sendAuthMessage(txn, i, localTimestamp, m.getMac(), m.getSignature()); // Move to the next state @@ -516,8 +502,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 = getLocalTimestamp(txn, s, i); + Message sent = sendActivateMessage(txn, i, localTimestamp, m.getMac()); // Move to the next state IntroducerState state = START; @@ -539,8 +525,9 @@ 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 = max(i.getLocalTimestamp(), + s.getRequestTimestamp()) + 1; + Message sent = sendAbortMessage(txn, i, localTimestamp); // Broadcast abort event for testing txn.attach(new IntroductionAbortedEvent(s.getSessionId())); @@ -558,15 +545,42 @@ 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 = getLocalTimestamp(txn, 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 = getLocalTimestamp(txn, s, s.getIntroduceeA()); Message sentA = sendAbortMessage(txn, s.getIntroduceeA(), timestampA); - long timestampB = getLocalTimestamp(s, s.getIntroduceeB()); + long timestampB = getLocalTimestamp(txn, s, s.getIntroduceeB()); Message sentB = sendAbortMessage(txn, s.getIntroduceeB(), timestampB); // Reset the session back to initial state Introducee introduceeA = new Introducee(s.getIntroduceeA(), sentA); @@ -596,9 +610,17 @@ class IntroducerProtocolEngine return isInvalidDependency(expected, dependency); } - private long getLocalTimestamp(IntroducerSession s, PeerSession p) { - return getLocalTimestamp(p.getLocalTimestamp(), - s.getRequestTimestamp()); + /** + * Returns a timestamp for an outgoing message, which is later than the + * timestamp of any message sent or received so far in the conversation + * or the session. + */ + private long getLocalTimestamp(Transaction txn, IntroducerSession s, + PeerSession p) throws DbException { + long conversationTimestamp = + getTimestampForOutgoingMessage(txn, p.getContactGroupId()); + long sessionTimestamp = + max(p.getLocalTimestamp(), s.getRequestTimestamp()) + 1; + return max(conversationTimestamp, sessionTimestamp); } - } 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 48eb1df7a..f3c232330 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 @@ -315,8 +315,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 @@ -348,8 +348,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); @@ -362,7 +361,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 @@ -380,11 +379,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 7d06d5efa..1abbf6461 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<>(); } @@ -76,6 +81,14 @@ class ConversationManagerImpl implements ConversationManager { 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 -> { 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); From f459beccdb6f2109b3398515bb55807894ba5c6b Mon Sep 17 00:00:00 2001 From: akwizgran Date: Tue, 1 Dec 2020 16:21:06 +0000 Subject: [PATCH 024/124] Move lookup of latest conversation timestamp to core for blog and forum sharing. --- .../sharing/ShareBlogControllerImpl.java | 17 +-- .../sharing/ShareForumControllerImpl.java | 17 +-- .../api/conversation/ConversationManager.java | 2 +- .../briar/api/sharing/SharingManager.java | 2 +- .../briar/sharing/BlogProtocolEngineImpl.java | 11 +- .../sharing/ForumProtocolEngineImpl.java | 12 +- .../briar/sharing/ProtocolEngine.java | 2 +- .../briar/sharing/ProtocolEngineImpl.java | 54 +++++--- .../briar/sharing/SharingManagerImpl.java | 4 +- .../briar/forum/ForumManagerTest.java | 6 +- .../sharing/BlogSharingIntegrationTest.java | 22 ++-- .../sharing/ForumSharingIntegrationTest.java | 123 +++++++++--------- 12 files changed, 128 insertions(+), 144 deletions(-) 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 abff0f41d..f07cdd130 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 org.briarproject.briar.api.identity.AuthorManager; import java.util.Collection; @@ -26,6 +24,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 @@ -34,22 +33,17 @@ 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, AuthorManager authorManager, - ConversationManager conversationManager, - BlogSharingManager blogSharingManager, Clock clock) { + BlogSharingManager blogSharingManager) { super(dbExecutor, lifecycleManager, contactManager, authorManager); - this.conversationManager = conversationManager; this.blogSharingManager = blogSharingManager; - this.clock = clock; } @Override @@ -64,10 +58,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 1ab210d2e..dcbf5af91 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 org.briarproject.briar.api.identity.AuthorManager; @@ -26,6 +24,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 @@ -34,22 +33,17 @@ 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, AuthorManager authorManager, - ConversationManager conversationManager, - ForumSharingManager forumSharingManager, Clock clock) { + ForumSharingManager forumSharingManager) { super(dbExecutor, lifecycleManager, contactManager, authorManager); - this.conversationManager = conversationManager; this.forumSharingManager = forumSharingManager; - this.clock = clock; } @Override @@ -64,10 +58,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 cecbe7a36..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 @@ -50,7 +50,7 @@ public interface ConversationManager { /** * Returns a timestamp for an outgoing message, which is later than the - * timestamp of any visible message sent or received so far. + * timestamp of any message in the conversation with the given contact. */ long getTimestampForOutgoingMessage(Transaction txn, ContactId c) throws DbException; 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 2170744ed..e3de2fd91 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 @@ -22,7 +22,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/sharing/BlogProtocolEngineImpl.java b/briar-core/src/main/java/org/briarproject/briar/sharing/BlogProtocolEngineImpl.java index 05fcc2eb0..7ffa0679e 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 @@ -9,7 +9,6 @@ import org.briarproject.bramble.api.db.Transaction; import org.briarproject.bramble.api.event.Event; import org.briarproject.bramble.api.nullsafety.NotNullByDefault; import org.briarproject.bramble.api.sync.MessageId; -import org.briarproject.bramble.api.system.Clock; import org.briarproject.bramble.api.versioning.ClientVersioningManager; import org.briarproject.briar.api.autodelete.AutoDeleteManager; import org.briarproject.briar.api.blog.Blog; @@ -19,6 +18,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 +41,14 @@ class BlogProtocolEngineImpl extends ProtocolEngineImpl { MessageParser messageParser, MessageTracker messageTracker, AutoDeleteManager autoDeleteManager, - Clock clock, + ConversationManager conversationManager, 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, 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..55a1b76f3 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 @@ -9,10 +9,10 @@ import org.briarproject.bramble.api.db.Transaction; import org.briarproject.bramble.api.event.Event; import org.briarproject.bramble.api.nullsafety.NotNullByDefault; import org.briarproject.bramble.api.sync.MessageId; -import org.briarproject.bramble.api.system.Clock; import org.briarproject.bramble.api.versioning.ClientVersioningManager; import org.briarproject.briar.api.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 +41,14 @@ class ForumProtocolEngineImpl extends ProtocolEngineImpl { MessageParser messageParser, MessageTracker messageTracker, AutoDeleteManager autoDeleteManager, - Clock clock, + ConversationManager conversationManager, 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, 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..21503179e 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 @@ -16,11 +16,11 @@ import org.briarproject.bramble.api.sync.Group.Visibility; import org.briarproject.bramble.api.sync.GroupId; import org.briarproject.bramble.api.sync.Message; import org.briarproject.bramble.api.sync.MessageId; -import org.briarproject.bramble.api.system.Clock; import org.briarproject.bramble.api.versioning.ClientVersioningManager; import org.briarproject.briar.api.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 +29,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,7 +59,7 @@ abstract class ProtocolEngineImpl private final MessageEncoder messageEncoder; private final MessageTracker messageTracker; private final AutoDeleteManager autoDeleteManager; - private final Clock clock; + private final ConversationManager conversationManager; private final ClientId sharingClientId, shareableClientId; private final int sharingClientMajorVersion, shareableClientMajorVersion; @@ -70,7 +71,7 @@ abstract class ProtocolEngineImpl MessageParser messageParser, MessageTracker messageTracker, AutoDeleteManager autoDeleteManager, - Clock clock, + ConversationManager conversationManager, ClientId sharingClientId, int sharingClientMajorVersion, ClientId shareableClientId, @@ -82,7 +83,7 @@ abstract class ProtocolEngineImpl this.messageParser = messageParser; this.messageTracker = messageTracker; this.autoDeleteManager = autoDeleteManager; - this.clock = clock; + this.conversationManager = conversationManager; this.sharingClientId = sharingClientId; this.sharingClientMajorVersion = sharingClientMajorVersion; this.shareableClientId = shareableClientId; @@ -91,10 +92,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 +108,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 +126,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,7 +134,7 @@ abstract class ProtocolEngineImpl } catch (FormatException e) { throw new DbException(e); // Invalid group descriptor } - long localTimestamp = Math.max(timestamp, getLocalTimestamp(s)); + long localTimestamp = getLocalTimestamp(txn, s); Message m; ContactId c = getContactId(txn, s.getContactGroupId()); if (contactSupportsAutoDeletion(txn, c)) { @@ -201,16 +202,17 @@ abstract class ProtocolEngineImpl private Message sendAcceptMessage(Transaction txn, Session s) throws DbException { Message m; + long localTimestamp = getLocalTimestamp(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 +256,17 @@ abstract class ProtocolEngineImpl private Message sendDeclineMessage(Transaction txn, Session s) throws DbException { Message m; + long localTimestamp = getLocalTimestamp(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 +310,10 @@ abstract class ProtocolEngineImpl private Message sendLeaveMessage(Transaction txn, Session session) throws DbException { + long localTimestamp = getLocalTimestamp(txn, 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 +609,10 @@ abstract class ProtocolEngineImpl private Message sendAbortMessage(Transaction txn, Session session) throws DbException { + long localTimestamp = getLocalTimestamp(txn, 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 +682,19 @@ 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 an outgoing message, which is later than the + * timestamp of any message sent or received so far in the conversation + * or the session. + */ + private long getLocalTimestamp(Transaction txn, Session session) + throws DbException { + ContactId c = getContactId(txn, session.getContactGroupId()); + long conversationTimestamp = + conversationManager.getTimestampForOutgoingMessage(txn, c); + long sessionTimestamp = max(session.getLocalTimestamp(), + session.getInviteTimestamp()) + 1; + return max(conversationTimestamp, sessionTimestamp); } 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 ae1980ef4..63803c341 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/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); From 6e6923b10838bc3f12043338b121b57845746964 Mon Sep 17 00:00:00 2001 From: akwizgran Date: Tue, 1 Dec 2020 17:21:09 +0000 Subject: [PATCH 025/124] Look up conversation timestamp when creating group invitation messages. --- .../creation/CreateGroupControllerImpl.java | 77 ++++++++++++------- .../invitation/AbstractProtocolEngine.java | 35 ++++++--- .../invitation/CreatorProtocolEngine.java | 7 +- .../invitation/InviteeProtocolEngine.java | 7 +- .../invitation/PeerProtocolEngine.java | 4 +- .../invitation/ProtocolEngineFactoryImpl.java | 10 ++- .../AbstractProtocolEngineTest.java | 10 ++- .../invitation/CreatorProtocolEngineTest.java | 3 +- .../invitation/InviteeProtocolEngineTest.java | 3 +- .../invitation/PeerProtocolEngineTest.java | 3 +- 10 files changed, 107 insertions(+), 52 deletions(-) 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 809f224e6..6e62bfb14 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,7 @@ 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.TransactionManager; import org.briarproject.bramble.api.identity.IdentityManager; import org.briarproject.bramble.api.identity.LocalAuthor; import org.briarproject.bramble.api.lifecycle.LifecycleManager; @@ -15,6 +16,7 @@ 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.conversation.ConversationManager; import org.briarproject.briar.api.identity.AuthorManager; import org.briarproject.briar.api.privategroup.GroupMessage; import org.briarproject.briar.api.privategroup.GroupMessageFactory; @@ -36,6 +38,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 @@ -44,9 +48,11 @@ 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 ConversationManager conversationManager; private final ContactManager contactManager; private final IdentityManager identityManager; private final PrivateGroupFactory groupFactory; @@ -57,17 +63,25 @@ class CreateGroupControllerImpl extends ContactSelectorControllerImpl private final Clock clock; @Inject - CreateGroupControllerImpl(@DatabaseExecutor Executor dbExecutor, + CreateGroupControllerImpl( + @DatabaseExecutor Executor dbExecutor, @CryptoExecutor Executor cryptoExecutor, - LifecycleManager lifecycleManager, ContactManager contactManager, - AuthorManager authorManager, IdentityManager identityManager, + TransactionManager db, + ConversationManager conversationManager, + LifecycleManager lifecycleManager, + ContactManager contactManager, + AuthorManager authorManager, + IdentityManager identityManager, PrivateGroupFactory groupFactory, GroupMessageFactory groupMessageFactory, PrivateGroupManager groupManager, GroupInvitationFactory groupInvitationFactory, - GroupInvitationManager groupInvitationManager, Clock clock) { + GroupInvitationManager groupInvitationManager, + Clock clock) { super(dbExecutor, lifecycleManager, contactManager, authorManager); this.cryptoExecutor = cryptoExecutor; + this.db = db; + this.conversationManager = conversationManager; this.contactManager = contactManager; this.identityManager = identityManager; this.groupFactory = groupFactory; @@ -131,16 +145,24 @@ 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 + db.transaction(true, txn -> { + List contexts = new ArrayList<>(); + LocalAuthor localAuthor = + identityManager.getLocalAuthor(txn); + for (ContactId c : contactIds) { + try { + Contact contact = contactManager.getContact(txn, c); + long timestamp = conversationManager + .getTimestampForOutgoingMessage(txn, c); + contexts.add( + new InvitationContext(contact, timestamp)); + } catch (NoSuchContactException e) { + // Continue + } } - } - signInvitations(g, localAuthor, contacts, text, handler); + txn.attach(() -> signInvitations(g, localAuthor, contexts, + text, handler)); + }); } catch (DbException e) { logException(LOG, WARNING, e); handler.onException(e); @@ -149,16 +171,13 @@ class CreateGroupControllerImpl extends ContactSelectorControllerImpl } 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, timestamp, localAuthor.getPrivateKey()); } sendInvitations(g, contexts, text, handler); }); @@ -172,8 +191,9 @@ class CreateGroupControllerImpl extends ContactSelectorControllerImpl for (InvitationContext context : contexts) { try { groupInvitationManager.sendInvitation(g, - context.contactId, text, context.timestamp, - context.signature); + context.contact.getId(), text, + context.timestamp, + requireNonNull(context.signature)); } catch (NoSuchContactException e) { // Continue } @@ -188,15 +208,14 @@ class CreateGroupControllerImpl extends ContactSelectorControllerImpl private static class InvitationContext { - private final ContactId contactId; + private final Contact contact; private final long timestamp; - private final byte[] signature; + @Nullable + private byte[] signature = null; - private InvitationContext(ContactId contactId, long timestamp, - byte[] signature) { - this.contactId = contactId; + private InvitationContext(Contact contact, long timestamp) { + this.contact = contact; this.timestamp = timestamp; - this.signature = signature; } } } 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..ee275abf2 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; } @@ -142,6 +147,7 @@ abstract class AbstractProtocolEngine> Message sendJoinMessage(Transaction txn, S s, boolean visibleInUi) throws DbException { Message m; + long localTimestamp = getLocalTimestamp(txn, s); ContactId c = getContactId(txn, s.getContactGroupId()); if (contactSupportsAutoDeletion(txn, c)) { // Set auto-delete timer if manually accepting an invitation @@ -149,13 +155,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 +172,7 @@ abstract class AbstractProtocolEngine> Message sendLeaveMessage(Transaction txn, S s, boolean visibleInUi) throws DbException { Message m; + long localTimestamp = getLocalTimestamp(txn, s); ContactId c = getContactId(txn, s.getContactGroupId()); if (contactSupportsAutoDeletion(txn, c)) { // Set auto-delete timer if manually accepting an invitation @@ -173,13 +180,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 +197,7 @@ abstract class AbstractProtocolEngine> Message sendAbortMessage(Transaction txn, S session) throws DbException { Message m = messageEncoder.encodeAbortMessage( session.getContactGroupId(), session.getPrivateGroupId(), - getLocalTimestamp(session)); + getLocalTimestamp(txn, session)); sendMessage(txn, m, ABORT, session.getPrivateGroupId(), false, NO_AUTO_DELETE_TIMER); return m; @@ -246,7 +253,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 +263,18 @@ 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 an outgoing message, which is later than the + * timestamp of any message sent or received so far in the conversation + * or the session. + */ + long getLocalTimestamp(Transaction txn, S s) throws DbException { + ContactId c = getContactId(txn, s.getContactGroupId()); + long conversationTimestamp = + conversationManager.getTimestampForOutgoingMessage(txn, c); + long sessionTimestamp = + max(s.getLocalTimestamp(), s.getInviteTimestamp()) + 1; + return max(conversationTimestamp, sessionTimestamp); } 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..ebb9ad2c4 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,11 +51,12 @@ 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 @@ -159,7 +162,7 @@ class CreatorProtocolEngine extends AbstractProtocolEngine { // Track the message messageTracker.trackOutgoingMessage(txn, sent); // Move to the INVITED state - long localTimestamp = Math.max(timestamp, getLocalTimestamp(s)); + long localTimestamp = max(timestamp, getLocalTimestamp(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/InviteeProtocolEngine.java b/briar-core/src/main/java/org/briarproject/briar/privategroup/invitation/InviteeProtocolEngine.java index dbc17477f..3ee96b9f9 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,11 +55,12 @@ 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 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..8f57c7e4e 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,11 +50,12 @@ 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 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/test/java/org/briarproject/briar/privategroup/invitation/AbstractProtocolEngineTest.java b/briar-core/src/test/java/org/briarproject/briar/privategroup/invitation/AbstractProtocolEngineTest.java index 1f2f85008..2ceff9376 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,9 +118,12 @@ abstract class AbstractProtocolEngineTest extends BrambleMockTestCase { assertEquals(inviteTimestamp, s.getInviteTimestamp()); } - void expectGetLocalTimestamp(long time) { + void expectGetLocalTimestamp(long time) throws Exception { context.checking(new Expectations() {{ - oneOf(clock).currentTimeMillis(); + oneOf(clientHelper).getContactId(txn, contactGroupId); + will(returnValue(contactId)); + oneOf(conversationManager) + .getTimestampForOutgoingMessage(txn, contactId); will(returnValue(time)); }}); } 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..2e967228f 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, 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..f8552e09f 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) { 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..533246f6a 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, From efc56a8724f14c244af7edaef411e6fe880dbda3 Mon Sep 17 00:00:00 2001 From: akwizgran Date: Tue, 1 Dec 2020 17:38:49 +0000 Subject: [PATCH 026/124] Provide TransactionManager. --- .../java/org/briarproject/briar/android/AndroidComponent.java | 3 +++ 1 file changed, 3 insertions(+) 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 5e04f88eb..a19df2e7d 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 @@ -46,6 +46,7 @@ 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.attachment.AttachmentReader; +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; @@ -188,6 +189,8 @@ public interface AndroidComponent Thread.UncaughtExceptionHandler exceptionHandler(); + AutoDeleteManager autoDeleteManager(); + void inject(SignInReminderReceiver briarService); void inject(BriarService briarService); From c9a97343684f693dda9e2e5e1f208e9e006ae3c1 Mon Sep 17 00:00:00 2001 From: akwizgran Date: Wed, 2 Dec 2020 11:08:58 +0000 Subject: [PATCH 027/124] Use the right timestamp when signing private group invitation. --- .../privategroup/creation/CreateGroupControllerImpl.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) 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 6e62bfb14..4cd66fe80 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 @@ -174,10 +174,10 @@ class CreateGroupControllerImpl extends ContactSelectorControllerImpl List contexts, @Nullable String text, ResultExceptionHandler handler) { cryptoExecutor.execute(() -> { - long timestamp = clock.currentTimeMillis(); for (InvitationContext ctx : contexts) { ctx.signature = groupInvitationFactory.signInvitation( - ctx.contact, g, timestamp, localAuthor.getPrivateKey()); + ctx.contact, g, ctx.timestamp, + localAuthor.getPrivateKey()); } sendInvitations(g, contexts, text, handler); }); From 00ed6d9bb8b01868d1f75f783893f09eb2a69e5d Mon Sep 17 00:00:00 2001 From: akwizgran Date: Wed, 2 Dec 2020 11:30:54 +0000 Subject: [PATCH 028/124] Look up auto-delete timer when creating private group invitation. --- .../creation/CreateGroupControllerImpl.java | 50 ++++++++++++------- .../invitation/GroupInvitationManager.java | 3 +- .../invitation/AbstractProtocolEngine.java | 5 +- .../invitation/CreatorProtocolEngine.java | 14 +++--- .../GroupInvitationManagerImpl.java | 6 +-- .../invitation/InviteeProtocolEngine.java | 3 +- .../invitation/PeerProtocolEngine.java | 3 +- .../invitation/ProtocolEngine.java | 5 +- .../PrivateGroupIntegrationTest.java | 5 +- .../AbstractProtocolEngineTest.java | 22 ++++---- .../invitation/CreatorProtocolEngineTest.java | 14 +++--- .../GroupInvitationIntegrationTest.java | 4 +- .../GroupInvitationManagerImplTest.java | 8 +-- .../invitation/InviteeProtocolEngineTest.java | 14 +++--- .../invitation/PeerProtocolEngineTest.java | 14 +++--- 15 files changed, 98 insertions(+), 72 deletions(-) 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 4cd66fe80..a5268cb5f 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,7 @@ 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; @@ -16,6 +17,7 @@ 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.identity.AuthorManager; import org.briarproject.briar.api.privategroup.GroupMessage; @@ -52,6 +54,7 @@ class CreateGroupControllerImpl extends ContactSelectorControllerImpl private final Executor cryptoExecutor; private final TransactionManager db; + private final AutoDeleteManager autoDeleteManager; private final ConversationManager conversationManager; private final ContactManager contactManager; private final IdentityManager identityManager; @@ -67,6 +70,7 @@ class CreateGroupControllerImpl extends ContactSelectorControllerImpl @DatabaseExecutor Executor dbExecutor, @CryptoExecutor Executor cryptoExecutor, TransactionManager db, + AutoDeleteManager autoDeleteManager, ConversationManager conversationManager, LifecycleManager lifecycleManager, ContactManager contactManager, @@ -81,6 +85,7 @@ class CreateGroupControllerImpl extends ContactSelectorControllerImpl super(dbExecutor, lifecycleManager, contactManager, authorManager); this.cryptoExecutor = cryptoExecutor; this.db = db; + this.autoDeleteManager = autoDeleteManager; this.conversationManager = conversationManager; this.contactManager = contactManager; this.identityManager = identityManager; @@ -146,20 +151,10 @@ class CreateGroupControllerImpl extends ContactSelectorControllerImpl runOnDbThread(() -> { try { db.transaction(true, txn -> { - List contexts = new ArrayList<>(); LocalAuthor localAuthor = identityManager.getLocalAuthor(txn); - for (ContactId c : contactIds) { - try { - Contact contact = contactManager.getContact(txn, c); - long timestamp = conversationManager - .getTimestampForOutgoingMessage(txn, c); - contexts.add( - new InvitationContext(contact, timestamp)); - } catch (NoSuchContactException e) { - // Continue - } - } + List contexts = + createInvitationContexts(txn, contactIds); txn.attach(() -> signInvitations(g, localAuthor, contexts, text, handler)); }); @@ -170,6 +165,23 @@ 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, List contexts, @Nullable String text, ResultExceptionHandler handler) { @@ -188,12 +200,12 @@ class CreateGroupControllerImpl extends ContactSelectorControllerImpl ResultExceptionHandler handler) { runOnDbThread(() -> { try { - for (InvitationContext context : contexts) { + for (InvitationContext ctx : contexts) { try { groupInvitationManager.sendInvitation(g, - context.contact.getId(), text, - context.timestamp, - requireNonNull(context.signature)); + ctx.contact.getId(), text, ctx.timestamp, + requireNonNull(ctx.signature), + ctx.autoDeleteTimer); } catch (NoSuchContactException e) { // Continue } @@ -209,13 +221,15 @@ class CreateGroupControllerImpl extends ContactSelectorControllerImpl private static class InvitationContext { private final Contact contact; - private final long timestamp; + private final long timestamp, autoDeleteTimer; @Nullable private byte[] signature = null; - private InvitationContext(Contact contact, long timestamp) { + private InvitationContext(Contact contact, long timestamp, + long autoDeleteTimer) { this.contact = contact; this.timestamp = timestamp; + this.autoDeleteTimer = autoDeleteTimer; } } } 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-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 ee275abf2..abccc404d 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 @@ -115,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 { @@ -127,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, 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 ebb9ad2c4..2cf40d270 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 @@ -61,11 +61,12 @@ class CreatorProtocolEngine extends AbstractProtocolEngine { @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: @@ -155,10 +156,11 @@ 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 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 3ee96b9f9..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 @@ -65,7 +65,8 @@ class InviteeProtocolEngine extends AbstractProtocolEngine { @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 8f57c7e4e..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 @@ -60,7 +60,8 @@ class PeerProtocolEngine extends AbstractProtocolEngine { @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/test/java/org/briarproject/briar/privategroup/PrivateGroupIntegrationTest.java b/briar-core/src/test/java/org/briarproject/briar/privategroup/PrivateGroupIntegrationTest.java index 51e7dcc57..2c5b6cf8d 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 @@ -24,6 +24,7 @@ import java.util.Collection; import javax.annotation.Nullable; +import static org.briarproject.briar.api.autodelete.AutoDeleteConstants.NO_AUTO_DELETE_TIMER; import static org.briarproject.briar.api.identity.AuthorInfo.Status.OURSELVES; import static org.briarproject.briar.api.privategroup.Visibility.INVISIBLE; import static org.briarproject.briar.api.privategroup.Visibility.REVEALED_BY_CONTACT; @@ -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 2ceff9376..d7c4fd5e2 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 @@ -129,8 +129,8 @@ abstract class AbstractProtocolEngineTest extends BrambleMockTestCase { } void expectSendInviteMessage(String text) throws Exception { - expectCheckWhetherContactSupportsAutoDeletion(true); expectGetLocalTimestamp(messageTimestamp); + expectCheckWhetherContactSupportsAutoDeletion(); context.checking(new Expectations() {{ oneOf(messageEncoder).encodeInviteMessage(contactGroupId, privateGroupId, inviteTimestamp, privateGroup.getName(), @@ -143,8 +143,9 @@ abstract class AbstractProtocolEngineTest extends BrambleMockTestCase { void expectSendJoinMessage(JoinMessage m, boolean visible) throws Exception { - expectCheckWhetherContactSupportsAutoDeletion(visible); expectGetLocalTimestamp(messageTimestamp); + expectCheckWhetherContactSupportsAutoDeletion(); + if (visible) expectGetAutoDeleteTimer(); context.checking(new Expectations() {{ oneOf(messageEncoder).encodeJoinMessage(m.getContactGroupId(), m.getPrivateGroupId(), m.getTimestamp(), @@ -155,8 +156,9 @@ abstract class AbstractProtocolEngineTest extends BrambleMockTestCase { } void expectSendLeaveMessage(boolean visible) throws Exception { - expectCheckWhetherContactSupportsAutoDeletion(visible); expectGetLocalTimestamp(messageTimestamp); + expectCheckWhetherContactSupportsAutoDeletion(); + if (visible) expectGetAutoDeleteTimer(); context.checking(new Expectations() {{ oneOf(messageEncoder).encodeLeaveMessage(contactGroupId, privateGroupId, messageTimestamp, lastLocalMessageId, @@ -232,8 +234,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)); @@ -241,10 +242,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 2e967228f..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 @@ -44,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()); @@ -61,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()); @@ -84,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 f8552e09f..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 @@ -58,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 533246f6a..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 @@ -40,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 From e2a894acd31ae928f812482a0033736cb09cb503 Mon Sep 17 00:00:00 2001 From: akwizgran Date: Wed, 2 Dec 2020 11:55:52 +0000 Subject: [PATCH 029/124] Get timestamp for abort message in same way as other messages. --- .../briar/introduction/IntroducerProtocolEngine.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) 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 fc4040d1f..e79d0ad97 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 @@ -525,8 +525,7 @@ class IntroducerProtocolEngine IntroducerSession s, AbortMessage m) throws DbException { // Forward ABORT message Introducee i = getOtherIntroducee(s, m.getGroupId()); - long localTimestamp = max(i.getLocalTimestamp(), - s.getRequestTimestamp()) + 1; + long localTimestamp = getLocalTimestamp(txn, s, i); Message sent = sendAbortMessage(txn, i, localTimestamp); // Broadcast abort event for testing From b6cf302131b3fb3659db71df11d2c24b64d6d9b2 Mon Sep 17 00:00:00 2001 From: akwizgran Date: Thu, 3 Dec 2020 16:33:55 +0000 Subject: [PATCH 030/124] Only use conversation timestamp for messages that will be visible in conversation. --- .../introduction/AbstractProtocolEngine.java | 6 +- .../IntroduceeProtocolEngine.java | 50 ++++++++----- .../IntroducerProtocolEngine.java | 71 +++++++++++++------ .../invitation/AbstractProtocolEngine.java | 40 ++++++++--- .../invitation/CreatorProtocolEngine.java | 3 +- .../briar/sharing/BlogProtocolEngineImpl.java | 4 +- .../sharing/ForumProtocolEngineImpl.java | 4 +- .../briar/sharing/ProtocolEngineImpl.java | 45 ++++++++---- .../AbstractProtocolEngineTest.java | 19 +++-- 9 files changed, 172 insertions(+), 70 deletions(-) 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 95e500e94..69bc47752 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 @@ -20,6 +20,7 @@ import org.briarproject.bramble.api.properties.TransportProperties; import org.briarproject.bramble.api.sync.GroupId; import org.briarproject.bramble.api.sync.Message; import org.briarproject.bramble.api.sync.MessageId; +import org.briarproject.bramble.api.system.Clock; import org.briarproject.bramble.api.versioning.ClientVersioningManager; import org.briarproject.briar.api.autodelete.AutoDeleteManager; import org.briarproject.briar.api.client.MessageTracker; @@ -62,6 +63,7 @@ abstract class AbstractProtocolEngine> protected final ClientVersioningManager clientVersioningManager; protected final AutoDeleteManager autoDeleteManager; protected final ConversationManager conversationManager; + protected final Clock clock; AbstractProtocolEngine( DatabaseComponent db, @@ -75,7 +77,8 @@ abstract class AbstractProtocolEngine> MessageEncoder messageEncoder, ClientVersioningManager clientVersioningManager, AutoDeleteManager autoDeleteManager, - ConversationManager conversationManager) { + ConversationManager conversationManager, + Clock clock) { this.db = db; this.clientHelper = clientHelper; this.contactManager = contactManager; @@ -88,6 +91,7 @@ abstract class AbstractProtocolEngine> this.clientVersioningManager = clientVersioningManager; this.autoDeleteManager = autoDeleteManager; this.conversationManager = conversationManager; + this.clock = clock; } Message sendRequestMessage(Transaction txn, PeerSession s, 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 8031115fe..5f1a2833f 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 @@ -22,6 +22,7 @@ import org.briarproject.bramble.api.properties.TransportProperties; import org.briarproject.bramble.api.properties.TransportPropertyManager; import org.briarproject.bramble.api.sync.Message; import org.briarproject.bramble.api.sync.MessageId; +import org.briarproject.bramble.api.system.Clock; import org.briarproject.bramble.api.transport.KeyManager; import org.briarproject.bramble.api.transport.KeySetId; import org.briarproject.bramble.api.versioning.ClientVersioningManager; @@ -83,11 +84,12 @@ class IntroduceeProtocolEngine TransportPropertyManager transportPropertyManager, ClientVersioningManager clientVersioningManager, AutoDeleteManager autoDeleteManager, - ConversationManager conversationManager) { + ConversationManager conversationManager, + Clock clock) { super(db, clientHelper, contactManager, contactGroupFactory, messageTracker, identityManager, authorManager, messageParser, messageEncoder, clientVersioningManager, autoDeleteManager, - conversationManager); + conversationManager, clock); this.crypto = crypto; this.keyManager = keyManager; this.transportPropertyManager = transportPropertyManager; @@ -287,8 +289,8 @@ class IntroduceeProtocolEngine Map transportProperties = transportPropertyManager.getLocalProperties(txn); - // Send a ACCEPT message - long localTimestamp = getLocalTimestamp(txn, s); + // Send an ACCEPT message + long localTimestamp = getTimestampForVisibleMessage(txn, s); Message sent = sendAcceptMessage(txn, s, localTimestamp, publicKey, localTimestamp, transportProperties, true); // Track the message @@ -318,7 +320,7 @@ class IntroduceeProtocolEngine markRequestsUnavailableToAnswer(txn, s); // Send a DECLINE message - long localTimestamp = getLocalTimestamp(txn, s); + long localTimestamp = getTimestampForVisibleMessage(txn, s); Message sent = sendDeclineMessage(txn, s, localTimestamp, true); // Track the message @@ -416,7 +418,7 @@ class IntroduceeProtocolEngine return abort(txn, s); } if (s.getState() != AWAIT_AUTH) throw new AssertionError(); - long localTimestamp = getLocalTimestamp(txn, s); + long localTimestamp = getTimestampForInvisibleMessage(s); Message sent = sendAuthMessage(txn, s, localTimestamp, mac, signature); return IntroduceeSession.addLocalAuth(s, AWAIT_AUTH, sent, masterKey, aliceMacKey, bobMacKey); @@ -466,7 +468,7 @@ class IntroduceeProtocolEngine // send ACTIVATE message with a MAC byte[] mac = crypto.activateMac(s); - long localTimestamp = getLocalTimestamp(txn, s); + long localTimestamp = getTimestampForInvisibleMessage(s); Message sent = sendActivateMessage(txn, s, localTimestamp, mac); // Move to AWAIT_ACTIVATE state and clear key material from session @@ -518,7 +520,7 @@ class IntroduceeProtocolEngine markRequestsUnavailableToAnswer(txn, s); // Send an ABORT message - long localTimestamp = getLocalTimestamp(txn, s); + long localTimestamp = getTimestampForInvisibleMessage(s); Message sent = sendAbortMessage(txn, s, localTimestamp); // Broadcast abort event for testing @@ -535,17 +537,33 @@ class IntroduceeProtocolEngine } /** - * Returns a timestamp for an outgoing message, which is later than the - * timestamp of any message sent or received so far in the conversation - * or the session. + * 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 getLocalTimestamp(Transaction txn, IntroduceeSession s) - throws DbException { + private long getTimestampForVisibleMessage(Transaction txn, + IntroduceeSession s) throws DbException { long conversationTimestamp = getTimestampForOutgoingMessage(txn, s.getContactGroupId()); - long sessionTimestamp = - max(s.getLocalTimestamp(), s.getRequestTimestamp()) + 1; - return max(conversationTimestamp, sessionTimestamp); + 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 e79d0ad97..e547b2700 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 @@ -12,6 +12,7 @@ import org.briarproject.bramble.api.nullsafety.NotNullByDefault; import org.briarproject.bramble.api.sync.GroupId; import org.briarproject.bramble.api.sync.Message; import org.briarproject.bramble.api.sync.MessageId; +import org.briarproject.bramble.api.system.Clock; import org.briarproject.bramble.api.versioning.ClientVersioningManager; import org.briarproject.briar.api.autodelete.AutoDeleteManager; import org.briarproject.briar.api.client.MessageTracker; @@ -57,11 +58,12 @@ class IntroducerProtocolEngine MessageEncoder messageEncoder, ClientVersioningManager clientVersioningManager, AutoDeleteManager autoDeleteManager, - ConversationManager conversationManager) { + ConversationManager conversationManager, + Clock clock) { super(db, clientHelper, contactManager, contactGroupFactory, messageTracker, identityManager, authorManager, messageParser, messageEncoder, clientVersioningManager, autoDeleteManager, - conversationManager); + conversationManager, clock); } @Override @@ -219,8 +221,10 @@ class IntroducerProtocolEngine private IntroducerSession onLocalRequest(Transaction txn, IntroducerSession s, @Nullable String text) throws DbException { // Send REQUEST messages - long timestampA = getLocalTimestamp(txn, s, s.getIntroduceeA()); - long timestampB = getLocalTimestamp(txn, s, s.getIntroduceeB()); + 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); @@ -261,7 +265,8 @@ class IntroducerProtocolEngine // Forward ACCEPT message Introducee i = getOtherIntroducee(s, m.getGroupId()); - long localTimestamp = getLocalTimestamp(txn, s, i); + // The message will be visible to the introducee + long localTimestamp = getTimestampForVisibleMessage(txn, s, i); Message sent = sendAcceptMessage(txn, i, localTimestamp, m.getEphemeralPublicKey(), m.getAcceptTimestamp(), m.getTransportProperties(), false); @@ -321,7 +326,8 @@ class IntroducerProtocolEngine // Forward ACCEPT message Introducee i = getOtherIntroducee(s, m.getGroupId()); - long localTimestamp = getLocalTimestamp(txn, s, i); + // The message will be visible to the introducee + long localTimestamp = getTimestampForVisibleMessage(txn, s, i); Message sent = sendAcceptMessage(txn, i, localTimestamp, m.getEphemeralPublicKey(), m.getAcceptTimestamp(), m.getTransportProperties(), false); @@ -373,7 +379,8 @@ class IntroducerProtocolEngine // Forward DECLINE message Introducee i = getOtherIntroducee(s, m.getGroupId()); - long localTimestamp = getLocalTimestamp(txn, s, i); + // The message will be visible to the introducee + long localTimestamp = getTimestampForVisibleMessage(txn, s, i); Message sent = sendDeclineMessage(txn, i, localTimestamp, false); // Create the next state @@ -425,7 +432,8 @@ class IntroducerProtocolEngine // Forward DECLINE message Introducee i = getOtherIntroducee(s, m.getGroupId()); - long localTimestamp = getLocalTimestamp(txn, s, i); + // The message will be visible to the introducee + long localTimestamp = getTimestampForVisibleMessage(txn, s, i); Message sent = sendDeclineMessage(txn, i, localTimestamp, false); Introducee introduceeA, introduceeB; @@ -466,7 +474,7 @@ class IntroducerProtocolEngine // Forward AUTH message Introducee i = getOtherIntroducee(s, m.getGroupId()); - long localTimestamp = getLocalTimestamp(txn, s, i); + long localTimestamp = getTimestampForInvisibleMessage(s, i); Message sent = sendAuthMessage(txn, i, localTimestamp, m.getMac(), m.getSignature()); @@ -502,7 +510,7 @@ class IntroducerProtocolEngine // Forward ACTIVATE message Introducee i = getOtherIntroducee(s, m.getGroupId()); - long localTimestamp = getLocalTimestamp(txn, s, i); + long localTimestamp = getTimestampForInvisibleMessage(s, i); Message sent = sendActivateMessage(txn, i, localTimestamp, m.getMac()); // Move to the next state @@ -525,7 +533,7 @@ class IntroducerProtocolEngine IntroducerSession s, AbortMessage m) throws DbException { // Forward ABORT message Introducee i = getOtherIntroducee(s, m.getGroupId()); - long localTimestamp = getLocalTimestamp(txn, s, i); + long localTimestamp = getTimestampForInvisibleMessage(s, i); Message sent = sendAbortMessage(txn, i, localTimestamp); // Broadcast abort event for testing @@ -550,7 +558,8 @@ class IntroducerProtocolEngine txn.attach(new IntroductionAbortedEvent(s.getSessionId())); // Send an ABORT message to the remaining introducee - long localTimestamp = getLocalTimestamp(txn, s, remainingIntroducee); + long localTimestamp = + getTimestampForInvisibleMessage(s, remainingIntroducee); Message sent = sendAbortMessage(txn, remainingIntroducee, localTimestamp); // Reset the session back to initial state @@ -577,9 +586,11 @@ class IntroducerProtocolEngine txn.attach(new IntroductionAbortedEvent(s.getSessionId())); // Send an ABORT message to both introducees - long timestampA = getLocalTimestamp(txn, s, s.getIntroduceeA()); + long timestampA = + getTimestampForInvisibleMessage(s, s.getIntroduceeA()); Message sentA = sendAbortMessage(txn, s.getIntroduceeA(), timestampA); - long timestampB = getLocalTimestamp(txn, 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); @@ -610,16 +621,32 @@ class IntroducerProtocolEngine } /** - * Returns a timestamp for an outgoing message, which is later than the - * timestamp of any message sent or received so far in the conversation - * or the session. + * 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 getLocalTimestamp(Transaction txn, IntroducerSession s, - PeerSession p) throws DbException { + private long getTimestampForVisibleMessage(Transaction txn, + IntroducerSession s, PeerSession p) throws DbException { long conversationTimestamp = getTimestampForOutgoingMessage(txn, p.getContactGroupId()); - long sessionTimestamp = - max(p.getLocalTimestamp(), s.getRequestTimestamp()) + 1; - return max(conversationTimestamp, sessionTimestamp); + 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/privategroup/invitation/AbstractProtocolEngine.java b/briar-core/src/main/java/org/briarproject/briar/privategroup/invitation/AbstractProtocolEngine.java index abccc404d..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 @@ -146,7 +146,9 @@ abstract class AbstractProtocolEngine> Message sendJoinMessage(Transaction txn, S s, boolean visibleInUi) throws DbException { Message m; - long localTimestamp = getLocalTimestamp(txn, s); + 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 @@ -171,7 +173,9 @@ abstract class AbstractProtocolEngine> Message sendLeaveMessage(Transaction txn, S s, boolean visibleInUi) throws DbException { Message m; - long localTimestamp = getLocalTimestamp(txn, s); + 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 @@ -196,7 +200,7 @@ abstract class AbstractProtocolEngine> Message sendAbortMessage(Transaction txn, S session) throws DbException { Message m = messageEncoder.encodeAbortMessage( session.getContactGroupId(), session.getPrivateGroupId(), - getLocalTimestamp(txn, session)); + getTimestampForInvisibleMessage(session)); sendMessage(txn, m, ABORT, session.getPrivateGroupId(), false, NO_AUTO_DELETE_TIMER); return m; @@ -263,17 +267,33 @@ abstract class AbstractProtocolEngine> } /** - * Returns a timestamp for an outgoing message, which is later than the - * timestamp of any message sent or received so far in the conversation - * or the session. + * 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 getLocalTimestamp(Transaction txn, S s) throws DbException { + long getTimestampForVisibleMessage(Transaction txn, S s) + throws DbException { ContactId c = getContactId(txn, s.getContactGroupId()); long conversationTimestamp = conversationManager.getTimestampForOutgoingMessage(txn, c); - long sessionTimestamp = - max(s.getLocalTimestamp(), s.getInviteTimestamp()) + 1; - return max(conversationTimestamp, sessionTimestamp); + 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 2cf40d270..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 @@ -164,7 +164,8 @@ class CreatorProtocolEngine extends AbstractProtocolEngine { // Track the message messageTracker.trackOutgoingMessage(txn, sent); // Move to the INVITED state - long localTimestamp = max(timestamp, getLocalTimestamp(txn, 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/sharing/BlogProtocolEngineImpl.java b/briar-core/src/main/java/org/briarproject/briar/sharing/BlogProtocolEngineImpl.java index 7ffa0679e..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 @@ -9,6 +9,7 @@ import org.briarproject.bramble.api.db.Transaction; import org.briarproject.bramble.api.event.Event; import org.briarproject.bramble.api.nullsafety.NotNullByDefault; import org.briarproject.bramble.api.sync.MessageId; +import org.briarproject.bramble.api.system.Clock; import org.briarproject.bramble.api.versioning.ClientVersioningManager; import org.briarproject.briar.api.autodelete.AutoDeleteManager; import org.briarproject.briar.api.blog.Blog; @@ -42,11 +43,12 @@ class BlogProtocolEngineImpl extends ProtocolEngineImpl { MessageTracker messageTracker, AutoDeleteManager autoDeleteManager, ConversationManager conversationManager, + Clock clock, BlogManager blogManager, InvitationFactory invitationFactory) { super(db, clientHelper, clientVersioningManager, messageEncoder, messageParser, messageTracker, autoDeleteManager, - conversationManager, BlogSharingManager.CLIENT_ID, + conversationManager, clock, BlogSharingManager.CLIENT_ID, BlogSharingManager.MAJOR_VERSION, BlogManager.CLIENT_ID, BlogManager.MAJOR_VERSION); this.blogManager = blogManager; 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 55a1b76f3..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 @@ -9,6 +9,7 @@ import org.briarproject.bramble.api.db.Transaction; import org.briarproject.bramble.api.event.Event; import org.briarproject.bramble.api.nullsafety.NotNullByDefault; import org.briarproject.bramble.api.sync.MessageId; +import org.briarproject.bramble.api.system.Clock; import org.briarproject.bramble.api.versioning.ClientVersioningManager; import org.briarproject.briar.api.autodelete.AutoDeleteManager; import org.briarproject.briar.api.client.MessageTracker; @@ -42,11 +43,12 @@ class ForumProtocolEngineImpl extends ProtocolEngineImpl { MessageTracker messageTracker, AutoDeleteManager autoDeleteManager, ConversationManager conversationManager, + Clock clock, ForumManager forumManager, InvitationFactory invitationFactory) { super(db, clientHelper, clientVersioningManager, messageEncoder, messageParser, messageTracker, autoDeleteManager, - conversationManager, ForumSharingManager.CLIENT_ID, + conversationManager, clock, ForumSharingManager.CLIENT_ID, ForumSharingManager.MAJOR_VERSION, ForumManager.CLIENT_ID, ForumManager.MAJOR_VERSION); this.forumManager = forumManager; 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 21503179e..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 @@ -16,6 +16,7 @@ import org.briarproject.bramble.api.sync.Group.Visibility; import org.briarproject.bramble.api.sync.GroupId; import org.briarproject.bramble.api.sync.Message; import org.briarproject.bramble.api.sync.MessageId; +import org.briarproject.bramble.api.system.Clock; import org.briarproject.bramble.api.versioning.ClientVersioningManager; import org.briarproject.briar.api.autodelete.AutoDeleteManager; import org.briarproject.briar.api.client.MessageTracker; @@ -60,6 +61,7 @@ abstract class ProtocolEngineImpl 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; @@ -72,6 +74,7 @@ abstract class ProtocolEngineImpl MessageTracker messageTracker, AutoDeleteManager autoDeleteManager, ConversationManager conversationManager, + Clock clock, ClientId sharingClientId, int sharingClientMajorVersion, ClientId shareableClientId, @@ -84,6 +87,7 @@ abstract class ProtocolEngineImpl this.messageTracker = messageTracker; this.autoDeleteManager = autoDeleteManager; this.conversationManager = conversationManager; + this.clock = clock; this.sharingClientId = sharingClientId; this.sharingClientMajorVersion = sharingClientMajorVersion; this.shareableClientId = shareableClientId; @@ -134,8 +138,8 @@ abstract class ProtocolEngineImpl } catch (FormatException e) { throw new DbException(e); // Invalid group descriptor } - long localTimestamp = getLocalTimestamp(txn, s); Message m; + long localTimestamp = getTimestampForVisibleMessage(txn, s); ContactId c = getContactId(txn, s.getContactGroupId()); if (contactSupportsAutoDeletion(txn, c)) { long timer = autoDeleteManager.getAutoDeleteTimer(txn, c); @@ -202,7 +206,7 @@ abstract class ProtocolEngineImpl private Message sendAcceptMessage(Transaction txn, Session s) throws DbException { Message m; - long localTimestamp = getLocalTimestamp(txn, s); + long localTimestamp = getTimestampForVisibleMessage(txn, s); ContactId c = getContactId(txn, s.getContactGroupId()); if (contactSupportsAutoDeletion(txn, c)) { long timer = autoDeleteManager.getAutoDeleteTimer(txn, c); @@ -256,7 +260,7 @@ abstract class ProtocolEngineImpl private Message sendDeclineMessage(Transaction txn, Session s) throws DbException { Message m; - long localTimestamp = getLocalTimestamp(txn, s); + long localTimestamp = getTimestampForVisibleMessage(txn, s); ContactId c = getContactId(txn, s.getContactGroupId()); if (contactSupportsAutoDeletion(txn, c)) { long timer = autoDeleteManager.getAutoDeleteTimer(txn, c); @@ -310,7 +314,7 @@ abstract class ProtocolEngineImpl private Message sendLeaveMessage(Transaction txn, Session session) throws DbException { - long localTimestamp = getLocalTimestamp(txn, session); + long localTimestamp = getTimestampForInvisibleMessage(session); Message m = messageEncoder.encodeLeaveMessage( session.getContactGroupId(), session.getShareableId(), localTimestamp, session.getLastLocalMessageId()); @@ -609,7 +613,7 @@ abstract class ProtocolEngineImpl private Message sendAbortMessage(Transaction txn, Session session) throws DbException { - long localTimestamp = getLocalTimestamp(txn, session); + long localTimestamp = getTimestampForInvisibleMessage(session); Message m = messageEncoder.encodeAbortMessage( session.getContactGroupId(), session.getShareableId(), localTimestamp, session.getLastLocalMessageId()); @@ -683,18 +687,33 @@ abstract class ProtocolEngineImpl } /** - * Returns a timestamp for an outgoing message, which is later than the - * timestamp of any message sent or received so far in the conversation - * or the session. + * 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 getLocalTimestamp(Transaction txn, Session session) + private long getTimestampForVisibleMessage(Transaction txn, Session s) throws DbException { - ContactId c = getContactId(txn, session.getContactGroupId()); + ContactId c = getContactId(txn, s.getContactGroupId()); long conversationTimestamp = conversationManager.getTimestampForOutgoingMessage(txn, c); - long sessionTimestamp = max(session.getLocalTimestamp(), - session.getInviteTimestamp()) + 1; - return max(conversationTimestamp, sessionTimestamp); + 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/test/java/org/briarproject/briar/privategroup/invitation/AbstractProtocolEngineTest.java b/briar-core/src/test/java/org/briarproject/briar/privategroup/invitation/AbstractProtocolEngineTest.java index d7c4fd5e2..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 @@ -118,7 +118,14 @@ abstract class AbstractProtocolEngineTest extends BrambleMockTestCase { assertEquals(inviteTimestamp, s.getInviteTimestamp()); } - void expectGetLocalTimestamp(long time) throws Exception { + 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)); @@ -129,7 +136,7 @@ abstract class AbstractProtocolEngineTest extends BrambleMockTestCase { } void expectSendInviteMessage(String text) throws Exception { - expectGetLocalTimestamp(messageTimestamp); + expectGetTimestampForVisibleMessage(messageTimestamp); expectCheckWhetherContactSupportsAutoDeletion(); context.checking(new Expectations() {{ oneOf(messageEncoder).encodeInviteMessage(contactGroupId, @@ -143,7 +150,8 @@ abstract class AbstractProtocolEngineTest extends BrambleMockTestCase { void expectSendJoinMessage(JoinMessage m, boolean visible) throws Exception { - expectGetLocalTimestamp(messageTimestamp); + if (visible) expectGetTimestampForVisibleMessage(messageTimestamp); + else expectGetTimestampForInvisibleMessage(messageTimestamp); expectCheckWhetherContactSupportsAutoDeletion(); if (visible) expectGetAutoDeleteTimer(); context.checking(new Expectations() {{ @@ -156,7 +164,8 @@ abstract class AbstractProtocolEngineTest extends BrambleMockTestCase { } void expectSendLeaveMessage(boolean visible) throws Exception { - expectGetLocalTimestamp(messageTimestamp); + if (visible) expectGetTimestampForVisibleMessage(messageTimestamp); + else expectGetTimestampForInvisibleMessage(messageTimestamp); expectCheckWhetherContactSupportsAutoDeletion(); if (visible) expectGetAutoDeleteTimer(); context.checking(new Expectations() {{ @@ -169,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, From 0328aa0630928f08bf1225d01010b14656a603d3 Mon Sep 17 00:00:00 2001 From: akwizgran Date: Thu, 3 Dec 2020 17:12:52 +0000 Subject: [PATCH 031/124] Forwarded accept messages aren't visible to the introducee. --- .../briar/introduction/IntroducerProtocolEngine.java | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) 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 e547b2700..3607a354b 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 @@ -265,8 +265,8 @@ class IntroducerProtocolEngine // Forward ACCEPT message Introducee i = getOtherIntroducee(s, m.getGroupId()); - // The message will be visible to the introducee - long localTimestamp = getTimestampForVisibleMessage(txn, 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); @@ -326,8 +326,8 @@ class IntroducerProtocolEngine // Forward ACCEPT message Introducee i = getOtherIntroducee(s, m.getGroupId()); - // The message will be visible to the introducee - long localTimestamp = getTimestampForVisibleMessage(txn, 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); @@ -379,7 +379,7 @@ class IntroducerProtocolEngine // Forward DECLINE message Introducee i = getOtherIntroducee(s, m.getGroupId()); - // The message will be visible to the introducee + // The forwarded message will be visible to the introducee long localTimestamp = getTimestampForVisibleMessage(txn, s, i); Message sent = sendDeclineMessage(txn, i, localTimestamp, false); @@ -432,7 +432,7 @@ class IntroducerProtocolEngine // Forward DECLINE message Introducee i = getOtherIntroducee(s, m.getGroupId()); - // The message will be visible to the introducee + // The forwarded message will be visible to the introducee long localTimestamp = getTimestampForVisibleMessage(txn, s, i); Message sent = sendDeclineMessage(txn, i, localTimestamp, false); From d7a2de58178f3887b60f3b2bdd33af91aef6fd64 Mon Sep 17 00:00:00 2001 From: akwizgran Date: Thu, 3 Dec 2020 17:58:10 +0000 Subject: [PATCH 032/124] Add integration tests for auto-delete timer. --- .../IntroductionIntegrationTest.java | 66 +++++++++++++++++++ .../SimplexMessagingIntegrationTest.java | 4 +- .../GroupInvitationIntegrationTest.java | 62 ++++++++++++++++- .../sharing/BlogSharingIntegrationTest.java | 47 +++++++++++++ .../sharing/ForumSharingIntegrationTest.java | 36 ++++++++++ .../briar/test/BriarIntegrationTest.java | 20 +++++- .../test/BriarIntegrationTestComponent.java | 3 + 7 files changed, 230 insertions(+), 8 deletions(-) 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 bbf2434ce..2c2eacf21 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 @@ -50,6 +50,7 @@ import static org.briarproject.bramble.test.TestUtils.getAgreementPublicKey; import static org.briarproject.bramble.test.TestUtils.getSecretKey; import static org.briarproject.bramble.test.TestUtils.getTransportProperties; import static org.briarproject.bramble.test.TestUtils.getTransportPropertiesMap; +import static org.briarproject.briar.api.autodelete.AutoDeleteConstants.MIN_AUTO_DELETE_TIMER_MS; import static org.briarproject.briar.api.autodelete.AutoDeleteConstants.NO_AUTO_DELETE_TIMER; import static org.briarproject.briar.api.introduction.IntroductionManager.CLIENT_ID; import static org.briarproject.briar.api.introduction.IntroductionManager.MAJOR_VERSION; @@ -257,6 +258,71 @@ public class IntroductionIntegrationTest assertGroupCount(messageTracker2, g2.getId(), 2, 1); } + @Test + public void testIntroductionSessionWithAutoDelete() throws Exception { + addListeners(true, true); + + // 0 and 1 set an auto-delete timer for their conversation + setAutoDeleteTimer(c0, contactId1From0); + setAutoDeleteTimer(c1, contactId0From1); + + // Make introduction + introductionManager0 + .makeIntroduction(contact1From0, contact2From0, "Hi!"); + + // Sync first REQUEST message + sync0To1(1, true); + eventWaiter.await(TIMEOUT, 1); + + // Sync second REQUEST message + sync0To2(1, true); + eventWaiter.await(TIMEOUT, 1); + + // Sync first ACCEPT message + sync1To0(1, true); + eventWaiter.await(TIMEOUT, 1); + + // Sync second ACCEPT message + sync2To0(1, true); + eventWaiter.await(TIMEOUT, 1); + + // Sync forwarded ACCEPT messages to introducees + sync0To1(1, true); + sync0To2(1, true); + + // Sync first AUTH and its forward + sync1To0(1, true); + sync0To2(1, true); + + // Sync second AUTH and its forward as well as the following ACTIVATE + sync2To0(2, true); + sync0To1(2, true); + + // Sync second ACTIVATE and its forward + sync1To0(1, true); + sync0To2(1, true); + + // Wait for introduction to succeed + eventWaiter.await(TIMEOUT, 2); + assertTrue(listener1.succeeded); + assertTrue(listener2.succeeded); + + // All visible messages between 0 and 1 should have auto-delete timers + for (ConversationMessageHeader h : getMessages1From0()) { + assertEquals(MIN_AUTO_DELETE_TIMER_MS, h.getAutoDeleteTimer()); + } + for (ConversationMessageHeader h : getMessages0From1()) { + assertEquals(MIN_AUTO_DELETE_TIMER_MS, h.getAutoDeleteTimer()); + } + // No visible messages between 0 and 2 should have auto-delete timers + for (ConversationMessageHeader h : getMessages2From0()) { + assertEquals(NO_AUTO_DELETE_TIMER, h.getAutoDeleteTimer()); + } + for (ConversationMessageHeader h : getMessages0From2()) { + assertEquals(NO_AUTO_DELETE_TIMER, h.getAutoDeleteTimer()); + } + } + @Test public void testIntroductionSessionFirstDecline() throws Exception { addListeners(false, true); diff --git a/briar-core/src/test/java/org/briarproject/briar/messaging/SimplexMessagingIntegrationTest.java b/briar-core/src/test/java/org/briarproject/briar/messaging/SimplexMessagingIntegrationTest.java index faa27b3f3..16e540e95 100644 --- a/briar-core/src/test/java/org/briarproject/briar/messaging/SimplexMessagingIntegrationTest.java +++ b/briar-core/src/test/java/org/briarproject/briar/messaging/SimplexMessagingIntegrationTest.java @@ -39,7 +39,7 @@ import static org.briarproject.bramble.test.TestPluginConfigModule.SIMPLEX_TRANS import static org.briarproject.bramble.test.TestUtils.deleteTestDirectory; import static org.briarproject.bramble.test.TestUtils.getSecretKey; import static org.briarproject.bramble.test.TestUtils.getTestDirectory; -import static org.briarproject.briar.api.autodelete.AutoDeleteConstants.NO_AUTO_DELETE_TIMER; +import static org.briarproject.briar.api.autodelete.AutoDeleteConstants.MIN_AUTO_DELETE_TIMER_MS; import static org.junit.Assert.assertTrue; public class SimplexMessagingIntegrationTest extends BriarTestCase { @@ -125,7 +125,7 @@ public class SimplexMessagingIntegrationTest extends BriarTestCase { device.getPrivateMessageFactory(); PrivateMessage message = privateMessageFactory.createPrivateMessage( groupId, timestamp, "Hi!", singletonList(attachmentHeader), - NO_AUTO_DELETE_TIMER); + MIN_AUTO_DELETE_TIMER_MS); messagingManager.addLocalMessage(message); } 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 9535b81f8..5a9064f28 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,7 +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.api.autodelete.AutoDeleteConstants.MIN_AUTO_DELETE_TIMER_MS; import static org.briarproject.briar.test.BriarTestUtils.assertGroupCount; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; @@ -165,6 +165,33 @@ public class GroupInvitationIntegrationTest assertEquals(0, groupManager1.getPrivateGroups().size()); } + @Test + public void testInvitationDeclineWithAutoDelete() throws Exception { + // 0 and 1 set an auto-delete timer for their conversation + setAutoDeleteTimer(c0, contactId1From0); + setAutoDeleteTimer(c1, contactId0From1); + + // Send invitation + sendInvitation(clock.currentTimeMillis(), null); + sync0To1(1, true); + + // Decline invitation + groupInvitationManager1 + .respondToInvitation(contactId0From1, privateGroup, false); + sync1To0(1, true); + + // Group was not added + assertTrue(groupManager1.getPrivateGroups().isEmpty()); + + // All visible messages between 0 and 1 should have auto-delete timers + for (ConversationMessageHeader h : getMessages1From0()) { + assertEquals(MIN_AUTO_DELETE_TIMER_MS, h.getAutoDeleteTimer()); + } + for (ConversationMessageHeader h : getMessages0From1()) { + assertEquals(MIN_AUTO_DELETE_TIMER_MS, h.getAutoDeleteTimer()); + } + } + @Test public void testInvitationAccept() throws Exception { long timestamp = clock.currentTimeMillis(); @@ -223,6 +250,35 @@ public class GroupInvitationIntegrationTest assertEquals(privateGroup, groups.iterator().next()); } + @Test + public void testInvitationAcceptWithAutoDelete() throws Exception { + // 0 and 1 set an auto-delete timer for their conversation + setAutoDeleteTimer(c0, contactId1From0); + setAutoDeleteTimer(c1, contactId0From1); + + // Send invitation + sendInvitation(clock.currentTimeMillis(), null); + sync0To1(1, true); + + // Accept invitation + groupInvitationManager1 + .respondToInvitation(contactId0From1, privateGroup, true); + sync1To0(1, true); + + // Group was added + Collection groups = groupManager1.getPrivateGroups(); + assertEquals(1, groups.size()); + assertEquals(privateGroup, groups.iterator().next()); + + // All visible messages between 0 and 1 should have auto-delete timers + for (ConversationMessageHeader h : getMessages1From0()) { + assertEquals(MIN_AUTO_DELETE_TIMER_MS, h.getAutoDeleteTimer()); + } + for (ConversationMessageHeader h : getMessages0From1()) { + assertEquals(MIN_AUTO_DELETE_TIMER_MS, h.getAutoDeleteTimer()); + } + } + @Test public void testGroupCount() throws Exception { long timestamp = clock.currentTimeMillis(); @@ -687,9 +743,9 @@ public class GroupInvitationIntegrationTest throws DbException { byte[] signature = groupInvitationFactory.signInvitation(contact1From0, privateGroup.getId(), timestamp, author0.getPrivateKey()); + long timer = getAutoDeleteTimer(c0, contactId1From0); groupInvitationManager0.sendInvitation(privateGroup.getId(), - contactId1From0, text, timestamp, signature, - NO_AUTO_DELETE_TIMER); + contactId1From0, text, timestamp, signature, timer); } } 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 b2deb691c..b8454c72d 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 @@ -30,6 +30,7 @@ import org.junit.rules.ExpectedException; import java.util.Collection; +import static org.briarproject.briar.api.autodelete.AutoDeleteConstants.MIN_AUTO_DELETE_TIMER_MS; import static org.briarproject.briar.api.blog.BlogSharingManager.CLIENT_ID; import static org.briarproject.briar.api.blog.BlogSharingManager.MAJOR_VERSION; import static org.briarproject.briar.test.BriarTestUtils.assertGroupCount; @@ -203,6 +204,41 @@ public class BlogSharingIntegrationTest assertGroupCount(messageTracker1, g, 2, 1); } + @Test + public void testSuccessfulSharingWithAutoDelete() throws Exception { + // Initialize and let invitee accept all requests + listenToEvents(true); + + // Set an auto-delete timer for the conversation + setAutoDeleteTimer(c0, contactId1From0); + setAutoDeleteTimer(c1, contactId0From1); + + // Send invitation + blogSharingManager0 + .sendInvitation(blog2.getId(), contactId1From0, "Hi!"); + + // Sync first request message + sync0To1(1, true); + eventWaiter.await(TIMEOUT, 1); + + // Sync response back + sync1To0(1, true); + eventWaiter.await(TIMEOUT, 1); + + // Blog was added successfully + assertEquals(0, blogSharingManager0.getInvitations().size()); + assertEquals(3, blogManager1.getBlogs().size()); + assertTrue(blogManager1.getBlogs().contains(blog2)); + + // All visible messages should have auto-delete timers + for (ConversationMessageHeader h : getMessages1From0()) { + assertEquals(MIN_AUTO_DELETE_TIMER_MS, h.getAutoDeleteTimer()); + } + for (ConversationMessageHeader h : getMessages0From1()) { + assertEquals(MIN_AUTO_DELETE_TIMER_MS, h.getAutoDeleteTimer()); + } + } + @Test public void testSuccessfulSharingWithRssBlog() throws Exception { // initialize and let invitee accept all requests @@ -647,4 +683,15 @@ public class BlogSharingIntegrationTest c2.getEventBus().addListener(listener2); } + private Collection getMessages1From0() + throws DbException { + return db0.transactionWithResult(true, txn -> + blogSharingManager0.getMessageHeaders(txn, contactId1From0)); + } + + private Collection getMessages0From1() + throws DbException { + return db1.transactionWithResult(true, txn -> + blogSharingManager1.getMessageHeaders(txn, contactId0From1)); + } } 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 82efda25a..999e9c022 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 @@ -44,6 +44,7 @@ import javax.annotation.Nullable; import static java.util.Collections.emptySet; import static junit.framework.Assert.assertNotNull; import static org.briarproject.bramble.util.StringUtils.getRandomString; +import static org.briarproject.briar.api.autodelete.AutoDeleteConstants.MIN_AUTO_DELETE_TIMER_MS; import static org.briarproject.briar.api.forum.ForumSharingManager.CLIENT_ID; import static org.briarproject.briar.api.forum.ForumSharingManager.MAJOR_VERSION; import static org.briarproject.briar.test.BriarTestUtils.assertGroupCount; @@ -187,6 +188,41 @@ public class ForumSharingIntegrationTest assertFalse(forumSharingManager1.canBeShared(forum.getId(), c0)); } + @Test + public void testSuccessfulSharingWithAutoDelete() throws Exception { + // Set an auto-delete timer for the conversation + setAutoDeleteTimer(c0, contactId1From0); + setAutoDeleteTimer(c1, contactId0From1); + + // Send invitation + forumSharingManager0 + .sendInvitation(forum.getId(), contactId1From0, "Hi!"); + + // Sync request message + sync0To1(1, true); + eventWaiter.await(TIMEOUT, 1); + + // Invitee accepts + respondToRequest(contactId0From1, true); + + // Sync response back + sync1To0(1, true); + eventWaiter.await(TIMEOUT, 1); + assertResponseReceived(listener0, contactId1From0, true); + + // Forum was added successfully + assertEquals(0, forumSharingManager0.getInvitations().size()); + assertEquals(1, forumManager1.getForums().size()); + + // All visible messages should have auto-delete timers + for (ConversationMessageHeader h : getMessages1From0()) { + assertEquals(MIN_AUTO_DELETE_TIMER_MS, h.getAutoDeleteTimer()); + } + for (ConversationMessageHeader h : getMessages0From1()) { + assertEquals(MIN_AUTO_DELETE_TIMER_MS, h.getAutoDeleteTimer()); + } + } + @Test public void testDeclinedSharing() throws Exception { // send invitation diff --git a/briar-core/src/test/java/org/briarproject/briar/test/BriarIntegrationTest.java b/briar-core/src/test/java/org/briarproject/briar/test/BriarIntegrationTest.java index 30ce6dbb1..79cee06da 100644 --- a/briar-core/src/test/java/org/briarproject/briar/test/BriarIntegrationTest.java +++ b/briar-core/src/test/java/org/briarproject/briar/test/BriarIntegrationTest.java @@ -63,6 +63,7 @@ import static org.briarproject.bramble.api.sync.validation.MessageState.PENDING; import static org.briarproject.bramble.test.TestPluginConfigModule.SIMPLEX_TRANSPORT_ID; import static org.briarproject.bramble.test.TestUtils.getSecretKey; import static org.briarproject.bramble.util.LogUtils.logException; +import static org.briarproject.briar.api.autodelete.AutoDeleteConstants.MIN_AUTO_DELETE_TIMER_MS; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; @@ -94,9 +95,6 @@ public abstract class BriarIntegrationTest + component.getAutoDeleteManager().setAutoDeleteTimer(txn, + contactId, MIN_AUTO_DELETE_TIMER_MS)); + } + + protected long getAutoDeleteTimer(BriarIntegrationTestComponent component, + ContactId contactId) throws DbException { + return component.getDatabaseComponent().transactionWithResult(true, + txn -> component.getAutoDeleteManager().getAutoDeleteTimer(txn, + contactId)); + } } diff --git a/briar-core/src/test/java/org/briarproject/briar/test/BriarIntegrationTestComponent.java b/briar-core/src/test/java/org/briarproject/briar/test/BriarIntegrationTestComponent.java index 750275f78..9bee9e573 100644 --- a/briar-core/src/test/java/org/briarproject/briar/test/BriarIntegrationTestComponent.java +++ b/briar-core/src/test/java/org/briarproject/briar/test/BriarIntegrationTestComponent.java @@ -13,6 +13,7 @@ import org.briarproject.bramble.api.lifecycle.LifecycleManager; import org.briarproject.bramble.api.properties.TransportPropertyManager; import org.briarproject.bramble.test.BrambleCoreIntegrationTestModule; import org.briarproject.briar.api.attachment.AttachmentReader; +import org.briarproject.briar.api.autodelete.AutoDeleteManager; import org.briarproject.briar.api.avatar.AvatarManager; import org.briarproject.briar.api.blog.BlogFactory; import org.briarproject.briar.api.blog.BlogManager; @@ -131,6 +132,8 @@ public interface BriarIntegrationTestComponent ConnectionManager getConnectionManager(); + AutoDeleteManager getAutoDeleteManager(); + class Helper { public static void injectEagerSingletons( From 27dbe23914e6649f83443675eaa5ccd8ece6bf87 Mon Sep 17 00:00:00 2001 From: akwizgran Date: Wed, 2 Dec 2020 15:00:45 +0000 Subject: [PATCH 033/124] Mirror the remote auto-delete timer. --- .../conversation/ConversationViewModel.java | 3 +- .../creation/CreateGroupControllerImpl.java | 3 +- .../api/autodelete/AutoDeleteManager.java | 20 +- .../briar/autodelete/AutoDeleteConstants.java | 26 ++- .../autodelete/AutoDeleteManagerImpl.java | 92 +++++++-- .../introduction/AbstractProtocolEngine.java | 9 +- .../invitation/AbstractProtocolEngine.java | 16 +- .../briar/sharing/ProtocolEngineImpl.java | 9 +- .../autodelete/AutoDeleteManagerImplTest.java | 190 +++++++++++++++++- .../AbstractProtocolEngineTest.java | 3 +- 10 files changed, 331 insertions(+), 40 deletions(-) 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 d81f72958..66884d6c1 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 @@ -328,7 +328,8 @@ public class ConversationViewModel extends DbViewModel return privateMessageFactory.createPrivateMessage(groupId, timestamp, text, headers); } else { - long timer = autoDeleteManager.getAutoDeleteTimer(txn, c); + long timer = autoDeleteManager.getAutoDeleteTimer(txn, c, + timestamp); return privateMessageFactory.createPrivateMessage(groupId, timestamp, text, headers, timer); } 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 a5268cb5f..4f10d8fff 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 @@ -173,7 +173,8 @@ class CreateGroupControllerImpl extends ContactSelectorControllerImpl Contact contact = contactManager.getContact(txn, c); long timestamp = conversationManager .getTimestampForOutgoingMessage(txn, c); - long timer = autoDeleteManager.getAutoDeleteTimer(txn, c); + long timer = autoDeleteManager.getAutoDeleteTimer(txn, c, + timestamp); contexts.add(new InvitationContext(contact, timestamp, timer)); } catch (NoSuchContactException e) { // Continue diff --git a/briar-api/src/main/java/org/briarproject/briar/api/autodelete/AutoDeleteManager.java b/briar-api/src/main/java/org/briarproject/briar/api/autodelete/AutoDeleteManager.java index 251178817..8599892d1 100644 --- a/briar-api/src/main/java/org/briarproject/briar/api/autodelete/AutoDeleteManager.java +++ b/briar-api/src/main/java/org/briarproject/briar/api/autodelete/AutoDeleteManager.java @@ -24,8 +24,26 @@ public interface AutoDeleteManager { */ int MINOR_VERSION = 0; - long getAutoDeleteTimer(Transaction txn, ContactId c) throws DbException; + /** + * Returns the auto-delete timer duration for the given contact, for use in + * a message with the given timestamp. The timestamp is stored. + */ + long getAutoDeleteTimer(Transaction txn, ContactId c, long timestamp) + throws DbException; + /** + * Sets the auto-delete timer duration for the given contact. + */ void setAutoDeleteTimer(Transaction txn, ContactId c, long timer) throws DbException; + + /** + * Receives an auto-delete timer duration from the given contact, carried + * in a message with the given timestamp. The local timer is set to the + * same duration unless it has been + * {@link #setAutoDeleteTimer(Transaction, ContactId, long) changed} more + * recently than the remote timer. + */ + void receiveAutoDeleteTimer(Transaction txn, ContactId c, long timer, + long timestamp) throws DbException; } diff --git a/briar-core/src/main/java/org/briarproject/briar/autodelete/AutoDeleteConstants.java b/briar-core/src/main/java/org/briarproject/briar/autodelete/AutoDeleteConstants.java index 7dc94eced..ff274fcc7 100644 --- a/briar-core/src/main/java/org/briarproject/briar/autodelete/AutoDeleteConstants.java +++ b/briar-core/src/main/java/org/briarproject/briar/autodelete/AutoDeleteConstants.java @@ -2,6 +2,28 @@ package org.briarproject.briar.autodelete; interface AutoDeleteConstants { - // Group metadata key for storing the auto-delete timer - String GROUP_KEY_AUTO_DELETE_TIMER = "autoDeleteTimer"; + /** + * Group metadata key for storing the auto-delete timer duration. + */ + String GROUP_KEY_TIMER = "autoDeleteTimer"; + + /** + * Group metadata key for storing the timestamp of the latest incoming or + * outgoing message carrying an auto-delete timer (including a null timer). + */ + String GROUP_KEY_TIMESTAMP = "autoDeleteTimestamp"; + + /** + * Group metadata key for storing the previous auto-delete timer duration. + * This is used to decide whether a local change to the duration should be + * overwritten by a duration received from the contact. + */ + String GROUP_KEY_PREVIOUS_TIMER = "autoDeletePreviousTimer"; + + /** + * Special value for {@link #GROUP_KEY_PREVIOUS_TIMER} indicating that + * there are no local changes to the auto-delete timer duration that need + * to be compared with durations received from the contact. + */ + long NO_PREVIOUS_TIMER = 0; } diff --git a/briar-core/src/main/java/org/briarproject/briar/autodelete/AutoDeleteManagerImpl.java b/briar-core/src/main/java/org/briarproject/briar/autodelete/AutoDeleteManagerImpl.java index ce83a3085..e0644c63e 100644 --- a/briar-core/src/main/java/org/briarproject/briar/autodelete/AutoDeleteManagerImpl.java +++ b/briar-core/src/main/java/org/briarproject/briar/autodelete/AutoDeleteManagerImpl.java @@ -17,19 +17,29 @@ import org.briarproject.bramble.api.sync.Group; import org.briarproject.bramble.api.sync.GroupFactory; import org.briarproject.briar.api.autodelete.AutoDeleteManager; +import java.util.logging.Logger; + import javax.annotation.concurrent.Immutable; import javax.inject.Inject; +import static java.util.logging.Level.INFO; +import static java.util.logging.Logger.getLogger; import static org.briarproject.briar.api.autodelete.AutoDeleteConstants.MAX_AUTO_DELETE_TIMER_MS; import static org.briarproject.briar.api.autodelete.AutoDeleteConstants.MIN_AUTO_DELETE_TIMER_MS; import static org.briarproject.briar.api.autodelete.AutoDeleteConstants.NO_AUTO_DELETE_TIMER; -import static org.briarproject.briar.autodelete.AutoDeleteConstants.GROUP_KEY_AUTO_DELETE_TIMER; +import static org.briarproject.briar.autodelete.AutoDeleteConstants.GROUP_KEY_PREVIOUS_TIMER; +import static org.briarproject.briar.autodelete.AutoDeleteConstants.GROUP_KEY_TIMER; +import static org.briarproject.briar.autodelete.AutoDeleteConstants.GROUP_KEY_TIMESTAMP; +import static org.briarproject.briar.autodelete.AutoDeleteConstants.NO_PREVIOUS_TIMER; @Immutable @NotNullByDefault class AutoDeleteManagerImpl implements AutoDeleteManager, OpenDatabaseHook, ContactHook { + private static final Logger LOG = + getLogger(AutoDeleteManagerImpl.class.getName()); + private final DatabaseComponent db; private final ClientHelper clientHelper; private final GroupFactory groupFactory; @@ -69,14 +79,22 @@ class AutoDeleteManagerImpl } @Override - public long getAutoDeleteTimer(Transaction txn, ContactId c) + public long getAutoDeleteTimer(Transaction txn, ContactId c, long timestamp) throws DbException { try { Group g = getGroup(db.getContact(txn, c)); BdfDictionary meta = clientHelper.getGroupMetadataAsDictionary(txn, g.getId()); - return meta.getLong(GROUP_KEY_AUTO_DELETE_TIMER, - NO_AUTO_DELETE_TIMER); + long timer = meta.getLong(GROUP_KEY_TIMER, NO_AUTO_DELETE_TIMER); + if (LOG.isLoggable(INFO)) { + LOG.info("Sending message with auto-delete timer " + timer); + } + // Update the timestamp and clear the previous timer, if any + meta = BdfDictionary.of( + new BdfEntry(GROUP_KEY_TIMESTAMP, timestamp), + new BdfEntry(GROUP_KEY_PREVIOUS_TIMER, NO_PREVIOUS_TIMER)); + clientHelper.mergeGroupMetadata(txn, g.getId(), meta); + return timer; } catch (FormatException e) { throw new DbException(e); } @@ -85,18 +103,60 @@ class AutoDeleteManagerImpl @Override public void setAutoDeleteTimer(Transaction txn, ContactId c, long timer) throws DbException { - if (timer != NO_AUTO_DELETE_TIMER && - (timer < MIN_AUTO_DELETE_TIMER_MS || - timer > MAX_AUTO_DELETE_TIMER_MS)) { - throw new IllegalArgumentException(); - } + validateTimer(timer); try { Group g = getGroup(db.getContact(txn, c)); - BdfDictionary meta = BdfDictionary.of( - new BdfEntry(GROUP_KEY_AUTO_DELETE_TIMER, timer)); + BdfDictionary meta = + clientHelper.getGroupMetadataAsDictionary(txn, g.getId()); + long oldTimer = meta.getLong(GROUP_KEY_TIMER, NO_AUTO_DELETE_TIMER); + if (timer == oldTimer) return; + if (LOG.isLoggable(INFO)) { + LOG.info("Setting auto-delete timer to " + timer); + } + // Store the new timer and the previous timer + meta = BdfDictionary.of( + new BdfEntry(GROUP_KEY_TIMER, timer), + new BdfEntry(GROUP_KEY_PREVIOUS_TIMER, oldTimer)); clientHelper.mergeGroupMetadata(txn, g.getId(), meta); } catch (FormatException e) { - throw new AssertionError(e); + throw new DbException(e); + } + } + + @Override + public void receiveAutoDeleteTimer(Transaction txn, ContactId c, + long timer, long timestamp) throws DbException { + validateTimer(timer); + try { + Group g = getGroup(db.getContact(txn, c)); + BdfDictionary meta = + clientHelper.getGroupMetadataAsDictionary(txn, g.getId()); + long oldTimestamp = meta.getLong(GROUP_KEY_TIMESTAMP, 0L); + if (timestamp <= oldTimestamp) return; + long oldTimer = + meta.getLong(GROUP_KEY_PREVIOUS_TIMER, NO_PREVIOUS_TIMER); + meta = new BdfDictionary(); + if (oldTimer == NO_PREVIOUS_TIMER) { + // We don't have an unsent change. Mirror their timer + if (LOG.isLoggable(INFO)) { + LOG.info("Mirroring auto-delete timer " + timer); + } + meta.put(GROUP_KEY_TIMER, timer); + } else if (timer != oldTimer) { + // Their sent change trumps our unsent change. Mirror their + // timer and clear the previous timer to drop our unsent change + if (LOG.isLoggable(INFO)) { + LOG.info("Mirroring auto-delete timer " + timer + + " and forgetting unsent change"); + } + meta.put(GROUP_KEY_TIMER, timer); + meta.put(GROUP_KEY_PREVIOUS_TIMER, NO_PREVIOUS_TIMER); + } + // Always update the timestamp + meta.put(GROUP_KEY_TIMESTAMP, timestamp); + clientHelper.mergeGroupMetadata(txn, g.getId(), meta); + } catch (FormatException e) { + throw new DbException(e); } } @@ -104,4 +164,12 @@ class AutoDeleteManagerImpl byte[] descriptor = c.getAuthor().getId().getBytes(); return groupFactory.createGroup(CLIENT_ID, MAJOR_VERSION, descriptor); } + + private void validateTimer(long timer) { + if (timer != NO_AUTO_DELETE_TIMER && + (timer < MIN_AUTO_DELETE_TIMER_MS || + timer > MAX_AUTO_DELETE_TIMER_MS)) { + throw new IllegalArgumentException(); + } + } } 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 69bc47752..ee304f845 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 @@ -100,7 +100,8 @@ abstract class AbstractProtocolEngine> Message m; ContactId c = getContactId(txn, s.getContactGroupId()); if (contactSupportsAutoDeletion(txn, c)) { - long timer = autoDeleteManager.getAutoDeleteTimer(txn, c); + long timer = autoDeleteManager.getAutoDeleteTimer(txn, c, + timestamp); m = messageEncoder.encodeRequestMessage(s.getContactGroupId(), timestamp, s.getLastLocalMessageId(), author, text, timer); sendMessage(txn, REQUEST, s.getSessionId(), m, true, timer); @@ -120,7 +121,8 @@ abstract class AbstractProtocolEngine> Message m; ContactId c = getContactId(txn, s.getContactGroupId()); if (contactSupportsAutoDeletion(txn, c)) { - long timer = autoDeleteManager.getAutoDeleteTimer(txn, c); + long timer = autoDeleteManager.getAutoDeleteTimer(txn, c, + timestamp); m = messageEncoder.encodeAcceptMessage(s.getContactGroupId(), timestamp, s.getLastLocalMessageId(), s.getSessionId(), ephemeralPublicKey, acceptTimestamp, transportProperties, @@ -141,7 +143,8 @@ abstract class AbstractProtocolEngine> Message m; ContactId c = getContactId(txn, s.getContactGroupId()); if (contactSupportsAutoDeletion(txn, c)) { - long timer = autoDeleteManager.getAutoDeleteTimer(txn, c); + long timer = autoDeleteManager.getAutoDeleteTimer(txn, c, + timestamp); m = messageEncoder.encodeDeclineMessage(s.getContactGroupId(), timestamp, s.getLastLocalMessageId(), s.getSessionId(), timer); 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 a8d355005..96a2f17f7 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 @@ -152,9 +152,11 @@ abstract class AbstractProtocolEngine> ContactId c = getContactId(txn, s.getContactGroupId()); if (contactSupportsAutoDeletion(txn, c)) { // Set auto-delete timer if manually accepting an invitation - long timer = visibleInUi - ? autoDeleteManager.getAutoDeleteTimer(txn, c) - : NO_AUTO_DELETE_TIMER; + long timer = NO_AUTO_DELETE_TIMER; + if (visibleInUi) { + timer = autoDeleteManager + .getAutoDeleteTimer(txn, c, localTimestamp); + } m = messageEncoder.encodeJoinMessage(s.getContactGroupId(), s.getPrivateGroupId(), localTimestamp, s.getLastLocalMessageId(), timer); @@ -179,9 +181,11 @@ abstract class AbstractProtocolEngine> ContactId c = getContactId(txn, s.getContactGroupId()); if (contactSupportsAutoDeletion(txn, c)) { // Set auto-delete timer if manually accepting an invitation - long timer = visibleInUi - ? autoDeleteManager.getAutoDeleteTimer(txn, c) - : NO_AUTO_DELETE_TIMER; + long timer = NO_AUTO_DELETE_TIMER; + if (visibleInUi) { + timer = autoDeleteManager.getAutoDeleteTimer(txn, c, + localTimestamp); + } m = messageEncoder.encodeLeaveMessage(s.getContactGroupId(), s.getPrivateGroupId(), localTimestamp, s.getLastLocalMessageId(), timer); 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 37726ac70..8c3c423a5 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 @@ -142,7 +142,8 @@ abstract class ProtocolEngineImpl long localTimestamp = getTimestampForVisibleMessage(txn, s); ContactId c = getContactId(txn, s.getContactGroupId()); if (contactSupportsAutoDeletion(txn, c)) { - long timer = autoDeleteManager.getAutoDeleteTimer(txn, c); + long timer = autoDeleteManager.getAutoDeleteTimer(txn, c, + localTimestamp); m = messageEncoder.encodeInviteMessage(s.getContactGroupId(), localTimestamp, s.getLastLocalMessageId(), descriptor, text, timer); @@ -209,7 +210,8 @@ abstract class ProtocolEngineImpl long localTimestamp = getTimestampForVisibleMessage(txn, s); ContactId c = getContactId(txn, s.getContactGroupId()); if (contactSupportsAutoDeletion(txn, c)) { - long timer = autoDeleteManager.getAutoDeleteTimer(txn, c); + long timer = autoDeleteManager.getAutoDeleteTimer(txn, c, + localTimestamp); m = messageEncoder.encodeAcceptMessage(s.getContactGroupId(), s.getShareableId(), localTimestamp, s.getLastLocalMessageId(), timer); @@ -263,7 +265,8 @@ abstract class ProtocolEngineImpl long localTimestamp = getTimestampForVisibleMessage(txn, s); ContactId c = getContactId(txn, s.getContactGroupId()); if (contactSupportsAutoDeletion(txn, c)) { - long timer = autoDeleteManager.getAutoDeleteTimer(txn, c); + long timer = autoDeleteManager.getAutoDeleteTimer(txn, c, + localTimestamp); m = messageEncoder.encodeDeclineMessage(s.getContactGroupId(), s.getShareableId(), localTimestamp, s.getLastLocalMessageId(), timer); diff --git a/briar-core/src/test/java/org/briarproject/briar/autodelete/AutoDeleteManagerImplTest.java b/briar-core/src/test/java/org/briarproject/briar/autodelete/AutoDeleteManagerImplTest.java index ef2e83f77..d63ac338e 100644 --- a/briar-core/src/test/java/org/briarproject/briar/autodelete/AutoDeleteManagerImplTest.java +++ b/briar-core/src/test/java/org/briarproject/briar/autodelete/AutoDeleteManagerImplTest.java @@ -18,12 +18,18 @@ import static org.briarproject.bramble.api.client.ContactGroupConstants.GROUP_KE import static org.briarproject.bramble.test.TestUtils.getContact; import static org.briarproject.bramble.test.TestUtils.getGroup; import static org.briarproject.briar.api.autodelete.AutoDeleteConstants.MAX_AUTO_DELETE_TIMER_MS; +import static org.briarproject.briar.api.autodelete.AutoDeleteConstants.MIN_AUTO_DELETE_TIMER_MS; import static org.briarproject.briar.api.autodelete.AutoDeleteConstants.NO_AUTO_DELETE_TIMER; import static org.briarproject.briar.api.autodelete.AutoDeleteManager.CLIENT_ID; import static org.briarproject.briar.api.autodelete.AutoDeleteManager.MAJOR_VERSION; -import static org.briarproject.briar.autodelete.AutoDeleteConstants.GROUP_KEY_AUTO_DELETE_TIMER; +import static org.briarproject.briar.autodelete.AutoDeleteConstants.GROUP_KEY_PREVIOUS_TIMER; +import static org.briarproject.briar.autodelete.AutoDeleteConstants.GROUP_KEY_TIMER; +import static org.briarproject.briar.autodelete.AutoDeleteConstants.GROUP_KEY_TIMESTAMP; +import static org.briarproject.briar.autodelete.AutoDeleteConstants.NO_PREVIOUS_TIMER; import static org.junit.Assert.assertEquals; +// Thank you, I'm using them for readability +@SuppressWarnings("UnnecessaryLocalVariable") public class AutoDeleteManagerImplTest extends BrambleMockTestCase { private final DatabaseComponent db = context.mock(DatabaseComponent.class); @@ -35,6 +41,7 @@ public class AutoDeleteManagerImplTest extends BrambleMockTestCase { private final Group localGroup = getGroup(CLIENT_ID, MAJOR_VERSION); private final Group contactGroup = getGroup(CLIENT_ID, MAJOR_VERSION); private final Contact contact = getContact(); + private final long now = System.currentTimeMillis(); private final AutoDeleteManagerImpl autoDeleteManager; @@ -113,15 +120,44 @@ public class AutoDeleteManagerImplTest extends BrambleMockTestCase { @Test public void testStoresTimer() throws Exception { Transaction txn = new Transaction(null, false); - long timer = MAX_AUTO_DELETE_TIMER_MS; - BdfDictionary meta = BdfDictionary.of( - new BdfEntry(GROUP_KEY_AUTO_DELETE_TIMER, timer)); + long oldTimer = MIN_AUTO_DELETE_TIMER_MS; + long newTimer = MAX_AUTO_DELETE_TIMER_MS; + BdfDictionary oldMeta = BdfDictionary.of( + new BdfEntry(GROUP_KEY_TIMER, oldTimer), + new BdfEntry(GROUP_KEY_PREVIOUS_TIMER, NO_PREVIOUS_TIMER), + new BdfEntry(GROUP_KEY_TIMESTAMP, now)); + BdfDictionary newMeta = BdfDictionary.of( + new BdfEntry(GROUP_KEY_TIMER, newTimer), + new BdfEntry(GROUP_KEY_PREVIOUS_TIMER, oldTimer)); expectGetContact(txn); expectGetContactGroup(); context.checking(new Expectations() {{ + oneOf(clientHelper).getGroupMetadataAsDictionary(txn, + contactGroup.getId()); + will(returnValue(oldMeta)); oneOf(clientHelper).mergeGroupMetadata(txn, - contactGroup.getId(), meta); + contactGroup.getId(), newMeta); + }}); + + autoDeleteManager.setAutoDeleteTimer(txn, contact.getId(), newTimer); + } + + @Test + public void testDoesNotStoreTimerIfUnchanged() throws Exception { + Transaction txn = new Transaction(null, false); + long timer = MAX_AUTO_DELETE_TIMER_MS; + BdfDictionary meta = BdfDictionary.of( + new BdfEntry(GROUP_KEY_TIMER, timer), + new BdfEntry(GROUP_KEY_PREVIOUS_TIMER, NO_PREVIOUS_TIMER), + new BdfEntry(GROUP_KEY_TIMESTAMP, now)); + + expectGetContact(txn); + expectGetContactGroup(); + context.checking(new Expectations() {{ + oneOf(clientHelper).getGroupMetadataAsDictionary(txn, + contactGroup.getId()); + will(returnValue(meta)); }}); autoDeleteManager.setAutoDeleteTimer(txn, contact.getId(), timer); @@ -133,7 +169,10 @@ public class AutoDeleteManagerImplTest extends BrambleMockTestCase { long timer = MAX_AUTO_DELETE_TIMER_MS; BdfDictionary meta = BdfDictionary.of( new BdfEntry(GROUP_KEY_CONTACT_ID, contact.getId().getInt()), - new BdfEntry(GROUP_KEY_AUTO_DELETE_TIMER, timer)); + new BdfEntry(GROUP_KEY_TIMER, timer)); + BdfDictionary newMeta = BdfDictionary.of( + new BdfEntry(GROUP_KEY_TIMESTAMP, now), + new BdfEntry(GROUP_KEY_PREVIOUS_TIMER, NO_PREVIOUS_TIMER)); expectGetContact(txn); expectGetContactGroup(); @@ -141,10 +180,12 @@ public class AutoDeleteManagerImplTest extends BrambleMockTestCase { oneOf(clientHelper).getGroupMetadataAsDictionary(txn, contactGroup.getId()); will(returnValue(meta)); + oneOf(clientHelper).mergeGroupMetadata(txn, contactGroup.getId(), + newMeta); }}); - assertEquals(timer, - autoDeleteManager.getAutoDeleteTimer(txn, contact.getId())); + assertEquals(timer, autoDeleteManager + .getAutoDeleteTimer(txn, contact.getId(), now)); } @Test @@ -152,6 +193,44 @@ public class AutoDeleteManagerImplTest extends BrambleMockTestCase { Transaction txn = new Transaction(null, false); BdfDictionary meta = BdfDictionary.of( new BdfEntry(GROUP_KEY_CONTACT_ID, contact.getId().getInt())); + BdfDictionary newMeta = BdfDictionary.of( + new BdfEntry(GROUP_KEY_TIMESTAMP, now), + new BdfEntry(GROUP_KEY_PREVIOUS_TIMER, NO_PREVIOUS_TIMER)); + + expectGetContact(txn); + expectGetContactGroup(); + context.checking(new Expectations() {{ + oneOf(clientHelper).getGroupMetadataAsDictionary(txn, + contactGroup.getId()); + will(returnValue(meta)); + oneOf(clientHelper).mergeGroupMetadata(txn, contactGroup.getId(), + newMeta); + }}); + + assertEquals(NO_AUTO_DELETE_TIMER, autoDeleteManager + .getAutoDeleteTimer(txn, contact.getId(), now)); + } + + @Test + public void testIgnoresReceivedTimerWithEarlierTimestamp() + throws Exception { + testIgnoresReceivedTimerWithTimestamp(now - 1); + } + + @Test + public void testIgnoresReceivedTimerWithEqualTimestamp() throws Exception { + testIgnoresReceivedTimerWithTimestamp(now); + } + + private void testIgnoresReceivedTimerWithTimestamp(long remoteTimestamp) + throws Exception { + Transaction txn = new Transaction(null, false); + long localTimer = MIN_AUTO_DELETE_TIMER_MS; + long remoteTimer = MAX_AUTO_DELETE_TIMER_MS; + BdfDictionary meta = BdfDictionary.of( + new BdfEntry(GROUP_KEY_TIMER, localTimer), + new BdfEntry(GROUP_KEY_PREVIOUS_TIMER, NO_PREVIOUS_TIMER), + new BdfEntry(GROUP_KEY_TIMESTAMP, now)); expectGetContact(txn); expectGetContactGroup(); @@ -161,8 +240,99 @@ public class AutoDeleteManagerImplTest extends BrambleMockTestCase { will(returnValue(meta)); }}); - assertEquals(NO_AUTO_DELETE_TIMER, - autoDeleteManager.getAutoDeleteTimer(txn, contact.getId())); + autoDeleteManager.receiveAutoDeleteTimer(txn, contact.getId(), + remoteTimer, remoteTimestamp); + } + + @Test + public void testMirrorsRemoteTimestampIfNoUnsentChange() throws Exception { + Transaction txn = new Transaction(null, false); + long localTimer = MIN_AUTO_DELETE_TIMER_MS; + long remoteTimer = MAX_AUTO_DELETE_TIMER_MS; + long remoteTimestamp = now + 1; + BdfDictionary oldMeta = BdfDictionary.of( + new BdfEntry(GROUP_KEY_TIMER, localTimer), + new BdfEntry(GROUP_KEY_PREVIOUS_TIMER, NO_PREVIOUS_TIMER), + new BdfEntry(GROUP_KEY_TIMESTAMP, now)); + // The timestamp should be updated and the timer should be mirrored + BdfDictionary newMeta = BdfDictionary.of( + new BdfEntry(GROUP_KEY_TIMESTAMP, remoteTimestamp), + new BdfEntry(GROUP_KEY_TIMER, remoteTimer)); + + expectGetContact(txn); + expectGetContactGroup(); + context.checking(new Expectations() {{ + oneOf(clientHelper).getGroupMetadataAsDictionary(txn, + contactGroup.getId()); + will(returnValue(oldMeta)); + oneOf(clientHelper).mergeGroupMetadata(txn, + contactGroup.getId(), newMeta); + }}); + + autoDeleteManager.receiveAutoDeleteTimer(txn, contact.getId(), + remoteTimer, remoteTimestamp); + } + + @Test + public void testDoesNotMirrorUnchangedRemoteTimestampIfUnsentChange() + throws Exception { + Transaction txn = new Transaction(null, false); + long localTimer = MIN_AUTO_DELETE_TIMER_MS; + long remoteTimer = MAX_AUTO_DELETE_TIMER_MS; + long remoteTimestamp = now + 1; + BdfDictionary oldMeta = BdfDictionary.of( + new BdfEntry(GROUP_KEY_TIMER, localTimer), + new BdfEntry(GROUP_KEY_PREVIOUS_TIMER, remoteTimer), + new BdfEntry(GROUP_KEY_TIMESTAMP, now)); + // The timestamp should be updated but the timer should not revert + BdfDictionary newMeta = BdfDictionary.of( + new BdfEntry(GROUP_KEY_TIMESTAMP, remoteTimestamp)); + + expectGetContact(txn); + expectGetContactGroup(); + context.checking(new Expectations() {{ + oneOf(clientHelper).getGroupMetadataAsDictionary(txn, + contactGroup.getId()); + will(returnValue(oldMeta)); + oneOf(clientHelper).mergeGroupMetadata(txn, + contactGroup.getId(), newMeta); + }}); + + autoDeleteManager.receiveAutoDeleteTimer(txn, contact.getId(), + remoteTimer, remoteTimestamp); + } + + @Test + public void testMirrorsChangedRemoteTimestampIfUnsentChange() + throws Exception { + Transaction txn = new Transaction(null, false); + long localTimer = MIN_AUTO_DELETE_TIMER_MS; + long oldRemoteTimer = MAX_AUTO_DELETE_TIMER_MS; + long newRemoteTimer = MAX_AUTO_DELETE_TIMER_MS - 1; + long remoteTimestamp = now + 1; + BdfDictionary oldMeta = BdfDictionary.of( + new BdfEntry(GROUP_KEY_TIMER, localTimer), + new BdfEntry(GROUP_KEY_PREVIOUS_TIMER, oldRemoteTimer), + new BdfEntry(GROUP_KEY_TIMESTAMP, now)); + // The timestamp should be updated , the timer should be mirrored and + // the previous timer should be cleared + BdfDictionary newMeta = BdfDictionary.of( + new BdfEntry(GROUP_KEY_TIMESTAMP, remoteTimestamp), + new BdfEntry(GROUP_KEY_TIMER, newRemoteTimer), + new BdfEntry(GROUP_KEY_PREVIOUS_TIMER, NO_PREVIOUS_TIMER)); + + expectGetContact(txn); + expectGetContactGroup(); + context.checking(new Expectations() {{ + oneOf(clientHelper).getGroupMetadataAsDictionary(txn, + contactGroup.getId()); + will(returnValue(oldMeta)); + oneOf(clientHelper).mergeGroupMetadata(txn, + contactGroup.getId(), newMeta); + }}); + + autoDeleteManager.receiveAutoDeleteTimer(txn, contact.getId(), + newRemoteTimer, remoteTimestamp); } private void expectGetContact(Transaction txn) throws Exception { 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 8eb16aa3c..991023c4b 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 @@ -256,7 +256,8 @@ abstract class AbstractProtocolEngineTest extends BrambleMockTestCase { void expectGetAutoDeleteTimer() throws Exception { context.checking(new Expectations() {{ - oneOf(autoDeleteManager).getAutoDeleteTimer(txn, contactId); + oneOf(autoDeleteManager).getAutoDeleteTimer(txn, contactId, + localTimestamp); will(returnValue(NO_AUTO_DELETE_TIMER)); }}); } From 49080cb64c6b22f21f6069dfc35eff99fbfa618a Mon Sep 17 00:00:00 2001 From: akwizgran Date: Thu, 3 Dec 2020 12:44:28 +0000 Subject: [PATCH 034/124] Hook up incoming messages to the auto-delete manager. --- .../introduction/AbstractProtocolEngine.java | 7 ++++++ .../IntroduceeProtocolEngine.java | 12 +++++++-- .../IntroducerProtocolEngine.java | 8 ++++++ .../briar/messaging/MessagingManagerImpl.java | 15 ++++++++--- .../invitation/AbstractProtocolEngine.java | 7 ++++++ .../invitation/CreatorProtocolEngine.java | 4 +++ .../invitation/InviteeProtocolEngine.java | 2 ++ .../briar/sharing/ProtocolEngineImpl.java | 15 +++++++++++ .../autodelete/AutoDeleteManagerImplTest.java | 3 +-- .../MessageSizeIntegrationTestComponent.java | 2 ++ ...plexMessagingIntegrationTestComponent.java | 2 ++ .../AbstractProtocolEngineTest.java | 25 ++++++++++++++++--- .../invitation/CreatorProtocolEngineTest.java | 14 +++-------- .../invitation/InviteeProtocolEngineTest.java | 4 +-- 14 files changed, 97 insertions(+), 23 deletions(-) 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 ee304f845..7d1894a3a 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 @@ -244,6 +244,13 @@ abstract class AbstractProtocolEngine> return conversationManager.getTimestampForOutgoingMessage(txn, c); } + void receiveAutoDeleteTimer(Transaction txn, AbstractIntroductionMessage m) + throws DbException { + ContactId c = getContactId(txn, m.getGroupId()); + autoDeleteManager.receiveAutoDeleteTimer(txn, c, m.getAutoDeleteTimer(), + m.getTimestamp()); + } + private ContactId getContactId(Transaction txn, GroupId contactGroupId) throws DbException { try { 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 5f1a2833f..4ea339851 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 @@ -259,6 +259,9 @@ class IntroduceeProtocolEngine messageTracker .trackMessage(txn, m.getGroupId(), m.getTimestamp(), false); + // Receive the auto-delete timer + receiveAutoDeleteTimer(txn, m); + // Broadcast IntroductionRequestReceivedEvent LocalAuthor localAuthor = identityManager.getLocalAuthor(txn); Contact c = contactManager.getContact(txn, s.getIntroducer().getId(), @@ -334,8 +337,7 @@ class IntroduceeProtocolEngine } private IntroduceeSession onRemoteAccept(Transaction txn, - IntroduceeSession s, AcceptMessage m) - throws DbException { + IntroduceeSession s, AcceptMessage m) throws DbException { // The timestamp must be higher than the last request message if (m.getTimestamp() <= s.getRequestTimestamp()) return abort(txn, s); @@ -343,6 +345,9 @@ class IntroduceeProtocolEngine if (isInvalidDependency(s, m.getPreviousMessageId())) return abort(txn, s); + // Receive the auto-delete timer + receiveAutoDeleteTimer(txn, m); + // Determine next state IntroduceeState state = s.getState() == AWAIT_RESPONSES ? REMOTE_ACCEPTED : AWAIT_AUTH; @@ -372,6 +377,9 @@ class IntroduceeProtocolEngine messageTracker .trackMessage(txn, m.getGroupId(), m.getTimestamp(), false); + // Receive the auto-delete timer + receiveAutoDeleteTimer(txn, m); + // Broadcast IntroductionResponseReceivedEvent broadcastIntroductionResponseReceivedEvent(txn, s, s.getIntroducer().getId(), s.getRemote().author, m, false); 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 3607a354b..b0d1dbdd7 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 @@ -262,6 +262,8 @@ class IntroducerProtocolEngine // Track the incoming message messageTracker .trackMessage(txn, m.getGroupId(), m.getTimestamp(), false); + // Receive the auto-delete timer + receiveAutoDeleteTimer(txn, m); // Forward ACCEPT message Introducee i = getOtherIntroducee(s, m.getGroupId()); @@ -323,6 +325,8 @@ class IntroducerProtocolEngine // Track the incoming message messageTracker .trackMessage(txn, m.getGroupId(), m.getTimestamp(), false); + // Receive the auto-delete timer + receiveAutoDeleteTimer(txn, m); // Forward ACCEPT message Introducee i = getOtherIntroducee(s, m.getGroupId()); @@ -376,6 +380,8 @@ class IntroducerProtocolEngine // Track the incoming message messageTracker .trackMessage(txn, m.getGroupId(), m.getTimestamp(), false); + // Receive the auto-delete timer + receiveAutoDeleteTimer(txn, m); // Forward DECLINE message Introducee i = getOtherIntroducee(s, m.getGroupId()); @@ -429,6 +435,8 @@ class IntroducerProtocolEngine // Track the incoming message messageTracker .trackMessage(txn, m.getGroupId(), m.getTimestamp(), false); + // Receive the auto-delete timer + receiveAutoDeleteTimer(txn, m); // Forward DECLINE message Introducee i = getOtherIntroducee(s, m.getGroupId()); diff --git a/briar-core/src/main/java/org/briarproject/briar/messaging/MessagingManagerImpl.java b/briar-core/src/main/java/org/briarproject/briar/messaging/MessagingManagerImpl.java index a79a91574..45ff75687 100644 --- a/briar-core/src/main/java/org/briarproject/briar/messaging/MessagingManagerImpl.java +++ b/briar-core/src/main/java/org/briarproject/briar/messaging/MessagingManagerImpl.java @@ -29,6 +29,7 @@ import org.briarproject.bramble.api.versioning.ClientVersioningManager; import org.briarproject.bramble.api.versioning.ClientVersioningManager.ClientVersioningHook; import org.briarproject.briar.api.attachment.AttachmentHeader; import org.briarproject.briar.api.attachment.FileTooBigException; +import org.briarproject.briar.api.autodelete.AutoDeleteManager; import org.briarproject.briar.api.client.MessageTracker; import org.briarproject.briar.api.client.MessageTracker.GroupCount; import org.briarproject.briar.api.conversation.ConversationManager.ConversationClient; @@ -87,18 +88,24 @@ class MessagingManagerImpl implements MessagingManager, IncomingMessageHook, private final MessageTracker messageTracker; private final ClientVersioningManager clientVersioningManager; private final ContactGroupFactory contactGroupFactory; + private final AutoDeleteManager autoDeleteManager; @Inject - MessagingManagerImpl(DatabaseComponent db, ClientHelper clientHelper, + MessagingManagerImpl( + DatabaseComponent db, + ClientHelper clientHelper, ClientVersioningManager clientVersioningManager, - MetadataParser metadataParser, MessageTracker messageTracker, - ContactGroupFactory contactGroupFactory) { + MetadataParser metadataParser, + MessageTracker messageTracker, + ContactGroupFactory contactGroupFactory, + AutoDeleteManager autoDeleteManager) { this.db = db; this.clientHelper = clientHelper; this.metadataParser = metadataParser; this.messageTracker = messageTracker; this.clientVersioningManager = clientVersioningManager; this.contactGroupFactory = contactGroupFactory; + this.autoDeleteManager = autoDeleteManager; } @Override @@ -203,6 +210,8 @@ class MessagingManagerImpl implements MessagingManager, IncomingMessageHook, new PrivateMessageReceivedEvent(header, contactId); txn.attach(event); messageTracker.trackIncomingMessage(txn, m); + autoDeleteManager.receiveAutoDeleteTimer(txn, contactId, timer, + timestamp); } private List parseAttachmentHeaders(GroupId g, 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 96a2f17f7..d11db5bbb 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 @@ -300,6 +300,13 @@ abstract class AbstractProtocolEngine> return max(s.getLocalTimestamp(), s.getInviteTimestamp()); } + void receiveAutoDeleteTimer(Transaction txn, + DeletableGroupInvitationMessage m) throws DbException { + ContactId c = getContactId(txn, m.getContactGroupId()); + autoDeleteManager.receiveAutoDeleteTimer(txn, c, m.getAutoDeleteTimer(), + m.getTimestamp()); + } + private void sendMessage(Transaction txn, Message m, MessageType type, GroupId privateGroupId, boolean visibleInConversation, long autoDeleteTimer) throws DbException { 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 ac483b1d6..07ff7a802 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 @@ -201,6 +201,8 @@ class CreatorProtocolEngine extends AbstractProtocolEngine { // Track the message messageTracker.trackMessage(txn, m.getContactGroupId(), m.getTimestamp(), false); + // Receive the auto-delete timer + receiveAutoDeleteTimer(txn, m); // Share the private group with the contact setPrivateGroupVisibility(txn, s, SHARED); // Broadcast an event @@ -226,6 +228,8 @@ class CreatorProtocolEngine extends AbstractProtocolEngine { // Track the message messageTracker.trackMessage(txn, m.getContactGroupId(), m.getTimestamp(), false); + // Receive the auto-delete timer + receiveAutoDeleteTimer(txn, m); // Broadcast an event ContactId contactId = clientHelper.getContactId(txn, m.getContactGroupId()); 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 87d82fdff..d7fdd070b 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 @@ -251,6 +251,8 @@ class InviteeProtocolEngine extends AbstractProtocolEngine { // Track the message messageTracker.trackMessage(txn, m.getContactGroupId(), m.getTimestamp(), false); + // Receive the auto-delete timer + receiveAutoDeleteTimer(txn, m); // Broadcast an event PrivateGroup privateGroup = privateGroupFactory.createPrivateGroup( m.getGroupName(), m.getCreator(), m.getSalt()); 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 8c3c423a5..381c22a12 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 @@ -360,6 +360,8 @@ abstract class ProtocolEngineImpl // Track the message messageTracker.trackMessage(txn, m.getContactGroupId(), m.getTimestamp(), false); + // Receive the auto-delete timer + receiveAutoDeleteTimer(txn, m); // Broadcast an event ContactId contactId = clientHelper.getContactId(txn, s.getContactGroupId()); @@ -385,6 +387,8 @@ abstract class ProtocolEngineImpl // Track the message messageTracker.trackMessage(txn, m.getContactGroupId(), m.getTimestamp(), false); + // Receive the auto-delete timer + receiveAutoDeleteTimer(txn, m); // Share the shareable with the contact setShareableVisibility(txn, s, SHARED); // Broadcast an event @@ -432,6 +436,8 @@ abstract class ProtocolEngineImpl // Track the message messageTracker.trackMessage(txn, m.getContactGroupId(), m.getTimestamp(), false); + // Receive the auto-delete timer + receiveAutoDeleteTimer(txn, m); // Broadcast an event ContactId contactId = clientHelper.getContactId(txn, m.getContactGroupId()); @@ -485,6 +491,8 @@ abstract class ProtocolEngineImpl // Track the message messageTracker.trackMessage(txn, m.getContactGroupId(), m.getTimestamp(), false); + // Receive the auto-delete timer + receiveAutoDeleteTimer(txn, m); // Make the shareable invisible (not actually needed in REMOTE_HANGING) try { setShareableVisibility(txn, s, INVISIBLE); @@ -719,6 +727,13 @@ abstract class ProtocolEngineImpl return max(s.getLocalTimestamp(), s.getInviteTimestamp()); } + private void receiveAutoDeleteTimer(Transaction txn, + DeletableSharingMessage m) throws DbException { + ContactId c = getContactId(txn, m.getContactGroupId()); + autoDeleteManager.receiveAutoDeleteTimer(txn, c, m.getAutoDeleteTimer(), + m.getTimestamp()); + } + private ContactId getContactId(Transaction txn, GroupId contactGroupId) throws DbException { try { diff --git a/briar-core/src/test/java/org/briarproject/briar/autodelete/AutoDeleteManagerImplTest.java b/briar-core/src/test/java/org/briarproject/briar/autodelete/AutoDeleteManagerImplTest.java index d63ac338e..853b931eb 100644 --- a/briar-core/src/test/java/org/briarproject/briar/autodelete/AutoDeleteManagerImplTest.java +++ b/briar-core/src/test/java/org/briarproject/briar/autodelete/AutoDeleteManagerImplTest.java @@ -28,8 +28,7 @@ import static org.briarproject.briar.autodelete.AutoDeleteConstants.GROUP_KEY_TI import static org.briarproject.briar.autodelete.AutoDeleteConstants.NO_PREVIOUS_TIMER; import static org.junit.Assert.assertEquals; -// Thank you, I'm using them for readability -@SuppressWarnings("UnnecessaryLocalVariable") +@SuppressWarnings("UnnecessaryLocalVariable") // Using them for readability public class AutoDeleteManagerImplTest extends BrambleMockTestCase { private final DatabaseComponent db = context.mock(DatabaseComponent.class); diff --git a/briar-core/src/test/java/org/briarproject/briar/messaging/MessageSizeIntegrationTestComponent.java b/briar-core/src/test/java/org/briarproject/briar/messaging/MessageSizeIntegrationTestComponent.java index 4aa2e44e6..214ccf854 100644 --- a/briar-core/src/test/java/org/briarproject/briar/messaging/MessageSizeIntegrationTestComponent.java +++ b/briar-core/src/test/java/org/briarproject/briar/messaging/MessageSizeIntegrationTestComponent.java @@ -3,6 +3,7 @@ package org.briarproject.briar.messaging; import org.briarproject.bramble.BrambleCoreIntegrationTestEagerSingletons; import org.briarproject.bramble.BrambleCoreModule; import org.briarproject.bramble.test.BrambleCoreIntegrationTestModule; +import org.briarproject.briar.autodelete.AutoDeleteModule; import org.briarproject.briar.avatar.AvatarModule; import org.briarproject.briar.client.BriarClientModule; import org.briarproject.briar.forum.ForumModule; @@ -17,6 +18,7 @@ import dagger.Component; BrambleCoreIntegrationTestModule.class, BrambleCoreModule.class, BriarClientModule.class, + AutoDeleteModule.class, AvatarModule.class, ForumModule.class, IdentityModule.class, diff --git a/briar-core/src/test/java/org/briarproject/briar/messaging/SimplexMessagingIntegrationTestComponent.java b/briar-core/src/test/java/org/briarproject/briar/messaging/SimplexMessagingIntegrationTestComponent.java index 250e8bbda..56ba72fe3 100644 --- a/briar-core/src/test/java/org/briarproject/briar/messaging/SimplexMessagingIntegrationTestComponent.java +++ b/briar-core/src/test/java/org/briarproject/briar/messaging/SimplexMessagingIntegrationTestComponent.java @@ -10,6 +10,7 @@ import org.briarproject.bramble.api.lifecycle.LifecycleManager; import org.briarproject.bramble.test.BrambleCoreIntegrationTestModule; import org.briarproject.briar.api.messaging.MessagingManager; import org.briarproject.briar.api.messaging.PrivateMessageFactory; +import org.briarproject.briar.autodelete.AutoDeleteModule; import org.briarproject.briar.client.BriarClientModule; import javax.inject.Singleton; @@ -18,6 +19,7 @@ import dagger.Component; @Singleton @Component(modules = { + AutoDeleteModule.class, BrambleCoreIntegrationTestModule.class, BrambleCoreModule.class, BriarClientModule.class, 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 991023c4b..1978d2b7f 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 @@ -153,7 +153,7 @@ abstract class AbstractProtocolEngineTest extends BrambleMockTestCase { if (visible) expectGetTimestampForVisibleMessage(messageTimestamp); else expectGetTimestampForInvisibleMessage(messageTimestamp); expectCheckWhetherContactSupportsAutoDeletion(); - if (visible) expectGetAutoDeleteTimer(); + if (visible) expectGetAutoDeleteTimer(messageTimestamp); context.checking(new Expectations() {{ oneOf(messageEncoder).encodeJoinMessage(m.getContactGroupId(), m.getPrivateGroupId(), m.getTimestamp(), @@ -167,7 +167,7 @@ abstract class AbstractProtocolEngineTest extends BrambleMockTestCase { if (visible) expectGetTimestampForVisibleMessage(messageTimestamp); else expectGetTimestampForInvisibleMessage(messageTimestamp); expectCheckWhetherContactSupportsAutoDeletion(); - if (visible) expectGetAutoDeleteTimer(); + if (visible) expectGetAutoDeleteTimer(messageTimestamp); context.checking(new Expectations() {{ oneOf(messageEncoder).encodeLeaveMessage(contactGroupId, privateGroupId, messageTimestamp, lastLocalMessageId, @@ -254,11 +254,28 @@ abstract class AbstractProtocolEngineTest extends BrambleMockTestCase { }}); } - void expectGetAutoDeleteTimer() throws Exception { + void expectGetAutoDeleteTimer(long timestamp) throws Exception { context.checking(new Expectations() {{ oneOf(autoDeleteManager).getAutoDeleteTimer(txn, contactId, - localTimestamp); + timestamp); will(returnValue(NO_AUTO_DELETE_TIMER)); }}); } + + void expectTrackUnreadMessage(long timestamp) throws Exception { + context.checking(new Expectations() {{ + oneOf(messageTracker).trackMessage(txn, contactGroupId, timestamp, + false); + }}); + } + + void expectReceiveAutoDeleteTimer(DeletableGroupInvitationMessage m) + throws Exception { + context.checking(new Expectations() {{ + oneOf(clientHelper).getContactId(txn, contactGroupId); + will(returnValue(contactId)); + oneOf(autoDeleteManager).receiveAutoDeleteTimer(txn, contactId, + m.getAutoDeleteTimer(), m.getTimestamp()); + }}); + } } 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 6faaace02..4a3e7fb85 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 @@ -308,11 +308,8 @@ public class CreatorProtocolEngineTest extends AbstractProtocolEngineTest { expectSendJoinMessage(properJoinMessage, false); expectMarkMessageVisibleInUi(properJoinMessage.getId()); - context.checking(new Expectations() {{ - oneOf(messageTracker) - .trackMessage(txn, contactGroupId, inviteTimestamp + 1, - false); - }}); + expectTrackUnreadMessage(properJoinMessage.getTimestamp()); + expectReceiveAutoDeleteTimer(properJoinMessage); expectGetContactId(); expectSetPrivateGroupVisibility(SHARED); CreatorSession newSession = @@ -399,11 +396,8 @@ public class CreatorProtocolEngineTest extends AbstractProtocolEngineTest { CreatorSession session = getDefaultSession(INVITED); expectMarkMessageVisibleInUi(properLeaveMessage.getId()); - context.checking(new Expectations() {{ - oneOf(messageTracker) - .trackMessage(txn, contactGroupId, inviteTimestamp + 1, - false); - }}); + expectTrackUnreadMessage(properLeaveMessage.getTimestamp()); + expectReceiveAutoDeleteTimer(properLeaveMessage); expectGetContactId(); CreatorSession newSession = engine.onLeaveMessage(txn, session, properLeaveMessage); 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 27c635d3c..7631aeb83 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 @@ -366,9 +366,9 @@ public class InviteeProtocolEngineTest extends AbstractProtocolEngineTest { }}); expectMarkMessageVisibleInUi(properInviteMessage.getId()); expectMarkMessageAvailableToAnswer(properInviteMessage.getId(), true); + expectTrackUnreadMessage(properInviteMessage.getTimestamp()); + expectReceiveAutoDeleteTimer(properInviteMessage); context.checking(new Expectations() {{ - oneOf(messageTracker).trackMessage(txn, contactGroupId, - properInviteMessage.getTimestamp(), false); oneOf(privateGroupFactory) .createPrivateGroup(properInviteMessage.getGroupName(), properInviteMessage.getCreator(), From c3057141d81beda8f92648b5bf94c44514ee3a0d Mon Sep 17 00:00:00 2001 From: akwizgran Date: Thu, 3 Dec 2020 16:55:18 +0000 Subject: [PATCH 035/124] Don't receive auto-delete timer from remote accept message as introducee. --- .../briar/introduction/IntroduceeProtocolEngine.java | 3 --- 1 file changed, 3 deletions(-) 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 4ea339851..bd978f746 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 @@ -345,9 +345,6 @@ class IntroduceeProtocolEngine if (isInvalidDependency(s, m.getPreviousMessageId())) return abort(txn, s); - // Receive the auto-delete timer - receiveAutoDeleteTimer(txn, m); - // Determine next state IntroduceeState state = s.getState() == AWAIT_RESPONSES ? REMOTE_ACCEPTED : AWAIT_AUTH; From f941a73999b14cd8bf5cbb5b7e67f753e5b29c06 Mon Sep 17 00:00:00 2001 From: akwizgran Date: Thu, 3 Dec 2020 18:00:31 +0000 Subject: [PATCH 036/124] Update integration tests. --- .../invitation/GroupInvitationIntegrationTest.java | 2 +- .../org/briarproject/briar/test/BriarIntegrationTest.java | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) 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 5a9064f28..e2c49bb24 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 @@ -743,7 +743,7 @@ public class GroupInvitationIntegrationTest throws DbException { byte[] signature = groupInvitationFactory.signInvitation(contact1From0, privateGroup.getId(), timestamp, author0.getPrivateKey()); - long timer = getAutoDeleteTimer(c0, contactId1From0); + long timer = getAutoDeleteTimer(c0, contactId1From0, timestamp); groupInvitationManager0.sendInvitation(privateGroup.getId(), contactId1From0, text, timestamp, signature, timer); } diff --git a/briar-core/src/test/java/org/briarproject/briar/test/BriarIntegrationTest.java b/briar-core/src/test/java/org/briarproject/briar/test/BriarIntegrationTest.java index 79cee06da..6711de50d 100644 --- a/briar-core/src/test/java/org/briarproject/briar/test/BriarIntegrationTest.java +++ b/briar-core/src/test/java/org/briarproject/briar/test/BriarIntegrationTest.java @@ -460,9 +460,9 @@ public abstract class BriarIntegrationTest component.getAutoDeleteManager().getAutoDeleteTimer(txn, - contactId)); + contactId, timestamp)); } } From 8d6bd29b9333ef0dc6d13328f12bfbe8404ceff7 Mon Sep 17 00:00:00 2001 From: akwizgran Date: Fri, 4 Dec 2020 12:10:10 +0000 Subject: [PATCH 037/124] Add method for UI and tests to get current timer. --- .../briar/api/autodelete/AutoDeleteManager.java | 7 +++++++ .../briar/autodelete/AutoDeleteManagerImpl.java | 13 +++++++++++++ 2 files changed, 20 insertions(+) diff --git a/briar-api/src/main/java/org/briarproject/briar/api/autodelete/AutoDeleteManager.java b/briar-api/src/main/java/org/briarproject/briar/api/autodelete/AutoDeleteManager.java index 8599892d1..fac485335 100644 --- a/briar-api/src/main/java/org/briarproject/briar/api/autodelete/AutoDeleteManager.java +++ b/briar-api/src/main/java/org/briarproject/briar/api/autodelete/AutoDeleteManager.java @@ -24,6 +24,13 @@ public interface AutoDeleteManager { */ int MINOR_VERSION = 0; + /** + * Returns the auto-delete timer duration for the given contact. Use + * {@link #getAutoDeleteTimer(Transaction, ContactId, long)} if the timer + * will be used in an outgoing message. + */ + long getAutoDeleteTimer(Transaction txn, ContactId c) throws DbException; + /** * Returns the auto-delete timer duration for the given contact, for use in * a message with the given timestamp. The timestamp is stored. diff --git a/briar-core/src/main/java/org/briarproject/briar/autodelete/AutoDeleteManagerImpl.java b/briar-core/src/main/java/org/briarproject/briar/autodelete/AutoDeleteManagerImpl.java index e0644c63e..c07759092 100644 --- a/briar-core/src/main/java/org/briarproject/briar/autodelete/AutoDeleteManagerImpl.java +++ b/briar-core/src/main/java/org/briarproject/briar/autodelete/AutoDeleteManagerImpl.java @@ -78,6 +78,19 @@ class AutoDeleteManagerImpl db.removeGroup(txn, getGroup(c)); } + @Override + public long getAutoDeleteTimer(Transaction txn, ContactId c) + throws DbException { + try { + Group g = getGroup(db.getContact(txn, c)); + BdfDictionary meta = + clientHelper.getGroupMetadataAsDictionary(txn, g.getId()); + return meta.getLong(GROUP_KEY_TIMER, NO_AUTO_DELETE_TIMER); + } catch (FormatException e) { + throw new DbException(e); + } + } + @Override public long getAutoDeleteTimer(Transaction txn, ContactId c, long timestamp) throws DbException { From e12ad0cd7972b9865547eec5665ea43f6bc2fe8c Mon Sep 17 00:00:00 2001 From: akwizgran Date: Fri, 4 Dec 2020 12:10:43 +0000 Subject: [PATCH 038/124] Add integration tests for timer mirroring. --- .../blog/BlogManagerIntegrationTest.java | 2 - .../IntroductionIntegrationTest.java | 4 +- .../messaging/AutoDeleteIntegrationTest.java | 240 ++++++++++++++++++ .../GroupInvitationIntegrationTest.java | 8 +- .../sharing/BlogSharingIntegrationTest.java | 4 +- .../sharing/ForumSharingIntegrationTest.java | 4 +- .../briar/test/BriarIntegrationTest.java | 21 +- 7 files changed, 263 insertions(+), 20 deletions(-) create mode 100644 briar-core/src/test/java/org/briarproject/briar/messaging/AutoDeleteIntegrationTest.java diff --git a/briar-core/src/test/java/org/briarproject/briar/blog/BlogManagerIntegrationTest.java b/briar-core/src/test/java/org/briarproject/briar/blog/BlogManagerIntegrationTest.java index 94fad0819..84d104e74 100644 --- a/briar-core/src/test/java/org/briarproject/briar/blog/BlogManagerIntegrationTest.java +++ b/briar-core/src/test/java/org/briarproject/briar/blog/BlogManagerIntegrationTest.java @@ -46,8 +46,6 @@ public class BlogManagerIntegrationTest public void setUp() throws Exception { super.setUp(); - author0 = identityManager0.getLocalAuthor(); - author1 = identityManager1.getLocalAuthor(); String rssTitle = getRandomString(MAX_AUTHOR_NAME_LENGTH); rssAuthor = c0.getAuthorFactory().createLocalAuthor(rssTitle); 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 2c2eacf21..7ffdc7ccb 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 @@ -263,8 +263,8 @@ public class IntroductionIntegrationTest addListeners(true, true); // 0 and 1 set an auto-delete timer for their conversation - setAutoDeleteTimer(c0, contactId1From0); - setAutoDeleteTimer(c1, contactId0From1); + setAutoDeleteTimer(c0, contactId1From0, MIN_AUTO_DELETE_TIMER_MS); + setAutoDeleteTimer(c1, contactId0From1, MIN_AUTO_DELETE_TIMER_MS); // Make introduction introductionManager0 diff --git a/briar-core/src/test/java/org/briarproject/briar/messaging/AutoDeleteIntegrationTest.java b/briar-core/src/test/java/org/briarproject/briar/messaging/AutoDeleteIntegrationTest.java new file mode 100644 index 000000000..1778b7115 --- /dev/null +++ b/briar-core/src/test/java/org/briarproject/briar/messaging/AutoDeleteIntegrationTest.java @@ -0,0 +1,240 @@ +package org.briarproject.briar.messaging; + +import org.briarproject.bramble.api.contact.ContactId; +import org.briarproject.bramble.api.db.DatabaseComponent; +import org.briarproject.bramble.api.db.DbException; +import org.briarproject.bramble.api.sync.GroupId; +import org.briarproject.bramble.api.sync.MessageId; +import org.briarproject.bramble.test.TestDatabaseConfigModule; +import org.briarproject.briar.api.autodelete.AutoDeleteManager; +import org.briarproject.briar.api.conversation.ConversationManager; +import org.briarproject.briar.api.conversation.ConversationMessageHeader; +import org.briarproject.briar.api.messaging.MessagingManager; +import org.briarproject.briar.api.messaging.PrivateMessage; +import org.briarproject.briar.api.messaging.PrivateMessageFactory; +import org.briarproject.briar.test.BriarIntegrationTest; +import org.briarproject.briar.test.BriarIntegrationTestComponent; +import org.briarproject.briar.test.DaggerBriarIntegrationTestComponent; +import org.junit.Test; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; + +import static java.util.Collections.emptyList; +import static org.briarproject.briar.api.autodelete.AutoDeleteConstants.MIN_AUTO_DELETE_TIMER_MS; +import static org.briarproject.briar.api.autodelete.AutoDeleteConstants.NO_AUTO_DELETE_TIMER; +import static org.junit.Assert.assertEquals; + +public class AutoDeleteIntegrationTest + extends BriarIntegrationTest { + + @Override + protected void createComponents() { + BriarIntegrationTestComponent component = + DaggerBriarIntegrationTestComponent.builder().build(); + BriarIntegrationTestComponent.Helper.injectEagerSingletons(component); + component.inject(this); + + c0 = DaggerBriarIntegrationTestComponent.builder() + .testDatabaseConfigModule(new TestDatabaseConfigModule(t0Dir)) + .build(); + BriarIntegrationTestComponent.Helper.injectEagerSingletons(c0); + + c1 = DaggerBriarIntegrationTestComponent.builder() + .testDatabaseConfigModule(new TestDatabaseConfigModule(t1Dir)) + .build(); + BriarIntegrationTestComponent.Helper.injectEagerSingletons(c1); + + c2 = DaggerBriarIntegrationTestComponent.builder() + .testDatabaseConfigModule(new TestDatabaseConfigModule(t2Dir)) + .build(); + BriarIntegrationTestComponent.Helper.injectEagerSingletons(c2); + } + + @Test + public void testMessageWithoutTimer() throws Exception { + // 0 creates a message without a timer + MessageId messageId = createMessageWithoutTimer(c0, contactId1From0); + // The message should have been added to 0's view of the conversation + List headers0 = + getMessageHeaders(c0, contactId1From0); + assertEquals(1, headers0.size()); + ConversationMessageHeader h0 = headers0.get(0); + assertEquals(messageId, h0.getId()); + // The message should not have a timer + assertEquals(NO_AUTO_DELETE_TIMER, h0.getAutoDeleteTimer()); + // Sync the message to 1 + sync0To1(1, true); + // The message should have been added to 1's view of the conversation + List headers1 = + getMessageHeaders(c1, contactId0From1); + assertEquals(1, headers1.size()); + ConversationMessageHeader h1 = headers1.get(0); + assertEquals(messageId, h1.getId()); + // The message should not have a timer + assertEquals(NO_AUTO_DELETE_TIMER, h1.getAutoDeleteTimer()); + } + + @Test + public void testDefaultTimer() throws Exception { + // 0 creates a message with the default timer + MessageId messageId = createMessageWithTimer(c0, contactId1From0); + // The message should have been added to 0's view of the conversation + List headers0 = + getMessageHeaders(c0, contactId1From0); + assertEquals(1, headers0.size()); + ConversationMessageHeader h0 = headers0.get(0); + assertEquals(messageId, h0.getId()); + // The message should have the default timer (none) + assertEquals(NO_AUTO_DELETE_TIMER, h0.getAutoDeleteTimer()); + // Sync the message to 1 + sync0To1(1, true); + // The message should have been added to 1's view of the conversation + List headers1 = + getMessageHeaders(c1, contactId0From1); + assertEquals(1, headers1.size()); + ConversationMessageHeader h1 = headers1.get(0); + assertEquals(messageId, h1.getId()); + // The message should have the default timer (none) + assertEquals(NO_AUTO_DELETE_TIMER, h1.getAutoDeleteTimer()); + // Both peers should still be using the default timer + assertEquals(NO_AUTO_DELETE_TIMER, + getAutoDeleteTimer(c0, contactId1From0)); + assertEquals(NO_AUTO_DELETE_TIMER, + getAutoDeleteTimer(c1, contactId0From1)); + } + + @Test + public void testTimerIsMirrored() throws Exception { + // Set 0's timer + setAutoDeleteTimer(c0, contactId1From0, MIN_AUTO_DELETE_TIMER_MS); + // 0 should be using the new timer + assertEquals(MIN_AUTO_DELETE_TIMER_MS, + getAutoDeleteTimer(c0, contactId1From0)); + // 1 should still be using the default timer + assertEquals(NO_AUTO_DELETE_TIMER, + getAutoDeleteTimer(c1, contactId0From1)); + // 0 creates a message with the new timer + MessageId messageId0 = createMessageWithTimer(c0, contactId1From0); + // The message should have been added to 0's view of the conversation + List headers0 = + getMessageHeaders(c0, contactId1From0); + assertEquals(1, headers0.size()); + ConversationMessageHeader h0 = headers0.get(0); + assertEquals(messageId0, h0.getId()); + // The message should have the new timer + assertEquals(MIN_AUTO_DELETE_TIMER_MS, h0.getAutoDeleteTimer()); + // Sync the message to 1 + sync0To1(1, true); + // The message should have been added to 1's view of the conversation + List headers1 = + getMessageHeaders(c1, contactId0From1); + assertEquals(1, headers1.size()); + ConversationMessageHeader h1 = headers1.get(0); + assertEquals(messageId0, h1.getId()); + // The message should have the new timer + assertEquals(MIN_AUTO_DELETE_TIMER_MS, h1.getAutoDeleteTimer()); + // 0 and 1 should both be using the new timer + assertEquals(MIN_AUTO_DELETE_TIMER_MS, + getAutoDeleteTimer(c0, contactId1From0)); + assertEquals(MIN_AUTO_DELETE_TIMER_MS, + getAutoDeleteTimer(c1, contactId0From1)); + // 1 creates a message + MessageId messageId1 = createMessageWithTimer(c1, contactId0From1); + // The message should have been added to 1's view of the conversation + headers1 = getMessageHeaders(c1, contactId0From1); + assertEquals(2, headers1.size()); + assertEquals(messageId0, headers1.get(0).getId()); + assertEquals(messageId1, headers1.get(1).getId()); + // The message should have the new timer + assertEquals(MIN_AUTO_DELETE_TIMER_MS, + headers1.get(1).getAutoDeleteTimer()); + // Sync the message to 0 + sync1To0(1, true); + // The message should have been added to 0's view of the conversation + headers0 = getMessageHeaders(c0, contactId1From0); + assertEquals(2, headers0.size()); + assertEquals(messageId0, headers0.get(0).getId()); + assertEquals(messageId1, headers0.get(1).getId()); + // The message should have the new timer + assertEquals(MIN_AUTO_DELETE_TIMER_MS, + headers0.get(1).getAutoDeleteTimer()); + // 0 and 1 should both be using the new timer + assertEquals(MIN_AUTO_DELETE_TIMER_MS, + getAutoDeleteTimer(c0, contactId1From0)); + assertEquals(MIN_AUTO_DELETE_TIMER_MS, + getAutoDeleteTimer(c1, contactId0From1)); + } + + private MessageId createMessageWithoutTimer( + BriarIntegrationTestComponent component, ContactId contactId) + throws Exception { + DatabaseComponent db = component.getDatabaseComponent(); + ConversationManager conversationManager = + component.getConversationManager(); + MessagingManager messagingManager = component.getMessagingManager(); + PrivateMessageFactory factory = component.getPrivateMessageFactory(); + + GroupId groupId = messagingManager.getConversationId(contactId); + return db.transactionWithResult(false, txn -> { + long timestamp = conversationManager + .getTimestampForOutgoingMessage(txn, contactId); + PrivateMessage m = factory.createPrivateMessage(groupId, timestamp, + "Hi!", emptyList()); + messagingManager.addLocalMessage(txn, m); + return m.getMessage().getId(); + }); + } + + private MessageId createMessageWithTimer( + BriarIntegrationTestComponent component, ContactId contactId) + throws Exception { + DatabaseComponent db = component.getDatabaseComponent(); + ConversationManager conversationManager = + component.getConversationManager(); + AutoDeleteManager autoDeleteManager = component.getAutoDeleteManager(); + MessagingManager messagingManager = component.getMessagingManager(); + PrivateMessageFactory factory = component.getPrivateMessageFactory(); + + GroupId groupId = messagingManager.getConversationId(contactId); + return db.transactionWithResult(false, txn -> { + long timestamp = conversationManager + .getTimestampForOutgoingMessage(txn, contactId); + long timer = autoDeleteManager + .getAutoDeleteTimer(txn, contactId, timestamp); + PrivateMessage m = factory.createPrivateMessage(groupId, timestamp, + "Hi!", emptyList(), timer); + messagingManager.addLocalMessage(txn, m); + return m.getMessage().getId(); + }); + } + + private List getMessageHeaders( + BriarIntegrationTestComponent component, ContactId contactId) + throws Exception { + DatabaseComponent db = component.getDatabaseComponent(); + MessagingManager messagingManager = component.getMessagingManager(); + + return sortHeaders(db.transactionWithResult(true, txn -> + messagingManager.getMessageHeaders(txn, contactId))); + } + + private long getAutoDeleteTimer(BriarIntegrationTestComponent component, + ContactId contactId) throws DbException { + DatabaseComponent db = component.getDatabaseComponent(); + AutoDeleteManager autoDeleteManager = component.getAutoDeleteManager(); + + return db.transactionWithResult(false, + txn -> autoDeleteManager.getAutoDeleteTimer(txn, contactId)); + } + + private List sortHeaders( + Collection in) { + List out = new ArrayList<>(in); + //noinspection UseCompareMethod + out.sort((a, b) -> + Long.valueOf(a.getTimestamp()).compareTo(b.getTimestamp())); + return out; + } +} 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 e2c49bb24..f4cbd6c7c 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 @@ -168,8 +168,8 @@ public class GroupInvitationIntegrationTest @Test public void testInvitationDeclineWithAutoDelete() throws Exception { // 0 and 1 set an auto-delete timer for their conversation - setAutoDeleteTimer(c0, contactId1From0); - setAutoDeleteTimer(c1, contactId0From1); + setAutoDeleteTimer(c0, contactId1From0, MIN_AUTO_DELETE_TIMER_MS); + setAutoDeleteTimer(c1, contactId0From1, MIN_AUTO_DELETE_TIMER_MS); // Send invitation sendInvitation(clock.currentTimeMillis(), null); @@ -253,8 +253,8 @@ public class GroupInvitationIntegrationTest @Test public void testInvitationAcceptWithAutoDelete() throws Exception { // 0 and 1 set an auto-delete timer for their conversation - setAutoDeleteTimer(c0, contactId1From0); - setAutoDeleteTimer(c1, contactId0From1); + setAutoDeleteTimer(c0, contactId1From0, MIN_AUTO_DELETE_TIMER_MS); + setAutoDeleteTimer(c1, contactId0From1, MIN_AUTO_DELETE_TIMER_MS); // Send invitation sendInvitation(clock.currentTimeMillis(), null); 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 b8454c72d..173d3bebf 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 @@ -210,8 +210,8 @@ public class BlogSharingIntegrationTest listenToEvents(true); // Set an auto-delete timer for the conversation - setAutoDeleteTimer(c0, contactId1From0); - setAutoDeleteTimer(c1, contactId0From1); + setAutoDeleteTimer(c0, contactId1From0, MIN_AUTO_DELETE_TIMER_MS); + setAutoDeleteTimer(c1, contactId0From1, MIN_AUTO_DELETE_TIMER_MS); // Send invitation blogSharingManager0 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 999e9c022..f46b494aa 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 @@ -191,8 +191,8 @@ public class ForumSharingIntegrationTest @Test public void testSuccessfulSharingWithAutoDelete() throws Exception { // Set an auto-delete timer for the conversation - setAutoDeleteTimer(c0, contactId1From0); - setAutoDeleteTimer(c1, contactId0From1); + setAutoDeleteTimer(c0, contactId1From0, MIN_AUTO_DELETE_TIMER_MS); + setAutoDeleteTimer(c1, contactId0From1, MIN_AUTO_DELETE_TIMER_MS); // Send invitation forumSharingManager0 diff --git a/briar-core/src/test/java/org/briarproject/briar/test/BriarIntegrationTest.java b/briar-core/src/test/java/org/briarproject/briar/test/BriarIntegrationTest.java index 6711de50d..c2b353811 100644 --- a/briar-core/src/test/java/org/briarproject/briar/test/BriarIntegrationTest.java +++ b/briar-core/src/test/java/org/briarproject/briar/test/BriarIntegrationTest.java @@ -30,6 +30,7 @@ import org.briarproject.bramble.api.system.Clock; import org.briarproject.bramble.test.TestTransportConnectionReader; import org.briarproject.bramble.test.TestTransportConnectionWriter; import org.briarproject.bramble.test.TestUtils; +import org.briarproject.briar.api.autodelete.AutoDeleteManager; import org.briarproject.briar.api.blog.BlogFactory; import org.briarproject.briar.api.blog.BlogPostFactory; import org.briarproject.briar.api.client.MessageTracker; @@ -63,7 +64,6 @@ import static org.briarproject.bramble.api.sync.validation.MessageState.PENDING; import static org.briarproject.bramble.test.TestPluginConfigModule.SIMPLEX_TRANSPORT_ID; import static org.briarproject.bramble.test.TestUtils.getSecretKey; import static org.briarproject.bramble.util.LogUtils.logException; -import static org.briarproject.briar.api.autodelete.AutoDeleteConstants.MIN_AUTO_DELETE_TIMER_MS; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; @@ -453,16 +453,21 @@ public abstract class BriarIntegrationTest - component.getAutoDeleteManager().setAutoDeleteTimer(txn, - contactId, MIN_AUTO_DELETE_TIMER_MS)); + ContactId contactId, long timer) throws DbException { + DatabaseComponent db = component.getDatabaseComponent(); + AutoDeleteManager autoDeleteManager = component.getAutoDeleteManager(); + + db.transaction(false, txn -> + autoDeleteManager.setAutoDeleteTimer(txn, contactId, timer)); } protected long getAutoDeleteTimer(BriarIntegrationTestComponent component, ContactId contactId, long timestamp) throws DbException { - return component.getDatabaseComponent().transactionWithResult(false, - txn -> component.getAutoDeleteManager().getAutoDeleteTimer(txn, - contactId, timestamp)); + DatabaseComponent db = component.getDatabaseComponent(); + AutoDeleteManager autoDeleteManager = component.getAutoDeleteManager(); + + return db.transactionWithResult(false, + txn -> autoDeleteManager.getAutoDeleteTimer(txn, contactId, + timestamp)); } } From 1c93a794487eb092f31c0f1d30887a6f40e49001 Mon Sep 17 00:00:00 2001 From: akwizgran Date: Fri, 4 Dec 2020 12:16:58 +0000 Subject: [PATCH 039/124] Use Collections.sort() to satisfy Animal Sniffer. --- .../briar/messaging/AutoDeleteIntegrationTest.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/briar-core/src/test/java/org/briarproject/briar/messaging/AutoDeleteIntegrationTest.java b/briar-core/src/test/java/org/briarproject/briar/messaging/AutoDeleteIntegrationTest.java index 1778b7115..163c445d1 100644 --- a/briar-core/src/test/java/org/briarproject/briar/messaging/AutoDeleteIntegrationTest.java +++ b/briar-core/src/test/java/org/briarproject/briar/messaging/AutoDeleteIntegrationTest.java @@ -22,6 +22,7 @@ import java.util.Collection; import java.util.List; import static java.util.Collections.emptyList; +import static java.util.Collections.sort; import static org.briarproject.briar.api.autodelete.AutoDeleteConstants.MIN_AUTO_DELETE_TIMER_MS; import static org.briarproject.briar.api.autodelete.AutoDeleteConstants.NO_AUTO_DELETE_TIMER; import static org.junit.Assert.assertEquals; @@ -229,11 +230,11 @@ public class AutoDeleteIntegrationTest txn -> autoDeleteManager.getAutoDeleteTimer(txn, contactId)); } + @SuppressWarnings({"UseCompareMethod", "Java8ListSort"}) // Animal Sniffer private List sortHeaders( Collection in) { List out = new ArrayList<>(in); - //noinspection UseCompareMethod - out.sort((a, b) -> + sort(out, (a, b) -> Long.valueOf(a.getTimestamp()).compareTo(b.getTimestamp())); return out; } From d91e6c6c1abaaa29cc9810687a4e465989e28ee3 Mon Sep 17 00:00:00 2001 From: Torsten Grote Date: Fri, 4 Dec 2020 13:52:27 -0300 Subject: [PATCH 040/124] Allow setting a self-destruct timer This is a rough prototype of #1837 meant to make testing the UI easier. --- .../conversation/ConversationActivity.java | 11 ++++++++ .../conversation/ConversationViewModel.java | 16 +++++++++++ .../main/res/menu/conversation_actions.xml | 28 ++++++++++++------- briar-android/src/main/res/values/strings.xml | 1 + 4 files changed, 46 insertions(+), 10 deletions(-) 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 692a46a28..a0fecd904 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 @@ -138,6 +138,7 @@ import static org.briarproject.briar.android.util.UiUtils.observeOnce; import static org.briarproject.briar.android.view.AuthorView.setAvatar; import static org.briarproject.briar.api.messaging.MessagingConstants.MAX_ATTACHMENTS_PER_MESSAGE; import static org.briarproject.briar.api.messaging.MessagingConstants.MAX_PRIVATE_MESSAGE_TEXT_LENGTH; +import static org.briarproject.briar.api.messaging.PrivateMessageFormat.TEXT_IMAGES_AUTO_DELETE; import static org.briarproject.briar.api.messaging.PrivateMessageFormat.TEXT_ONLY; @MethodsNotNullByDefault @@ -366,6 +367,11 @@ public class ConversationActivity extends BriarActivity // enable alias action if available observeOnce(viewModel.getContactItem(), this, contact -> menu.findItem(R.id.action_set_alias).setEnabled(true)); + // show auto-delete timer setting only, if contacts supports it + observeOnce(viewModel.getPrivateMessageFormat(), this, format -> { + boolean visible = format == TEXT_IMAGES_AUTO_DELETE; + menu.findItem(R.id.action_auto_delete).setVisible(visible); + }); return super.onCreateOptionsMenu(menu); } @@ -387,6 +393,11 @@ public class ConversationActivity extends BriarActivity AliasDialogFragment.newInstance().show( getSupportFragmentManager(), AliasDialogFragment.TAG); return true; + case R.id.action_auto_delete: + boolean enabled = !item.isChecked(); + viewModel.setAutoDeleteTimerEnabled(enabled); + item.setChecked(enabled); + return true; case R.id.action_delete_all_messages: askToDeleteAllMessages(); return true; 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 66884d6c1..57e48aa88 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 @@ -59,6 +59,7 @@ import androidx.lifecycle.MutableLiveData; import static androidx.lifecycle.Transformations.map; import static java.util.Objects.requireNonNull; +import static java.util.concurrent.TimeUnit.DAYS; import static java.util.logging.Level.WARNING; import static java.util.logging.Logger.getLogger; import static org.briarproject.bramble.util.LogUtils.logDuration; @@ -66,6 +67,7 @@ import static org.briarproject.bramble.util.LogUtils.logException; import static org.briarproject.bramble.util.LogUtils.now; import static org.briarproject.briar.android.settings.SettingsFragment.SETTINGS_NAMESPACE; import static org.briarproject.briar.android.util.UiUtils.observeForeverOnce; +import static org.briarproject.briar.api.autodelete.AutoDeleteConstants.NO_AUTO_DELETE_TIMER; import static org.briarproject.briar.api.messaging.PrivateMessageFormat.TEXT_IMAGES; import static org.briarproject.briar.api.messaging.PrivateMessageFormat.TEXT_ONLY; @@ -367,6 +369,20 @@ public class ConversationViewModel extends DbViewModel }); } + void setAutoDeleteTimerEnabled(boolean enabled) { + final long timer = enabled ? DAYS.toMillis(7) : NO_AUTO_DELETE_TIMER; + // ContactId is set before menu gets inflated and UI interaction + final ContactId c = requireNonNull(contactId); + runOnDbThread(() -> { + try { + db.transaction(false, txn -> + autoDeleteManager.setAutoDeleteTimer(txn, c, timer)); + } catch (DbException e) { + logException(LOG, WARNING, e); + } + }); + } + AttachmentRetriever getAttachmentRetriever() { return attachmentRetriever; } diff --git a/briar-android/src/main/res/menu/conversation_actions.xml b/briar-android/src/main/res/menu/conversation_actions.xml index 8447178c7..8695171fa 100644 --- a/briar-android/src/main/res/menu/conversation_actions.xml +++ b/briar-android/src/main/res/menu/conversation_actions.xml @@ -1,30 +1,38 @@ -

+ + app:showAsAction="never" /> + android:title="@string/set_contact_alias" + app:showAsAction="never" /> + + + app:showAsAction="never" /> + app:showAsAction="never" /> - \ No newline at end of file + diff --git a/briar-android/src/main/res/values/strings.xml b/briar-android/src/main/res/values/strings.xml index 34314f7fc..f31ff3b4c 100644 --- a/briar-android/src/main/res/values/strings.xml +++ b/briar-android/src/main/res/values/strings.xml @@ -165,6 +165,7 @@ Image format unsupported: %s Change contact name Contact name + Disappearing messages Delete all messages Confirm Message Deletion Are you sure that you want to delete all messages? From 923185b3f4252141884a7d1917d54902fb34bacb Mon Sep 17 00:00:00 2001 From: Torsten Grote Date: Sat, 5 Dec 2020 09:52:08 -0300 Subject: [PATCH 041/124] Show timer change notices in private conversations --- .../conversation/ConversationAdapter.java | 84 +++++++++++++------ .../conversation/ConversationItem.java | 50 ++++++++++- .../ConversationItemViewHolder.java | 44 +++++++++- .../conversation/ConversationMessageItem.java | 5 +- .../conversation/ConversationNoticeItem.java | 9 +- .../conversation/ConversationRequestItem.java | 8 +- .../conversation/ConversationVisitor.java | 53 ++++++++---- .../list_item_conversation_msg_image.xml | 2 + .../list_item_conversation_msg_image_text.xml | 2 + .../layout/list_item_conversation_msg_in.xml | 17 ++-- .../list_item_conversation_msg_in_content.xml | 2 + .../layout/list_item_conversation_msg_out.xml | 10 ++- .../list_item_conversation_notice_in.xml | 9 +- .../list_item_conversation_notice_out.xml | 6 +- .../layout/list_item_conversation_request.xml | 6 +- .../list_item_conversation_top_notice_in.xml | 19 +++++ .../list_item_conversation_top_notice_out.xml | 21 +++++ briar-android/src/main/res/values/strings.xml | 8 ++ 18 files changed, 284 insertions(+), 71 deletions(-) create mode 100644 briar-android/src/main/res/layout/list_item_conversation_top_notice_in.xml create mode 100644 briar-android/src/main/res/layout/list_item_conversation_top_notice_out.xml diff --git a/briar-android/src/main/java/org/briarproject/briar/android/conversation/ConversationAdapter.java b/briar-android/src/main/java/org/briarproject/briar/android/conversation/ConversationAdapter.java index 1e7065df7..662ea2729 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/conversation/ConversationAdapter.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/conversation/ConversationAdapter.java @@ -13,6 +13,8 @@ import org.briarproject.briar.R; import org.briarproject.briar.android.util.BriarAdapter; import org.briarproject.briar.android.util.ItemReturningAdapter; +import java.util.Collection; + import androidx.annotation.LayoutRes; import androidx.annotation.Nullable; import androidx.recyclerview.selection.SelectionTracker; @@ -20,13 +22,14 @@ import androidx.recyclerview.widget.LinearLayoutManager; import androidx.recyclerview.widget.RecyclerView.RecycledViewPool; import static androidx.recyclerview.widget.RecyclerView.NO_POSITION; +import static org.briarproject.briar.api.autodelete.AutoDeleteConstants.NO_AUTO_DELETE_TIMER; @NotNullByDefault class ConversationAdapter extends BriarAdapter implements ItemReturningAdapter { - private ConversationListener listener; + private final ConversationListener listener; private final RecycledViewPool imageViewPool; private final ImageItemDecoration imageItemDecoration; @Nullable @@ -65,22 +68,20 @@ class ConversationAdapter @LayoutRes int type) { View v = LayoutInflater.from(viewGroup.getContext()).inflate( type, viewGroup, false); - switch (type) { - case R.layout.list_item_conversation_msg_in: - return new ConversationMessageViewHolder(v, listener, true, - imageViewPool, imageItemDecoration); - case R.layout.list_item_conversation_msg_out: - return new ConversationMessageViewHolder(v, listener, false, - imageViewPool, imageItemDecoration); - case R.layout.list_item_conversation_notice_in: - return new ConversationNoticeViewHolder(v, listener, true); - case R.layout.list_item_conversation_notice_out: - return new ConversationNoticeViewHolder(v, listener, false); - case R.layout.list_item_conversation_request: - return new ConversationRequestViewHolder(v, listener, true); - default: - throw new IllegalArgumentException("Unknown ConversationItem"); + if (type == R.layout.list_item_conversation_msg_in) { + return new ConversationMessageViewHolder(v, listener, true, + imageViewPool, imageItemDecoration); + } else if (type == R.layout.list_item_conversation_msg_out) { + return new ConversationMessageViewHolder(v, listener, false, + imageViewPool, imageItemDecoration); + } else if (type == R.layout.list_item_conversation_notice_in) { + return new ConversationNoticeViewHolder(v, listener, true); + } else if (type == R.layout.list_item_conversation_notice_out) { + return new ConversationNoticeViewHolder(v, listener, false); + } else if (type == R.layout.list_item_conversation_request) { + return new ConversationRequestViewHolder(v, listener, true); } + throw new IllegalArgumentException("Unknown ConversationItem"); } @Override @@ -107,22 +108,53 @@ class ConversationAdapter return c1.equals(c2); } + @Override + public void add(ConversationItem item) { + items.beginBatchedUpdates(); + items.add(item); + updateTimersInBatch(true); + items.endBatchedUpdates(); + } + + @Override + public void addAll(Collection itemsToAdd) { + items.beginBatchedUpdates(); + items.addAll(itemsToAdd); + updateTimersInBatch(false); + items.endBatchedUpdates(); + } + + private void updateTimersInBatch(boolean updateItems) { + long lastTimerIncoming = NO_AUTO_DELETE_TIMER; + long lastTimerOutgoing = NO_AUTO_DELETE_TIMER; + for (int i = 0; i < items.size(); i++) { + ConversationItem c = items.get(i); + boolean itemChanged; + boolean timerChanged; + boolean timerMirrored; + if (c.isIncoming()) { + timerChanged = lastTimerIncoming != c.getAutoDeleteTimer(); + timerMirrored = timerChanged && + lastTimerOutgoing == c.getAutoDeleteTimer(); + lastTimerIncoming = c.getAutoDeleteTimer(); + } else { + timerChanged = lastTimerOutgoing != c.getAutoDeleteTimer(); + timerMirrored = timerChanged && + lastTimerIncoming == c.getAutoDeleteTimer(); + lastTimerOutgoing = c.getAutoDeleteTimer(); + } + itemChanged = c.setTimerNoticeVisible(timerChanged); + itemChanged |= c.setTimerMirrored(timerMirrored); + if (itemChanged && updateItems) items.updateItemAt(i, c); + } + } + void setSelectionTracker(SelectionTracker tracker) { this.tracker = tracker; } - @Nullable - ConversationItem getLastItem() { - if (items.size() > 0) { - return items.get(items.size() - 1); - } else { - return null; - } - } - SparseArray getOutgoingMessages() { SparseArray messages = new SparseArray<>(); - for (int i = 0; i < items.size(); i++) { ConversationItem item = items.get(i); if (!item.isIncoming()) { diff --git a/briar-android/src/main/java/org/briarproject/briar/android/conversation/ConversationItem.java b/briar-android/src/main/java/org/briarproject/briar/android/conversation/ConversationItem.java index 470a5fd2c..2802892ce 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/conversation/ConversationItem.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/conversation/ConversationItem.java @@ -9,6 +9,7 @@ import javax.annotation.Nullable; import javax.annotation.concurrent.NotThreadSafe; import androidx.annotation.LayoutRes; +import androidx.lifecycle.LiveData; import static org.briarproject.bramble.util.StringUtils.toHexString; @@ -24,9 +25,11 @@ abstract class ConversationItem { private final GroupId groupId; private final long time, autoDeleteTimer; private final boolean isIncoming; - private boolean read, sent, seen; + private final LiveData contactName; + private boolean read, sent, seen, showTimerNotice, timerMirrored; - ConversationItem(@LayoutRes int layoutRes, ConversationMessageHeader h) { + ConversationItem(@LayoutRes int layoutRes, ConversationMessageHeader h, + LiveData contactName) { this.layoutRes = layoutRes; this.text = null; this.id = h.getId(); @@ -37,6 +40,9 @@ abstract class ConversationItem { this.sent = h.isSent(); this.seen = h.isSeen(); this.isIncoming = !h.isLocal(); + this.contactName = contactName; + this.showTimerNotice = false; + this.timerMirrored = false; } @LayoutRes @@ -116,4 +122,44 @@ abstract class ConversationItem { return isIncoming; } + public LiveData getContactName() { + return contactName; + } + + /** + * Set this to true when {@link #getAutoDeleteTimer()} has changed + * since the last message from the same peer. + * + * @return true if the value was set, false if it was already set. + */ + boolean setTimerNoticeVisible(boolean visible) { + if (this.showTimerNotice != visible) { + this.showTimerNotice = visible; + return true; + } + return false; + } + + boolean isTimerNoticeVisible() { + return showTimerNotice; + } + + /** + * Set this to true when {@link #getAutoDeleteTimer()} has changed + * to the same timer of the last message + * from the other peer in this conversation. + * + * @return true if the value was set, false if it was already set. + */ + public boolean setTimerMirrored(boolean timerMirrored) { + if (this.timerMirrored != timerMirrored) { + this.timerMirrored = timerMirrored; + return true; + } + return false; + } + + public boolean wasTimerMirrored() { + return timerMirrored; + } } diff --git a/briar-android/src/main/java/org/briarproject/briar/android/conversation/ConversationItemViewHolder.java b/briar-android/src/main/java/org/briarproject/briar/android/conversation/ConversationItemViewHolder.java index 7e9cd582d..c0d552e3f 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/conversation/ConversationItemViewHolder.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/conversation/ConversationItemViewHolder.java @@ -1,5 +1,6 @@ package org.briarproject.briar.android.conversation; +import android.content.Context; import android.view.View; import android.widget.TextView; @@ -27,7 +28,7 @@ abstract class ConversationItemViewHolder extends ViewHolder { protected final ConstraintLayout layout; @Nullable private final OutItemViewHolder outViewHolder; - private final TextView text; + private final TextView topNotice, text; protected final TextView time; private final View bomb; @Nullable @@ -39,6 +40,7 @@ abstract class ConversationItemViewHolder extends ViewHolder { this.listener = listener; this.outViewHolder = isIncoming ? null : new OutItemViewHolder(v); root = v; + topNotice = v.findViewById(R.id.topNotice); layout = v.findViewById(R.id.layout); text = v.findViewById(R.id.text); time = v.findViewById(R.id.time); @@ -50,6 +52,8 @@ abstract class ConversationItemViewHolder extends ViewHolder { itemKey = item.getKey(); root.setActivated(selected); + setTopNotice(item); + if (item.getText() != null) { text.setText(trim(item.getText())); } @@ -72,4 +76,42 @@ abstract class ConversationItemViewHolder extends ViewHolder { return itemKey; } + private void setTopNotice(ConversationItem item) { + if (item.isTimerNoticeVisible()) { + Context ctx = itemView.getContext(); + topNotice.setVisibility(VISIBLE); + boolean enabled = item.getAutoDeleteTimer() != NO_AUTO_DELETE_TIMER; + String text; + if (item.isIncoming()) { + String name = item.getContactName().getValue(); + if (item.wasTimerMirrored()) { + int strRes = enabled ? + R.string.auto_delete_msg_contact_enabled_mirrored : + R.string.auto_delete_msg_contact_disabled_mirrored; + text = ctx.getString(strRes, name); + } else { + int strRes = enabled ? + R.string.auto_delete_msg_contact_enabled : + R.string.auto_delete_msg_contact_disabled; + text = ctx.getString(strRes, name, name); + } + } else { + int strRes; + if (item.wasTimerMirrored()) { + strRes = enabled ? + R.string.auto_delete_msg_you_enabled_mirrored : + R.string.auto_delete_msg_you_disabled_mirrored; + } else { + strRes = enabled ? + R.string.auto_delete_msg_you_enabled : + R.string.auto_delete_msg_you_disabled; + } + text = ctx.getString(strRes); + } + topNotice.setText(text); + } else { + topNotice.setVisibility(GONE); + } + } + } diff --git a/briar-android/src/main/java/org/briarproject/briar/android/conversation/ConversationMessageItem.java b/briar-android/src/main/java/org/briarproject/briar/android/conversation/ConversationMessageItem.java index 8fc50d299..b9185c1ce 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/conversation/ConversationMessageItem.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/conversation/ConversationMessageItem.java @@ -10,6 +10,7 @@ import javax.annotation.concurrent.NotThreadSafe; import androidx.annotation.LayoutRes; import androidx.annotation.UiThread; +import androidx.lifecycle.LiveData; @NotThreadSafe @NotNullByDefault @@ -18,8 +19,8 @@ class ConversationMessageItem extends ConversationItem { private final List attachments; ConversationMessageItem(@LayoutRes int layoutRes, PrivateMessageHeader h, - List attachments) { - super(layoutRes, h); + LiveData contactName, List attachments) { + super(layoutRes, h, contactName); this.attachments = attachments; } diff --git a/briar-android/src/main/java/org/briarproject/briar/android/conversation/ConversationNoticeItem.java b/briar-android/src/main/java/org/briarproject/briar/android/conversation/ConversationNoticeItem.java index 0694a0762..50400017a 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/conversation/ConversationNoticeItem.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/conversation/ConversationNoticeItem.java @@ -8,6 +8,7 @@ import javax.annotation.Nullable; import javax.annotation.concurrent.NotThreadSafe; import androidx.annotation.LayoutRes; +import androidx.lifecycle.LiveData; @NotThreadSafe @NotNullByDefault @@ -17,15 +18,15 @@ class ConversationNoticeItem extends ConversationItem { private final String msgText; ConversationNoticeItem(@LayoutRes int layoutRes, String text, - ConversationRequest r) { - super(layoutRes, r); + LiveData contactName, ConversationRequest r) { + super(layoutRes, r, contactName); this.text = text; this.msgText = r.getText(); } ConversationNoticeItem(@LayoutRes int layoutRes, String text, - ConversationResponse r) { - super(layoutRes, r); + LiveData contactName, ConversationResponse r) { + super(layoutRes, r, contactName); this.text = text; this.msgText = null; } diff --git a/briar-android/src/main/java/org/briarproject/briar/android/conversation/ConversationRequestItem.java b/briar-android/src/main/java/org/briarproject/briar/android/conversation/ConversationRequestItem.java index 71984db65..5f7027d63 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/conversation/ConversationRequestItem.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/conversation/ConversationRequestItem.java @@ -11,6 +11,7 @@ import javax.annotation.Nullable; import javax.annotation.concurrent.NotThreadSafe; import androidx.annotation.LayoutRes; +import androidx.lifecycle.LiveData; @NotThreadSafe @NotNullByDefault @@ -26,14 +27,15 @@ class ConversationRequestItem extends ConversationNoticeItem { private boolean answered; ConversationRequestItem(@LayoutRes int layoutRes, String text, - RequestType type, ConversationRequest r) { - super(layoutRes, text, r); + LiveData contactName, RequestType type, + ConversationRequest r) { + super(layoutRes, text, contactName, r); this.requestType = type; this.sessionId = r.getSessionId(); this.answered = r.wasAnswered(); if (r instanceof InvitationRequest) { this.requestedGroupId = ((Shareable) r.getNameable()).getId(); - this.canBeOpened = ((InvitationRequest) r).canBeOpened(); + this.canBeOpened = ((InvitationRequest) r).canBeOpened(); } else { this.requestedGroupId = null; this.canBeOpened = false; diff --git a/briar-android/src/main/java/org/briarproject/briar/android/conversation/ConversationVisitor.java b/briar-android/src/main/java/org/briarproject/briar/android/conversation/ConversationVisitor.java index 46468c030..756c8535e 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/conversation/ConversationVisitor.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/conversation/ConversationVisitor.java @@ -60,10 +60,12 @@ class ConversationVisitor implements } if (h.isLocal()) { item = new ConversationMessageItem( - R.layout.list_item_conversation_msg_out, h, attachments); + R.layout.list_item_conversation_msg_out, h, contactName, + attachments); } else { item = new ConversationMessageItem( - R.layout.list_item_conversation_msg_in, h, attachments); + R.layout.list_item_conversation_msg_in, h, contactName, + attachments); } if (h.hasText()) { String text = textCache.getText(h.getId()); @@ -79,13 +81,15 @@ class ConversationVisitor implements String text = ctx.getString(R.string.blogs_sharing_invitation_sent, r.getName(), contactName.getValue()); return new ConversationNoticeItem( - R.layout.list_item_conversation_notice_out, text, r); + R.layout.list_item_conversation_notice_out, text, + contactName, r); } else { String text = ctx.getString( R.string.blogs_sharing_invitation_received, contactName.getValue(), r.getName()); return new ConversationRequestItem( - R.layout.list_item_conversation_request, text, BLOG, r); + R.layout.list_item_conversation_request, text, contactName, + BLOG, r); } } @@ -104,7 +108,8 @@ class ConversationVisitor implements contactName.getValue()); } return new ConversationNoticeItem( - R.layout.list_item_conversation_notice_out, text, r); + R.layout.list_item_conversation_notice_out, text, + contactName, r); } else { String text; if (r.wasAccepted()) { @@ -117,7 +122,8 @@ class ConversationVisitor implements contactName.getValue()); } return new ConversationNoticeItem( - R.layout.list_item_conversation_notice_in, text, r); + R.layout.list_item_conversation_notice_in, text, + contactName, r); } } @@ -128,13 +134,15 @@ class ConversationVisitor implements String text = ctx.getString(R.string.forum_invitation_sent, r.getName(), contactName.getValue()); return new ConversationNoticeItem( - R.layout.list_item_conversation_notice_out, text, r); + R.layout.list_item_conversation_notice_out, text, + contactName, r); } else { String text = ctx.getString( R.string.forum_invitation_received, contactName.getValue(), r.getName()); return new ConversationRequestItem( - R.layout.list_item_conversation_request, text, FORUM, r); + R.layout.list_item_conversation_request, text, contactName, + FORUM, r); } } @@ -153,7 +161,8 @@ class ConversationVisitor implements contactName.getValue()); } return new ConversationNoticeItem( - R.layout.list_item_conversation_notice_out, text, r); + R.layout.list_item_conversation_notice_out, text, + contactName, r); } else { String text; if (r.wasAccepted()) { @@ -166,7 +175,8 @@ class ConversationVisitor implements contactName.getValue()); } return new ConversationNoticeItem( - R.layout.list_item_conversation_notice_in, text, r); + R.layout.list_item_conversation_notice_in, text, + contactName, r); } } @@ -178,13 +188,15 @@ class ConversationVisitor implements R.string.groups_invitations_invitation_sent, contactName.getValue(), r.getName()); return new ConversationNoticeItem( - R.layout.list_item_conversation_notice_out, text, r); + R.layout.list_item_conversation_notice_out, text, + contactName, r); } else { String text = ctx.getString( R.string.groups_invitations_invitation_received, contactName.getValue(), r.getName()); return new ConversationRequestItem( - R.layout.list_item_conversation_request, text, GROUP, r); + R.layout.list_item_conversation_request, text, contactName, + GROUP, r); } } @@ -203,7 +215,8 @@ class ConversationVisitor implements contactName.getValue()); } return new ConversationNoticeItem( - R.layout.list_item_conversation_notice_out, text, r); + R.layout.list_item_conversation_notice_out, text, + contactName, r); } else { String text; if (r.wasAccepted()) { @@ -216,7 +229,8 @@ class ConversationVisitor implements contactName.getValue()); } return new ConversationNoticeItem( - R.layout.list_item_conversation_notice_in, text, r); + R.layout.list_item_conversation_notice_in, text, + contactName, r); } } @@ -227,7 +241,8 @@ class ConversationVisitor implements String text = ctx.getString(R.string.introduction_request_sent, contactName.getValue(), name); return new ConversationNoticeItem( - R.layout.list_item_conversation_notice_out, text, r); + R.layout.list_item_conversation_notice_out, text, + contactName, r); } else { String text; if (r.wasAnswered()) { @@ -243,7 +258,7 @@ class ConversationVisitor implements contactName.getValue(), name); } return new ConversationRequestItem( - R.layout.list_item_conversation_request, text, + R.layout.list_item_conversation_request, text, contactName, INTRODUCTION, r); } } @@ -268,7 +283,8 @@ class ConversationVisitor implements introducedAuthor); } return new ConversationNoticeItem( - R.layout.list_item_conversation_notice_out, text, r); + R.layout.list_item_conversation_notice_out, text, + contactName, r); } else { String text; if (r.wasAccepted()) { @@ -288,7 +304,8 @@ class ConversationVisitor implements introducedAuthor); } return new ConversationNoticeItem( - R.layout.list_item_conversation_notice_in, text, r); + R.layout.list_item_conversation_notice_in, text, + contactName, r); } } diff --git a/briar-android/src/main/res/layout/list_item_conversation_msg_image.xml b/briar-android/src/main/res/layout/list_item_conversation_msg_image.xml index 4e23ec880..cfc78c4f8 100644 --- a/briar-android/src/main/res/layout/list_item_conversation_msg_image.xml +++ b/briar-android/src/main/res/layout/list_item_conversation_msg_image.xml @@ -1,4 +1,6 @@ + + + + - + android:background="@drawable/list_item_background_selectable" + android:orientation="vertical"> + + + - + diff --git a/briar-android/src/main/res/layout/list_item_conversation_msg_in_content.xml b/briar-android/src/main/res/layout/list_item_conversation_msg_in_content.xml index c691819b2..63b679572 100644 --- a/briar-android/src/main/res/layout/list_item_conversation_msg_in_content.xml +++ b/briar-android/src/main/res/layout/list_item_conversation_msg_in_content.xml @@ -1,4 +1,6 @@ + + - + android:background="@drawable/list_item_background_selectable" + android:orientation="vertical" + android:paddingTop="@dimen/message_bubble_margin"> + + - \ No newline at end of file + \ No newline at end of file diff --git a/briar-android/src/main/res/layout/list_item_conversation_notice_in.xml b/briar-android/src/main/res/layout/list_item_conversation_notice_in.xml index 4a7bb701a..0a6a2fcd1 100644 --- a/briar-android/src/main/res/layout/list_item_conversation_notice_in.xml +++ b/briar-android/src/main/res/layout/list_item_conversation_notice_in.xml @@ -5,8 +5,9 @@ android:layout_width="match_parent" android:layout_height="wrap_content" android:background="@drawable/list_item_background_selectable" - android:orientation="vertical" - android:paddingTop="@dimen/message_bubble_margin"> + android:orientation="vertical"> + + + tools:text="Short message" + tools:visibility="visible" /> + + + tools:text="This is a long long long message that spans over several lines.\n\nIt ends here." + tools:visibility="visible" /> + android:orientation="vertical"> + + + diff --git a/briar-android/src/main/res/layout/list_item_conversation_top_notice_out.xml b/briar-android/src/main/res/layout/list_item_conversation_top_notice_out.xml new file mode 100644 index 000000000..38935f5fd --- /dev/null +++ b/briar-android/src/main/res/layout/list_item_conversation_top_notice_out.xml @@ -0,0 +1,21 @@ + + diff --git a/briar-android/src/main/res/values/strings.xml b/briar-android/src/main/res/values/strings.xml index f31ff3b4c..e4b879c20 100644 --- a/briar-android/src/main/res/values/strings.xml +++ b/briar-android/src/main/res/values/strings.xml @@ -166,6 +166,14 @@ Change contact name Contact name Disappearing messages + You turned on disappearing messages. Your messages will disappear after 7 days. + You turned off disappearing messages. Your messages will not disappear. + Your messages will disappear after 7 days. + Your messages will not disappear. + %1$s turned on disappearing messages. %2$s\'s messages will disappear after 7 days. + %1$s turned off disappearing messages. %2$s\'s messages will not disappear. + %1$s\'s messages will disappear after 7 days. + %1$s\'s messages will not disappear. Delete all messages Confirm Message Deletion Are you sure that you want to delete all messages? From 4ea3ce0e3c767e2fdff7e6ec5a8a146d87cb3649 Mon Sep 17 00:00:00 2001 From: Torsten Grote Date: Tue, 15 Dec 2020 14:29:37 -0300 Subject: [PATCH 042/124] Remove mirrored timer texts as we can't detect reliably if a timer setting was mirrored or manually changed. Also remove item update optimization from adapter as this can cause issues when items already exist. --- .../conversation/ConversationAdapter.java | 16 ++++------- .../conversation/ConversationItem.java | 22 +-------------- .../ConversationItemViewHolder.java | 28 +++++-------------- briar-android/src/main/res/values/strings.xml | 12 +++----- 4 files changed, 18 insertions(+), 60 deletions(-) diff --git a/briar-android/src/main/java/org/briarproject/briar/android/conversation/ConversationAdapter.java b/briar-android/src/main/java/org/briarproject/briar/android/conversation/ConversationAdapter.java index 662ea2729..84fddd084 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/conversation/ConversationAdapter.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/conversation/ConversationAdapter.java @@ -112,40 +112,36 @@ class ConversationAdapter public void add(ConversationItem item) { items.beginBatchedUpdates(); items.add(item); - updateTimersInBatch(true); + updateTimersInBatch(); items.endBatchedUpdates(); } @Override public void addAll(Collection itemsToAdd) { items.beginBatchedUpdates(); + // there can be items already in the adapter + // SortedList takes care of duplicates and detecting changed items items.addAll(itemsToAdd); - updateTimersInBatch(false); + updateTimersInBatch(); items.endBatchedUpdates(); } - private void updateTimersInBatch(boolean updateItems) { + private void updateTimersInBatch() { long lastTimerIncoming = NO_AUTO_DELETE_TIMER; long lastTimerOutgoing = NO_AUTO_DELETE_TIMER; for (int i = 0; i < items.size(); i++) { ConversationItem c = items.get(i); boolean itemChanged; boolean timerChanged; - boolean timerMirrored; if (c.isIncoming()) { timerChanged = lastTimerIncoming != c.getAutoDeleteTimer(); - timerMirrored = timerChanged && - lastTimerOutgoing == c.getAutoDeleteTimer(); lastTimerIncoming = c.getAutoDeleteTimer(); } else { timerChanged = lastTimerOutgoing != c.getAutoDeleteTimer(); - timerMirrored = timerChanged && - lastTimerIncoming == c.getAutoDeleteTimer(); lastTimerOutgoing = c.getAutoDeleteTimer(); } itemChanged = c.setTimerNoticeVisible(timerChanged); - itemChanged |= c.setTimerMirrored(timerMirrored); - if (itemChanged && updateItems) items.updateItemAt(i, c); + if (itemChanged) items.updateItemAt(i, c); } } diff --git a/briar-android/src/main/java/org/briarproject/briar/android/conversation/ConversationItem.java b/briar-android/src/main/java/org/briarproject/briar/android/conversation/ConversationItem.java index 2802892ce..c3d96e462 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/conversation/ConversationItem.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/conversation/ConversationItem.java @@ -26,7 +26,7 @@ abstract class ConversationItem { private final long time, autoDeleteTimer; private final boolean isIncoming; private final LiveData contactName; - private boolean read, sent, seen, showTimerNotice, timerMirrored; + private boolean read, sent, seen, showTimerNotice; ConversationItem(@LayoutRes int layoutRes, ConversationMessageHeader h, LiveData contactName) { @@ -42,7 +42,6 @@ abstract class ConversationItem { this.isIncoming = !h.isLocal(); this.contactName = contactName; this.showTimerNotice = false; - this.timerMirrored = false; } @LayoutRes @@ -143,23 +142,4 @@ abstract class ConversationItem { boolean isTimerNoticeVisible() { return showTimerNotice; } - - /** - * Set this to true when {@link #getAutoDeleteTimer()} has changed - * to the same timer of the last message - * from the other peer in this conversation. - * - * @return true if the value was set, false if it was already set. - */ - public boolean setTimerMirrored(boolean timerMirrored) { - if (this.timerMirrored != timerMirrored) { - this.timerMirrored = timerMirrored; - return true; - } - return false; - } - - public boolean wasTimerMirrored() { - return timerMirrored; - } } diff --git a/briar-android/src/main/java/org/briarproject/briar/android/conversation/ConversationItemViewHolder.java b/briar-android/src/main/java/org/briarproject/briar/android/conversation/ConversationItemViewHolder.java index c0d552e3f..8c3dc790d 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/conversation/ConversationItemViewHolder.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/conversation/ConversationItemViewHolder.java @@ -84,28 +84,14 @@ abstract class ConversationItemViewHolder extends ViewHolder { String text; if (item.isIncoming()) { String name = item.getContactName().getValue(); - if (item.wasTimerMirrored()) { - int strRes = enabled ? - R.string.auto_delete_msg_contact_enabled_mirrored : - R.string.auto_delete_msg_contact_disabled_mirrored; - text = ctx.getString(strRes, name); - } else { - int strRes = enabled ? - R.string.auto_delete_msg_contact_enabled : - R.string.auto_delete_msg_contact_disabled; - text = ctx.getString(strRes, name, name); - } + int strRes = enabled ? + R.string.auto_delete_msg_contact_enabled : + R.string.auto_delete_msg_contact_disabled; + text = ctx.getString(strRes, name); } else { - int strRes; - if (item.wasTimerMirrored()) { - strRes = enabled ? - R.string.auto_delete_msg_you_enabled_mirrored : - R.string.auto_delete_msg_you_disabled_mirrored; - } else { - strRes = enabled ? - R.string.auto_delete_msg_you_enabled : - R.string.auto_delete_msg_you_disabled; - } + int strRes = enabled ? + R.string.auto_delete_msg_you_enabled : + R.string.auto_delete_msg_you_disabled; text = ctx.getString(strRes); } topNotice.setText(text); diff --git a/briar-android/src/main/res/values/strings.xml b/briar-android/src/main/res/values/strings.xml index e4b879c20..4d3715856 100644 --- a/briar-android/src/main/res/values/strings.xml +++ b/briar-android/src/main/res/values/strings.xml @@ -166,14 +166,10 @@ Change contact name Contact name Disappearing messages - You turned on disappearing messages. Your messages will disappear after 7 days. - You turned off disappearing messages. Your messages will not disappear. - Your messages will disappear after 7 days. - Your messages will not disappear. - %1$s turned on disappearing messages. %2$s\'s messages will disappear after 7 days. - %1$s turned off disappearing messages. %2$s\'s messages will not disappear. - %1$s\'s messages will disappear after 7 days. - %1$s\'s messages will not disappear. + Your messages will disappear after 7 days. + Your messages will not disappear. + %1$s\'s messages will disappear after 7 days. + %1$s\'s messages will not disappear. Delete all messages Confirm Message Deletion Are you sure that you want to delete all messages? From 7a3be374c898622fc91f5331293283768271839c Mon Sep 17 00:00:00 2001 From: Torsten Grote Date: Tue, 15 Dec 2020 15:23:29 -0300 Subject: [PATCH 043/124] Broadcast event when auto delete timer is mirrored --- .../event/AutoDeleteTimerMirroredEvent.java | 28 +++++++++++++++++++ .../autodelete/AutoDeleteManagerImpl.java | 3 ++ .../autodelete/AutoDeleteManagerImplTest.java | 28 +++++++++++++++++++ 3 files changed, 59 insertions(+) create mode 100644 briar-api/src/main/java/org/briarproject/briar/api/autodelete/event/AutoDeleteTimerMirroredEvent.java diff --git a/briar-api/src/main/java/org/briarproject/briar/api/autodelete/event/AutoDeleteTimerMirroredEvent.java b/briar-api/src/main/java/org/briarproject/briar/api/autodelete/event/AutoDeleteTimerMirroredEvent.java new file mode 100644 index 000000000..a3f392985 --- /dev/null +++ b/briar-api/src/main/java/org/briarproject/briar/api/autodelete/event/AutoDeleteTimerMirroredEvent.java @@ -0,0 +1,28 @@ +package org.briarproject.briar.api.autodelete.event; + +import org.briarproject.bramble.api.contact.ContactId; +import org.briarproject.bramble.api.event.Event; +import org.briarproject.bramble.api.nullsafety.NotNullByDefault; + +import javax.annotation.concurrent.Immutable; + +@Immutable +@NotNullByDefault +public class AutoDeleteTimerMirroredEvent extends Event { + + private final ContactId contactId; + private final long newTimer; + + public AutoDeleteTimerMirroredEvent(ContactId contactId, long newTimer) { + this.contactId = contactId; + this.newTimer = newTimer; + } + + public ContactId getContactId() { + return contactId; + } + + public long getNewTimer() { + return newTimer; + } +} diff --git a/briar-core/src/main/java/org/briarproject/briar/autodelete/AutoDeleteManagerImpl.java b/briar-core/src/main/java/org/briarproject/briar/autodelete/AutoDeleteManagerImpl.java index c07759092..5a4d87d86 100644 --- a/briar-core/src/main/java/org/briarproject/briar/autodelete/AutoDeleteManagerImpl.java +++ b/briar-core/src/main/java/org/briarproject/briar/autodelete/AutoDeleteManagerImpl.java @@ -16,6 +16,7 @@ import org.briarproject.bramble.api.nullsafety.NotNullByDefault; import org.briarproject.bramble.api.sync.Group; import org.briarproject.bramble.api.sync.GroupFactory; import org.briarproject.briar.api.autodelete.AutoDeleteManager; +import org.briarproject.briar.api.autodelete.event.AutoDeleteTimerMirroredEvent; import java.util.logging.Logger; @@ -155,6 +156,7 @@ class AutoDeleteManagerImpl LOG.info("Mirroring auto-delete timer " + timer); } meta.put(GROUP_KEY_TIMER, timer); + txn.attach(new AutoDeleteTimerMirroredEvent(c, timer)); } else if (timer != oldTimer) { // Their sent change trumps our unsent change. Mirror their // timer and clear the previous timer to drop our unsent change @@ -164,6 +166,7 @@ class AutoDeleteManagerImpl } meta.put(GROUP_KEY_TIMER, timer); meta.put(GROUP_KEY_PREVIOUS_TIMER, NO_PREVIOUS_TIMER); + txn.attach(new AutoDeleteTimerMirroredEvent(c, timer)); } // Always update the timestamp meta.put(GROUP_KEY_TIMESTAMP, timestamp); diff --git a/briar-core/src/test/java/org/briarproject/briar/autodelete/AutoDeleteManagerImplTest.java b/briar-core/src/test/java/org/briarproject/briar/autodelete/AutoDeleteManagerImplTest.java index 853b931eb..1dc2d5b9d 100644 --- a/briar-core/src/test/java/org/briarproject/briar/autodelete/AutoDeleteManagerImplTest.java +++ b/briar-core/src/test/java/org/briarproject/briar/autodelete/AutoDeleteManagerImplTest.java @@ -5,11 +5,15 @@ import org.briarproject.bramble.api.client.ContactGroupFactory; import org.briarproject.bramble.api.contact.Contact; import org.briarproject.bramble.api.data.BdfDictionary; import org.briarproject.bramble.api.data.BdfEntry; +import org.briarproject.bramble.api.db.CommitAction; import org.briarproject.bramble.api.db.DatabaseComponent; +import org.briarproject.bramble.api.db.EventAction; import org.briarproject.bramble.api.db.Transaction; +import org.briarproject.bramble.api.event.Event; import org.briarproject.bramble.api.sync.Group; import org.briarproject.bramble.api.sync.GroupFactory; import org.briarproject.bramble.test.BrambleMockTestCase; +import org.briarproject.briar.api.autodelete.event.AutoDeleteTimerMirroredEvent; import org.jmock.Expectations; import org.junit.Test; @@ -27,6 +31,7 @@ import static org.briarproject.briar.autodelete.AutoDeleteConstants.GROUP_KEY_TI import static org.briarproject.briar.autodelete.AutoDeleteConstants.GROUP_KEY_TIMESTAMP; import static org.briarproject.briar.autodelete.AutoDeleteConstants.NO_PREVIOUS_TIMER; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; @SuppressWarnings("UnnecessaryLocalVariable") // Using them for readability public class AutoDeleteManagerImplTest extends BrambleMockTestCase { @@ -241,6 +246,9 @@ public class AutoDeleteManagerImplTest extends BrambleMockTestCase { autoDeleteManager.receiveAutoDeleteTimer(txn, contact.getId(), remoteTimer, remoteTimestamp); + + // no events broadcast + assertTrue(txn.getActions().isEmpty()); } @Test @@ -270,6 +278,9 @@ public class AutoDeleteManagerImplTest extends BrambleMockTestCase { autoDeleteManager.receiveAutoDeleteTimer(txn, contact.getId(), remoteTimer, remoteTimestamp); + + // assert that event is broadcast with new timer + assertEvent(txn, remoteTimer); } @Test @@ -299,6 +310,9 @@ public class AutoDeleteManagerImplTest extends BrambleMockTestCase { autoDeleteManager.receiveAutoDeleteTimer(txn, contact.getId(), remoteTimer, remoteTimestamp); + + // no events broadcast + assertTrue(txn.getActions().isEmpty()); } @Test @@ -332,6 +346,9 @@ public class AutoDeleteManagerImplTest extends BrambleMockTestCase { autoDeleteManager.receiveAutoDeleteTimer(txn, contact.getId(), newRemoteTimer, remoteTimestamp); + + // assert that event is broadcast with new timer + assertEvent(txn, newRemoteTimer); } private void expectGetContact(Transaction txn) throws Exception { @@ -348,4 +365,15 @@ public class AutoDeleteManagerImplTest extends BrambleMockTestCase { will(returnValue(contactGroup)); }}); } + + private void assertEvent(Transaction txn, long timer) { + assertEquals(1, txn.getActions().size()); + CommitAction action = txn.getActions().get(0); + assertTrue(action instanceof EventAction); + Event event = ((EventAction) action).getEvent(); + assertTrue(event instanceof AutoDeleteTimerMirroredEvent); + AutoDeleteTimerMirroredEvent e = (AutoDeleteTimerMirroredEvent) event; + assertEquals(contact.getId(), e.getContactId()); + assertEquals(timer, e.getNewTimer()); + } } From 9947a6aa1bcbc9694bf804cfcba6c9e73b7ea279 Mon Sep 17 00:00:00 2001 From: Torsten Grote Date: Tue, 15 Dec 2020 16:20:12 -0300 Subject: [PATCH 044/124] Use a different hint in conversation when message will disappear and keep the hint updated when the auto-delete timer changes --- .../conversation/ConversationActivity.java | 9 +++++++- .../conversation/ConversationViewModel.java | 22 ++++++++++++++++--- .../android/view/TextSendController.java | 15 +++++++++++++ briar-android/src/main/res/values/strings.xml | 3 ++- 4 files changed, 44 insertions(+), 5 deletions(-) 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 a0fecd904..5b45365c2 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 @@ -136,6 +136,7 @@ import static org.briarproject.briar.android.conversation.ImageActivity.ITEM_ID; import static org.briarproject.briar.android.conversation.ImageActivity.NAME; import static org.briarproject.briar.android.util.UiUtils.observeOnce; import static org.briarproject.briar.android.view.AuthorView.setAvatar; +import static org.briarproject.briar.api.autodelete.AutoDeleteConstants.NO_AUTO_DELETE_TIMER; import static org.briarproject.briar.api.messaging.MessagingConstants.MAX_ATTACHMENTS_PER_MESSAGE; import static org.briarproject.briar.api.messaging.MessagingConstants.MAX_PRIVATE_MESSAGE_TEXT_LENGTH; import static org.briarproject.briar.api.messaging.PrivateMessageFormat.TEXT_IMAGES_AUTO_DELETE; @@ -284,6 +285,9 @@ public class ConversationActivity extends BriarActivity textInputView.setMaxTextLength(MAX_PRIVATE_MESSAGE_TEXT_LENGTH); textInputView.setReady(false); textInputView.setOnKeyboardShownListener(this::scrollToBottom); + + viewModel.getAutoDeleteTimer().observe(this, timer -> + sendController.setAutoDeleteTimer(timer)); } private void scrollToBottom() { @@ -370,7 +374,10 @@ public class ConversationActivity extends BriarActivity // show auto-delete timer setting only, if contacts supports it observeOnce(viewModel.getPrivateMessageFormat(), this, format -> { boolean visible = format == TEXT_IMAGES_AUTO_DELETE; - menu.findItem(R.id.action_auto_delete).setVisible(visible); + MenuItem item = menu.findItem(R.id.action_auto_delete); + item.setVisible(visible); + viewModel.getAutoDeleteTimer().observe(this, timer -> + item.setChecked(timer != NO_AUTO_DELETE_TIMER)); }); return super.onCreateOptionsMenu(menu); 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 57e48aa88..815849317 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 @@ -34,6 +34,7 @@ import org.briarproject.briar.android.viewmodel.LiveEvent; import org.briarproject.briar.android.viewmodel.MutableLiveEvent; import org.briarproject.briar.api.attachment.AttachmentHeader; import org.briarproject.briar.api.autodelete.AutoDeleteManager; +import org.briarproject.briar.api.autodelete.event.AutoDeleteTimerMirroredEvent; import org.briarproject.briar.api.avatar.event.AvatarUpdatedEvent; import org.briarproject.briar.api.conversation.ConversationManager; import org.briarproject.briar.api.identity.AuthorInfo; @@ -110,8 +111,10 @@ public class ConversationViewModel extends DbViewModel new MutableLiveEvent<>(); private final MutableLiveData showIntroductionAction = new MutableLiveData<>(); - private final MutableLiveData contactDeleted = + private final MutableLiveData autoDeleteTimer = new MutableLiveData<>(); + private final MutableLiveData contactDeleted = + new MutableLiveData<>(false); private final MutableLiveEvent addedHeader = new MutableLiveEvent<>(); @@ -145,8 +148,6 @@ public class ConversationViewModel extends DbViewModel this.conversationManager = conversationManager; messagingGroupId = map(contactItem, c -> messagingManager.getContactGroup(c.getContact()).getId()); - contactDeleted.setValue(false); - eventBus.addListener(this); } @@ -166,6 +167,11 @@ public class ConversationViewModel extends DbViewModel runOnDbThread(() -> attachmentRetriever .loadAttachmentItem(a.getMessageId())); } + } else if (e instanceof AutoDeleteTimerMirroredEvent) { + AutoDeleteTimerMirroredEvent a = (AutoDeleteTimerMirroredEvent) e; + if (a.getContactId().equals(contactId)) { + autoDeleteTimer.postValue(a.getNewTimer()); + } } else if (e instanceof AvatarUpdatedEvent) { AvatarUpdatedEvent a = (AvatarUpdatedEvent) e; if (a.getContactId().equals(contactId)) { @@ -215,6 +221,11 @@ public class ConversationViewModel extends DbViewModel contactItem.postValue(new ContactItem(c, authorInfo)); logDuration(LOG, "Loading contact", start); start = now(); + long timer = db.transactionWithResult(true, txn -> + autoDeleteManager.getAutoDeleteTimer(txn, contactId)); + autoDeleteTimer.postValue(timer); + logDuration(LOG, "Getting auto-delete timer", start); + start = now(); checkFeaturesAndOnboarding(contactId); logDuration(LOG, "Checking for image support", start); } catch (NoSuchContactException e) { @@ -377,6 +388,7 @@ public class ConversationViewModel extends DbViewModel try { db.transaction(false, txn -> autoDeleteManager.setAutoDeleteTimer(txn, c, timer)); + autoDeleteTimer.postValue(timer); } catch (DbException e) { logException(LOG, WARNING, e); } @@ -411,6 +423,10 @@ public class ConversationViewModel extends DbViewModel return showIntroductionAction; } + LiveData getAutoDeleteTimer() { + return autoDeleteTimer; + } + LiveData isContactDeleted() { return contactDeleted; } diff --git a/briar-android/src/main/java/org/briarproject/briar/android/view/TextSendController.java b/briar-android/src/main/java/org/briarproject/briar/android/view/TextSendController.java index e070a3dd4..2e510132b 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/view/TextSendController.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/view/TextSendController.java @@ -17,6 +17,7 @@ import androidx.annotation.UiThread; import static com.google.android.material.snackbar.Snackbar.LENGTH_SHORT; import static java.util.Collections.emptyList; +import static org.briarproject.briar.api.autodelete.AutoDeleteConstants.NO_AUTO_DELETE_TIMER; @UiThread @NotNullByDefault @@ -29,6 +30,7 @@ public class TextSendController implements TextInputListener { protected boolean ready = true, textIsEmpty = true; private final boolean allowEmptyText; + private CharSequence defaultHint; public TextSendController(TextInputView v, SendListener listener, boolean allowEmptyText) { @@ -36,6 +38,7 @@ public class TextSendController implements TextInputListener { this.compositeSendButton.setOnClickListener(view -> onSendEvent()); this.listener = listener; this.textInput = v.getEmojiTextInputView(); + this.defaultHint = textInput.getHint(); this.allowEmptyText = allowEmptyText; } @@ -57,6 +60,18 @@ public class TextSendController implements TextInputListener { updateViewState(); } + public void setAutoDeleteTimer(long timer) { + // update hint + if (timer == NO_AUTO_DELETE_TIMER) { + textInput.setHint(defaultHint); + } else { + // this might need to be adapted when other screens + // besides the private conversation use auto delete timers + defaultHint = textInput.getHint(); + textInput.setHint(R.string.message_hint_auto_delete); + } + } + protected void updateViewState() { textInput.setEnabled(ready); compositeSendButton diff --git a/briar-android/src/main/res/values/strings.xml b/briar-android/src/main/res/values/strings.xml index 4d3715856..a91b4a420 100644 --- a/briar-android/src/main/res/values/strings.xml +++ b/briar-android/src/main/res/values/strings.xml @@ -157,7 +157,8 @@ Tap the + icon to add a contact No messages. No messages to show - Type message + New message + New disappearing message Add a caption (optional) Attach image Could not attach image(s) From dceb38b777fb48274d68c6c840c698d8977a4785 Mon Sep 17 00:00:00 2001 From: Torsten Grote Date: Tue, 15 Dec 2020 17:23:08 -0300 Subject: [PATCH 045/124] Show a bomb badge on the send button when disappearing messages is active --- .../briar/android/view/CompositeSendButton.java | 15 +++++++++++++-- .../briar/android/view/TextSendController.java | 12 ++++++++++++ .../src/main/res/drawable/bomb_badge.xml | 13 +++++++++++++ .../res/layout/view_composite_send_button.xml | 13 +++++++++++++ 4 files changed, 51 insertions(+), 2 deletions(-) create mode 100644 briar-android/src/main/res/drawable/bomb_badge.xml diff --git a/briar-android/src/main/java/org/briarproject/briar/android/view/CompositeSendButton.java b/briar-android/src/main/java/org/briarproject/briar/android/view/CompositeSendButton.java index 273a250c5..11ed0adfc 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/view/CompositeSendButton.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/view/CompositeSendButton.java @@ -5,6 +5,7 @@ import android.util.AttributeSet; import android.view.LayoutInflater; import android.view.View; import android.widget.FrameLayout; +import android.widget.ImageView; import android.widget.ProgressBar; import org.briarproject.briar.R; @@ -19,9 +20,10 @@ import static java.util.Objects.requireNonNull; public class CompositeSendButton extends FrameLayout { private final AppCompatImageButton sendButton, imageButton; + private final ImageView bombBadge; private final ProgressBar progressBar; - private boolean hasImageSupport = false; + private boolean hasImageSupport = false, bombVisible = false; public CompositeSendButton(@NonNull Context context, @Nullable AttributeSet attrs) { @@ -32,6 +34,7 @@ public class CompositeSendButton extends FrameLayout { sendButton = findViewById(R.id.sendButton); imageButton = findViewById(R.id.imageButton); + bombBadge = findViewById(R.id.bombBadge); progressBar = findViewById(R.id.progressBar); } @@ -71,6 +74,11 @@ public class CompositeSendButton extends FrameLayout { return hasImageSupport; } + public void setBombVisible(boolean visible) { + bombVisible = visible; + bombBadge.setVisibility(visible ? VISIBLE : INVISIBLE); + } + public void showImageButton(boolean showImageButton, boolean sendEnabled) { if (showImageButton) { imageButton.setVisibility(VISIBLE); @@ -78,6 +86,7 @@ public class CompositeSendButton extends FrameLayout { sendButton.clearAnimation(); sendButton.animate().alpha(0f).withEndAction(() -> { sendButton.setVisibility(INVISIBLE); + bombBadge.setVisibility(INVISIBLE); imageButton.setEnabled(true); }).start(); imageButton.clearAnimation(); @@ -88,7 +97,9 @@ public class CompositeSendButton extends FrameLayout { sendButton.setEnabled(sendEnabled); imageButton.setEnabled(false); sendButton.clearAnimation(); - sendButton.animate().alpha(1f).start(); + sendButton.animate().alpha(1f).withEndAction(() -> { + if (bombVisible) bombBadge.setVisibility(VISIBLE); + }).start(); imageButton.clearAnimation(); imageButton.animate().alpha(0f).withEndAction(() -> imageButton.setVisibility(INVISIBLE) diff --git a/briar-android/src/main/java/org/briarproject/briar/android/view/TextSendController.java b/briar-android/src/main/java/org/briarproject/briar/android/view/TextSendController.java index 2e510132b..886a0a44b 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/view/TextSendController.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/view/TextSendController.java @@ -7,6 +7,7 @@ import com.google.android.material.snackbar.Snackbar; import org.briarproject.bramble.api.nullsafety.NotNullByDefault; import org.briarproject.briar.R; +import org.briarproject.briar.android.conversation.ConversationActivity; import org.briarproject.briar.android.view.EmojiTextInputView.TextInputListener; import org.briarproject.briar.api.attachment.AttachmentHeader; @@ -60,15 +61,26 @@ public class TextSendController implements TextInputListener { updateViewState(); } + /** + * Sets the current auto delete timer and updates the UI accordingly. + *

+ * Attention: Works only in {@link ConversationActivity}. + */ public void setAutoDeleteTimer(long timer) { + // this will need to be adapted when other screens + // besides the private conversation use auto delete timers + CompositeSendButton sendButton = + (CompositeSendButton) compositeSendButton; // update hint if (timer == NO_AUTO_DELETE_TIMER) { textInput.setHint(defaultHint); + sendButton.setBombVisible(false); } else { // this might need to be adapted when other screens // besides the private conversation use auto delete timers defaultHint = textInput.getHint(); textInput.setHint(R.string.message_hint_auto_delete); + sendButton.setBombVisible(true); } } diff --git a/briar-android/src/main/res/drawable/bomb_badge.xml b/briar-android/src/main/res/drawable/bomb_badge.xml new file mode 100644 index 000000000..c3bf3da45 --- /dev/null +++ b/briar-android/src/main/res/drawable/bomb_badge.xml @@ -0,0 +1,13 @@ + + + + + + + + diff --git a/briar-android/src/main/res/layout/view_composite_send_button.xml b/briar-android/src/main/res/layout/view_composite_send_button.xml index b72677e71..01b474b85 100644 --- a/briar-android/src/main/res/layout/view_composite_send_button.xml +++ b/briar-android/src/main/res/layout/view_composite_send_button.xml @@ -37,6 +37,19 @@ app:srcCompat="@drawable/social_send_now_white" app:tint="@color/briar_accent" /> + + Date: Wed, 16 Dec 2020 11:21:24 -0300 Subject: [PATCH 046/124] Show bomb badge in same style as send button --- briar-android/src/main/res/drawable/bomb_badge.xml | 13 ------------- .../main/res/layout/view_composite_send_button.xml | 5 ++--- 2 files changed, 2 insertions(+), 16 deletions(-) delete mode 100644 briar-android/src/main/res/drawable/bomb_badge.xml diff --git a/briar-android/src/main/res/drawable/bomb_badge.xml b/briar-android/src/main/res/drawable/bomb_badge.xml deleted file mode 100644 index c3bf3da45..000000000 --- a/briar-android/src/main/res/drawable/bomb_badge.xml +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - - - diff --git a/briar-android/src/main/res/layout/view_composite_send_button.xml b/briar-android/src/main/res/layout/view_composite_send_button.xml index 01b474b85..062e36740 100644 --- a/briar-android/src/main/res/layout/view_composite_send_button.xml +++ b/briar-android/src/main/res/layout/view_composite_send_button.xml @@ -42,12 +42,11 @@ android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="end|bottom" - android:layout_margin="1dp" - android:background="@drawable/bomb_badge" + android:layout_margin="3dp" android:contentDescription="@string/auto_delete_msg_contact_enabled" android:visibility="invisible" app:srcCompat="@drawable/ic_bomb" - app:tint="@color/color_primary" + app:tint="@color/briar_accent" tools:visibility="visible" /> Date: Wed, 16 Dec 2020 12:22:03 -0300 Subject: [PATCH 047/124] Make view state of text send UI easier to reason about and fix bugs with bomb badge and hint display --- .../android/view/CompositeSendButton.java | 8 +-- .../view/TextAttachmentController.java | 39 ++++++++---- .../android/view/TextSendController.java | 61 ++++++++++++------- 3 files changed, 68 insertions(+), 40 deletions(-) diff --git a/briar-android/src/main/java/org/briarproject/briar/android/view/CompositeSendButton.java b/briar-android/src/main/java/org/briarproject/briar/android/view/CompositeSendButton.java index 11ed0adfc..095130fb7 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/view/CompositeSendButton.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/view/CompositeSendButton.java @@ -23,7 +23,7 @@ public class CompositeSendButton extends FrameLayout { private final ImageView bombBadge; private final ProgressBar progressBar; - private boolean hasImageSupport = false, bombVisible = false; + private boolean hasImageSupport = false; public CompositeSendButton(@NonNull Context context, @Nullable AttributeSet attrs) { @@ -75,7 +75,6 @@ public class CompositeSendButton extends FrameLayout { } public void setBombVisible(boolean visible) { - bombVisible = visible; bombBadge.setVisibility(visible ? VISIBLE : INVISIBLE); } @@ -86,7 +85,6 @@ public class CompositeSendButton extends FrameLayout { sendButton.clearAnimation(); sendButton.animate().alpha(0f).withEndAction(() -> { sendButton.setVisibility(INVISIBLE); - bombBadge.setVisibility(INVISIBLE); imageButton.setEnabled(true); }).start(); imageButton.clearAnimation(); @@ -97,9 +95,7 @@ public class CompositeSendButton extends FrameLayout { sendButton.setEnabled(sendEnabled); imageButton.setEnabled(false); sendButton.clearAnimation(); - sendButton.animate().alpha(1f).withEndAction(() -> { - if (bombVisible) bombBadge.setVisibility(VISIBLE); - }).start(); + sendButton.animate().alpha(1f).start(); imageButton.clearAnimation(); imageButton.animate().alpha(0f).withEndAction(() -> imageButton.setVisibility(INVISIBLE) diff --git a/briar-android/src/main/java/org/briarproject/briar/android/view/TextAttachmentController.java b/briar-android/src/main/java/org/briarproject/briar/android/view/TextAttachmentController.java index a048d43e2..5c016ba39 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/view/TextAttachmentController.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/view/TextAttachmentController.java @@ -52,7 +52,6 @@ public class TextAttachmentController extends TextSendController private final AttachmentManager attachmentManager; private final List imageUris = new ArrayList<>(); - private final CharSequence textHint; private boolean loadingUris = false; public TextAttachmentController(TextInputView v, ImagePreview imagePreview, @@ -66,23 +65,44 @@ public class TextAttachmentController extends TextSendController sendButton = (CompositeSendButton) compositeSendButton; sendButton.setOnImageClickListener(view -> onImageButtonClicked()); - - textHint = textInput.getHint(); } @Override protected void updateViewState() { - textInput.setEnabled(ready && !loadingUris); - boolean sendEnabled = ready && !loadingUris && - (!textIsEmpty || canSendEmptyText()); + super.updateViewState(); if (loadingUris) { sendButton.showProgress(true); } else if (imageUris.isEmpty()) { sendButton.showProgress(false); - sendButton.showImageButton(textIsEmpty, sendEnabled); + sendButton.showImageButton(textIsEmpty, isSendButtonEnabled()); } else { sendButton.showProgress(false); - sendButton.showImageButton(false, sendEnabled); + sendButton.showImageButton(false, isSendButtonEnabled()); + } + } + + @Override + protected boolean isTextInputEnabled() { + return super.isTextInputEnabled() && !loadingUris; + } + + @Override + protected boolean isSendButtonEnabled() { + return super.isSendButtonEnabled() && !loadingUris; + } + + @Override + protected boolean isBombVisible() { + return super.isBombVisible() && (!textIsEmpty || !imageUris.isEmpty()); + } + + @Override + protected CharSequence getCurrentTextHint() { + if (imageUris.isEmpty()) { + return super.getCurrentTextHint(); + } else { + Context ctx = textInput.getContext(); + return ctx.getString(R.string.image_caption_hint); } } @@ -161,7 +181,6 @@ public class TextAttachmentController extends TextSendController } imageUris.addAll(newUris); updateViewState(); - textInput.setHint(R.string.image_caption_hint); List items = ImagePreviewItem.fromUris(imageUris); imagePreview.showPreview(items); // store attachments and show preview when successful @@ -207,8 +226,6 @@ public class TextAttachmentController extends TextSendController } private void reset() { - // restore hint - textInput.setHint(textHint); // hide image layout imagePreview.setVisibility(GONE); // reset image URIs diff --git a/briar-android/src/main/java/org/briarproject/briar/android/view/TextSendController.java b/briar-android/src/main/java/org/briarproject/briar/android/view/TextSendController.java index 886a0a44b..3d471f688 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/view/TextSendController.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/view/TextSendController.java @@ -1,5 +1,6 @@ package org.briarproject.briar.android.view; +import android.content.Context; import android.os.Parcelable; import android.view.View; @@ -7,12 +8,12 @@ import com.google.android.material.snackbar.Snackbar; import org.briarproject.bramble.api.nullsafety.NotNullByDefault; import org.briarproject.briar.R; -import org.briarproject.briar.android.conversation.ConversationActivity; import org.briarproject.briar.android.view.EmojiTextInputView.TextInputListener; import org.briarproject.briar.api.attachment.AttachmentHeader; import java.util.List; +import androidx.annotation.CallSuper; import androidx.annotation.Nullable; import androidx.annotation.UiThread; @@ -28,10 +29,12 @@ public class TextSendController implements TextInputListener { protected final View compositeSendButton; protected final SendListener listener; - protected boolean ready = true, textIsEmpty = true; + protected boolean textIsEmpty = true; + private boolean ready = true; + private long currentTimer = NO_AUTO_DELETE_TIMER; + private final CharSequence defaultHint; private final boolean allowEmptyText; - private CharSequence defaultHint; public TextSendController(TextInputView v, SendListener listener, boolean allowEmptyText) { @@ -63,31 +66,43 @@ public class TextSendController implements TextInputListener { /** * Sets the current auto delete timer and updates the UI accordingly. - *

- * Attention: Works only in {@link ConversationActivity}. */ public void setAutoDeleteTimer(long timer) { - // this will need to be adapted when other screens - // besides the private conversation use auto delete timers - CompositeSendButton sendButton = - (CompositeSendButton) compositeSendButton; - // update hint - if (timer == NO_AUTO_DELETE_TIMER) { - textInput.setHint(defaultHint); - sendButton.setBombVisible(false); - } else { - // this might need to be adapted when other screens - // besides the private conversation use auto delete timers - defaultHint = textInput.getHint(); - textInput.setHint(R.string.message_hint_auto_delete); - sendButton.setBombVisible(true); + currentTimer = timer; + updateViewState(); + } + + @CallSuper + protected void updateViewState() { + textInput.setEnabled(isTextInputEnabled()); + textInput.setHint(getCurrentTextHint()); + compositeSendButton.setEnabled(isSendButtonEnabled()); + if (compositeSendButton instanceof CompositeSendButton) { + CompositeSendButton sendButton = + (CompositeSendButton) compositeSendButton; + sendButton.setBombVisible(isBombVisible()); } } - protected void updateViewState() { - textInput.setEnabled(ready); - compositeSendButton - .setEnabled(ready && (!textIsEmpty || canSendEmptyText())); + protected boolean isTextInputEnabled() { + return ready; + } + + protected boolean isSendButtonEnabled() { + return ready && (!textIsEmpty || canSendEmptyText()); + } + + protected boolean isBombVisible() { + return currentTimer != NO_AUTO_DELETE_TIMER; + } + + protected CharSequence getCurrentTextHint() { + if (currentTimer == NO_AUTO_DELETE_TIMER) { + return defaultHint; + } else { + Context ctx = textInput.getContext(); + return ctx.getString(R.string.message_hint_auto_delete); + } } protected final boolean canSend() { From baa03417276e587404ed504fca1f6d1c3e0fdc5a Mon Sep 17 00:00:00 2001 From: Torsten Grote Date: Mon, 11 Jan 2021 09:51:47 -0300 Subject: [PATCH 048/124] Create group invitation with read-write transaction because the AutoDeleteManager needs to change the DB and otherwise crashes. Closes #1863 --- .../privategroup/creation/CreateGroupControllerImpl.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 4f10d8fff..4bae607e8 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 @@ -150,7 +150,7 @@ class CreateGroupControllerImpl extends ContactSelectorControllerImpl ResultExceptionHandler handler) { runOnDbThread(() -> { try { - db.transaction(true, txn -> { + db.transaction(false, txn -> { LocalAuthor localAuthor = identityManager.getLocalAuthor(txn); List contexts = From e10b6334f5b96fe46ff1c6a969a1ac1a9ea2d0b4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20K=C3=BCrten?= Date: Thu, 21 Jan 2021 19:21:10 +0100 Subject: [PATCH 049/124] Introduce conversation settings screen --- .../android/activity/ActivityComponent.java | 3 + .../conversation/AliasDialogFragment.java | 2 + .../conversation/ConversationActivity.java | 20 +-- .../ConversationSettingsDialog.java | 122 ++++++++++++++++++ .../ConversationSettingsLearnMoreDialog.java | 43 ++++++ .../layout/fragment_conversation_settings.xml | 71 ++++++++++ ...gment_conversation_settings_learn_more.xml | 19 +++ .../main/res/menu/conversation_actions.xml | 5 +- briar-android/src/main/res/values/strings.xml | 15 ++- briar-android/src/main/res/values/themes.xml | 10 ++ 10 files changed, 296 insertions(+), 14 deletions(-) create mode 100644 briar-android/src/main/java/org/briarproject/briar/android/conversation/ConversationSettingsDialog.java create mode 100644 briar-android/src/main/java/org/briarproject/briar/android/conversation/ConversationSettingsLearnMoreDialog.java create mode 100644 briar-android/src/main/res/layout/fragment_conversation_settings.xml create mode 100644 briar-android/src/main/res/layout/fragment_conversation_settings_learn_more.xml diff --git a/briar-android/src/main/java/org/briarproject/briar/android/activity/ActivityComponent.java b/briar-android/src/main/java/org/briarproject/briar/android/activity/ActivityComponent.java index 1ce3bbd76..d1f3ad737 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/activity/ActivityComponent.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/activity/ActivityComponent.java @@ -29,6 +29,7 @@ import org.briarproject.briar.android.contact.add.remote.NicknameFragment; import org.briarproject.briar.android.contact.add.remote.PendingContactListActivity; import org.briarproject.briar.android.conversation.AliasDialogFragment; import org.briarproject.briar.android.conversation.ConversationActivity; +import org.briarproject.briar.android.conversation.ConversationSettingsDialog; import org.briarproject.briar.android.conversation.ImageActivity; import org.briarproject.briar.android.conversation.ImageFragment; import org.briarproject.briar.android.forum.CreateForumActivity; @@ -233,4 +234,6 @@ public interface ActivityComponent { void inject(ConfirmAvatarDialogFragment fragment); + void inject(ConversationSettingsDialog dialog); + } diff --git a/briar-android/src/main/java/org/briarproject/briar/android/conversation/AliasDialogFragment.java b/briar-android/src/main/java/org/briarproject/briar/android/conversation/AliasDialogFragment.java index 30df0ecad..8db22b212 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/conversation/AliasDialogFragment.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/conversation/AliasDialogFragment.java @@ -31,6 +31,8 @@ import static org.briarproject.briar.android.util.UiUtils.showSoftKeyboard; @MethodsNotNullByDefault @ParametersNotNullByDefault +// TODO: we can probably switch to androidx DialogFragment here but need to +// test this properly public class AliasDialogFragment extends AppCompatDialogFragment { final static String TAG = AliasDialogFragment.class.getName(); 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 5b45365c2..375a72d70 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 @@ -50,6 +50,7 @@ import org.briarproject.briar.android.blog.BlogActivity; import org.briarproject.briar.android.conversation.ConversationVisitor.AttachmentCache; import org.briarproject.briar.android.conversation.ConversationVisitor.TextCache; import org.briarproject.briar.android.forum.ForumActivity; +import org.briarproject.briar.android.fragment.BaseFragment.BaseFragmentListener; import org.briarproject.briar.android.introduction.IntroductionActivity; import org.briarproject.briar.android.privategroup.conversation.GroupActivity; import org.briarproject.briar.android.util.BriarSnackbarBuilder; @@ -136,7 +137,6 @@ import static org.briarproject.briar.android.conversation.ImageActivity.ITEM_ID; import static org.briarproject.briar.android.conversation.ImageActivity.NAME; import static org.briarproject.briar.android.util.UiUtils.observeOnce; import static org.briarproject.briar.android.view.AuthorView.setAvatar; -import static org.briarproject.briar.api.autodelete.AutoDeleteConstants.NO_AUTO_DELETE_TIMER; import static org.briarproject.briar.api.messaging.MessagingConstants.MAX_ATTACHMENTS_PER_MESSAGE; import static org.briarproject.briar.api.messaging.MessagingConstants.MAX_PRIVATE_MESSAGE_TEXT_LENGTH; import static org.briarproject.briar.api.messaging.PrivateMessageFormat.TEXT_IMAGES_AUTO_DELETE; @@ -145,8 +145,8 @@ import static org.briarproject.briar.api.messaging.PrivateMessageFormat.TEXT_ONL @MethodsNotNullByDefault @ParametersNotNullByDefault public class ConversationActivity extends BriarActivity - implements EventListener, ConversationListener, TextCache, - AttachmentCache, AttachmentListener, ActionMode.Callback { + implements BaseFragmentListener, EventListener, ConversationListener, + TextCache, AttachmentCache, AttachmentListener, ActionMode.Callback { public static final String CONTACT_ID = "briar.CONTACT_ID"; @@ -374,10 +374,8 @@ public class ConversationActivity extends BriarActivity // show auto-delete timer setting only, if contacts supports it observeOnce(viewModel.getPrivateMessageFormat(), this, format -> { boolean visible = format == TEXT_IMAGES_AUTO_DELETE; - MenuItem item = menu.findItem(R.id.action_auto_delete); + MenuItem item = menu.findItem(R.id.action_conversation_settings); item.setVisible(visible); - viewModel.getAutoDeleteTimer().observe(this, timer -> - item.setChecked(timer != NO_AUTO_DELETE_TIMER)); }); return super.onCreateOptionsMenu(menu); @@ -400,10 +398,12 @@ public class ConversationActivity extends BriarActivity AliasDialogFragment.newInstance().show( getSupportFragmentManager(), AliasDialogFragment.TAG); return true; - case R.id.action_auto_delete: - boolean enabled = !item.isChecked(); - viewModel.setAutoDeleteTimerEnabled(enabled); - item.setChecked(enabled); + case R.id.action_conversation_settings: + if (contactId == null) return false; + ConversationSettingsDialog dialog = + ConversationSettingsDialog.newInstance(contactId); + dialog.show(getSupportFragmentManager(), + ConversationSettingsDialog.TAG); return true; case R.id.action_delete_all_messages: askToDeleteAllMessages(); diff --git a/briar-android/src/main/java/org/briarproject/briar/android/conversation/ConversationSettingsDialog.java b/briar-android/src/main/java/org/briarproject/briar/android/conversation/ConversationSettingsDialog.java new file mode 100644 index 000000000..0f38d964e --- /dev/null +++ b/briar-android/src/main/java/org/briarproject/briar/android/conversation/ConversationSettingsDialog.java @@ -0,0 +1,122 @@ +package org.briarproject.briar.android.conversation; + +import android.content.Context; +import android.os.Bundle; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.TextView; + +import org.briarproject.bramble.api.contact.ContactId; +import org.briarproject.bramble.api.nullsafety.MethodsNotNullByDefault; +import org.briarproject.bramble.api.nullsafety.ParametersNotNullByDefault; +import org.briarproject.briar.R; +import org.briarproject.briar.android.activity.ActivityComponent; +import org.briarproject.briar.android.fragment.BaseFragment; + +import java.util.logging.Logger; + +import javax.inject.Inject; + +import androidx.annotation.Nullable; +import androidx.appcompat.widget.SwitchCompat; +import androidx.appcompat.widget.Toolbar; +import androidx.fragment.app.DialogFragment; +import androidx.fragment.app.FragmentActivity; +import androidx.lifecycle.ViewModelProvider; + +import static org.briarproject.briar.android.conversation.ConversationActivity.CONTACT_ID; +import static org.briarproject.briar.api.autodelete.AutoDeleteConstants.NO_AUTO_DELETE_TIMER; + +@MethodsNotNullByDefault +@ParametersNotNullByDefault +public class ConversationSettingsDialog extends DialogFragment { + + final static String TAG = ConversationSettingsDialog.class.getName(); + + private static final Logger LOG = Logger.getLogger(TAG); + + @Inject + ViewModelProvider.Factory viewModelFactory; + + private ConversationViewModel viewModel; + + static ConversationSettingsDialog newInstance(ContactId contactId) { + Bundle args = new Bundle(); + args.putInt(CONTACT_ID, contactId.getInt()); + ConversationSettingsDialog dialog = new ConversationSettingsDialog(); + dialog.setArguments(args); + return dialog; + } + + @Override + public void onAttach(Context context) { + super.onAttach(context); + injectFragment(((BaseFragment.BaseFragmentListener) context) + .getActivityComponent()); + } + + public void injectFragment(ActivityComponent component) { + component.inject(this); + viewModel = new ViewModelProvider(requireActivity(), viewModelFactory) + .get(ConversationViewModel.class); + } + + @Override + public void onCreate(@Nullable Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setStyle(DialogFragment.STYLE_NO_FRAME, + R.style.BriarFullScreenDialogTheme); + } + + @Nullable + @Override + public View onCreateView(LayoutInflater inflater, + @Nullable ViewGroup container, + @Nullable Bundle savedInstanceState) { + View view = inflater.inflate(R.layout.fragment_conversation_settings, + container, false); + + Bundle args = requireArguments(); + int id = args.getInt(CONTACT_ID, -1); + if (id == -1) throw new IllegalStateException(); + ContactId contactId = new ContactId(id); + + FragmentActivity activity = requireActivity(); + viewModel = new ViewModelProvider(activity, viewModelFactory) + .get(ConversationViewModel.class); + viewModel.setContactId(contactId); + + Toolbar toolbar = view.findViewById(R.id.toolbar); + toolbar.setNavigationOnClickListener(v -> dismiss()); + + SwitchCompat switchDisappearingMessages = view.findViewById( + R.id.switchDisappearingMessages); + switchDisappearingMessages.setOnCheckedChangeListener( + (button, value) -> viewModel.setAutoDeleteTimerEnabled(value)); + + TextView buttonLearnMore = + view.findViewById(R.id.buttonLearnMore); + buttonLearnMore.setOnClickListener(e -> showLearnMoreDialog()); + + viewModel.getAutoDeleteTimer() + .observe(getViewLifecycleOwner(), timer -> { + LOG.info("Received auto delete timer: " + timer); + boolean disappearingMessages = + timer != NO_AUTO_DELETE_TIMER; + switchDisappearingMessages + .setChecked(disappearingMessages); + switchDisappearingMessages.setEnabled(true); + }); + + return view; + } + + private void showLearnMoreDialog() { + ConversationSettingsLearnMoreDialog + dialog = new ConversationSettingsLearnMoreDialog(); + dialog.show(getChildFragmentManager(), + ConversationSettingsLearnMoreDialog.TAG); + } + +} diff --git a/briar-android/src/main/java/org/briarproject/briar/android/conversation/ConversationSettingsLearnMoreDialog.java b/briar-android/src/main/java/org/briarproject/briar/android/conversation/ConversationSettingsLearnMoreDialog.java new file mode 100644 index 000000000..5f5b960fd --- /dev/null +++ b/briar-android/src/main/java/org/briarproject/briar/android/conversation/ConversationSettingsLearnMoreDialog.java @@ -0,0 +1,43 @@ +package org.briarproject.briar.android.conversation; + +import android.app.Dialog; +import android.os.Bundle; +import android.view.LayoutInflater; +import android.view.View; + +import org.briarproject.bramble.api.nullsafety.MethodsNotNullByDefault; +import org.briarproject.bramble.api.nullsafety.ParametersNotNullByDefault; +import org.briarproject.briar.R; + +import androidx.annotation.Nullable; +import androidx.appcompat.app.AlertDialog; +import androidx.fragment.app.DialogFragment; +import androidx.fragment.app.FragmentActivity; + +@MethodsNotNullByDefault +@ParametersNotNullByDefault +public class ConversationSettingsLearnMoreDialog extends DialogFragment { + + final static String TAG = + ConversationSettingsLearnMoreDialog.class.getName(); + + @Override + public Dialog onCreateDialog(@Nullable Bundle savedInstanceState) { + FragmentActivity activity = requireActivity(); + + AlertDialog.Builder builder = new AlertDialog.Builder(activity, + R.style.OnboardingDialogTheme); + + LayoutInflater inflater = LayoutInflater.from(builder.getContext()); + View view = inflater.inflate( + R.layout.fragment_conversation_settings_learn_more, null); + builder.setView(view); + + builder.setTitle(R.string.disappearing_messages_title); + builder.setPositiveButton(R.string.ok, null); + + return builder.create(); + } + + +} diff --git a/briar-android/src/main/res/layout/fragment_conversation_settings.xml b/briar-android/src/main/res/layout/fragment_conversation_settings.xml new file mode 100644 index 000000000..c363d9b09 --- /dev/null +++ b/briar-android/src/main/res/layout/fragment_conversation_settings.xml @@ -0,0 +1,71 @@ + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/briar-android/src/main/res/layout/fragment_conversation_settings_learn_more.xml b/briar-android/src/main/res/layout/fragment_conversation_settings_learn_more.xml new file mode 100644 index 000000000..3e3c6260d --- /dev/null +++ b/briar-android/src/main/res/layout/fragment_conversation_settings_learn_more.xml @@ -0,0 +1,19 @@ + + + + + + \ No newline at end of file diff --git a/briar-android/src/main/res/menu/conversation_actions.xml b/briar-android/src/main/res/menu/conversation_actions.xml index 8695171fa..f3d057b08 100644 --- a/briar-android/src/main/res/menu/conversation_actions.xml +++ b/briar-android/src/main/res/menu/conversation_actions.xml @@ -17,9 +17,8 @@ app:showAsAction="never" /> diff --git a/briar-android/src/main/res/values/strings.xml b/briar-android/src/main/res/values/strings.xml index a91b4a420..414228051 100644 --- a/briar-android/src/main/res/values/strings.xml +++ b/briar-android/src/main/res/values/strings.xml @@ -166,7 +166,7 @@ Image format unsupported: %s Change contact name Contact name - Disappearing messages + Disappearing messages Your messages will disappear after 7 days. Your messages will not disappear. %1$s\'s messages will disappear after 7 days. @@ -557,6 +557,19 @@ Choose ringtone Cannot load ringtone + + Disappearing messages + Turning on this setting will make new + messages in this conversation automatically disappear 7\u00A0days after being received. + This applies to messages you send to your contact as well as messages your contact sends to you. + Your contact can also change this setting for the both of you. + \n\nMessages that will disappear are marked with a bomb icon. + \n\nKeep in mind that recipients can still make copies of the messages you send. + \n\nIf you change this setting, it will apply to your messages immediately and to your + contact\'s messages once they receive your next message. + Learn more + Make future messages in this conversation automatically disappear 7\u00A0days after being received. + Send feedback diff --git a/briar-android/src/main/res/values/themes.xml b/briar-android/src/main/res/values/themes.xml index 211fe6ebc..72eac331f 100644 --- a/briar-android/src/main/res/values/themes.xml +++ b/briar-android/src/main/res/values/themes.xml @@ -43,6 +43,16 @@ true + + + +