Continue cleaning mostly on coroutine

This commit is contained in:
ganfra 2022-04-15 18:52:35 +02:00
parent ba540eb861
commit 9cb43ce4c8
11 changed files with 304 additions and 245 deletions

View File

@ -16,7 +16,6 @@
package org.matrix.android.sdk.api.session.crypto.crosssigning package org.matrix.android.sdk.api.session.crypto.crosssigning
import androidx.lifecycle.LiveData
import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.Flow
import org.matrix.android.sdk.api.MatrixCallback import org.matrix.android.sdk.api.MatrixCallback
import org.matrix.android.sdk.api.auth.UserInteractiveAuthInterceptor import org.matrix.android.sdk.api.auth.UserInteractiveAuthInterceptor
@ -62,8 +61,8 @@ interface CrossSigningService {
* by the server and if they do so * by the server and if they do so
*/ */
suspend fun checkTrustFromPrivateKeys(masterKeyPrivateKey: String?, suspend fun checkTrustFromPrivateKeys(masterKeyPrivateKey: String?,
uskKeyPrivateKey: String?, uskKeyPrivateKey: String?,
sskPrivateKey: String?): UserTrustResult sskPrivateKey: String?): UserTrustResult
/** /**
* Get the public cross signing keys for the given user * Get the public cross signing keys for the given user
@ -94,7 +93,7 @@ interface CrossSigningService {
/** Mark a user identity as trusted and sign and upload signatures of our user-signing key to the server */ /** Mark a user identity as trusted and sign and upload signatures of our user-signing key to the server */
suspend fun trustUser(otherUserId: String, suspend fun trustUser(otherUserId: String,
callback: MatrixCallback<Unit>) callback: MatrixCallback<Unit>)
/** Mark our own master key as trusted */ /** Mark our own master key as trusted */
suspend fun markMyMasterKeyAsTrusted() suspend fun markMyMasterKeyAsTrusted()
@ -115,9 +114,9 @@ interface CrossSigningService {
* key of another user. * key of another user.
*/ */
suspend fun checkDeviceTrust(otherUserId: String, suspend fun checkDeviceTrust(otherUserId: String,
otherDeviceId: String, otherDeviceId: String,
// TODO what is locallyTrusted used for? // TODO what is locallyTrusted used for?
locallyTrusted: Boolean?): DeviceTrustResult locallyTrusted: Boolean?): DeviceTrustResult
// FIXME Those method do not have to be in the service // FIXME Those method do not have to be in the service
// TODO those three methods doesn't seem to be used anywhere? // TODO those three methods doesn't seem to be used anywhere?

View File

@ -988,18 +988,17 @@ internal class DefaultCryptoService @Inject constructor(
val cancellation = requestPair.cancellation val cancellation = requestPair.cancellation
val request = requestPair.keyRequest val request = requestPair.keyRequest
if (cancellation != null) { when (cancellation) {
when (cancellation) { is Request.ToDevice -> {
is Request.ToDevice -> { sendToDevice(cancellation)
sendToDevice(cancellation)
}
} }
else -> Unit
} }
when (request) { when (request) {
is Request.ToDevice -> { is Request.ToDevice -> {
sendToDevice(request) sendToDevice(request)
} }
else -> Unit
} }
} }
} }
@ -1100,7 +1099,7 @@ internal class DefaultCryptoService @Inject constructor(
} }
try { try {
preshareRoomKey(roomId, userIds) preshareRoomKey(roomId, userIds)
}catch (failure: Throwable){ } catch (failure: Throwable) {
Timber.tag(loggerTag.value).e("prepareToEncrypt() : Failed to PreshareRoomKey") Timber.tag(loggerTag.value).e("prepareToEncrypt() : Failed to PreshareRoomKey")
} }
} }

View File

@ -16,8 +16,8 @@
package org.matrix.android.sdk.internal.crypto package org.matrix.android.sdk.internal.crypto
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext import kotlinx.coroutines.withContext
import org.matrix.android.sdk.api.MatrixCoroutineDispatchers
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
import org.matrix.android.sdk.internal.crypto.crosssigning.DeviceTrustLevel import org.matrix.android.sdk.internal.crypto.crosssigning.DeviceTrustLevel
@ -39,16 +39,17 @@ internal class Device(
private val machine: OlmMachine, private val machine: OlmMachine,
private var inner: InnerDevice, private var inner: InnerDevice,
private val sender: RequestSender, private val sender: RequestSender,
private val coroutineDispatchers: MatrixCoroutineDispatchers,
private val listeners: ArrayList<VerificationService.Listener> private val listeners: ArrayList<VerificationService.Listener>
) { ) {
@Throws(CryptoStoreException::class) @Throws(CryptoStoreException::class)
private suspend fun refreshData() { private suspend fun refreshData() {
val device = withContext(Dispatchers.IO) { val device = withContext(coroutineDispatchers.io) {
machine.getDevice(inner.userId, inner.deviceId) machine.getDevice(inner.userId, inner.deviceId)
} }
if (device != null) { if (device != null) {
this.inner = device inner = device
} }
} }
@ -66,12 +67,12 @@ internal class Device(
@Throws(CryptoStoreException::class) @Throws(CryptoStoreException::class)
suspend fun requestVerification(methods: List<VerificationMethod>): VerificationRequest? { suspend fun requestVerification(methods: List<VerificationMethod>): VerificationRequest? {
val stringMethods = prepareMethods(methods) val stringMethods = prepareMethods(methods)
val result = withContext(Dispatchers.IO) { val result = withContext(coroutineDispatchers.io) {
machine.requestVerificationWithDevice(inner.userId, inner.deviceId, stringMethods) machine.requestVerificationWithDevice(inner.userId, inner.deviceId, stringMethods)
} }
return if (result != null) { return if (result != null) {
this.sender.sendVerificationRequest(result.request) sender.sendVerificationRequest(result.request)
result.verification result.verification
} else { } else {
null null
@ -89,14 +90,18 @@ internal class Device(
*/ */
@Throws(CryptoStoreException::class) @Throws(CryptoStoreException::class)
suspend fun startVerification(): SasVerification? { suspend fun startVerification(): SasVerification? {
val result = withContext(Dispatchers.IO) { val result = withContext(coroutineDispatchers.io) {
machine.startSasWithDevice(inner.userId, inner.deviceId) machine.startSasWithDevice(inner.userId, inner.deviceId)
} }
return if (result != null) { return if (result != null) {
this.sender.sendVerificationRequest(result.request) sender.sendVerificationRequest(result.request)
SasVerification( SasVerification(
this.machine, result.sas, this.sender, this.listeners, machine = machine,
inner = result.sas,
sender = sender,
coroutineDispatchers = coroutineDispatchers,
listeners = listeners
) )
} else { } else {
null null
@ -111,7 +116,7 @@ internal class Device(
*/ */
@Throws(CryptoStoreException::class) @Throws(CryptoStoreException::class)
suspend fun markAsTrusted() { suspend fun markAsTrusted() {
withContext(Dispatchers.IO) { withContext(coroutineDispatchers.io) {
machine.markDeviceAsTrusted(inner.userId, inner.deviceId) machine.markDeviceAsTrusted(inner.userId, inner.deviceId)
} }
} }
@ -127,11 +132,11 @@ internal class Device(
*/ */
@Throws(SignatureException::class) @Throws(SignatureException::class)
suspend fun verify(): Boolean { suspend fun verify(): Boolean {
val request = withContext(Dispatchers.IO) { val request = withContext(coroutineDispatchers.io) {
machine.verifyDevice(inner.userId, inner.deviceId) machine.verifyDevice(inner.userId, inner.deviceId)
} }
this.sender.sendSignatureUpload(request) sender.sendSignatureUpload(request)
return true return true
} }
@ -151,20 +156,20 @@ internal class Device(
* This will not fetch out fresh data from the Rust side. * This will not fetch out fresh data from the Rust side.
**/ **/
internal fun toCryptoDeviceInfo(): CryptoDeviceInfo { internal fun toCryptoDeviceInfo(): CryptoDeviceInfo {
val keys = this.inner.keys.map { (keyId, key) -> "$keyId:$this.inner.deviceId" to key }.toMap() val keys = inner.keys.map { (keyId, key) -> "$keyId:$inner.deviceId" to key }.toMap()
return CryptoDeviceInfo( return CryptoDeviceInfo(
this.inner.deviceId, deviceId = inner.deviceId,
this.inner.userId, userId = inner.userId,
this.inner.algorithms, algorithms = inner.algorithms,
keys, keys = keys,
// The Kotlin side doesn't need to care about signatures, // The Kotlin side doesn't need to care about signatures,
// so we're not filling this out // so we're not filling this out
mapOf(), signatures = mapOf(),
UnsignedDeviceInfo(this.inner.displayName), unsigned = UnsignedDeviceInfo(inner.displayName),
DeviceTrustLevel(crossSigningVerified = this.inner.crossSigningTrusted, locallyVerified = this.inner.locallyTrusted), trustLevel = DeviceTrustLevel(crossSigningVerified = inner.crossSigningTrusted, locallyVerified = inner.locallyTrusted),
this.inner.isBlocked, isBlocked = inner.isBlocked,
// TODO // TODO
null) firstTimeSeenLocalTs = null)
} }
} }

View File

@ -16,6 +16,7 @@
package org.matrix.android.sdk.internal.crypto package org.matrix.android.sdk.internal.crypto
import com.squareup.moshi.Moshi
import kotlinx.coroutines.channels.SendChannel import kotlinx.coroutines.channels.SendChannel
import kotlinx.coroutines.channels.awaitClose import kotlinx.coroutines.channels.awaitClose
import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.Flow
@ -102,7 +103,8 @@ internal class OlmMachine(
device_id: String, device_id: String,
path: File, path: File,
private val requestSender: RequestSender, private val requestSender: RequestSender,
private val coroutineDispatchers: MatrixCoroutineDispatchers private val coroutineDispatchers: MatrixCoroutineDispatchers,
private val moshi: Moshi
) { ) {
private val inner: InnerMachine = InnerMachine(user_id, device_id, path.toString()) private val inner: InnerMachine = InnerMachine(user_id, device_id, path.toString())
internal val verificationListeners = ArrayList<VerificationService.Listener>() internal val verificationListeners = ArrayList<VerificationService.Listener>()
@ -110,21 +112,21 @@ internal class OlmMachine(
/** Get our own user ID. */ /** Get our own user ID. */
fun userId(): String { fun userId(): String {
return this.inner.userId() return inner.userId()
} }
/** Get our own device ID. */ /** Get our own device ID. */
fun deviceId(): String { fun deviceId(): String {
return this.inner.deviceId() return inner.deviceId()
} }
/** Get our own public identity keys ID. */ /** Get our own public identity keys ID. */
fun identityKeys(): Map<String, String> { fun identityKeys(): Map<String, String> {
return this.inner.identityKeys() return inner.identityKeys()
} }
fun inner(): InnerMachine { fun inner(): InnerMachine {
return this.inner return inner
} }
private suspend fun updateLiveDevices() { private suspend fun updateLiveDevices() {
@ -142,7 +144,7 @@ internal class OlmMachine(
} }
private suspend fun updateLivePrivateKeys() { private suspend fun updateLivePrivateKeys() {
val keys = this.exportCrossSigningKeys().toOptional() val keys = exportCrossSigningKeys().toOptional()
for (privateKeyCollector in flowCollectors.privateKeyCollectors) { for (privateKeyCollector in flowCollectors.privateKeyCollectors) {
privateKeyCollector.send(keys) privateKeyCollector.send(keys)
} }
@ -152,18 +154,18 @@ internal class OlmMachine(
* Get our own device info as [CryptoDeviceInfo]. * Get our own device info as [CryptoDeviceInfo].
*/ */
suspend fun ownDevice(): CryptoDeviceInfo { suspend fun ownDevice(): CryptoDeviceInfo {
val deviceId = this.deviceId() val deviceId = deviceId()
val keys = this.identityKeys().map { (keyId, key) -> "$keyId:$deviceId" to key }.toMap() val keys = identityKeys().map { (keyId, key) -> "$keyId:$deviceId" to key }.toMap()
val crossSigningVerified = when (val ownIdentity = this.getIdentity(this.userId())) { val crossSigningVerified = when (val ownIdentity = getIdentity(userId())) {
is OwnUserIdentity -> ownIdentity.trustsOurOwnDevice() is OwnUserIdentity -> ownIdentity.trustsOurOwnDevice()
else -> false else -> false
} }
return CryptoDeviceInfo( return CryptoDeviceInfo(
this.deviceId(), deviceId(),
this.userId(), userId(),
// TODO pass the algorithms here. // TODO pass the algorithms here.
listOf(), listOf(),
keys, keys,
@ -238,7 +240,7 @@ internal class OlmMachine(
val devices = val devices =
DeviceLists(deviceChanges?.changed.orEmpty(), deviceChanges?.left.orEmpty()) DeviceLists(deviceChanges?.changed.orEmpty(), deviceChanges?.left.orEmpty())
val adapter = val adapter =
MoshiProvider.providesMoshi().adapter(ToDeviceSyncResponse::class.java) moshi.adapter(ToDeviceSyncResponse::class.java)
val events = adapter.toJson(toDevice ?: ToDeviceSyncResponse())!! val events = adapter.toJson(toDevice ?: ToDeviceSyncResponse())!!
// TODO once our sync response type parses the unused fallback key // TODO once our sync response type parses the unused fallback key
@ -247,7 +249,7 @@ internal class OlmMachine(
} }
// We may get cross signing keys over a to-device event, update our listeners. // We may get cross signing keys over a to-device event, update our listeners.
this.updateLivePrivateKeys() updateLivePrivateKeys()
return response return response
} }
@ -270,7 +272,7 @@ internal class OlmMachine(
*/ */
@Throws(CryptoStoreException::class) @Throws(CryptoStoreException::class)
fun isUserTracked(userId: String): Boolean { fun isUserTracked(userId: String): Boolean {
return this.inner.isUserTracked(userId) return inner.isUserTracked(userId)
} }
/** /**
@ -344,7 +346,7 @@ internal class OlmMachine(
@Throws(CryptoStoreException::class) @Throws(CryptoStoreException::class)
suspend fun encrypt(roomId: String, eventType: String, content: Content): Content = suspend fun encrypt(roomId: String, eventType: String, content: Content): Content =
withContext(coroutineDispatchers.io) { withContext(coroutineDispatchers.io) {
val adapter = MoshiProvider.providesMoshi().adapter<Content>(Map::class.java) val adapter = moshi.adapter<Content>(Map::class.java)
val contentString = adapter.toJson(content) val contentString = adapter.toJson(content)
val encrypted = inner.encrypt(roomId, eventType, contentString) val encrypted = inner.encrypt(roomId, eventType, contentString)
adapter.fromJson(encrypted)!! adapter.fromJson(encrypted)!!
@ -362,7 +364,7 @@ internal class OlmMachine(
@Throws(MXCryptoError::class) @Throws(MXCryptoError::class)
suspend fun decryptRoomEvent(event: Event): MXEventDecryptionResult = suspend fun decryptRoomEvent(event: Event): MXEventDecryptionResult =
withContext(coroutineDispatchers.io) { withContext(coroutineDispatchers.io) {
val adapter = MoshiProvider.providesMoshi().adapter(Event::class.java) val adapter = moshi.adapter(Event::class.java)
try { try {
if (event.roomId.isNullOrBlank()) { if (event.roomId.isNullOrBlank()) {
throw MXCryptoError.Base(MXCryptoError.ErrorType.MISSING_FIELDS, MXCryptoError.MISSING_FIELDS_REASON) throw MXCryptoError.Base(MXCryptoError.ErrorType.MISSING_FIELDS, MXCryptoError.MISSING_FIELDS_REASON)
@ -371,7 +373,7 @@ internal class OlmMachine(
val decrypted = inner.decryptRoomEvent(serializedEvent, event.roomId) val decrypted = inner.decryptRoomEvent(serializedEvent, event.roomId)
val deserializationAdapter = val deserializationAdapter =
MoshiProvider.providesMoshi().adapter<JsonDict>(Map::class.java) moshi.adapter<JsonDict>(Map::class.java)
val clearEvent = deserializationAdapter.fromJson(decrypted.clearEvent) val clearEvent = deserializationAdapter.fromJson(decrypted.clearEvent)
?: throw MXCryptoError.Base(MXCryptoError.ErrorType.MISSING_FIELDS, MXCryptoError.MISSING_FIELDS_REASON) ?: throw MXCryptoError.Base(MXCryptoError.ErrorType.MISSING_FIELDS, MXCryptoError.MISSING_FIELDS_REASON)
@ -402,7 +404,7 @@ internal class OlmMachine(
@Throws(DecryptionException::class) @Throws(DecryptionException::class)
suspend fun requestRoomKey(event: Event): KeyRequestPair = suspend fun requestRoomKey(event: Event): KeyRequestPair =
withContext(coroutineDispatchers.io) { withContext(coroutineDispatchers.io) {
val adapter = MoshiProvider.providesMoshi().adapter(Event::class.java) val adapter = moshi.adapter(Event::class.java)
val serializedEvent = adapter.toJson(event) val serializedEvent = adapter.toJson(event)
inner.requestRoomKey(serializedEvent, event.roomId!!) inner.requestRoomKey(serializedEvent, event.roomId!!)
@ -453,7 +455,7 @@ internal class OlmMachine(
listener: ProgressListener? listener: ProgressListener?
): ImportRoomKeysResult = ): ImportRoomKeysResult =
withContext(coroutineDispatchers.io) { withContext(coroutineDispatchers.io) {
val adapter = MoshiProvider.providesMoshi().adapter(List::class.java) val adapter = moshi.adapter(List::class.java)
// If the key backup is too big we take the risk of causing OOM // If the key backup is too big we take the risk of causing OOM
// when serializing to json // when serializing to json
@ -485,22 +487,28 @@ internal class OlmMachine(
val identity = withContext(coroutineDispatchers.io) { val identity = withContext(coroutineDispatchers.io) {
inner.getIdentity(userId) inner.getIdentity(userId)
} }
val adapter = MoshiProvider.providesMoshi().adapter(RestKeyInfo::class.java) val adapter = moshi.adapter(RestKeyInfo::class.java)
return when (identity) { return when (identity) {
is RustUserIdentity.Other -> { is RustUserIdentity.Other -> {
val verified = this.inner().isIdentityVerified(userId) val verified = inner().isIdentityVerified(userId)
val masterKey = adapter.fromJson(identity.masterKey)!!.toCryptoModel().apply { val masterKey = adapter.fromJson(identity.masterKey)!!.toCryptoModel().apply {
trustLevel = DeviceTrustLevel(verified, verified) trustLevel = DeviceTrustLevel(verified, verified)
} }
val selfSigningKey = adapter.fromJson(identity.selfSigningKey)!!.toCryptoModel().apply { val selfSigningKey = adapter.fromJson(identity.selfSigningKey)!!.toCryptoModel().apply {
trustLevel = DeviceTrustLevel(verified, verified) trustLevel = DeviceTrustLevel(verified, verified)
} }
UserIdentity(
UserIdentity(identity.userId, masterKey, selfSigningKey, this, this.requestSender) userId = identity.userId,
masterKey = masterKey,
selfSigningKey = selfSigningKey,
olmMachine = this,
requestSender = requestSender,
coroutineDispatchers = coroutineDispatchers
)
} }
is RustUserIdentity.Own -> { is RustUserIdentity.Own -> {
val verified = this.inner().isIdentityVerified(userId) val verified = inner().isIdentityVerified(userId)
val masterKey = adapter.fromJson(identity.masterKey)!!.toCryptoModel().apply { val masterKey = adapter.fromJson(identity.masterKey)!!.toCryptoModel().apply {
trustLevel = DeviceTrustLevel(verified, verified) trustLevel = DeviceTrustLevel(verified, verified)
@ -511,13 +519,14 @@ internal class OlmMachine(
val userSigningKey = adapter.fromJson(identity.userSigningKey)!!.toCryptoModel() val userSigningKey = adapter.fromJson(identity.userSigningKey)!!.toCryptoModel()
OwnUserIdentity( OwnUserIdentity(
identity.userId, userId = identity.userId,
masterKey, masterKey = masterKey,
selfSigningKey, selfSigningKey = selfSigningKey,
userSigningKey, userSigningKey = userSigningKey,
identity.trustsOurOwnDevice, trustsOurOwnDevice = identity.trustsOurOwnDevice,
this, olmMachine = this,
this.requestSender requestSender = requestSender,
coroutineDispatchers = coroutineDispatchers
) )
} }
null -> null null -> null
@ -552,12 +561,26 @@ internal class OlmMachine(
inner.getDevice(userId, deviceId) inner.getDevice(userId, deviceId)
} ?: return null } ?: return null
return Device(this.inner, device, this.requestSender, this.verificationListeners) return Device(
machine = inner,
inner = device,
sender = requestSender,
coroutineDispatchers = coroutineDispatchers,
listeners = verificationListeners
)
} }
suspend fun getUserDevices(userId: String): List<Device> { suspend fun getUserDevices(userId: String): List<Device> {
return withContext(coroutineDispatchers.io) { return withContext(coroutineDispatchers.io) {
inner.getUserDevices(userId).map { Device(inner, it, requestSender, verificationListeners) } inner.getUserDevices(userId).map {
Device(
machine = inner,
inner = it,
sender = requestSender,
coroutineDispatchers = coroutineDispatchers,
listeners = verificationListeners
)
}
} }
} }
@ -570,12 +593,12 @@ internal class OlmMachine(
*/ */
@Throws(CryptoStoreException::class) @Throws(CryptoStoreException::class)
suspend fun getCryptoDeviceInfo(userId: String): List<CryptoDeviceInfo> { suspend fun getCryptoDeviceInfo(userId: String): List<CryptoDeviceInfo> {
val devices = this.getUserDevices(userId).map { it.toCryptoDeviceInfo() }.toMutableList() val devices = getUserDevices(userId).map { it.toCryptoDeviceInfo() }.toMutableList()
// EA doesn't differentiate much between our own and other devices of // EA doesn't differentiate much between our own and other devices of
// while the rust-sdk does, append our own device here. // while the rust-sdk does, append our own device here.
if (userId == this.userId()) { if (userId == userId()) {
devices.add(this.ownDevice()) devices.add(ownDevice())
} }
return devices return devices
@ -592,7 +615,7 @@ internal class OlmMachine(
val plainDevices: ArrayList<CryptoDeviceInfo> = arrayListOf() val plainDevices: ArrayList<CryptoDeviceInfo> = arrayListOf()
for (user in userIds) { for (user in userIds) {
val devices = this.getCryptoDeviceInfo(user) val devices = getCryptoDeviceInfo(user)
plainDevices.addAll(devices) plainDevices.addAll(devices)
} }
@ -612,7 +635,7 @@ internal class OlmMachine(
val userMap = MXUsersDevicesMap<CryptoDeviceInfo>() val userMap = MXUsersDevicesMap<CryptoDeviceInfo>()
for (user in userIds) { for (user in userIds) {
val devices = this.getCryptoDeviceInfo(user) val devices = getCryptoDeviceInfo(user)
for (device in devices) { for (device in devices) {
userMap.setObject(user, device.deviceId, device) userMap.setObject(user, device.deviceId, device)
@ -703,26 +726,27 @@ internal class OlmMachine(
* @return The list of [VerificationRequest] that we share with the given user * @return The list of [VerificationRequest] that we share with the given user
*/ */
fun getVerificationRequests(userId: String): List<VerificationRequest> { fun getVerificationRequests(userId: String): List<VerificationRequest> {
return this.inner.getVerificationRequests(userId).map { return inner.getVerificationRequests(userId).map {
VerificationRequest( VerificationRequest(
this.inner, machine = inner,
it, inner = it,
this.requestSender, sender = requestSender,
this.verificationListeners, coroutineDispatchers = coroutineDispatchers,
listeners = 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? {
val request = this.inner.getVerificationRequest(userId, flowId) val request = inner.getVerificationRequest(userId, flowId)
return if (request != null) { return if (request != null) {
VerificationRequest( VerificationRequest(
this.inner, machine = inner,
request, inner = request,
requestSender, sender = requestSender,
this.verificationListeners, coroutineDispatchers = coroutineDispatchers,
listeners = verificationListeners,
) )
} else { } else {
null null
@ -735,13 +759,26 @@ internal class OlmMachine(
* verification. * verification.
*/ */
fun getVerification(userId: String, flowId: String): VerificationTransaction? { fun getVerification(userId: String, flowId: String): VerificationTransaction? {
return when (val verification = this.inner.getVerification(userId, flowId)) { return when (val verification = inner.getVerification(userId, flowId)) {
is uniffi.olm.Verification.QrCodeV1 -> { is uniffi.olm.Verification.QrCodeV1 -> {
val request = this.getVerificationRequest(userId, flowId) ?: return null val request = getVerificationRequest(userId, flowId) ?: return null
QrCodeVerification(inner, request, verification.qrcode, requestSender, verificationListeners) QrCodeVerification(
machine = inner,
request = request,
inner = verification.qrcode,
sender = requestSender,
coroutineDispatchers = coroutineDispatchers,
listeners = verificationListeners
)
} }
is uniffi.olm.Verification.SasV1 -> { is uniffi.olm.Verification.SasV1 -> {
SasVerification(inner, verification.sas, requestSender, verificationListeners) SasVerification(
machine = inner,
inner = verification.sas,
sender = requestSender,
coroutineDispatchers = coroutineDispatchers,
listeners = verificationListeners
)
} }
null -> { null -> {
// This branch exists because scanning a QR code is tied to the QrCodeVerification, // This branch exists because scanning a QR code is tied to the QrCodeVerification,
@ -751,7 +788,14 @@ internal class OlmMachine(
val request = getVerificationRequest(userId, flowId) ?: return null val request = getVerificationRequest(userId, flowId) ?: return null
if (request.canScanQrCodes()) { if (request.canScanQrCodes()) {
QrCodeVerification(inner, request, null, requestSender, verificationListeners) QrCodeVerification(
machine = inner,
request = request,
inner = null,
sender = requestSender,
coroutineDispatchers = coroutineDispatchers,
listeners = verificationListeners
)
} else { } else {
null null
} }
@ -763,16 +807,15 @@ internal class OlmMachine(
val requests = withContext(coroutineDispatchers.io) { val requests = withContext(coroutineDispatchers.io) {
inner.bootstrapCrossSigning() inner.bootstrapCrossSigning()
} }
requestSender.uploadCrossSigningKeys(requests.uploadSigningKeysRequest, uiaInterceptor)
this.requestSender.uploadCrossSigningKeys(requests.uploadSigningKeysRequest, uiaInterceptor) requestSender.sendSignatureUpload(requests.signatureRequest)
this.requestSender.sendSignatureUpload(requests.signatureRequest)
} }
/** /**
* Get the status of our private cross signing keys, i.e. which private keys do we have stored locally. * Get the status of our private cross signing keys, i.e. which private keys do we have stored locally.
*/ */
fun crossSigningStatus(): CrossSigningStatus { fun crossSigningStatus(): CrossSigningStatus {
return this.inner.crossSigningStatus() return inner.crossSigningStatus()
} }
suspend fun exportCrossSigningKeys(): PrivateKeysInfo? { suspend fun exportCrossSigningKeys(): PrivateKeysInfo? {
@ -867,8 +910,7 @@ internal class OlmMachine(
@Throws(CryptoStoreException::class) @Throws(CryptoStoreException::class)
suspend fun checkAuthDataSignature(authData: MegolmBackupAuthData): Boolean { suspend fun checkAuthDataSignature(authData: MegolmBackupAuthData): Boolean {
return withContext(coroutineDispatchers.computation) { return withContext(coroutineDispatchers.computation) {
val adapter = MoshiProvider val adapter = moshi
.providesMoshi()
.newBuilder() .newBuilder()
.add(CheckNumberType.JSON_ADAPTER_FACTORY) .add(CheckNumberType.JSON_ADAPTER_FACTORY)
.build() .build()

View File

@ -16,6 +16,7 @@
package org.matrix.android.sdk.internal.crypto package org.matrix.android.sdk.internal.crypto
import com.squareup.moshi.Moshi
import org.matrix.android.sdk.api.MatrixCoroutineDispatchers import org.matrix.android.sdk.api.MatrixCoroutineDispatchers
import org.matrix.android.sdk.internal.di.DeviceId import org.matrix.android.sdk.internal.di.DeviceId
import org.matrix.android.sdk.internal.di.SessionFilesDirectory import org.matrix.android.sdk.internal.di.SessionFilesDirectory
@ -30,8 +31,15 @@ internal class OlmMachineProvider @Inject constructor(
@DeviceId private val deviceId: String?, @DeviceId private val deviceId: String?,
@SessionFilesDirectory private val dataDir: File, @SessionFilesDirectory private val dataDir: File,
requestSender: RequestSender, requestSender: RequestSender,
coroutineDispatchers: MatrixCoroutineDispatchers coroutineDispatchers: MatrixCoroutineDispatchers,
moshi: Moshi
) { ) {
var olmMachine: OlmMachine = OlmMachine(userId, deviceId!!, dataDir, requestSender, coroutineDispatchers) var olmMachine: OlmMachine = OlmMachine(
user_id = userId,
device_id = deviceId!!,
path = dataDir,
requestSender = requestSender,
coroutineDispatchers = coroutineDispatchers,
moshi = moshi)
} }

View File

@ -16,8 +16,8 @@
package org.matrix.android.sdk.internal.crypto package org.matrix.android.sdk.internal.crypto
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext import kotlinx.coroutines.withContext
import org.matrix.android.sdk.api.MatrixCoroutineDispatchers
import org.matrix.android.sdk.api.session.crypto.verification.CancelCode 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.QrCodeVerificationTransaction
import org.matrix.android.sdk.api.session.crypto.verification.VerificationService import org.matrix.android.sdk.api.session.crypto.verification.VerificationService
@ -36,13 +36,15 @@ internal class QrCodeVerification(
private var request: VerificationRequest, private var request: VerificationRequest,
private var inner: QrCode?, private var inner: QrCode?,
private val sender: RequestSender, private val sender: RequestSender,
private val coroutineDispatchers: MatrixCoroutineDispatchers,
listeners: ArrayList<VerificationService.Listener> listeners: ArrayList<VerificationService.Listener>
) : QrCodeVerificationTransaction { ) : QrCodeVerificationTransaction {
private val dispatcher = UpdateDispatcher(listeners) private val dispatcher = UpdateDispatcher(listeners)
private fun dispatchTxUpdated() { private fun dispatchTxUpdated() {
refreshData() refreshData()
this.dispatcher.dispatchTxUpdated(this) dispatcher.dispatchTxUpdated(this)
} }
/** Generate, if possible, data that should be encoded as a QR code for QR code verification. /** Generate, if possible, data that should be encoded as a QR code for QR code verification.
@ -59,7 +61,7 @@ internal class QrCodeVerification(
*/ */
override val qrCodeText: String? override val qrCodeText: String?
get() { get() {
val data = this.inner?.let { this.machine.generateQrCode(it.otherUserId, it.flowId) } val data = inner?.let { machine.generateQrCode(it.otherUserId, it.flowId) }
// TODO Why are we encoding this to ISO_8859_1? If we're going to encode, why not base64? // 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) return data?.fromBase64()?.toString(Charsets.ISO_8859_1)
@ -85,7 +87,7 @@ internal class QrCodeVerification(
override var state: VerificationTxState override var state: VerificationTxState
get() { get() {
refreshData() refreshData()
val inner = this.inner val inner = inner
val cancelInfo = inner?.cancelInfo val cancelInfo = inner?.cancelInfo
return if (inner != null) { return if (inner != null) {
@ -111,22 +113,22 @@ internal class QrCodeVerification(
/** Get the unique id of this verification */ /** Get the unique id of this verification */
override val transactionId: String override val transactionId: String
get() = this.request.flowId() get() = request.flowId()
/** Get the user id of the other user participating in this verification flow */ /** Get the user id of the other user participating in this verification flow */
override val otherUserId: String override val otherUserId: String
get() = this.request.otherUser() get() = request.otherUser()
/** Get the device id of the other user's device participating in this verification flow */ /** Get the device id of the other user's device participating in this verification flow */
override var otherDeviceId: String? override var otherDeviceId: String?
get() = this.request.otherDeviceId() get() = request.otherDeviceId()
@Suppress("UNUSED_PARAMETER") @Suppress("UNUSED_PARAMETER")
set(value) { set(value) {
} }
/** Did the other side initiate this verification flow */ /** Did the other side initiate this verification flow */
override val isIncoming: Boolean override val isIncoming: Boolean
get() = !this.request.weStarted() get() = !request.weStarted()
/** Cancel the verification flow /** Cancel the verification flow
* *
@ -158,7 +160,7 @@ internal class QrCodeVerification(
/** Is this verification happening over to-device messages */ /** Is this verification happening over to-device messages */
override fun isToDeviceTransport(): Boolean { override fun isToDeviceTransport(): Boolean {
return this.request.roomId() == null return request.roomId() == null
} }
/** Confirm the QR code verification /** Confirm the QR code verification
@ -171,24 +173,24 @@ internal class QrCodeVerification(
*/ */
@Throws(CryptoStoreException::class) @Throws(CryptoStoreException::class)
private suspend fun confirm() { private suspend fun confirm() {
val result = withContext(Dispatchers.IO) { val result = withContext(coroutineDispatchers.io) {
machine.confirmVerification(request.otherUser(), request.flowId()) machine.confirmVerification(request.otherUser(), request.flowId())
} }
if (result != null) { if (result != null) {
this.sender.sendVerificationRequest(result.request) sender.sendVerificationRequest(result.request)
dispatchTxUpdated() dispatchTxUpdated()
val signatureRequest = result.signatureRequest val signatureRequest = result.signatureRequest
if (signatureRequest != null) { if (signatureRequest != null) {
this.sender.sendSignatureUpload(signatureRequest) sender.sendSignatureUpload(signatureRequest)
} }
} }
} }
private suspend fun cancelHelper(code: CancelCode) { private suspend fun cancelHelper(code: CancelCode) {
val request = this.machine.cancelVerification(this.request.otherUser(), this.request.flowId(), code.value) val request = machine.cancelVerification(request.otherUser(), request.flowId(), code.value)
if (request != null) { if (request != null) {
sender.sendVerificationRequest(request) sender.sendVerificationRequest(request)
@ -198,9 +200,9 @@ internal class QrCodeVerification(
/** Fetch fresh data from the Rust side for our verification flow */ /** Fetch fresh data from the Rust side for our verification flow */
private fun refreshData() { private fun refreshData() {
when (val verification = this.machine.getVerification(this.request.otherUser(), this.request.flowId())) { when (val verification = machine.getVerification(request.otherUser(), request.flowId())) {
is Verification.QrCodeV1 -> { is Verification.QrCodeV1 -> {
this.inner = verification.qrcode inner = verification.qrcode
} }
else -> { else -> {
} }

View File

@ -16,7 +16,6 @@
package org.matrix.android.sdk.internal.crypto package org.matrix.android.sdk.internal.crypto
import androidx.lifecycle.LiveData
import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.Flow
import org.matrix.android.sdk.api.MatrixCallback import org.matrix.android.sdk.api.MatrixCallback
import org.matrix.android.sdk.api.NoOpMatrixCallback import org.matrix.android.sdk.api.NoOpMatrixCallback
@ -31,7 +30,6 @@ import org.matrix.android.sdk.internal.crypto.crosssigning.UserTrustResult
import org.matrix.android.sdk.internal.crypto.crosssigning.isVerified import org.matrix.android.sdk.internal.crypto.crosssigning.isVerified
import org.matrix.android.sdk.internal.crypto.store.PrivateKeysInfo import org.matrix.android.sdk.internal.crypto.store.PrivateKeysInfo
import org.matrix.android.sdk.internal.di.UserId import org.matrix.android.sdk.internal.di.UserId
import org.matrix.android.sdk.internal.extensions.foldToCallback
import javax.inject.Inject import javax.inject.Inject
internal class RustCrossSigningService @Inject constructor( internal class RustCrossSigningService @Inject constructor(
@ -54,7 +52,7 @@ internal class RustCrossSigningService @Inject constructor(
override suspend fun isUserTrusted(otherUserId: String): Boolean { override suspend fun isUserTrusted(otherUserId: String): Boolean {
// This seems to be used only in tests. // This seems to be used only in tests.
return this.checkUserTrust(otherUserId).isVerified() return checkUserTrust(otherUserId).isVerified()
} }
/** /**
@ -136,13 +134,13 @@ internal class RustCrossSigningService @Inject constructor(
* Returning true means that we have the private self-signing and user-signing keys at hand. * Returning true means that we have the private self-signing and user-signing keys at hand.
*/ */
override fun canCrossSign(): Boolean { override fun canCrossSign(): Boolean {
val status = this.olmMachine.crossSigningStatus() val status = olmMachine.crossSigningStatus()
return status.hasSelfSigning && status.hasUserSigning return status.hasSelfSigning && status.hasUserSigning
} }
override fun allPrivateKeysKnown(): Boolean { override fun allPrivateKeysKnown(): Boolean {
val status = this.olmMachine.crossSigningStatus() val status = olmMachine.crossSigningStatus()
return status.hasMaster && status.hasSelfSigning && status.hasUserSigning return status.hasMaster && status.hasSelfSigning && status.hasUserSigning
} }
@ -163,7 +161,7 @@ internal class RustCrossSigningService @Inject constructor(
/** Mark our own master key as trusted */ /** Mark our own master key as trusted */
override suspend fun markMyMasterKeyAsTrusted() { override suspend fun markMyMasterKeyAsTrusted() {
// This doesn't seem to be used? // This doesn't seem to be used?
this.trustUser(this.olmMachine.userId(), NoOpMatrixCallback()) trustUser(olmMachine.userId(), NoOpMatrixCallback())
} }
/** /**
@ -213,7 +211,7 @@ internal class RustCrossSigningService @Inject constructor(
} }
override fun onSecretUSKGossip(uskPrivateKey: String) { override fun onSecretUSKGossip(uskPrivateKey: String) {
// And this. // And
} }
override suspend fun shieldForGroup(userIds: List<String>): RoomEncryptionTrustLevel { override suspend fun shieldForGroup(userIds: List<String>): RoomEncryptionTrustLevel {

View File

@ -16,8 +16,8 @@
package org.matrix.android.sdk.internal.crypto package org.matrix.android.sdk.internal.crypto
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext import kotlinx.coroutines.withContext
import org.matrix.android.sdk.api.MatrixCoroutineDispatchers
import org.matrix.android.sdk.api.session.crypto.verification.CancelCode import org.matrix.android.sdk.api.session.crypto.verification.CancelCode
import org.matrix.android.sdk.api.session.crypto.verification.EmojiRepresentation import org.matrix.android.sdk.api.session.crypto.verification.EmojiRepresentation
import org.matrix.android.sdk.api.session.crypto.verification.SasVerificationTransaction import org.matrix.android.sdk.api.session.crypto.verification.SasVerificationTransaction
@ -36,6 +36,7 @@ internal class SasVerification(
private val machine: OlmMachine, private val machine: OlmMachine,
private var inner: Sas, private var inner: Sas,
private val sender: RequestSender, private val sender: RequestSender,
private val coroutineDispatchers: MatrixCoroutineDispatchers,
listeners: ArrayList<VerificationService.Listener> listeners: ArrayList<VerificationService.Listener>
) : ) :
SasVerificationTransaction { SasVerificationTransaction {
@ -43,27 +44,27 @@ internal class SasVerification(
private fun dispatchTxUpdated() { private fun dispatchTxUpdated() {
refreshData() refreshData()
this.dispatcher.dispatchTxUpdated(this) dispatcher.dispatchTxUpdated(this)
} }
/** The user ID of the other user that is participating in this verification flow */ /** The user ID of the other user that is participating in this verification flow */
override val otherUserId: String = this.inner.otherUserId override val otherUserId: String = inner.otherUserId
/** Get the device id of the other user's device participating in this verification flow */ /** Get the device id of the other user's device participating in this verification flow */
override var otherDeviceId: String? override var otherDeviceId: String?
get() = this.inner.otherDeviceId get() = inner.otherDeviceId
@Suppress("UNUSED_PARAMETER") @Suppress("UNUSED_PARAMETER")
set(value) { set(value) {
} }
/** Did the other side initiate this verification flow */ /** Did the other side initiate this verification flow */
override val isIncoming: Boolean override val isIncoming: Boolean
get() = !this.inner.weStarted get() = !inner.weStarted
override var state: VerificationTxState override var state: VerificationTxState
get() { get() {
refreshData() refreshData()
val cancelInfo = this.inner.cancelInfo val cancelInfo = inner.cancelInfo
return when { return when {
cancelInfo != null -> { cancelInfo != null -> {
@ -83,7 +84,7 @@ internal class SasVerification(
/** Get the unique id of this verification */ /** Get the unique id of this verification */
override val transactionId: String override val transactionId: String
get() = this.inner.flowId get() = inner.flowId
/** Cancel the verification flow /** Cancel the verification flow
* *
@ -95,7 +96,7 @@ internal class SasVerification(
* The method turns into a noop, if the verification flow has already been cancelled. * The method turns into a noop, if the verification flow has already been cancelled.
* */ * */
override suspend fun cancel() { override suspend fun cancel() {
this.cancelHelper(CancelCode.User) cancelHelper(CancelCode.User)
} }
/** Cancel the verification flow /** Cancel the verification flow
@ -110,7 +111,7 @@ internal class SasVerification(
* @param code The cancel code that should be given as the reason for the cancellation. * @param code The cancel code that should be given as the reason for the cancellation.
* */ * */
override suspend fun cancel(code: CancelCode) { override suspend fun cancel(code: CancelCode) {
this.cancelHelper(code) cancelHelper(code)
} }
/** Cancel the verification flow /** Cancel the verification flow
@ -123,11 +124,11 @@ internal class SasVerification(
* The method turns into a noop, if the verification flow has already been cancelled. * The method turns into a noop, if the verification flow has already been cancelled.
*/ */
override suspend fun shortCodeDoesNotMatch() { override suspend fun shortCodeDoesNotMatch() {
this.cancelHelper(CancelCode.MismatchedSas) cancelHelper(CancelCode.MismatchedSas)
} }
/** Is this verification happening over to-device messages */ /** Is this verification happening over to-device messages */
override fun isToDeviceTransport(): Boolean = this.inner.roomId == null override fun isToDeviceTransport(): Boolean = inner.roomId == null
/** Does the verification flow support showing decimals as the short auth string */ /** Does the verification flow support showing decimals as the short auth string */
override fun supportsDecimal(): Boolean { override fun supportsDecimal(): Boolean {
@ -140,7 +141,7 @@ internal class SasVerification(
/** Does the verification flow support showing emojis as the short auth string */ /** Does the verification flow support showing emojis as the short auth string */
override fun supportsEmoji(): Boolean { override fun supportsEmoji(): Boolean {
refreshData() refreshData()
return this.inner.supportsEmoji return inner.supportsEmoji
} }
/** Confirm that the short authentication code matches on both sides /** Confirm that the short authentication code matches on both sides
@ -175,7 +176,7 @@ internal class SasVerification(
* in a presentable state. * in a presentable state.
*/ */
override fun getDecimalCodeRepresentation(): String { override fun getDecimalCodeRepresentation(): String {
val decimals = this.machine.getDecimals(this.inner.otherUserId, this.inner.flowId) val decimals = machine.getDecimals(inner.otherUserId, inner.flowId)
return decimals?.joinToString(" ") ?: "" return decimals?.joinToString(" ") ?: ""
} }
@ -187,40 +188,40 @@ internal class SasVerification(
* state. * state.
*/ */
override fun getEmojiCodeRepresentation(): List<EmojiRepresentation> { override fun getEmojiCodeRepresentation(): List<EmojiRepresentation> {
val emojiIndex = this.machine.getEmojiIndex(this.inner.otherUserId, this.inner.flowId) val emojiIndex = machine.getEmojiIndex(inner.otherUserId, inner.flowId)
return emojiIndex?.map { getEmojiForCode(it) } ?: listOf() return emojiIndex?.map { getEmojiForCode(it) } ?: listOf()
} }
internal suspend fun accept() { internal suspend fun accept() {
val request = this.machine.acceptSasVerification(this.inner.otherUserId, inner.flowId) val request = machine.acceptSasVerification(inner.otherUserId, inner.flowId)
if (request != null) { if (request != null) {
this.sender.sendVerificationRequest(request) sender.sendVerificationRequest(request)
dispatchTxUpdated() dispatchTxUpdated()
} }
} }
@Throws(CryptoStoreException::class) @Throws(CryptoStoreException::class)
private suspend fun confirm() { private suspend fun confirm() {
val result = withContext(Dispatchers.IO) { val result = withContext(coroutineDispatchers.io) {
machine.confirmVerification(inner.otherUserId, inner.flowId) machine.confirmVerification(inner.otherUserId, inner.flowId)
} }
if (result != null) { if (result != null) {
this.sender.sendVerificationRequest(result.request) sender.sendVerificationRequest(result.request)
dispatchTxUpdated() dispatchTxUpdated()
val signatureRequest = result.signatureRequest val signatureRequest = result.signatureRequest
if (signatureRequest != null) { if (signatureRequest != null) {
this.sender.sendSignatureUpload(signatureRequest) sender.sendSignatureUpload(signatureRequest)
} }
} }
} }
private suspend fun cancelHelper(code: CancelCode) { private suspend fun cancelHelper(code: CancelCode) {
val request = this.machine.cancelVerification(this.inner.otherUserId, inner.flowId, code.value) val request = machine.cancelVerification(inner.otherUserId, inner.flowId, code.value)
if (request != null) { if (request != null) {
sender.sendVerificationRequest(request) sender.sendVerificationRequest(request)
@ -230,9 +231,9 @@ internal class SasVerification(
/** Fetch fresh data from the Rust side for our verification flow */ /** Fetch fresh data from the Rust side for our verification flow */
private fun refreshData() { private fun refreshData() {
when (val verification = this.machine.getVerification(this.inner.otherUserId, this.inner.flowId)) { when (val verification = machine.getVerification(inner.otherUserId, inner.flowId)) {
is Verification.SasV1 -> { is Verification.SasV1 -> {
this.inner = verification.sas inner = verification.sas
} }
else -> { else -> {
} }

View File

@ -16,9 +16,8 @@
package org.matrix.android.sdk.internal.crypto package org.matrix.android.sdk.internal.crypto
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.runBlocking
import kotlinx.coroutines.withContext import kotlinx.coroutines.withContext
import org.matrix.android.sdk.api.MatrixCoroutineDispatchers
import org.matrix.android.sdk.api.session.crypto.crosssigning.MXCrossSigningInfo import org.matrix.android.sdk.api.session.crypto.crosssigning.MXCrossSigningInfo
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.events.model.EventType import org.matrix.android.sdk.api.session.events.model.EventType
@ -80,11 +79,12 @@ internal class OwnUserIdentity(
private val userSigningKey: CryptoCrossSigningKey, private val userSigningKey: CryptoCrossSigningKey,
private val trustsOurOwnDevice: Boolean, private val trustsOurOwnDevice: Boolean,
private val olmMachine: OlmMachine, private val olmMachine: OlmMachine,
private val requestSender: RequestSender) : UserIdentities() { private val requestSender: RequestSender,
private val coroutineDispatchers: MatrixCoroutineDispatchers) : UserIdentities() {
/** /**
* Our own user id. * Our own user id.
*/ */
override fun userId() = this.userId override fun userId() = userId
/** /**
* Manually verify our user identity. * Manually verify our user identity.
@ -95,8 +95,8 @@ internal class OwnUserIdentity(
*/ */
@Throws(SignatureException::class) @Throws(SignatureException::class)
override suspend fun verify() { override suspend fun verify() {
val request = withContext(Dispatchers.Default) { olmMachine.inner().verifyIdentity(userId) } val request = withContext(coroutineDispatchers.computation) { olmMachine.inner().verifyIdentity(userId) }
this.requestSender.sendSignatureUpload(request) requestSender.sendSignatureUpload(request)
} }
/** /**
@ -106,13 +106,13 @@ internal class OwnUserIdentity(
*/ */
@Throws(CryptoStoreException::class) @Throws(CryptoStoreException::class)
override suspend fun verified(): Boolean { override suspend fun verified(): Boolean {
return withContext(Dispatchers.IO) { olmMachine.inner().isIdentityVerified(userId) } return withContext(coroutineDispatchers.io) { olmMachine.inner().isIdentityVerified(userId) }
} }
/** /**
* Does the identity trust our own device. * Does the identity trust our own device.
*/ */
fun trustsOurOwnDevice() = this.trustsOurOwnDevice fun trustsOurOwnDevice() = trustsOurOwnDevice
/** /**
* Request an interactive verification to begin * Request an interactive verification to begin
@ -133,14 +133,15 @@ internal class OwnUserIdentity(
@Throws(CryptoStoreException::class) @Throws(CryptoStoreException::class)
suspend fun requestVerification(methods: List<VerificationMethod>): VerificationRequest { suspend fun requestVerification(methods: List<VerificationMethod>): VerificationRequest {
val stringMethods = prepareMethods(methods) val stringMethods = prepareMethods(methods)
val result = this.olmMachine.inner().requestSelfVerification(stringMethods) val result = olmMachine.inner().requestSelfVerification(stringMethods)
this.requestSender.sendVerificationRequest(result!!.request) requestSender.sendVerificationRequest(result!!.request)
return VerificationRequest( return VerificationRequest(
this.olmMachine.inner(), machine = olmMachine.inner(),
result.verification, inner = result.verification,
this.requestSender, sender = requestSender,
this.olmMachine.verificationListeners coroutineDispatchers = coroutineDispatchers,
listeners = olmMachine.verificationListeners
) )
} }
@ -148,9 +149,9 @@ internal class OwnUserIdentity(
* Convert the identity into a MxCrossSigningInfo class. * Convert the identity into a MxCrossSigningInfo class.
*/ */
override suspend fun toMxCrossSigningInfo(): MXCrossSigningInfo { override suspend fun toMxCrossSigningInfo(): MXCrossSigningInfo {
val masterKey = this.masterKey val masterKey = masterKey
val selfSigningKey = this.selfSigningKey val selfSigningKey = selfSigningKey
val userSigningKey = this.userSigningKey val userSigningKey = userSigningKey
val trustLevel = DeviceTrustLevel(verified(), false) val trustLevel = DeviceTrustLevel(verified(), false)
// TODO remove this, this is silly, we have way too many methods to check if a user is verified // TODO remove this, this is silly, we have way too many methods to check if a user is verified
masterKey.trustLevel = trustLevel masterKey.trustLevel = trustLevel
@ -158,7 +159,7 @@ internal class OwnUserIdentity(
userSigningKey.trustLevel = trustLevel userSigningKey.trustLevel = trustLevel
val crossSigningKeys = listOf(masterKey, selfSigningKey, userSigningKey) val crossSigningKeys = listOf(masterKey, selfSigningKey, userSigningKey)
return MXCrossSigningInfo(this.userId, crossSigningKeys) return MXCrossSigningInfo(userId, crossSigningKeys)
} }
} }
@ -172,11 +173,12 @@ internal class UserIdentity(
private val masterKey: CryptoCrossSigningKey, private val masterKey: CryptoCrossSigningKey,
private val selfSigningKey: CryptoCrossSigningKey, private val selfSigningKey: CryptoCrossSigningKey,
private val olmMachine: OlmMachine, private val olmMachine: OlmMachine,
private val requestSender: RequestSender) : UserIdentities() { private val requestSender: RequestSender,
private val coroutineDispatchers: MatrixCoroutineDispatchers) : UserIdentities() {
/** /**
* The unique ID of the user that this identity belongs to. * The unique ID of the user that this identity belongs to.
*/ */
override fun userId() = this.userId override fun userId() = userId
/** /**
* Manually verify this user identity. * Manually verify this user identity.
@ -189,8 +191,8 @@ internal class UserIdentity(
*/ */
@Throws(SignatureException::class) @Throws(SignatureException::class)
override suspend fun verify() { override suspend fun verify() {
val request = withContext(Dispatchers.Default) { olmMachine.inner().verifyIdentity(userId) } val request = withContext(coroutineDispatchers.computation) { olmMachine.inner().verifyIdentity(userId) }
this.requestSender.sendSignatureUpload(request) requestSender.sendSignatureUpload(request)
} }
/** /**
@ -199,7 +201,7 @@ internal class UserIdentity(
* @return True if the identity is considered to be verified and trusted, false otherwise. * @return True if the identity is considered to be verified and trusted, false otherwise.
*/ */
override suspend fun verified(): Boolean { override suspend fun verified(): Boolean {
return withContext(Dispatchers.IO) { olmMachine.inner().isIdentityVerified(userId) } return withContext(coroutineDispatchers.io) { olmMachine.inner().isIdentityVerified(userId) }
} }
/** /**
@ -232,17 +234,18 @@ internal class UserIdentity(
transactionId: String transactionId: String
): VerificationRequest { ): VerificationRequest {
val stringMethods = prepareMethods(methods) val stringMethods = prepareMethods(methods)
val content = this.olmMachine.inner().verificationRequestContent(this.userId, stringMethods)!! val content = olmMachine.inner().verificationRequestContent(userId, stringMethods)!!
val eventID = requestSender.sendRoomMessage(EventType.MESSAGE, roomId, content, transactionId) val eventID = requestSender.sendRoomMessage(EventType.MESSAGE, roomId, content, transactionId)
val innerRequest = this.olmMachine.inner().requestVerification(this.userId, roomId, eventID, stringMethods)!! val innerRequest = olmMachine.inner().requestVerification(userId, roomId, eventID, stringMethods)!!
return VerificationRequest( return VerificationRequest(
this.olmMachine.inner(), machine = olmMachine.inner(),
innerRequest, inner = innerRequest,
this.requestSender, sender = requestSender,
this.olmMachine.verificationListeners coroutineDispatchers = coroutineDispatchers,
listeners = olmMachine.verificationListeners
) )
} }
@ -250,14 +253,14 @@ internal class UserIdentity(
* Convert the identity into a MxCrossSigningInfo class. * Convert the identity into a MxCrossSigningInfo class.
*/ */
override suspend fun toMxCrossSigningInfo(): MXCrossSigningInfo { override suspend fun toMxCrossSigningInfo(): MXCrossSigningInfo {
// val crossSigningKeys = listOf(this.masterKey, this.selfSigningKey) // val crossSigningKeys = listOf(masterKey, selfSigningKey)
val trustLevel = DeviceTrustLevel(verified(), false) val trustLevel = DeviceTrustLevel(verified(), false)
// TODO remove this, this is silly, we have way too many methods to check if a user is verified // TODO remove this, this is silly, we have way too many methods to check if a user is verified
masterKey.trustLevel = trustLevel masterKey.trustLevel = trustLevel
selfSigningKey.trustLevel = trustLevel selfSigningKey.trustLevel = trustLevel
return MXCrossSigningInfo(this.userId, listOf( return MXCrossSigningInfo(userId, listOf(
this.masterKey.also { it.trustLevel = trustLevel }, masterKey.also { it.trustLevel = trustLevel },
this.selfSigningKey.also { it.trustLevel = trustLevel } selfSigningKey.also { it.trustLevel = trustLevel }
)) ))
} }
} }

View File

@ -20,6 +20,7 @@ import android.os.Handler
import android.os.Looper import android.os.Looper
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext import kotlinx.coroutines.withContext
import org.matrix.android.sdk.api.MatrixCoroutineDispatchers
import org.matrix.android.sdk.api.session.crypto.verification.CancelCode import org.matrix.android.sdk.api.session.crypto.verification.CancelCode
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.ValidVerificationInfoReady import org.matrix.android.sdk.api.session.crypto.verification.ValidVerificationInfoReady
@ -45,6 +46,7 @@ internal class VerificationRequest(
private val machine: OlmMachine, private val machine: OlmMachine,
private var inner: VerificationRequest, private var inner: VerificationRequest,
private val sender: RequestSender, private val sender: RequestSender,
private val coroutineDispatchers: MatrixCoroutineDispatchers,
private val listeners: ArrayList<VerificationService.Listener> private val listeners: ArrayList<VerificationService.Listener>
) { ) {
private val uiHandler = Handler(Looper.getMainLooper()) private val uiHandler = Handler(Looper.getMainLooper())
@ -53,7 +55,7 @@ internal class VerificationRequest(
uiHandler.post { uiHandler.post {
listeners.forEach { listeners.forEach {
try { try {
it.verificationRequestUpdated(this.toPendingVerificationRequest()) it.verificationRequestUpdated(toPendingVerificationRequest())
} catch (e: Throwable) { } catch (e: Throwable) {
Timber.e(e, "## Error while notifying listeners") Timber.e(e, "## Error while notifying listeners")
} }
@ -68,12 +70,12 @@ internal class VerificationRequest(
* event that initiated the flow. * event that initiated the flow.
*/ */
internal fun flowId(): String { internal fun flowId(): String {
return this.inner.flowId return inner.flowId
} }
/** The user ID of the other user that is participating in this verification flow */ /** The user ID of the other user that is participating in this verification flow */
internal fun otherUser(): String { internal fun otherUser(): String {
return this.inner.otherUserId return inner.otherUserId
} }
/** The device ID of the other user's device that is participating in this verification flow /** The device ID of the other user's device that is participating in this verification flow
@ -83,12 +85,12 @@ internal class VerificationRequest(
* */ * */
internal fun otherDeviceId(): String? { internal fun otherDeviceId(): String? {
refreshData() refreshData()
return this.inner.otherDeviceId return inner.otherDeviceId
} }
/** Did we initiate this verification flow */ /** Did we initiate this verification flow */
internal fun weStarted(): Boolean { internal fun weStarted(): Boolean {
return this.inner.weStarted return inner.weStarted
} }
/** Get the id of the room where this verification is happening /** Get the id of the room where this verification is happening
@ -96,7 +98,7 @@ internal class VerificationRequest(
* Will be null if the verification is not happening inside a room. * Will be null if the verification is not happening inside a room.
*/ */
internal fun roomId(): String? { internal fun roomId(): String? {
return this.inner.roomId return inner.roomId
} }
/** Did the non-initiating side respond with a m.key.verification.read event /** Did the non-initiating side respond with a m.key.verification.read event
@ -107,13 +109,13 @@ internal class VerificationRequest(
*/ */
internal fun isReady(): Boolean { internal fun isReady(): Boolean {
refreshData() refreshData()
return this.inner.isReady return inner.isReady
} }
/** Did we advertise that we're able to scan QR codes */ /** Did we advertise that we're able to scan QR codes */
internal fun canScanQrCodes(): Boolean { internal fun canScanQrCodes(): Boolean {
refreshData() refreshData()
return this.inner.ourMethods?.contains(VERIFICATION_METHOD_QR_CODE_SCAN) ?: false return inner.ourMethods?.contains(VERIFICATION_METHOD_QR_CODE_SCAN) ?: false
} }
/** Accept the verification request advertising the given methods as supported /** Accept the verification request advertising the given methods as supported
@ -132,15 +134,15 @@ internal class VerificationRequest(
suspend fun acceptWithMethods(methods: List<VerificationMethod>) { suspend fun acceptWithMethods(methods: List<VerificationMethod>) {
val stringMethods = prepareMethods(methods) val stringMethods = prepareMethods(methods)
val request = this.machine.acceptVerificationRequest( val request = machine.acceptVerificationRequest(
this.inner.otherUserId, inner.otherUserId,
this.inner.flowId, inner.flowId,
stringMethods stringMethods
) )
if (request != null) { if (request != null) {
this.sender.sendVerificationRequest(request) sender.sendVerificationRequest(request)
this.dispatchRequestUpdated() dispatchRequestUpdated()
} }
} }
@ -158,12 +160,12 @@ internal class VerificationRequest(
* emoji verification, or null if we can't yet transition into emoji verification. * emoji verification, or null if we can't yet transition into emoji verification.
*/ */
internal suspend fun startSasVerification(): SasVerification? { internal suspend fun startSasVerification(): SasVerification? {
return withContext(Dispatchers.IO) { return withContext(coroutineDispatchers.io) {
val result = machine.startSasVerification(inner.otherUserId, inner.flowId) val result = machine.startSasVerification(inner.otherUserId, inner.flowId)
if (result != null) { if (result != null) {
sender.sendVerificationRequest(result.request) sender.sendVerificationRequest(result.request)
SasVerification(machine, result.sas, sender, listeners) SasVerification(machine, result.sas, sender, coroutineDispatchers, listeners)
} else { } else {
null null
} }
@ -187,10 +189,10 @@ internal class VerificationRequest(
// TODO again, what's the deal with ISO_8859_1? // TODO again, what's the deal with ISO_8859_1?
val byteArray = data.toByteArray(Charsets.ISO_8859_1) val byteArray = data.toByteArray(Charsets.ISO_8859_1)
val encodedData = byteArray.toBase64NoPadding() val encodedData = byteArray.toBase64NoPadding()
val result = this.machine.scanQrCode(this.otherUser(), this.flowId(), encodedData) ?: return null val result = machine.scanQrCode(otherUser(), flowId(), encodedData) ?: return null
this.sender.sendVerificationRequest(result.request) sender.sendVerificationRequest(result.request)
return QrCodeVerification(this.machine, this, result.qr, this.sender, this.listeners) return QrCodeVerification(machine, this, result.qr, sender, coroutineDispatchers, listeners)
} }
/** Transition into a QR code verification to display a QR code /** Transition into a QR code verification to display a QR code
@ -211,15 +213,16 @@ internal class VerificationRequest(
* QR code verification, or null if we can't yet transition into QR code verification. * QR code verification, or null if we can't yet transition into QR code verification.
*/ */
internal fun startQrVerification(): QrCodeVerification? { internal fun startQrVerification(): QrCodeVerification? {
val qrcode = this.machine.startQrVerification(this.inner.otherUserId, this.inner.flowId) val qrcode = machine.startQrVerification(inner.otherUserId, inner.flowId)
return if (qrcode != null) { return if (qrcode != null) {
QrCodeVerification( QrCodeVerification(
this.machine, machine = machine,
this, request = this,
qrcode, inner = qrcode,
this.sender, sender = sender,
this.listeners, coroutineDispatchers = coroutineDispatchers,
listeners = listeners,
) )
} else { } else {
null null
@ -237,24 +240,24 @@ internal class VerificationRequest(
* The method turns into a noop, if the verification flow has already been cancelled. * The method turns into a noop, if the verification flow has already been cancelled.
*/ */
internal suspend fun cancel() { internal suspend fun cancel() {
val request = this.machine.cancelVerification( val request = machine.cancelVerification(
this.inner.otherUserId, inner.otherUserId,
this.inner.flowId, inner.flowId,
CancelCode.User.value CancelCode.User.value
) )
if (request != null) { if (request != null) {
this.sender.sendVerificationRequest(request) sender.sendVerificationRequest(request)
this.dispatchRequestUpdated() dispatchRequestUpdated()
} }
} }
/** Fetch fresh data from the Rust side for our verification flow */ /** Fetch fresh data from the Rust side for our verification flow */
private fun refreshData() { private fun refreshData() {
val request = this.machine.getVerificationRequest(this.inner.otherUserId, this.inner.flowId) val request = machine.getVerificationRequest(inner.otherUserId, inner.flowId)
if (request != null) { if (request != null) {
this.inner = request inner = request
} }
} }
@ -269,7 +272,7 @@ internal class VerificationRequest(
*/ */
internal fun toPendingVerificationRequest(): PendingVerificationRequest { internal fun toPendingVerificationRequest(): PendingVerificationRequest {
refreshData() refreshData()
val cancelInfo = this.inner.cancelInfo val cancelInfo = inner.cancelInfo
val cancelCode = val cancelCode =
if (cancelInfo != null) { if (cancelInfo != null) {
safeValueOf(cancelInfo.cancelCode) safeValueOf(cancelInfo.cancelCode)
@ -277,72 +280,72 @@ internal class VerificationRequest(
null null
} }
val ourMethods = this.inner.ourMethods val ourMethods = inner.ourMethods
val theirMethods = this.inner.theirMethods val theirMethods = inner.theirMethods
val otherDeviceId = this.inner.otherDeviceId val otherDeviceId = inner.otherDeviceId
var requestInfo: ValidVerificationInfoRequest? = null var requestInfo: ValidVerificationInfoRequest? = null
var readyInfo: ValidVerificationInfoReady? = null var readyInfo: ValidVerificationInfoReady? = null
if (this.inner.weStarted && ourMethods != null) { if (inner.weStarted && ourMethods != null) {
requestInfo = requestInfo =
ValidVerificationInfoRequest( ValidVerificationInfoRequest(
this.inner.flowId, transactionId = inner.flowId,
this.machine.deviceId(), fromDevice = machine.deviceId(),
ourMethods, methods = ourMethods,
null, timestamp = null,
) )
} else if (!this.inner.weStarted && ourMethods != null) { } else if (!inner.weStarted && ourMethods != null) {
readyInfo = readyInfo =
ValidVerificationInfoReady( ValidVerificationInfoReady(
this.inner.flowId, transactionId = inner.flowId,
this.machine.deviceId(), fromDevice = machine.deviceId(),
ourMethods, methods = ourMethods,
) )
} }
if (this.inner.weStarted && theirMethods != null && otherDeviceId != null) { if (inner.weStarted && theirMethods != null && otherDeviceId != null) {
readyInfo = readyInfo =
ValidVerificationInfoReady( ValidVerificationInfoReady(
this.inner.flowId, transactionId = inner.flowId,
otherDeviceId, fromDevice = otherDeviceId,
theirMethods, methods = theirMethods,
) )
} else if (!this.inner.weStarted && theirMethods != null && otherDeviceId != null) { } else if (!inner.weStarted && theirMethods != null && otherDeviceId != null) {
requestInfo = requestInfo =
ValidVerificationInfoRequest( ValidVerificationInfoRequest(
this.inner.flowId, transactionId = inner.flowId,
otherDeviceId, fromDevice = otherDeviceId,
theirMethods, methods = theirMethods,
System.currentTimeMillis(), timestamp = System.currentTimeMillis(),
) )
} }
return PendingVerificationRequest( return PendingVerificationRequest(
// Creation time // Creation time
System.currentTimeMillis(), ageLocalTs = System.currentTimeMillis(),
// Who initiated the request // Who initiated the request
!this.inner.weStarted, isIncoming = !inner.weStarted,
// Local echo id, what to do here? // Local echo id, what to do here?
this.inner.flowId, localId = inner.flowId,
// other user // other user
this.inner.otherUserId, otherUserId = inner.otherUserId,
// room id // room id
this.inner.roomId, roomId = inner.roomId,
// transaction id // transaction id
this.inner.flowId, transactionId = inner.flowId,
// val requestInfo: ValidVerificationInfoRequest? = null, // val requestInfo: ValidVerificationInfoRequest? = null,
requestInfo, requestInfo = requestInfo,
// val readyInfo: ValidVerificationInfoReady? = null, // val readyInfo: ValidVerificationInfoReady? = null,
readyInfo, readyInfo = readyInfo,
// cancel code if there is one // cancel code if there is one
cancelCode, cancelConclusion = cancelCode,
// are we done/successful // are we done/successful
this.inner.isDone, isSuccessful = inner.isDone,
// did another device answer the request // did another device answer the request
this.inner.isPassive, handledByOtherSession = inner.isPassive,
// devices that should receive the events we send out // devices that should receive the events we send out
null, targetDevices = null
) )
} }
} }

View File

@ -21,7 +21,6 @@ import android.os.Looper
import androidx.annotation.VisibleForTesting import androidx.annotation.VisibleForTesting
import androidx.annotation.WorkerThread import androidx.annotation.WorkerThread
import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.SupervisorJob import kotlinx.coroutines.SupervisorJob
import kotlinx.coroutines.async import kotlinx.coroutines.async
import kotlinx.coroutines.awaitAll import kotlinx.coroutines.awaitAll
@ -95,7 +94,7 @@ internal class RustKeyBackupService @Inject constructor(
// private var backupAllGroupSessionsCallback: MatrixCallback<Unit>? = null // private var backupAllGroupSessionsCallback: MatrixCallback<Unit>? = null
private val importScope = CoroutineScope(SupervisorJob() + Dispatchers.Main) private val importScope = CoroutineScope(SupervisorJob() + coroutineDispatchers.main)
private var keysBackupStateListener: KeysBackupStateListener? = null private var keysBackupStateListener: KeysBackupStateListener? = null
@ -490,7 +489,7 @@ internal class RustKeyBackupService @Inject constructor(
val data = getKeys(sessionId, roomId, keysVersionResult.version) val data = getKeys(sessionId, roomId, keysVersionResult.version)
return withContext(coroutineDispatchers.computation) { return withContext(coroutineDispatchers.computation) {
withContext(Dispatchers.Main) { withContext(coroutineDispatchers.main) {
stepProgressListener?.onStepProgress(StepProgressListener.Step.DecryptingKey(0, data.roomIdToRoomKeysBackupData.size)) stepProgressListener?.onStepProgress(StepProgressListener.Step.DecryptingKey(0, data.roomIdToRoomKeysBackupData.size))
} }
// Decrypting by chunk of 500 keys in parallel // Decrypting by chunk of 500 keys in parallel
@ -513,7 +512,7 @@ internal class RustKeyBackupService @Inject constructor(
.awaitAll() .awaitAll()
.flatten() .flatten()
withContext(Dispatchers.Main) { withContext(coroutineDispatchers.main) {
val stepProgress = StepProgressListener.Step.DecryptingKey(data.roomIdToRoomKeysBackupData.size, data.roomIdToRoomKeysBackupData.size) val stepProgress = StepProgressListener.Step.DecryptingKey(data.roomIdToRoomKeysBackupData.size, data.roomIdToRoomKeysBackupData.size)
stepProgressListener?.onStepProgress(stepProgress) stepProgressListener?.onStepProgress(stepProgress)
} }
@ -532,7 +531,7 @@ internal class RustKeyBackupService @Inject constructor(
val progressListener = if (stepProgressListener != null) { val progressListener = if (stepProgressListener != null) {
object : ProgressListener { object : ProgressListener {
override fun onProgress(progress: Int, total: Int) { override fun onProgress(progress: Int, total: Int) {
cryptoCoroutineScope.launch(Dispatchers.Main) { cryptoCoroutineScope.launch(coroutineDispatchers.main) {
val stepProgress = StepProgressListener.Step.ImportingKey(progress, total) val stepProgress = StepProgressListener.Step.ImportingKey(progress, total)
stepProgressListener.onStepProgress(stepProgress) stepProgressListener.onStepProgress(stepProgress)
} }
@ -878,7 +877,7 @@ internal class RustKeyBackupService @Inject constructor(
} }
} catch (failure: Throwable) { } catch (failure: Throwable) {
if (failure is Failure.ServerError) { if (failure is Failure.ServerError) {
withContext(Dispatchers.Main) { withContext(coroutineDispatchers.main) {
Timber.e(failure, "backupKeys: backupKeys failed.") Timber.e(failure, "backupKeys: backupKeys failed.")
when (failure.error.code) { when (failure.error.code) {