Add auto-deletion timer to private messages.

This commit is contained in:
akwizgran
2020-11-19 12:57:07 +00:00
committed by Torsten Grote
parent 629cff20a3
commit dba85debfa
18 changed files with 208 additions and 75 deletions

View File

@@ -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";
}

View File

@@ -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

View File

@@ -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;
}
}

View File

@@ -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);
}

View File

@@ -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 {

View File

@@ -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);
}

View File

@@ -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;

View File

@@ -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);
}