crypto: Allow the displaying of QR codes

This commit is contained in:
Damir Jelić 2021-06-25 20:24:56 +02:00
parent d15269a4bd
commit 6523ca5afe
4 changed files with 212 additions and 23 deletions

View File

@ -16,6 +16,8 @@
package org.matrix.android.sdk.internal.crypto
import android.os.Handler
import android.os.Looper
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import java.io.File
@ -26,10 +28,16 @@ import kotlinx.coroutines.runBlocking
import kotlinx.coroutines.withContext
import org.matrix.android.sdk.api.listeners.ProgressListener
import org.matrix.android.sdk.api.session.crypto.MXCryptoError
import org.matrix.android.sdk.api.session.crypto.verification.CancelCode
import org.matrix.android.sdk.api.session.crypto.verification.QrCodeVerificationTransaction
import org.matrix.android.sdk.api.session.crypto.verification.VerificationService
import org.matrix.android.sdk.api.session.crypto.verification.VerificationTxState
import org.matrix.android.sdk.api.session.crypto.verification.safeValueOf
import org.matrix.android.sdk.api.session.events.model.Content
import org.matrix.android.sdk.api.session.events.model.Event
import org.matrix.android.sdk.api.util.JsonDict
import org.matrix.android.sdk.internal.crypto.crosssigning.DeviceTrustLevel
import org.matrix.android.sdk.internal.crypto.crosssigning.fromBase64
import org.matrix.android.sdk.internal.crypto.model.CryptoDeviceInfo
import org.matrix.android.sdk.internal.crypto.model.ImportRoomKeysResult
import org.matrix.android.sdk.internal.crypto.model.MXUsersDevicesMap
@ -45,11 +53,14 @@ import uniffi.olm.Device
import uniffi.olm.DeviceLists
import uniffi.olm.KeyRequestPair
import uniffi.olm.Logger
import uniffi.olm.OutgoingVerificationRequest
import uniffi.olm.QrCode
import uniffi.olm.OlmMachine as InnerMachine
import uniffi.olm.ProgressListener as RustProgressListener
import uniffi.olm.Request
import uniffi.olm.RequestType
import uniffi.olm.Sas
import uniffi.olm.Verification
import uniffi.olm.VerificationRequest
import uniffi.olm.setLogger
class CryptoLogger : Logger {
@ -117,6 +128,136 @@ internal class DeviceUpdateObserver {
}
}
internal class QrCodeVerification(
private val machine: uniffi.olm.OlmMachine,
private var inner: QrCode,
private val sender: RequestSender,
private val listeners: ArrayList<VerificationService.Listener>,
) : QrCodeVerificationTransaction {
private val uiHandler = Handler(Looper.getMainLooper())
private var stateField: VerificationTxState = VerificationTxState.OnStarted
private fun dispatchTxUpdated() {
uiHandler.post {
listeners.forEach {
try {
it.transactionUpdated(this)
} catch (e: Throwable) {
Timber.e(e, "## Error while notifying listeners")
}
}
}
}
override val qrCodeText: String?
get() {
val data = this.machine.generateQrCode(this.inner.otherUserId, this.inner.flowId)
// TODO Why are we encoding this to ISO_8859_1? If we're going to encode, why not base64?
return data?.fromBase64()?.toString(Charsets.ISO_8859_1)
}
override fun userHasScannedOtherQrCode(otherQrCodeText: String) {
TODO("Not yet implemented")
}
override fun otherUserScannedMyQrCode() {
val request = runBlocking { confirm() } ?: return
sendRequest(request)
}
override fun otherUserDidNotScannedMyQrCode() {
// TODO Is this code correct here? The old code seems to do this
cancelHelper(CancelCode.MismatchedKeys)
}
override var state: VerificationTxState
get() {
refreshData()
val state = when {
this.inner.isDone -> VerificationTxState.Verified
this.inner.otherSideScanned -> VerificationTxState.QrScannedByOther
this.inner.isCancelled -> {
val cancelCode = safeValueOf(this.inner.cancelCode)
val byMe = this.inner.cancelledByUs ?: false
VerificationTxState.Cancelled(cancelCode, byMe)
}
else -> {
VerificationTxState.None
}
}
return state
}
@Suppress("UNUSED_PARAMETER")
set(value) {}
override val transactionId: String
get() = this.inner.flowId
override val otherUserId: String
get() = this.inner.otherUserId
override var otherDeviceId: String?
get() = this.inner.otherDeviceId
@Suppress("UNUSED_PARAMETER")
set(value) {}
override val isIncoming: Boolean
get() = !this.inner.weStarted
override fun cancel() {
cancelHelper(CancelCode.User)
}
override fun cancel(code: CancelCode) {
cancelHelper(code)
}
override fun isToDeviceTransport(): Boolean {
return this.inner.roomId == null
}
@Throws(CryptoStoreErrorException::class)
suspend fun confirm(): OutgoingVerificationRequest? =
withContext(Dispatchers.IO) {
machine.confirmVerification(inner.otherUserId, inner.flowId)
}
private fun sendRequest(request: OutgoingVerificationRequest) {
runBlocking {
when (request) {
is OutgoingVerificationRequest.ToDevice -> {
sender.sendToDevice(request.eventType, request.body)
}
is OutgoingVerificationRequest.InRoom -> TODO()
}
}
refreshData()
dispatchTxUpdated()
}
private fun cancelHelper(code: CancelCode) {
val request = this.machine.cancelVerification(this.inner.otherUserId, inner.flowId, code.value)
if (request != null) {
sendRequest(request)
}
}
private fun refreshData() {
when (val verification = this.machine.getVerification(this.inner.otherUserId, this.inner.flowId)) {
is Verification.QrCodeV1 -> {
this.inner = verification.qrcode
}
else -> {}
}
return
}
}
internal class OlmMachine(
user_id: String,
device_id: String,
@ -523,24 +664,16 @@ internal class OlmMachine(
runBlocking { inner.discardRoomKey(roomId) }
}
fun getVerificationRequests(userId: String): List<VerificationRequest> {
return this.inner.getVerificationRequests(userId).map {
VerificationRequest(this.inner, it)
}
fun getVerificationRequests(userId: String): List<uniffi.olm.VerificationRequest> {
return this.inner.getVerificationRequests(userId)
}
fun getVerificationRequest(userId: String, flowId: String): VerificationRequest? {
val request = this.inner.getVerificationRequest(userId, flowId)
return if (request == null) {
null
} else {
VerificationRequest(this.inner, request)
}
return this.inner.getVerificationRequest(userId, flowId)
}
/** Get an active verification */
fun getVerification(userId: String, flowId: String): Sas? {
fun getVerification(userId: String, flowId: String): Verification? {
return this.inner.getVerification(userId, flowId)
}
}

View File

@ -33,6 +33,7 @@ import uniffi.olm.CryptoStoreErrorException
import uniffi.olm.OlmMachine
import uniffi.olm.OutgoingVerificationRequest
import uniffi.olm.Sas
import uniffi.olm.Verification
internal class SasVerification(
private val machine: OlmMachine,
@ -57,10 +58,11 @@ internal class SasVerification(
}
private fun refreshData() {
val sas = this.machine.getVerification(this.inner.otherUserId, this.inner.flowId)
if (sas != null) {
this.inner = sas
when (val verification = this.machine.getVerification(this.inner.otherUserId, this.inner.flowId)) {
is Verification.SasV1 -> {
this.inner = verification.sas
}
else -> {}
}
return

View File

@ -22,6 +22,7 @@ import org.matrix.android.sdk.api.session.crypto.verification.PendingVerificatio
import org.matrix.android.sdk.api.session.crypto.verification.ValidVerificationInfoReady
import org.matrix.android.sdk.api.session.crypto.verification.ValidVerificationInfoRequest
import org.matrix.android.sdk.api.session.crypto.verification.VerificationMethod
import org.matrix.android.sdk.api.session.crypto.verification.VerificationService
import org.matrix.android.sdk.api.session.crypto.verification.safeValueOf
import org.matrix.android.sdk.internal.crypto.model.rest.VERIFICATION_METHOD_QR_CODE_SCAN
import org.matrix.android.sdk.internal.crypto.model.rest.VERIFICATION_METHOD_QR_CODE_SHOW
@ -34,7 +35,9 @@ import uniffi.olm.VerificationRequest
internal class VerificationRequest(
private val machine: OlmMachine,
private var inner: VerificationRequest
private var inner: VerificationRequest,
private val sender: RequestSender,
private val listeners: ArrayList<VerificationService.Listener>,
) {
private fun refreshData() {
val request = this.machine.getVerificationRequest(this.inner.otherUserId, this.inner.flowId)
@ -46,6 +49,21 @@ internal class VerificationRequest(
return
}
internal fun startQrVerification(): QrCodeVerification? {
val qrcode = this.machine.startQrVerification(this.inner.otherUserId, this.inner.flowId)
return if (qrcode != null) {
QrCodeVerification(
this.machine,
qrcode,
this.sender,
this.listeners,
)
} else {
null
}
}
fun acceptWithMethods(methods: List<VerificationMethod>): OutgoingVerificationRequest? {
val stringMethods: MutableList<String> =
methods

View File

@ -29,14 +29,17 @@ import org.matrix.android.sdk.api.session.events.model.EventType
import org.matrix.android.sdk.api.session.events.model.toModel
import org.matrix.android.sdk.api.session.room.model.message.MessageType
import org.matrix.android.sdk.internal.crypto.OlmMachine
import org.matrix.android.sdk.internal.crypto.QrCodeVerification
import org.matrix.android.sdk.internal.crypto.RequestSender
import org.matrix.android.sdk.internal.crypto.SasVerification
import org.matrix.android.sdk.internal.crypto.VerificationRequest
import org.matrix.android.sdk.internal.crypto.model.rest.KeyVerificationDone
import org.matrix.android.sdk.internal.crypto.model.rest.KeyVerificationKey
import org.matrix.android.sdk.internal.crypto.model.rest.KeyVerificationRequest
import org.matrix.android.sdk.internal.session.SessionScope
import timber.log.Timber
import uniffi.olm.OutgoingVerificationRequest
import uniffi.olm.Verification
@SessionScope
internal class RustVerificationService
@ -183,13 +186,16 @@ constructor(
tid: String,
): VerificationTransaction? {
val verification = this.olmMachine.getVerification(otherUserId, tid) ?: return null
return SasVerification(this.olmMachine.inner(), verification, this.requestSender, this.listeners)
return when (verification) {
is Verification.QrCodeV1 -> QrCodeVerification(this.olmMachine.inner(), verification.qrcode, this.requestSender, this.listeners)
is Verification.SasV1 -> SasVerification(this.olmMachine.inner(), verification.sas, this.requestSender, this.listeners)
}
}
override fun getExistingVerificationRequests(
otherUserId: String
): List<PendingVerificationRequest> {
return this.olmMachine.getVerificationRequests(otherUserId).map {
return this.getVerificationRequests(otherUserId).map {
it.toPendingVerificationRequest()
}
}
@ -199,7 +205,7 @@ constructor(
tid: String?
): PendingVerificationRequest? {
return if (tid != null) {
olmMachine.getVerificationRequest(otherUserId, tid)?.toPendingVerificationRequest()
this.getVerificationRequest(otherUserId, tid)?.toPendingVerificationRequest()
} else {
null
}
@ -221,7 +227,7 @@ constructor(
// should check if already one (and cancel it)
return if (method == VerificationMethod.SAS) {
val flowId = transactionId ?: return null
val request = this.olmMachine.getVerificationRequest(otherUserId, flowId)
val request = this.getVerificationRequest(otherUserId, flowId)
runBlocking {
val response = request?.startSasVerification()
if (response != null) {
@ -297,12 +303,38 @@ constructor(
return true
}
private fun getVerificationRequest(otherUserId: String, transactionId: String): VerificationRequest? {
val request = this.olmMachine.getVerificationRequest(otherUserId, transactionId)
return if (request != null) {
VerificationRequest(
this.olmMachine.inner(),
request,
requestSender,
listeners,
)
} else {
null
}
}
private fun getVerificationRequests(userId: String): List<VerificationRequest> {
return this.olmMachine.getVerificationRequests(userId).map {
VerificationRequest(
this.olmMachine.inner(),
it,
this.requestSender,
this.listeners,
)
}
}
override fun readyPendingVerification(
methods: List<VerificationMethod>,
otherUserId: String,
transactionId: String
): Boolean {
val request = this.olmMachine.getVerificationRequest(otherUserId, transactionId)
val request = this.getVerificationRequest(otherUserId, transactionId)
return if (request != null) {
val outgoingRequest = request.acceptWithMethods(methods)
@ -310,6 +342,10 @@ constructor(
if (outgoingRequest != null) {
runBlocking { sendRequest(outgoingRequest) }
dispatchRequestUpdated(request.toPendingVerificationRequest())
val qrcode = request.startQrVerification()
if (qrcode != null) {
dispatchTxAdded(qrcode)
}
true
} else {
false