From e9b33f6234b2fce18ebef47e98e68e3d3b16ac33 Mon Sep 17 00:00:00 2001 From: Valere Date: Wed, 3 Aug 2022 14:28:36 +0200 Subject: [PATCH 1/7] Per room block unverified devices --- changelog.d/6725.bugfix | 1 + .../src/main/res/values/strings.xml | 3 + .../sdk/internal/crypto/E2eeTestConfig.kt | 132 ++++++++++++++++++ .../sdk/api/session/crypto/CryptoService.kt | 7 +- .../api/session/crypto/GlobalCryptoConfig.kt | 23 +++ .../internal/crypto/DefaultCryptoService.kt | 31 ++-- .../algorithms/megolm/MXMegolmEncryption.kt | 2 +- .../internal/crypto/store/IMXCryptoStore.kt | 25 +++- .../crypto/store/db/RealmCryptoStore.kt | 83 ++++++++--- .../roomprofile/RoomProfileViewState.kt | 2 +- .../settings/RoomSettingsAction.kt | 1 + .../settings/RoomSettingsController.kt | 52 +++++++ .../settings/RoomSettingsFragment.kt | 4 + .../settings/RoomSettingsViewModel.kt | 47 +++++++ .../settings/RoomSettingsViewState.kt | 6 +- .../src/main/res/layout/item_form_switch.xml | 2 + 16 files changed, 376 insertions(+), 45 deletions(-) create mode 100644 changelog.d/6725.bugfix create mode 100644 matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/crypto/E2eeTestConfig.kt create mode 100644 matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/crypto/GlobalCryptoConfig.kt diff --git a/changelog.d/6725.bugfix b/changelog.d/6725.bugfix new file mode 100644 index 0000000000..f05ddbc69d --- /dev/null +++ b/changelog.d/6725.bugfix @@ -0,0 +1 @@ +Add option to only send to verified devices per room (web parity) diff --git a/library/ui-strings/src/main/res/values/strings.xml b/library/ui-strings/src/main/res/values/strings.xml index 5aeac44a55..cc339f91d9 100644 --- a/library/ui-strings/src/main/res/values/strings.xml +++ b/library/ui-strings/src/main/res/values/strings.xml @@ -1234,6 +1234,9 @@ Import Encrypt to verified sessions only Never send encrypted messages to unverified sessions from this session. + Never send encrypted messages to unverified sessions in this room. + ⚠ There are unverified devices in this room, they won’t be able to decrypt messages you send. + πŸ”’ You have enable encrypt to verified sessions only for all rooms in Security Settings. %1$d/%2$d key imported with success. %1$d/%2$d keys imported with success. diff --git a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/crypto/E2eeTestConfig.kt b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/crypto/E2eeTestConfig.kt new file mode 100644 index 0000000000..7a03276d34 --- /dev/null +++ b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/crypto/E2eeTestConfig.kt @@ -0,0 +1,132 @@ +/* + * Copyright 2022 The Matrix.org Foundation C.I.C. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.matrix.android.sdk.internal.crypto + +import androidx.test.filters.LargeTest +import org.amshove.kluent.shouldBe +import org.junit.FixMethodOrder +import org.junit.Test +import org.junit.runner.RunWith +import org.junit.runners.JUnit4 +import org.junit.runners.MethodSorters +import org.matrix.android.sdk.InstrumentedTest +import org.matrix.android.sdk.api.session.crypto.MXCryptoError +import org.matrix.android.sdk.api.session.room.timeline.getLastMessageContent +import org.matrix.android.sdk.common.CommonTestHelper.Companion.runCryptoTest + +@RunWith(JUnit4::class) +@FixMethodOrder(MethodSorters.JVM) +@LargeTest +class E2eeTestConfig : InstrumentedTest { + + @Test + fun testBlacklistUnverifiedDefault() = runCryptoTest(context()) { cryptoTestHelper, _ -> + val cryptoTestData = cryptoTestHelper.doE2ETestWithAliceAndBobInARoom(true) + + cryptoTestData.firstSession.cryptoService().getGlobalBlacklistUnverifiedDevices() shouldBe false + cryptoTestData.firstSession.cryptoService().isRoomBlacklistUnverifiedDevices(cryptoTestData.roomId) shouldBe false + cryptoTestData.secondSession!!.cryptoService().getGlobalBlacklistUnverifiedDevices() shouldBe false + cryptoTestData.secondSession!!.cryptoService().isRoomBlacklistUnverifiedDevices(cryptoTestData.roomId) shouldBe false + } + + @Test + fun testCantDecryptIfGlobalUnverified() = runCryptoTest(context()) { cryptoTestHelper, testHelper -> + val cryptoTestData = cryptoTestHelper.doE2ETestWithAliceAndBobInARoom(true) + + cryptoTestData.firstSession.cryptoService().setGlobalBlacklistUnverifiedDevices(true) + + val roomAlicePOV = cryptoTestData.firstSession.roomService().getRoom(cryptoTestData.roomId)!! + + val sentMessage = testHelper.sendTextMessage(roomAlicePOV, "you are blocked", 1).first() + + val roomBobPOV = cryptoTestData.secondSession!!.roomService().getRoom(cryptoTestData.roomId)!! + // ensure other received + testHelper.waitWithLatch { latch -> + testHelper.retryPeriodicallyWithLatch(latch) { + roomBobPOV.timelineService().getTimelineEvent(sentMessage.eventId) != null + } + } + + cryptoTestHelper.ensureCannotDecrypt(listOf(sentMessage.eventId), cryptoTestData.secondSession!!, cryptoTestData.roomId) + } + + @Test + fun testCanDecryptIfGlobalUnverifiedAndUserTrusted() = runCryptoTest(context()) { cryptoTestHelper, testHelper -> + val cryptoTestData = cryptoTestHelper.doE2ETestWithAliceAndBobInARoom(true) + + cryptoTestHelper.initializeCrossSigning(cryptoTestData.firstSession) + cryptoTestHelper.initializeCrossSigning(cryptoTestData.secondSession!!) + + cryptoTestHelper.verifySASCrossSign(cryptoTestData.firstSession, cryptoTestData.secondSession!!, cryptoTestData.roomId) + + cryptoTestData.firstSession.cryptoService().setGlobalBlacklistUnverifiedDevices(true) + + val roomAlicePOV = cryptoTestData.firstSession.roomService().getRoom(cryptoTestData.roomId)!! + + val sentMessage = testHelper.sendTextMessage(roomAlicePOV, "you can read", 1).first() + + val roomBobPOV = cryptoTestData.secondSession!!.roomService().getRoom(cryptoTestData.roomId)!! + // ensure other received + testHelper.waitWithLatch { latch -> + testHelper.retryPeriodicallyWithLatch(latch) { + roomBobPOV.timelineService().getTimelineEvent(sentMessage.eventId) != null + } + } + + cryptoTestHelper.ensureCanDecrypt( + listOf(sentMessage.eventId), + cryptoTestData.secondSession!!, + cryptoTestData.roomId, + listOf(sentMessage.getLastMessageContent()!!.body) + ) + } + + @Test + fun testCantDecryptIfPerRoomUnverified() = runCryptoTest(context()) { cryptoTestHelper, testHelper -> + val cryptoTestData = cryptoTestHelper.doE2ETestWithAliceAndBobInARoom(true) + + val roomAlicePOV = cryptoTestData.firstSession.roomService().getRoom(cryptoTestData.roomId)!! + + val beforeMessage = testHelper.sendTextMessage(roomAlicePOV, "you can read", 1).first() + + val roomBobPOV = cryptoTestData.secondSession!!.roomService().getRoom(cryptoTestData.roomId)!! + // ensure other received + testHelper.waitWithLatch { latch -> + testHelper.retryPeriodicallyWithLatch(latch) { + roomBobPOV.timelineService().getTimelineEvent(beforeMessage.eventId) != null + } + } + + cryptoTestHelper.ensureCanDecrypt( + listOf(beforeMessage.eventId), + cryptoTestData.secondSession!!, + cryptoTestData.roomId, + listOf(beforeMessage.getLastMessageContent()!!.body) + ) + + cryptoTestData.firstSession.cryptoService().setRoomBlacklistUnverifiedDevices(cryptoTestData.roomId, true) + + val afterMessage = testHelper.sendTextMessage(roomAlicePOV, "you are blocked", 1).first() + + cryptoTestHelper.ensureCannotDecrypt( + listOf(afterMessage.eventId), + cryptoTestData.secondSession!!, + cryptoTestData.roomId, + MXCryptoError.ErrorType.KEYS_WITHHELD + ) + } +} diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/crypto/CryptoService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/crypto/CryptoService.kt index e0e662c789..5e0c087c08 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/crypto/CryptoService.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/crypto/CryptoService.kt @@ -42,6 +42,7 @@ 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.api.util.Optional import org.matrix.android.sdk.internal.crypto.model.SessionInfo +import org.matrix.android.sdk.api.session.crypto.GlobalCryptoConfig interface CryptoService { @@ -61,6 +62,8 @@ interface CryptoService { fun isRoomBlacklistUnverifiedDevices(roomId: String?): Boolean + fun getLiveBlacklistUnverifiedDevices(roomId: String): LiveData + fun setWarnOnUnknownDevices(warn: Boolean) fun setDeviceVerification(trustLevel: DeviceTrustLevel, userId: String, deviceId: String) @@ -77,6 +80,8 @@ interface CryptoService { fun setGlobalBlacklistUnverifiedDevices(block: Boolean) + fun getLiveGlobalCryptoConfig(): LiveData + /** * Enable or disable key gossiping. * Default is true. @@ -112,7 +117,7 @@ interface CryptoService { suspend fun exportRoomKeys(password: String): ByteArray - fun setRoomBlacklistUnverifiedDevices(roomId: String) + fun setRoomBlacklistUnverifiedDevices(roomId: String, enable: Boolean) fun getCryptoDeviceInfo(userId: String, deviceId: String?): CryptoDeviceInfo? diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/crypto/GlobalCryptoConfig.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/crypto/GlobalCryptoConfig.kt new file mode 100644 index 0000000000..a6afe6087b --- /dev/null +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/crypto/GlobalCryptoConfig.kt @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2022 New Vector Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.matrix.android.sdk.api.session.crypto + +data class GlobalCryptoConfig( + val globalBlacklistUnverifiedDevices: Boolean, + val globalEnableKeyGossiping: Boolean, + val enableKeyForwardingOnInvite: Boolean, +) 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 901700cac6..f37be4ff62 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 @@ -87,6 +87,7 @@ import org.matrix.android.sdk.internal.crypto.model.MXKey.Companion.KEY_SIGNED_C import org.matrix.android.sdk.internal.crypto.model.SessionInfo import org.matrix.android.sdk.internal.crypto.model.toRest import org.matrix.android.sdk.internal.crypto.repository.WarnOnUnknownDeviceRepository +import org.matrix.android.sdk.api.session.crypto.GlobalCryptoConfig import org.matrix.android.sdk.internal.crypto.store.IMXCryptoStore import org.matrix.android.sdk.internal.crypto.tasks.DeleteDeviceTask import org.matrix.android.sdk.internal.crypto.tasks.GetDeviceInfoTask @@ -1163,6 +1164,10 @@ internal class DefaultCryptoService @Inject constructor( return cryptoStore.getGlobalBlacklistUnverifiedDevices() } + override fun getLiveGlobalCryptoConfig(): LiveData { + return cryptoStore.getLiveGlobalCryptoConfig() + } + /** * Tells whether the client should encrypt messages only for the verified devices * in this room. @@ -1171,30 +1176,18 @@ internal class DefaultCryptoService @Inject constructor( * @param roomId the room id * @return true if the client should encrypt messages only for the verified devices. */ -// TODO add this info in CryptoRoomEntity? override fun isRoomBlacklistUnverifiedDevices(roomId: String?): Boolean { - return roomId?.let { cryptoStore.getRoomsListBlacklistUnverifiedDevices().contains(it) } + return roomId?.let { cryptoStore.getBlacklistUnverifiedDevices(roomId) } ?: false } /** - * Manages the room black-listing for unverified devices. + * A live status regarding sharing keys for unverified devices in this room. * - * @param roomId the room id - * @param add true to add the room id to the list, false to remove it. + * @return Live status */ - private fun setRoomBlacklistUnverifiedDevices(roomId: String, add: Boolean) { - val roomIds = cryptoStore.getRoomsListBlacklistUnverifiedDevices().toMutableList() - - if (add) { - if (roomId !in roomIds) { - roomIds.add(roomId) - } - } else { - roomIds.remove(roomId) - } - - cryptoStore.setRoomsListBlacklistUnverifiedDevices(roomIds) + override fun getLiveBlacklistUnverifiedDevices(roomId: String): LiveData { + return cryptoStore.getLiveBlacklistUnverifiedDevices(roomId) } /** @@ -1202,8 +1195,8 @@ internal class DefaultCryptoService @Inject constructor( * * @param roomId the room id */ - override fun setRoomBlacklistUnverifiedDevices(roomId: String) { - setRoomBlacklistUnverifiedDevices(roomId, true) + override fun setRoomBlacklistUnverifiedDevices(roomId: String, enable: Boolean) { + cryptoStore.blackListUnverifiedDevicesInRoom(roomId, enable) } /** diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/algorithms/megolm/MXMegolmEncryption.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/algorithms/megolm/MXMegolmEncryption.kt index fca6fab66c..e19e513b63 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/algorithms/megolm/MXMegolmEncryption.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/algorithms/megolm/MXMegolmEncryption.kt @@ -424,7 +424,7 @@ internal class MXMegolmEncryption( // an m.new_device. val keys = deviceListManager.downloadKeys(userIds, false) val encryptToVerifiedDevicesOnly = cryptoStore.getGlobalBlacklistUnverifiedDevices() || - cryptoStore.getRoomsListBlacklistUnverifiedDevices().contains(roomId) + cryptoStore.getBlacklistUnverifiedDevices(roomId) val devicesInRoom = DeviceInRoomInfo() val unknownDevices = MXUsersDevicesMap() 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 56eba25249..193b53ec4e 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 @@ -18,6 +18,7 @@ package org.matrix.android.sdk.internal.crypto.store import androidx.lifecycle.LiveData import androidx.paging.PagedList +import org.matrix.android.sdk.api.session.crypto.GlobalCryptoConfig import org.matrix.android.sdk.api.session.crypto.NewSessionListener import org.matrix.android.sdk.api.session.crypto.OutgoingKeyRequest import org.matrix.android.sdk.api.session.crypto.OutgoingRoomKeyRequestState @@ -120,11 +121,26 @@ internal interface IMXCryptoStore { fun getRoomsListBlacklistUnverifiedDevices(): List /** - * Updates the rooms ids list in which the messages are not encrypted for the unverified devices. + * A live status regarding sharing keys for unverified devices in this room. * - * @param roomIds the room ids list + * @return Live status */ - fun setRoomsListBlacklistUnverifiedDevices(roomIds: List) + fun getLiveBlacklistUnverifiedDevices(roomId: String): LiveData + + /** + * Tell if unverified devices should be blacklisted when sending keys. + * + * @return true if should not send keys to unverified devices + */ + fun getBlacklistUnverifiedDevices(roomId: String): Boolean + + /** + * Define if encryption keys should be sent to unverified devices in this room. + * + * @param roomId the roomId + * @param blacklist if true will not send keys to unverified devices + */ + fun blackListUnverifiedDevicesInRoom(roomId: String, blacklist: Boolean) /** * Get the current keys backup version. @@ -516,6 +532,9 @@ internal interface IMXCryptoStore { fun getCrossSigningPrivateKeys(): PrivateKeysInfo? fun getLiveCrossSigningPrivateKeys(): LiveData> + fun getGlobalCryptoConfig(): GlobalCryptoConfig + fun getLiveGlobalCryptoConfig(): LiveData + fun saveBackupRecoveryKey(recoveryKey: String?, version: String?) fun getKeyBackupRecoveryKeyInfo(): SavedKeyBackupKeyInfo? 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 6a2ef3bde1..801d012385 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 @@ -53,6 +53,7 @@ import org.matrix.android.sdk.api.util.toOptional import org.matrix.android.sdk.internal.crypto.model.MXInboundMegolmSessionWrapper import org.matrix.android.sdk.internal.crypto.model.OlmSessionWrapper import org.matrix.android.sdk.internal.crypto.model.OutboundGroupSessionWrapper +import org.matrix.android.sdk.api.session.crypto.GlobalCryptoConfig import org.matrix.android.sdk.internal.crypto.store.IMXCryptoStore import org.matrix.android.sdk.internal.crypto.store.db.mapper.CrossSigningKeysMapper import org.matrix.android.sdk.internal.crypto.store.db.mapper.MyDeviceLastSeenInfoEntityMapper @@ -445,6 +446,38 @@ internal class RealmCryptoStore @Inject constructor( } } + override fun getGlobalCryptoConfig(): GlobalCryptoConfig { + return doWithRealm(realmConfiguration) { realm -> + realm.where().findFirst() + ?.let { + GlobalCryptoConfig( + globalBlacklistUnverifiedDevices = it.globalBlacklistUnverifiedDevices, + globalEnableKeyGossiping = it.globalEnableKeyGossiping, + enableKeyForwardingOnInvite = it.enableKeyForwardingOnInvite + ) + } ?: GlobalCryptoConfig(false, false, false) + } + } + + override fun getLiveGlobalCryptoConfig(): LiveData { + val liveData = monarchy.findAllMappedWithChanges( + { realm: Realm -> + realm + .where() + }, + { + GlobalCryptoConfig( + globalBlacklistUnverifiedDevices = it.globalBlacklistUnverifiedDevices, + globalEnableKeyGossiping = it.globalEnableKeyGossiping, + enableKeyForwardingOnInvite = it.enableKeyForwardingOnInvite + ) + } + ) + return Transformations.map(liveData) { + it.firstOrNull() ?: GlobalCryptoConfig(false, false, false) + } + } + override fun storePrivateKeysInfo(msk: String?, usk: String?, ssk: String?) { Timber.v("## CRYPTO | *** storePrivateKeysInfo ${msk != null}, ${usk != null}, ${ssk != null}") doRealmTransaction(realmConfiguration) { realm -> @@ -1053,25 +1086,6 @@ internal class RealmCryptoStore @Inject constructor( } ?: false } - override fun setRoomsListBlacklistUnverifiedDevices(roomIds: List) { - doRealmTransaction(realmConfiguration) { - // Reset all - it.where() - .findAll() - .forEach { room -> - room.blacklistUnverifiedDevices = false - } - - // Enable those in the list - it.where() - .`in`(CryptoRoomEntityFields.ROOM_ID, roomIds.toTypedArray()) - .findAll() - .forEach { room -> - room.blacklistUnverifiedDevices = true - } - } - } - override fun getRoomsListBlacklistUnverifiedDevices(): List { return doWithRealm(realmConfiguration) { it.where() @@ -1083,6 +1097,37 @@ internal class RealmCryptoStore @Inject constructor( } } + override fun getLiveBlacklistUnverifiedDevices(roomId: String): LiveData { + val liveData = monarchy.findAllMappedWithChanges( + { realm: Realm -> + realm.where() + .equalTo(CryptoRoomEntityFields.ROOM_ID, roomId) + }, + { + it.blacklistUnverifiedDevices + } + ) + return Transformations.map(liveData) { + it.firstOrNull() ?: false + } + } + + override fun getBlacklistUnverifiedDevices(roomId: String): Boolean { + return doWithRealm(realmConfiguration) { realm -> + realm.where() + .equalTo(CryptoRoomEntityFields.ROOM_ID, roomId) + .findFirst() + ?.blacklistUnverifiedDevices ?: false + } + } + + override fun blackListUnverifiedDevicesInRoom(roomId: String, blacklist: Boolean) { + doRealmTransaction(realmConfiguration) { realm -> + CryptoRoomEntity.getById(realm, roomId) + ?.blacklistUnverifiedDevices = blacklist + } + } + override fun getDeviceTrackingStatuses(): Map { return doWithRealm(realmConfiguration) { it.where() diff --git a/vector/src/main/java/im/vector/app/features/roomprofile/RoomProfileViewState.kt b/vector/src/main/java/im/vector/app/features/roomprofile/RoomProfileViewState.kt index 87db15ea3b..c457a01750 100644 --- a/vector/src/main/java/im/vector/app/features/roomprofile/RoomProfileViewState.kt +++ b/vector/src/main/java/im/vector/app/features/roomprofile/RoomProfileViewState.kt @@ -35,7 +35,7 @@ data class RoomProfileViewState( val recommendedRoomVersion: String? = null, val canUpgradeRoom: Boolean = false, val isTombstoned: Boolean = false, - val canUpdateRoomState: Boolean = false + val canUpdateRoomState: Boolean = false, ) : MavericksState { constructor(args: RoomProfileArgs) : this(roomId = args.roomId) diff --git a/vector/src/main/java/im/vector/app/features/roomprofile/settings/RoomSettingsAction.kt b/vector/src/main/java/im/vector/app/features/roomprofile/settings/RoomSettingsAction.kt index eb601605e0..bb2dc08e76 100644 --- a/vector/src/main/java/im/vector/app/features/roomprofile/settings/RoomSettingsAction.kt +++ b/vector/src/main/java/im/vector/app/features/roomprofile/settings/RoomSettingsAction.kt @@ -28,6 +28,7 @@ sealed class RoomSettingsAction : VectorViewModelAction { data class SetRoomHistoryVisibility(val visibility: RoomHistoryVisibility) : RoomSettingsAction() data class SetRoomJoinRule(val roomJoinRule: RoomJoinRules) : RoomSettingsAction() data class SetRoomGuestAccess(val guestAccess: GuestAccess) : RoomSettingsAction() + data class SetEncryptToVerifiedDeviceOnly(val enable: Boolean) : RoomSettingsAction() object Save : RoomSettingsAction() object Cancel : RoomSettingsAction() diff --git a/vector/src/main/java/im/vector/app/features/roomprofile/settings/RoomSettingsController.kt b/vector/src/main/java/im/vector/app/features/roomprofile/settings/RoomSettingsController.kt index f8efe73ebf..936ebbd861 100644 --- a/vector/src/main/java/im/vector/app/features/roomprofile/settings/RoomSettingsController.kt +++ b/vector/src/main/java/im/vector/app/features/roomprofile/settings/RoomSettingsController.kt @@ -22,6 +22,7 @@ import im.vector.app.core.epoxy.dividerItem import im.vector.app.core.epoxy.profiles.buildProfileAction import im.vector.app.core.epoxy.profiles.buildProfileSection import im.vector.app.core.resources.StringProvider +import im.vector.app.core.ui.list.genericFooterItem import im.vector.app.core.ui.list.verticalMarginItem import im.vector.app.core.utils.DimensionConverter import im.vector.app.features.form.formEditTextItem @@ -30,6 +31,8 @@ import im.vector.app.features.form.formSwitchItem import im.vector.app.features.home.AvatarRenderer import im.vector.app.features.home.room.detail.timeline.format.RoomHistoryVisibilityFormatter import im.vector.app.features.settings.VectorPreferences +import im.vector.lib.core.utils.epoxy.charsequence.toEpoxyCharSequence +import me.gujun.android.span.span import org.matrix.android.sdk.api.session.room.model.GuestAccess import org.matrix.android.sdk.api.session.room.model.RoomJoinRules import org.matrix.android.sdk.api.util.toMatrixItem @@ -52,6 +55,7 @@ class RoomSettingsController @Inject constructor( fun onHistoryVisibilityClicked() fun onJoinRuleClicked() fun onToggleGuestAccess() + fun setEncryptedToVerifiedDevicesOnly(enabled: Boolean) } var callback: Callback? = null @@ -145,5 +149,53 @@ class RoomSettingsController @Inject constructor( id("guestAccessDivider") } } + + // Security + buildProfileSection(stringProvider.getString(R.string.room_profile_section_security)) + + data.globalCryptoConfig.invoke()?.let { globalConfig -> + if (globalConfig.globalBlacklistUnverifiedDevices) { + genericFooterItem { + id("globalConfig") + centered(false) + text( + span { + +host.stringProvider.getString(R.string.room_settings_global_blacklist_unverified_info_text) + apply { + if (data.unverifiedDevicesInTheRoom.invoke() == true) { + +"\n" + +host.stringProvider.getString(R.string.some_devices_will_not_be_able_to_decrypt) + } + } + }.toEpoxyCharSequence() + ) + itemClickAction { + } + } + } else { + // per room setting is available + val shouldBlockUnverified = data.encryptToVerifiedDeviceOnly.invoke() + formSwitchItem { + id("send_to_unverified") + enabled(shouldBlockUnverified != null) + title(host.stringProvider.getString(R.string.encryption_never_send_to_unverified_devices_in_room)) + + switchChecked(shouldBlockUnverified ?: false) + + apply { + if (shouldBlockUnverified == true && data.unverifiedDevicesInTheRoom.invoke() == true) { + summary( + host.stringProvider.getString(R.string.some_devices_will_not_be_able_to_decrypt) + ) + } else { + summary(null) + } + } + listener { value -> + host.callback?.setEncryptedToVerifiedDevicesOnly(value) + } + } + } + } } } diff --git a/vector/src/main/java/im/vector/app/features/roomprofile/settings/RoomSettingsFragment.kt b/vector/src/main/java/im/vector/app/features/roomprofile/settings/RoomSettingsFragment.kt index ba50890db3..b7d8f13343 100644 --- a/vector/src/main/java/im/vector/app/features/roomprofile/settings/RoomSettingsFragment.kt +++ b/vector/src/main/java/im/vector/app/features/roomprofile/settings/RoomSettingsFragment.kt @@ -199,6 +199,10 @@ class RoomSettingsFragment : viewModel.handle(RoomSettingsAction.SetRoomGuestAccess(toggled)) } + override fun setEncryptedToVerifiedDevicesOnly(enabled: Boolean) { + viewModel.handle(RoomSettingsAction.SetEncryptToVerifiedDeviceOnly(enabled)) + } + override fun onImageReady(uri: Uri?) { uri ?: return viewModel.handle( diff --git a/vector/src/main/java/im/vector/app/features/roomprofile/settings/RoomSettingsViewModel.kt b/vector/src/main/java/im/vector/app/features/roomprofile/settings/RoomSettingsViewModel.kt index 501ff7553a..cb5809d96a 100644 --- a/vector/src/main/java/im/vector/app/features/roomprofile/settings/RoomSettingsViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/roomprofile/settings/RoomSettingsViewModel.kt @@ -17,6 +17,7 @@ package im.vector.app.features.roomprofile.settings import androidx.core.net.toFile +import androidx.lifecycle.asFlow import com.airbnb.mvrx.MavericksViewModelFactory import dagger.assisted.Assisted import dagger.assisted.AssistedFactory @@ -25,8 +26,12 @@ import im.vector.app.core.di.MavericksAssistedViewModelFactory import im.vector.app.core.di.hiltMavericksViewModelFactory import im.vector.app.core.platform.VectorViewModel import im.vector.app.features.powerlevel.PowerLevelsFlowFactory +import im.vector.app.features.session.coroutineScope import im.vector.app.features.settings.VectorPreferences +import kotlinx.coroutines.flow.flatMapLatest +import kotlinx.coroutines.flow.flowOf import kotlinx.coroutines.flow.launchIn +import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.mapNotNull import kotlinx.coroutines.flow.onEach import kotlinx.coroutines.launch @@ -37,6 +42,8 @@ import org.matrix.android.sdk.api.session.events.model.EventType import org.matrix.android.sdk.api.session.events.model.toModel import org.matrix.android.sdk.api.session.getRoom import org.matrix.android.sdk.api.session.homeserver.HomeServerCapabilities +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.RoomAvatarContent import org.matrix.android.sdk.api.session.room.model.RoomGuestAccessContent import org.matrix.android.sdk.api.session.room.model.RoomHistoryVisibilityContent @@ -83,6 +90,39 @@ class RoomSettingsViewModel @AssistedInject constructor( canUpgradeToRestricted = couldUpgradeToRestricted ) } + + session.cryptoService().getLiveBlacklistUnverifiedDevices(initialState.roomId) + .asFlow() + .execute { + copy(encryptToVerifiedDeviceOnly = it) + } + + session.cryptoService().getLiveGlobalCryptoConfig() + .asFlow() + .execute { + copy(globalCryptoConfig = it) + } + + val flowRoom = room.flow() + session.cryptoService().getLiveBlacklistUnverifiedDevices(initialState.roomId) + .asFlow() + .flatMapLatest { + if (it) { + flowRoom.liveRoomMembers(roomMemberQueryParams { memberships = Membership.activeMemberships() }) + .map { it.map { it.userId } } + .flatMapLatest { + session.cryptoService().getLiveCryptoDeviceInfo(it).asFlow() + } + } else { + flowOf(emptyList()) + } + }.map { + it.isNotEmpty() + }.execute { + copy( + unverifiedDevicesInTheRoom = it + ) + } } private fun observeState() { @@ -212,6 +252,7 @@ class RoomSettingsViewModel @AssistedInject constructor( is RoomSettingsAction.SetRoomGuestAccess -> handleSetGuestAccess(action) is RoomSettingsAction.Save -> saveSettings() is RoomSettingsAction.Cancel -> cancel() + is RoomSettingsAction.SetEncryptToVerifiedDeviceOnly -> setEncryptToVerifiedDeviceOnly(action.enable) } } @@ -233,6 +274,12 @@ class RoomSettingsViewModel @AssistedInject constructor( } } + private fun setEncryptToVerifiedDeviceOnly(enabled: Boolean) { + session.coroutineScope.launch { + session.cryptoService().setRoomBlacklistUnverifiedDevices(room.roomId, enabled) + } + } + private fun handleSetAvatarAction(action: RoomSettingsAction.SetAvatarAction) { setState { deletePendingAvatar(this) diff --git a/vector/src/main/java/im/vector/app/features/roomprofile/settings/RoomSettingsViewState.kt b/vector/src/main/java/im/vector/app/features/roomprofile/settings/RoomSettingsViewState.kt index 81e98335c0..e3c6cd9b03 100644 --- a/vector/src/main/java/im/vector/app/features/roomprofile/settings/RoomSettingsViewState.kt +++ b/vector/src/main/java/im/vector/app/features/roomprofile/settings/RoomSettingsViewState.kt @@ -27,6 +27,7 @@ import org.matrix.android.sdk.api.session.room.model.GuestAccess import org.matrix.android.sdk.api.session.room.model.RoomHistoryVisibility import org.matrix.android.sdk.api.session.room.model.RoomJoinRules import org.matrix.android.sdk.api.session.room.model.RoomSummary +import org.matrix.android.sdk.api.session.crypto.GlobalCryptoConfig data class RoomSettingsViewState( val roomId: String, @@ -45,7 +46,10 @@ data class RoomSettingsViewState( val showSaveAction: Boolean = false, val actionPermissions: ActionPermissions = ActionPermissions(), val supportsRestricted: Boolean = false, - val canUpgradeToRestricted: Boolean = false + val canUpgradeToRestricted: Boolean = false, + val encryptToVerifiedDeviceOnly: Async = Uninitialized, + val globalCryptoConfig: Async = Uninitialized, + val unverifiedDevicesInTheRoom: Async = Uninitialized, ) : MavericksState { constructor(args: RoomProfileArgs) : this(roomId = args.roomId) diff --git a/vector/src/main/res/layout/item_form_switch.xml b/vector/src/main/res/layout/item_form_switch.xml index a637c8f52e..67d286a917 100644 --- a/vector/src/main/res/layout/item_form_switch.xml +++ b/vector/src/main/res/layout/item_form_switch.xml @@ -7,6 +7,8 @@ android:background="?android:colorBackground" android:foreground="?attr/selectableItemBackground" android:minHeight="@dimen/item_form_min_height" + android:paddingBottom="8dp" + android:paddingTop="8dp" tools:viewBindingIgnore="true"> Date: Wed, 3 Aug 2022 15:05:33 +0200 Subject: [PATCH 2/7] cleaning --- .../org/matrix/android/sdk/api/session/crypto/CryptoService.kt | 1 - .../matrix/android/sdk/internal/crypto/DefaultCryptoService.kt | 3 ++- .../android/sdk/internal/crypto/store/db/RealmCryptoStore.kt | 2 +- .../app/features/roomprofile/settings/RoomSettingsViewState.kt | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/crypto/CryptoService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/crypto/CryptoService.kt index 5e0c087c08..c2151ab6aa 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/crypto/CryptoService.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/crypto/CryptoService.kt @@ -42,7 +42,6 @@ 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.api.util.Optional import org.matrix.android.sdk.internal.crypto.model.SessionInfo -import org.matrix.android.sdk.api.session.crypto.GlobalCryptoConfig interface CryptoService { 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 f37be4ff62..bdbd326fe3 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 @@ -40,6 +40,7 @@ import org.matrix.android.sdk.api.failure.Failure import org.matrix.android.sdk.api.listeners.ProgressListener import org.matrix.android.sdk.api.logger.LoggerTag import org.matrix.android.sdk.api.session.crypto.CryptoService +import org.matrix.android.sdk.api.session.crypto.GlobalCryptoConfig import org.matrix.android.sdk.api.session.crypto.MXCryptoError import org.matrix.android.sdk.api.session.crypto.NewSessionListener import org.matrix.android.sdk.api.session.crypto.OutgoingKeyRequest @@ -87,7 +88,6 @@ import org.matrix.android.sdk.internal.crypto.model.MXKey.Companion.KEY_SIGNED_C import org.matrix.android.sdk.internal.crypto.model.SessionInfo import org.matrix.android.sdk.internal.crypto.model.toRest import org.matrix.android.sdk.internal.crypto.repository.WarnOnUnknownDeviceRepository -import org.matrix.android.sdk.api.session.crypto.GlobalCryptoConfig import org.matrix.android.sdk.internal.crypto.store.IMXCryptoStore import org.matrix.android.sdk.internal.crypto.tasks.DeleteDeviceTask import org.matrix.android.sdk.internal.crypto.tasks.GetDeviceInfoTask @@ -1194,6 +1194,7 @@ internal class DefaultCryptoService @Inject constructor( * Add this room to the ones which don't encrypt messages to unverified devices. * * @param roomId the room id + * @param if true will block sending keys to unverified devices */ override fun setRoomBlacklistUnverifiedDevices(roomId: String, enable: Boolean) { cryptoStore.blackListUnverifiedDevicesInRoom(roomId, enable) 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 801d012385..b5b2a2392d 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 @@ -29,6 +29,7 @@ import io.realm.kotlin.where import org.matrix.android.sdk.api.crypto.MXCRYPTO_ALGORITHM_MEGOLM import org.matrix.android.sdk.api.extensions.tryOrNull import org.matrix.android.sdk.api.logger.LoggerTag +import org.matrix.android.sdk.api.session.crypto.GlobalCryptoConfig import org.matrix.android.sdk.api.session.crypto.NewSessionListener import org.matrix.android.sdk.api.session.crypto.OutgoingKeyRequest import org.matrix.android.sdk.api.session.crypto.OutgoingRoomKeyRequestState @@ -53,7 +54,6 @@ import org.matrix.android.sdk.api.util.toOptional import org.matrix.android.sdk.internal.crypto.model.MXInboundMegolmSessionWrapper import org.matrix.android.sdk.internal.crypto.model.OlmSessionWrapper import org.matrix.android.sdk.internal.crypto.model.OutboundGroupSessionWrapper -import org.matrix.android.sdk.api.session.crypto.GlobalCryptoConfig import org.matrix.android.sdk.internal.crypto.store.IMXCryptoStore import org.matrix.android.sdk.internal.crypto.store.db.mapper.CrossSigningKeysMapper import org.matrix.android.sdk.internal.crypto.store.db.mapper.MyDeviceLastSeenInfoEntityMapper diff --git a/vector/src/main/java/im/vector/app/features/roomprofile/settings/RoomSettingsViewState.kt b/vector/src/main/java/im/vector/app/features/roomprofile/settings/RoomSettingsViewState.kt index e3c6cd9b03..26f4c6bdad 100644 --- a/vector/src/main/java/im/vector/app/features/roomprofile/settings/RoomSettingsViewState.kt +++ b/vector/src/main/java/im/vector/app/features/roomprofile/settings/RoomSettingsViewState.kt @@ -23,11 +23,11 @@ import com.airbnb.mvrx.Uninitialized import im.vector.app.R import im.vector.app.core.resources.StringProvider import im.vector.app.features.roomprofile.RoomProfileArgs +import org.matrix.android.sdk.api.session.crypto.GlobalCryptoConfig import org.matrix.android.sdk.api.session.room.model.GuestAccess import org.matrix.android.sdk.api.session.room.model.RoomHistoryVisibility import org.matrix.android.sdk.api.session.room.model.RoomJoinRules import org.matrix.android.sdk.api.session.room.model.RoomSummary -import org.matrix.android.sdk.api.session.crypto.GlobalCryptoConfig data class RoomSettingsViewState( val roomId: String, From f7d83563278cb627a0ba13a1c46e2b5be2aa0db1 Mon Sep 17 00:00:00 2001 From: Valere Date: Fri, 30 Sep 2022 17:37:33 +0200 Subject: [PATCH 3/7] post rebase fix & cleaning --- .../{E2eeTestConfig.kt => E2eeConfigTest.kt} | 28 +++++++++---------- .../sdk/api/session/crypto/CryptoService.kt | 4 +-- .../api/session/crypto/GlobalCryptoConfig.kt | 4 +-- .../internal/crypto/DefaultCryptoService.kt | 10 +++---- .../internal/crypto/store/IMXCryptoStore.kt | 4 +-- .../crypto/store/db/RealmCryptoStore.kt | 8 +++--- .../settings/RoomSettingsAction.kt | 2 +- .../settings/RoomSettingsController.kt | 2 +- .../settings/RoomSettingsViewModel.kt | 4 +-- 9 files changed, 33 insertions(+), 33 deletions(-) rename matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/crypto/{E2eeTestConfig.kt => E2eeConfigTest.kt} (86%) diff --git a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/crypto/E2eeTestConfig.kt b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/crypto/E2eeConfigTest.kt similarity index 86% rename from matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/crypto/E2eeTestConfig.kt rename to matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/crypto/E2eeConfigTest.kt index 7a03276d34..8b12092b79 100644 --- a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/crypto/E2eeTestConfig.kt +++ b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/crypto/E2eeConfigTest.kt @@ -25,13 +25,14 @@ import org.junit.runners.JUnit4 import org.junit.runners.MethodSorters import org.matrix.android.sdk.InstrumentedTest import org.matrix.android.sdk.api.session.crypto.MXCryptoError +import org.matrix.android.sdk.api.session.getRoom import org.matrix.android.sdk.api.session.room.timeline.getLastMessageContent import org.matrix.android.sdk.common.CommonTestHelper.Companion.runCryptoTest @RunWith(JUnit4::class) @FixMethodOrder(MethodSorters.JVM) @LargeTest -class E2eeTestConfig : InstrumentedTest { +class E2eeConfigTest : InstrumentedTest { @Test fun testBlacklistUnverifiedDefault() = runCryptoTest(context()) { cryptoTestHelper, _ -> @@ -55,10 +56,8 @@ class E2eeTestConfig : InstrumentedTest { val roomBobPOV = cryptoTestData.secondSession!!.roomService().getRoom(cryptoTestData.roomId)!! // ensure other received - testHelper.waitWithLatch { latch -> - testHelper.retryPeriodicallyWithLatch(latch) { - roomBobPOV.timelineService().getTimelineEvent(sentMessage.eventId) != null - } + testHelper.retryPeriodically { + roomBobPOV.timelineService().getTimelineEvent(sentMessage.eventId) != null } cryptoTestHelper.ensureCannotDecrypt(listOf(sentMessage.eventId), cryptoTestData.secondSession!!, cryptoTestData.roomId) @@ -81,10 +80,8 @@ class E2eeTestConfig : InstrumentedTest { val roomBobPOV = cryptoTestData.secondSession!!.roomService().getRoom(cryptoTestData.roomId)!! // ensure other received - testHelper.waitWithLatch { latch -> - testHelper.retryPeriodicallyWithLatch(latch) { - roomBobPOV.timelineService().getTimelineEvent(sentMessage.eventId) != null - } + testHelper.retryPeriodically { + roomBobPOV.timelineService().getTimelineEvent(sentMessage.eventId) != null } cryptoTestHelper.ensureCanDecrypt( @@ -105,10 +102,8 @@ class E2eeTestConfig : InstrumentedTest { val roomBobPOV = cryptoTestData.secondSession!!.roomService().getRoom(cryptoTestData.roomId)!! // ensure other received - testHelper.waitWithLatch { latch -> - testHelper.retryPeriodicallyWithLatch(latch) { - roomBobPOV.timelineService().getTimelineEvent(beforeMessage.eventId) != null - } + testHelper.retryPeriodically { + roomBobPOV.timelineService().getTimelineEvent(beforeMessage.eventId) != null } cryptoTestHelper.ensureCanDecrypt( @@ -118,10 +113,15 @@ class E2eeTestConfig : InstrumentedTest { listOf(beforeMessage.getLastMessageContent()!!.body) ) - cryptoTestData.firstSession.cryptoService().setRoomBlacklistUnverifiedDevices(cryptoTestData.roomId, true) + cryptoTestData.firstSession.cryptoService().setRoomBlockUnverifiedDevices(cryptoTestData.roomId, true) val afterMessage = testHelper.sendTextMessage(roomAlicePOV, "you are blocked", 1).first() + // ensure received + testHelper.retryPeriodically { + cryptoTestData.secondSession?.getRoom(cryptoTestData.roomId)?.timelineService()?.getTimelineEvent(afterMessage.eventId)?.root != null + } + cryptoTestHelper.ensureCannotDecrypt( listOf(afterMessage.eventId), cryptoTestData.secondSession!!, diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/crypto/CryptoService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/crypto/CryptoService.kt index c2151ab6aa..c383e05707 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/crypto/CryptoService.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/crypto/CryptoService.kt @@ -104,7 +104,7 @@ interface CryptoService { */ fun isShareKeysOnInviteEnabled(): Boolean - fun setRoomUnBlacklistUnverifiedDevices(roomId: String) + fun setRoomUnBlockUnverifiedDevices(roomId: String) fun getDeviceTrackingStatus(userId: String): Int @@ -116,7 +116,7 @@ interface CryptoService { suspend fun exportRoomKeys(password: String): ByteArray - fun setRoomBlacklistUnverifiedDevices(roomId: String, enable: Boolean) + fun setRoomBlockUnverifiedDevices(roomId: String, block: Boolean) fun getCryptoDeviceInfo(userId: String, deviceId: String?): CryptoDeviceInfo? diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/crypto/GlobalCryptoConfig.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/crypto/GlobalCryptoConfig.kt index a6afe6087b..6405652a68 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/crypto/GlobalCryptoConfig.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/crypto/GlobalCryptoConfig.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022 New Vector Ltd + * Copyright (c) 2022 The Matrix.org Foundation C.I.C. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -17,7 +17,7 @@ package org.matrix.android.sdk.api.session.crypto data class GlobalCryptoConfig( - val globalBlacklistUnverifiedDevices: Boolean, + val globalBlockUnverifiedDevices: Boolean, val globalEnableKeyGossiping: Boolean, val enableKeyForwardingOnInvite: Boolean, ) 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 bdbd326fe3..4a160f07b2 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 @@ -1194,10 +1194,10 @@ internal class DefaultCryptoService @Inject constructor( * Add this room to the ones which don't encrypt messages to unverified devices. * * @param roomId the room id - * @param if true will block sending keys to unverified devices + * @param block if true will block sending keys to unverified devices */ - override fun setRoomBlacklistUnverifiedDevices(roomId: String, enable: Boolean) { - cryptoStore.blackListUnverifiedDevicesInRoom(roomId, enable) + override fun setRoomBlockUnverifiedDevices(roomId: String, block: Boolean) { + cryptoStore.blockUnverifiedDevicesInRoom(roomId, block) } /** @@ -1205,8 +1205,8 @@ internal class DefaultCryptoService @Inject constructor( * * @param roomId the room id */ - override fun setRoomUnBlacklistUnverifiedDevices(roomId: String) { - setRoomBlacklistUnverifiedDevices(roomId, false) + override fun setRoomUnBlockUnverifiedDevices(roomId: String) { + setRoomBlockUnverifiedDevices(roomId, false) } /** 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 193b53ec4e..7c5dd6c585 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 @@ -138,9 +138,9 @@ internal interface IMXCryptoStore { * Define if encryption keys should be sent to unverified devices in this room. * * @param roomId the roomId - * @param blacklist if true will not send keys to unverified devices + * @param block if true will not send keys to unverified devices */ - fun blackListUnverifiedDevicesInRoom(roomId: String, blacklist: Boolean) + fun blockUnverifiedDevicesInRoom(roomId: String, block: Boolean) /** * Get the current keys backup version. 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 b5b2a2392d..81a4a9d427 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 @@ -451,7 +451,7 @@ internal class RealmCryptoStore @Inject constructor( realm.where().findFirst() ?.let { GlobalCryptoConfig( - globalBlacklistUnverifiedDevices = it.globalBlacklistUnverifiedDevices, + globalBlockUnverifiedDevices = it.globalBlacklistUnverifiedDevices, globalEnableKeyGossiping = it.globalEnableKeyGossiping, enableKeyForwardingOnInvite = it.enableKeyForwardingOnInvite ) @@ -467,7 +467,7 @@ internal class RealmCryptoStore @Inject constructor( }, { GlobalCryptoConfig( - globalBlacklistUnverifiedDevices = it.globalBlacklistUnverifiedDevices, + globalBlockUnverifiedDevices = it.globalBlacklistUnverifiedDevices, globalEnableKeyGossiping = it.globalEnableKeyGossiping, enableKeyForwardingOnInvite = it.enableKeyForwardingOnInvite ) @@ -1121,10 +1121,10 @@ internal class RealmCryptoStore @Inject constructor( } } - override fun blackListUnverifiedDevicesInRoom(roomId: String, blacklist: Boolean) { + override fun blockUnverifiedDevicesInRoom(roomId: String, block: Boolean) { doRealmTransaction(realmConfiguration) { realm -> CryptoRoomEntity.getById(realm, roomId) - ?.blacklistUnverifiedDevices = blacklist + ?.blacklistUnverifiedDevices = block } } diff --git a/vector/src/main/java/im/vector/app/features/roomprofile/settings/RoomSettingsAction.kt b/vector/src/main/java/im/vector/app/features/roomprofile/settings/RoomSettingsAction.kt index bb2dc08e76..13662c1f9b 100644 --- a/vector/src/main/java/im/vector/app/features/roomprofile/settings/RoomSettingsAction.kt +++ b/vector/src/main/java/im/vector/app/features/roomprofile/settings/RoomSettingsAction.kt @@ -28,7 +28,7 @@ sealed class RoomSettingsAction : VectorViewModelAction { data class SetRoomHistoryVisibility(val visibility: RoomHistoryVisibility) : RoomSettingsAction() data class SetRoomJoinRule(val roomJoinRule: RoomJoinRules) : RoomSettingsAction() data class SetRoomGuestAccess(val guestAccess: GuestAccess) : RoomSettingsAction() - data class SetEncryptToVerifiedDeviceOnly(val enable: Boolean) : RoomSettingsAction() + data class SetEncryptToVerifiedDeviceOnly(val enabled: Boolean) : RoomSettingsAction() object Save : RoomSettingsAction() object Cancel : RoomSettingsAction() diff --git a/vector/src/main/java/im/vector/app/features/roomprofile/settings/RoomSettingsController.kt b/vector/src/main/java/im/vector/app/features/roomprofile/settings/RoomSettingsController.kt index 936ebbd861..04727eca2c 100644 --- a/vector/src/main/java/im/vector/app/features/roomprofile/settings/RoomSettingsController.kt +++ b/vector/src/main/java/im/vector/app/features/roomprofile/settings/RoomSettingsController.kt @@ -154,7 +154,7 @@ class RoomSettingsController @Inject constructor( buildProfileSection(stringProvider.getString(R.string.room_profile_section_security)) data.globalCryptoConfig.invoke()?.let { globalConfig -> - if (globalConfig.globalBlacklistUnverifiedDevices) { + if (globalConfig.globalBlockUnverifiedDevices) { genericFooterItem { id("globalConfig") centered(false) diff --git a/vector/src/main/java/im/vector/app/features/roomprofile/settings/RoomSettingsViewModel.kt b/vector/src/main/java/im/vector/app/features/roomprofile/settings/RoomSettingsViewModel.kt index cb5809d96a..06a859a384 100644 --- a/vector/src/main/java/im/vector/app/features/roomprofile/settings/RoomSettingsViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/roomprofile/settings/RoomSettingsViewModel.kt @@ -252,7 +252,7 @@ class RoomSettingsViewModel @AssistedInject constructor( is RoomSettingsAction.SetRoomGuestAccess -> handleSetGuestAccess(action) is RoomSettingsAction.Save -> saveSettings() is RoomSettingsAction.Cancel -> cancel() - is RoomSettingsAction.SetEncryptToVerifiedDeviceOnly -> setEncryptToVerifiedDeviceOnly(action.enable) + is RoomSettingsAction.SetEncryptToVerifiedDeviceOnly -> setEncryptToVerifiedDeviceOnly(action.enabled) } } @@ -276,7 +276,7 @@ class RoomSettingsViewModel @AssistedInject constructor( private fun setEncryptToVerifiedDeviceOnly(enabled: Boolean) { session.coroutineScope.launch { - session.cryptoService().setRoomBlacklistUnverifiedDevices(room.roomId, enabled) + session.cryptoService().setRoomBlockUnverifiedDevices(room.roomId, enabled) } } From 8c7e7a8f3571beb477b60878ee3c166bed0834cc Mon Sep 17 00:00:00 2001 From: Valere Date: Mon, 3 Oct 2022 14:22:13 +0200 Subject: [PATCH 4/7] open global settings from room settings --- .../features/roomprofile/settings/RoomSettingsController.kt | 2 ++ .../features/roomprofile/settings/RoomSettingsFragment.kt | 5 +++++ 2 files changed, 7 insertions(+) diff --git a/vector/src/main/java/im/vector/app/features/roomprofile/settings/RoomSettingsController.kt b/vector/src/main/java/im/vector/app/features/roomprofile/settings/RoomSettingsController.kt index 04727eca2c..c54c6d5db8 100644 --- a/vector/src/main/java/im/vector/app/features/roomprofile/settings/RoomSettingsController.kt +++ b/vector/src/main/java/im/vector/app/features/roomprofile/settings/RoomSettingsController.kt @@ -56,6 +56,7 @@ class RoomSettingsController @Inject constructor( fun onJoinRuleClicked() fun onToggleGuestAccess() fun setEncryptedToVerifiedDevicesOnly(enabled: Boolean) + fun openGlobalBlockSettings() } var callback: Callback? = null @@ -170,6 +171,7 @@ class RoomSettingsController @Inject constructor( }.toEpoxyCharSequence() ) itemClickAction { + host.callback?.openGlobalBlockSettings() } } } else { diff --git a/vector/src/main/java/im/vector/app/features/roomprofile/settings/RoomSettingsFragment.kt b/vector/src/main/java/im/vector/app/features/roomprofile/settings/RoomSettingsFragment.kt index b7d8f13343..093f146a53 100644 --- a/vector/src/main/java/im/vector/app/features/roomprofile/settings/RoomSettingsFragment.kt +++ b/vector/src/main/java/im/vector/app/features/roomprofile/settings/RoomSettingsFragment.kt @@ -43,6 +43,7 @@ import im.vector.app.core.utils.toast import im.vector.app.databinding.FragmentRoomSettingGenericBinding import im.vector.app.features.analytics.plan.MobileScreen import im.vector.app.features.home.AvatarRenderer +import im.vector.app.features.navigation.SettingsActivityPayload import im.vector.app.features.roomprofile.RoomProfileArgs import im.vector.app.features.roomprofile.RoomProfileSharedActionViewModel import im.vector.app.features.roomprofile.settings.historyvisibility.RoomHistoryVisibilityBottomSheet @@ -203,6 +204,10 @@ class RoomSettingsFragment : viewModel.handle(RoomSettingsAction.SetEncryptToVerifiedDeviceOnly(enabled)) } + override fun openGlobalBlockSettings() { + navigator.openSettings(requireContext(), SettingsActivityPayload.SecurityPrivacy) + } + override fun onImageReady(uri: Uri?) { uri ?: return viewModel.handle( From 8de2fe891740cc1e1da7192c18b5c14aa3af661b Mon Sep 17 00:00:00 2001 From: Valere Date: Tue, 4 Oct 2022 15:59:28 +0200 Subject: [PATCH 5/7] Update library/ui-strings/src/main/res/values/strings.xml Co-authored-by: Benoit Marty --- library/ui-strings/src/main/res/values/strings.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/ui-strings/src/main/res/values/strings.xml b/library/ui-strings/src/main/res/values/strings.xml index cc339f91d9..1126d511b2 100644 --- a/library/ui-strings/src/main/res/values/strings.xml +++ b/library/ui-strings/src/main/res/values/strings.xml @@ -1236,7 +1236,7 @@ Never send encrypted messages to unverified sessions from this session. Never send encrypted messages to unverified sessions in this room. ⚠ There are unverified devices in this room, they won’t be able to decrypt messages you send. - πŸ”’ You have enable encrypt to verified sessions only for all rooms in Security Settings. + πŸ”’ You have enabled encrypt to verified sessions only for all rooms in Security Settings. %1$d/%2$d key imported with success. %1$d/%2$d keys imported with success. From 68d4ac34c75149d9e1a5d8cd28ebae33dba8b74f Mon Sep 17 00:00:00 2001 From: Valere Date: Tue, 4 Oct 2022 17:17:01 +0200 Subject: [PATCH 6/7] Move setting to room profile --- .../src/main/res/values/strings.xml | 2 +- .../sdk/api/session/crypto/CryptoService.kt | 2 +- .../internal/crypto/DefaultCryptoService.kt | 6 +- .../algorithms/megolm/MXMegolmEncryption.kt | 2 +- .../internal/crypto/store/IMXCryptoStore.kt | 4 +- .../crypto/store/db/RealmCryptoStore.kt | 4 +- .../features/roomprofile/RoomProfileAction.kt | 1 + .../roomprofile/RoomProfileController.kt | 50 +++++++++ .../roomprofile/RoomProfileFragment.kt | 9 ++ .../roomprofile/RoomProfileViewModel.kt | 51 +++++++++ .../roomprofile/RoomProfileViewState.kt | 4 + .../settings/RoomSettingsAction.kt | 1 - .../settings/RoomSettingsController.kt | 101 +++++++++--------- .../settings/RoomSettingsFragment.kt | 9 -- .../settings/RoomSettingsViewModel.kt | 47 -------- .../settings/RoomSettingsViewState.kt | 4 - 16 files changed, 173 insertions(+), 124 deletions(-) diff --git a/library/ui-strings/src/main/res/values/strings.xml b/library/ui-strings/src/main/res/values/strings.xml index 1126d511b2..5ddcbf324f 100644 --- a/library/ui-strings/src/main/res/values/strings.xml +++ b/library/ui-strings/src/main/res/values/strings.xml @@ -1236,7 +1236,7 @@ Never send encrypted messages to unverified sessions from this session. Never send encrypted messages to unverified sessions in this room. ⚠ There are unverified devices in this room, they won’t be able to decrypt messages you send. - πŸ”’ You have enabled encrypt to verified sessions only for all rooms in Security Settings. + πŸ”’ You have enabled encrypt to verified sessions only for all rooms in Security Settings. %1$d/%2$d key imported with success. %1$d/%2$d keys imported with success. diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/crypto/CryptoService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/crypto/CryptoService.kt index c383e05707..d2aa8020e8 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/crypto/CryptoService.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/crypto/CryptoService.kt @@ -61,7 +61,7 @@ interface CryptoService { fun isRoomBlacklistUnverifiedDevices(roomId: String?): Boolean - fun getLiveBlacklistUnverifiedDevices(roomId: String): LiveData + fun getLiveBlockUnverifiedDevices(roomId: String): LiveData fun setWarnOnUnknownDevices(warn: Boolean) 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 4a160f07b2..9c3e0ba1c5 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 @@ -1177,7 +1177,7 @@ internal class DefaultCryptoService @Inject constructor( * @return true if the client should encrypt messages only for the verified devices. */ override fun isRoomBlacklistUnverifiedDevices(roomId: String?): Boolean { - return roomId?.let { cryptoStore.getBlacklistUnverifiedDevices(roomId) } + return roomId?.let { cryptoStore.getBlockUnverifiedDevices(roomId) } ?: false } @@ -1186,8 +1186,8 @@ internal class DefaultCryptoService @Inject constructor( * * @return Live status */ - override fun getLiveBlacklistUnverifiedDevices(roomId: String): LiveData { - return cryptoStore.getLiveBlacklistUnverifiedDevices(roomId) + override fun getLiveBlockUnverifiedDevices(roomId: String): LiveData { + return cryptoStore.getLiveBlockUnverifiedDevices(roomId) } /** diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/algorithms/megolm/MXMegolmEncryption.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/algorithms/megolm/MXMegolmEncryption.kt index e19e513b63..7b6051932a 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/algorithms/megolm/MXMegolmEncryption.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/algorithms/megolm/MXMegolmEncryption.kt @@ -424,7 +424,7 @@ internal class MXMegolmEncryption( // an m.new_device. val keys = deviceListManager.downloadKeys(userIds, false) val encryptToVerifiedDevicesOnly = cryptoStore.getGlobalBlacklistUnverifiedDevices() || - cryptoStore.getBlacklistUnverifiedDevices(roomId) + cryptoStore.getBlockUnverifiedDevices(roomId) val devicesInRoom = DeviceInRoomInfo() val unknownDevices = MXUsersDevicesMap() 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 7c5dd6c585..21e3342365 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 @@ -125,14 +125,14 @@ internal interface IMXCryptoStore { * * @return Live status */ - fun getLiveBlacklistUnverifiedDevices(roomId: String): LiveData + fun getLiveBlockUnverifiedDevices(roomId: String): LiveData /** * Tell if unverified devices should be blacklisted when sending keys. * * @return true if should not send keys to unverified devices */ - fun getBlacklistUnverifiedDevices(roomId: String): Boolean + fun getBlockUnverifiedDevices(roomId: String): Boolean /** * Define if encryption keys should be sent to unverified devices in this room. 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 81a4a9d427..e97cf437c6 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 @@ -1097,7 +1097,7 @@ internal class RealmCryptoStore @Inject constructor( } } - override fun getLiveBlacklistUnverifiedDevices(roomId: String): LiveData { + override fun getLiveBlockUnverifiedDevices(roomId: String): LiveData { val liveData = monarchy.findAllMappedWithChanges( { realm: Realm -> realm.where() @@ -1112,7 +1112,7 @@ internal class RealmCryptoStore @Inject constructor( } } - override fun getBlacklistUnverifiedDevices(roomId: String): Boolean { + override fun getBlockUnverifiedDevices(roomId: String): Boolean { return doWithRealm(realmConfiguration) { realm -> realm.where() .equalTo(CryptoRoomEntityFields.ROOM_ID, roomId) diff --git a/vector/src/main/java/im/vector/app/features/roomprofile/RoomProfileAction.kt b/vector/src/main/java/im/vector/app/features/roomprofile/RoomProfileAction.kt index 22b040b4c0..44bac1c8a0 100644 --- a/vector/src/main/java/im/vector/app/features/roomprofile/RoomProfileAction.kt +++ b/vector/src/main/java/im/vector/app/features/roomprofile/RoomProfileAction.kt @@ -27,4 +27,5 @@ sealed class RoomProfileAction : VectorViewModelAction { object ShareRoomProfile : RoomProfileAction() object CreateShortcut : RoomProfileAction() object RestoreEncryptionState : RoomProfileAction() + data class SetEncryptToVerifiedDeviceOnly(val enabled: Boolean) : RoomProfileAction() } diff --git a/vector/src/main/java/im/vector/app/features/roomprofile/RoomProfileController.kt b/vector/src/main/java/im/vector/app/features/roomprofile/RoomProfileController.kt index 06f56bff89..eb43a345f2 100644 --- a/vector/src/main/java/im/vector/app/features/roomprofile/RoomProfileController.kt +++ b/vector/src/main/java/im/vector/app/features/roomprofile/RoomProfileController.kt @@ -27,6 +27,7 @@ import im.vector.app.core.resources.DrawableProvider import im.vector.app.core.resources.StringProvider import im.vector.app.core.ui.list.genericFooterItem import im.vector.app.core.ui.list.genericPositiveButtonItem +import im.vector.app.features.form.formSwitchItem import im.vector.app.features.home.ShortcutCreator import im.vector.app.features.home.room.detail.timeline.TimelineEventController import im.vector.app.features.home.room.detail.timeline.tools.createLinkMovementMethod @@ -66,6 +67,8 @@ class RoomProfileController @Inject constructor( fun onUrlInTopicLongClicked(url: String) fun doMigrateToVersion(newVersion: String) fun restoreEncryptionState() + fun setEncryptedToVerifiedDevicesOnly(enabled: Boolean) + fun openGlobalBlockSettings() } override fun buildModels(data: RoomProfileViewState?) { @@ -175,6 +178,53 @@ class RoomProfileController @Inject constructor( } buildEncryptionAction(data.actionPermissions, roomSummary) + if (roomSummary.isEncrypted && !encryptionMisconfigured) { + data.globalCryptoConfig.invoke()?.let { globalConfig -> + if (globalConfig.globalBlockUnverifiedDevices) { + genericFooterItem { + id("globalConfig") + centered(false) + text( + span { + +host.stringProvider.getString(R.string.room_settings_global_block_unverified_info_text) + apply { + if (data.unverifiedDevicesInTheRoom.invoke() == true) { + +"\n" + +host.stringProvider.getString(R.string.some_devices_will_not_be_able_to_decrypt) + } + } + }.toEpoxyCharSequence() + ) + itemClickAction { + host.callback?.openGlobalBlockSettings() + } + } + } else { + // per room setting is available + val shouldBlockUnverified = data.encryptToVerifiedDeviceOnly.invoke() + formSwitchItem { + id("send_to_unverified") + enabled(shouldBlockUnverified != null) + title(host.stringProvider.getString(R.string.encryption_never_send_to_unverified_devices_in_room)) + + switchChecked(shouldBlockUnverified ?: false) + + apply { + if (shouldBlockUnverified == true && data.unverifiedDevicesInTheRoom.invoke() == true) { + summary( + host.stringProvider.getString(R.string.some_devices_will_not_be_able_to_decrypt) + ) + } else { + summary(null) + } + } + listener { value -> + host.callback?.setEncryptedToVerifiedDevicesOnly(value) + } + } + } + } + } // More buildProfileSection(stringProvider.getString(R.string.room_profile_section_more)) buildProfileAction( diff --git a/vector/src/main/java/im/vector/app/features/roomprofile/RoomProfileFragment.kt b/vector/src/main/java/im/vector/app/features/roomprofile/RoomProfileFragment.kt index 4135ab3d1c..f4394111ab 100644 --- a/vector/src/main/java/im/vector/app/features/roomprofile/RoomProfileFragment.kt +++ b/vector/src/main/java/im/vector/app/features/roomprofile/RoomProfileFragment.kt @@ -53,6 +53,7 @@ import im.vector.app.features.home.room.detail.RoomDetailPendingActionStore import im.vector.app.features.home.room.detail.upgrade.MigrateRoomBottomSheet import im.vector.app.features.home.room.list.actions.RoomListQuickActionsSharedAction import im.vector.app.features.home.room.list.actions.RoomListQuickActionsSharedActionViewModel +import im.vector.app.features.navigation.SettingsActivityPayload import kotlinx.coroutines.flow.launchIn import kotlinx.coroutines.flow.onEach import kotlinx.parcelize.Parcelize @@ -346,6 +347,14 @@ class RoomProfileFragment : ) } + override fun setEncryptedToVerifiedDevicesOnly(enabled: Boolean) { + roomProfileViewModel.handle(RoomProfileAction.SetEncryptToVerifiedDeviceOnly(enabled)) + } + + override fun openGlobalBlockSettings() { + navigator.openSettings(requireContext(), SettingsActivityPayload.SecurityPrivacy) + } + private fun onAvatarClicked(view: View) = withState(roomProfileViewModel) { state -> state.roomSummary()?.toMatrixItem()?.let { matrixItem -> navigator.openBigImageViewer(requireActivity(), view, matrixItem) diff --git a/vector/src/main/java/im/vector/app/features/roomprofile/RoomProfileViewModel.kt b/vector/src/main/java/im/vector/app/features/roomprofile/RoomProfileViewModel.kt index 30664c5618..215a1e1e9c 100644 --- a/vector/src/main/java/im/vector/app/features/roomprofile/RoomProfileViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/roomprofile/RoomProfileViewModel.kt @@ -17,6 +17,7 @@ package im.vector.app.features.roomprofile +import androidx.lifecycle.asFlow import com.airbnb.mvrx.MavericksViewModelFactory import dagger.assisted.Assisted import dagger.assisted.AssistedFactory @@ -32,7 +33,11 @@ import im.vector.app.features.home.ShortcutCreator import im.vector.app.features.powerlevel.PowerLevelsFlowFactory import im.vector.app.features.session.coroutineScope import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.flow.combine +import kotlinx.coroutines.flow.flatMapLatest +import kotlinx.coroutines.flow.flowOf import kotlinx.coroutines.flow.launchIn +import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.onEach import kotlinx.coroutines.launch import org.matrix.android.sdk.api.query.QueryStringValue @@ -76,6 +81,45 @@ class RoomProfileViewModel @AssistedInject constructor( observeBannedRoomMembers(flowRoom) observePermissions() observePowerLevels() + observeCryptoSettings(flowRoom) + } + + private fun observeCryptoSettings(flowRoom: FlowRoom) { + val perRoomBlockStatus = session.cryptoService().getLiveBlockUnverifiedDevices(initialState.roomId) + .asFlow() + + perRoomBlockStatus + .execute { + copy(encryptToVerifiedDeviceOnly = it) + } + + val globalBlockStatus = session.cryptoService().getLiveGlobalCryptoConfig() + .asFlow() + + globalBlockStatus + .execute { + copy(globalCryptoConfig = it) + } + + perRoomBlockStatus.combine(globalBlockStatus) { perRoom, global -> + perRoom || global.globalBlockUnverifiedDevices + }.flatMapLatest { + if (it) { + flowRoom.liveRoomMembers(roomMemberQueryParams { memberships = Membership.activeMemberships() }) + .map { it.map { it.userId } } + .flatMapLatest { + session.cryptoService().getLiveCryptoDeviceInfo(it).asFlow() + } + } else { + flowOf(emptyList()) + } + }.map { + it.isNotEmpty() + }.execute { + copy( + unverifiedDevicesInTheRoom = it + ) + } } private fun observePowerLevels() { @@ -141,6 +185,7 @@ class RoomProfileViewModel @AssistedInject constructor( is RoomProfileAction.ShareRoomProfile -> handleShareRoomProfile() RoomProfileAction.CreateShortcut -> handleCreateShortcut() RoomProfileAction.RestoreEncryptionState -> restoreEncryptionState() + is RoomProfileAction.SetEncryptToVerifiedDeviceOnly -> setEncryptToVerifiedDeviceOnly(action.enabled) } } @@ -212,6 +257,12 @@ class RoomProfileViewModel @AssistedInject constructor( } } + private fun setEncryptToVerifiedDeviceOnly(enabled: Boolean) { + session.coroutineScope.launch { + session.cryptoService().setRoomBlockUnverifiedDevices(room.roomId, enabled) + } + } + private fun restoreEncryptionState() { _viewEvents.post(RoomProfileViewEvents.Loading()) session.coroutineScope.launch { diff --git a/vector/src/main/java/im/vector/app/features/roomprofile/RoomProfileViewState.kt b/vector/src/main/java/im/vector/app/features/roomprofile/RoomProfileViewState.kt index c457a01750..5393ceb152 100644 --- a/vector/src/main/java/im/vector/app/features/roomprofile/RoomProfileViewState.kt +++ b/vector/src/main/java/im/vector/app/features/roomprofile/RoomProfileViewState.kt @@ -20,6 +20,7 @@ package im.vector.app.features.roomprofile import com.airbnb.mvrx.Async import com.airbnb.mvrx.MavericksState import com.airbnb.mvrx.Uninitialized +import org.matrix.android.sdk.api.session.crypto.GlobalCryptoConfig import org.matrix.android.sdk.api.session.room.model.RoomMemberSummary import org.matrix.android.sdk.api.session.room.model.RoomSummary import org.matrix.android.sdk.api.session.room.model.create.RoomCreateContent @@ -36,6 +37,9 @@ data class RoomProfileViewState( val canUpgradeRoom: Boolean = false, val isTombstoned: Boolean = false, val canUpdateRoomState: Boolean = false, + val encryptToVerifiedDeviceOnly: Async = Uninitialized, + val globalCryptoConfig: Async = Uninitialized, + val unverifiedDevicesInTheRoom: Async = Uninitialized, ) : MavericksState { constructor(args: RoomProfileArgs) : this(roomId = args.roomId) diff --git a/vector/src/main/java/im/vector/app/features/roomprofile/settings/RoomSettingsAction.kt b/vector/src/main/java/im/vector/app/features/roomprofile/settings/RoomSettingsAction.kt index 13662c1f9b..eb601605e0 100644 --- a/vector/src/main/java/im/vector/app/features/roomprofile/settings/RoomSettingsAction.kt +++ b/vector/src/main/java/im/vector/app/features/roomprofile/settings/RoomSettingsAction.kt @@ -28,7 +28,6 @@ sealed class RoomSettingsAction : VectorViewModelAction { data class SetRoomHistoryVisibility(val visibility: RoomHistoryVisibility) : RoomSettingsAction() data class SetRoomJoinRule(val roomJoinRule: RoomJoinRules) : RoomSettingsAction() data class SetRoomGuestAccess(val guestAccess: GuestAccess) : RoomSettingsAction() - data class SetEncryptToVerifiedDeviceOnly(val enabled: Boolean) : RoomSettingsAction() object Save : RoomSettingsAction() object Cancel : RoomSettingsAction() diff --git a/vector/src/main/java/im/vector/app/features/roomprofile/settings/RoomSettingsController.kt b/vector/src/main/java/im/vector/app/features/roomprofile/settings/RoomSettingsController.kt index c54c6d5db8..91d6ac76ed 100644 --- a/vector/src/main/java/im/vector/app/features/roomprofile/settings/RoomSettingsController.kt +++ b/vector/src/main/java/im/vector/app/features/roomprofile/settings/RoomSettingsController.kt @@ -22,7 +22,6 @@ import im.vector.app.core.epoxy.dividerItem import im.vector.app.core.epoxy.profiles.buildProfileAction import im.vector.app.core.epoxy.profiles.buildProfileSection import im.vector.app.core.resources.StringProvider -import im.vector.app.core.ui.list.genericFooterItem import im.vector.app.core.ui.list.verticalMarginItem import im.vector.app.core.utils.DimensionConverter import im.vector.app.features.form.formEditTextItem @@ -31,8 +30,6 @@ import im.vector.app.features.form.formSwitchItem import im.vector.app.features.home.AvatarRenderer import im.vector.app.features.home.room.detail.timeline.format.RoomHistoryVisibilityFormatter import im.vector.app.features.settings.VectorPreferences -import im.vector.lib.core.utils.epoxy.charsequence.toEpoxyCharSequence -import me.gujun.android.span.span import org.matrix.android.sdk.api.session.room.model.GuestAccess import org.matrix.android.sdk.api.session.room.model.RoomJoinRules import org.matrix.android.sdk.api.util.toMatrixItem @@ -55,8 +52,6 @@ class RoomSettingsController @Inject constructor( fun onHistoryVisibilityClicked() fun onJoinRuleClicked() fun onToggleGuestAccess() - fun setEncryptedToVerifiedDevicesOnly(enabled: Boolean) - fun openGlobalBlockSettings() } var callback: Callback? = null @@ -150,54 +145,54 @@ class RoomSettingsController @Inject constructor( id("guestAccessDivider") } } +// +// // Security +// buildProfileSection(stringProvider.getString(R.string.room_profile_section_security)) - // Security - buildProfileSection(stringProvider.getString(R.string.room_profile_section_security)) - - data.globalCryptoConfig.invoke()?.let { globalConfig -> - if (globalConfig.globalBlockUnverifiedDevices) { - genericFooterItem { - id("globalConfig") - centered(false) - text( - span { - +host.stringProvider.getString(R.string.room_settings_global_blacklist_unverified_info_text) - apply { - if (data.unverifiedDevicesInTheRoom.invoke() == true) { - +"\n" - +host.stringProvider.getString(R.string.some_devices_will_not_be_able_to_decrypt) - } - } - }.toEpoxyCharSequence() - ) - itemClickAction { - host.callback?.openGlobalBlockSettings() - } - } - } else { - // per room setting is available - val shouldBlockUnverified = data.encryptToVerifiedDeviceOnly.invoke() - formSwitchItem { - id("send_to_unverified") - enabled(shouldBlockUnverified != null) - title(host.stringProvider.getString(R.string.encryption_never_send_to_unverified_devices_in_room)) - - switchChecked(shouldBlockUnverified ?: false) - - apply { - if (shouldBlockUnverified == true && data.unverifiedDevicesInTheRoom.invoke() == true) { - summary( - host.stringProvider.getString(R.string.some_devices_will_not_be_able_to_decrypt) - ) - } else { - summary(null) - } - } - listener { value -> - host.callback?.setEncryptedToVerifiedDevicesOnly(value) - } - } - } - } +// data.globalCryptoConfig.invoke()?.let { globalConfig -> +// if (globalConfig.globalBlockUnverifiedDevices) { +// genericFooterItem { +// id("globalConfig") +// centered(false) +// text( +// span { +// +host.stringProvider.getString(R.string.room_settings_global_block_unverified_info_text) +// apply { +// if (data.unverifiedDevicesInTheRoom.invoke() == true) { +// +"\n" +// +host.stringProvider.getString(R.string.some_devices_will_not_be_able_to_decrypt) +// } +// } +// }.toEpoxyCharSequence() +// ) +// itemClickAction { +// host.callback?.openGlobalBlockSettings() +// } +// } +// } else { +// // per room setting is available +// val shouldBlockUnverified = data.encryptToVerifiedDeviceOnly.invoke() +// formSwitchItem { +// id("send_to_unverified") +// enabled(shouldBlockUnverified != null) +// title(host.stringProvider.getString(R.string.encryption_never_send_to_unverified_devices_in_room)) +// +// switchChecked(shouldBlockUnverified ?: false) +// +// apply { +// if (shouldBlockUnverified == true && data.unverifiedDevicesInTheRoom.invoke() == true) { +// summary( +// host.stringProvider.getString(R.string.some_devices_will_not_be_able_to_decrypt) +// ) +// } else { +// summary(null) +// } +// } +// listener { value -> +// host.callback?.setEncryptedToVerifiedDevicesOnly(value) +// } +// } +// } +// } } } diff --git a/vector/src/main/java/im/vector/app/features/roomprofile/settings/RoomSettingsFragment.kt b/vector/src/main/java/im/vector/app/features/roomprofile/settings/RoomSettingsFragment.kt index 093f146a53..ba50890db3 100644 --- a/vector/src/main/java/im/vector/app/features/roomprofile/settings/RoomSettingsFragment.kt +++ b/vector/src/main/java/im/vector/app/features/roomprofile/settings/RoomSettingsFragment.kt @@ -43,7 +43,6 @@ import im.vector.app.core.utils.toast import im.vector.app.databinding.FragmentRoomSettingGenericBinding import im.vector.app.features.analytics.plan.MobileScreen import im.vector.app.features.home.AvatarRenderer -import im.vector.app.features.navigation.SettingsActivityPayload import im.vector.app.features.roomprofile.RoomProfileArgs import im.vector.app.features.roomprofile.RoomProfileSharedActionViewModel import im.vector.app.features.roomprofile.settings.historyvisibility.RoomHistoryVisibilityBottomSheet @@ -200,14 +199,6 @@ class RoomSettingsFragment : viewModel.handle(RoomSettingsAction.SetRoomGuestAccess(toggled)) } - override fun setEncryptedToVerifiedDevicesOnly(enabled: Boolean) { - viewModel.handle(RoomSettingsAction.SetEncryptToVerifiedDeviceOnly(enabled)) - } - - override fun openGlobalBlockSettings() { - navigator.openSettings(requireContext(), SettingsActivityPayload.SecurityPrivacy) - } - override fun onImageReady(uri: Uri?) { uri ?: return viewModel.handle( diff --git a/vector/src/main/java/im/vector/app/features/roomprofile/settings/RoomSettingsViewModel.kt b/vector/src/main/java/im/vector/app/features/roomprofile/settings/RoomSettingsViewModel.kt index 06a859a384..501ff7553a 100644 --- a/vector/src/main/java/im/vector/app/features/roomprofile/settings/RoomSettingsViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/roomprofile/settings/RoomSettingsViewModel.kt @@ -17,7 +17,6 @@ package im.vector.app.features.roomprofile.settings import androidx.core.net.toFile -import androidx.lifecycle.asFlow import com.airbnb.mvrx.MavericksViewModelFactory import dagger.assisted.Assisted import dagger.assisted.AssistedFactory @@ -26,12 +25,8 @@ import im.vector.app.core.di.MavericksAssistedViewModelFactory import im.vector.app.core.di.hiltMavericksViewModelFactory import im.vector.app.core.platform.VectorViewModel import im.vector.app.features.powerlevel.PowerLevelsFlowFactory -import im.vector.app.features.session.coroutineScope import im.vector.app.features.settings.VectorPreferences -import kotlinx.coroutines.flow.flatMapLatest -import kotlinx.coroutines.flow.flowOf import kotlinx.coroutines.flow.launchIn -import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.mapNotNull import kotlinx.coroutines.flow.onEach import kotlinx.coroutines.launch @@ -42,8 +37,6 @@ import org.matrix.android.sdk.api.session.events.model.EventType import org.matrix.android.sdk.api.session.events.model.toModel import org.matrix.android.sdk.api.session.getRoom import org.matrix.android.sdk.api.session.homeserver.HomeServerCapabilities -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.RoomAvatarContent import org.matrix.android.sdk.api.session.room.model.RoomGuestAccessContent import org.matrix.android.sdk.api.session.room.model.RoomHistoryVisibilityContent @@ -90,39 +83,6 @@ class RoomSettingsViewModel @AssistedInject constructor( canUpgradeToRestricted = couldUpgradeToRestricted ) } - - session.cryptoService().getLiveBlacklistUnverifiedDevices(initialState.roomId) - .asFlow() - .execute { - copy(encryptToVerifiedDeviceOnly = it) - } - - session.cryptoService().getLiveGlobalCryptoConfig() - .asFlow() - .execute { - copy(globalCryptoConfig = it) - } - - val flowRoom = room.flow() - session.cryptoService().getLiveBlacklistUnverifiedDevices(initialState.roomId) - .asFlow() - .flatMapLatest { - if (it) { - flowRoom.liveRoomMembers(roomMemberQueryParams { memberships = Membership.activeMemberships() }) - .map { it.map { it.userId } } - .flatMapLatest { - session.cryptoService().getLiveCryptoDeviceInfo(it).asFlow() - } - } else { - flowOf(emptyList()) - } - }.map { - it.isNotEmpty() - }.execute { - copy( - unverifiedDevicesInTheRoom = it - ) - } } private fun observeState() { @@ -252,7 +212,6 @@ class RoomSettingsViewModel @AssistedInject constructor( is RoomSettingsAction.SetRoomGuestAccess -> handleSetGuestAccess(action) is RoomSettingsAction.Save -> saveSettings() is RoomSettingsAction.Cancel -> cancel() - is RoomSettingsAction.SetEncryptToVerifiedDeviceOnly -> setEncryptToVerifiedDeviceOnly(action.enabled) } } @@ -274,12 +233,6 @@ class RoomSettingsViewModel @AssistedInject constructor( } } - private fun setEncryptToVerifiedDeviceOnly(enabled: Boolean) { - session.coroutineScope.launch { - session.cryptoService().setRoomBlockUnverifiedDevices(room.roomId, enabled) - } - } - private fun handleSetAvatarAction(action: RoomSettingsAction.SetAvatarAction) { setState { deletePendingAvatar(this) diff --git a/vector/src/main/java/im/vector/app/features/roomprofile/settings/RoomSettingsViewState.kt b/vector/src/main/java/im/vector/app/features/roomprofile/settings/RoomSettingsViewState.kt index 26f4c6bdad..10465b03ea 100644 --- a/vector/src/main/java/im/vector/app/features/roomprofile/settings/RoomSettingsViewState.kt +++ b/vector/src/main/java/im/vector/app/features/roomprofile/settings/RoomSettingsViewState.kt @@ -23,7 +23,6 @@ import com.airbnb.mvrx.Uninitialized import im.vector.app.R import im.vector.app.core.resources.StringProvider import im.vector.app.features.roomprofile.RoomProfileArgs -import org.matrix.android.sdk.api.session.crypto.GlobalCryptoConfig import org.matrix.android.sdk.api.session.room.model.GuestAccess import org.matrix.android.sdk.api.session.room.model.RoomHistoryVisibility import org.matrix.android.sdk.api.session.room.model.RoomJoinRules @@ -47,9 +46,6 @@ data class RoomSettingsViewState( val actionPermissions: ActionPermissions = ActionPermissions(), val supportsRestricted: Boolean = false, val canUpgradeToRestricted: Boolean = false, - val encryptToVerifiedDeviceOnly: Async = Uninitialized, - val globalCryptoConfig: Async = Uninitialized, - val unverifiedDevicesInTheRoom: Async = Uninitialized, ) : MavericksState { constructor(args: RoomProfileArgs) : this(roomId = args.roomId) From b567fc5be6e78b213d8abf03da576c3acb522daa Mon Sep 17 00:00:00 2001 From: Valere Date: Tue, 4 Oct 2022 19:03:16 +0200 Subject: [PATCH 7/7] remove commented code --- .../settings/RoomSettingsController.kt | 49 ------------------- 1 file changed, 49 deletions(-) diff --git a/vector/src/main/java/im/vector/app/features/roomprofile/settings/RoomSettingsController.kt b/vector/src/main/java/im/vector/app/features/roomprofile/settings/RoomSettingsController.kt index 91d6ac76ed..f8efe73ebf 100644 --- a/vector/src/main/java/im/vector/app/features/roomprofile/settings/RoomSettingsController.kt +++ b/vector/src/main/java/im/vector/app/features/roomprofile/settings/RoomSettingsController.kt @@ -145,54 +145,5 @@ class RoomSettingsController @Inject constructor( id("guestAccessDivider") } } -// -// // Security -// buildProfileSection(stringProvider.getString(R.string.room_profile_section_security)) - -// data.globalCryptoConfig.invoke()?.let { globalConfig -> -// if (globalConfig.globalBlockUnverifiedDevices) { -// genericFooterItem { -// id("globalConfig") -// centered(false) -// text( -// span { -// +host.stringProvider.getString(R.string.room_settings_global_block_unverified_info_text) -// apply { -// if (data.unverifiedDevicesInTheRoom.invoke() == true) { -// +"\n" -// +host.stringProvider.getString(R.string.some_devices_will_not_be_able_to_decrypt) -// } -// } -// }.toEpoxyCharSequence() -// ) -// itemClickAction { -// host.callback?.openGlobalBlockSettings() -// } -// } -// } else { -// // per room setting is available -// val shouldBlockUnverified = data.encryptToVerifiedDeviceOnly.invoke() -// formSwitchItem { -// id("send_to_unverified") -// enabled(shouldBlockUnverified != null) -// title(host.stringProvider.getString(R.string.encryption_never_send_to_unverified_devices_in_room)) -// -// switchChecked(shouldBlockUnverified ?: false) -// -// apply { -// if (shouldBlockUnverified == true && data.unverifiedDevicesInTheRoom.invoke() == true) { -// summary( -// host.stringProvider.getString(R.string.some_devices_will_not_be_able_to_decrypt) -// ) -// } else { -// summary(null) -// } -// } -// listener { value -> -// host.callback?.setEncryptedToVerifiedDevicesOnly(value) -// } -// } -// } -// } } }