mirror of
https://github.com/oxen-io/session-android.git
synced 2024-11-28 20:45:17 +00:00
feat: add almost all group editing cases, need to hook into the thread deletion for groups in the user groups
This commit is contained in:
parent
eca5712282
commit
c28fe290df
@ -7,10 +7,7 @@ import network.loki.messenger.libsession_util.Contacts
|
||||
import network.loki.messenger.libsession_util.ConversationVolatileConfig
|
||||
import network.loki.messenger.libsession_util.UserGroupsConfig
|
||||
import network.loki.messenger.libsession_util.UserProfile
|
||||
import network.loki.messenger.libsession_util.util.BaseCommunityInfo
|
||||
import network.loki.messenger.libsession_util.util.Conversation
|
||||
import network.loki.messenger.libsession_util.util.ExpiryMode
|
||||
import network.loki.messenger.libsession_util.util.UserPic
|
||||
import network.loki.messenger.libsession_util.util.*
|
||||
import org.session.libsession.avatars.AvatarHelper
|
||||
import org.session.libsession.database.StorageProtocol
|
||||
import org.session.libsession.messaging.BlindedIdMapping
|
||||
@ -468,6 +465,7 @@ class Storage(context: Context, helper: SQLCipherOpenHelper, private val configF
|
||||
// Notify the user
|
||||
val threadID = getOrCreateThreadIdFor(Address.fromSerialized(groupId))
|
||||
insertOutgoingInfoMessage(context, groupId, SignalServiceGroup.Type.CREATION, title, members.map { it.serialize() }, admins.map { it.serialize() }, threadID, formationTimestamp)
|
||||
// Don't create config group here, it's from a config update
|
||||
// Start polling
|
||||
ClosedGroupPollerV2.shared.startPolling(group.sessionId)
|
||||
}
|
||||
@ -671,14 +669,55 @@ class Storage(context: Context, helper: SQLCipherOpenHelper, private val configF
|
||||
|
||||
override fun createGroup(groupId: String, title: String?, members: List<Address>, avatar: SignalServiceAttachmentPointer?, relay: String?, admins: List<Address>, formationTimestamp: Long) {
|
||||
DatabaseComponent.get(context).groupDatabase().create(groupId, title, members, avatar, relay, admins, formationTimestamp)
|
||||
}
|
||||
|
||||
override fun createInitialConfigGroup(groupPublicKey: String, name: String, members: Map<String, Boolean>, formationTimestamp: Long, encryptionKeyPair: ECKeyPair) {
|
||||
val volatiles = configFactory.convoVolatile ?: return
|
||||
val groupPublicKey = GroupUtil.doubleDecodeGroupId(groupId)
|
||||
val userGroups = configFactory.userGroups ?: return
|
||||
val groupVolatileConfig = volatiles.getOrConstructLegacyGroup(groupPublicKey)
|
||||
groupVolatileConfig.lastRead = formationTimestamp
|
||||
volatiles.set(groupVolatileConfig)
|
||||
val groupInfo = GroupInfo.LegacyGroupInfo(
|
||||
sessionId = groupPublicKey,
|
||||
name = name,
|
||||
members = members,
|
||||
hidden = false,
|
||||
encPubKey = encryptionKeyPair.publicKey.serialize(),
|
||||
encSecKey = encryptionKeyPair.privateKey.serialize(),
|
||||
disappearingTimer = 0L
|
||||
)
|
||||
// shouldn't exist, don't use getOrConstruct + copy
|
||||
userGroups.set(groupInfo)
|
||||
ConfigurationMessageUtilities.forceSyncConfigurationNowIfNeeded(context)
|
||||
}
|
||||
|
||||
override fun updateGroupConfig(groupPublicKey: String) {
|
||||
val groupID = GroupUtil.doubleEncodeGroupID(groupPublicKey)
|
||||
val groupAddress = fromSerialized(groupID)
|
||||
// TODO: probably add a check in here for isActive?
|
||||
// TODO: also check if local user is a member / maybe run delete otherwise?
|
||||
val existingGroup = getGroup(groupID)
|
||||
?: return Log.w("Loki-DBG", "No existing group for ${groupPublicKey.take(4)}...${groupPublicKey.takeLast(4)} when updating group config")
|
||||
val userGroups = configFactory.userGroups ?: return
|
||||
val name = existingGroup.title
|
||||
val admins = existingGroup.admins.map { it.serialize() }
|
||||
val members = existingGroup.members.map { it.serialize() }
|
||||
val membersMap = GroupUtil.createConfigMemberMap(admins = admins, members = members)
|
||||
val latestKeyPair = getLatestClosedGroupEncryptionKeyPair(groupPublicKey)
|
||||
?: return Log.w("Loki-DBG", "No latest closed group encryption key pair for ${groupPublicKey.take(4)}...${groupPublicKey.takeLast(4)} when updating group config")
|
||||
val recipientSettings = getRecipientSettings(groupAddress) ?: return
|
||||
val threadID = getThreadId(groupAddress) ?: return
|
||||
val groupInfo = userGroups.getOrConstructLegacyGroupInfo(groupPublicKey).copy(
|
||||
name = name,
|
||||
members = membersMap,
|
||||
encPubKey = latestKeyPair.publicKey.serialize(),
|
||||
encSecKey = latestKeyPair.privateKey.serialize(),
|
||||
priority = if (isPinned(threadID)) 1 else 0,
|
||||
disappearingTimer = recipientSettings.expireMessages.toLong()
|
||||
)
|
||||
userGroups.set(groupInfo)
|
||||
}
|
||||
|
||||
override fun isGroupActive(groupPublicKey: String): Boolean {
|
||||
return DatabaseComponent.get(context).groupDatabase().getGroup(GroupUtil.doubleEncodeGroupID(groupPublicKey)).orNull()?.isActive == true
|
||||
}
|
||||
|
@ -1,11 +1,17 @@
|
||||
package org.thoughtcrime.securesms.groups
|
||||
|
||||
import android.content.Context
|
||||
import network.loki.messenger.libsession_util.util.GroupInfo
|
||||
import org.session.libsession.messaging.MessagingModuleConfiguration
|
||||
import org.session.libsession.messaging.sending_receiving.notifications.PushNotificationAPI
|
||||
import org.session.libsession.messaging.sending_receiving.pollers.ClosedGroupPollerV2
|
||||
import org.session.libsession.utilities.Address
|
||||
import org.session.libsession.utilities.GroupRecord
|
||||
import org.session.libsession.utilities.GroupUtil
|
||||
import org.session.libsession.utilities.recipients.Recipient
|
||||
import org.session.libsignal.utilities.toHexString
|
||||
import org.thoughtcrime.securesms.ApplicationContext
|
||||
import org.thoughtcrime.securesms.dependencies.ConfigFactory
|
||||
|
||||
object ClosedGroupManager {
|
||||
|
||||
@ -28,4 +34,31 @@ object ClosedGroupManager {
|
||||
}
|
||||
}
|
||||
|
||||
fun ConfigFactory.removeLegacyGroup(group: GroupRecord): Boolean {
|
||||
val groups = userGroups ?: return false
|
||||
if (!group.isClosedGroup) return false
|
||||
val groupPublicKey = GroupUtil.doubleEncodeGroupID(group.getId())
|
||||
return groups.eraseLegacyGroup(groupPublicKey)
|
||||
}
|
||||
|
||||
fun ConfigFactory.updateLegacyGroup(groupRecipientSettings: Recipient.RecipientSettings, group: GroupRecord) {
|
||||
val groups = userGroups ?: return
|
||||
if (!group.isClosedGroup) return
|
||||
val storage = MessagingModuleConfiguration.shared.storage
|
||||
val threadId = storage.getThreadId(group.encodedId) ?: return
|
||||
val groupPublicKey = GroupUtil.doubleEncodeGroupID(group.getId())
|
||||
val latestKeyPair = storage.getLatestClosedGroupEncryptionKeyPair(groupPublicKey) ?: return
|
||||
val legacyInfo = groups.getOrConstructLegacyGroupInfo(groupPublicKey)
|
||||
val latestMemberMap = GroupUtil.createConfigMemberMap(group.members.map(Address::serialize), group.admins.map(Address::serialize))
|
||||
val toSet = legacyInfo.copy(
|
||||
members = latestMemberMap,
|
||||
name = group.title,
|
||||
disappearingTimer = groupRecipientSettings.expireMessages.toLong(),
|
||||
priority = if (storage.isPinned(threadId)) 1 else 0,
|
||||
encSecKey = latestKeyPair.privateKey.serialize(),
|
||||
encPubKey = latestKeyPair.publicKey.serialize()
|
||||
)
|
||||
groups.set(toSet)
|
||||
}
|
||||
|
||||
}
|
@ -16,6 +16,7 @@ import androidx.loader.app.LoaderManager
|
||||
import androidx.loader.content.Loader
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import dagger.hilt.android.AndroidEntryPoint
|
||||
import network.loki.messenger.R
|
||||
import nl.komponents.kovenant.Promise
|
||||
import nl.komponents.kovenant.task
|
||||
@ -28,16 +29,28 @@ import org.session.libsession.utilities.GroupUtil
|
||||
import org.session.libsession.utilities.TextSecurePreferences
|
||||
import org.session.libsession.utilities.ThemeUtil
|
||||
import org.session.libsession.utilities.recipients.Recipient
|
||||
import org.session.libsignal.utilities.Log
|
||||
import org.session.libsignal.utilities.toHexString
|
||||
import org.thoughtcrime.securesms.PassphraseRequiredActionBarActivity
|
||||
import org.thoughtcrime.securesms.contacts.SelectContactsActivity
|
||||
import org.thoughtcrime.securesms.database.Storage
|
||||
import org.thoughtcrime.securesms.dependencies.ConfigFactory
|
||||
import org.thoughtcrime.securesms.dependencies.DatabaseComponent
|
||||
import org.thoughtcrime.securesms.groups.ClosedGroupManager.updateLegacyGroup
|
||||
import org.thoughtcrime.securesms.mms.GlideApp
|
||||
import org.thoughtcrime.securesms.util.fadeIn
|
||||
import org.thoughtcrime.securesms.util.fadeOut
|
||||
import java.io.IOException
|
||||
import javax.inject.Inject
|
||||
|
||||
@AndroidEntryPoint
|
||||
class EditClosedGroupActivity : PassphraseRequiredActionBarActivity() {
|
||||
|
||||
@Inject
|
||||
lateinit var groupConfigFactory: ConfigFactory
|
||||
@Inject
|
||||
lateinit var storage: Storage
|
||||
|
||||
private val originalMembers = HashSet<String>()
|
||||
private val zombies = HashSet<String>()
|
||||
private val members = HashSet<String>()
|
||||
@ -306,6 +319,7 @@ class EditClosedGroupActivity : PassphraseRequiredActionBarActivity() {
|
||||
promise.successUi {
|
||||
loaderContainer.fadeOut()
|
||||
isLoading = false
|
||||
updateGroupConfig()
|
||||
finish()
|
||||
}.failUi { exception ->
|
||||
val message = if (exception is MessageSender.Error) exception.description else "An error occurred"
|
||||
@ -316,5 +330,13 @@ class EditClosedGroupActivity : PassphraseRequiredActionBarActivity() {
|
||||
}
|
||||
}
|
||||
|
||||
class GroupMembers(val members: List<String>, val zombieMembers: List<String>) { }
|
||||
private fun updateGroupConfig() {
|
||||
val latestRecipient = storage.getRecipientSettings(Address.fromSerialized(groupID))
|
||||
?: return Log.w("Loki", "No recipient settings when trying to update group config")
|
||||
val latestGroup = storage.getGroup(groupID)
|
||||
?: return Log.w("Loki", "No group record when trying to update group config")
|
||||
groupConfigFactory.updateLegacyGroup(latestRecipient, latestGroup)
|
||||
}
|
||||
|
||||
class GroupMembers(val members: List<String>, val zombieMembers: List<String>)
|
||||
}
|
@ -6,6 +6,7 @@ import android.graphics.Bitmap;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import org.session.libsession.messaging.MessagingModuleConfiguration;
|
||||
import org.session.libsession.utilities.Address;
|
||||
import org.session.libsession.utilities.DistributionTypes;
|
||||
import org.session.libsession.utilities.GroupUtil;
|
||||
@ -16,11 +17,14 @@ import org.thoughtcrime.securesms.database.ThreadDatabase;
|
||||
import org.thoughtcrime.securesms.dependencies.DatabaseComponent;
|
||||
import org.thoughtcrime.securesms.util.BitmapUtil;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedList;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
|
||||
import network.loki.messenger.libsession_util.UserGroupsConfig;
|
||||
|
||||
public class GroupManager {
|
||||
|
||||
public static long getOpenGroupThreadID(String id, @NonNull Context context) {
|
||||
|
@ -625,7 +625,7 @@ class HomeActivity : PassphraseRequiredActionBarActivity(),
|
||||
OpenGroupManager.delete(v2OpenGroup.server, v2OpenGroup.room, this@HomeActivity)
|
||||
} else {
|
||||
lifecycleScope.launch(Dispatchers.IO) {
|
||||
threadDb.deleteConversation(threadID)
|
||||
storage.deleteConversation(threadID)
|
||||
}
|
||||
}
|
||||
// Update the badge count
|
||||
|
@ -257,13 +257,13 @@ class DefaultConversationRepository @Inject constructor(
|
||||
|
||||
override suspend fun deleteThread(threadId: Long): ResultOf<Unit> {
|
||||
sessionJobDb.cancelPendingMessageSendJobs(threadId)
|
||||
threadDb.deleteConversation(threadId)
|
||||
storage.deleteConversation(threadId)
|
||||
return ResultOf.Success(Unit)
|
||||
}
|
||||
|
||||
override suspend fun deleteMessageRequest(thread: ThreadRecord): ResultOf<Unit> {
|
||||
sessionJobDb.cancelPendingMessageSendJobs(thread.threadId)
|
||||
threadDb.deleteConversation(thread.threadId)
|
||||
storage.deleteConversation(thread.threadId)
|
||||
return ResultOf.Success(Unit)
|
||||
}
|
||||
|
||||
@ -290,7 +290,7 @@ class DefaultConversationRepository @Inject constructor(
|
||||
|
||||
override fun declineMessageRequest(threadId: Long) {
|
||||
sessionJobDb.cancelPendingMessageSendJobs(threadId)
|
||||
threadDb.deleteConversation(threadId)
|
||||
storage.deleteConversation(threadId)
|
||||
}
|
||||
|
||||
override fun hasReceived(threadId: Long): Boolean {
|
||||
|
@ -6,11 +6,7 @@ import network.loki.messenger.libsession_util.Contacts
|
||||
import network.loki.messenger.libsession_util.ConversationVolatileConfig
|
||||
import network.loki.messenger.libsession_util.UserGroupsConfig
|
||||
import network.loki.messenger.libsession_util.UserProfile
|
||||
import network.loki.messenger.libsession_util.util.BaseCommunityInfo
|
||||
import network.loki.messenger.libsession_util.util.Contact
|
||||
import network.loki.messenger.libsession_util.util.Conversation
|
||||
import network.loki.messenger.libsession_util.util.GroupInfo
|
||||
import network.loki.messenger.libsession_util.util.UserPic
|
||||
import network.loki.messenger.libsession_util.util.*
|
||||
import nl.komponents.kovenant.Promise
|
||||
import org.session.libsession.messaging.MessagingModuleConfiguration
|
||||
import org.session.libsession.messaging.jobs.ConfigurationSyncJob
|
||||
@ -21,6 +17,7 @@ import org.session.libsession.messaging.sending_receiving.MessageSender
|
||||
import org.session.libsession.messaging.utilities.SessionId
|
||||
import org.session.libsession.utilities.Address
|
||||
import org.session.libsession.utilities.GroupUtil
|
||||
import org.session.libsession.utilities.SSKEnvironment
|
||||
import org.session.libsession.utilities.TextSecurePreferences
|
||||
import org.session.libsignal.utilities.Hex
|
||||
import org.session.libsignal.utilities.Log
|
||||
@ -163,7 +160,8 @@ object ConfigurationMessageUtilities {
|
||||
approved = settings.isApproved,
|
||||
approvedMe = settings.hasApprovedMe(),
|
||||
profilePicture = userPic ?: UserPic.DEFAULT,
|
||||
priority = if (isPinned) 1 else 0
|
||||
priority = if (isPinned) 1 else 0,
|
||||
expiryMode = if (settings.expireMessages == 0) ExpiryMode.NONE else ExpiryMode.AfterRead(settings.expireMessages.toLong())
|
||||
)
|
||||
contactConfig.set(contactInfo)
|
||||
}
|
||||
@ -185,7 +183,7 @@ object ConfigurationMessageUtilities {
|
||||
val contact = when {
|
||||
recipient.isOpenGroupRecipient -> {
|
||||
val openGroup = storage.getOpenGroup(current.threadId) ?: continue
|
||||
val (base, room, pubKey) = Conversation.Community.parseFullUrl(openGroup.joinURL) ?: continue
|
||||
val (base, room, pubKey) = BaseCommunityInfo.parseFullUrl(openGroup.joinURL) ?: continue
|
||||
convoConfig.getOrConstructCommunity(base, room, pubKey)
|
||||
}
|
||||
recipient.isClosedGroupRecipient -> {
|
||||
@ -229,7 +227,9 @@ object ConfigurationMessageUtilities {
|
||||
}
|
||||
|
||||
val allLgc = storage.getAllGroups().filter { it.isClosedGroup }.mapNotNull { group ->
|
||||
val groupPublicKey = GroupUtil.doubleDecodeGroupID(group.encodedId).toHexString()
|
||||
val groupAddress = Address.fromSerialized(group.encodedId)
|
||||
val groupPublicKey = GroupUtil.doubleDecodeGroupID(groupAddress.serialize()).toHexString()
|
||||
val recipient = storage.getRecipientSettings(groupAddress) ?: return@mapNotNull null
|
||||
val encryptionKeyPair = storage.getLatestClosedGroupEncryptionKeyPair(groupPublicKey) ?: return@mapNotNull null
|
||||
val threadId = storage.getThreadId(group.encodedId)
|
||||
val isPinned = threadId?.let { storage.isPinned(threadId) } ?: false
|
||||
@ -243,7 +243,8 @@ object ConfigurationMessageUtilities {
|
||||
hidden = threadId == null,
|
||||
priority = if (isPinned) 1 else 0,
|
||||
encPubKey = encryptionKeyPair.publicKey.serialize(),
|
||||
encSecKey = encryptionKeyPair.privateKey.serialize()
|
||||
encSecKey = encryptionKeyPair.privateKey.serialize(),
|
||||
disappearingTimer = recipient.expireMessages.toLong()
|
||||
)
|
||||
}
|
||||
(allOpenGroups + allLgc).forEach { groupInfo ->
|
||||
|
@ -233,6 +233,7 @@ object MockDataGenerator {
|
||||
val encryptionKeyPair = Curve.generateKeyPair()
|
||||
storage.addClosedGroupEncryptionKeyPair(encryptionKeyPair, randomGroupPublicKey, System.currentTimeMillis())
|
||||
storage.setExpirationTimer(groupId, 0)
|
||||
storage.createInitialConfigGroup(randomGroupPublicKey, groupName, GroupUtil.createConfigMemberMap(members, setOf(adminUserId)), System.currentTimeMillis(), encryptionKeyPair)
|
||||
|
||||
// Add the group created message
|
||||
if (userSessionId == adminUserId) {
|
||||
|
@ -233,3 +233,23 @@ Java_network_loki_messenger_libsession_1util_UserGroupsConfig_allLegacyGroupInfo
|
||||
jobject legacy_stack = iterator_as_java_stack(env, conf->begin_legacy_groups(), conf->end());
|
||||
return legacy_stack;
|
||||
}
|
||||
extern "C"
|
||||
JNIEXPORT jboolean JNICALL
|
||||
Java_network_loki_messenger_libsession_1util_UserGroupsConfig_eraseCommunity(JNIEnv *env,
|
||||
jobject thiz,
|
||||
jobject base_community_info) {
|
||||
auto conf = ptrToUserGroups(env, thiz);
|
||||
auto base_community = util::deserialize_base_community(env, base_community_info);
|
||||
return conf->erase_community(base_community.base_url(),base_community.room());
|
||||
}
|
||||
extern "C"
|
||||
JNIEXPORT jboolean JNICALL
|
||||
Java_network_loki_messenger_libsession_1util_UserGroupsConfig_eraseLegacyGroup(JNIEnv *env,
|
||||
jobject thiz,
|
||||
jstring session_id) {
|
||||
auto conf = ptrToUserGroups(env, thiz);
|
||||
auto session_id_bytes = env->GetStringUTFChars(session_id, nullptr);
|
||||
bool return_bool = conf->erase_legacy_group(session_id_bytes);
|
||||
env->ReleaseStringUTFChars(session_id, session_id_bytes);
|
||||
return return_bool;
|
||||
}
|
@ -1,10 +1,6 @@
|
||||
package network.loki.messenger.libsession_util
|
||||
|
||||
import network.loki.messenger.libsession_util.util.ConfigPush
|
||||
import network.loki.messenger.libsession_util.util.Contact
|
||||
import network.loki.messenger.libsession_util.util.Conversation
|
||||
import network.loki.messenger.libsession_util.util.GroupInfo
|
||||
import network.loki.messenger.libsession_util.util.UserPic
|
||||
import network.loki.messenger.libsession_util.util.*
|
||||
import org.session.libsignal.protos.SignalServiceProtos.SharedConfigMessage.Kind
|
||||
|
||||
|
||||
@ -160,6 +156,8 @@ class UserGroupsConfig(pointer: Long): ConfigBase(pointer) {
|
||||
external fun set(legacyGroupInfo: GroupInfo.LegacyGroupInfo)
|
||||
external fun erase(communityInfo: GroupInfo.CommunityGroupInfo)
|
||||
external fun erase(legacyGroupInfo: GroupInfo.LegacyGroupInfo)
|
||||
external fun eraseCommunity(baseCommunityInfo: BaseCommunityInfo): Boolean
|
||||
external fun eraseLegacyGroup(sessionId: String): Boolean
|
||||
external fun sizeCommunityInfo(): Int
|
||||
external fun sizeLegacyGroupInfo(): Int
|
||||
external fun size(): Int
|
||||
|
@ -121,6 +121,8 @@ interface StorageProtocol {
|
||||
// Closed Groups
|
||||
fun getGroup(groupID: String): GroupRecord?
|
||||
fun createGroup(groupID: String, title: String?, members: List<Address>, avatar: SignalServiceAttachmentPointer?, relay: String?, admins: List<Address>, formationTimestamp: Long)
|
||||
fun createInitialConfigGroup(groupPublicKey: String, name: String, members: Map<String, Boolean>, formationTimestamp: Long, encryptionKeyPair: ECKeyPair)
|
||||
fun updateGroupConfig(groupPublicKey: String)
|
||||
fun isGroupActive(groupPublicKey: String): Boolean
|
||||
fun setActive(groupID: String, value: Boolean)
|
||||
fun getZombieMembers(groupID: String): Set<String>
|
||||
|
@ -73,6 +73,7 @@ fun MessageSender.create(name: String, members: Collection<String>): Promise<Str
|
||||
// Notify the user
|
||||
val threadID = storage.getOrCreateThreadIdFor(Address.fromSerialized(groupID))
|
||||
storage.insertOutgoingInfoMessage(context, groupID, SignalServiceGroup.Type.CREATION, name, members, admins, threadID, sentTime)
|
||||
storage.createInitialConfigGroup(groupPublicKey, name, GroupUtil.createConfigMemberMap(members, admins), sentTime, encryptionKeyPair)
|
||||
// Notify the PN server
|
||||
PushNotificationAPI.performOperation(PushNotificationAPI.ClosedGroupOperation.Subscribe, groupPublicKey, userPublicKey)
|
||||
// Start polling
|
||||
@ -84,24 +85,6 @@ fun MessageSender.create(name: String, members: Collection<String>): Promise<Str
|
||||
return deferred.promise
|
||||
}
|
||||
|
||||
fun MessageSender.update(groupPublicKey: String, members: List<String>, name: String) {
|
||||
val context = MessagingModuleConfiguration.shared.context
|
||||
val storage = MessagingModuleConfiguration.shared.storage
|
||||
val groupID = GroupUtil.doubleEncodeGroupID(groupPublicKey)
|
||||
val group = storage.getGroup(groupID) ?: run {
|
||||
Log.d("Loki", "Can't update nonexistent closed group.")
|
||||
throw Error.NoThread
|
||||
}
|
||||
// Update name if needed
|
||||
if (name != group.title) { setName(groupPublicKey, name) }
|
||||
// Add members if needed
|
||||
val addedMembers = members - group.members.map { it.serialize() }
|
||||
if (!addedMembers.isEmpty()) { addMembers(groupPublicKey, addedMembers) }
|
||||
// Remove members if needed
|
||||
val removedMembers = group.members.map { it.serialize() } - members
|
||||
if (removedMembers.isEmpty()) { removeMembers(groupPublicKey, removedMembers) }
|
||||
}
|
||||
|
||||
fun MessageSender.setName(groupPublicKey: String, newName: String) {
|
||||
val context = MessagingModuleConfiguration.shared.context
|
||||
val storage = MessagingModuleConfiguration.shared.storage
|
||||
|
@ -437,8 +437,23 @@ private fun MessageReceiver.handleClosedGroupControlMessage(message: ClosedGroup
|
||||
is ClosedGroupControlMessage.Kind.MembersRemoved -> handleClosedGroupMembersRemoved(message)
|
||||
is ClosedGroupControlMessage.Kind.MemberLeft -> handleClosedGroupMemberLeft(message)
|
||||
}
|
||||
if (message.kind !is ClosedGroupControlMessage.Kind.New) {
|
||||
// update the config
|
||||
val closedGroupPublicKey = message.getPublicKey()
|
||||
val storage = MessagingModuleConfiguration.shared.storage
|
||||
storage.updateGroupConfig(closedGroupPublicKey)
|
||||
}
|
||||
}
|
||||
|
||||
private fun ClosedGroupControlMessage.getPublicKey(): String = kind!!.let { when (it) {
|
||||
is ClosedGroupControlMessage.Kind.New -> it.publicKey.toByteArray().toHexString()
|
||||
is ClosedGroupControlMessage.Kind.EncryptionKeyPair -> it.publicKey?.toByteArray()?.toHexString() ?: groupPublicKey!!
|
||||
is ClosedGroupControlMessage.Kind.MemberLeft -> groupPublicKey!!
|
||||
is ClosedGroupControlMessage.Kind.MembersAdded -> groupPublicKey!!
|
||||
is ClosedGroupControlMessage.Kind.MembersRemoved -> groupPublicKey!!
|
||||
is ClosedGroupControlMessage.Kind.NameChange -> groupPublicKey!!
|
||||
}}
|
||||
|
||||
private fun MessageReceiver.handleNewClosedGroup(message: ClosedGroupControlMessage) {
|
||||
val kind = message.kind!! as? ClosedGroupControlMessage.Kind.New ?: return
|
||||
val recipient = Recipient.from(MessagingModuleConfiguration.shared.context, Address.fromSerialized(message.sender!!), false)
|
||||
@ -476,6 +491,7 @@ private fun handleNewClosedGroup(sender: String, sentTimestamp: Long, groupPubli
|
||||
storage.addClosedGroupPublicKey(groupPublicKey)
|
||||
// Store the encryption key pair
|
||||
storage.addClosedGroupEncryptionKeyPair(encryptionKeyPair, groupPublicKey, sentTimestamp)
|
||||
storage.createInitialConfigGroup(groupPublicKey, name, GroupUtil.createConfigMemberMap(members, admins), formationTimestamp, encryptionKeyPair)
|
||||
// Set expiration timer
|
||||
storage.setExpirationTimer(groupID, expireTimer)
|
||||
// Notify the PN server
|
||||
|
@ -1,5 +1,6 @@
|
||||
package org.session.libsession.utilities
|
||||
|
||||
import network.loki.messenger.libsession_util.util.GroupInfo
|
||||
import org.session.libsignal.messages.SignalServiceGroup
|
||||
import org.session.libsignal.utilities.Hex
|
||||
import java.io.IOException
|
||||
@ -102,4 +103,22 @@ object GroupUtil {
|
||||
fun doubleDecodeGroupId(groupID: String): String {
|
||||
return Hex.toStringCondensed(getDecodedGroupIDAsData(getDecodedGroupID(groupID)))
|
||||
}
|
||||
|
||||
fun createConfigMemberMap(
|
||||
members: Collection<String>,
|
||||
admins: Collection<String>
|
||||
): Map<String, Boolean> {
|
||||
// Start with admins
|
||||
val memberMap = admins.associate {
|
||||
it to true
|
||||
}.toMutableMap()
|
||||
|
||||
// Add the remaining members (there may be duplicates, so only add ones that aren't already in there from admins)
|
||||
for (member in members) {
|
||||
if (!memberMap.contains(member)) {
|
||||
memberMap[member] = false
|
||||
}
|
||||
}
|
||||
return memberMap
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user