- Share only the first chunk of inbound sessions instead of the whole key history

- Download keys if the user is unknown (first invite)
This commit is contained in:
ariskotsomitopoulos 2022-04-27 12:10:21 +03:00 committed by Valere
parent e861edd544
commit b3bfd05ecb
4 changed files with 58 additions and 3 deletions

View file

@ -40,6 +40,7 @@ import org.matrix.android.sdk.api.session.crypto.verification.VerificationServic
import org.matrix.android.sdk.api.session.events.model.Content
import org.matrix.android.sdk.api.session.events.model.Event
import org.matrix.android.sdk.api.session.events.model.content.RoomKeyWithHeldContent
import org.matrix.android.sdk.internal.database.helper.SessionInfoPair
interface CryptoService {
@ -178,7 +179,12 @@ interface CryptoService {
fun prepareToEncrypt(roomId: String, callback: MatrixCallback<Unit>)
/**
* Share existing inbound sessions with the provided userId devices
* Share all existing inbound sessions to the provided userId devices
*/
fun sendSharedHistoryKeys(roomId: String, userId: String)
/**
* Share all inbound sessions of the last chunk messages to the provided userId devices
*/
fun sendSharedHistoryKeysToLastChunk(roomId: String, userId: String, sessionInfoSet: Set<SessionInfoPair>?)
}

View file

@ -92,6 +92,7 @@ import org.matrix.android.sdk.internal.crypto.tasks.SetDeviceNameTask
import org.matrix.android.sdk.internal.crypto.tasks.UploadKeysTask
import org.matrix.android.sdk.internal.crypto.verification.DefaultVerificationService
import org.matrix.android.sdk.internal.crypto.verification.VerificationMessageProcessor
import org.matrix.android.sdk.internal.database.helper.SessionInfoPair
import org.matrix.android.sdk.internal.di.DeviceId
import org.matrix.android.sdk.internal.di.MoshiProvider
import org.matrix.android.sdk.internal.di.UserId
@ -1337,6 +1338,34 @@ internal class DefaultCryptoService @Inject constructor(
}
}
override fun sendSharedHistoryKeysToLastChunk(roomId: String, userId: String, sessionInfoSet: Set<SessionInfoPair>?) {
cryptoCoroutineScope.launch(coroutineDispatchers.crypto) {
runCatching {
deviceListManager.downloadKeys(listOf(userId), false)
}.mapCatching {
val userDevices = cryptoStore.getUserDevices(userId)
userDevices?.forEach {
// Lets share the provided inbound sessions for every user device
val deviceId = it.key
sessionInfoSet?.mapNotNull { sessionInfoPair ->
// Get inbound session from sessionId and sessionKey
cryptoStore.getInboundGroupSession(sessionInfoPair.first, sessionInfoPair.second)
}?.filter { inboundGroupSession ->
// Filter only sessions with sharedHistory enabled
inboundGroupSession.sharedHistory
}?.forEach { inboundGroupSession ->
// Share the session to userId with deviceId
val exportedKeys = inboundGroupSession.exportKeys()
val algorithm = exportedKeys?.algorithm
val decryptor = roomDecryptorProvider.getRoomDecryptor(roomId, algorithm)
decryptor?.shareKeysWithDevice(exportedKeys, deviceId, userId)
Timber.i("## CRYPTO | Sharing inbound session")
}
}
}
}
}
override fun sendSharedHistoryKeys(roomId: String, userId: String) {
cryptoCoroutineScope.launch(coroutineDispatchers.crypto) {
val userDevices = cryptoStore.getUserDevices(userId)
@ -1347,7 +1376,7 @@ internal class DefaultCryptoService @Inject constructor(
inboundSessions.filter { inboundGroupSession ->
inboundGroupSession.sharedHistory
}.forEach { inboundGroupSession ->
// Share the session with the to userId with deviceId
// Share the session to userId with deviceId
val exportedKeys = inboundGroupSession.exportKeys()
val algorithm = exportedKeys?.algorithm
val decryptor = roomDecryptorProvider.getRoomDecryptor(roomId, algorithm)

View file

@ -18,7 +18,10 @@ package org.matrix.android.sdk.internal.database.helper
import io.realm.Realm
import io.realm.kotlin.createObject
import org.matrix.android.sdk.api.session.events.model.content.EncryptedEventContent
import org.matrix.android.sdk.api.session.events.model.toModel
import org.matrix.android.sdk.api.session.room.model.RoomMemberContent
import org.matrix.android.sdk.internal.database.mapper.asDomain
import org.matrix.android.sdk.internal.database.model.ChunkEntity
import org.matrix.android.sdk.internal.database.model.CurrentStateEventEntityFields
import org.matrix.android.sdk.internal.database.model.EventAnnotationsSummaryEntity
@ -31,6 +34,7 @@ import org.matrix.android.sdk.internal.database.model.RoomMemberSummaryEntityFie
import org.matrix.android.sdk.internal.database.model.TimelineEventEntity
import org.matrix.android.sdk.internal.database.model.TimelineEventEntityFields
import org.matrix.android.sdk.internal.database.query.find
import org.matrix.android.sdk.internal.database.query.findLastForwardChunkOfRoom
import org.matrix.android.sdk.internal.database.query.getOrCreate
import org.matrix.android.sdk.internal.database.query.where
import org.matrix.android.sdk.internal.session.room.timeline.PaginationDirection
@ -180,3 +184,14 @@ internal fun ChunkEntity.isMoreRecentThan(chunkToCheck: ChunkEntity): Boolean {
// We don't know, so we assume it's false
return false
}
internal fun ChunkEntity.Companion.findLatestSessionInfo(realm: Realm, roomId: String): Set<SessionInfoPair>? =
ChunkEntity.findLastForwardChunkOfRoom(realm, roomId)?.timelineEvents?.mapNotNull { timelineEvent ->
timelineEvent?.root?.asDomain()?.content?.toModel<EncryptedEventContent>()?.let { content ->
content.sessionId ?: return@mapNotNull null
content.senderKey ?: return@mapNotNull null
Pair(content.sessionId, content.senderKey)
}
}?.toSet()
internal typealias SessionInfoPair = Pair<String, String>

View file

@ -29,7 +29,9 @@ import org.matrix.android.sdk.api.session.room.members.MembershipService
import org.matrix.android.sdk.api.session.room.members.RoomMemberQueryParams
import org.matrix.android.sdk.api.session.room.model.Membership
import org.matrix.android.sdk.api.session.room.model.RoomMemberSummary
import org.matrix.android.sdk.internal.database.helper.findLatestSessionInfo
import org.matrix.android.sdk.internal.database.mapper.asDomain
import org.matrix.android.sdk.internal.database.model.ChunkEntity
import org.matrix.android.sdk.internal.database.model.RoomMemberSummaryEntity
import org.matrix.android.sdk.internal.database.model.RoomMemberSummaryEntityFields
import org.matrix.android.sdk.internal.database.model.RoomMembersLoadStatusType
@ -141,7 +143,10 @@ internal class DefaultMembershipService @AssistedInject constructor(
}
override suspend fun invite(userId: String, reason: String?) {
cryptoService.sendSharedHistoryKeys(roomId, userId)
val sessionInfoSet = Realm.getInstance(monarchy.realmConfiguration).use {
ChunkEntity.findLatestSessionInfo(it, roomId)
}
cryptoService.sendSharedHistoryKeysToLastChunk(roomId, userId, sessionInfoSet)
val params = InviteTask.Params(roomId, userId, reason)
inviteTask.execute(params)
}