mirror of
https://code.briarproject.org/briar/briar.git
synced 2026-02-12 18:59:06 +01:00
Add auto-deletion timer to private messages.
This commit is contained in:
@@ -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);
|
||||
}
|
||||
@@ -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<Boolean>() {
|
||||
@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());
|
||||
|
||||
@@ -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<String> contactName = map(contactItem, c ->
|
||||
UiUtils.getContactDisplayName(c.getContact()));
|
||||
private final LiveData<GroupId> messagingGroupId;
|
||||
private final MutableLiveData<Boolean> imageSupport =
|
||||
private final MutableLiveData<PrivateMessageFormat> privateMessageFormat =
|
||||
new MutableLiveData<>();
|
||||
private final MutableLiveEvent<Boolean> 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<Contact> 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<AttachmentHeader> 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<Boolean> hasImageSupport() {
|
||||
return imageSupport;
|
||||
LiveData<PrivateMessageFormat> getPrivateMessageFormat() {
|
||||
return privateMessageFormat;
|
||||
}
|
||||
|
||||
LiveEvent<Boolean> showImageOnboarding() {
|
||||
|
||||
@@ -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.
|
||||
* <p>
|
||||
* 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;
|
||||
|
||||
}
|
||||
|
||||
@@ -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<AttachmentHeader> 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<AttachmentHeader> 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<AttachmentHeader> 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<AttachmentHeader> getAttachmentHeaders() {
|
||||
return attachmentHeaders;
|
||||
}
|
||||
|
||||
public long getAutoDeleteTimer() {
|
||||
return autoDeleteTimer;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,4 +19,7 @@ public interface PrivateMessageFactory {
|
||||
@Nullable String text, List<AttachmentHeader> headers)
|
||||
throws FormatException;
|
||||
|
||||
PrivateMessage createPrivateMessage(GroupId groupId, long timestamp,
|
||||
@Nullable String text, List<AttachmentHeader> headers,
|
||||
long autoDeleteTimer) throws FormatException;
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
@@ -17,13 +17,16 @@ public class PrivateMessageHeader extends ConversationMessageHeader {
|
||||
|
||||
private final boolean hasText;
|
||||
private final List<AttachmentHeader> attachmentHeaders;
|
||||
private final long autoDeleteTimer;
|
||||
|
||||
public PrivateMessageHeader(MessageId id, GroupId groupId, long timestamp,
|
||||
boolean local, boolean read, boolean sent, boolean seen,
|
||||
boolean hasText, List<AttachmentHeader> headers) {
|
||||
boolean hasText, List<AttachmentHeader> 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> T accept(ConversationMessageVisitor<T> v) {
|
||||
return v.visitPrivateMessageHeader(this);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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";
|
||||
}
|
||||
|
||||
@@ -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<AttachmentHeader> parseAttachmentHeaders(GroupId g,
|
||||
BdfDictionary meta)
|
||||
throws FormatException {
|
||||
BdfDictionary meta) throws FormatException {
|
||||
BdfList attachmentHeaders = meta.getList(MSG_KEY_ATTACHMENT_HEADERS);
|
||||
int length = attachmentHeaders.size();
|
||||
List<AttachmentHeader> 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
|
||||
|
||||
@@ -47,21 +47,42 @@ class PrivateMessageFactoryImpl implements PrivateMessageFactory {
|
||||
public PrivateMessage createPrivateMessage(GroupId groupId, long timestamp,
|
||||
@Nullable String text, List<AttachmentHeader> 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<AttachmentHeader> 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<AttachmentHeader> 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<AttachmentHeader> 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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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_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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
@@ -351,14 +352,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 {
|
||||
|
||||
@@ -19,6 +19,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;
|
||||
@@ -78,12 +79,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);
|
||||
}
|
||||
|
||||
|
||||
@@ -340,8 +340,9 @@ public class MessagingManagerIntegrationTest
|
||||
BriarIntegrationTestComponent to, @Nullable String text,
|
||||
List<AttachmentHeader> 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;
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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))
|
||||
|
||||
@@ -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)
|
||||
|
||||
Reference in New Issue
Block a user