From e861edd544b49a5702f66f8d1b00e98c5df094be Mon Sep 17 00:00:00 2001 From: ariskotsomitopoulos Date: Tue, 26 Apr 2022 17:51:03 +0300 Subject: [PATCH] Implement history key sharing functionality with respect to room visibility settings --- .../room/model/RoomHistoryVisibility.kt | 6 ++++ .../internal/crypto/DefaultCryptoService.kt | 9 +++-- .../model/OlmInboundGroupSessionWrapper2.kt | 4 +++ .../internal/crypto/store/IMXCryptoStore.kt | 11 ++++++ .../crypto/store/db/RealmCryptoStore.kt | 34 +++++++++++-------- .../store/db/RealmCryptoStoreMigration.kt | 3 ++ .../store/db/migration/MigrateCryptoTo017.kt | 4 +++ .../crypto/store/db/model/CryptoRoomEntity.kt | 2 ++ 8 files changed, 57 insertions(+), 16 deletions(-) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/RoomHistoryVisibility.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/RoomHistoryVisibility.kt index 06069f2646..3648d6b883 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/RoomHistoryVisibility.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/RoomHistoryVisibility.kt @@ -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 diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/DefaultCryptoService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/DefaultCryptoService.kt index ee95dfed9e..4a44e9e2d0 100755 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/DefaultCryptoService.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/DefaultCryptoService.kt @@ -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() 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") } } } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/model/OlmInboundGroupSessionWrapper2.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/model/OlmInboundGroupSessionWrapper2.kt index 289c169d6d..570532ae8b 100755 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/model/OlmInboundGroupSessionWrapper2.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/model/OlmInboundGroupSessionWrapper2.kt @@ -43,6 +43,10 @@ internal class OlmInboundGroupSessionWrapper2 : Serializable { // Devices which forwarded this session to us (normally empty). var forwardingCurve25519KeyChain: List? = 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 */ diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/IMXCryptoStore.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/IMXCryptoStore.kt index b961e83b9a..ceb91aa8ce 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/IMXCryptoStore.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/IMXCryptoStore.kt @@ -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. * diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/RealmCryptoStore.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/RealmCryptoStore.kt index c39ae6813e..7cc2f75285 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/RealmCryptoStore.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/RealmCryptoStore.kt @@ -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) } } } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/RealmCryptoStoreMigration.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/RealmCryptoStoreMigration.kt index 4ca9d44f98..35229d205d 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/RealmCryptoStoreMigration.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/RealmCryptoStoreMigration.kt @@ -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 } } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/migration/MigrateCryptoTo017.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/migration/MigrateCryptoTo017.kt index 36f17f4674..6ce94c3eb2 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/migration/MigrateCryptoTo017.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/migration/MigrateCryptoTo017.kt @@ -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) } } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/model/CryptoRoomEntity.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/model/CryptoRoomEntity.kt index 114a596964..be57586163 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/model/CryptoRoomEntity.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/model/CryptoRoomEntity.kt @@ -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