crypto: Move most of the getters of verification objecs into the olm machine

This commit is contained in:
Damir Jelić 2021-07-21 16:25:28 +02:00
parent 38ce3ebed7
commit cbed5be810
3 changed files with 96 additions and 82 deletions

View file

@ -392,7 +392,7 @@ internal class DefaultCryptoService @Inject constructor(
try { try {
setRustLogger() setRustLogger()
val machine = OlmMachine(userId, deviceId!!, dataDir, deviceObserver) val machine = OlmMachine(userId, deviceId!!, dataDir, deviceObserver, sender)
olmMachine = machine olmMachine = machine
verificationService = RustVerificationService(machine, this.sender) verificationService = RustVerificationService(machine, this.sender)
Timber.v( Timber.v(
@ -482,7 +482,7 @@ internal class DefaultCryptoService @Inject constructor(
override fun getDeviceInfo(userId: String, deviceId: String?): CryptoDeviceInfo? { override fun getDeviceInfo(userId: String, deviceId: String?): CryptoDeviceInfo? {
return if (userId.isNotEmpty() && !deviceId.isNullOrEmpty()) { return if (userId.isNotEmpty() && !deviceId.isNullOrEmpty()) {
runBlocking { runBlocking {
this@DefaultCryptoService.olmMachine?.getDevice(userId, deviceId) this@DefaultCryptoService.olmMachine?.getCryptoDeviceInfo(userId, deviceId)
} }
} else { } else {
null null

View file

@ -26,6 +26,8 @@ import kotlinx.coroutines.runBlocking
import kotlinx.coroutines.withContext import kotlinx.coroutines.withContext
import org.matrix.android.sdk.api.listeners.ProgressListener 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.MXCryptoError
import org.matrix.android.sdk.api.session.crypto.verification.VerificationService
import org.matrix.android.sdk.api.session.crypto.verification.VerificationTransaction
import org.matrix.android.sdk.api.session.events.model.Content 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.session.events.model.Event
import org.matrix.android.sdk.api.util.JsonDict import org.matrix.android.sdk.api.util.JsonDict
@ -49,8 +51,7 @@ import uniffi.olm.OlmMachine as InnerMachine
import uniffi.olm.ProgressListener as RustProgressListener import uniffi.olm.ProgressListener as RustProgressListener
import uniffi.olm.Request import uniffi.olm.Request
import uniffi.olm.RequestType import uniffi.olm.RequestType
import uniffi.olm.Verification import uniffi.olm.Verification as InnerVerification
import uniffi.olm.VerificationRequest
import uniffi.olm.setLogger import uniffi.olm.setLogger
class CryptoLogger : Logger { class CryptoLogger : Logger {
@ -122,10 +123,12 @@ internal class OlmMachine(
user_id: String, user_id: String,
device_id: String, device_id: String,
path: File, path: File,
deviceObserver: DeviceUpdateObserver deviceObserver: DeviceUpdateObserver,
private val requestSender: RequestSender,
) { ) {
private val inner: InnerMachine = InnerMachine(user_id, device_id, path.toString()) private val inner: InnerMachine = InnerMachine(user_id, device_id, path.toString())
private val deviceUpdateObserver = deviceObserver private val deviceUpdateObserver = deviceObserver
internal val verificationListeners = ArrayList<VerificationService.Listener>()
/** Get our own user ID. */ /** Get our own user ID. */
fun userId(): String { fun userId(): String {
@ -429,17 +432,26 @@ internal class OlmMachine(
* @return The Device if it found one. * @return The Device if it found one.
*/ */
@Throws(CryptoStoreErrorException::class) @Throws(CryptoStoreErrorException::class)
suspend fun getDevice(userId: String, deviceId: String): CryptoDeviceInfo? = suspend fun getCryptoDeviceInfo(userId: String, deviceId: String): CryptoDeviceInfo? {
withContext(Dispatchers.IO) { return if (userId == userId() && deviceId == deviceId()) {
// Our own device isn't part of our store on the rust side, return it // Our own device isn't part of our store on the Rust side, return it
// using our ownDevice method // using our ownDevice method
if (userId == userId() && deviceId == deviceId()) { ownDevice()
ownDevice() } else {
} else { val device = getRawDevice(userId, deviceId) ?: return null
val device = inner.getDevice(userId, deviceId) toCryptoDeviceInfo(device)
if (device != null) toCryptoDeviceInfo(device) else null }
} }
}
private suspend fun getRawDevice(userId: String, deviceId: String): InnerDevice? =
withContext(Dispatchers.IO) {
inner.getDevice(userId, deviceId)
}
suspend fun getDevice(userId: String, deviceId: String): Device? {
val device = this.getRawDevice(userId, deviceId) ?: return null
return Device(this.inner, device, this.requestSender, this.verificationListeners)
}
/** /**
* Get all devices of an user. * Get all devices of an user.
@ -546,19 +558,58 @@ internal class OlmMachine(
* @return The list of VerificationRequests that we share with the given user * @return The list of VerificationRequests that we share with the given user
*/ */
fun getVerificationRequests(userId: String): List<VerificationRequest> { fun getVerificationRequests(userId: String): List<VerificationRequest> {
return this.inner.getVerificationRequests(userId) return this.inner.getVerificationRequests(userId).map {
VerificationRequest(
this.inner,
it,
this.requestSender,
this.verificationListeners,
)
}
} }
/** Get a verification request for the given user with the given flow ID */ /** Get a verification request for the given user with the given flow ID */
fun getVerificationRequest(userId: String, flowId: String): VerificationRequest? { fun getVerificationRequest(userId: String, flowId: String): VerificationRequest? {
return this.inner.getVerificationRequest(userId, flowId) val request = this.inner.getVerificationRequest(userId, flowId)
return if (request != null) {
VerificationRequest(
this.inner,
request,
requestSender,
this.verificationListeners,
)
} else {
null
}
} }
/** Get an active verification for the given user and given flow ID /** Get an active verification for the given user and given flow ID
* *
* This can return a SAS verification or a QR code verification * This can return a SAS verification or a QR code verification
*/ */
fun getVerification(userId: String, flowId: String): Verification? { fun getVerification(userId: String, flowId: String): VerificationTransaction? {
return this.inner.getVerification(userId, flowId) return when (val verification = this.inner.getVerification(userId, flowId)) {
is uniffi.olm.Verification.QrCodeV1 -> {
val request = this.getVerificationRequest(userId, flowId) ?: return null
QrCodeVerification(inner, request, verification.qrcode, requestSender, verificationListeners)
}
is uniffi.olm.Verification.SasV1 -> {
SasVerification(inner, verification.sas, requestSender, verificationListeners)
}
null -> {
// This branch exists because scanning a QR code is tied to the QrCodeVerification,
// i.e. instead of branching into a scanned QR code verification from the verification request,
// like it's done for SAS verifications, the public API expects us to create an empty dummy
// QrCodeVerification object that gets populated once a QR code is scanned.
val request = getVerificationRequest(userId, flowId) ?: return null
if (request.canScanQrCodes()) {
QrCodeVerification(inner, request, null, requestSender, verificationListeners)
} else {
null
}
}
}
} }
} }

View file

@ -20,9 +20,7 @@ import android.os.Handler
import android.os.Looper import android.os.Looper
import com.squareup.moshi.Json import com.squareup.moshi.Json
import com.squareup.moshi.JsonClass import com.squareup.moshi.JsonClass
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.runBlocking import kotlinx.coroutines.runBlocking
import kotlinx.coroutines.withContext
import org.matrix.android.sdk.api.session.crypto.verification.PendingVerificationRequest import org.matrix.android.sdk.api.session.crypto.verification.PendingVerificationRequest
import org.matrix.android.sdk.api.session.crypto.verification.VerificationMethod 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.VerificationService
@ -34,7 +32,6 @@ import org.matrix.android.sdk.api.session.room.model.message.MessageRelationCont
import org.matrix.android.sdk.api.session.room.model.message.MessageType import org.matrix.android.sdk.api.session.room.model.message.MessageType
import org.matrix.android.sdk.internal.crypto.Device import org.matrix.android.sdk.internal.crypto.Device
import org.matrix.android.sdk.internal.crypto.OlmMachine 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.RequestSender
import org.matrix.android.sdk.internal.crypto.SasVerification import org.matrix.android.sdk.internal.crypto.SasVerification
import org.matrix.android.sdk.internal.crypto.VerificationRequest import org.matrix.android.sdk.internal.crypto.VerificationRequest
@ -43,14 +40,15 @@ import org.matrix.android.sdk.internal.crypto.model.rest.VERIFICATION_METHOD_QR_
import org.matrix.android.sdk.internal.crypto.model.rest.VERIFICATION_METHOD_RECIPROCATE import org.matrix.android.sdk.internal.crypto.model.rest.VERIFICATION_METHOD_RECIPROCATE
import org.matrix.android.sdk.internal.crypto.model.rest.toValue import org.matrix.android.sdk.internal.crypto.model.rest.toValue
import timber.log.Timber import timber.log.Timber
import uniffi.olm.Verification
/** A helper class to deserialize to-device `m.key.verification.*` events to fetch the transaction id out */
@JsonClass(generateAdapter = true) @JsonClass(generateAdapter = true)
internal data class ToDeviceVerificationEvent( internal data class ToDeviceVerificationEvent(
@Json(name = "sender") val sender: String?, @Json(name = "sender") val sender: String?,
@Json(name = "transaction_id") val transactionId: String, @Json(name = "transaction_id") val transactionId: String,
) )
/** Helper method to fetch the unique ID of the verification event */
private fun getFlowId(event: Event): String? { private fun getFlowId(event: Event): String? {
return if (event.eventId != null) { return if (event.eventId != null) {
val relatesTo = event.content.toModel<MessageRelationContent>()?.relatesTo val relatesTo = event.content.toModel<MessageRelationContent>()?.relatesTo
@ -61,6 +59,7 @@ private fun getFlowId(event: Event): String? {
} }
} }
/** Convert a list of VerificationMethod into a list of strings that can be passed to the Rust side */
internal fun prepareMethods(methods: List<VerificationMethod>): List<String> { internal fun prepareMethods(methods: List<VerificationMethod>): List<String> {
val stringMethods: MutableList<String> = methods.map { it.toValue() }.toMutableList() val stringMethods: MutableList<String> = methods.map { it.toValue() }.toMutableList()
@ -77,23 +76,22 @@ internal class RustVerificationService(
private val requestSender: RequestSender, private val requestSender: RequestSender,
) : VerificationService { ) : VerificationService {
private val uiHandler = Handler(Looper.getMainLooper()) private val uiHandler = Handler(Looper.getMainLooper())
private var listeners = ArrayList<VerificationService.Listener>()
override fun addListener(listener: VerificationService.Listener) { override fun addListener(listener: VerificationService.Listener) {
uiHandler.post { uiHandler.post {
if (!listeners.contains(listener)) { if (!this.olmMachine.verificationListeners.contains(listener)) {
listeners.add(listener) this.olmMachine.verificationListeners.add(listener)
} }
} }
} }
override fun removeListener(listener: VerificationService.Listener) { override fun removeListener(listener: VerificationService.Listener) {
uiHandler.post { listeners.remove(listener) } uiHandler.post { this.olmMachine.verificationListeners.remove(listener) }
} }
private fun dispatchTxAdded(tx: VerificationTransaction) { private fun dispatchTxAdded(tx: VerificationTransaction) {
uiHandler.post { uiHandler.post {
listeners.forEach { this.olmMachine.verificationListeners.forEach {
try { try {
it.transactionCreated(tx) it.transactionCreated(tx)
} catch (e: Throwable) { } catch (e: Throwable) {
@ -105,7 +103,7 @@ internal class RustVerificationService(
private fun dispatchTxUpdated(tx: VerificationTransaction) { private fun dispatchTxUpdated(tx: VerificationTransaction) {
uiHandler.post { uiHandler.post {
listeners.forEach { this.olmMachine.verificationListeners.forEach {
try { try {
it.transactionUpdated(tx) it.transactionUpdated(tx)
} catch (e: Throwable) { } catch (e: Throwable) {
@ -118,7 +116,7 @@ internal class RustVerificationService(
private fun dispatchRequestAdded(tx: PendingVerificationRequest) { private fun dispatchRequestAdded(tx: PendingVerificationRequest) {
Timber.v("## SAS dispatchRequestAdded txId:${tx.transactionId} $tx") Timber.v("## SAS dispatchRequestAdded txId:${tx.transactionId} $tx")
uiHandler.post { uiHandler.post {
listeners.forEach { this.olmMachine.verificationListeners.forEach {
try { try {
it.verificationRequestCreated(tx) it.verificationRequestCreated(tx)
} catch (e: Throwable) { } catch (e: Throwable) {
@ -188,30 +186,11 @@ internal class RustVerificationService(
} }
private fun getVerificationRequest(otherUserId: String, transactionId: String): VerificationRequest? { private fun getVerificationRequest(otherUserId: String, transactionId: String): VerificationRequest? {
val request = this.olmMachine.getVerificationRequest(otherUserId, transactionId) return this.olmMachine.getVerificationRequest(otherUserId, transactionId)
return if (request != null) {
VerificationRequest(
this.olmMachine.inner(),
request,
requestSender,
listeners,
)
} else {
null
}
} }
private suspend fun getDevice(userId: String, deviceID: String): Device? { private suspend fun getDevice(userId: String, deviceID: String): Device? {
val device = withContext(Dispatchers.IO) { return this.olmMachine.getDevice(userId, deviceID)
olmMachine.inner().getDevice(userId, deviceID)
}
return if (device != null) {
Device(this.olmMachine.inner(), device, this.requestSender, this.listeners)
} else {
null
}
} }
override fun markedLocallyAsManuallyVerified(userId: String, deviceID: String) { override fun markedLocallyAsManuallyVerified(userId: String, deviceID: String) {
@ -230,40 +209,14 @@ internal class RustVerificationService(
otherUserId: String, otherUserId: String,
tid: String, tid: String,
): VerificationTransaction? { ): VerificationTransaction? {
return when (val verification = this.olmMachine.getVerification(otherUserId, tid)) { return this.olmMachine.getVerification(otherUserId, tid)
is Verification.QrCodeV1 -> {
val request = getVerificationRequest(otherUserId, tid) ?: return null
QrCodeVerification(this.olmMachine.inner(), request, verification.qrcode, this.requestSender, this.listeners)
}
is Verification.SasV1 -> {
SasVerification(this.olmMachine.inner(), verification.sas, this.requestSender, this.listeners)
}
null -> {
// This branch exists because scanning a QR code is tied to the QrCodeVerification,
// i.e. instead of branching into a scanned QR code verification from the verification request,
// like it's done for SAS verifications, the public API expects us to create an empty dummy
// QrCodeVerification object that gets populated once a QR code is scanned.
val request = getVerificationRequest(otherUserId, tid) ?: return null
if (request.canScanQrCodes()) {
QrCodeVerification(this.olmMachine.inner(), request, null, this.requestSender, this.listeners)
} else {
null
}
}
}
} }
override fun getExistingVerificationRequests( override fun getExistingVerificationRequests(
otherUserId: String otherUserId: String
): List<PendingVerificationRequest> { ): List<PendingVerificationRequest> {
return this.olmMachine.getVerificationRequests(otherUserId).map { return this.olmMachine.getVerificationRequests(otherUserId).map {
VerificationRequest( it.toPendingVerificationRequest()
this.olmMachine.inner(),
it,
this.requestSender,
this.listeners,
).toPendingVerificationRequest()
} }
} }
@ -314,7 +267,12 @@ internal class RustVerificationService(
requestSender.sendVerificationRequest(result!!.request) requestSender.sendVerificationRequest(result!!.request)
} }
return VerificationRequest(this.olmMachine.inner(), result!!.verification, this.requestSender, this.listeners).toPendingVerificationRequest() return VerificationRequest(
this.olmMachine.inner(),
result!!.verification,
this.requestSender,
this.olmMachine.verificationListeners
).toPendingVerificationRequest()
} }
override fun requestKeyVerificationInDMs( override fun requestKeyVerificationInDMs(
@ -332,7 +290,12 @@ internal class RustVerificationService(
} }
val innerRequest = this.olmMachine.inner().requestVerification(otherUserId, roomId, eventID, stringMethods)!! val innerRequest = this.olmMachine.inner().requestVerification(otherUserId, roomId, eventID, stringMethods)!!
return VerificationRequest(this.olmMachine.inner(), innerRequest, this.requestSender, this.listeners).toPendingVerificationRequest() return VerificationRequest(
this.olmMachine.inner(),
innerRequest,
this.requestSender,
this.olmMachine.verificationListeners
).toPendingVerificationRequest()
} }
override fun readyPendingVerification( override fun readyPendingVerification(