From d9342707fd05d4a66c8dcecce933406debb43c6f Mon Sep 17 00:00:00 2001 From: valere Date: Mon, 28 Nov 2022 21:48:46 +0100 Subject: [PATCH] update rust-sdk bindings --- .gitignore | 2 + matrix-sdk-android/build.gradle | 5 +- .../crypto/model/ImportRoomKeysResult.kt | 2 +- .../verification/VerificationService.kt | 2 +- .../VerificationListenersHolder.kt | 73 ++----- .../android/sdk/internal/di/MoshiProvider.kt | 4 + .../sdk/internal/session/SessionModule.kt | 6 +- .../android/sdk/internal/crypto/Device.kt | 23 ++- .../internal/crypto/EnsureUsersKeysUseCase.kt | 4 +- .../internal/crypto/GetUserIdentityUseCase.kt | 6 +- .../android/sdk/internal/crypto/OlmMachine.kt | 76 ++++--- .../crypto/PrepareToEncryptUseCase.kt | 28 ++- .../crypto/RustCrossSigningService.kt | 20 ++ .../sdk/internal/crypto/RustCryptoService.kt | 6 +- .../sdk/internal/crypto/UserIdentities.kt | 6 +- .../crypto/keysbackup/BackupRecoveryKey.kt | 2 +- .../crypto/keysbackup/RustKeyBackupService.kt | 4 +- .../network/OutgoingRequestsProcessor.kt | 4 +- .../internal/crypto/network/RequestSender.kt | 8 +- .../verification/RustVerificationService.kt | 81 ++++---- .../crypto/verification/SasVerification.kt | 136 ++++++------ .../verification/VerificationRequest.kt | 194 +++++++++++------- .../verification/VerificationsProvider.kt | 52 +++-- .../verification/qrcode/QrCodeVerification.kt | 105 +++++----- .../sdk/internal/crypto/MoshiNumbersAsInt.kt | 54 +++++ .../crypto/UnRequestedKeysManagerTest.kt | 0 26 files changed, 535 insertions(+), 368 deletions(-) create mode 100644 matrix-sdk-android/src/test/java/org/matrix/android/sdk/internal/crypto/MoshiNumbersAsInt.kt rename matrix-sdk-android/src/{test => testKotlinCrypto}/java/org/matrix/android/sdk/internal/crypto/UnRequestedKeysManagerTest.kt (100%) diff --git a/.gitignore b/.gitignore index 7324f63919..b7332e11f1 100644 --- a/.gitignore +++ b/.gitignore @@ -31,3 +31,5 @@ Cargo.lock matrix-sdk-android/src/main/jniLibs/ matrix-sdk-android/libs/crypto-android-release.aar + +matrix-sdk-android/libs/matrix-rust-sdk-crypto.aar diff --git a/matrix-sdk-android/build.gradle b/matrix-sdk-android/build.gradle index be093b0699..718bd75070 100644 --- a/matrix-sdk-android/build.gradle +++ b/matrix-sdk-android/build.gradle @@ -169,8 +169,6 @@ dependencies { implementation libs.jetbrains.coroutinesCore implementation libs.jetbrains.coroutinesAndroid - implementation 'org.matrix.rustcomponents:crypto-android:0.2.1-SNAPSHOT' - //implementation files('libs/crypto-android-release.aar') // implementation(name: 'crypto-android-release', ext: 'aar') implementation 'net.java.dev.jna:jna:5.10.0@aar' @@ -236,7 +234,8 @@ dependencies { implementation libs.google.phonenumber - rustCryptoImplementation 'org.matrix.rustcomponents:crypto-android:0.2.1-SNAPSHOT' + // rustCryptoImplementation 'org.matrix.rustcomponents:crypto-android:0.2.1-SNAPSHOT' + rustCryptoImplementation files('libs/matrix-rust-sdk-crypto.aar') testImplementation libs.tests.junit // Note: version sticks to 1.9.2 due to https://github.com/mockk/mockk/issues/281 diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/crypto/model/ImportRoomKeysResult.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/crypto/model/ImportRoomKeysResult.kt index 321ba7fc00..7bd3c0667d 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/crypto/model/ImportRoomKeysResult.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/crypto/model/ImportRoomKeysResult.kt @@ -16,7 +16,7 @@ package org.matrix.android.sdk.api.session.crypto.model -import uniffi.olm.KeysImportResult +import org.matrix.rustcomponents.sdk.crypto.KeysImportResult data class ImportRoomKeysResult( val totalNumberOfKeys: Int, diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/crypto/verification/VerificationService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/crypto/verification/VerificationService.kt index ac09fe884d..4a0c442879 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/crypto/verification/VerificationService.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/crypto/verification/VerificationService.kt @@ -104,7 +104,7 @@ interface VerificationService { scannedData: String ): String? - suspend fun sasCodeMatch(theyMatch: Boolean, transactionId: String) +// suspend fun sasCodeMatch(theyMatch: Boolean, transactionId: String) // This starts the short SAS flow, the one that doesn't start with a request, deprecated diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/verification/VerificationListenersHolder.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/verification/VerificationListenersHolder.kt index 66e3ebeae8..c12bc6fac8 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/verification/VerificationListenersHolder.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/verification/VerificationListenersHolder.kt @@ -16,82 +16,49 @@ package org.matrix.android.sdk.internal.crypto.verification -import android.os.Handler -import android.os.Looper +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.SupervisorJob +import kotlinx.coroutines.channels.BufferOverflow +import kotlinx.coroutines.flow.MutableSharedFlow +import kotlinx.coroutines.launch +import org.matrix.android.sdk.api.MatrixCoroutineDispatchers import org.matrix.android.sdk.api.session.crypto.verification.PendingVerificationRequest -import org.matrix.android.sdk.api.session.crypto.verification.VerificationService +import org.matrix.android.sdk.api.session.crypto.verification.VerificationEvent import org.matrix.android.sdk.api.session.crypto.verification.VerificationTransaction import org.matrix.android.sdk.internal.session.SessionScope import timber.log.Timber import javax.inject.Inject @SessionScope -internal class VerificationListenersHolder @Inject constructor() { +internal class VerificationListenersHolder @Inject constructor( + private val coroutineDispatchers: MatrixCoroutineDispatchers +) { - private val listeners = ArrayList() - - private val uiHandler = Handler(Looper.getMainLooper()) - - fun listeners(): List = listeners - - fun addListener(listener: VerificationService.Listener) { - uiHandler.post { - if (!this.listeners.contains(listener)) { - this.listeners.add(listener) - } - } - } - - fun removeListener(listener: VerificationService.Listener) { - uiHandler.post { this.listeners.remove(listener) } - } + val scope = CoroutineScope(SupervisorJob() + coroutineDispatchers.dmVerif) + val eventFlow = MutableSharedFlow(extraBufferCapacity = 20, onBufferOverflow = BufferOverflow.SUSPEND) fun dispatchTxAdded(tx: VerificationTransaction) { - uiHandler.post { - this.listeners.forEach { - try { - it.transactionCreated(tx) - } catch (e: Throwable) { - Timber.e(e, "## Error while notifying listeners") - } - } + scope.launch { + eventFlow.emit(VerificationEvent.TransactionAdded(tx)) } } fun dispatchTxUpdated(tx: VerificationTransaction) { - uiHandler.post { - this.listeners.forEach { - try { - it.transactionUpdated(tx) - } catch (e: Throwable) { - Timber.e(e, "## Error while notifying listeners") - } - } + scope.launch { + eventFlow.emit(VerificationEvent.TransactionUpdated(tx)) } } fun dispatchRequestAdded(verificationRequest: PendingVerificationRequest) { Timber.v("## SAS dispatchRequestAdded txId:${verificationRequest.transactionId} $verificationRequest") - uiHandler.post { - this.listeners.forEach { - try { - it.verificationRequestCreated(verificationRequest) - } catch (e: Throwable) { - Timber.e(e, "## Error while notifying listeners") - } - } + scope.launch { + eventFlow.emit(VerificationEvent.RequestAdded(verificationRequest)) } } fun dispatchRequestUpdated(verificationRequest: PendingVerificationRequest) { - uiHandler.post { - listeners.forEach { - try { - it.verificationRequestUpdated(verificationRequest) - } catch (e: Throwable) { - Timber.e(e, "## Error while notifying listeners") - } - } + scope.launch { + eventFlow.emit(VerificationEvent.RequestUpdated(verificationRequest)) } } } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/di/MoshiProvider.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/di/MoshiProvider.kt index 0a737d5e64..e027a0d257 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/di/MoshiProvider.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/di/MoshiProvider.kt @@ -32,6 +32,7 @@ import org.matrix.android.sdk.api.session.room.model.message.MessageTextContent import org.matrix.android.sdk.api.session.room.model.message.MessageType import org.matrix.android.sdk.api.session.room.model.message.MessageVerificationRequestContent import org.matrix.android.sdk.api.session.room.model.message.MessageVideoContent +import org.matrix.android.sdk.internal.network.parsing.CheckNumberType import org.matrix.android.sdk.internal.network.parsing.CipherSuiteMoshiAdapter import org.matrix.android.sdk.internal.network.parsing.ForceToBooleanJsonAdapter import org.matrix.android.sdk.internal.network.parsing.RuntimeJsonAdapterFactory @@ -42,6 +43,9 @@ import org.matrix.android.sdk.internal.session.sync.parsing.DefaultLazyRoomSyncE internal object MoshiProvider { private val moshi: Moshi = Moshi.Builder() + // By default all numbers are transformed into floats by moshi + // this adapter tries to see first if it's a natural number before using float + .add(CheckNumberType.JSON_ADAPTER_FACTORY) .add(UriMoshiAdapter()) .add(ForceToBooleanJsonAdapter()) .add(CipherSuiteMoshiAdapter()) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/SessionModule.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/SessionModule.kt index 0cc6de285f..cc78670f7d 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/SessionModule.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/SessionModule.kt @@ -279,8 +279,12 @@ internal abstract class SessionModule { sessionParams: SessionParams, retrofitFactory: RetrofitFactory ): Retrofit { + var uri = sessionParams.homeServerConnectionConfig.homeServerUriBase.toString() + if (uri == "http://localhost:8080") { + uri = "http://10.0.2.2:8080" + } return retrofitFactory - .create(okHttpClient, sessionParams.homeServerConnectionConfig.homeServerUriBase.toString()) + .create(okHttpClient, uri) } @JvmStatic diff --git a/matrix-sdk-android/src/rustCrypto/java/org/matrix/android/sdk/internal/crypto/Device.kt b/matrix-sdk-android/src/rustCrypto/java/org/matrix/android/sdk/internal/crypto/Device.kt index 093ac53ace..7f2b1232fe 100644 --- a/matrix-sdk-android/src/rustCrypto/java/org/matrix/android/sdk/internal/crypto/Device.kt +++ b/matrix-sdk-android/src/rustCrypto/java/org/matrix/android/sdk/internal/crypto/Device.kt @@ -30,9 +30,10 @@ import org.matrix.android.sdk.internal.crypto.network.RequestSender import org.matrix.android.sdk.internal.crypto.verification.SasVerification import org.matrix.android.sdk.internal.crypto.verification.VerificationRequest import org.matrix.android.sdk.internal.crypto.verification.prepareMethods -import uniffi.olm.CryptoStoreException -import uniffi.olm.SignatureException -import uniffi.olm.Device as InnerDevice +import org.matrix.rustcomponents.sdk.crypto.CryptoStoreException +import org.matrix.rustcomponents.sdk.crypto.LocalTrust +import org.matrix.rustcomponents.sdk.crypto.SignatureException +import org.matrix.rustcomponents.sdk.crypto.Device as InnerDevice /** Class representing a device that supports E2EE in the Matrix world * @@ -88,7 +89,7 @@ internal class Device @AssistedInject constructor( requestSender.sendVerificationRequest(result.request) verificationRequestFactory.create(result.verification) } catch (failure: Throwable) { - innerMachine.cancelVerification(result.verification.otherUserId, result.verification.flowId, CancelCode.UserError.value) + // innerMachine.cancelVerification(result.verification.otherUserId, result.verification.flowId, CancelCode.UserError.value) null } } else { @@ -115,7 +116,8 @@ internal class Device @AssistedInject constructor( requestSender.sendVerificationRequest(result.request) sasVerificationFactory.create(result.sas) } catch (failure: Throwable) { - innerMachine.cancelVerification(result.sas.otherUserId, result.sas.flowId, CancelCode.UserError.value) + result.sas.cancel(CancelCode.UserError.value) +// innerMachine.cancelVerification(result.sas.otherUserId, result.sas.flowId, CancelCode.UserError.value) null } } else { @@ -132,7 +134,7 @@ internal class Device @AssistedInject constructor( @Throws(CryptoStoreException::class) suspend fun markAsTrusted() { withContext(coroutineDispatchers.io) { - innerMachine.markDeviceAsTrusted(innerDevice.userId, innerDevice.deviceId) + innerMachine.setLocalTrust(innerDevice.userId, innerDevice.deviceId, LocalTrust.VERIFIED) } } @@ -169,18 +171,21 @@ internal class Device @AssistedInject constructor( * This will not fetch out fresh data from the Rust side. **/ internal fun toCryptoDeviceInfo(): CryptoDeviceInfo { - val keys = innerDevice.keys.map { (keyId, key) -> "$keyId:$innerDevice.deviceId" to key }.toMap() +// val keys = innerDevice.keys.map { (keyId, key) -> keyId to key }.toMap() return CryptoDeviceInfo( deviceId = innerDevice.deviceId, userId = innerDevice.userId, algorithms = innerDevice.algorithms, - keys = keys, + keys = innerDevice.keys, // The Kotlin side doesn't need to care about signatures, // so we're not filling this out signatures = mapOf(), unsigned = UnsignedDeviceInfo(innerDevice.displayName), - trustLevel = DeviceTrustLevel(crossSigningVerified = innerDevice.crossSigningTrusted, locallyVerified = innerDevice.locallyTrusted), + trustLevel = DeviceTrustLevel( + crossSigningVerified = innerDevice.crossSigningTrusted, + locallyVerified = innerDevice.locallyTrusted + ), isBlocked = innerDevice.isBlocked, // TODO firstTimeSeenLocalTs = null diff --git a/matrix-sdk-android/src/rustCrypto/java/org/matrix/android/sdk/internal/crypto/EnsureUsersKeysUseCase.kt b/matrix-sdk-android/src/rustCrypto/java/org/matrix/android/sdk/internal/crypto/EnsureUsersKeysUseCase.kt index 8d522419bb..5d87d87010 100644 --- a/matrix-sdk-android/src/rustCrypto/java/org/matrix/android/sdk/internal/crypto/EnsureUsersKeysUseCase.kt +++ b/matrix-sdk-android/src/rustCrypto/java/org/matrix/android/sdk/internal/crypto/EnsureUsersKeysUseCase.kt @@ -21,8 +21,8 @@ import org.matrix.android.sdk.api.MatrixCoroutineDispatchers import org.matrix.android.sdk.api.extensions.tryOrNull import org.matrix.android.sdk.internal.crypto.network.OutgoingRequestsProcessor import org.matrix.android.sdk.internal.crypto.network.RequestSender -import uniffi.olm.Request -import uniffi.olm.RequestType +import org.matrix.rustcomponents.sdk.crypto.Request +import org.matrix.rustcomponents.sdk.crypto.RequestType import java.util.UUID import javax.inject.Inject import javax.inject.Provider diff --git a/matrix-sdk-android/src/rustCrypto/java/org/matrix/android/sdk/internal/crypto/GetUserIdentityUseCase.kt b/matrix-sdk-android/src/rustCrypto/java/org/matrix/android/sdk/internal/crypto/GetUserIdentityUseCase.kt index 466e763b65..2d88f926ff 100644 --- a/matrix-sdk-android/src/rustCrypto/java/org/matrix/android/sdk/internal/crypto/GetUserIdentityUseCase.kt +++ b/matrix-sdk-android/src/rustCrypto/java/org/matrix/android/sdk/internal/crypto/GetUserIdentityUseCase.kt @@ -23,7 +23,7 @@ import org.matrix.android.sdk.api.session.crypto.crosssigning.DeviceTrustLevel import org.matrix.android.sdk.internal.crypto.model.rest.RestKeyInfo import org.matrix.android.sdk.internal.crypto.network.RequestSender import org.matrix.android.sdk.internal.crypto.verification.VerificationRequest -import uniffi.olm.CryptoStoreException +import org.matrix.rustcomponents.sdk.crypto.CryptoStoreException import javax.inject.Inject import javax.inject.Provider @@ -44,7 +44,7 @@ internal class GetUserIdentityUseCase @Inject constructor( val adapter = moshi.adapter(RestKeyInfo::class.java) return when (identity) { - is uniffi.olm.UserIdentity.Other -> { + is org.matrix.rustcomponents.sdk.crypto.UserIdentity.Other -> { val verified = innerMachine.isIdentityVerified(userId) val masterKey = adapter.fromJson(identity.masterKey)!!.toCryptoModel().apply { trustLevel = DeviceTrustLevel(verified, verified) @@ -62,7 +62,7 @@ internal class GetUserIdentityUseCase @Inject constructor( verificationRequestFactory = verificationRequestFactory ) } - is uniffi.olm.UserIdentity.Own -> { + is org.matrix.rustcomponents.sdk.crypto.UserIdentity.Own -> { val verified = innerMachine.isIdentityVerified(userId) val masterKey = adapter.fromJson(identity.masterKey)!!.toCryptoModel().apply { diff --git a/matrix-sdk-android/src/rustCrypto/java/org/matrix/android/sdk/internal/crypto/OlmMachine.kt b/matrix-sdk-android/src/rustCrypto/java/org/matrix/android/sdk/internal/crypto/OlmMachine.kt index 1d7473791d..05f4aab536 100644 --- a/matrix-sdk-android/src/rustCrypto/java/org/matrix/android/sdk/internal/crypto/OlmMachine.kt +++ b/matrix-sdk-android/src/rustCrypto/java/org/matrix/android/sdk/internal/crypto/OlmMachine.kt @@ -19,6 +19,8 @@ package org.matrix.android.sdk.internal.crypto import androidx.lifecycle.LiveData import androidx.lifecycle.asLiveData import com.squareup.moshi.Moshi +import com.squareup.moshi.Types +import com.squareup.moshi.adapter import kotlinx.coroutines.channels.SendChannel import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.channelFlow @@ -55,30 +57,32 @@ import org.matrix.android.sdk.internal.crypto.verification.VerificationRequest import org.matrix.android.sdk.internal.crypto.verification.VerificationsProvider import org.matrix.android.sdk.internal.crypto.verification.qrcode.QrCodeVerification import org.matrix.android.sdk.internal.di.DeviceId +import org.matrix.android.sdk.internal.di.MoshiProvider import org.matrix.android.sdk.internal.di.SessionFilesDirectory import org.matrix.android.sdk.internal.di.UserId import org.matrix.android.sdk.internal.network.parsing.CheckNumberType import org.matrix.android.sdk.internal.session.SessionScope +import org.matrix.rustcomponents.sdk.crypto.BackupKeys +import org.matrix.rustcomponents.sdk.crypto.BackupRecoveryKey +import org.matrix.rustcomponents.sdk.crypto.CrossSigningKeyExport +import org.matrix.rustcomponents.sdk.crypto.CrossSigningStatus +import org.matrix.rustcomponents.sdk.crypto.CryptoStoreException +import org.matrix.rustcomponents.sdk.crypto.DecryptionException +import org.matrix.rustcomponents.sdk.crypto.DeviceLists +import org.matrix.rustcomponents.sdk.crypto.EncryptionSettings +import org.matrix.rustcomponents.sdk.crypto.KeyRequestPair +import org.matrix.rustcomponents.sdk.crypto.Logger +import org.matrix.rustcomponents.sdk.crypto.MegolmV1BackupKey +import org.matrix.rustcomponents.sdk.crypto.Request +import org.matrix.rustcomponents.sdk.crypto.RequestType +import org.matrix.rustcomponents.sdk.crypto.RoomKeyCounts +import org.matrix.rustcomponents.sdk.crypto.setLogger import timber.log.Timber -import uniffi.olm.BackupKeys -import uniffi.olm.BackupRecoveryKey -import uniffi.olm.CrossSigningKeyExport -import uniffi.olm.CrossSigningStatus -import uniffi.olm.CryptoStoreException -import uniffi.olm.DecryptionException -import uniffi.olm.DeviceLists -import uniffi.olm.KeyRequestPair -import uniffi.olm.Logger -import uniffi.olm.MegolmV1BackupKey -import uniffi.olm.Request -import uniffi.olm.RequestType -import uniffi.olm.RoomKeyCounts -import uniffi.olm.setLogger import java.io.File import java.nio.charset.Charset import javax.inject.Inject -import uniffi.olm.OlmMachine as InnerMachine -import uniffi.olm.ProgressListener as RustProgressListener +import org.matrix.rustcomponents.sdk.crypto.OlmMachine as InnerMachine +import org.matrix.rustcomponents.sdk.crypto.ProgressListener as RustProgressListener class CryptoLogger : Logger { override fun log(logLine: String) { @@ -256,19 +260,33 @@ internal class OlmMachine @Inject constructor( val devices = DeviceLists(deviceChanges?.changed.orEmpty(), deviceChanges?.left.orEmpty()) - val adapter = - moshi.adapter(ToDeviceSyncResponse::class.java) - val events = adapter.toJson(toDevice ?: ToDeviceSyncResponse())!! + + val adapter = MoshiProvider.providesMoshi().adapter(ToDeviceSyncResponse::class.java) + val events = adapter.toJson(toDevice ?: ToDeviceSyncResponse()).also { + Timber.w("## VALR events: $it") + } // TODO once our sync response type parses the unused fallback key // field pass in the list of unused fallback keys here - adapter.fromJson(inner.receiveSyncChanges(events, devices, counts, unusedFallbackKeys = null)) ?: ToDeviceSyncResponse() + val receiveSyncChanges = inner.receiveSyncChanges(events, devices, counts, unusedFallbackKeys = null).also { + Timber.w("## VALR $it") + } + val outAdapter = moshi.adapter>( + Types.newParameterizedType( + List::class.java, + Event::class.java, + String::class.java, + Integer::class.java, + Any::class.java, + ) + ) + outAdapter.fromJson(receiveSyncChanges) ?: emptyList() } // We may get cross signing keys over a to-device event, update our listeners. updateLivePrivateKeys() - return response + return ToDeviceSyncResponse(events = response) } suspend fun receiveUnencryptedVerificationEvent(roomId: String, event: Event) = withContext(coroutineDispatchers.io) { @@ -333,8 +351,10 @@ internal class OlmMachine @Inject constructor( * @return The list of [Request.ToDevice] that need to be sent out. */ @Throws(CryptoStoreException::class) - suspend fun shareRoomKey(roomId: String, users: List): List = - withContext(coroutineDispatchers.io) { inner.shareRoomKey(roomId, users) } + suspend fun shareRoomKey(roomId: String, users: List, settings: EncryptionSettings): List = + withContext(coroutineDispatchers.io) { + inner.shareRoomKey(roomId, users, settings) + } /** * Encrypt the given event with the given type and content for the given room. @@ -450,7 +470,9 @@ internal class OlmMachine @Inject constructor( */ @Throws(CryptoStoreException::class) suspend fun exportKeys(passphrase: String, rounds: Int): ByteArray = - withContext(coroutineDispatchers.io) { inner.exportKeys(passphrase, rounds).toByteArray() } + withContext(coroutineDispatchers.io) { + inner.exportRoomKeys(passphrase, rounds).toByteArray() + } /** * Import room keys from the given serialized key export. @@ -472,7 +494,7 @@ internal class OlmMachine @Inject constructor( val rustListener = CryptoProgressListener(listener) - val result = inner.importKeys(decodedKeys, passphrase, rustListener) + val result = inner.importRoomKeys(decodedKeys, passphrase, rustListener) ImportRoomKeysResult.fromOlm(result) } @@ -501,7 +523,7 @@ internal class OlmMachine @Inject constructor( } } - inner.importDecryptedKeys(encodedKeys, rustListener).let { + inner.importDecryptedRoomKeys(encodedKeys, rustListener).let { totalImported += it.imported accTotal += it.total details.putAll(it.keys) @@ -812,7 +834,7 @@ internal class OlmMachine @Inject constructor( .build() .adapter(MegolmBackupAuthData::class.java) val serializedAuthData = adapter.toJson(authData) - inner.verifyBackup(serializedAuthData) + inner.verifyBackup(serializedAuthData).trusted } } } diff --git a/matrix-sdk-android/src/rustCrypto/java/org/matrix/android/sdk/internal/crypto/PrepareToEncryptUseCase.kt b/matrix-sdk-android/src/rustCrypto/java/org/matrix/android/sdk/internal/crypto/PrepareToEncryptUseCase.kt index 16e6b81583..92fdebf5bd 100644 --- a/matrix-sdk-android/src/rustCrypto/java/org/matrix/android/sdk/internal/crypto/PrepareToEncryptUseCase.kt +++ b/matrix-sdk-android/src/rustCrypto/java/org/matrix/android/sdk/internal/crypto/PrepareToEncryptUseCase.kt @@ -30,9 +30,12 @@ import org.matrix.android.sdk.internal.crypto.network.RequestSender import org.matrix.android.sdk.internal.crypto.store.IMXCryptoStore import org.matrix.android.sdk.internal.session.SessionScope import org.matrix.android.sdk.internal.session.room.membership.LoadRoomMembersTask +import org.matrix.rustcomponents.sdk.crypto.EncryptionSettings +import org.matrix.rustcomponents.sdk.crypto.EventEncryptionAlgorithm +import org.matrix.rustcomponents.sdk.crypto.HistoryVisibility +import org.matrix.rustcomponents.sdk.crypto.Request +import org.matrix.rustcomponents.sdk.crypto.RequestType import timber.log.Timber -import uniffi.olm.Request -import uniffi.olm.RequestType import java.util.concurrent.ConcurrentHashMap import javax.inject.Inject @@ -83,9 +86,26 @@ internal class PrepareToEncryptUseCase @Inject constructor( claimMissingKeys(roomMembers) val keyShareLock = roomKeyShareLocks.getOrPut(roomId) { Mutex() } var sharedKey = false + + cryptoStore.getBlockUnverifiedDevices(roomId) + cryptoStore.shouldShareHistory(roomId) + val settings = EncryptionSettings( + algorithm = EventEncryptionAlgorithm.MEGOLM_V1_AES_SHA2, + onlyAllowTrustedDevices = cryptoStore.getBlockUnverifiedDevices(roomId), + // TODO should take that from m.room.encryption event + rotationPeriod = (7 * 24 * 3600 * 1000).toULong(), + rotationPeriodMsgs = 100UL, + historyVisibility = if (cryptoStore.shouldShareHistory(roomId)) { + HistoryVisibility.SHARED + } else if (cryptoStore.shouldEncryptForInvitedMembers(roomId)) { + HistoryVisibility.INVITED + } else { + HistoryVisibility.JOINED + } + ) keyShareLock.withLock { coroutineScope { - olmMachine.shareRoomKey(roomId, roomMembers).map { + olmMachine.shareRoomKey(roomId, roomMembers, settings).map { when (it) { is Request.ToDevice -> { sharedKey = true @@ -93,7 +113,7 @@ internal class PrepareToEncryptUseCase @Inject constructor( sendToDevice(olmMachine, it) } } - else -> { + else -> { // This request can only be a to-device request but // we need to handle all our cases and put this // async block for our joinAll to work. diff --git a/matrix-sdk-android/src/rustCrypto/java/org/matrix/android/sdk/internal/crypto/RustCrossSigningService.kt b/matrix-sdk-android/src/rustCrypto/java/org/matrix/android/sdk/internal/crypto/RustCrossSigningService.kt index 20f2b6555d..ac071beae7 100644 --- a/matrix-sdk-android/src/rustCrypto/java/org/matrix/android/sdk/internal/crypto/RustCrossSigningService.kt +++ b/matrix-sdk-android/src/rustCrypto/java/org/matrix/android/sdk/internal/crypto/RustCrossSigningService.kt @@ -17,6 +17,7 @@ package org.matrix.android.sdk.internal.crypto import androidx.lifecycle.LiveData +import kotlinx.coroutines.runBlocking import org.matrix.android.sdk.api.auth.UserInteractiveAuthInterceptor import org.matrix.android.sdk.api.session.crypto.crosssigning.CrossSigningService import org.matrix.android.sdk.api.session.crypto.crosssigning.DeviceTrustResult @@ -24,6 +25,7 @@ import org.matrix.android.sdk.api.session.crypto.crosssigning.MXCrossSigningInfo import org.matrix.android.sdk.api.session.crypto.crosssigning.PrivateKeysInfo import org.matrix.android.sdk.api.session.crypto.crosssigning.UserTrustResult import org.matrix.android.sdk.api.session.crypto.crosssigning.isVerified +import org.matrix.android.sdk.api.session.crypto.model.CryptoDeviceInfo import org.matrix.android.sdk.api.session.crypto.model.RoomEncryptionTrustLevel import org.matrix.android.sdk.api.util.Optional import javax.inject.Inject @@ -213,4 +215,22 @@ internal class RustCrossSigningService @Inject constructor( // TODO // is this needed in rust? } + + override fun checkSelfTrust(myCrossSigningInfo: MXCrossSigningInfo?, myDevices: List?): UserTrustResult { + // is this needed in rust? should be moved to internal API? + val verified = runBlocking { + val identity = olmMachine.getIdentity(olmMachine.userId()) as? OwnUserIdentity + identity?.verified() + } + return if (verified == null) { + UserTrustResult.CrossSigningNotConfigured(olmMachine.userId()) + } else { + UserTrustResult.Success + } + } + + override fun checkOtherMSKTrusted(myCrossSigningInfo: MXCrossSigningInfo?, otherInfo: MXCrossSigningInfo?): UserTrustResult { + // is this needed in rust? should be moved to internal API? + TODO() + } } diff --git a/matrix-sdk-android/src/rustCrypto/java/org/matrix/android/sdk/internal/crypto/RustCryptoService.kt b/matrix-sdk-android/src/rustCrypto/java/org/matrix/android/sdk/internal/crypto/RustCryptoService.kt index 37125f807f..e83734773c 100755 --- a/matrix-sdk-android/src/rustCrypto/java/org/matrix/android/sdk/internal/crypto/RustCryptoService.kt +++ b/matrix-sdk-android/src/rustCrypto/java/org/matrix/android/sdk/internal/crypto/RustCryptoService.kt @@ -683,11 +683,11 @@ internal class RustCryptoService @Inject constructor( } override fun enableShareKeyOnInvite(enable: Boolean) { - TODO("Not yet implemented") + TODO("Enable share key on invite not implemented") } override fun isShareKeysOnInviteEnabled(): Boolean { - TODO("Not yet implemented") + return false } override fun setRoomUnBlockUnverifiedDevices(roomId: String) { @@ -851,7 +851,7 @@ internal class RustCryptoService @Inject constructor( override suspend fun prepareToEncrypt(roomId: String) = prepareToEncrypt.invoke(roomId, ensureAllMembersAreLoaded = true) override suspend fun sendSharedHistoryKeys(roomId: String, userId: String, sessionInfoSet: Set?) { - TODO("Not yet implemented") + // TODO("Not yet implemented") } /* ========================================================================================== diff --git a/matrix-sdk-android/src/rustCrypto/java/org/matrix/android/sdk/internal/crypto/UserIdentities.kt b/matrix-sdk-android/src/rustCrypto/java/org/matrix/android/sdk/internal/crypto/UserIdentities.kt index 42874d5746..d0422834db 100644 --- a/matrix-sdk-android/src/rustCrypto/java/org/matrix/android/sdk/internal/crypto/UserIdentities.kt +++ b/matrix-sdk-android/src/rustCrypto/java/org/matrix/android/sdk/internal/crypto/UserIdentities.kt @@ -26,9 +26,9 @@ import org.matrix.android.sdk.api.session.events.model.EventType import org.matrix.android.sdk.internal.crypto.network.RequestSender import org.matrix.android.sdk.internal.crypto.verification.VerificationRequest import org.matrix.android.sdk.internal.crypto.verification.prepareMethods -import uniffi.olm.CryptoStoreException -import uniffi.olm.OlmMachine -import uniffi.olm.SignatureException +import org.matrix.rustcomponents.sdk.crypto.CryptoStoreException +import org.matrix.rustcomponents.sdk.crypto.OlmMachine +import org.matrix.rustcomponents.sdk.crypto.SignatureException /** * A sealed class representing user identities. diff --git a/matrix-sdk-android/src/rustCrypto/java/org/matrix/android/sdk/internal/crypto/keysbackup/BackupRecoveryKey.kt b/matrix-sdk-android/src/rustCrypto/java/org/matrix/android/sdk/internal/crypto/keysbackup/BackupRecoveryKey.kt index 5a2db17d9b..a3ab09d3d6 100644 --- a/matrix-sdk-android/src/rustCrypto/java/org/matrix/android/sdk/internal/crypto/keysbackup/BackupRecoveryKey.kt +++ b/matrix-sdk-android/src/rustCrypto/java/org/matrix/android/sdk/internal/crypto/keysbackup/BackupRecoveryKey.kt @@ -16,7 +16,7 @@ package org.matrix.android.sdk.api.session.crypto.keysbackup -import uniffi.olm.BackupRecoveryKey as InnerBackupRecoveryKey +import org.matrix.rustcomponents.sdk.crypto.BackupRecoveryKey as InnerBackupRecoveryKey class BackupRecoveryKey internal constructor(internal val inner: InnerBackupRecoveryKey) : IBackupRecoveryKey { diff --git a/matrix-sdk-android/src/rustCrypto/java/org/matrix/android/sdk/internal/crypto/keysbackup/RustKeyBackupService.kt b/matrix-sdk-android/src/rustCrypto/java/org/matrix/android/sdk/internal/crypto/keysbackup/RustKeyBackupService.kt index d6fb699060..05c22f76b1 100644 --- a/matrix-sdk-android/src/rustCrypto/java/org/matrix/android/sdk/internal/crypto/keysbackup/RustKeyBackupService.kt +++ b/matrix-sdk-android/src/rustCrypto/java/org/matrix/android/sdk/internal/crypto/keysbackup/RustKeyBackupService.kt @@ -61,9 +61,9 @@ import org.matrix.android.sdk.internal.di.MoshiProvider import org.matrix.android.sdk.internal.session.SessionScope import org.matrix.android.sdk.internal.util.JsonCanonicalizer import org.matrix.olm.OlmException +import org.matrix.rustcomponents.sdk.crypto.Request +import org.matrix.rustcomponents.sdk.crypto.RequestType import timber.log.Timber -import uniffi.olm.Request -import uniffi.olm.RequestType import java.security.InvalidParameterException import javax.inject.Inject import kotlin.random.Random diff --git a/matrix-sdk-android/src/rustCrypto/java/org/matrix/android/sdk/internal/crypto/network/OutgoingRequestsProcessor.kt b/matrix-sdk-android/src/rustCrypto/java/org/matrix/android/sdk/internal/crypto/network/OutgoingRequestsProcessor.kt index c4754e5d51..2bfc5e3e26 100644 --- a/matrix-sdk-android/src/rustCrypto/java/org/matrix/android/sdk/internal/crypto/network/OutgoingRequestsProcessor.kt +++ b/matrix-sdk-android/src/rustCrypto/java/org/matrix/android/sdk/internal/crypto/network/OutgoingRequestsProcessor.kt @@ -29,9 +29,9 @@ import org.matrix.android.sdk.internal.crypto.ComputeShieldForGroupUseCase import org.matrix.android.sdk.internal.crypto.CryptoSessionInfoProvider import org.matrix.android.sdk.internal.crypto.OlmMachine import org.matrix.android.sdk.internal.session.SessionScope +import org.matrix.rustcomponents.sdk.crypto.Request +import org.matrix.rustcomponents.sdk.crypto.RequestType import timber.log.Timber -import uniffi.olm.Request -import uniffi.olm.RequestType import javax.inject.Inject private val loggerTag = LoggerTag("OutgoingRequestsProcessor", LoggerTag.CRYPTO) diff --git a/matrix-sdk-android/src/rustCrypto/java/org/matrix/android/sdk/internal/crypto/network/RequestSender.kt b/matrix-sdk-android/src/rustCrypto/java/org/matrix/android/sdk/internal/crypto/network/RequestSender.kt index 901df6be35..77de8cbbac 100644 --- a/matrix-sdk-android/src/rustCrypto/java/org/matrix/android/sdk/internal/crypto/network/RequestSender.kt +++ b/matrix-sdk-android/src/rustCrypto/java/org/matrix/android/sdk/internal/crypto/network/RequestSender.kt @@ -62,11 +62,11 @@ import org.matrix.android.sdk.internal.di.MoshiProvider import org.matrix.android.sdk.internal.network.DEFAULT_REQUEST_RETRY_COUNT import org.matrix.android.sdk.internal.network.parsing.CheckNumberType import org.matrix.android.sdk.internal.session.room.send.SendResponse +import org.matrix.rustcomponents.sdk.crypto.OutgoingVerificationRequest +import org.matrix.rustcomponents.sdk.crypto.Request +import org.matrix.rustcomponents.sdk.crypto.SignatureUploadRequest +import org.matrix.rustcomponents.sdk.crypto.UploadSigningKeysRequest import timber.log.Timber -import uniffi.olm.OutgoingVerificationRequest -import uniffi.olm.Request -import uniffi.olm.SignatureUploadRequest -import uniffi.olm.UploadSigningKeysRequest import javax.inject.Inject internal class RequestSender @Inject constructor( diff --git a/matrix-sdk-android/src/rustCrypto/java/org/matrix/android/sdk/internal/crypto/verification/RustVerificationService.kt b/matrix-sdk-android/src/rustCrypto/java/org/matrix/android/sdk/internal/crypto/verification/RustVerificationService.kt index dcb0ae250e..b6ce901057 100644 --- a/matrix-sdk-android/src/rustCrypto/java/org/matrix/android/sdk/internal/crypto/verification/RustVerificationService.kt +++ b/matrix-sdk-android/src/rustCrypto/java/org/matrix/android/sdk/internal/crypto/verification/RustVerificationService.kt @@ -74,6 +74,8 @@ internal class RustVerificationService @Inject constructor( private val olmMachine: OlmMachine, private val verificationListenersHolder: VerificationListenersHolder) : VerificationService { + override fun requestEventFlow() = verificationListenersHolder.eventFlow + /** * * All verification related events should be forwarded through this method to @@ -103,7 +105,7 @@ internal class RustVerificationService @Inject constructor( } } - private fun onRoomMessage(event: Event) { + private suspend fun onRoomMessage(event: Event) { val messageContent = event.getClearContent()?.toModel() ?: return if (messageContent.msgType == MessageType.MSGTYPE_VERIFICATION_REQUEST) { onRequest(event, fromRoomMessage = true) @@ -111,7 +113,7 @@ internal class RustVerificationService @Inject constructor( } /** Dispatch updates after a verification event has been received */ - private fun onUpdate(event: Event) { + private suspend fun onUpdate(event: Event) { val sender = event.senderId ?: return val flowId = getFlowId(event) ?: return @@ -150,7 +152,7 @@ internal class RustVerificationService @Inject constructor( } /** Check if the request event created a nev verification request object and dispatch that it dis so */ - private fun onRequest(event: Event, fromRoomMessage: Boolean) { + private suspend fun onRequest(event: Event, fromRoomMessage: Boolean) { val flowId = if (fromRoomMessage) { event.eventId } else { @@ -162,26 +164,26 @@ internal class RustVerificationService @Inject constructor( verificationListenersHolder.dispatchRequestAdded(request) } - override fun addListener(listener: VerificationService.Listener) { - verificationListenersHolder.addListener(listener) - } - - override fun removeListener(listener: VerificationService.Listener) { - verificationListenersHolder.removeListener(listener) - } +// override fun addListener(listener: VerificationService.Listener) { +// verificationListenersHolder.addListener(listener) +// } +// +// override fun removeListener(listener: VerificationService.Listener) { +// verificationListenersHolder.removeListener(listener) +// } override suspend fun markedLocallyAsManuallyVerified(userId: String, deviceID: String) { olmMachine.getDevice(userId, deviceID)?.markAsTrusted() } - override fun getExistingTransaction( + override suspend fun getExistingTransaction( otherUserId: String, tid: String, ): VerificationTransaction? { return olmMachine.getVerification(otherUserId, tid) } - override fun getExistingVerificationRequests( + override suspend fun getExistingVerificationRequests( otherUserId: String ): List { return olmMachine.getVerificationRequests(otherUserId).map { @@ -189,7 +191,7 @@ internal class RustVerificationService @Inject constructor( } } - override fun getExistingVerificationRequest( + override suspend fun getExistingVerificationRequest( otherUserId: String, tid: String? ): PendingVerificationRequest? { @@ -200,9 +202,9 @@ internal class RustVerificationService @Inject constructor( } } - override fun getExistingVerificationRequestInRoom( + override suspend fun getExistingVerificationRequestInRoom( roomId: String, - tid: String? + tid: String ): PendingVerificationRequest? { // This is only used in `RoomDetailViewModel` to resume the verification. // @@ -251,13 +253,23 @@ internal class RustVerificationService @Inject constructor( override suspend fun requestDeviceVerification(methods: List, otherUserId: String, - otherDeviceId: String?): PendingVerificationRequest? { + otherDeviceId: String?): PendingVerificationRequest { // how do we send request to several devices in rust? - if (otherDeviceId == null) return null olmMachine.ensureUsersKeys(listOf(otherUserId)) - val otherDevice = olmMachine.getDevice(otherUserId, otherDeviceId) - val verificationRequest = otherDevice?.requestVerification(methods) - return verificationRequest?.toPendingVerificationRequest() + val request = if (otherDeviceId == null) { + // Todo + when (val identity = olmMachine.getIdentity(otherUserId)) { + is OwnUserIdentity -> identity.requestVerification(methods) + is UserIdentity -> { + throw IllegalArgumentException("to_device request only allowed for own user $otherUserId") + } + null -> throw IllegalArgumentException("Unknown identity") + } + } else { + val otherDevice = olmMachine.getDevice(otherUserId, otherDeviceId) + otherDevice?.requestVerification(methods) ?: throw IllegalArgumentException("Unknown device $otherDeviceId") + } + return request.toPendingVerificationRequest() } override suspend fun readyPendingVerification( @@ -269,29 +281,15 @@ internal class RustVerificationService @Inject constructor( return if (request != null) { request.acceptWithMethods(methods) - if (request.isReady()) { - val qrcode = request.startQrVerification() - - if (qrcode != null) { - verificationListenersHolder.dispatchTxAdded(qrcode) - } - - true - } else { - false - } + request.isReady() } else { false } } - override suspend fun beginKeyVerification( - method: VerificationMethod, - otherUserId: String, - transactionId: String - ): String? { + override suspend fun startKeyVerification(method: VerificationMethod, otherUserId: String, requestId: String): String? { return if (method == VerificationMethod.SAS) { - val request = olmMachine.getVerificationRequest(otherUserId, transactionId) + val request = olmMachine.getVerificationRequest(otherUserId, requestId) val sas = request?.startSasVerification() @@ -306,7 +304,13 @@ internal class RustVerificationService @Inject constructor( } } - override fun onPotentiallyInterestingEventRoomFailToDecrypt(event: Event) { + override suspend fun reciprocateQRVerification(otherUserId: String, requestId: String, scannedData: String): String? { + val matchingRequest = olmMachine.getVerificationRequest(otherUserId, requestId) + matchingRequest?.scanQrCode(scannedData) + return matchingRequest?.startQrVerification()?.transactionId + } + + override suspend fun onPotentiallyInterestingEventRoomFailToDecrypt(event: Event) { // not available in rust } @@ -331,7 +335,6 @@ internal class RustVerificationService @Inject constructor( // } override suspend fun cancelVerificationRequest(request: PendingVerificationRequest) { - request.transactionId ?: return cancelVerificationRequest(request.otherUserId, request.transactionId) } diff --git a/matrix-sdk-android/src/rustCrypto/java/org/matrix/android/sdk/internal/crypto/verification/SasVerification.kt b/matrix-sdk-android/src/rustCrypto/java/org/matrix/android/sdk/internal/crypto/verification/SasVerification.kt index dcdf028e7e..1de12dc0e9 100644 --- a/matrix-sdk-android/src/rustCrypto/java/org/matrix/android/sdk/internal/crypto/verification/SasVerification.kt +++ b/matrix-sdk-android/src/rustCrypto/java/org/matrix/android/sdk/internal/crypto/verification/SasVerification.kt @@ -25,14 +25,16 @@ import org.matrix.android.sdk.api.MatrixCoroutineDispatchers import org.matrix.android.sdk.api.extensions.tryOrNull 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.SasTransactionState import org.matrix.android.sdk.api.session.crypto.verification.SasVerificationTransaction -import org.matrix.android.sdk.api.session.crypto.verification.VerificationTxState +import org.matrix.android.sdk.api.session.crypto.verification.VerificationMethod import org.matrix.android.sdk.api.session.crypto.verification.safeValueOf import org.matrix.android.sdk.internal.crypto.OlmMachine import org.matrix.android.sdk.internal.crypto.network.RequestSender -import uniffi.olm.CryptoStoreException -import uniffi.olm.Sas -import uniffi.olm.Verification +import org.matrix.rustcomponents.sdk.crypto.CryptoStoreException +import org.matrix.rustcomponents.sdk.crypto.Sas +import org.matrix.rustcomponents.sdk.crypto.SasListener +import org.matrix.rustcomponents.sdk.crypto.SasState /** Class representing a short auth string verification flow */ internal class SasVerification @AssistedInject constructor( @@ -40,60 +42,67 @@ internal class SasVerification @AssistedInject constructor( private val olmMachine: OlmMachine, private val sender: RequestSender, private val coroutineDispatchers: MatrixCoroutineDispatchers, - private val verificationListenersHolder: VerificationListenersHolder + private val verificationListenersHolder: VerificationListenersHolder, ) : - SasVerificationTransaction { + SasVerificationTransaction, SasListener { + + init { + inner.setChangesListener(this) + } + + var innerState: SasState = SasState.Started @AssistedFactory interface Factory { fun create(inner: Sas): SasVerification } - private val innerMachine = olmMachine.inner() - - private fun dispatchTxUpdated() { - refreshData() - verificationListenersHolder.dispatchTxUpdated(this) - } - /** The user ID of the other user that is participating in this verification flow */ - override val otherUserId: String = inner.otherUserId + override val otherUserId: String = inner.otherUserId() /** Get the device id of the other user's device participating in this verification flow */ - override var otherDeviceId: String? - get() = inner.otherDeviceId - @Suppress("UNUSED_PARAMETER") - set(value) { - } + override val otherDeviceId: String + get() = inner.otherDeviceId() /** Did the other side initiate this verification flow */ override val isIncoming: Boolean - get() = !inner.weStarted + get() = !inner.weStarted() - override var state: VerificationTxState - get() { - refreshData() - val cancelInfo = inner.cancelInfo + private var decimals: List? = null + private var emojis: List? = null - return when { - cancelInfo != null -> { - val cancelCode = safeValueOf(cancelInfo.cancelCode) - VerificationTxState.Cancelled(cancelCode, cancelInfo.cancelledByUs) - } - inner.isDone -> VerificationTxState.Verified - inner.haveWeConfirmed -> VerificationTxState.SasMacSent - inner.canBePresented -> VerificationTxState.SasShortCodeReady - inner.hasBeenAccepted -> VerificationTxState.SasAccepted - else -> VerificationTxState.SasStarted + override fun state(): SasTransactionState { + return when (val state = innerState) { + SasState.Started -> SasTransactionState.SasStarted + SasState.Accepted -> SasTransactionState.SasAccepted + is SasState.KeysExchanged -> { + this.decimals = state.decimals + this.emojis = state.emojis + SasTransactionState.SasShortCodeReady } + SasState.Confirmed -> SasTransactionState.SasMacSent + SasState.Done -> SasTransactionState.Done(false) + is SasState.Cancelled -> SasTransactionState.Cancelled(safeValueOf(state.cancelInfo.cancelCode), state.cancelInfo.cancelledByUs) } - @Suppress("UNUSED_PARAMETER") - set(v) { - } +// refreshData() +// val cancelInfo = inner.cancelInfo +// +// return when { +// cancelInfo != null -> { +// val cancelCode = safeValueOf(cancelInfo.cancelCode) +// SasTransactionState.Cancelled(cancelCode, cancelInfo.cancelledByUs) +// } +// inner.isDone -> SasTransactionState.Done(true) +// inner.haveWeConfirmed -> SasTransactionState.SasAccepted +// inner.canBePresented -> SasTransactionState.SasShortCodeReady +// inner.hasBeenAccepted -> SasTransactionState.SasAccepted +// else -> SasTransactionState.SasStarted +// } + } /** Get the unique id of this verification */ override val transactionId: String - get() = inner.flowId + get() = inner.flowId() /** Cancel the verification flow * @@ -136,13 +145,15 @@ internal class SasVerification @AssistedInject constructor( cancelHelper(CancelCode.MismatchedSas) } + override val method: VerificationMethod + get() = VerificationMethod.QR_CODE_SCAN + /** Is this verification happening over to-device messages */ - override fun isToDeviceTransport(): Boolean = inner.roomId == null + override fun isToDeviceTransport(): Boolean = inner.roomId() == null /** Does the verification flow support showing emojis as the short auth string */ override fun supportsEmoji(): Boolean { - refreshData() - return inner.supportsEmoji + return inner.supportsEmoji() } /** Confirm that the short authentication code matches on both sides @@ -177,8 +188,6 @@ internal class SasVerification @AssistedInject constructor( * in a presentable state. */ override fun getDecimalCodeRepresentation(): String { - val decimals = innerMachine.getDecimals(inner.otherUserId, inner.flowId) - return decimals?.joinToString(" ") ?: "" } @@ -189,14 +198,13 @@ internal class SasVerification @AssistedInject constructor( * state. */ override fun getEmojiCodeRepresentation(): List { - val emojiIndex = innerMachine.getEmojiIndex(inner.otherUserId, inner.flowId) - - return emojiIndex?.map { getEmojiForCode(it) } ?: listOf() + return emojis?.map { getEmojiForCode(it) } ?: listOf() } internal suspend fun accept() { - val request = innerMachine.acceptSasVerification(inner.otherUserId, inner.flowId) ?: return - dispatchTxUpdated() + val request = inner.accept() ?: return Unit.also { + // TODO should throw here? + } try { sender.sendVerificationRequest(request) } catch (failure: Throwable) { @@ -207,10 +215,8 @@ internal class SasVerification @AssistedInject constructor( @Throws(CryptoStoreException::class) private suspend fun confirm() { val result = withContext(coroutineDispatchers.io) { - innerMachine.confirmVerification(inner.otherUserId, inner.flowId) + inner.confirm() } ?: return - - dispatchTxUpdated() try { for (verificationRequest in result.requests) { sender.sendVerificationRequest(verificationRequest) @@ -225,24 +231,28 @@ internal class SasVerification @AssistedInject constructor( } private suspend fun cancelHelper(code: CancelCode) = withContext(NonCancellable) { - val request = innerMachine.cancelVerification(inner.otherUserId, inner.flowId, code.value) ?: return@withContext - dispatchTxUpdated() + val request = inner.cancel(code.value) ?: return@withContext tryOrNull("Fail to send cancel request") { sender.sendVerificationRequest(request, retryCount = Int.MAX_VALUE) } } /** Fetch fresh data from the Rust side for our verification flow */ - private fun refreshData() { - when (val verification = innerMachine.getVerification(inner.otherUserId, inner.flowId)) { - is Verification.SasV1 -> { - inner = verification.sas - } - else -> { - } - } +// private fun refreshData() { +// when (val verification = innerMachine.getVerification(inner.otherUserId, inner.flowId)) { +// is Verification.SasV1 -> { +// inner = verification.sas +// } +// else -> { +// } +// } +// +// return +// } - return + override fun onChange(state: SasState) { + innerState = state + verificationListenersHolder.dispatchTxUpdated(this) } override fun toString(): String { @@ -250,7 +260,7 @@ internal class SasVerification @AssistedInject constructor( "otherUserId='$otherUserId', " + "otherDeviceId=$otherDeviceId, " + "isIncoming=$isIncoming, " + - "state=$state, " + + "state=${state()}, " + "transactionId='$transactionId')" } } diff --git a/matrix-sdk-android/src/rustCrypto/java/org/matrix/android/sdk/internal/crypto/verification/VerificationRequest.kt b/matrix-sdk-android/src/rustCrypto/java/org/matrix/android/sdk/internal/crypto/verification/VerificationRequest.kt index 996c6fdee0..c3505f34cc 100644 --- a/matrix-sdk-android/src/rustCrypto/java/org/matrix/android/sdk/internal/crypto/verification/VerificationRequest.kt +++ b/matrix-sdk-android/src/rustCrypto/java/org/matrix/android/sdk/internal/crypto/verification/VerificationRequest.kt @@ -24,18 +24,21 @@ import kotlinx.coroutines.withContext import org.matrix.android.sdk.api.MatrixCoroutineDispatchers import org.matrix.android.sdk.api.extensions.tryOrNull import org.matrix.android.sdk.api.session.crypto.verification.CancelCode +import org.matrix.android.sdk.api.session.crypto.verification.EVerificationState 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.ValidVerificationInfoRequest import org.matrix.android.sdk.api.session.crypto.verification.VerificationMethod import org.matrix.android.sdk.api.session.crypto.verification.safeValueOf import org.matrix.android.sdk.api.util.toBase64NoPadding import org.matrix.android.sdk.internal.crypto.OlmMachine 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 +import org.matrix.android.sdk.internal.crypto.model.rest.VERIFICATION_METHOD_RECIPROCATE +import org.matrix.android.sdk.internal.crypto.model.rest.VERIFICATION_METHOD_SAS import org.matrix.android.sdk.internal.crypto.network.RequestSender import org.matrix.android.sdk.internal.crypto.verification.qrcode.QrCodeVerification import org.matrix.android.sdk.internal.util.time.Clock -import uniffi.olm.VerificationRequest as InnerVerificationRequest +import org.matrix.rustcomponents.sdk.crypto.QrCode +import org.matrix.rustcomponents.sdk.crypto.VerificationRequest as InnerVerificationRequest /** A verification request object * @@ -74,12 +77,12 @@ internal class VerificationRequest @AssistedInject constructor( * event that initiated the flow. */ internal fun flowId(): String { - return innerVerificationRequest.flowId + return innerVerificationRequest.flowId() } /** The user ID of the other user that is participating in this verification flow */ internal fun otherUser(): String { - return innerVerificationRequest.otherUserId + return innerVerificationRequest.otherUserId() } /** The device ID of the other user's device that is participating in this verification flow @@ -89,12 +92,12 @@ internal class VerificationRequest @AssistedInject constructor( * */ internal fun otherDeviceId(): String? { refreshData() - return innerVerificationRequest.otherDeviceId + return innerVerificationRequest.otherDeviceId() } /** Did we initiate this verification flow */ internal fun weStarted(): Boolean { - return innerVerificationRequest.weStarted + return innerVerificationRequest.weStarted() } /** Get the id of the room where this verification is happening @@ -102,7 +105,7 @@ internal class VerificationRequest @AssistedInject constructor( * Will be null if the verification is not happening inside a room. */ internal fun roomId(): String? { - return innerVerificationRequest.roomId + return innerVerificationRequest.roomId() } /** Did the non-initiating side respond with a m.key.verification.read event @@ -113,13 +116,13 @@ internal class VerificationRequest @AssistedInject constructor( */ internal fun isReady(): Boolean { refreshData() - return innerVerificationRequest.isReady + return innerVerificationRequest.isReady() } /** Did we advertise that we're able to scan QR codes */ internal fun canScanQrCodes(): Boolean { refreshData() - return innerVerificationRequest.ourMethods?.contains(VERIFICATION_METHOD_QR_CODE_SCAN) ?: false + return innerVerificationRequest.ourSupportedMethods()?.contains(VERIFICATION_METHOD_QR_CODE_SCAN) ?: false } /** Accept the verification request advertising the given methods as supported @@ -138,20 +141,28 @@ internal class VerificationRequest @AssistedInject constructor( suspend fun acceptWithMethods(methods: List) { val stringMethods = prepareMethods(methods) - val request = innerOlmMachine.acceptVerificationRequest( - innerVerificationRequest.otherUserId, - innerVerificationRequest.flowId, - stringMethods - ) ?: return + val request = innerVerificationRequest.accept(stringMethods) + ?: return // should throw here? +// val request = innerOlmMachine.acceptVerificationRequest( +// innerVerificationRequest.otherUserId(), +// innerVerificationRequest.flowId, +// stringMethods +// ) ?: return try { dispatchRequestUpdated() requestSender.sendVerificationRequest(request) + + if (innerVerificationRequest.isReady()) { + activeQRCode = innerVerificationRequest.startQrVerification() + } } catch (failure: Throwable) { cancel(CancelCode.UserError) } } + var activeQRCode: QrCode? = null + /** Transition from a ready verification request into emoji verification * * This method will move the verification forward into emoji verification, @@ -167,7 +178,10 @@ internal class VerificationRequest @AssistedInject constructor( */ internal suspend fun startSasVerification(): SasVerification? { return withContext(coroutineDispatchers.io) { - val result = innerOlmMachine.startSasVerification(innerVerificationRequest.otherUserId, innerVerificationRequest.flowId) ?: return@withContext null + val result = innerVerificationRequest.startSasVerification() + ?: return@withContext null +// sasStartResult.request +// val result = innerOlmMachine.startSasVerification(innerVerificationRequest.otherUserId, innerVerificationRequest.flowId) ?: return@withContext null try { requestSender.sendVerificationRequest(result.request) sasVerificationFactory.create(result.sas) @@ -195,7 +209,8 @@ internal class VerificationRequest @AssistedInject constructor( // TODO again, what's the deal with ISO_8859_1? val byteArray = data.toByteArray(Charsets.ISO_8859_1) val encodedData = byteArray.toBase64NoPadding() - val result = innerOlmMachine.scanQrCode(otherUser(), flowId(), encodedData) ?: return null +// val result = innerOlmMachine.scanQrCode(otherUser(), flowId(), encodedData) ?: return null + val result = innerVerificationRequest.scanQrCode(encodedData) ?: return null try { requestSender.sendVerificationRequest(result.request) } catch (failure: Throwable) { @@ -223,9 +238,12 @@ internal class VerificationRequest @AssistedInject constructor( * QR code verification, or null if we can't yet transition into QR code verification. */ internal fun startQrVerification(): QrCodeVerification? { - val qrcode = innerOlmMachine.startQrVerification(innerVerificationRequest.otherUserId, innerVerificationRequest.flowId) - return if (qrcode != null) { - qrCodeVerificationFactory.create(this, qrcode) + activeQRCode = innerVerificationRequest.startQrVerification() +// val qrcode = innerOlmMachine.startQrVerification(innerVerificationRequest.otherUserId, innerVerificationRequest.flowId) + return if (activeQRCode != null) { + TODO("Is this reciprocate or just doing nothing?") +// activeQRCode. +// qrCodeVerificationFactory.create(this, qrcode) } else { null } @@ -242,11 +260,13 @@ internal class VerificationRequest @AssistedInject constructor( * The method turns into a noop, if the verification flow has already been cancelled. */ internal suspend fun cancel(cancelCode: CancelCode = CancelCode.User) = withContext(NonCancellable) { - val request = innerOlmMachine.cancelVerification( - innerVerificationRequest.otherUserId, - innerVerificationRequest.flowId, - cancelCode.value - ) ?: return@withContext + // TODO damir how to add the code? + val request = innerVerificationRequest.cancel() ?: return@withContext +// val request = innerOlmMachine.cancelVerification( +// innerVerificationRequest.otherUserId, +// innerVerificationRequest.flowId, +// cancelCode.value +// ) ?: return@withContext dispatchRequestUpdated() tryOrNull("Fail to send cancel request") { requestSender.sendVerificationRequest(request, retryCount = Int.MAX_VALUE) @@ -255,13 +275,24 @@ internal class VerificationRequest @AssistedInject constructor( /** Fetch fresh data from the Rust side for our verification flow */ private fun refreshData() { - val request = innerOlmMachine.getVerificationRequest(innerVerificationRequest.otherUserId, innerVerificationRequest.flowId) + val request = innerOlmMachine.getVerificationRequest(innerVerificationRequest.otherUserId(), innerVerificationRequest.flowId()) if (request != null) { innerVerificationRequest = request } } + private fun state(): EVerificationState { + when { + innerVerificationRequest.weStarted() -> EVerificationState.WaitingForReady + innerVerificationRequest.isDone() -> EVerificationState.Done + innerVerificationRequest.isCancelled() -> EVerificationState.Cancelled + innerVerificationRequest.isReady() -> EVerificationState.Ready + innerVerificationRequest.isPassive() -> EVerificationState.HandledByOtherSession + } + return EVerificationState.Requested + } + /** Convert the VerificationRequest into a PendingVerificationRequest * * The public interface of the VerificationService dispatches the data class @@ -273,7 +304,7 @@ internal class VerificationRequest @AssistedInject constructor( */ internal fun toPendingVerificationRequest(): PendingVerificationRequest { refreshData() - val cancelInfo = innerVerificationRequest.cancelInfo + val cancelInfo = innerVerificationRequest.cancelInfo() val cancelCode = if (cancelInfo != null) { safeValueOf(cancelInfo.cancelCode) @@ -281,72 +312,79 @@ internal class VerificationRequest @AssistedInject constructor( null } - val ourMethods = innerVerificationRequest.ourMethods - val theirMethods = innerVerificationRequest.theirMethods - val otherDeviceId = innerVerificationRequest.otherDeviceId + val ourMethods = innerVerificationRequest.ourSupportedMethods() + val theirMethods = innerVerificationRequest.theirSupportedMethods() + val otherDeviceId = innerVerificationRequest.otherDeviceId() - var requestInfo: ValidVerificationInfoRequest? = null - var readyInfo: ValidVerificationInfoReady? = null +// var requestInfo: ValidVerificationInfoRequest? = null +// var readyInfo: ValidVerificationInfoReady? = null +// +// if (innerVerificationRequest.weStarted && ourMethods != null) { +// requestInfo = +// ValidVerificationInfoRequest( +// transactionId = innerVerificationRequest.flowId, +// fromDevice = innerOlmMachine.deviceId(), +// methods = ourMethods, +// timestamp = null, +// ) +// } else if (!innerVerificationRequest.weStarted && ourMethods != null) { +// readyInfo = +// ValidVerificationInfoReady( +// transactionId = innerVerificationRequest.flowId, +// fromDevice = innerOlmMachine.deviceId(), +// methods = ourMethods, +// ) +// } +// +// if (innerVerificationRequest.weStarted && theirMethods != null && otherDeviceId != null) { +// readyInfo = +// ValidVerificationInfoReady( +// transactionId = innerVerificationRequest.flowId, +// fromDevice = otherDeviceId, +// methods = theirMethods, +// ) +// } else if (!innerVerificationRequest.weStarted && theirMethods != null && otherDeviceId != null) { +// requestInfo = +// ValidVerificationInfoRequest( +// transactionId = innerVerificationRequest.flowId, +// fromDevice = otherDeviceId, +// methods = theirMethods, +// timestamp = clock.epochMillis(), +// ) +// } - if (innerVerificationRequest.weStarted && ourMethods != null) { - requestInfo = - ValidVerificationInfoRequest( - transactionId = innerVerificationRequest.flowId, - fromDevice = innerOlmMachine.deviceId(), - methods = ourMethods, - timestamp = null, - ) - } else if (!innerVerificationRequest.weStarted && ourMethods != null) { - readyInfo = - ValidVerificationInfoReady( - transactionId = innerVerificationRequest.flowId, - fromDevice = innerOlmMachine.deviceId(), - methods = ourMethods, - ) - } - - if (innerVerificationRequest.weStarted && theirMethods != null && otherDeviceId != null) { - readyInfo = - ValidVerificationInfoReady( - transactionId = innerVerificationRequest.flowId, - fromDevice = otherDeviceId, - methods = theirMethods, - ) - } else if (!innerVerificationRequest.weStarted && theirMethods != null && otherDeviceId != null) { - requestInfo = - ValidVerificationInfoRequest( - transactionId = innerVerificationRequest.flowId, - fromDevice = otherDeviceId, - methods = theirMethods, - timestamp = clock.epochMillis(), - ) - } + innerVerificationRequest.startQrVerification() return PendingVerificationRequest( // Creation time ageLocalTs = clock.epochMillis(), + state = state(), // Who initiated the request - isIncoming = !innerVerificationRequest.weStarted, + isIncoming = !innerVerificationRequest.weStarted(), // Local echo id, what to do here? - localId = innerVerificationRequest.flowId, + otherDeviceId = innerVerificationRequest.otherDeviceId(), // other user - otherUserId = innerVerificationRequest.otherUserId, + otherUserId = innerVerificationRequest.otherUserId(), // room id - roomId = innerVerificationRequest.roomId, + roomId = innerVerificationRequest.roomId(), // transaction id - transactionId = innerVerificationRequest.flowId, - // val requestInfo: ValidVerificationInfoRequest? = null, - requestInfo = requestInfo, - // val readyInfo: ValidVerificationInfoReady? = null, - readyInfo = readyInfo, + transactionId = innerVerificationRequest.flowId(), // cancel code if there is one cancelConclusion = cancelCode, - // are we done/successful - isSuccessful = innerVerificationRequest.isDone, + isFinished = innerVerificationRequest.isDone() || innerVerificationRequest.isCancelled(), // did another device answer the request - handledByOtherSession = innerVerificationRequest.isPassive, + handledByOtherSession = innerVerificationRequest.isPassive(), // devices that should receive the events we send out - targetDevices = null + targetDevices = otherDeviceId?.let { listOf(it) }, + // TODO qr, + qrCodeText = activeQRCode?.generateQrCode(), + isSasSupported = ourMethods.canSas() && theirMethods.canSas(), + weShouldDisplayQRCode = theirMethods.canScanQR() && ourMethods.canShowQR(), + weShouldShowScanOption = ourMethods.canScanQR() && theirMethods.canShowQR() ) } + + private fun List?.canSas() = orEmpty().contains(VERIFICATION_METHOD_SAS) + private fun List?.canShowQR() = orEmpty().contains(VERIFICATION_METHOD_RECIPROCATE) && orEmpty().contains(VERIFICATION_METHOD_QR_CODE_SHOW) + private fun List?.canScanQR() = orEmpty().contains(VERIFICATION_METHOD_RECIPROCATE) && orEmpty().contains(VERIFICATION_METHOD_QR_CODE_SCAN) } diff --git a/matrix-sdk-android/src/rustCrypto/java/org/matrix/android/sdk/internal/crypto/verification/VerificationsProvider.kt b/matrix-sdk-android/src/rustCrypto/java/org/matrix/android/sdk/internal/crypto/verification/VerificationsProvider.kt index e7f9248abb..a30c05884e 100644 --- a/matrix-sdk-android/src/rustCrypto/java/org/matrix/android/sdk/internal/crypto/verification/VerificationsProvider.kt +++ b/matrix-sdk-android/src/rustCrypto/java/org/matrix/android/sdk/internal/crypto/verification/VerificationsProvider.kt @@ -21,7 +21,7 @@ import org.matrix.android.sdk.internal.crypto.OlmMachine import org.matrix.android.sdk.internal.crypto.verification.qrcode.QrCodeVerification import javax.inject.Inject import javax.inject.Provider -import uniffi.olm.OlmMachine as InnerOlmMachine +import org.matrix.rustcomponents.sdk.crypto.OlmMachine as InnerOlmMachine internal class VerificationsProvider @Inject constructor( private val olmMachine: Provider, @@ -49,26 +49,36 @@ internal class VerificationsProvider @Inject constructor( * verification. */ fun getVerification(userId: String, flowId: String): VerificationTransaction? { - return when (val verification = innerMachine.getVerification(userId, flowId)) { - is uniffi.olm.Verification.QrCodeV1 -> { - val request = getVerificationRequest(userId, flowId) ?: return null - qrVerificationFactory.create(request, verification.qrcode) - } - is uniffi.olm.Verification.SasV1 -> { - sasVerificationFactory.create(verification.sas) - } - 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()) { - qrVerificationFactory.create(request, null) - } else { - null - } - } + val verification = innerMachine.getVerification(userId, flowId) + return if (verification?.asSas() != null) { + sasVerificationFactory.create(verification.asSas()!!) + } else if (verification?.asQr() != null) { + // qrVerificationFactory.create(verification, verification.asQr()!!) + // TODO + null + } else { + null } +// return when (val verification = innerMachine.getVerification(userId, flowId)) { +// is org.matrix.rustcomponents.sdk.crypto.Verification. -> { +// val request = getVerificationRequest(userId, flowId) ?: return null +// qrVerificationFactory.create(request, verification.qrcode) +// } +// is org.matrix.rustcomponents.sdk.crypto.Verification.SasV1 -> { +// sasVerificationFactory.create(verification.sas) +// } +// 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()) { +// qrVerificationFactory.create(request, null) +// } else { +// null +// } +// } +// } } } diff --git a/matrix-sdk-android/src/rustCrypto/java/org/matrix/android/sdk/internal/crypto/verification/qrcode/QrCodeVerification.kt b/matrix-sdk-android/src/rustCrypto/java/org/matrix/android/sdk/internal/crypto/verification/qrcode/QrCodeVerification.kt index d96ed74d93..fbc87e1b8a 100644 --- a/matrix-sdk-android/src/rustCrypto/java/org/matrix/android/sdk/internal/crypto/verification/qrcode/QrCodeVerification.kt +++ b/matrix-sdk-android/src/rustCrypto/java/org/matrix/android/sdk/internal/crypto/verification/qrcode/QrCodeVerification.kt @@ -24,22 +24,21 @@ import kotlinx.coroutines.withContext import org.matrix.android.sdk.api.MatrixCoroutineDispatchers import org.matrix.android.sdk.api.extensions.tryOrNull import org.matrix.android.sdk.api.session.crypto.verification.CancelCode +import org.matrix.android.sdk.api.session.crypto.verification.QRCodeVerificationState import org.matrix.android.sdk.api.session.crypto.verification.QrCodeVerificationTransaction -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.crypto.verification.VerificationMethod import org.matrix.android.sdk.api.util.fromBase64 import org.matrix.android.sdk.internal.crypto.OlmMachine import org.matrix.android.sdk.internal.crypto.network.RequestSender import org.matrix.android.sdk.internal.crypto.verification.VerificationListenersHolder import org.matrix.android.sdk.internal.crypto.verification.VerificationRequest -import uniffi.olm.CryptoStoreException -import uniffi.olm.QrCode -import uniffi.olm.Verification +import org.matrix.rustcomponents.sdk.crypto.CryptoStoreException +import org.matrix.rustcomponents.sdk.crypto.QrCode /** Class representing a QR code based verification flow */ internal class QrCodeVerification @AssistedInject constructor( @Assisted private var request: VerificationRequest, - @Assisted private var inner: QrCode?, + @Assisted private var inner: QrCode, private val olmMachine: OlmMachine, private val sender: RequestSender, private val coroutineDispatchers: MatrixCoroutineDispatchers, @@ -48,9 +47,12 @@ internal class QrCodeVerification @AssistedInject constructor( @AssistedFactory interface Factory { - fun create(request: VerificationRequest, inner: QrCode?): QrCodeVerification + fun create(request: VerificationRequest, inner: QrCode): QrCodeVerification } + override val method: VerificationMethod + get() = VerificationMethod.QR_CODE_SCAN + private val innerMachine = olmMachine.inner() private fun dispatchTxUpdated() { @@ -72,17 +74,17 @@ internal class QrCodeVerification @AssistedInject constructor( */ override val qrCodeText: String? get() { - val data = inner?.let { innerMachine.generateQrCode(it.otherUserId, it.flowId) } + val data = inner.generateQrCode() // 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) } /** Pass the data from a scanned QR code into the QR code verification object */ - override suspend fun userHasScannedOtherQrCode(otherQrCodeText: String) { - request.scanQrCode(otherQrCodeText) - dispatchTxUpdated() - } +// override suspend fun userHasScannedOtherQrCode(otherQrCodeText: String) { +// request.scanQrCode(otherQrCodeText) +// dispatchTxUpdated() +// } /** Confirm that the other side has indeed scanned the QR code we presented */ override suspend fun otherUserScannedMyQrCode() { @@ -95,32 +97,35 @@ internal class QrCodeVerification @AssistedInject constructor( cancelHelper(CancelCode.MismatchedKeys) } - override var state: VerificationTxState - get() { - refreshData() - val inner = inner - val cancelInfo = inner?.cancelInfo - - return if (inner != null) { - when { - cancelInfo != null -> { - val cancelCode = safeValueOf(cancelInfo.cancelCode) - val byMe = cancelInfo.cancelledByUs - VerificationTxState.Cancelled(cancelCode, byMe) - } - inner.isDone -> VerificationTxState.Verified - inner.reciprocated -> VerificationTxState.Started - inner.hasBeenConfirmed -> VerificationTxState.WaitingOtherReciprocateConfirm - inner.otherSideScanned -> VerificationTxState.QrScannedByOther - else -> VerificationTxState.None - } - } else { - VerificationTxState.None - } - } - @Suppress("UNUSED_PARAMETER") - set(value) { - } + override fun state(): QRCodeVerificationState { + return QRCodeVerificationState.Reciprocated + } +// override var state: VerificationTxState +// get() { +// refreshData() +// val inner = inner +// val cancelInfo = inner?.cancelInfo +// +// return if (inner != null) { +// when { +// cancelInfo != null -> { +// val cancelCode = safeValueOf(cancelInfo.cancelCode) +// val byMe = cancelInfo.cancelledByUs +// VerificationTxState.Cancelled(cancelCode, byMe) +// } +// inner.isDone -> VerificationTxState.Verified +// inner.reciprocated -> VerificationTxState.Started +// inner.hasBeenConfirmed -> VerificationTxState.WaitingOtherReciprocateConfirm +// inner.otherSideScanned -> VerificationTxState.QrScannedByOther +// else -> VerificationTxState.None +// } +// } else { +// VerificationTxState.None +// } +// } +// @Suppress("UNUSED_PARAMETER") +// set(value) { +// } /** Get the unique id of this verification */ override val transactionId: String @@ -185,7 +190,7 @@ internal class QrCodeVerification @AssistedInject constructor( @Throws(CryptoStoreException::class) private suspend fun confirm() { val result = withContext(coroutineDispatchers.io) { - innerMachine.confirmVerification(request.otherUser(), request.flowId()) + inner.confirm() } ?: return dispatchTxUpdated() try { @@ -202,7 +207,7 @@ internal class QrCodeVerification @AssistedInject constructor( } private suspend fun cancelHelper(code: CancelCode) = withContext(NonCancellable) { - val request = innerMachine.cancelVerification(request.otherUser(), request.flowId(), code.value) ?: return@withContext + val request = inner.cancel(code.value) ?: return@withContext dispatchTxUpdated() tryOrNull("Fail to send cancel verification request") { sender.sendVerificationRequest(request, retryCount = Int.MAX_VALUE) @@ -211,13 +216,17 @@ internal class QrCodeVerification @AssistedInject constructor( /** Fetch fresh data from the Rust side for our verification flow */ private fun refreshData() { - when (val verification = innerMachine.getVerification(request.otherUser(), request.flowId())) { - is Verification.QrCodeV1 -> { - inner = verification.qrcode - } - else -> { - } - } + innerMachine.getVerification(request.otherUser(), request.flowId()) + ?.asQr()?.let { + inner = it + } +// when (val verification = innerMachine.getVerification(request.otherUser(), request.flowId())) { +// is Verification.QrCodeV1 -> { +// inner = verification.qrcode +// } +// else -> { +// } +// } return } @@ -225,7 +234,7 @@ internal class QrCodeVerification @AssistedInject constructor( override fun toString(): String { return "QrCodeVerification(" + "qrCodeText=$qrCodeText, " + - "state=$state, " + + "state=${state()}, " + "transactionId='$transactionId', " + "otherUserId='$otherUserId', " + "otherDeviceId=$otherDeviceId, " + diff --git a/matrix-sdk-android/src/test/java/org/matrix/android/sdk/internal/crypto/MoshiNumbersAsInt.kt b/matrix-sdk-android/src/test/java/org/matrix/android/sdk/internal/crypto/MoshiNumbersAsInt.kt new file mode 100644 index 0000000000..a326c133ec --- /dev/null +++ b/matrix-sdk-android/src/test/java/org/matrix/android/sdk/internal/crypto/MoshiNumbersAsInt.kt @@ -0,0 +1,54 @@ +/* + * Copyright 2022 The Matrix.org Foundation C.I.C. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.matrix.android.sdk.internal.crypto + +import org.amshove.kluent.shouldNotContain +import org.junit.Test +import org.matrix.android.sdk.api.session.events.model.Event +import org.matrix.android.sdk.api.session.sync.model.ToDeviceSyncResponse +import org.matrix.android.sdk.internal.di.MoshiProvider + +class MoshiNumbersAsInt { + + @Test + fun numberShouldNotPutAllAsFloat() { + val event = Event( + type = "m.room.encrypted", + eventId = null, + content = mapOf( + "algorithm" to "m.olm.v1.curve25519-aes-sha2", + "ciphertext" to mapOf( + "cfA3dINwtmMW0DbJmnT6NiGAbOSa299Hxs6KxHgbDBw" to mapOf( + "body" to "Awogc5...", + "type" to 1 + ), + ), + ), + prevContent = null, + originServerTs = null, + senderId = "@web:localhost:8481" + ) + + val toDeviceSyncResponse = ToDeviceSyncResponse(listOf(event)) + + val adapter = MoshiProvider.providesMoshi().adapter(ToDeviceSyncResponse::class.java) + + val jsonString = adapter.toJson(toDeviceSyncResponse) + + jsonString shouldNotContain "1.0" + } +} diff --git a/matrix-sdk-android/src/test/java/org/matrix/android/sdk/internal/crypto/UnRequestedKeysManagerTest.kt b/matrix-sdk-android/src/testKotlinCrypto/java/org/matrix/android/sdk/internal/crypto/UnRequestedKeysManagerTest.kt similarity index 100% rename from matrix-sdk-android/src/test/java/org/matrix/android/sdk/internal/crypto/UnRequestedKeysManagerTest.kt rename to matrix-sdk-android/src/testKotlinCrypto/java/org/matrix/android/sdk/internal/crypto/UnRequestedKeysManagerTest.kt