diff --git a/changelog.d/7733.bugfix b/changelog.d/7733.bugfix new file mode 100644 index 0000000000..9de3759f1a --- /dev/null +++ b/changelog.d/7733.bugfix @@ -0,0 +1 @@ +[Session manager] Sessions without encryption support should not prompt to verify diff --git a/library/ui-strings/src/main/res/values/strings.xml b/library/ui-strings/src/main/res/values/strings.xml index 7f11e63469..0ab1d85f0f 100644 --- a/library/ui-strings/src/main/res/values/strings.xml +++ b/library/ui-strings/src/main/res/values/strings.xml @@ -3308,6 +3308,7 @@ Verify your current session for enhanced secure messaging. Verify or sign out from this session for best security and reliability. Verify your current session to reveal this session\'s verification status. + This session doesn\'t support encryption and thus can\'t be verified. Verify Session View Details View All (%1$d) @@ -3400,6 +3401,7 @@ Verified sessions have logged in with your credentials and then been verified, either using your secure passphrase or by cross-verifying.\n\nThis means they hold encryption keys for your previous messages, and confirm to other users you are communicating with that these sessions are really you. Verified sessions are anywhere you are using this account after entering your passphrase or confirming your identity with another verified session.\n\nThis means that you have all the keys needed to unlock your encrypted messages and confirm to other users that you trust this session. + This session doesn\'t support encryption, so it can\'t be verified.\n\nYou won\'t be able to participate in rooms where encryption is enabled when using this session.\n\nFor best security and privacy, it is recommended to use Matrix clients that support encryption. Renaming sessions Other users in direct messages and rooms that you join are able to view a full list of your sessions.\n\nThis provides them with confidence that they are really speaking to you, but it also means they can see the session name you enter here. Enable new session manager diff --git a/vector/src/main/java/im/vector/app/core/ui/views/ShieldImageView.kt b/vector/src/main/java/im/vector/app/core/ui/views/ShieldImageView.kt index 0570bbe4d7..34714d97d0 100644 --- a/vector/src/main/java/im/vector/app/core/ui/views/ShieldImageView.kt +++ b/vector/src/main/java/im/vector/app/core/ui/views/ShieldImageView.kt @@ -40,20 +40,26 @@ class ShieldImageView @JvmOverloads constructor( /** * Renders device shield with the support of unknown shields instead of black shields which is used for rooms. - * @param roomEncryptionTrustLevel trust level that is usally calculated with [im.vector.app.features.settings.devices.TrustUtils.shieldForTrust] + * @param roomEncryptionTrustLevel trust level that is usually calculated with [im.vector.app.features.settings.devices.TrustUtils.shieldForTrust] * @param borderLess if true then the shield icon with border around is used */ fun renderDeviceShield(roomEncryptionTrustLevel: RoomEncryptionTrustLevel?, borderLess: Boolean = false) { - isVisible = roomEncryptionTrustLevel != null - - if (roomEncryptionTrustLevel == RoomEncryptionTrustLevel.Default) { - contentDescription = context.getString(R.string.a11y_trust_level_default) - setImageResource( - if (borderLess) R.drawable.ic_shield_unknown_no_border - else R.drawable.ic_shield_unknown - ) - } else { - render(roomEncryptionTrustLevel, borderLess) + when (roomEncryptionTrustLevel) { + null -> { + contentDescription = context.getString(R.string.a11y_trust_level_warning) + setImageResource( + if (borderLess) R.drawable.ic_shield_warning_no_border + else R.drawable.ic_shield_warning + ) + } + RoomEncryptionTrustLevel.Default -> { + contentDescription = context.getString(R.string.a11y_trust_level_default) + setImageResource( + if (borderLess) R.drawable.ic_shield_unknown_no_border + else R.drawable.ic_shield_unknown + ) + } + else -> render(roomEncryptionTrustLevel, borderLess) } } diff --git a/vector/src/main/java/im/vector/app/features/home/UnknownDeviceDetectorSharedViewModel.kt b/vector/src/main/java/im/vector/app/features/home/UnknownDeviceDetectorSharedViewModel.kt index 21c7bd6ea1..347c16653d 100644 --- a/vector/src/main/java/im/vector/app/features/home/UnknownDeviceDetectorSharedViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/home/UnknownDeviceDetectorSharedViewModel.kt @@ -104,7 +104,7 @@ class UnknownDeviceDetectorSharedViewModel @AssistedInject constructor( // Timber.v("## Detector trigger canCrossSign ${pInfo.get().selfSigned != null}") infoList .filter { info -> - // filter verified session, by checking the crypto device info + // filter out verified sessions or those which do not support encryption (i.e. without crypto info) cryptoList.firstOrNull { info.deviceId == it.deviceId }?.isVerified?.not().orFalse() } // filter out ignored devices diff --git a/vector/src/main/java/im/vector/app/features/settings/devices/DevicesViewModel.kt b/vector/src/main/java/im/vector/app/features/settings/devices/DevicesViewModel.kt index 67b41ea5aa..e779948b41 100644 --- a/vector/src/main/java/im/vector/app/features/settings/devices/DevicesViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/settings/devices/DevicesViewModel.kt @@ -88,7 +88,7 @@ data class DevicesViewState( data class DeviceFullInfo( val deviceInfo: DeviceInfo, val cryptoDeviceInfo: CryptoDeviceInfo?, - val trustLevelForShield: RoomEncryptionTrustLevel, + val trustLevelForShield: RoomEncryptionTrustLevel?, val isInactive: Boolean, ) diff --git a/vector/src/main/java/im/vector/app/features/settings/devices/v2/DeviceFullInfo.kt b/vector/src/main/java/im/vector/app/features/settings/devices/v2/DeviceFullInfo.kt index 4864c41394..186a6ebe69 100644 --- a/vector/src/main/java/im/vector/app/features/settings/devices/v2/DeviceFullInfo.kt +++ b/vector/src/main/java/im/vector/app/features/settings/devices/v2/DeviceFullInfo.kt @@ -25,7 +25,7 @@ import org.matrix.android.sdk.api.session.crypto.model.RoomEncryptionTrustLevel data class DeviceFullInfo( val deviceInfo: DeviceInfo, val cryptoDeviceInfo: CryptoDeviceInfo?, - val roomEncryptionTrustLevel: RoomEncryptionTrustLevel, + val roomEncryptionTrustLevel: RoomEncryptionTrustLevel?, val isInactive: Boolean, val isCurrentDevice: Boolean, val deviceExtendedInfo: DeviceExtendedInfo, diff --git a/vector/src/main/java/im/vector/app/features/settings/devices/v2/list/SessionInfoView.kt b/vector/src/main/java/im/vector/app/features/settings/devices/v2/list/SessionInfoView.kt index 7727cee4fa..eecec72b0a 100644 --- a/vector/src/main/java/im/vector/app/features/settings/devices/v2/list/SessionInfoView.kt +++ b/vector/src/main/java/im/vector/app/features/settings/devices/v2/list/SessionInfoView.kt @@ -85,13 +85,14 @@ class SessionInfoView @JvmOverloads constructor( } private fun renderVerificationStatus( - encryptionTrustLevel: RoomEncryptionTrustLevel, + encryptionTrustLevel: RoomEncryptionTrustLevel?, isCurrentSession: Boolean, hasLearnMoreLink: Boolean, isVerifyButtonVisible: Boolean, ) { views.sessionInfoVerificationStatusImageView.renderDeviceShield(encryptionTrustLevel) when { + encryptionTrustLevel == null -> renderCrossSigningEncryptionNotSupported() encryptionTrustLevel == RoomEncryptionTrustLevel.Trusted -> renderCrossSigningVerified(isCurrentSession) encryptionTrustLevel == RoomEncryptionTrustLevel.Default && !isCurrentSession -> renderCrossSigningUnknown() else -> renderCrossSigningUnverified(isCurrentSession, isVerifyButtonVisible) @@ -149,6 +150,14 @@ class SessionInfoView @JvmOverloads constructor( views.sessionInfoVerifySessionButton.isVisible = false } + private fun renderCrossSigningEncryptionNotSupported() { + views.sessionInfoVerificationStatusTextView.text = context.getString(R.string.device_manager_verification_status_unverified) + views.sessionInfoVerificationStatusTextView.setTextColor(ThemeUtils.getColor(context, R.attr.colorError)) + views.sessionInfoVerificationStatusDetailTextView.text = + context.getString(R.string.device_manager_verification_status_detail_session_encryption_not_supported) + views.sessionInfoVerifySessionButton.isVisible = false + } + private fun renderDeviceInfo(sessionName: String, deviceType: DeviceType, stringProvider: StringProvider) { setDeviceTypeIconUseCase.execute(deviceType, views.sessionInfoDeviceTypeImageView, stringProvider) views.sessionInfoNameTextView.text = sessionName diff --git a/vector/src/main/java/im/vector/app/features/settings/devices/v2/overview/SessionOverviewFragment.kt b/vector/src/main/java/im/vector/app/features/settings/devices/v2/overview/SessionOverviewFragment.kt index be60b3b805..f3df0cced0 100644 --- a/vector/src/main/java/im/vector/app/features/settings/devices/v2/overview/SessionOverviewFragment.kt +++ b/vector/src/main/java/im/vector/app/features/settings/devices/v2/overview/SessionOverviewFragment.kt @@ -229,7 +229,7 @@ class SessionOverviewFragment : ) views.sessionOverviewInfo.render(infoViewState, dateFormatter, drawableProvider, colorProvider, stringProvider) views.sessionOverviewInfo.onLearnMoreClickListener = { - showLearnMoreInfoVerificationStatus(deviceInfo.roomEncryptionTrustLevel == RoomEncryptionTrustLevel.Trusted) + showLearnMoreInfoVerificationStatus(deviceInfo.roomEncryptionTrustLevel) } } else { views.sessionOverviewInfo.isVisible = false @@ -293,21 +293,28 @@ class SessionOverviewFragment : } } - private fun showLearnMoreInfoVerificationStatus(isVerified: Boolean) { - val titleResId = if (isVerified) { - R.string.device_manager_verification_status_verified - } else { - R.string.device_manager_verification_status_unverified + private fun showLearnMoreInfoVerificationStatus(roomEncryptionTrustLevel: RoomEncryptionTrustLevel?) { + val args = when (roomEncryptionTrustLevel) { + null -> { + // encryption not supported + SessionLearnMoreBottomSheet.Args( + title = getString(R.string.device_manager_verification_status_unverified), + description = getString(R.string.device_manager_learn_more_sessions_encryption_not_supported), + ) + } + RoomEncryptionTrustLevel.Trusted -> { + SessionLearnMoreBottomSheet.Args( + title = getString(R.string.device_manager_verification_status_verified), + description = getString(R.string.device_manager_learn_more_sessions_verified_description), + ) + } + else -> { + SessionLearnMoreBottomSheet.Args( + title = getString(R.string.device_manager_verification_status_unverified), + description = getString(R.string.device_manager_learn_more_sessions_unverified), + ) + } } - val descriptionResId = if (isVerified) { - R.string.device_manager_learn_more_sessions_verified_description - } else { - R.string.device_manager_learn_more_sessions_unverified - } - val args = SessionLearnMoreBottomSheet.Args( - title = getString(titleResId), - description = getString(descriptionResId), - ) SessionLearnMoreBottomSheet.show(childFragmentManager, args) } } diff --git a/vector/src/main/java/im/vector/app/features/settings/devices/v2/verification/GetEncryptionTrustLevelForDeviceUseCase.kt b/vector/src/main/java/im/vector/app/features/settings/devices/v2/verification/GetEncryptionTrustLevelForDeviceUseCase.kt index ba9a380ade..268ae86601 100644 --- a/vector/src/main/java/im/vector/app/features/settings/devices/v2/verification/GetEncryptionTrustLevelForDeviceUseCase.kt +++ b/vector/src/main/java/im/vector/app/features/settings/devices/v2/verification/GetEncryptionTrustLevelForDeviceUseCase.kt @@ -25,11 +25,15 @@ class GetEncryptionTrustLevelForDeviceUseCase @Inject constructor( private val getEncryptionTrustLevelForOtherDeviceUseCase: GetEncryptionTrustLevelForOtherDeviceUseCase, ) { - fun execute(currentSessionCrossSigningInfo: CurrentSessionCrossSigningInfo, cryptoDeviceInfo: CryptoDeviceInfo?): RoomEncryptionTrustLevel { + fun execute(currentSessionCrossSigningInfo: CurrentSessionCrossSigningInfo, cryptoDeviceInfo: CryptoDeviceInfo?): RoomEncryptionTrustLevel? { + if (cryptoDeviceInfo == null) { + return null + } + val legacyMode = !currentSessionCrossSigningInfo.isCrossSigningInitialized val trustMSK = currentSessionCrossSigningInfo.isCrossSigningVerified - val isCurrentDevice = !cryptoDeviceInfo?.deviceId.isNullOrEmpty() && cryptoDeviceInfo?.deviceId == currentSessionCrossSigningInfo.deviceId - val deviceTrustLevel = cryptoDeviceInfo?.trustLevel + val isCurrentDevice = !cryptoDeviceInfo.deviceId.isNullOrEmpty() && cryptoDeviceInfo.deviceId == currentSessionCrossSigningInfo.deviceId + val deviceTrustLevel = cryptoDeviceInfo.trustLevel return when { isCurrentDevice -> getEncryptionTrustLevelForCurrentDeviceUseCase.execute(trustMSK, legacyMode) diff --git a/vector/src/test/java/im/vector/app/features/settings/devices/v2/verification/GetEncryptionTrustLevelForDeviceUseCaseTest.kt b/vector/src/test/java/im/vector/app/features/settings/devices/v2/verification/GetEncryptionTrustLevelForDeviceUseCaseTest.kt index 1b39fe5f73..fd10ee1083 100644 --- a/vector/src/test/java/im/vector/app/features/settings/devices/v2/verification/GetEncryptionTrustLevelForDeviceUseCaseTest.kt +++ b/vector/src/test/java/im/vector/app/features/settings/devices/v2/verification/GetEncryptionTrustLevelForDeviceUseCaseTest.kt @@ -19,6 +19,7 @@ package im.vector.app.features.settings.devices.v2.verification import io.mockk.every import io.mockk.mockk import io.mockk.verify +import org.amshove.kluent.shouldBe import org.amshove.kluent.shouldBeEqualTo import org.junit.Test import org.matrix.android.sdk.api.session.crypto.crosssigning.DeviceTrustLevel @@ -89,6 +90,20 @@ class GetEncryptionTrustLevelForDeviceUseCaseTest { } } + @Test + fun `given no crypto device info when computing trust level then result is null`() { + val currentSessionCrossSigningInfo = givenCurrentSessionCrossSigningInfo( + deviceId = A_DEVICE_ID, + isCrossSigningInitialized = true, + isCrossSigningVerified = false + ) + val cryptoDeviceInfo = null + + val result = getEncryptionTrustLevelForDeviceUseCase.execute(currentSessionCrossSigningInfo, cryptoDeviceInfo) + + result shouldBe null + } + private fun givenCurrentSessionCrossSigningInfo( deviceId: String, isCrossSigningInitialized: Boolean,