Make self verification work!

This commit is contained in:
Benoit Marty 2020-01-31 12:17:13 +01:00
parent 87b76d10dd
commit 43358cd86c
9 changed files with 91 additions and 56 deletions

View File

@ -298,6 +298,7 @@ internal class DefaultVerificationService @Inject constructor(
otherUserId = senderId, // requestInfo.toUserId, otherUserId = senderId, // requestInfo.toUserId,
roomId = null, roomId = null,
transactionId = requestInfo.transactionID, transactionId = requestInfo.transactionID,
localID = requestInfo.transactionID!!,
requestInfo = requestInfo requestInfo = requestInfo
) )
requestsForUser.add(pendingVerificationRequest) requestsForUser.add(pendingVerificationRequest)
@ -336,6 +337,7 @@ internal class DefaultVerificationService @Inject constructor(
otherUserId = senderId, // requestInfo.toUserId, otherUserId = senderId, // requestInfo.toUserId,
roomId = event.roomId, roomId = event.roomId,
transactionId = event.eventId, transactionId = event.eventId,
localID = event.eventId!!,
requestInfo = requestInfo requestInfo = requestInfo
) )
requestsForUser.add(pendingVerificationRequest) requestsForUser.add(pendingVerificationRequest)
@ -1075,6 +1077,7 @@ internal class DefaultVerificationService @Inject constructor(
// We need to update with the syncedID // We need to update with the syncedID
updatePendingRequest(verificationRequest.copy( updatePendingRequest(verificationRequest.copy(
transactionId = syncedId, transactionId = syncedId,
// localId stays different
requestInfo = info requestInfo = info
)) ))
} }

View File

@ -143,6 +143,7 @@ internal class VerificationTransportRoomMessage(
roomId: String?, roomId: String?,
toDevices: List<String>?, toDevices: List<String>?,
callback: (String?, VerificationInfoRequest?) -> Unit) { callback: (String?, VerificationInfoRequest?) -> Unit) {
Timber.d("## SAS sending verification request with supported methods: $supportedMethods")
// This transport requires a room // This transport requires a room
requireNotNull(roomId) requireNotNull(roomId)
@ -222,6 +223,7 @@ internal class VerificationTransportRoomMessage(
} }
override fun done(transactionId: String) { override fun done(transactionId: String) {
Timber.d("## SAS sending done for $transactionId")
val event = createEventAndLocalEcho( val event = createEventAndLocalEcho(
type = EventType.KEY_VERIFICATION_DONE, type = EventType.KEY_VERIFICATION_DONE,
roomId = roomId, roomId = roomId,
@ -337,7 +339,8 @@ internal class VerificationTransportRoomMessage(
otherUserId: String, otherUserId: String,
otherDeviceId: String, otherDeviceId: String,
callback: (() -> Unit)?) { callback: (() -> Unit)?) {
// Not applicable // Not applicable (send event is called directly)
Timber.w("## SAS ignored verification ready with methods: ${keyReq.methods}")
} }
} }

View File

@ -50,6 +50,7 @@ internal class VerificationTransportToDevice(
roomId: String?, roomId: String?,
toDevices: List<String>?, toDevices: List<String>?,
callback: (String?, VerificationInfoRequest?) -> Unit) { callback: (String?, VerificationInfoRequest?) -> Unit) {
Timber.d("## SAS sending verification request with supported methods: $supportedMethods")
val contentMap = MXUsersDevicesMap<Any>() val contentMap = MXUsersDevicesMap<Any>()
val keyReq = KeyVerificationRequest( val keyReq = KeyVerificationRequest(
fromDevice = myDeviceId, fromDevice = myDeviceId,
@ -80,6 +81,7 @@ internal class VerificationTransportToDevice(
otherUserId: String, otherUserId: String,
otherDeviceId: String, otherDeviceId: String,
callback: (() -> Unit)?) { callback: (() -> Unit)?) {
Timber.d("## SAS sending verification ready with methods: ${keyReq.methods}")
val contentMap = MXUsersDevicesMap<Any>() val contentMap = MXUsersDevicesMap<Any>()
contentMap.setObject(otherUserId, otherDeviceId, keyReq) contentMap.setObject(otherUserId, otherDeviceId, keyReq)
@ -137,6 +139,7 @@ internal class VerificationTransportToDevice(
override fun done(transactionId: String) { override fun done(transactionId: String) {
// To device do not do anything here // 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) { override fun cancelTransaction(transactionId: String, otherUserId: String, otherUserDeviceId: String, code: CancelCode) {
@ -164,8 +167,7 @@ internal class VerificationTransportToDevice(
hash: String, hash: String,
commitment: String, commitment: String,
messageAuthenticationCode: String, messageAuthenticationCode: String,
shortAuthenticationStrings: List<String>) shortAuthenticationStrings: List<String>): VerificationInfoAccept = KeyVerificationAccept.create(
: VerificationInfoAccept = KeyVerificationAccept.create(
tid, tid,
keyAgreementProtocol, keyAgreementProtocol,
hash, hash,

View File

@ -105,7 +105,7 @@ internal class DefaultQrCodeVerificationTransaction(
// Check device key if available // Check device key if available
if (otherQrCodeData.otherDeviceKey != null 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") Timber.d("## Verification QR: Invalid other device key")
cancel(CancelCode.MismatchedKeys) cancel(CancelCode.MismatchedKeys)
return return

View File

@ -18,7 +18,13 @@ package im.vector.matrix.android.internal.session.room
import com.zhuinden.monarchy.Monarchy import com.zhuinden.monarchy.Monarchy
import im.vector.matrix.android.api.session.crypto.CryptoService 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.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.ReferencesAggregatedContent
import im.vector.matrix.android.api.session.room.model.message.MessageContent import im.vector.matrix.android.api.session.room.model.message.MessageContent
import im.vector.matrix.android.api.session.room.model.message.MessageRelationContent 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.crypto.model.event.EncryptedEventContent
import im.vector.matrix.android.internal.database.mapper.ContentMapper 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.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.create
import im.vector.matrix.android.internal.database.query.getOrCreate import im.vector.matrix.android.internal.database.query.getOrCreate
import im.vector.matrix.android.internal.database.query.where import im.vector.matrix.android.internal.database.query.where
@ -53,9 +65,10 @@ enum class VerificationState {
DONE DONE
} }
fun VerificationState.isCanceled() : Boolean { fun VerificationState.isCanceled(): Boolean {
return this == VerificationState.CANCELED_BY_ME || this == VerificationState.CANCELED_BY_OTHER 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. * 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_ACCEPT,
EventType.KEY_VERIFICATION_START, EventType.KEY_VERIFICATION_START,
EventType.KEY_VERIFICATION_MAC, EventType.KEY_VERIFICATION_MAC,
// TODO Add ?
// EventType.KEY_VERIFICATION_READY,
EventType.KEY_VERIFICATION_KEY -> { EventType.KEY_VERIFICATION_KEY -> {
Timber.v("## SAS REF in room $roomId for event ${event.eventId}") Timber.v("## SAS REF in room $roomId for event ${event.eventId}")
event.content.toModel<MessageRelationContent>()?.relatesTo?.let { event.content.toModel<MessageRelationContent>()?.relatesTo?.let {
@ -146,6 +161,8 @@ internal class DefaultEventRelationsAggregationTask @Inject constructor(
EventType.KEY_VERIFICATION_ACCEPT, EventType.KEY_VERIFICATION_ACCEPT,
EventType.KEY_VERIFICATION_START, EventType.KEY_VERIFICATION_START,
EventType.KEY_VERIFICATION_MAC, EventType.KEY_VERIFICATION_MAC,
// TODO Add ?
// EventType.KEY_VERIFICATION_READY,
EventType.KEY_VERIFICATION_KEY -> { EventType.KEY_VERIFICATION_KEY -> {
Timber.v("## SAS REF in room $roomId for event ${event.eventId}") Timber.v("## SAS REF in room $roomId for event ${event.eventId}")
encryptedEventContent.relatesTo.eventId?.let { 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 ? // 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 // 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 // consider as canceled

View File

@ -35,7 +35,6 @@ import javax.inject.Inject
* For reactions will build a EventAnnotationsSummaryEntity, ans for edits a EditAggregatedSummaryEntity. * 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. * The summaries can then be extracted and added (as a decoration) to a TimelineEvent for final display.
*/ */
internal class EventRelationsAggregationUpdater @Inject constructor( internal class EventRelationsAggregationUpdater @Inject constructor(
@SessionDatabase realmConfiguration: RealmConfiguration, @SessionDatabase realmConfiguration: RealmConfiguration,
@UserId private val userId: String, @UserId private val userId: String,
@ -52,6 +51,8 @@ internal class EventRelationsAggregationUpdater @Inject constructor(
EventType.KEY_VERIFICATION_ACCEPT, EventType.KEY_VERIFICATION_ACCEPT,
EventType.KEY_VERIFICATION_START, EventType.KEY_VERIFICATION_START,
EventType.KEY_VERIFICATION_MAC, EventType.KEY_VERIFICATION_MAC,
// TODO Add ?
// EventType.KEY_VERIFICATION_READY,
EventType.KEY_VERIFICATION_KEY, EventType.KEY_VERIFICATION_KEY,
EventType.ENCRYPTED) EventType.ENCRYPTED)
) )

View File

@ -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.MatrixItem
import im.vector.matrix.android.api.util.toMatrixItem import im.vector.matrix.android.api.util.toMatrixItem
import im.vector.matrix.android.internal.crypto.verification.PendingVerificationRequest 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.extensions.exhaustive
import im.vector.riotx.core.platform.EmptyViewEvents import im.vector.riotx.core.platform.EmptyViewEvents
import im.vector.riotx.core.platform.VectorViewModel import im.vector.riotx.core.platform.VectorViewModel
@ -56,11 +55,13 @@ data class VerificationBottomSheetViewState(
val sasTransactionState: VerificationTxState? = null, val sasTransactionState: VerificationTxState? = null,
val qrTransactionState: VerificationTxState? = null, val qrTransactionState: VerificationTxState? = null,
val transactionId: String? = null, val transactionId: String? = null,
// true when we display the loading and we wait for the other (incoming request)
val waitForOtherUserMode: Boolean = false, val waitForOtherUserMode: Boolean = false,
val isMe: Boolean = false val isMe: Boolean = false
) : MvRxState ) : MvRxState
class VerificationBottomSheetViewModel @AssistedInject constructor(@Assisted initialState: VerificationBottomSheetViewState, class VerificationBottomSheetViewModel @AssistedInject constructor(@Assisted initialState: VerificationBottomSheetViewState,
@Assisted args: VerificationBottomSheet.VerificationArgs,
private val session: Session) private val session: Session)
: VectorViewModel<VerificationBottomSheetViewState, VerificationAction, EmptyViewEvents>(initialState), : VectorViewModel<VerificationBottomSheetViewState, VerificationAction, EmptyViewEvents>(initialState),
VerificationService.VerificationListener { VerificationService.VerificationListener {
@ -72,42 +73,21 @@ class VerificationBottomSheetViewModel @AssistedInject constructor(@Assisted ini
init { init {
session.getVerificationService().addListener(this) session.getVerificationService().addListener(this)
}
override fun onCleared() {
session.getVerificationService().removeListener(this)
super.onCleared()
}
@AssistedInject.Factory
interface Factory {
fun create(initialState: VerificationBottomSheetViewState): VerificationBottomSheetViewModel
}
companion object : MvRxViewModelFactory<VerificationBottomSheetViewModel, VerificationBottomSheetViewState> {
override fun create(viewModelContext: ViewModelContext, state: VerificationBottomSheetViewState): VerificationBottomSheetViewModel? {
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 userItem = session.getUser(args.otherUserId)
val isWaitingForOtherMode = args.waitForIncomingRequest val isWaitingForOtherMode = args.waitForIncomingRequest
var autoReady = false
val pr = if (isWaitingForOtherMode) { val pr = if (isWaitingForOtherMode) {
// See if active tx for this user and take it // See if active tx for this user and take it
session.getVerificationService().getExistingVerificationRequest(args.otherUserId) session.getVerificationService().getExistingVerificationRequest(args.otherUserId)
?.firstOrNull { !it.isFinished } ?.lastOrNull { !it.isFinished }
?.also { verificationRequest -> ?.also { verificationRequest ->
if (verificationRequest.isIncoming && !verificationRequest.isReady) { if (verificationRequest.isIncoming && !verificationRequest.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? autoReady = true
session.getVerificationService()
.readyPendingVerification(supportedVerificationMethods,
verificationRequest.otherUserId,
verificationRequest.transactionId ?: "")
} }
} }
} else { } else {
@ -122,17 +102,47 @@ class VerificationBottomSheetViewModel @AssistedInject constructor(@Assisted ini
session.getVerificationService().getExistingTransaction(args.otherUserId, it) as? QrCodeVerificationTransaction session.getVerificationService().getExistingTransaction(args.otherUserId, it) as? QrCodeVerificationTransaction
} }
return fragment.verificationViewModelFactory.create(VerificationBottomSheetViewState( setState {
copy(
otherUserMxItem = userItem?.toMatrixItem(), otherUserMxItem = userItem?.toMatrixItem(),
sasTransactionState = sasTx?.state, sasTransactionState = sasTx?.state,
qrTransactionState = qrTx?.state, qrTransactionState = qrTx?.state,
transactionId = args.verificationId, transactionId = pr?.transactionId ?: args.verificationId,
pendingRequest = if (pr != null) Success(pr) else Uninitialized, pendingRequest = if (pr != null) Success(pr) else Uninitialized,
waitForOtherUserMode = isWaitingForOtherMode, waitForOtherUserMode = isWaitingForOtherMode,
roomId = args.roomId, roomId = args.roomId,
isMe = args.otherUserId == session.myUserId) 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() {
session.getVerificationService().removeListener(this)
super.onCleared()
}
@AssistedInject.Factory
interface Factory {
fun create(initialState: VerificationBottomSheetViewState,
args: VerificationBottomSheet.VerificationArgs): VerificationBottomSheetViewModel
}
companion object : MvRxViewModelFactory<VerificationBottomSheetViewModel, VerificationBottomSheetViewState> {
override fun create(viewModelContext: ViewModelContext, state: VerificationBottomSheetViewState): VerificationBottomSheetViewModel? {
val fragment: VerificationBottomSheet = (viewModelContext as FragmentViewModelContext).fragment()
val args: VerificationBottomSheet.VerificationArgs = viewModelContext.args()
return fragment.verificationViewModelFactory.create(state, args)
}
} }
override fun handle(action: VerificationAction) = withState { state -> override fun handle(action: VerificationAction) = withState { state ->
@ -309,7 +319,7 @@ class VerificationBottomSheetViewModel @AssistedInject constructor(@Assisted ini
// is this an incoming with that user // is this an incoming with that user
if (pr.isIncoming && pr.otherUserId == state.otherUserMxItem?.id) { if (pr.isIncoming && pr.otherUserId == state.otherUserMxItem?.id) {
if (!pr.isReady) { 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? // TODO, can I be here in DM mode? in this case should test if roomID is null?
session.getVerificationService() session.getVerificationService()
.readyPendingVerification(supportedVerificationMethods, .readyPendingVerification(supportedVerificationMethods,

View File

@ -16,7 +16,6 @@
package im.vector.riotx.features.settings.devices package im.vector.riotx.features.settings.devices
import com.airbnb.epoxy.TypedEpoxyController import com.airbnb.epoxy.TypedEpoxyController
import com.airbnb.mvrx.Fail
import im.vector.matrix.android.api.session.Session import im.vector.matrix.android.api.session.Session
import im.vector.riotx.R import im.vector.riotx.R
import im.vector.riotx.core.epoxy.dividerItem import im.vector.riotx.core.epoxy.dividerItem