From aded1daf925ba4ac6189f36832a3c96096926c2d Mon Sep 17 00:00:00 2001 From: Torsten Grote Date: Mon, 1 Mar 2021 13:57:23 -0300 Subject: [PATCH] Auto-delete PrivateGroup invitations and responses as well --- .../invitation/AbstractProtocolEngine.java | 12 +++ .../GroupInvitationManagerImpl.java | 75 +++++++++++++++++-- .../invitation/GroupInvitationModule.java | 6 +- .../GroupInvitationManagerImplTest.java | 17 ++--- 4 files changed, 93 insertions(+), 17 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 b52156ecd..2bf722db0 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 @@ -132,6 +132,10 @@ abstract class AbstractProtocolEngine> privateGroup.getCreator(), privateGroup.getSalt(), text, signature, timer); sendMessage(txn, m, INVITE, privateGroup.getId(), true, timer); + // Set the auto-delete timer duration on the message + if (timer != NO_AUTO_DELETE_TIMER) { + db.setCleanupTimerDuration(txn, m.getId(), timer); + } } else { m = messageEncoder.encodeInviteMessage(s.getContactGroupId(), privateGroup.getId(), timestamp, privateGroup.getName(), @@ -162,6 +166,10 @@ abstract class AbstractProtocolEngine> s.getLastLocalMessageId(), timer); sendMessage(txn, m, JOIN, s.getPrivateGroupId(), visibleInUi, timer); + // Set the auto-delete timer duration on the message + if (timer != NO_AUTO_DELETE_TIMER) { + db.setCleanupTimerDuration(txn, m.getId(), timer); + } } else { m = messageEncoder.encodeJoinMessage(s.getContactGroupId(), s.getPrivateGroupId(), localTimestamp, @@ -191,6 +199,10 @@ abstract class AbstractProtocolEngine> s.getLastLocalMessageId(), timer); sendMessage(txn, m, LEAVE, s.getPrivateGroupId(), visibleInUi, timer); + // Set the auto-delete timer duration on the message + if (timer != NO_AUTO_DELETE_TIMER) { + db.setCleanupTimerDuration(txn, m.getId(), timer); + } } else { m = messageEncoder.encodeLeaveMessage(s.getContactGroupId(), s.getPrivateGroupId(), localTimestamp, 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 c34a23c3e..f2036b4f5 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 @@ -1,6 +1,7 @@ package org.briarproject.briar.privategroup.invitation; import org.briarproject.bramble.api.FormatException; +import org.briarproject.bramble.api.cleanup.CleanupHook; import org.briarproject.bramble.api.client.ClientHelper; import org.briarproject.bramble.api.client.ContactGroupFactory; import org.briarproject.bramble.api.contact.Contact; @@ -24,6 +25,7 @@ import org.briarproject.bramble.api.sync.MessageId; import org.briarproject.bramble.api.sync.MessageStatus; import org.briarproject.bramble.api.versioning.ClientVersioningManager; import org.briarproject.bramble.api.versioning.ClientVersioningManager.ClientVersioningHook; +import org.briarproject.briar.api.autodelete.event.ConversationMessagesDeletedEvent; import org.briarproject.briar.api.client.MessageTracker; import org.briarproject.briar.api.client.SessionId; import org.briarproject.briar.api.conversation.ConversationMessageHeader; @@ -52,6 +54,7 @@ import javax.annotation.concurrent.Immutable; import javax.inject.Inject; import static org.briarproject.bramble.api.sync.Group.Visibility.SHARED; +import static org.briarproject.briar.api.autodelete.AutoDeleteConstants.NO_AUTO_DELETE_TIMER; import static org.briarproject.briar.privategroup.invitation.CreatorState.START; import static org.briarproject.briar.privategroup.invitation.MessageType.ABORT; import static org.briarproject.briar.privategroup.invitation.MessageType.INVITE; @@ -65,7 +68,7 @@ import static org.briarproject.briar.privategroup.invitation.Role.PEER; @NotNullByDefault class GroupInvitationManagerImpl extends ConversationClientImpl implements GroupInvitationManager, OpenDatabaseHook, ContactHook, - PrivateGroupHook, ClientVersioningHook { + PrivateGroupHook, ClientVersioningHook, CleanupHook { private final ClientVersioningManager clientVersioningManager; private final ContactGroupFactory contactGroupFactory; @@ -148,6 +151,11 @@ class GroupInvitationManagerImpl extends ConversationClientImpl BdfDictionary bdfMeta) throws DbException, FormatException { // Parse the metadata MessageMetadata meta = messageParser.parseMetadata(bdfMeta); + // set the clean-up timer that will be started when message gets read + long timer = meta.getAutoDeleteTimer(); + if (timer != NO_AUTO_DELETE_TIMER) { + db.setCleanupTimerDuration(txn, m.getId(), timer); + } // Look up the session, if there is one SessionId sessionId = getSessionId(meta.getPrivateGroupId()); StoredSession ss = getSession(txn, m.getGroupId(), sessionId); @@ -301,7 +309,12 @@ class GroupInvitationManagerImpl extends ConversationClientImpl @Override public void respondToInvitation(ContactId c, SessionId sessionId, boolean accept) throws DbException { - Transaction txn = db.startTransaction(false); + db.transaction(false, + txn -> respondToInvitation(txn, c, sessionId, accept)); + } + + private void respondToInvitation(Transaction txn, ContactId c, + SessionId sessionId, boolean accept) throws DbException { try { // Look up the session Contact contact = db.getContact(txn, c); @@ -316,11 +329,8 @@ class GroupInvitationManagerImpl extends ConversationClientImpl else session = inviteeEngine.onLeaveAction(txn, session); // Store the updated session storeSession(txn, ss.storageId, session); - db.commitTransaction(txn); } catch (FormatException e) { throw new DbException(e); - } finally { - db.endTransaction(txn); } } @@ -686,7 +696,7 @@ class GroupInvitationManagerImpl extends ConversationClientImpl // get ID of the contact group GroupId g = getContactGroup(db.getContact(txn, c)).getId(); - // get metadata for all messages in the + // get metadata for all messages in the group // (these are sessions *and* protocol messages) Map metadata; try { @@ -762,6 +772,59 @@ class GroupInvitationManagerImpl extends ConversationClientImpl return result; } + @Override + public void deleteMessages(Transaction txn, GroupId g, + Collection messageIds) throws DbException { + ContactId c; + Map sessions = new HashMap<>(); + try { + // get the ContactId from the given GroupId + c = clientHelper.getContactId(txn, g); + // get sessions for all messages to be deleted + for (MessageId messageId : messageIds) { + BdfDictionary d = clientHelper + .getMessageMetadataAsDictionary(txn, messageId); + MessageMetadata messageMetadata = + messageParser.parseMetadata(d); + if (!messageMetadata.isVisibleInConversation()) + throw new IllegalArgumentException(); + SessionId sessionId = + getSessionId(messageMetadata.getPrivateGroupId()); + DeletableSession deletableSession = sessions.get(sessionId); + if (deletableSession == null) { + StoredSession ss = getSession(txn, g, sessionId); + if (ss == null) throw new DbException(); + BdfDictionary sessionMeta = clientHelper + .getMessageMetadataAsDictionary(txn, ss.storageId); + Session session = sessionParser + .parseSession(g, sessionMeta); + deletableSession = new DeletableSession(session.getState()); + sessions.put(sessionId, deletableSession); + } + deletableSession.messages.add(messageId); + } + } catch (FormatException e) { + throw new DbException(e); + } + + // delete given visible messages in sessions and auto-respond before + for (Entry entry : sessions.entrySet()) { + DeletableSession session = entry.getValue(); + // decline invitee sessions waiting for a response before + if (session.state instanceof InviteeState && + session.state.isAwaitingResponse()) { + respondToInvitation(txn, c, entry.getKey(), false); + } + for (MessageId m : session.messages) { + db.deleteMessage(txn, m); + db.deleteMessageMetadata(txn, m); + } + } + recalculateGroupCount(txn, g); + + txn.attach(new ConversationMessagesDeletedEvent(c, messageIds)); + } + @Override public Set getMessageIds(Transaction txn, ContactId c) throws DbException { diff --git a/briar-core/src/main/java/org/briarproject/briar/privategroup/invitation/GroupInvitationModule.java b/briar-core/src/main/java/org/briarproject/briar/privategroup/invitation/GroupInvitationModule.java index 0628357e3..fa0b09019 100644 --- a/briar-core/src/main/java/org/briarproject/briar/privategroup/invitation/GroupInvitationModule.java +++ b/briar-core/src/main/java/org/briarproject/briar/privategroup/invitation/GroupInvitationModule.java @@ -1,5 +1,6 @@ package org.briarproject.briar.privategroup.invitation; +import org.briarproject.bramble.api.cleanup.CleanupManager; import org.briarproject.bramble.api.client.ClientHelper; import org.briarproject.bramble.api.contact.ContactManager; import org.briarproject.bramble.api.data.MetadataEncoder; @@ -41,7 +42,8 @@ public class GroupInvitationModule { ValidationManager validationManager, ContactManager contactManager, PrivateGroupManager privateGroupManager, ConversationManager conversationManager, - ClientVersioningManager clientVersioningManager) { + ClientVersioningManager clientVersioningManager, + CleanupManager cleanupManager) { lifecycleManager.registerOpenDatabaseHook(groupInvitationManager); validationManager.registerIncomingMessageHook(CLIENT_ID, MAJOR_VERSION, groupInvitationManager); @@ -56,6 +58,8 @@ public class GroupInvitationModule { PrivateGroupManager.MAJOR_VERSION, PrivateGroupManager.MINOR_VERSION, groupInvitationManager.getPrivateGroupClientVersioningHook()); + cleanupManager.registerCleanupHook(CLIENT_ID, MAJOR_VERSION, + groupInvitationManager); return groupInvitationManager; } 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 3785a649e..01a3e79a3 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 @@ -21,6 +21,7 @@ import org.briarproject.bramble.api.sync.Message; import org.briarproject.bramble.api.sync.MessageId; import org.briarproject.bramble.api.versioning.ClientVersioningManager; import org.briarproject.bramble.test.BrambleMockTestCase; +import org.briarproject.bramble.test.DbExpectations; import org.briarproject.bramble.test.TestUtils; import org.briarproject.briar.api.client.MessageTracker; import org.briarproject.briar.api.client.SessionId; @@ -329,10 +330,11 @@ public class GroupInvitationManagerImplTest extends BrambleMockTestCase { context.checking(new Expectations() {{ oneOf(messageParser).parseMetadata(meta); will(returnValue(messageMetadata)); + oneOf(messageMetadata).getAutoDeleteTimer(); + will(returnValue(NO_AUTO_DELETE_TIMER)); oneOf(messageMetadata).getPrivateGroupId(); will(returnValue(privateGroup.getId())); }}); - } private void expectIncomingMessage(Role role, MessageType type) @@ -530,15 +532,13 @@ public class GroupInvitationManagerImplTest extends BrambleMockTestCase { public void testRespondToInvitationWithoutSession() throws Exception { SessionId sessionId = new SessionId(getRandomId()); - context.checking(new Expectations() {{ - oneOf(db).startTransaction(false); - will(returnValue(txn)); + context.checking(new DbExpectations() {{ + oneOf(db).transaction(with(false), withDbRunnable(txn)); oneOf(db).getContact(txn, contactId); will(returnValue(contact)); oneOf(contactGroupFactory).createContactGroup(CLIENT_ID, MAJOR_VERSION, contact); will(returnValue(contactGroup)); - oneOf(db).endTransaction(txn); }}); expectGetSession(noResults, sessionId, contactGroup.getId()); @@ -582,9 +582,8 @@ public class GroupInvitationManagerImplTest extends BrambleMockTestCase { private void expectRespondToInvitation(SessionId sessionId, boolean accept) throws Exception { expectGetSession(oneResult, sessionId, contactGroup.getId()); - context.checking(new Expectations() {{ - oneOf(db).startTransaction(false); - will(returnValue(txn)); + context.checking(new DbExpectations() {{ + oneOf(db).transaction(with(false), withDbRunnable(txn)); oneOf(db).getContact(txn, contactId); will(returnValue(contact)); oneOf(contactGroupFactory).createContactGroup(CLIENT_ID, @@ -596,8 +595,6 @@ public class GroupInvitationManagerImplTest extends BrambleMockTestCase { if (accept) oneOf(inviteeEngine).onJoinAction(txn, inviteeSession); else oneOf(inviteeEngine).onLeaveAction(txn, inviteeSession); will(returnValue(inviteeSession)); - oneOf(db).commitTransaction(txn); - oneOf(db).endTransaction(txn); }}); expectStoreSession(inviteeSession, storageMessage.getId()); }