Making sure restored accounts do not display deleted messages

When getting messages we check if the contact was marked as hidden and compare the timestamps of both the message and the config object to check whether to re-show the thread or not.
This commit is contained in:
ThomasSession 2024-10-14 10:42:10 +11:00
parent 2945a9231b
commit bf6157997a
4 changed files with 46 additions and 6 deletions

View File

@ -196,6 +196,18 @@ class ConfigFactory(
} }
} }
override fun getConfigTimestamp(forConfigObject: ConfigBase, publicKey: String): Long {
val variant = when (forConfigObject) {
is UserProfile -> SharedConfigMessage.Kind.USER_PROFILE.name
is Contacts -> SharedConfigMessage.Kind.CONTACTS.name
is ConversationVolatileConfig -> SharedConfigMessage.Kind.CONVO_INFO_VOLATILE.name
is UserGroupsConfig -> SharedConfigMessage.Kind.GROUPS.name
else -> throw UnsupportedOperationException("Can't support type of ${forConfigObject::class.simpleName} yet")
}
return configDatabase.retrieveConfigLastUpdateTimestamp(variant, publicKey)
}
override fun conversationInConfig( override fun conversationInConfig(
publicKey: String?, publicKey: String?,
groupPublicKey: String?, groupPublicKey: String?,

View File

@ -5,10 +5,12 @@ import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.async import kotlinx.coroutines.async
import kotlinx.coroutines.awaitAll import kotlinx.coroutines.awaitAll
import kotlinx.coroutines.runBlocking import kotlinx.coroutines.runBlocking
import network.loki.messenger.libsession_util.ConfigBase
import nl.komponents.kovenant.Promise import nl.komponents.kovenant.Promise
import nl.komponents.kovenant.task import nl.komponents.kovenant.task
import org.session.libsession.messaging.MessagingModuleConfiguration import org.session.libsession.messaging.MessagingModuleConfiguration
import org.session.libsession.messaging.messages.Message import org.session.libsession.messaging.messages.Message
import org.session.libsession.messaging.messages.Message.Companion.senderOrSync
import org.session.libsession.messaging.messages.control.CallMessage import org.session.libsession.messaging.messages.control.CallMessage
import org.session.libsession.messaging.messages.control.ClosedGroupControlMessage import org.session.libsession.messaging.messages.control.ClosedGroupControlMessage
import org.session.libsession.messaging.messages.control.ConfigurationMessage import org.session.libsession.messaging.messages.control.ConfigurationMessage
@ -96,6 +98,26 @@ class BatchMessageReceiveJob(
executeAsync(dispatcherName).get() executeAsync(dispatcherName).get()
} }
private fun isHidden(message: Message): Boolean{
// if the contact is marked as hidden for 1on1 messages
// and the message's sentTimestamp is earlier than the sentTimestamp of the last config
val config = MessagingModuleConfiguration.shared.configFactory
val publicKey = MessagingModuleConfiguration.shared.storage.getUserPublicKey()
if(config.contacts == null || message.sentTimestamp == null || publicKey == null) return false
val contactConfigTimestamp = config.getConfigTimestamp(config.contacts!!, publicKey)
if(message.groupPublicKey == null && // not a group
message.openGroupServerMessageID == null && // not a community
// not marked as hidden
config.contacts?.get(message.senderOrSync)?.priority == ConfigBase.PRIORITY_HIDDEN &&
// the message's sentTimestamp is earlier than the sentTimestamp of the last config
message.sentTimestamp!! < contactConfigTimestamp
) {
return true
}
return false
}
fun executeAsync(dispatcherName: String): Promise<Unit, Exception> { fun executeAsync(dispatcherName: String): Promise<Unit, Exception> {
return task { return task {
val threadMap = mutableMapOf<Long, MutableList<ParsedMessage>>() val threadMap = mutableMapOf<Long, MutableList<ParsedMessage>>()
@ -112,6 +134,9 @@ class BatchMessageReceiveJob(
val (message, proto) = MessageReceiver.parse(data, openGroupMessageServerID, openGroupPublicKey = serverPublicKey, currentClosedGroups = currentClosedGroups) val (message, proto) = MessageReceiver.parse(data, openGroupMessageServerID, openGroupPublicKey = serverPublicKey, currentClosedGroups = currentClosedGroups)
message.serverHash = serverHash message.serverHash = serverHash
val parsedParams = ParsedMessage(messageParameters, message, proto) val parsedParams = ParsedMessage(messageParameters, message, proto)
if(isHidden(message)) return@forEach
val threadID = Message.getThreadId(message, openGroupID, storage, shouldCreateThread(parsedParams)) ?: NO_THREAD_MAPPING val threadID = Message.getThreadId(message, openGroupID, storage, shouldCreateThread(parsedParams)) ?: NO_THREAD_MAPPING
if (!threadMap.containsKey(threadID)) { if (!threadMap.containsKey(threadID)) {
threadMap[threadID] = mutableListOf(parsedParams) threadMap[threadID] = mutableListOf(parsedParams)

View File

@ -33,12 +33,13 @@ abstract class Message {
companion object { companion object {
fun getThreadId(message: Message, openGroupID: String?, storage: StorageProtocol, shouldCreateThread: Boolean): Long? { fun getThreadId(message: Message, openGroupID: String?, storage: StorageProtocol, shouldCreateThread: Boolean): Long? {
val senderOrSync = when (message) { return storage.getThreadIdFor(message.senderOrSync, message.groupPublicKey, openGroupID, createThread = shouldCreateThread)
is VisibleMessage -> message.syncTarget ?: message.sender!!
is ExpirationTimerUpdate -> message.syncTarget ?: message.sender!!
else -> message.sender!!
} }
return storage.getThreadIdFor(senderOrSync, message.groupPublicKey, openGroupID, createThread = shouldCreateThread)
val Message.senderOrSync get() = when(this) {
is VisibleMessage -> syncTarget ?: sender!!
is ExpirationTimerUpdate -> syncTarget ?: sender!!
else -> sender!!
} }
} }

View File

@ -16,6 +16,8 @@ interface ConfigFactoryProtocol {
fun conversationInConfig(publicKey: String?, groupPublicKey: String?, openGroupId: String?, visibleOnly: Boolean): Boolean fun conversationInConfig(publicKey: String?, groupPublicKey: String?, openGroupId: String?, visibleOnly: Boolean): Boolean
fun canPerformChange(variant: String, publicKey: String, changeTimestampMs: Long): Boolean fun canPerformChange(variant: String, publicKey: String, changeTimestampMs: Long): Boolean
fun getConfigTimestamp(forConfigObject: ConfigBase, publicKey: String): Long
} }
interface ConfigFactoryUpdateListener { interface ConfigFactoryUpdateListener {