QrCode: WIP
This commit is contained in:
parent
0aaba26f17
commit
39e746413a
|
@ -27,7 +27,9 @@ enum class CancelCode(val value: String, val humanReadable: String) {
|
|||
UnexpectedMessage("m.unexpected_message", "the device received an unexpected message"),
|
||||
InvalidMessage("m.invalid_message", "an invalid message was received"),
|
||||
MismatchedKeys("m.key_mismatch", "Key mismatch"),
|
||||
UserMismatchError("m.user_error", "User mismatch")
|
||||
UserError("m.user_error", "User mismatch"),
|
||||
UserMismatchError("m.user_mismatch", "Key mismatch"),
|
||||
QrCodeInvalid("m.qr_code.invalid", "User mismatch")
|
||||
}
|
||||
|
||||
fun safeValueOf(code: String?): CancelCode {
|
||||
|
|
|
@ -1,7 +0,0 @@
|
|||
package im.vector.matrix.android.api.session.crypto.sas
|
||||
|
||||
interface QRVerificationTransaction : VerificationTransaction {
|
||||
|
||||
fun userHasScannedRemoteQrCode(scannedData: String)
|
||||
|
||||
}
|
|
@ -0,0 +1,30 @@
|
|||
/*
|
||||
* Copyright 2020 New Vector Ltd
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package im.vector.matrix.android.api.session.crypto.sas
|
||||
|
||||
interface QrCodeVerificationTransaction : VerificationTransaction {
|
||||
|
||||
/**
|
||||
* To use to display a qr code, for the other user to scan it
|
||||
*/
|
||||
val qrCodeText: String?
|
||||
|
||||
/**
|
||||
* Call when you have scan the other user QR code
|
||||
*/
|
||||
fun userHasScannedRemoteQrCode(otherQrCodeText: String): CancelCode?
|
||||
}
|
|
@ -67,7 +67,10 @@ interface VerificationService {
|
|||
/**
|
||||
* Returns false if the request is unknown
|
||||
*/
|
||||
fun readyPendingVerificationInDMs(otherUserId: String, roomId: String, transactionId: String): Boolean
|
||||
fun readyPendingVerificationInDMs(methods: List<VerificationMethod>,
|
||||
otherUserId: String,
|
||||
roomId: String,
|
||||
transactionId: String): Boolean
|
||||
|
||||
// fun transactionUpdated(tx: SasVerificationTransaction)
|
||||
|
||||
|
|
|
@ -24,6 +24,8 @@ interface VerificationTransaction {
|
|||
val transactionId: String
|
||||
val otherUserId: String
|
||||
var otherDeviceId: String?
|
||||
|
||||
// TODO Not used. Remove?
|
||||
val isIncoming: Boolean
|
||||
/**
|
||||
* User wants to cancel the transaction
|
||||
|
|
|
@ -33,11 +33,3 @@ internal fun VerificationMethod.toValue(): String {
|
|||
VerificationMethod.QR_CODE_SHOW -> VERIFICATION_METHOD_QR_CODE_SHOW
|
||||
}
|
||||
}
|
||||
|
||||
internal val supportedVerificationMethods =
|
||||
listOf(
|
||||
VERIFICATION_METHOD_SAS,
|
||||
VERIFICATION_METHOD_QR_CODE_SHOW,
|
||||
VERIFICATION_METHOD_QR_CODE_SCAN,
|
||||
VERIFICATION_METHOD_RECIPROCATE
|
||||
)
|
||||
|
|
|
@ -55,11 +55,12 @@ import im.vector.matrix.android.internal.crypto.model.rest.KeyVerificationKey
|
|||
import im.vector.matrix.android.internal.crypto.model.rest.KeyVerificationMac
|
||||
import im.vector.matrix.android.internal.crypto.model.rest.KeyVerificationStart
|
||||
import im.vector.matrix.android.internal.crypto.model.rest.VERIFICATION_METHOD_QR_CODE_SCAN
|
||||
import im.vector.matrix.android.internal.crypto.model.rest.VERIFICATION_METHOD_QR_CODE_SHOW
|
||||
import im.vector.matrix.android.internal.crypto.model.rest.VERIFICATION_METHOD_RECIPROCATE
|
||||
import im.vector.matrix.android.internal.crypto.model.rest.VERIFICATION_METHOD_SAS
|
||||
import im.vector.matrix.android.internal.crypto.model.rest.supportedVerificationMethods
|
||||
import im.vector.matrix.android.internal.crypto.model.rest.toValue
|
||||
import im.vector.matrix.android.internal.crypto.store.IMXCryptoStore
|
||||
import im.vector.matrix.android.internal.crypto.verification.qrcode.DefaultQrCodeVerificationTransaction
|
||||
import im.vector.matrix.android.internal.crypto.verification.qrcode.QrCodeData
|
||||
import im.vector.matrix.android.internal.crypto.verification.qrcode.generateSharedSecret
|
||||
import im.vector.matrix.android.internal.crypto.verification.qrcode.toUrl
|
||||
|
@ -413,6 +414,16 @@ internal class DefaultVerificationService @Inject constructor(
|
|||
autoAccept).also { txConfigure(it) }
|
||||
addTransaction(tx)
|
||||
tx.acceptVerificationEvent(otherUserId, startReq)
|
||||
} else if (startReq.method == VERIFICATION_METHOD_RECIPROCATE) {
|
||||
// Other user has scanned my QR code
|
||||
val pendingTransaction = getExistingTransaction(otherUserId, startReq.transactionID!!)
|
||||
|
||||
if (pendingTransaction != null && pendingTransaction is DefaultQrCodeVerificationTransaction) {
|
||||
pendingTransaction.onStartReceived(startReq)
|
||||
} else {
|
||||
Timber.w("## SAS onStartRequestReceived - unknown transaction ${startReq.transactionID}")
|
||||
return CancelCode.UnknownTransaction
|
||||
}
|
||||
} else {
|
||||
Timber.e("## SAS onStartRequestReceived - unknown method ${startReq.method}")
|
||||
return CancelCode.UnknownMethod
|
||||
|
@ -606,7 +617,7 @@ internal class DefaultVerificationService @Inject constructor(
|
|||
return
|
||||
}
|
||||
|
||||
handleReadyReceived(event.senderId, readyReq)
|
||||
handleReadyReceived(event.senderId, event.roomId!!, readyReq)
|
||||
}
|
||||
|
||||
private fun onRoomDoneReceived(event: Event) {
|
||||
|
@ -651,7 +662,7 @@ internal class DefaultVerificationService @Inject constructor(
|
|||
}
|
||||
}
|
||||
|
||||
private fun handleReadyReceived(senderId: String, readyReq: VerificationInfoReady) {
|
||||
private fun handleReadyReceived(senderId: String, roomId: String, readyReq: VerificationInfoReady) {
|
||||
val existingRequest = getExistingVerificationRequest(senderId)?.find { it.transactionId == readyReq.transactionID }
|
||||
if (existingRequest == null) {
|
||||
Timber.e("## SAS Received Ready for unknown request txId:${readyReq.transactionID} fromDevice ${readyReq.fromDevice}")
|
||||
|
@ -710,10 +721,26 @@ internal class DefaultVerificationService @Inject constructor(
|
|||
).toUrl()
|
||||
}
|
||||
|
||||
if (qrCodeText != null) {
|
||||
// Create the pending transaction
|
||||
val tx = DefaultQrCodeVerificationTransaction(
|
||||
readyReq.transactionID!!,
|
||||
senderId,
|
||||
readyReq.fromDevice,
|
||||
crossSigningService,
|
||||
cryptoStore,
|
||||
myGeneratedSharedSecret!!,
|
||||
qrCodeText,
|
||||
deviceId ?: "",
|
||||
false)
|
||||
|
||||
tx.transport = verificationTransportRoomMessageFactory.createTransport(roomId, tx)
|
||||
|
||||
addTransaction(tx)
|
||||
}
|
||||
|
||||
updatePendingRequest(existingRequest.copy(
|
||||
readyInfo = readyReq,
|
||||
myGeneratedSecret = myGeneratedSharedSecret,
|
||||
qrCodeText = qrCodeText
|
||||
readyInfo = readyReq
|
||||
))
|
||||
}
|
||||
|
||||
|
@ -916,23 +943,26 @@ internal class DefaultVerificationService @Inject constructor(
|
|||
}
|
||||
}
|
||||
|
||||
override fun readyPendingVerificationInDMs(otherUserId: String, roomId: String, transactionId: String): Boolean {
|
||||
override fun readyPendingVerificationInDMs(methods: List<VerificationMethod>,
|
||||
otherUserId: String,
|
||||
roomId: String,
|
||||
transactionId: String): Boolean {
|
||||
Timber.v("## SAS readyPendingVerificationInDMs $otherUserId room:$roomId tx:$transactionId")
|
||||
// Let's find the related request
|
||||
val existingRequest = getExistingVerificationRequest(otherUserId, transactionId)
|
||||
if (existingRequest != null) {
|
||||
// we need to send a ready event, with matching methods
|
||||
val transport = verificationTransportRoomMessageFactory.createTransport(roomId, null)
|
||||
// TODO We should not use supportedVerificationMethods here, because it depends on the client implementation
|
||||
val methods = existingRequest.requestInfo?.methods?.intersect(supportedVerificationMethods)?.toList()
|
||||
val computedMethods = computeReadyMethods(existingRequest.requestInfo?.methods, methods)
|
||||
if (methods.isNullOrEmpty()) {
|
||||
Timber.i("Cannot ready this request, no common methods found txId:$transactionId")
|
||||
// TODO buttons should not be shown in this case?
|
||||
return false
|
||||
}
|
||||
// TODO this is not yet related to a transaction, maybe we should use another method like for cancel?
|
||||
val readyMsg = transport.createReady(transactionId, deviceId ?: "", methods)
|
||||
transport.sendToOther(EventType.KEY_VERIFICATION_READY, readyMsg,
|
||||
val readyMsg = transport.createReady(transactionId, deviceId ?: "", computedMethods)
|
||||
transport.sendToOther(EventType.KEY_VERIFICATION_READY,
|
||||
readyMsg,
|
||||
VerificationTxState.None,
|
||||
CancelCode.User,
|
||||
null // TODO handle error?
|
||||
|
@ -946,6 +976,31 @@ internal class DefaultVerificationService @Inject constructor(
|
|||
}
|
||||
}
|
||||
|
||||
private fun computeReadyMethods(otherUserMethods: List<String>?, methods: List<VerificationMethod>): List<String> {
|
||||
if (otherUserMethods.isNullOrEmpty()) {
|
||||
return emptyList()
|
||||
}
|
||||
|
||||
val result = mutableSetOf<String>()
|
||||
|
||||
if (VERIFICATION_METHOD_SAS in otherUserMethods && VerificationMethod.SAS in methods) {
|
||||
// Other can do SAS and so do I
|
||||
result + VERIFICATION_METHOD_SAS
|
||||
}
|
||||
if (VERIFICATION_METHOD_QR_CODE_SCAN in otherUserMethods && VerificationMethod.QR_CODE_SHOW in methods) {
|
||||
// Other can Scan and I can show QR code
|
||||
result + VERIFICATION_METHOD_QR_CODE_SHOW
|
||||
result + VERIFICATION_METHOD_RECIPROCATE
|
||||
}
|
||||
if (VERIFICATION_METHOD_QR_CODE_SHOW in otherUserMethods && VerificationMethod.QR_CODE_SCAN in methods) {
|
||||
// Other can show and I can scan QR code
|
||||
result + VERIFICATION_METHOD_QR_CODE_SCAN
|
||||
result + VERIFICATION_METHOD_RECIPROCATE
|
||||
}
|
||||
|
||||
return result.toList()
|
||||
}
|
||||
|
||||
/**
|
||||
* This string must be unique for the pair of users performing verification for the duration that the transaction is valid
|
||||
*/
|
||||
|
|
|
@ -38,12 +38,7 @@ data class PendingVerificationRequest(
|
|||
val readyInfo: VerificationInfoReady? = null,
|
||||
val cancelConclusion: CancelCode? = null,
|
||||
val isSuccessful: Boolean = false,
|
||||
val handledByOtherSession: Boolean = false,
|
||||
// TODO Move to OutgoingQrCodeTransaction
|
||||
val myGeneratedSecret: String? = null,
|
||||
// TODO Move to OutgoingQrCodeTransaction
|
||||
val qrCodeText: String? = null
|
||||
|
||||
val handledByOtherSession: Boolean = false
|
||||
) {
|
||||
val isReady: Boolean = readyInfo != null
|
||||
val isSent: Boolean = transactionId != null
|
||||
|
|
|
@ -0,0 +1,156 @@
|
|||
/*
|
||||
* Copyright 2020 New Vector Ltd
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package im.vector.matrix.android.internal.crypto.verification.qrcode
|
||||
|
||||
import im.vector.matrix.android.api.MatrixCallback
|
||||
import im.vector.matrix.android.api.session.crypto.crosssigning.CrossSigningService
|
||||
import im.vector.matrix.android.api.session.crypto.sas.CancelCode
|
||||
import im.vector.matrix.android.api.session.crypto.sas.QrCodeVerificationTransaction
|
||||
import im.vector.matrix.android.api.session.crypto.sas.VerificationTxState
|
||||
import im.vector.matrix.android.api.session.events.model.EventType
|
||||
import im.vector.matrix.android.internal.crypto.model.rest.SignatureUploadResponse
|
||||
import im.vector.matrix.android.internal.crypto.store.IMXCryptoStore
|
||||
import im.vector.matrix.android.internal.crypto.verification.DefaultVerificationTransaction
|
||||
import im.vector.matrix.android.internal.crypto.verification.VerificationInfo
|
||||
import im.vector.matrix.android.internal.crypto.verification.VerificationInfoStart
|
||||
import timber.log.Timber
|
||||
import kotlin.properties.Delegates
|
||||
|
||||
internal class DefaultQrCodeVerificationTransaction(
|
||||
override val transactionId: String,
|
||||
override val otherUserId: String,
|
||||
override var otherDeviceId: String?,
|
||||
private val crossSigningService: CrossSigningService,
|
||||
private val cryptoStore: IMXCryptoStore,
|
||||
private val myGeneratedSecret: String,
|
||||
override val qrCodeText: String,
|
||||
val deviceId: String,
|
||||
override val isIncoming: Boolean
|
||||
) : DefaultVerificationTransaction(transactionId, otherUserId, otherDeviceId, isIncoming), QrCodeVerificationTransaction {
|
||||
|
||||
override var cancelledReason: CancelCode? = null
|
||||
|
||||
override var state by Delegates.observable(VerificationTxState.None) { _, _, _ ->
|
||||
listeners.forEach {
|
||||
try {
|
||||
it.transactionUpdated(this)
|
||||
} catch (e: Throwable) {
|
||||
Timber.e(e, "## Error while notifying listeners")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun userHasScannedRemoteQrCode(otherQrCodeText: String): CancelCode? {
|
||||
val qrCodeData = otherQrCodeText.toQrCodeData() ?: return CancelCode.QrCodeInvalid
|
||||
|
||||
// Perform some checks
|
||||
if (qrCodeData.action != QrCodeData.ACTION_VERIFY) {
|
||||
return CancelCode.QrCodeInvalid
|
||||
}
|
||||
|
||||
if (qrCodeData.userId != otherUserId) {
|
||||
return CancelCode.UserMismatchError
|
||||
}
|
||||
|
||||
if (qrCodeData.requestEventId != transactionId) {
|
||||
return CancelCode.QrCodeInvalid
|
||||
}
|
||||
|
||||
// check master key
|
||||
if (qrCodeData.otherUserKey != crossSigningService.getUserCrossSigningKeys(otherUserId)?.masterKey()?.unpaddedBase64PublicKey) {
|
||||
return CancelCode.MismatchedKeys
|
||||
}
|
||||
|
||||
val otherDevices = cryptoStore.getUserDevices(otherUserId)
|
||||
qrCodeData.keys.keys.forEach { key ->
|
||||
Timber.w("Checking key $key")
|
||||
val fingerprint = otherDevices?.get(key)?.fingerprint()
|
||||
if (fingerprint != null && fingerprint != qrCodeData.keys[key]) {
|
||||
return CancelCode.MismatchedKeys
|
||||
}
|
||||
}
|
||||
|
||||
// All checks are correct
|
||||
|
||||
// Trust the other user
|
||||
trust()
|
||||
state = VerificationTxState.Verified
|
||||
|
||||
// Send the shared secret so that sender can trust me
|
||||
// qrCodeData.sharedSecret will be used to send the start request
|
||||
start(qrCodeData.sharedSecret)
|
||||
|
||||
return null
|
||||
}
|
||||
|
||||
fun start(remoteSecret: String) {
|
||||
if (state != VerificationTxState.None) {
|
||||
Timber.e("## SAS O: start verification from invalid state")
|
||||
// should I cancel??
|
||||
throw IllegalStateException("Interactive Key verification already started")
|
||||
}
|
||||
|
||||
val startMessage = transport.createStartForQrCode(
|
||||
deviceId,
|
||||
transactionId,
|
||||
remoteSecret
|
||||
)
|
||||
|
||||
transport.sendToOther(
|
||||
EventType.KEY_VERIFICATION_START,
|
||||
startMessage,
|
||||
VerificationTxState.Started,
|
||||
CancelCode.User,
|
||||
null
|
||||
)
|
||||
}
|
||||
|
||||
override fun acceptVerificationEvent(senderId: String, info: VerificationInfo) {
|
||||
}
|
||||
|
||||
override fun cancel() {
|
||||
cancel(CancelCode.User)
|
||||
}
|
||||
|
||||
override fun cancel(code: CancelCode) {
|
||||
cancelledReason = code
|
||||
state = VerificationTxState.Cancelled
|
||||
transport.cancelTransaction(transactionId, otherUserId, otherDeviceId ?: "", code)
|
||||
}
|
||||
|
||||
override fun isToDeviceTransport() = false
|
||||
|
||||
// Remote user has scanned our QR code. check that the secret matched, so we can trust him
|
||||
fun onStartReceived(startReq: VerificationInfoStart) {
|
||||
if (startReq.sharedSecret == myGeneratedSecret) {
|
||||
// Ok, we can trust the other user
|
||||
trust()
|
||||
} else {
|
||||
// Display a warning
|
||||
cancelledReason = CancelCode.QrCodeInvalid
|
||||
state = VerificationTxState.OnCancelled
|
||||
}
|
||||
}
|
||||
|
||||
private fun trust() {
|
||||
crossSigningService.trustUser(otherUserId, object : MatrixCallback<SignatureUploadResponse> {
|
||||
override fun onFailure(failure: Throwable) {
|
||||
Timber.e(failure, "## QR Verification: Failed to trust User $otherUserId")
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
|
@ -31,7 +31,7 @@ import com.squareup.inject.assisted.AssistedInject
|
|||
import im.vector.matrix.android.api.MatrixCallback
|
||||
import im.vector.matrix.android.api.session.Session
|
||||
import im.vector.matrix.android.api.session.crypto.sas.CancelCode
|
||||
import im.vector.matrix.android.api.session.crypto.sas.QRVerificationTransaction
|
||||
import im.vector.matrix.android.api.session.crypto.sas.QrCodeVerificationTransaction
|
||||
import im.vector.matrix.android.api.session.crypto.sas.SasVerificationTransaction
|
||||
import im.vector.matrix.android.api.session.crypto.sas.VerificationMethod
|
||||
import im.vector.matrix.android.api.session.crypto.sas.VerificationService
|
||||
|
@ -166,7 +166,7 @@ class VerificationBottomSheetViewModel @AssistedInject constructor(@Assisted ini
|
|||
}
|
||||
is VerificationAction.RemoteQrCodeScanned -> {
|
||||
val existingTransaction = session.getVerificationService()
|
||||
.getExistingTransaction(action.otherUserId, action.transactionId) as? QRVerificationTransaction
|
||||
.getExistingTransaction(action.otherUserId, action.transactionId) as? QrCodeVerificationTransaction
|
||||
existingTransaction
|
||||
?.userHasScannedRemoteQrCode(action.scannedData)
|
||||
}
|
||||
|
|
|
@ -22,8 +22,9 @@ import com.airbnb.mvrx.ViewModelContext
|
|||
import com.squareup.inject.assisted.Assisted
|
||||
import com.squareup.inject.assisted.AssistedInject
|
||||
import im.vector.matrix.android.api.session.Session
|
||||
import im.vector.matrix.android.api.session.crypto.sas.VerificationService
|
||||
import im.vector.matrix.android.api.session.crypto.sas.QrCodeVerificationTransaction
|
||||
import im.vector.matrix.android.api.session.crypto.sas.VerificationMethod
|
||||
import im.vector.matrix.android.api.session.crypto.sas.VerificationService
|
||||
import im.vector.matrix.android.api.session.crypto.sas.VerificationTransaction
|
||||
import im.vector.matrix.android.internal.crypto.verification.PendingVerificationRequest
|
||||
import im.vector.riotx.core.di.HasScreenInjector
|
||||
|
@ -46,9 +47,19 @@ class VerificationChooseMethodViewModel @AssistedInject constructor(
|
|||
private val session: Session
|
||||
) : VectorViewModel<VerificationChooseMethodViewState, EmptyAction, EmptyViewEvents>(initialState), VerificationService.VerificationListener {
|
||||
|
||||
override fun transactionCreated(tx: VerificationTransaction) {}
|
||||
override fun transactionCreated(tx: VerificationTransaction) {
|
||||
transactionUpdated(tx)
|
||||
}
|
||||
|
||||
override fun transactionUpdated(tx: VerificationTransaction) {}
|
||||
override fun transactionUpdated(tx: VerificationTransaction) = withState { state ->
|
||||
if (tx.transactionId == state.transactionId && tx is QrCodeVerificationTransaction) {
|
||||
setState {
|
||||
copy(
|
||||
qrCodeText = tx.qrCodeText
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun verificationRequestUpdated(pr: PendingVerificationRequest) = withState { state ->
|
||||
val pvr = session.getVerificationService().getExistingVerificationRequest(state.otherUserId, state.transactionId)
|
||||
|
@ -57,7 +68,6 @@ class VerificationChooseMethodViewModel @AssistedInject constructor(
|
|||
copy(
|
||||
otherCanShowQrCode = pvr?.hasMethod(VerificationMethod.QR_CODE_SHOW) ?: false,
|
||||
otherCanScanQrCode = pvr?.hasMethod(VerificationMethod.QR_CODE_SCAN) ?: false,
|
||||
qrCodeText = pvr?.qrCodeText,
|
||||
SASModeAvailable = pvr?.hasMethod(VerificationMethod.SAS) ?: false
|
||||
)
|
||||
}
|
||||
|
@ -92,7 +102,6 @@ class VerificationChooseMethodViewModel @AssistedInject constructor(
|
|||
transactionId = args.verificationId ?: "",
|
||||
otherCanShowQrCode = pvr?.hasMethod(VerificationMethod.QR_CODE_SHOW) ?: false,
|
||||
otherCanScanQrCode = pvr?.hasMethod(VerificationMethod.QR_CODE_SCAN) ?: false,
|
||||
qrCodeText = pvr?.qrCodeText,
|
||||
SASModeAvailable = pvr?.hasMethod(VerificationMethod.SAS) ?: false
|
||||
)
|
||||
}
|
||||
|
|
|
@ -809,7 +809,10 @@ class RoomDetailViewModel @AssistedInject constructor(@Assisted initialState: Ro
|
|||
|
||||
private fun handleAcceptVerification(action: RoomDetailAction.AcceptVerificationRequest) {
|
||||
Timber.v("## SAS handleAcceptVerification ${action.otherUserId}, roomId:${room.roomId}, txId:${action.transactionId}")
|
||||
if (session.getVerificationService().readyPendingVerificationInDMs(action.otherUserId, room.roomId,
|
||||
if (session.getVerificationService().readyPendingVerificationInDMs(
|
||||
supportedVerificationMethods,
|
||||
action.otherUserId,
|
||||
room.roomId,
|
||||
action.transactionId)) {
|
||||
_requestLiveData.postValue(LiveEvent(Success(action)))
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue