From 43358cd86c7bc4de595def4b46d44908b1088d03 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Fri, 31 Jan 2020 12:17:13 +0100 Subject: [PATCH] Make self verification work! --- .../crypto/IncomingRoomKeyRequestManager.kt | 2 +- .../DefaultVerificationService.kt | 3 + .../VerificationTransportRoomMessage.kt | 5 +- .../VerificationTransportToDevice.kt | 6 +- .../DefaultQrCodeVerificationTransaction.kt | 2 +- .../room/EventRelationsAggregationTask.kt | 25 ++++- .../room/EventRelationsAggregationUpdater.kt | 3 +- .../VerificationBottomSheetViewModel.kt | 100 ++++++++++-------- .../DeviceVerificationInfoEpoxyController.kt | 1 - 9 files changed, 91 insertions(+), 56 deletions(-) diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/IncomingRoomKeyRequestManager.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/IncomingRoomKeyRequestManager.kt index 290de52e85..814d9d5a7c 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/IncomingRoomKeyRequestManager.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/IncomingRoomKeyRequestManager.kt @@ -129,7 +129,7 @@ internal class IncomingRoomKeyRequestManager @Inject constructor( cryptoStore.deleteIncomingRoomKeyRequest(request) continue } - + cryptoStore.storeIncomingRoomKeyRequest(request) onRoomKeyRequest(request) } diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/verification/DefaultVerificationService.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/verification/DefaultVerificationService.kt index aa1a64cb6a..911fc2a572 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/verification/DefaultVerificationService.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/verification/DefaultVerificationService.kt @@ -298,6 +298,7 @@ internal class DefaultVerificationService @Inject constructor( otherUserId = senderId, // requestInfo.toUserId, roomId = null, transactionId = requestInfo.transactionID, + localID = requestInfo.transactionID!!, requestInfo = requestInfo ) requestsForUser.add(pendingVerificationRequest) @@ -336,6 +337,7 @@ internal class DefaultVerificationService @Inject constructor( otherUserId = senderId, // requestInfo.toUserId, roomId = event.roomId, transactionId = event.eventId, + localID = event.eventId!!, requestInfo = requestInfo ) requestsForUser.add(pendingVerificationRequest) @@ -1075,6 +1077,7 @@ internal class DefaultVerificationService @Inject constructor( // We need to update with the syncedID updatePendingRequest(verificationRequest.copy( transactionId = syncedId, + // localId stays different requestInfo = info )) } diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/verification/VerificationTransportRoomMessage.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/verification/VerificationTransportRoomMessage.kt index ab9e0ba8a0..e6367dedc0 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/verification/VerificationTransportRoomMessage.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/verification/VerificationTransportRoomMessage.kt @@ -143,6 +143,7 @@ internal class VerificationTransportRoomMessage( roomId: String?, toDevices: List?, callback: (String?, VerificationInfoRequest?) -> Unit) { + Timber.d("## SAS sending verification request with supported methods: $supportedMethods") // This transport requires a room requireNotNull(roomId) @@ -222,6 +223,7 @@ internal class VerificationTransportRoomMessage( } override fun done(transactionId: String) { + Timber.d("## SAS sending done for $transactionId") val event = createEventAndLocalEcho( type = EventType.KEY_VERIFICATION_DONE, roomId = roomId, @@ -337,7 +339,8 @@ internal class VerificationTransportRoomMessage( otherUserId: String, otherDeviceId: String, callback: (() -> Unit)?) { - // Not applicable + // Not applicable (send event is called directly) + Timber.w("## SAS ignored verification ready with methods: ${keyReq.methods}") } } diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/verification/VerificationTransportToDevice.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/verification/VerificationTransportToDevice.kt index f52035018f..49123d5ce9 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/verification/VerificationTransportToDevice.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/verification/VerificationTransportToDevice.kt @@ -50,6 +50,7 @@ internal class VerificationTransportToDevice( roomId: String?, toDevices: List?, callback: (String?, VerificationInfoRequest?) -> Unit) { + Timber.d("## SAS sending verification request with supported methods: $supportedMethods") val contentMap = MXUsersDevicesMap() val keyReq = KeyVerificationRequest( fromDevice = myDeviceId, @@ -80,6 +81,7 @@ internal class VerificationTransportToDevice( otherUserId: String, otherDeviceId: String, callback: (() -> Unit)?) { + Timber.d("## SAS sending verification ready with methods: ${keyReq.methods}") val contentMap = MXUsersDevicesMap() contentMap.setObject(otherUserId, otherDeviceId, keyReq) @@ -137,6 +139,7 @@ internal class VerificationTransportToDevice( override fun done(transactionId: String) { // To device do not do anything here + Timber.d("## SAS done (nothing send in to device transport)") } override fun cancelTransaction(transactionId: String, otherUserId: String, otherUserDeviceId: String, code: CancelCode) { @@ -164,8 +167,7 @@ internal class VerificationTransportToDevice( hash: String, commitment: String, messageAuthenticationCode: String, - shortAuthenticationStrings: List) - : VerificationInfoAccept = KeyVerificationAccept.create( + shortAuthenticationStrings: List): VerificationInfoAccept = KeyVerificationAccept.create( tid, keyAgreementProtocol, hash, diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/verification/qrcode/DefaultQrCodeVerificationTransaction.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/verification/qrcode/DefaultQrCodeVerificationTransaction.kt index 6833390393..d1b72f54c6 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/verification/qrcode/DefaultQrCodeVerificationTransaction.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/verification/qrcode/DefaultQrCodeVerificationTransaction.kt @@ -105,7 +105,7 @@ internal class DefaultQrCodeVerificationTransaction( // Check device key if available if (otherQrCodeData.otherDeviceKey != null - && otherQrCodeData.otherDeviceKey != cryptoStore.getUserDevice(otherQrCodeData.userId, otherDeviceId ?: "")?.fingerprint()) { + && otherQrCodeData.otherDeviceKey != cryptoStore.getUserDevice(userId, deviceId)?.fingerprint()) { Timber.d("## Verification QR: Invalid other device key") cancel(CancelCode.MismatchedKeys) return diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/EventRelationsAggregationTask.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/EventRelationsAggregationTask.kt index cf7a8a9275..70eadb550a 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/EventRelationsAggregationTask.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/EventRelationsAggregationTask.kt @@ -18,7 +18,13 @@ package im.vector.matrix.android.internal.session.room import com.zhuinden.monarchy.Monarchy import im.vector.matrix.android.api.session.crypto.CryptoService import im.vector.matrix.android.api.session.crypto.MXCryptoError -import im.vector.matrix.android.api.session.events.model.* +import im.vector.matrix.android.api.session.events.model.AggregatedAnnotation +import im.vector.matrix.android.api.session.events.model.Event +import im.vector.matrix.android.api.session.events.model.EventType +import im.vector.matrix.android.api.session.events.model.LocalEcho +import im.vector.matrix.android.api.session.events.model.RelationType +import im.vector.matrix.android.api.session.events.model.toContent +import im.vector.matrix.android.api.session.events.model.toModel import im.vector.matrix.android.api.session.room.model.ReferencesAggregatedContent import im.vector.matrix.android.api.session.room.model.message.MessageContent import im.vector.matrix.android.api.session.room.model.message.MessageRelationContent @@ -27,7 +33,13 @@ import im.vector.matrix.android.internal.crypto.algorithms.olm.OlmDecryptionResu import im.vector.matrix.android.internal.crypto.model.event.EncryptedEventContent import im.vector.matrix.android.internal.database.mapper.ContentMapper import im.vector.matrix.android.internal.database.mapper.EventMapper -import im.vector.matrix.android.internal.database.model.* +import im.vector.matrix.android.internal.database.model.EditAggregatedSummaryEntity +import im.vector.matrix.android.internal.database.model.EventAnnotationsSummaryEntity +import im.vector.matrix.android.internal.database.model.EventEntity +import im.vector.matrix.android.internal.database.model.ReactionAggregatedSummaryEntity +import im.vector.matrix.android.internal.database.model.ReactionAggregatedSummaryEntityFields +import im.vector.matrix.android.internal.database.model.ReferencesAggregatedSummaryEntity +import im.vector.matrix.android.internal.database.model.TimelineEventEntity import im.vector.matrix.android.internal.database.query.create import im.vector.matrix.android.internal.database.query.getOrCreate import im.vector.matrix.android.internal.database.query.where @@ -53,9 +65,10 @@ enum class VerificationState { DONE } -fun VerificationState.isCanceled() : Boolean { +fun VerificationState.isCanceled(): Boolean { return this == VerificationState.CANCELED_BY_ME || this == VerificationState.CANCELED_BY_OTHER } + /** * Called by EventRelationAggregationUpdater, when new events that can affect relations are inserted in base. */ @@ -118,6 +131,8 @@ internal class DefaultEventRelationsAggregationTask @Inject constructor( EventType.KEY_VERIFICATION_ACCEPT, EventType.KEY_VERIFICATION_START, EventType.KEY_VERIFICATION_MAC, + // TODO Add ? + // EventType.KEY_VERIFICATION_READY, EventType.KEY_VERIFICATION_KEY -> { Timber.v("## SAS REF in room $roomId for event ${event.eventId}") event.content.toModel()?.relatesTo?.let { @@ -146,6 +161,8 @@ internal class DefaultEventRelationsAggregationTask @Inject constructor( EventType.KEY_VERIFICATION_ACCEPT, EventType.KEY_VERIFICATION_START, EventType.KEY_VERIFICATION_MAC, + // TODO Add ? + // EventType.KEY_VERIFICATION_READY, EventType.KEY_VERIFICATION_KEY -> { Timber.v("## SAS REF in room $roomId for event ${event.eventId}") encryptedEventContent.relatesTo.eventId?.let { @@ -473,7 +490,7 @@ internal class DefaultEventRelationsAggregationTask @Inject constructor( } } - private fun updateVerificationState(oldState: VerificationState?, newState: VerificationState) : VerificationState { + private fun updateVerificationState(oldState: VerificationState?, newState: VerificationState): VerificationState { // Cancel is always prioritary ? // Eg id i found that mac or keys mismatch and send a cancel and the other send a done, i have to // consider as canceled diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/EventRelationsAggregationUpdater.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/EventRelationsAggregationUpdater.kt index 61c21396ed..c876c2c2ea 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/EventRelationsAggregationUpdater.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/EventRelationsAggregationUpdater.kt @@ -35,7 +35,6 @@ import javax.inject.Inject * For reactions will build a EventAnnotationsSummaryEntity, ans for edits a EditAggregatedSummaryEntity. * The summaries can then be extracted and added (as a decoration) to a TimelineEvent for final display. */ - internal class EventRelationsAggregationUpdater @Inject constructor( @SessionDatabase realmConfiguration: RealmConfiguration, @UserId private val userId: String, @@ -52,6 +51,8 @@ internal class EventRelationsAggregationUpdater @Inject constructor( EventType.KEY_VERIFICATION_ACCEPT, EventType.KEY_VERIFICATION_START, EventType.KEY_VERIFICATION_MAC, + // TODO Add ? + // EventType.KEY_VERIFICATION_READY, EventType.KEY_VERIFICATION_KEY, EventType.ENCRYPTED) ) diff --git a/vector/src/main/java/im/vector/riotx/features/crypto/verification/VerificationBottomSheetViewModel.kt b/vector/src/main/java/im/vector/riotx/features/crypto/verification/VerificationBottomSheetViewModel.kt index 101310d20e..5e11570ced 100644 --- a/vector/src/main/java/im/vector/riotx/features/crypto/verification/VerificationBottomSheetViewModel.kt +++ b/vector/src/main/java/im/vector/riotx/features/crypto/verification/VerificationBottomSheetViewModel.kt @@ -42,7 +42,6 @@ import im.vector.matrix.android.api.session.room.model.create.CreateRoomParams import im.vector.matrix.android.api.util.MatrixItem import im.vector.matrix.android.api.util.toMatrixItem import im.vector.matrix.android.internal.crypto.verification.PendingVerificationRequest -import im.vector.riotx.core.di.HasScreenInjector import im.vector.riotx.core.extensions.exhaustive import im.vector.riotx.core.platform.EmptyViewEvents import im.vector.riotx.core.platform.VectorViewModel @@ -56,11 +55,13 @@ data class VerificationBottomSheetViewState( val sasTransactionState: VerificationTxState? = null, val qrTransactionState: VerificationTxState? = null, val transactionId: String? = null, + // true when we display the loading and we wait for the other (incoming request) val waitForOtherUserMode: Boolean = false, val isMe: Boolean = false ) : MvRxState class VerificationBottomSheetViewModel @AssistedInject constructor(@Assisted initialState: VerificationBottomSheetViewState, + @Assisted args: VerificationBottomSheet.VerificationArgs, private val session: Session) : VectorViewModel(initialState), VerificationService.VerificationListener { @@ -72,6 +73,55 @@ class VerificationBottomSheetViewModel @AssistedInject constructor(@Assisted ini init { session.getVerificationService().addListener(this) + + val userItem = session.getUser(args.otherUserId) + + val isWaitingForOtherMode = args.waitForIncomingRequest + + var autoReady = false + val pr = if (isWaitingForOtherMode) { + // See if active tx for this user and take it + + session.getVerificationService().getExistingVerificationRequest(args.otherUserId) + ?.lastOrNull { !it.isFinished } + ?.also { verificationRequest -> + if (verificationRequest.isIncoming && !verificationRequest.isReady) { + // auto ready in this case, as we are waiting + autoReady = true + } + } + } else { + session.getVerificationService().getExistingVerificationRequest(args.otherUserId, args.verificationId) + } + + val sasTx = (pr?.transactionId ?: args.verificationId)?.let { + session.getVerificationService().getExistingTransaction(args.otherUserId, it) as? SasVerificationTransaction + } + + val qrTx = (pr?.transactionId ?: args.verificationId)?.let { + session.getVerificationService().getExistingTransaction(args.otherUserId, it) as? QrCodeVerificationTransaction + } + + setState { + copy( + otherUserMxItem = userItem?.toMatrixItem(), + sasTransactionState = sasTx?.state, + qrTransactionState = qrTx?.state, + transactionId = pr?.transactionId ?: args.verificationId, + pendingRequest = if (pr != null) Success(pr) else Uninitialized, + waitForOtherUserMode = isWaitingForOtherMode, + roomId = args.roomId, + isMe = args.otherUserId == session.myUserId + ) + } + + if (autoReady) { + // TODO, can I be here in DM mode? in this case should test if roomID is null? + session.getVerificationService() + .readyPendingVerification(supportedVerificationMethods, + pr!!.otherUserId, + pr.transactionId ?: "") + } } override fun onCleared() { @@ -81,7 +131,8 @@ class VerificationBottomSheetViewModel @AssistedInject constructor(@Assisted ini @AssistedInject.Factory interface Factory { - fun create(initialState: VerificationBottomSheetViewState): VerificationBottomSheetViewModel + fun create(initialState: VerificationBottomSheetViewState, + args: VerificationBottomSheet.VerificationArgs): VerificationBottomSheetViewModel } companion object : MvRxViewModelFactory { @@ -90,48 +141,7 @@ class VerificationBottomSheetViewModel @AssistedInject constructor(@Assisted ini val fragment: VerificationBottomSheet = (viewModelContext as FragmentViewModelContext).fragment() val args: VerificationBottomSheet.VerificationArgs = viewModelContext.args() - val session = (viewModelContext.activity as HasScreenInjector).injector().activeSessionHolder().getActiveSession() - - val userItem = session.getUser(args.otherUserId) - - val isWaitingForOtherMode = args.waitForIncomingRequest - - val pr = if (isWaitingForOtherMode) { - // See if active tx for this user and take it - session.getVerificationService().getExistingVerificationRequest(args.otherUserId) - ?.firstOrNull { !it.isFinished } - ?.also { verificationRequest -> - if (verificationRequest.isIncoming && !verificationRequest.isReady) { - //auto ready in this case, as we are waiting - // TODO, can I be here in DM mode? in this case should test if roomID is null? - session.getVerificationService() - .readyPendingVerification(supportedVerificationMethods, - verificationRequest.otherUserId, - verificationRequest.transactionId ?: "") - } - } - } else { - session.getVerificationService().getExistingVerificationRequest(args.otherUserId, args.verificationId) - } - - val sasTx = (pr?.transactionId ?: args.verificationId)?.let { - session.getVerificationService().getExistingTransaction(args.otherUserId, it) as? SasVerificationTransaction - } - - val qrTx = (pr?.transactionId ?: args.verificationId)?.let { - session.getVerificationService().getExistingTransaction(args.otherUserId, it) as? QrCodeVerificationTransaction - } - - return fragment.verificationViewModelFactory.create(VerificationBottomSheetViewState( - otherUserMxItem = userItem?.toMatrixItem(), - sasTransactionState = sasTx?.state, - qrTransactionState = qrTx?.state, - transactionId = args.verificationId, - pendingRequest = if (pr != null) Success(pr) else Uninitialized, - waitForOtherUserMode = isWaitingForOtherMode, - roomId = args.roomId, - isMe = args.otherUserId == session.myUserId) - ) + return fragment.verificationViewModelFactory.create(state, args) } } @@ -309,7 +319,7 @@ class VerificationBottomSheetViewModel @AssistedInject constructor(@Assisted ini // is this an incoming with that user if (pr.isIncoming && pr.otherUserId == state.otherUserMxItem?.id) { if (!pr.isReady) { - //auto ready in this case, as we are waiting + // auto ready in this case, as we are waiting // TODO, can I be here in DM mode? in this case should test if roomID is null? session.getVerificationService() .readyPendingVerification(supportedVerificationMethods, diff --git a/vector/src/main/java/im/vector/riotx/features/settings/devices/DeviceVerificationInfoEpoxyController.kt b/vector/src/main/java/im/vector/riotx/features/settings/devices/DeviceVerificationInfoEpoxyController.kt index decbb15c42..90724166a0 100644 --- a/vector/src/main/java/im/vector/riotx/features/settings/devices/DeviceVerificationInfoEpoxyController.kt +++ b/vector/src/main/java/im/vector/riotx/features/settings/devices/DeviceVerificationInfoEpoxyController.kt @@ -16,7 +16,6 @@ package im.vector.riotx.features.settings.devices import com.airbnb.epoxy.TypedEpoxyController -import com.airbnb.mvrx.Fail import im.vector.matrix.android.api.session.Session import im.vector.riotx.R import im.vector.riotx.core.epoxy.dividerItem