From b8efe73a3bc686cd1dfdf4451d735ede2db213b1 Mon Sep 17 00:00:00 2001 From: Brice-W Date: Thu, 10 Jun 2021 17:34:48 +1000 Subject: [PATCH 1/5] update formation timestamp when group is rejoined after being left --- .../securesms/database/GroupDatabase.java | 7 +++++++ .../securesms/database/Storage.kt | 4 ++++ .../libsession/database/StorageProtocol.kt | 1 + .../ReceivedMessageHandler.kt | 20 ++++++++++--------- 4 files changed, 23 insertions(+), 9 deletions(-) diff --git a/app/src/main/java/org/thoughtcrime/securesms/database/GroupDatabase.java b/app/src/main/java/org/thoughtcrime/securesms/database/GroupDatabase.java index de34abb650..340506ac30 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/database/GroupDatabase.java +++ b/app/src/main/java/org/thoughtcrime/securesms/database/GroupDatabase.java @@ -308,6 +308,13 @@ public class GroupDatabase extends Database implements LokiOpenGroupDatabaseProt databaseHelper.getWritableDatabase().update(TABLE_NAME, contents, GROUP_ID + " = ?", new String[] {groupId}); } + public void updateFormationTimestamp(String groupId, Long formationTimestamp) { + ContentValues contents = new ContentValues(); + contents.put(TIMESTAMP, formationTimestamp); + + databaseHelper.getWritableDatabase().update(TABLE_NAME, contents, GROUP_ID + " = ?", new String[] {groupId}); + } + public void removeMember(String groupId, Address source) { List
currentMembers = getCurrentMembers(groupId, false); currentMembers.remove(source); diff --git a/app/src/main/java/org/thoughtcrime/securesms/database/Storage.kt b/app/src/main/java/org/thoughtcrime/securesms/database/Storage.kt index 66b4fd5004..22f1f46041 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/database/Storage.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/database/Storage.kt @@ -428,6 +428,10 @@ class Storage(context: Context, helper: SQLCipherOpenHelper) : Database(context, DatabaseFactory.getLokiAPIDatabase(context).removeAllClosedGroupEncryptionKeyPairs(groupPublicKey) } + override fun updateFormationTimestamp(groupID: String, formationTimestamp: Long) { + DatabaseFactory.getGroupDatabase(context).updateFormationTimestamp(groupID, formationTimestamp) + } + override fun getAllV2OpenGroups(): Map { return DatabaseFactory.getLokiThreadDatabase(context).getAllV2OpenGroups() } diff --git a/libsession/src/main/java/org/session/libsession/database/StorageProtocol.kt b/libsession/src/main/java/org/session/libsession/database/StorageProtocol.kt index 9d42a2a2f8..20371c0715 100644 --- a/libsession/src/main/java/org/session/libsession/database/StorageProtocol.kt +++ b/libsession/src/main/java/org/session/libsession/database/StorageProtocol.kt @@ -115,6 +115,7 @@ interface StorageProtocol { fun isClosedGroup(publicKey: String): Boolean fun getClosedGroupEncryptionKeyPairs(groupPublicKey: String): MutableList fun getLatestClosedGroupEncryptionKeyPair(groupPublicKey: String): ECKeyPair? + fun updateFormationTimestamp(groupID: String, formationTimestamp: Long) // Groups fun getAllGroups(): List diff --git a/libsession/src/main/java/org/session/libsession/messaging/sending_receiving/ReceivedMessageHandler.kt b/libsession/src/main/java/org/session/libsession/messaging/sending_receiving/ReceivedMessageHandler.kt index 653492138e..58e0641331 100644 --- a/libsession/src/main/java/org/session/libsession/messaging/sending_receiving/ReceivedMessageHandler.kt +++ b/libsession/src/main/java/org/session/libsession/messaging/sending_receiving/ReceivedMessageHandler.kt @@ -262,27 +262,22 @@ private fun MessageReceiver.handleNewClosedGroup(message: ClosedGroupControlMess private fun handleNewClosedGroup(sender: String, sentTimestamp: Long, groupPublicKey: String, name: String, encryptionKeyPair: ECKeyPair, members: List, admins: List, formationTimestamp: Long) { val context = MessagingModuleConfiguration.shared.context val storage = MessagingModuleConfiguration.shared.storage + val userPublicKey = TextSecurePreferences.getLocalNumber(context) // Create the group val groupID = GroupUtil.doubleEncodeGroupID(groupPublicKey) if (storage.getGroup(groupID) != null) { // Update the group - // Clear zombie list if the group wasn't active if (!storage.isGroupActive(groupPublicKey)) { + // Clear zombie list if the group wasn't active storage.setZombieMembers(groupID, listOf()) + // Update the formation timestamp + storage.updateFormationTimestamp(groupID, formationTimestamp) } storage.updateTitle(groupID, name) storage.updateMembers(groupID, members.map { Address.fromSerialized(it) }) } else { storage.createGroup(groupID, name, LinkedList(members.map { Address.fromSerialized(it) }), null, null, LinkedList(admins.map { Address.fromSerialized(it) }), formationTimestamp) - val userPublicKey = TextSecurePreferences.getLocalNumber(context) - // Notify the user - if (userPublicKey == sender) { - val threadID = storage.getOrCreateThreadIdFor(Address.fromSerialized(groupID)) - storage.insertOutgoingInfoMessage(context, groupID, SignalServiceGroup.Type.CREATION, name, members, admins, threadID, sentTimestamp) - } else { - storage.insertIncomingInfoMessage(context, sender, groupID, SignalServiceGroup.Type.CREATION, name, members, admins, sentTimestamp) - } } storage.setProfileSharing(Address.fromSerialized(groupID), true) // Add the group to the user's set of public keys to poll for @@ -291,6 +286,13 @@ private fun handleNewClosedGroup(sender: String, sentTimestamp: Long, groupPubli storage.addClosedGroupEncryptionKeyPair(encryptionKeyPair, groupPublicKey) // Notify the PN server PushNotificationAPI.performOperation(PushNotificationAPI.ClosedGroupOperation.Subscribe, groupPublicKey, storage.getUserPublicKey()!!) + // Notify the user + if (userPublicKey == sender) { + val threadID = storage.getOrCreateThreadIdFor(Address.fromSerialized(groupID)) + storage.insertOutgoingInfoMessage(context, groupID, SignalServiceGroup.Type.CREATION, name, members, admins, threadID, sentTimestamp) + } else { + storage.insertIncomingInfoMessage(context, sender, groupID, SignalServiceGroup.Type.CREATION, name, members, admins, sentTimestamp) + } // Start polling ClosedGroupPollerV2.shared.startPolling(groupPublicKey) } From 7b22d14a2cab48072821c35b5c5c9eb99db881a3 Mon Sep 17 00:00:00 2001 From: Brice-W Date: Tue, 15 Jun 2021 16:16:03 +1000 Subject: [PATCH 2/5] using different timestamp for NEW group updates --- .../sending_receiving/MessageSenderClosedGroupHandler.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libsession/src/main/java/org/session/libsession/messaging/sending_receiving/MessageSenderClosedGroupHandler.kt b/libsession/src/main/java/org/session/libsession/messaging/sending_receiving/MessageSenderClosedGroupHandler.kt index 521d043170..c5c5e9a506 100644 --- a/libsession/src/main/java/org/session/libsession/messaging/sending_receiving/MessageSenderClosedGroupHandler.kt +++ b/libsession/src/main/java/org/session/libsession/messaging/sending_receiving/MessageSenderClosedGroupHandler.kt @@ -161,7 +161,7 @@ fun MessageSender.addMembers(groupPublicKey: String, membersToAdd: List) for (member in membersToAdd) { val closedGroupNewKind = ClosedGroupControlMessage.Kind.New(ByteString.copyFrom(Hex.fromStringCondensed(groupPublicKey)), name, encryptionKeyPair, membersAsData, adminsAsData, expireTimer) val closedGroupControlMessage = ClosedGroupControlMessage(closedGroupNewKind) - closedGroupControlMessage.sentTimestamp = sentTime + closedGroupControlMessage.sentTimestamp = System.currentTimeMillis() send(closedGroupControlMessage, Address.fromSerialized(member)) } // Notify the user From 1b6ab36a03d75820227b2c4d126c749f5b71de1b Mon Sep 17 00:00:00 2001 From: Brice-W Date: Tue, 15 Jun 2021 16:47:35 +1000 Subject: [PATCH 3/5] fix --- .../messaging/sending_receiving/ReceivedMessageHandler.kt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/libsession/src/main/java/org/session/libsession/messaging/sending_receiving/ReceivedMessageHandler.kt b/libsession/src/main/java/org/session/libsession/messaging/sending_receiving/ReceivedMessageHandler.kt index aad02caed4..27bd608f3c 100644 --- a/libsession/src/main/java/org/session/libsession/messaging/sending_receiving/ReceivedMessageHandler.kt +++ b/libsession/src/main/java/org/session/libsession/messaging/sending_receiving/ReceivedMessageHandler.kt @@ -429,7 +429,7 @@ private fun MessageReceiver.handleClosedGroupMembersAdded(message: ClosedGroupCo val encryptionKeyPair = pendingKeyPairs[groupPublicKey]?.orNull() ?: storage.getLatestClosedGroupEncryptionKeyPair(groupPublicKey) if (encryptionKeyPair == null) { - android.util.Log.d("Loki", "Couldn't get encryption key pair for closed group.") + Log.d("Loki", "Couldn't get encryption key pair for closed group.") } else { for (user in updateMembers) { MessageSender.sendEncryptionKeyPair(groupPublicKey, encryptionKeyPair, setOf(user), targetUser = user, force = false) @@ -561,12 +561,12 @@ private fun isValidGroupUpdate(group: GroupRecord, sentTimestamp: Long, senderPu val oldMembers = group.members.map { it.serialize() } // Check that the message isn't from before the group was created if (group.formationTimestamp > sentTimestamp) { - android.util.Log.d("Loki", "Ignoring closed group update from before thread was created.") + Log.d("Loki", "Ignoring closed group update from before thread was created.") return false } // Check that the sender is a member of the group (before the update) if (senderPublicKey !in oldMembers) { - android.util.Log.d("Loki", "Ignoring closed group info message from non-member.") + Log.d("Loki", "Ignoring closed group info message from non-member.") return false } return true From 88372562761cd426be3325898e817e2b56d27bf8 Mon Sep 17 00:00:00 2001 From: Brice-W Date: Tue, 15 Jun 2021 17:21:24 +1000 Subject: [PATCH 4/5] delete listener if current user is admin --- .../securesms/loki/activities/EditClosedGroupMembersAdapter.kt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/app/src/main/java/org/thoughtcrime/securesms/loki/activities/EditClosedGroupMembersAdapter.kt b/app/src/main/java/org/thoughtcrime/securesms/loki/activities/EditClosedGroupMembersAdapter.kt index ab5e79d105..4a451ba222 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/loki/activities/EditClosedGroupMembersAdapter.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/loki/activities/EditClosedGroupMembersAdapter.kt @@ -56,6 +56,8 @@ class EditClosedGroupMembersAdapter( if (unlocked) { viewHolder.view.setOnClickListener { this.memberClickListener?.invoke(member) } + } else { + viewHolder.view.setOnClickListener(null) } } From 71ffaaabc2ba99dfb0226c0007efdfa7ab1d106d Mon Sep 17 00:00:00 2001 From: Niels Andriesse Date: Wed, 16 Jun 2021 10:19:42 +1000 Subject: [PATCH 5/5] Add documentation --- .../sending_receiving/MessageSenderClosedGroupHandler.kt | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/libsession/src/main/java/org/session/libsession/messaging/sending_receiving/MessageSenderClosedGroupHandler.kt b/libsession/src/main/java/org/session/libsession/messaging/sending_receiving/MessageSenderClosedGroupHandler.kt index c5c5e9a506..dfd63b2090 100644 --- a/libsession/src/main/java/org/session/libsession/messaging/sending_receiving/MessageSenderClosedGroupHandler.kt +++ b/libsession/src/main/java/org/session/libsession/messaging/sending_receiving/MessageSenderClosedGroupHandler.kt @@ -161,6 +161,12 @@ fun MessageSender.addMembers(groupPublicKey: String, membersToAdd: List) for (member in membersToAdd) { val closedGroupNewKind = ClosedGroupControlMessage.Kind.New(ByteString.copyFrom(Hex.fromStringCondensed(groupPublicKey)), name, encryptionKeyPair, membersAsData, adminsAsData, expireTimer) val closedGroupControlMessage = ClosedGroupControlMessage(closedGroupNewKind) + // It's important that the sent timestamp of this message is greater than the sent timestamp + // of the `MembersAdded` message above. The reason is that upon receiving this `New` message, + // the recipient will update the closed group formation timestamp and ignore any closed group + // updates from before that timestamp. By setting the timestamp of the message below to a value + // greater than that of the `MembersAdded` message, we ensure that newly added members ignore + // the `MembersAdded` message. closedGroupControlMessage.sentTimestamp = System.currentTimeMillis() send(closedGroupControlMessage, Address.fromSerialized(member)) }