mirror of
https://github.com/vector-im/element-android.git
synced 2024-11-16 02:05:06 +08:00
Merge pull request #7736 from vector-im/fix/mna/session-without-crypto-keys
[Session manager] Sessions without encryption support should not prompt to verify (PSG-1004)
This commit is contained in:
commit
be7b49b707
1
changelog.d/7733.bugfix
Normal file
1
changelog.d/7733.bugfix
Normal file
@ -0,0 +1 @@
|
|||||||
|
[Session manager] Sessions without encryption support should not prompt to verify
|
@ -3308,6 +3308,7 @@
|
|||||||
<string name="device_manager_verification_status_detail_current_session_unverified">Verify your current session for enhanced secure messaging.</string>
|
<string name="device_manager_verification_status_detail_current_session_unverified">Verify your current session for enhanced secure messaging.</string>
|
||||||
<string name="device_manager_verification_status_detail_other_session_unverified">Verify or sign out from this session for best security and reliability.</string>
|
<string name="device_manager_verification_status_detail_other_session_unverified">Verify or sign out from this session for best security and reliability.</string>
|
||||||
<string name="device_manager_verification_status_detail_other_session_unknown">Verify your current session to reveal this session\'s verification status.</string>
|
<string name="device_manager_verification_status_detail_other_session_unknown">Verify your current session to reveal this session\'s verification status.</string>
|
||||||
|
<string name="device_manager_verification_status_detail_session_encryption_not_supported">This session doesn\'t support encryption and thus can\'t be verified.</string>
|
||||||
<string name="device_manager_verify_session">Verify Session</string>
|
<string name="device_manager_verify_session">Verify Session</string>
|
||||||
<string name="device_manager_view_details">View Details</string>
|
<string name="device_manager_view_details">View Details</string>
|
||||||
<string name="device_manager_other_sessions_view_all">View All (%1$d)</string>
|
<string name="device_manager_other_sessions_view_all">View All (%1$d)</string>
|
||||||
@ -3400,6 +3401,7 @@
|
|||||||
<!-- TODO TO BE REMOVED -->
|
<!-- TODO TO BE REMOVED -->
|
||||||
<string name="device_manager_learn_more_sessions_verified" tools:ignore="UnusedResources">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.</string>
|
<string name="device_manager_learn_more_sessions_verified" tools:ignore="UnusedResources">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.</string>
|
||||||
<string name="device_manager_learn_more_sessions_verified_description">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.</string>
|
<string name="device_manager_learn_more_sessions_verified_description">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.</string>
|
||||||
|
<string name="device_manager_learn_more_sessions_encryption_not_supported">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.</string>
|
||||||
<string name="device_manager_learn_more_session_rename_title">Renaming sessions</string>
|
<string name="device_manager_learn_more_session_rename_title">Renaming sessions</string>
|
||||||
<string name="device_manager_learn_more_session_rename">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.</string>
|
<string name="device_manager_learn_more_session_rename">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.</string>
|
||||||
<string name="labs_enable_session_manager_title">Enable new session manager</string>
|
<string name="labs_enable_session_manager_title">Enable new session manager</string>
|
||||||
|
@ -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.
|
* 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
|
* @param borderLess if true then the shield icon with border around is used
|
||||||
*/
|
*/
|
||||||
fun renderDeviceShield(roomEncryptionTrustLevel: RoomEncryptionTrustLevel?, borderLess: Boolean = false) {
|
fun renderDeviceShield(roomEncryptionTrustLevel: RoomEncryptionTrustLevel?, borderLess: Boolean = false) {
|
||||||
isVisible = roomEncryptionTrustLevel != null
|
when (roomEncryptionTrustLevel) {
|
||||||
|
null -> {
|
||||||
if (roomEncryptionTrustLevel == RoomEncryptionTrustLevel.Default) {
|
contentDescription = context.getString(R.string.a11y_trust_level_warning)
|
||||||
contentDescription = context.getString(R.string.a11y_trust_level_default)
|
setImageResource(
|
||||||
setImageResource(
|
if (borderLess) R.drawable.ic_shield_warning_no_border
|
||||||
if (borderLess) R.drawable.ic_shield_unknown_no_border
|
else R.drawable.ic_shield_warning
|
||||||
else R.drawable.ic_shield_unknown
|
)
|
||||||
)
|
}
|
||||||
} else {
|
RoomEncryptionTrustLevel.Default -> {
|
||||||
render(roomEncryptionTrustLevel, borderLess)
|
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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -104,7 +104,7 @@ class UnknownDeviceDetectorSharedViewModel @AssistedInject constructor(
|
|||||||
// Timber.v("## Detector trigger canCrossSign ${pInfo.get().selfSigned != null}")
|
// Timber.v("## Detector trigger canCrossSign ${pInfo.get().selfSigned != null}")
|
||||||
infoList
|
infoList
|
||||||
.filter { info ->
|
.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()
|
cryptoList.firstOrNull { info.deviceId == it.deviceId }?.isVerified?.not().orFalse()
|
||||||
}
|
}
|
||||||
// filter out ignored devices
|
// filter out ignored devices
|
||||||
|
@ -88,7 +88,7 @@ data class DevicesViewState(
|
|||||||
data class DeviceFullInfo(
|
data class DeviceFullInfo(
|
||||||
val deviceInfo: DeviceInfo,
|
val deviceInfo: DeviceInfo,
|
||||||
val cryptoDeviceInfo: CryptoDeviceInfo?,
|
val cryptoDeviceInfo: CryptoDeviceInfo?,
|
||||||
val trustLevelForShield: RoomEncryptionTrustLevel,
|
val trustLevelForShield: RoomEncryptionTrustLevel?,
|
||||||
val isInactive: Boolean,
|
val isInactive: Boolean,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -25,7 +25,7 @@ import org.matrix.android.sdk.api.session.crypto.model.RoomEncryptionTrustLevel
|
|||||||
data class DeviceFullInfo(
|
data class DeviceFullInfo(
|
||||||
val deviceInfo: DeviceInfo,
|
val deviceInfo: DeviceInfo,
|
||||||
val cryptoDeviceInfo: CryptoDeviceInfo?,
|
val cryptoDeviceInfo: CryptoDeviceInfo?,
|
||||||
val roomEncryptionTrustLevel: RoomEncryptionTrustLevel,
|
val roomEncryptionTrustLevel: RoomEncryptionTrustLevel?,
|
||||||
val isInactive: Boolean,
|
val isInactive: Boolean,
|
||||||
val isCurrentDevice: Boolean,
|
val isCurrentDevice: Boolean,
|
||||||
val deviceExtendedInfo: DeviceExtendedInfo,
|
val deviceExtendedInfo: DeviceExtendedInfo,
|
||||||
|
@ -85,13 +85,14 @@ class SessionInfoView @JvmOverloads constructor(
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun renderVerificationStatus(
|
private fun renderVerificationStatus(
|
||||||
encryptionTrustLevel: RoomEncryptionTrustLevel,
|
encryptionTrustLevel: RoomEncryptionTrustLevel?,
|
||||||
isCurrentSession: Boolean,
|
isCurrentSession: Boolean,
|
||||||
hasLearnMoreLink: Boolean,
|
hasLearnMoreLink: Boolean,
|
||||||
isVerifyButtonVisible: Boolean,
|
isVerifyButtonVisible: Boolean,
|
||||||
) {
|
) {
|
||||||
views.sessionInfoVerificationStatusImageView.renderDeviceShield(encryptionTrustLevel)
|
views.sessionInfoVerificationStatusImageView.renderDeviceShield(encryptionTrustLevel)
|
||||||
when {
|
when {
|
||||||
|
encryptionTrustLevel == null -> renderCrossSigningEncryptionNotSupported()
|
||||||
encryptionTrustLevel == RoomEncryptionTrustLevel.Trusted -> renderCrossSigningVerified(isCurrentSession)
|
encryptionTrustLevel == RoomEncryptionTrustLevel.Trusted -> renderCrossSigningVerified(isCurrentSession)
|
||||||
encryptionTrustLevel == RoomEncryptionTrustLevel.Default && !isCurrentSession -> renderCrossSigningUnknown()
|
encryptionTrustLevel == RoomEncryptionTrustLevel.Default && !isCurrentSession -> renderCrossSigningUnknown()
|
||||||
else -> renderCrossSigningUnverified(isCurrentSession, isVerifyButtonVisible)
|
else -> renderCrossSigningUnverified(isCurrentSession, isVerifyButtonVisible)
|
||||||
@ -149,6 +150,14 @@ class SessionInfoView @JvmOverloads constructor(
|
|||||||
views.sessionInfoVerifySessionButton.isVisible = false
|
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) {
|
private fun renderDeviceInfo(sessionName: String, deviceType: DeviceType, stringProvider: StringProvider) {
|
||||||
setDeviceTypeIconUseCase.execute(deviceType, views.sessionInfoDeviceTypeImageView, stringProvider)
|
setDeviceTypeIconUseCase.execute(deviceType, views.sessionInfoDeviceTypeImageView, stringProvider)
|
||||||
views.sessionInfoNameTextView.text = sessionName
|
views.sessionInfoNameTextView.text = sessionName
|
||||||
|
@ -229,7 +229,7 @@ class SessionOverviewFragment :
|
|||||||
)
|
)
|
||||||
views.sessionOverviewInfo.render(infoViewState, dateFormatter, drawableProvider, colorProvider, stringProvider)
|
views.sessionOverviewInfo.render(infoViewState, dateFormatter, drawableProvider, colorProvider, stringProvider)
|
||||||
views.sessionOverviewInfo.onLearnMoreClickListener = {
|
views.sessionOverviewInfo.onLearnMoreClickListener = {
|
||||||
showLearnMoreInfoVerificationStatus(deviceInfo.roomEncryptionTrustLevel == RoomEncryptionTrustLevel.Trusted)
|
showLearnMoreInfoVerificationStatus(deviceInfo.roomEncryptionTrustLevel)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
views.sessionOverviewInfo.isVisible = false
|
views.sessionOverviewInfo.isVisible = false
|
||||||
@ -293,21 +293,28 @@ class SessionOverviewFragment :
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun showLearnMoreInfoVerificationStatus(isVerified: Boolean) {
|
private fun showLearnMoreInfoVerificationStatus(roomEncryptionTrustLevel: RoomEncryptionTrustLevel?) {
|
||||||
val titleResId = if (isVerified) {
|
val args = when (roomEncryptionTrustLevel) {
|
||||||
R.string.device_manager_verification_status_verified
|
null -> {
|
||||||
} else {
|
// encryption not supported
|
||||||
R.string.device_manager_verification_status_unverified
|
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)
|
SessionLearnMoreBottomSheet.show(childFragmentManager, args)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -25,11 +25,15 @@ class GetEncryptionTrustLevelForDeviceUseCase @Inject constructor(
|
|||||||
private val getEncryptionTrustLevelForOtherDeviceUseCase: GetEncryptionTrustLevelForOtherDeviceUseCase,
|
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 legacyMode = !currentSessionCrossSigningInfo.isCrossSigningInitialized
|
||||||
val trustMSK = currentSessionCrossSigningInfo.isCrossSigningVerified
|
val trustMSK = currentSessionCrossSigningInfo.isCrossSigningVerified
|
||||||
val isCurrentDevice = !cryptoDeviceInfo?.deviceId.isNullOrEmpty() && cryptoDeviceInfo?.deviceId == currentSessionCrossSigningInfo.deviceId
|
val isCurrentDevice = !cryptoDeviceInfo.deviceId.isNullOrEmpty() && cryptoDeviceInfo.deviceId == currentSessionCrossSigningInfo.deviceId
|
||||||
val deviceTrustLevel = cryptoDeviceInfo?.trustLevel
|
val deviceTrustLevel = cryptoDeviceInfo.trustLevel
|
||||||
|
|
||||||
return when {
|
return when {
|
||||||
isCurrentDevice -> getEncryptionTrustLevelForCurrentDeviceUseCase.execute(trustMSK, legacyMode)
|
isCurrentDevice -> getEncryptionTrustLevelForCurrentDeviceUseCase.execute(trustMSK, legacyMode)
|
||||||
|
@ -19,6 +19,7 @@ package im.vector.app.features.settings.devices.v2.verification
|
|||||||
import io.mockk.every
|
import io.mockk.every
|
||||||
import io.mockk.mockk
|
import io.mockk.mockk
|
||||||
import io.mockk.verify
|
import io.mockk.verify
|
||||||
|
import org.amshove.kluent.shouldBe
|
||||||
import org.amshove.kluent.shouldBeEqualTo
|
import org.amshove.kluent.shouldBeEqualTo
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
import org.matrix.android.sdk.api.session.crypto.crosssigning.DeviceTrustLevel
|
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(
|
private fun givenCurrentSessionCrossSigningInfo(
|
||||||
deviceId: String,
|
deviceId: String,
|
||||||
isCrossSigningInitialized: Boolean,
|
isCrossSigningInitialized: Boolean,
|
||||||
|
Loading…
Reference in New Issue
Block a user