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,
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
))
}

View File

@ -143,6 +143,7 @@ internal class VerificationTransportRoomMessage(
roomId: String?,
toDevices: List<String>?,
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}")
}
}

View File

@ -50,6 +50,7 @@ internal class VerificationTransportToDevice(
roomId: String?,
toDevices: List<String>?,
callback: (String?, VerificationInfoRequest?) -> Unit) {
Timber.d("## SAS sending verification request with supported methods: $supportedMethods")
val contentMap = MXUsersDevicesMap<Any>()
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<Any>()
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<String>)
: VerificationInfoAccept = KeyVerificationAccept.create(
shortAuthenticationStrings: List<String>): VerificationInfoAccept = KeyVerificationAccept.create(
tid,
keyAgreementProtocol,
hash,

View File

@ -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

View File

@ -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<MessageRelationContent>()?.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

View File

@ -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)
)

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.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<VerificationBottomSheetViewState, VerificationAction, EmptyViewEvents>(initialState),
VerificationService.VerificationListener {
@ -72,42 +73,21 @@ class VerificationBottomSheetViewModel @AssistedInject constructor(@Assisted ini
init {
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 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)
?.firstOrNull { !it.isFinished }
?.lastOrNull { !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 ?: "")
// auto ready in this case, as we are waiting
autoReady = true
}
}
} else {
@ -122,17 +102,47 @@ class VerificationBottomSheetViewModel @AssistedInject constructor(@Assisted ini
session.getVerificationService().getExistingTransaction(args.otherUserId, it) as? QrCodeVerificationTransaction
}
return fragment.verificationViewModelFactory.create(VerificationBottomSheetViewState(
setState {
copy(
otherUserMxItem = userItem?.toMatrixItem(),
sasTransactionState = sasTx?.state,
qrTransactionState = qrTx?.state,
transactionId = args.verificationId,
transactionId = pr?.transactionId ?: args.verificationId,
pendingRequest = if (pr != null) Success(pr) else Uninitialized,
waitForOtherUserMode = isWaitingForOtherMode,
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 ->
@ -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,

View File

@ -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