From 88ac3904955917658876c168ef4223b0c9bc3435 Mon Sep 17 00:00:00 2001 From: Ryan ZHAO Date: Thu, 4 Mar 2021 14:54:32 +1100 Subject: [PATCH] plug in closed group message sender --- .../conversation/ConversationActivity.java | 4 +- .../activities/CreateClosedGroupActivity.kt | 6 +-- .../activities/EditClosedGroupActivity.kt | 14 ++--- .../securesms/loki/activities/HomeActivity.kt | 4 +- .../sending_receiving/MessageSender.kt | 26 ++++++++- .../MessageSenderClosedGroup.kt | 53 +++++++++++-------- 6 files changed, 67 insertions(+), 40 deletions(-) diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/ConversationActivity.java b/app/src/main/java/org/thoughtcrime/securesms/conversation/ConversationActivity.java index c89314b46e..d2b0db6b24 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/conversation/ConversationActivity.java +++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/ConversationActivity.java @@ -128,7 +128,6 @@ import org.thoughtcrime.securesms.database.DraftDatabase.Draft; import org.thoughtcrime.securesms.database.DraftDatabase.Drafts; import org.thoughtcrime.securesms.database.MessagingDatabase.MarkedMessageInfo; import org.thoughtcrime.securesms.database.MmsSmsColumns.Types; -import org.thoughtcrime.securesms.database.Storage; import org.thoughtcrime.securesms.database.ThreadDatabase; import org.thoughtcrime.securesms.database.model.MessageRecord; import org.thoughtcrime.securesms.database.model.MmsMessageRecord; @@ -142,7 +141,6 @@ import org.thoughtcrime.securesms.loki.activities.HomeActivity; import org.thoughtcrime.securesms.loki.api.PublicChatInfoUpdateWorker; import org.thoughtcrime.securesms.loki.database.LokiThreadDatabase; import org.thoughtcrime.securesms.loki.database.LokiUserDatabase; -import org.thoughtcrime.securesms.loki.protocol.ClosedGroupsProtocolV2; import org.thoughtcrime.securesms.loki.utilities.GeneralUtilitiesKt; import org.thoughtcrime.securesms.loki.utilities.MentionManagerUtilities; import org.thoughtcrime.securesms.loki.utilities.OpenGroupUtilities; @@ -1017,7 +1015,7 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity } try { if (isClosedGroup) { - ClosedGroupsProtocolV2.explicitLeave(this, groupPublicKey); + MessageSender.explicitLeave(groupPublicKey); initializeEnabledCheck(); } else { Toast.makeText(this, R.string.ConversationActivity_error_leaving_group, Toast.LENGTH_LONG).show(); diff --git a/app/src/main/java/org/thoughtcrime/securesms/loki/activities/CreateClosedGroupActivity.kt b/app/src/main/java/org/thoughtcrime/securesms/loki/activities/CreateClosedGroupActivity.kt index 7eee06e54e..5f63e6ec4e 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/loki/activities/CreateClosedGroupActivity.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/loki/activities/CreateClosedGroupActivity.kt @@ -13,6 +13,7 @@ import android.widget.Toast import kotlinx.android.synthetic.main.activity_create_closed_group.* import network.loki.messenger.R import nl.komponents.kovenant.ui.successUi +import org.session.libsession.messaging.sending_receiving.MessageSender import org.thoughtcrime.securesms.PassphraseRequiredActionBarActivity import org.thoughtcrime.securesms.conversation.ConversationActivity import org.session.libsession.messaging.threads.Address @@ -23,7 +24,6 @@ import org.thoughtcrime.securesms.loki.utilities.fadeOut import org.thoughtcrime.securesms.mms.GlideApp import org.session.libsession.messaging.threads.recipients.Recipient import org.session.libsession.utilities.TextSecurePreferences -import org.thoughtcrime.securesms.loki.protocol.ClosedGroupsProtocolV2 //TODO Refactor to avoid using kotlinx.android.synthetic class CreateClosedGroupActivity : PassphraseRequiredActionBarActivity(), LoaderManager.LoaderCallbacks> { @@ -103,13 +103,13 @@ class CreateClosedGroupActivity : PassphraseRequiredActionBarActivity(), LoaderM if (selectedMembers.count() < 1) { return Toast.makeText(this, R.string.activity_create_closed_group_not_enough_group_members_error, Toast.LENGTH_LONG).show() } - if (selectedMembers.count() >= ClosedGroupsProtocolV2.groupSizeLimit) { // Minus one because we're going to include self later + if (selectedMembers.count() >= MessageSender.groupSizeLimit) { // Minus one because we're going to include self later return Toast.makeText(this, R.string.activity_create_closed_group_too_many_group_members_error, Toast.LENGTH_LONG).show() } val userPublicKey = TextSecurePreferences.getLocalNumber(this)!! isLoading = true loaderContainer.fadeIn() - ClosedGroupsProtocolV2.createClosedGroup(this, name.toString(), selectedMembers + setOf( userPublicKey )).successUi { groupID -> + MessageSender.createClosedGroup(name.toString(), selectedMembers + setOf( userPublicKey )).successUi { groupID -> loaderContainer.fadeOut() isLoading = false val threadID = DatabaseFactory.getThreadDatabase(this).getOrCreateThreadIdFor(Recipient.from(this, Address.fromSerialized(groupID), false)) diff --git a/app/src/main/java/org/thoughtcrime/securesms/loki/activities/EditClosedGroupActivity.kt b/app/src/main/java/org/thoughtcrime/securesms/loki/activities/EditClosedGroupActivity.kt index e5605e2894..c3bc837b25 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/loki/activities/EditClosedGroupActivity.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/loki/activities/EditClosedGroupActivity.kt @@ -19,12 +19,12 @@ import nl.komponents.kovenant.Promise import nl.komponents.kovenant.task import nl.komponents.kovenant.ui.failUi import nl.komponents.kovenant.ui.successUi +import org.session.libsession.messaging.sending_receiving.MessageSender import org.thoughtcrime.securesms.PassphraseRequiredActionBarActivity import org.session.libsession.messaging.threads.Address import org.thoughtcrime.securesms.database.DatabaseFactory import org.thoughtcrime.securesms.groups.GroupManager import org.thoughtcrime.securesms.loki.dialogs.ClosedGroupEditingOptionsBottomSheet -import org.thoughtcrime.securesms.loki.protocol.ClosedGroupsProtocolV2 import org.thoughtcrime.securesms.loki.utilities.fadeIn import org.thoughtcrime.securesms.loki.utilities.fadeOut import org.thoughtcrime.securesms.mms.GlideApp @@ -260,7 +260,7 @@ class EditClosedGroupActivity : PassphraseRequiredActionBarActivity() { return Toast.makeText(this, R.string.activity_edit_closed_group_not_enough_group_members_error, Toast.LENGTH_LONG).show() } - val maxGroupMembers = if (isClosedGroup) ClosedGroupsProtocolV2.groupSizeLimit else legacyGroupSizeLimit + val maxGroupMembers = if (isClosedGroup) MessageSender.groupSizeLimit else legacyGroupSizeLimit if (members.size >= maxGroupMembers) { return Toast.makeText(this, R.string.activity_create_closed_group_too_many_group_members_error, Toast.LENGTH_LONG).show() } @@ -277,17 +277,17 @@ class EditClosedGroupActivity : PassphraseRequiredActionBarActivity() { isLoading = true loaderContainer.fadeIn() val promise: Promise = if (!members.contains(Recipient.from(this, Address.fromSerialized(userPublicKey), false))) { - ClosedGroupsProtocolV2.explicitLeave(this, groupPublicKey!!) + MessageSender.explicitLeave(groupPublicKey!!) } else { task { if (hasNameChanged) { - ClosedGroupsProtocolV2.explicitNameChange(this@EditClosedGroupActivity, groupPublicKey!!, name) + MessageSender.explicitNameChange(groupPublicKey!!, name) } members.filterNot { it in originalMembers }.let { adds -> - if (adds.isNotEmpty()) ClosedGroupsProtocolV2.explicitAddMembers(this@EditClosedGroupActivity, groupPublicKey!!, adds.map { it.address.serialize() }) + if (adds.isNotEmpty()) MessageSender.explicitAddMembers(groupPublicKey!!, adds.map { it.address.serialize() }) } originalMembers.filterNot { it in members }.let { removes -> - if (removes.isNotEmpty()) ClosedGroupsProtocolV2.explicitRemoveMembers(this@EditClosedGroupActivity, groupPublicKey!!, removes.map { it.address.serialize() }) + if (removes.isNotEmpty()) MessageSender.explicitRemoveMembers(groupPublicKey!!, removes.map { it.address.serialize() }) } } } @@ -296,7 +296,7 @@ class EditClosedGroupActivity : PassphraseRequiredActionBarActivity() { isLoading = false finish() }.failUi { exception -> - val message = if (exception is ClosedGroupsProtocolV2.Error) exception.description else "An error occurred" + val message = if (exception is MessageSender.Error) exception.description else "An error occurred" Toast.makeText(this@EditClosedGroupActivity, message, Toast.LENGTH_LONG).show() loaderContainer.fadeOut() isLoading = false diff --git a/app/src/main/java/org/thoughtcrime/securesms/loki/activities/HomeActivity.kt b/app/src/main/java/org/thoughtcrime/securesms/loki/activities/HomeActivity.kt index 583ea45279..1fb3a58f4b 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/loki/activities/HomeActivity.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/loki/activities/HomeActivity.kt @@ -25,6 +25,7 @@ import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch import kotlinx.coroutines.withContext import network.loki.messenger.R +import org.session.libsession.messaging.sending_receiving.MessageSender import org.thoughtcrime.securesms.ApplicationContext import org.thoughtcrime.securesms.PassphraseRequiredActionBarActivity import org.thoughtcrime.securesms.conversation.ConversationActivity @@ -43,7 +44,6 @@ import org.session.libsignal.service.loki.utilities.mentions.MentionsManager import org.session.libsignal.utilities.ThreadUtils import org.session.libsignal.service.loki.utilities.toHexString import org.thoughtcrime.securesms.loki.dialogs.* -import org.thoughtcrime.securesms.loki.protocol.ClosedGroupsProtocolV2 import java.io.IOException class HomeActivity : PassphraseRequiredActionBarActivity, ConversationClickListener, SeedReminderViewDelegate, NewConversationButtonSetViewDelegate { @@ -306,7 +306,7 @@ class HomeActivity : PassphraseRequiredActionBarActivity, ConversationClickListe isClosedGroup = false } if (isClosedGroup) { - ClosedGroupsProtocolV2.explicitLeave(context, groupPublicKey!!) + MessageSender.explicitLeave(groupPublicKey!!) } else { Toast.makeText(context, R.string.activity_home_leaving_group_failed_message, Toast.LENGTH_LONG).show() return@launch diff --git a/libsession/src/main/java/org/session/libsession/messaging/sending_receiving/MessageSender.kt b/libsession/src/main/java/org/session/libsession/messaging/sending_receiving/MessageSender.kt index 0f614e25b4..61447b795e 100644 --- a/libsession/src/main/java/org/session/libsession/messaging/sending_receiving/MessageSender.kt +++ b/libsession/src/main/java/org/session/libsession/messaging/sending_receiving/MessageSender.kt @@ -1,6 +1,5 @@ package org.session.libsession.messaging.sending_receiving -import android.util.Size import nl.komponents.kovenant.Promise import nl.komponents.kovenant.deferred import org.session.libsession.messaging.MessagingConfiguration @@ -33,9 +32,10 @@ import org.session.libsignal.utilities.logging.Log object MessageSender { + const val groupSizeLimit = 100 // Error - internal sealed class Error(val description: String) : Exception() { + sealed class Error(val description: String) : Exception() { object InvalidMessage : Error("Invalid message.") object ProtoConversionFailed : Error("Couldn't convert message to proto.") object ProofOfWorkCalculationFailed : Error("Proof of work calculation failed.") @@ -308,4 +308,26 @@ object MessageSender { val destination = Destination.from(address) return send(message, destination) } + + // Closed groups + fun createClosedGroup(name: String, members: Collection): Promise { + return create(name, members) + } + + fun explicitNameChange(groupPublicKey: String, newName: String) { + return setName(groupPublicKey, newName) + } + + fun explicitAddMembers(groupPublicKey: String, membersToAdd: List) { + return addMembers(groupPublicKey, membersToAdd) + } + + fun explicitRemoveMembers(groupPublicKey: String, membersToRemove: List) { + return removeMembers(groupPublicKey, membersToRemove) + } + + @JvmStatic + fun explicitLeave(groupPublicKey: String): Promise { + return leave(groupPublicKey) + } } \ No newline at end of file diff --git a/libsession/src/main/java/org/session/libsession/messaging/sending_receiving/MessageSenderClosedGroup.kt b/libsession/src/main/java/org/session/libsession/messaging/sending_receiving/MessageSenderClosedGroup.kt index 8299eb73c7..05353cd896 100644 --- a/libsession/src/main/java/org/session/libsession/messaging/sending_receiving/MessageSenderClosedGroup.kt +++ b/libsession/src/main/java/org/session/libsession/messaging/sending_receiving/MessageSenderClosedGroup.kt @@ -11,7 +11,9 @@ import org.session.libsession.messaging.messages.control.ClosedGroupControlMessa import org.session.libsession.messaging.sending_receiving.notifications.PushNotificationAPI import org.session.libsession.messaging.sending_receiving.MessageSender.Error import org.session.libsession.messaging.threads.Address +import org.session.libsession.messaging.threads.recipients.Recipient import org.session.libsession.utilities.GroupUtil +import org.session.libsession.utilities.TextSecurePreferences import org.session.libsignal.utilities.Hex import org.session.libsignal.libsignal.ecc.Curve @@ -27,7 +29,7 @@ import java.util.concurrent.ConcurrentHashMap private val pendingKeyPair = ConcurrentHashMap>() -fun MessageSender.createClosedGroup(name: String, members: Collection): Promise { +fun MessageSender.create(name: String, members: Collection): Promise { val deferred = deferred() ThreadUtils.queue { // Prepare @@ -68,7 +70,7 @@ fun MessageSender.createClosedGroup(name: String, members: Collection): return deferred.promise } -fun MessageSender.v2_update(groupPublicKey: String, members: List, name: String) { +fun MessageSender.update(groupPublicKey: String, members: List, name: String) { val context = MessagingConfiguration.shared.context val storage = MessagingConfiguration.shared.storage val groupID = GroupUtil.doubleEncodeGroupID(groupPublicKey) @@ -185,28 +187,33 @@ fun MessageSender.removeMembers(groupPublicKey: String, membersToRemove: List { + val deferred = deferred() + ThreadUtils.queue { + val context = MessagingConfiguration.shared.context + val storage = MessagingConfiguration.shared.storage + val userPublicKey = TextSecurePreferences.getLocalNumber(context)!! + val groupID = GroupUtil.doubleEncodeGroupID(groupPublicKey) + val group = storage.getGroup(groupID) ?: return@queue deferred.reject(Error.NoThread) + val updatedMembers = group.members.map { it.serialize() }.toSet() - userPublicKey + val admins = group.admins.map { it.serialize() } + val name = group.title + // Send the update to the group + val closedGroupControlMessage = ClosedGroupControlMessage(ClosedGroupControlMessage.Kind.MemberLeft) + closedGroupControlMessage.sentTimestamp = System.currentTimeMillis() + sendNonDurably(closedGroupControlMessage, Address.fromSerialized(groupID)).success { + // Notify the user + val infoType = SignalServiceProtos.GroupContext.Type.QUIT + val threadID = storage.getOrCreateThreadIdFor(Address.fromSerialized(groupID)) + if (notifyUser) { + storage.insertOutgoingInfoMessage(context, groupID, infoType, name, updatedMembers, admins, threadID) + } + // Remove the group private key and unsubscribe from PNs + MessageReceiver.disableLocalGroupAndUnsubscribe(groupPublicKey, groupID, userPublicKey) + deferred.resolve(Unit) + } } - // Notify the user - val infoType = SignalServiceProtos.GroupContext.Type.QUIT - val threadID = storage.getOrCreateThreadIdFor(Address.fromSerialized(groupID)) - storage.insertOutgoingInfoMessage(context, groupID, infoType, name, updatedMembers, admins, threadID) + return deferred.promise } fun MessageSender.generateAndSendNewEncryptionKeyPair(groupPublicKey: String, targetMembers: Collection) {