diff --git a/app/src/main/java/org/thoughtcrime/securesms/dependencies/ConfigFactory.kt b/app/src/main/java/org/thoughtcrime/securesms/dependencies/ConfigFactory.kt index cd143d488f..ddfe902db5 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/dependencies/ConfigFactory.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/dependencies/ConfigFactory.kt @@ -48,6 +48,7 @@ import org.session.libsignal.crypto.ecc.DjbECPublicKey import org.session.libsignal.utilities.AccountId import org.session.libsignal.utilities.Hex import org.session.libsignal.utilities.IdPrefix +import org.session.libsignal.utilities.Log import org.session.libsignal.utilities.toHexString import org.thoughtcrime.securesms.configs.ConfigToDatabaseSync import org.thoughtcrime.securesms.database.ConfigDatabase @@ -275,10 +276,11 @@ class ConfigFactory @Inject constructor( override fun withMutableGroupConfigs( groupId: AccountId, + forceChangeNotification: Boolean, cb: (MutableGroupConfigs) -> T ): T { return doWithMutableGroupConfigs(groupId = groupId) { - cb(it) to it.dumpIfNeeded(clock) + cb(it) to (it.dumpIfNeeded(clock) || forceChangeNotification) } } @@ -323,14 +325,30 @@ class ConfigFactory @Inject constructor( val changed = doWithMutableGroupConfigs(groupId) { configs -> // Keys must be loaded first as they are used to decrypt the other config messages val keysLoaded = keys.fold(false) { acc, msg -> - configs.groupKeys.loadKey(msg.data, msg.hash, msg.timestamp, configs.groupInfo.pointer, configs.groupMembers.pointer) || acc + val loaded = runCatching { + configs.groupKeys.loadKey(msg.data, msg.hash, msg.timestamp) + }.onFailure { e -> + Log.w("ConfigFactory", "Failed to load group key for $groupId", e) + }.getOrDefault(false) + + loaded || acc } val infoMerged = info.isNotEmpty() && - configs.groupInfo.merge(info.map { it.hash to it.data }.toTypedArray()).isNotEmpty() + runCatching { + configs.groupInfo.merge(info.map { it.hash to it.data }.toTypedArray()).isNotEmpty() + }.onFailure { e -> + Log.w("ConfigFactory", "Failed to merge group info for $groupId", e) + }.getOrDefault(false) + val membersMerged = members.isNotEmpty() && - configs.groupMembers.merge(members.map { it.hash to it.data }.toTypedArray()).isNotEmpty() + runCatching { + configs.groupMembers.merge(members.map { it.hash to it.data }.toTypedArray()).isNotEmpty() + }.onFailure { e -> + Log.w("ConfigFactory", "Failed to merge group members for $groupId", e) + }.getOrDefault(false) + configs.dumpIfNeeded(clock) @@ -396,7 +414,7 @@ class ConfigFactory @Inject constructor( keysPush?.let { (hash, timestamp) -> val pendingConfig = configs.groupKeys.pendingConfig() if (pendingConfig != null) { - configs.groupKeys.loadKey(pendingConfig, hash, timestamp, configs.groupInfo.pointer, configs.groupMembers.pointer) + configs.groupKeys.loadKey(pendingConfig, hash, timestamp) } } diff --git a/app/src/main/java/org/thoughtcrime/securesms/groups/GroupManagerV2Impl.kt b/app/src/main/java/org/thoughtcrime/securesms/groups/GroupManagerV2Impl.kt index dc1ea686f5..6f2741a764 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/groups/GroupManagerV2Impl.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/groups/GroupManagerV2Impl.kt @@ -782,7 +782,8 @@ class GroupManagerV2Impl @Inject constructor( // Update our promote state configFactory.withMutableGroupConfigs( - groupId = groupId + groupId = groupId, + forceChangeNotification = true, ) { configs -> configs.groupKeys.loadAdminKey(adminKey) diff --git a/libsession-util/src/main/java/network/loki/messenger/libsession_util/Config.kt b/libsession-util/src/main/java/network/loki/messenger/libsession_util/Config.kt index fb2404ca20..3ec44fa524 100644 --- a/libsession-util/src/main/java/network/loki/messenger/libsession_util/Config.kt +++ b/libsession-util/src/main/java/network/loki/messenger/libsession_util/Config.kt @@ -508,7 +508,7 @@ class GroupKeysConfig private constructor( external override fun groupKeys(): Stack external override fun needsDump(): Boolean external override fun dump(): ByteArray - external fun loadKey(message: ByteArray, + private external fun loadKey(message: ByteArray, hash: String, timestampMs: Long, infoPtr: Long, diff --git a/libsession/src/main/java/org/session/libsession/utilities/ConfigFactoryProtocol.kt b/libsession/src/main/java/org/session/libsession/utilities/ConfigFactoryProtocol.kt index f14e1695f9..4798afbd1d 100644 --- a/libsession/src/main/java/org/session/libsession/utilities/ConfigFactoryProtocol.kt +++ b/libsession/src/main/java/org/session/libsession/utilities/ConfigFactoryProtocol.kt @@ -52,9 +52,12 @@ interface ConfigFactoryProtocol { fun saveGroupConfigs(groupId: AccountId, groupConfigs: MutableGroupConfigs) /** - * @param recreateConfigInstances If true, the group configs will be recreated before calling the callback. This is useful when you have received an admin key or otherwise. + * @param forceChangeNotification If true, the group configs will be marked as changed even if no changes were made. + * Normally this is not needed, as in most cases the underlying config system will be able to work out + * something has changed, but in some very rare cases it might not be able to, and in those cases you + * will need to force a change notification so that other parts of the app can react to the change. */ - fun withMutableGroupConfigs(groupId: AccountId, cb: (MutableGroupConfigs) -> T): T + fun withMutableGroupConfigs(groupId: AccountId, forceChangeNotification: Boolean = false, cb: (MutableGroupConfigs) -> T): T fun conversationInConfig(publicKey: String?, groupPublicKey: String?, openGroupId: String?, visibleOnly: Boolean): Boolean fun canPerformChange(variant: String, publicKey: String, changeTimestampMs: Long): Boolean