Implement history key sharing functionality with respect to room visibility settings

This commit is contained in:
ariskotsomitopoulos 2022-04-26 17:51:03 +03:00 committed by Valere
parent 6e57aeb9e5
commit e861edd544
8 changed files with 57 additions and 16 deletions

View file

@ -48,3 +48,9 @@ enum class RoomHistoryVisibility {
*/
@Json(name = "joined") JOINED
}
/**
* Room history should be shared only if room visibility is world_readable or shared
*/
internal fun RoomHistoryVisibility.shouldShareHistory() =
this == RoomHistoryVisibility.WORLD_READABLE || this == RoomHistoryVisibility.SHARED

View file

@ -71,6 +71,7 @@ import org.matrix.android.sdk.api.session.room.model.Membership
import org.matrix.android.sdk.api.session.room.model.RoomHistoryVisibility
import org.matrix.android.sdk.api.session.room.model.RoomHistoryVisibilityContent
import org.matrix.android.sdk.api.session.room.model.RoomMemberContent
import org.matrix.android.sdk.api.session.room.model.shouldShareHistory
import org.matrix.android.sdk.api.session.sync.model.SyncResponse
import org.matrix.android.sdk.internal.crypto.actions.MegolmSessionDataImporter
import org.matrix.android.sdk.internal.crypto.actions.SetDeviceVerificationAction
@ -964,8 +965,8 @@ internal class DefaultCryptoService @Inject constructor(
if (!event.isStateEvent()) return
val eventContent = event.content.toModel<RoomHistoryVisibilityContent>()
eventContent?.historyVisibility?.let {
Timber.i("-----> onRoomHistoryVisibilityEvent $it")
cryptoStore.setShouldEncryptForInvitedMembers(roomId, it != RoomHistoryVisibility.JOINED)
cryptoStore.setShouldShareHistory(roomId, it.shouldShareHistory())
}
}
@ -1335,6 +1336,7 @@ internal class DefaultCryptoService @Inject constructor(
)
}
}
override fun sendSharedHistoryKeys(roomId: String, userId: String) {
cryptoCoroutineScope.launch(coroutineDispatchers.crypto) {
val userDevices = cryptoStore.getUserDevices(userId)
@ -1342,12 +1344,15 @@ internal class DefaultCryptoService @Inject constructor(
// Lets share our existing inbound sessions for every user device
val deviceId = it.key
val inboundSessions = cryptoStore.getInboundGroupSessions(roomId)
inboundSessions.forEach { inboundGroupSession ->
inboundSessions.filter { inboundGroupSession ->
inboundGroupSession.sharedHistory
}.forEach { inboundGroupSession ->
// Share the session with the 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")
}
}
}

View file

@ -43,6 +43,10 @@ internal class OlmInboundGroupSessionWrapper2 : Serializable {
// Devices which forwarded this session to us (normally empty).
var forwardingCurve25519KeyChain: List<String>? = ArrayList()
// Flag that indicates whether or not the current inboundSession will be shared to
// invited users to decrypt past messages
var sharedHistory: Boolean = false
/**
* @return the first known message index
*/

View file

@ -258,6 +258,17 @@ internal interface IMXCryptoStore {
fun setShouldEncryptForInvitedMembers(roomId: String, shouldEncryptForInvitedMembers: Boolean)
fun shouldShareHistory(roomId: String): Boolean
/**
* Sets a boolean flag that will determine whether or not room history (existing inbound sessions)
* will be shared to new user invites
*
* @param roomId the room id
* @param shouldShareHistory The boolean flag
*/
fun setShouldShareHistory(roomId: String, shouldShareHistory: Boolean)
/**
* Store a session between the logged-in user and another device.
*

View file

@ -657,12 +657,25 @@ internal class RealmCryptoStore @Inject constructor(
?: false
}
override fun shouldShareHistory(roomId: String): Boolean {
return doWithRealm(realmConfiguration) {
CryptoRoomEntity.getById(it, roomId)?.shouldShareHistory
}
?: false
}
override fun setShouldEncryptForInvitedMembers(roomId: String, shouldEncryptForInvitedMembers: Boolean) {
doRealmTransaction(realmConfiguration) {
CryptoRoomEntity.getOrCreate(it, roomId).shouldEncryptForInvitedMembers = shouldEncryptForInvitedMembers
}
}
override fun setShouldShareHistory(roomId: String, shouldShareHistory: Boolean) {
doRealmTransaction(realmConfiguration) {
CryptoRoomEntity.getOrCreate(it, roomId).shouldShareHistory = shouldShareHistory
}
}
override fun storeSession(olmSessionWrapper: OlmSessionWrapper, deviceKey: String) {
var sessionIdentifier: String? = null
@ -743,6 +756,10 @@ internal class RealmCryptoStore @Inject constructor(
}
if (sessionIdentifier != null) {
val shouldShareHistory = session.roomId?.let { roomId ->
CryptoRoomEntity.getById(realm, roomId)?.shouldShareHistory
} ?: false
session.sharedHistory = shouldShareHistory
val key = OlmInboundGroupSessionEntity.createPrimaryKey(sessionIdentifier, session.senderKey)
val realmOlmInboundGroupSession = OlmInboundGroupSessionEntity().apply {
@ -750,22 +767,11 @@ internal class RealmCryptoStore @Inject constructor(
sessionId = sessionIdentifier
senderKey = session.senderKey
roomId = session.roomId
sharedHistory = shouldShareHistory
putInboundGroupSession(session)
}
if (existing != null) {
// we want to keep the existing backup status
existing.putInboundGroupSession(session)
} else {
val realmOlmInboundGroupSession = OlmInboundGroupSessionEntity().apply {
primaryKey = key
sessionId = sessionIdentifier
senderKey = session.senderKey
putInboundGroupSession(session)
}
realm.insertOrUpdate(realmOlmInboundGroupSession)
}
Timber.i("## CRYPTO | shouldShareHistory: $shouldShareHistory for $key")
realm.insertOrUpdate(realmOlmInboundGroupSession)
}
}
}

View file

@ -73,6 +73,9 @@ internal class RealmCryptoStoreMigration @Inject constructor(
if (oldVersion < 14) MigrateCryptoTo014(realm).perform()
if (oldVersion < 15) MigrateCryptoTo015(realm).perform()
if (oldVersion < 16) MigrateCryptoTo016(realm).perform()
<<<<<<< develop
if (oldVersion < 17) MigrateCryptoTo017(realm).perform()
=======
>>>>>>> Implement history key sharing functionality with respect to room visibility settings
}
}

View file

@ -17,6 +17,7 @@
package org.matrix.android.sdk.internal.crypto.store.db.migration
import io.realm.DynamicRealm
import org.matrix.android.sdk.internal.crypto.store.db.model.CryptoRoomEntityFields
import org.matrix.android.sdk.internal.crypto.store.db.model.OlmInboundGroupSessionEntityFields
import org.matrix.android.sdk.internal.util.database.RealmMigrator
@ -28,5 +29,8 @@ internal class MigrateCryptoTo017(realm: DynamicRealm) : RealmMigrator(realm, 16
realm.schema.get("OlmInboundGroupSessionEntity")
?.addField(OlmInboundGroupSessionEntityFields.SHARED_HISTORY, Boolean::class.java)
?.addField(OlmInboundGroupSessionEntityFields.ROOM_ID, String::class.java)
realm.schema.get("CryptoRoomEntity")
?.addField(CryptoRoomEntityFields.SHOULD_SHARE_HISTORY, Boolean::class.java)
}
}

View file

@ -24,6 +24,8 @@ internal open class CryptoRoomEntity(
var algorithm: String? = null,
var shouldEncryptForInvitedMembers: Boolean? = null,
var blacklistUnverifiedDevices: Boolean = false,
// Determines whether or not room history should be shared on new member invites
var shouldShareHistory: Boolean = false,
// Store the current outbound session for this room,
// to avoid re-create and re-share at each startup (if rotation not needed..)
// This is specific to megolm but not sure how to model it better