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 86965760c7..372064c128 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 @@ -55,11 +55,15 @@ import im.vector.matrix.android.internal.crypto.model.rest.KeyVerificationCancel 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_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.QrCodeData +import im.vector.matrix.android.internal.crypto.verification.qrcode.generateSharedSecret +import im.vector.matrix.android.internal.crypto.verification.qrcode.toUrl import im.vector.matrix.android.internal.session.SessionScope import im.vector.matrix.android.internal.util.MatrixCoroutineDispatchers import kotlinx.coroutines.GlobalScope @@ -72,6 +76,9 @@ import kotlin.collections.set @SessionScope internal class DefaultVerificationService @Inject constructor( + // TODO @UserId private val userId: String, + // TODO @DeviceId private val deviceId: String, + // TODO Do not use credential (do it in a dedicated commit) private val credentials: Credentials, private val cryptoStore: IMXCryptoStore, private val myDeviceInfoHolder: Lazy, @@ -650,7 +657,63 @@ internal class DefaultVerificationService @Inject constructor( Timber.e("## SAS Received Ready for unknown request txId:${readyReq.transactionID} fromDevice ${readyReq.fromDevice}") return } - updatePendingRequest(existingRequest.copy(readyInfo = readyReq)) + + var myGeneratedSharedSecret: String? = null + val qrCodeText = readyReq.methods + // Check if other user is able to scan QR code + ?.takeIf { it.contains(VERIFICATION_METHOD_QR_CODE_SCAN) } + ?.let { + // Build the QR code URL + val requestEventId = existingRequest.transactionId ?: run { + Timber.w("Unknown requestEventId") + return@let null + } + + val myMasterKey = crossSigningService.getMyCrossSigningKeys() + ?.masterKey() + ?.unpaddedBase64PublicKey + ?: run { + Timber.w("Unable to get my master key") + return@let null + } + + val otherUserMasterKey = crossSigningService.getUserCrossSigningKeys(existingRequest.otherUserId) + ?.masterKey() + ?.unpaddedBase64PublicKey + ?: run { + Timber.w("Unable to get other user master key") + return@let null + } + + val myDeviceId = credentials.deviceId + ?: run { + Timber.w("Unable to get my deviceId") + return@let null + } + + // TODO I'm pretty sure it's the correct key to put here + val myDeviceKey = myDeviceInfoHolder.get().myDevice.fingerprint()!! + + val generatedSharedSecret = generateSharedSecret() + .also { myGeneratedSharedSecret = it } + QrCodeData( + userId = credentials.userId, + requestEventId = requestEventId, + action = QrCodeData.ACTION_VERIFY, + keys = hashMapOf( + myMasterKey to myMasterKey, + myDeviceId to myDeviceKey + ), + sharedSecret = generatedSharedSecret, + otherUserKey = otherUserMasterKey + ).toUrl() + } + + updatePendingRequest(existingRequest.copy( + readyInfo = readyReq, + myGeneratedSecret = myGeneratedSharedSecret, + qrCodeText = qrCodeText + )) } private fun handleDoneReceived(senderId: String, doneInfo: VerificationInfo) { diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/verification/PendingVerificationRequest.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/verification/PendingVerificationRequest.kt index 531d2c8fa1..573da614fb 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/verification/PendingVerificationRequest.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/verification/PendingVerificationRequest.kt @@ -37,7 +37,9 @@ data class PendingVerificationRequest( val readyInfo: VerificationInfoReady? = null, val cancelConclusion: CancelCode? = null, val isSuccessful: Boolean = false, - val handledByOtherSession: Boolean = false + val handledByOtherSession: Boolean = false, + val myGeneratedSecret: String? = null, + val qrCodeText: String? = null ) { val isReady: Boolean = readyInfo != null diff --git a/vector/src/main/java/im/vector/riotx/features/crypto/verification/choose/VerificationChooseMethodController.kt b/vector/src/main/java/im/vector/riotx/features/crypto/verification/choose/VerificationChooseMethodController.kt index f5568331a9..87bb843291 100644 --- a/vector/src/main/java/im/vector/riotx/features/crypto/verification/choose/VerificationChooseMethodController.kt +++ b/vector/src/main/java/im/vector/riotx/features/crypto/verification/choose/VerificationChooseMethodController.kt @@ -49,10 +49,10 @@ class VerificationChooseMethodController @Inject constructor( notice(stringProvider.getString(R.string.verification_scan_notice)) } - if (state.otherCanScanQrCode && !state.QRtext.isNullOrBlank()) { + if (state.otherCanScanQrCode && !state.qrCodeText.isNullOrBlank()) { bottomSheetVerificationQrCodeItem { id("qr") - data(state.QRtext) + data(state.qrCodeText) animate(false) } diff --git a/vector/src/main/java/im/vector/riotx/features/crypto/verification/choose/VerificationChooseMethodViewModel.kt b/vector/src/main/java/im/vector/riotx/features/crypto/verification/choose/VerificationChooseMethodViewModel.kt index a9b24b5710..e4b8f75a8c 100644 --- a/vector/src/main/java/im/vector/riotx/features/crypto/verification/choose/VerificationChooseMethodViewModel.kt +++ b/vector/src/main/java/im/vector/riotx/features/crypto/verification/choose/VerificationChooseMethodViewModel.kt @@ -37,7 +37,7 @@ data class VerificationChooseMethodViewState( val transactionId: String = "", val otherCanShowQrCode: Boolean = false, val otherCanScanQrCode: Boolean = false, - val QRtext: String? = null, + val qrCodeText: String? = null, val SASModeAvailable: Boolean = false ) : MvRxState @@ -57,8 +57,7 @@ class VerificationChooseMethodViewModel @AssistedInject constructor( copy( otherCanShowQrCode = pvr?.hasMethod(VerificationMethod.QR_CODE_SHOW) ?: false, otherCanScanQrCode = pvr?.hasMethod(VerificationMethod.QR_CODE_SCAN) ?: false, - // TODO - QRtext = "https://www.example.org", + qrCodeText = pvr?.qrCodeText, SASModeAvailable = pvr?.hasMethod(VerificationMethod.SAS) ?: false ) } @@ -93,8 +92,7 @@ class VerificationChooseMethodViewModel @AssistedInject constructor( transactionId = args.verificationId ?: "", otherCanShowQrCode = pvr?.hasMethod(VerificationMethod.QR_CODE_SHOW) ?: false, otherCanScanQrCode = pvr?.hasMethod(VerificationMethod.QR_CODE_SCAN) ?: false, - // TODO - QRtext = "https://www.example.org", + qrCodeText = pvr?.qrCodeText, SASModeAvailable = pvr?.hasMethod(VerificationMethod.SAS) ?: false ) }