mirror of
https://github.com/SchildiChat/SchildiChat-android.git
synced 2024-11-22 09:25:49 +03:00
update rust-sdk bindings
This commit is contained in:
parent
2f3bbab4c4
commit
d9342707fd
26 changed files with 535 additions and 368 deletions
2
.gitignore
vendored
2
.gitignore
vendored
|
@ -31,3 +31,5 @@ Cargo.lock
|
||||||
matrix-sdk-android/src/main/jniLibs/
|
matrix-sdk-android/src/main/jniLibs/
|
||||||
|
|
||||||
matrix-sdk-android/libs/crypto-android-release.aar
|
matrix-sdk-android/libs/crypto-android-release.aar
|
||||||
|
|
||||||
|
matrix-sdk-android/libs/matrix-rust-sdk-crypto.aar
|
||||||
|
|
|
@ -169,8 +169,6 @@ dependencies {
|
||||||
implementation libs.jetbrains.coroutinesCore
|
implementation libs.jetbrains.coroutinesCore
|
||||||
implementation libs.jetbrains.coroutinesAndroid
|
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(name: 'crypto-android-release', ext: 'aar')
|
||||||
implementation 'net.java.dev.jna:jna:5.10.0@aar'
|
implementation 'net.java.dev.jna:jna:5.10.0@aar'
|
||||||
|
@ -236,7 +234,8 @@ dependencies {
|
||||||
|
|
||||||
implementation libs.google.phonenumber
|
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
|
testImplementation libs.tests.junit
|
||||||
// Note: version sticks to 1.9.2 due to https://github.com/mockk/mockk/issues/281
|
// Note: version sticks to 1.9.2 due to https://github.com/mockk/mockk/issues/281
|
||||||
|
|
|
@ -16,7 +16,7 @@
|
||||||
|
|
||||||
package org.matrix.android.sdk.api.session.crypto.model
|
package org.matrix.android.sdk.api.session.crypto.model
|
||||||
|
|
||||||
import uniffi.olm.KeysImportResult
|
import org.matrix.rustcomponents.sdk.crypto.KeysImportResult
|
||||||
|
|
||||||
data class ImportRoomKeysResult(
|
data class ImportRoomKeysResult(
|
||||||
val totalNumberOfKeys: Int,
|
val totalNumberOfKeys: Int,
|
||||||
|
|
|
@ -104,7 +104,7 @@ interface VerificationService {
|
||||||
scannedData: String
|
scannedData: String
|
||||||
): 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
|
// This starts the short SAS flow, the one that doesn't start with a request, deprecated
|
||||||
|
|
||||||
|
|
|
@ -16,82 +16,49 @@
|
||||||
|
|
||||||
package org.matrix.android.sdk.internal.crypto.verification
|
package org.matrix.android.sdk.internal.crypto.verification
|
||||||
|
|
||||||
import android.os.Handler
|
import kotlinx.coroutines.CoroutineScope
|
||||||
import android.os.Looper
|
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.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.api.session.crypto.verification.VerificationTransaction
|
||||||
import org.matrix.android.sdk.internal.session.SessionScope
|
import org.matrix.android.sdk.internal.session.SessionScope
|
||||||
import timber.log.Timber
|
import timber.log.Timber
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
@SessionScope
|
@SessionScope
|
||||||
internal class VerificationListenersHolder @Inject constructor() {
|
internal class VerificationListenersHolder @Inject constructor(
|
||||||
|
private val coroutineDispatchers: MatrixCoroutineDispatchers
|
||||||
|
) {
|
||||||
|
|
||||||
private val listeners = ArrayList<VerificationService.Listener>()
|
val scope = CoroutineScope(SupervisorJob() + coroutineDispatchers.dmVerif)
|
||||||
|
val eventFlow = MutableSharedFlow<VerificationEvent>(extraBufferCapacity = 20, onBufferOverflow = BufferOverflow.SUSPEND)
|
||||||
private val uiHandler = Handler(Looper.getMainLooper())
|
|
||||||
|
|
||||||
fun listeners(): List<VerificationService.Listener> = 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) }
|
|
||||||
}
|
|
||||||
|
|
||||||
fun dispatchTxAdded(tx: VerificationTransaction) {
|
fun dispatchTxAdded(tx: VerificationTransaction) {
|
||||||
uiHandler.post {
|
scope.launch {
|
||||||
this.listeners.forEach {
|
eventFlow.emit(VerificationEvent.TransactionAdded(tx))
|
||||||
try {
|
|
||||||
it.transactionCreated(tx)
|
|
||||||
} catch (e: Throwable) {
|
|
||||||
Timber.e(e, "## Error while notifying listeners")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun dispatchTxUpdated(tx: VerificationTransaction) {
|
fun dispatchTxUpdated(tx: VerificationTransaction) {
|
||||||
uiHandler.post {
|
scope.launch {
|
||||||
this.listeners.forEach {
|
eventFlow.emit(VerificationEvent.TransactionUpdated(tx))
|
||||||
try {
|
|
||||||
it.transactionUpdated(tx)
|
|
||||||
} catch (e: Throwable) {
|
|
||||||
Timber.e(e, "## Error while notifying listeners")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun dispatchRequestAdded(verificationRequest: PendingVerificationRequest) {
|
fun dispatchRequestAdded(verificationRequest: PendingVerificationRequest) {
|
||||||
Timber.v("## SAS dispatchRequestAdded txId:${verificationRequest.transactionId} $verificationRequest")
|
Timber.v("## SAS dispatchRequestAdded txId:${verificationRequest.transactionId} $verificationRequest")
|
||||||
uiHandler.post {
|
scope.launch {
|
||||||
this.listeners.forEach {
|
eventFlow.emit(VerificationEvent.RequestAdded(verificationRequest))
|
||||||
try {
|
|
||||||
it.verificationRequestCreated(verificationRequest)
|
|
||||||
} catch (e: Throwable) {
|
|
||||||
Timber.e(e, "## Error while notifying listeners")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun dispatchRequestUpdated(verificationRequest: PendingVerificationRequest) {
|
fun dispatchRequestUpdated(verificationRequest: PendingVerificationRequest) {
|
||||||
uiHandler.post {
|
scope.launch {
|
||||||
listeners.forEach {
|
eventFlow.emit(VerificationEvent.RequestUpdated(verificationRequest))
|
||||||
try {
|
|
||||||
it.verificationRequestUpdated(verificationRequest)
|
|
||||||
} catch (e: Throwable) {
|
|
||||||
Timber.e(e, "## Error while notifying listeners")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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.MessageType
|
||||||
import org.matrix.android.sdk.api.session.room.model.message.MessageVerificationRequestContent
|
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.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.CipherSuiteMoshiAdapter
|
||||||
import org.matrix.android.sdk.internal.network.parsing.ForceToBooleanJsonAdapter
|
import org.matrix.android.sdk.internal.network.parsing.ForceToBooleanJsonAdapter
|
||||||
import org.matrix.android.sdk.internal.network.parsing.RuntimeJsonAdapterFactory
|
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 {
|
internal object MoshiProvider {
|
||||||
|
|
||||||
private val moshi: Moshi = Moshi.Builder()
|
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(UriMoshiAdapter())
|
||||||
.add(ForceToBooleanJsonAdapter())
|
.add(ForceToBooleanJsonAdapter())
|
||||||
.add(CipherSuiteMoshiAdapter())
|
.add(CipherSuiteMoshiAdapter())
|
||||||
|
|
|
@ -279,8 +279,12 @@ internal abstract class SessionModule {
|
||||||
sessionParams: SessionParams,
|
sessionParams: SessionParams,
|
||||||
retrofitFactory: RetrofitFactory
|
retrofitFactory: RetrofitFactory
|
||||||
): Retrofit {
|
): Retrofit {
|
||||||
|
var uri = sessionParams.homeServerConnectionConfig.homeServerUriBase.toString()
|
||||||
|
if (uri == "http://localhost:8080") {
|
||||||
|
uri = "http://10.0.2.2:8080"
|
||||||
|
}
|
||||||
return retrofitFactory
|
return retrofitFactory
|
||||||
.create(okHttpClient, sessionParams.homeServerConnectionConfig.homeServerUriBase.toString())
|
.create(okHttpClient, uri)
|
||||||
}
|
}
|
||||||
|
|
||||||
@JvmStatic
|
@JvmStatic
|
||||||
|
|
|
@ -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.SasVerification
|
||||||
import org.matrix.android.sdk.internal.crypto.verification.VerificationRequest
|
import org.matrix.android.sdk.internal.crypto.verification.VerificationRequest
|
||||||
import org.matrix.android.sdk.internal.crypto.verification.prepareMethods
|
import org.matrix.android.sdk.internal.crypto.verification.prepareMethods
|
||||||
import uniffi.olm.CryptoStoreException
|
import org.matrix.rustcomponents.sdk.crypto.CryptoStoreException
|
||||||
import uniffi.olm.SignatureException
|
import org.matrix.rustcomponents.sdk.crypto.LocalTrust
|
||||||
import uniffi.olm.Device as InnerDevice
|
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
|
/** Class representing a device that supports E2EE in the Matrix world
|
||||||
*
|
*
|
||||||
|
@ -88,7 +89,7 @@ internal class Device @AssistedInject constructor(
|
||||||
requestSender.sendVerificationRequest(result.request)
|
requestSender.sendVerificationRequest(result.request)
|
||||||
verificationRequestFactory.create(result.verification)
|
verificationRequestFactory.create(result.verification)
|
||||||
} catch (failure: Throwable) {
|
} 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
|
null
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -115,7 +116,8 @@ internal class Device @AssistedInject constructor(
|
||||||
requestSender.sendVerificationRequest(result.request)
|
requestSender.sendVerificationRequest(result.request)
|
||||||
sasVerificationFactory.create(result.sas)
|
sasVerificationFactory.create(result.sas)
|
||||||
} catch (failure: Throwable) {
|
} 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
|
null
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -132,7 +134,7 @@ internal class Device @AssistedInject constructor(
|
||||||
@Throws(CryptoStoreException::class)
|
@Throws(CryptoStoreException::class)
|
||||||
suspend fun markAsTrusted() {
|
suspend fun markAsTrusted() {
|
||||||
withContext(coroutineDispatchers.io) {
|
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.
|
* This will not fetch out fresh data from the Rust side.
|
||||||
**/
|
**/
|
||||||
internal fun toCryptoDeviceInfo(): CryptoDeviceInfo {
|
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(
|
return CryptoDeviceInfo(
|
||||||
deviceId = innerDevice.deviceId,
|
deviceId = innerDevice.deviceId,
|
||||||
userId = innerDevice.userId,
|
userId = innerDevice.userId,
|
||||||
algorithms = innerDevice.algorithms,
|
algorithms = innerDevice.algorithms,
|
||||||
keys = keys,
|
keys = innerDevice.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
|
||||||
signatures = mapOf(),
|
signatures = mapOf(),
|
||||||
unsigned = UnsignedDeviceInfo(innerDevice.displayName),
|
unsigned = UnsignedDeviceInfo(innerDevice.displayName),
|
||||||
trustLevel = DeviceTrustLevel(crossSigningVerified = innerDevice.crossSigningTrusted, locallyVerified = innerDevice.locallyTrusted),
|
trustLevel = DeviceTrustLevel(
|
||||||
|
crossSigningVerified = innerDevice.crossSigningTrusted,
|
||||||
|
locallyVerified = innerDevice.locallyTrusted
|
||||||
|
),
|
||||||
isBlocked = innerDevice.isBlocked,
|
isBlocked = innerDevice.isBlocked,
|
||||||
// TODO
|
// TODO
|
||||||
firstTimeSeenLocalTs = null
|
firstTimeSeenLocalTs = null
|
||||||
|
|
|
@ -21,8 +21,8 @@ import org.matrix.android.sdk.api.MatrixCoroutineDispatchers
|
||||||
import org.matrix.android.sdk.api.extensions.tryOrNull
|
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.OutgoingRequestsProcessor
|
||||||
import org.matrix.android.sdk.internal.crypto.network.RequestSender
|
import org.matrix.android.sdk.internal.crypto.network.RequestSender
|
||||||
import uniffi.olm.Request
|
import org.matrix.rustcomponents.sdk.crypto.Request
|
||||||
import uniffi.olm.RequestType
|
import org.matrix.rustcomponents.sdk.crypto.RequestType
|
||||||
import java.util.UUID
|
import java.util.UUID
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
import javax.inject.Provider
|
import javax.inject.Provider
|
||||||
|
|
|
@ -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.model.rest.RestKeyInfo
|
||||||
import org.matrix.android.sdk.internal.crypto.network.RequestSender
|
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.VerificationRequest
|
||||||
import uniffi.olm.CryptoStoreException
|
import org.matrix.rustcomponents.sdk.crypto.CryptoStoreException
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
import javax.inject.Provider
|
import javax.inject.Provider
|
||||||
|
|
||||||
|
@ -44,7 +44,7 @@ internal class GetUserIdentityUseCase @Inject constructor(
|
||||||
val adapter = moshi.adapter(RestKeyInfo::class.java)
|
val adapter = moshi.adapter(RestKeyInfo::class.java)
|
||||||
|
|
||||||
return when (identity) {
|
return when (identity) {
|
||||||
is uniffi.olm.UserIdentity.Other -> {
|
is org.matrix.rustcomponents.sdk.crypto.UserIdentity.Other -> {
|
||||||
val verified = innerMachine.isIdentityVerified(userId)
|
val verified = innerMachine.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)
|
||||||
|
@ -62,7 +62,7 @@ internal class GetUserIdentityUseCase @Inject constructor(
|
||||||
verificationRequestFactory = verificationRequestFactory
|
verificationRequestFactory = verificationRequestFactory
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
is uniffi.olm.UserIdentity.Own -> {
|
is org.matrix.rustcomponents.sdk.crypto.UserIdentity.Own -> {
|
||||||
val verified = innerMachine.isIdentityVerified(userId)
|
val verified = innerMachine.isIdentityVerified(userId)
|
||||||
|
|
||||||
val masterKey = adapter.fromJson(identity.masterKey)!!.toCryptoModel().apply {
|
val masterKey = adapter.fromJson(identity.masterKey)!!.toCryptoModel().apply {
|
||||||
|
|
|
@ -19,6 +19,8 @@ package org.matrix.android.sdk.internal.crypto
|
||||||
import androidx.lifecycle.LiveData
|
import androidx.lifecycle.LiveData
|
||||||
import androidx.lifecycle.asLiveData
|
import androidx.lifecycle.asLiveData
|
||||||
import com.squareup.moshi.Moshi
|
import com.squareup.moshi.Moshi
|
||||||
|
import com.squareup.moshi.Types
|
||||||
|
import com.squareup.moshi.adapter
|
||||||
import kotlinx.coroutines.channels.SendChannel
|
import kotlinx.coroutines.channels.SendChannel
|
||||||
import kotlinx.coroutines.flow.Flow
|
import kotlinx.coroutines.flow.Flow
|
||||||
import kotlinx.coroutines.flow.channelFlow
|
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.VerificationsProvider
|
||||||
import org.matrix.android.sdk.internal.crypto.verification.qrcode.QrCodeVerification
|
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.DeviceId
|
||||||
|
import org.matrix.android.sdk.internal.di.MoshiProvider
|
||||||
import org.matrix.android.sdk.internal.di.SessionFilesDirectory
|
import org.matrix.android.sdk.internal.di.SessionFilesDirectory
|
||||||
import org.matrix.android.sdk.internal.di.UserId
|
import org.matrix.android.sdk.internal.di.UserId
|
||||||
import org.matrix.android.sdk.internal.network.parsing.CheckNumberType
|
import org.matrix.android.sdk.internal.network.parsing.CheckNumberType
|
||||||
import org.matrix.android.sdk.internal.session.SessionScope
|
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 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.io.File
|
||||||
import java.nio.charset.Charset
|
import java.nio.charset.Charset
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
import uniffi.olm.OlmMachine as InnerMachine
|
import org.matrix.rustcomponents.sdk.crypto.OlmMachine as InnerMachine
|
||||||
import uniffi.olm.ProgressListener as RustProgressListener
|
import org.matrix.rustcomponents.sdk.crypto.ProgressListener as RustProgressListener
|
||||||
|
|
||||||
class CryptoLogger : Logger {
|
class CryptoLogger : Logger {
|
||||||
override fun log(logLine: String) {
|
override fun log(logLine: String) {
|
||||||
|
@ -256,19 +260,33 @@ internal class OlmMachine @Inject constructor(
|
||||||
|
|
||||||
val devices =
|
val devices =
|
||||||
DeviceLists(deviceChanges?.changed.orEmpty(), deviceChanges?.left.orEmpty())
|
DeviceLists(deviceChanges?.changed.orEmpty(), deviceChanges?.left.orEmpty())
|
||||||
val adapter =
|
|
||||||
moshi.adapter(ToDeviceSyncResponse::class.java)
|
val adapter = MoshiProvider.providesMoshi().adapter(ToDeviceSyncResponse::class.java)
|
||||||
val events = adapter.toJson(toDevice ?: ToDeviceSyncResponse())!!
|
val events = adapter.toJson(toDevice ?: ToDeviceSyncResponse()).also {
|
||||||
|
Timber.w("## VALR events: $it")
|
||||||
|
}
|
||||||
|
|
||||||
// TODO once our sync response type parses the unused fallback key
|
// TODO once our sync response type parses the unused fallback key
|
||||||
// field pass in the list of unused fallback keys here
|
// 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<List<Event>>(
|
||||||
|
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.
|
// We may get cross signing keys over a to-device event, update our listeners.
|
||||||
updateLivePrivateKeys()
|
updateLivePrivateKeys()
|
||||||
|
|
||||||
return response
|
return ToDeviceSyncResponse(events = response)
|
||||||
}
|
}
|
||||||
|
|
||||||
suspend fun receiveUnencryptedVerificationEvent(roomId: String, event: Event) = withContext(coroutineDispatchers.io) {
|
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.
|
* @return The list of [Request.ToDevice] that need to be sent out.
|
||||||
*/
|
*/
|
||||||
@Throws(CryptoStoreException::class)
|
@Throws(CryptoStoreException::class)
|
||||||
suspend fun shareRoomKey(roomId: String, users: List<String>): List<Request> =
|
suspend fun shareRoomKey(roomId: String, users: List<String>, settings: EncryptionSettings): List<Request> =
|
||||||
withContext(coroutineDispatchers.io) { inner.shareRoomKey(roomId, users) }
|
withContext(coroutineDispatchers.io) {
|
||||||
|
inner.shareRoomKey(roomId, users, settings)
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Encrypt the given event with the given type and content for the given room.
|
* 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)
|
@Throws(CryptoStoreException::class)
|
||||||
suspend fun exportKeys(passphrase: String, rounds: Int): ByteArray =
|
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.
|
* Import room keys from the given serialized key export.
|
||||||
|
@ -472,7 +494,7 @@ internal class OlmMachine @Inject constructor(
|
||||||
|
|
||||||
val rustListener = CryptoProgressListener(listener)
|
val rustListener = CryptoProgressListener(listener)
|
||||||
|
|
||||||
val result = inner.importKeys(decodedKeys, passphrase, rustListener)
|
val result = inner.importRoomKeys(decodedKeys, passphrase, rustListener)
|
||||||
|
|
||||||
ImportRoomKeysResult.fromOlm(result)
|
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
|
totalImported += it.imported
|
||||||
accTotal += it.total
|
accTotal += it.total
|
||||||
details.putAll(it.keys)
|
details.putAll(it.keys)
|
||||||
|
@ -812,7 +834,7 @@ internal class OlmMachine @Inject constructor(
|
||||||
.build()
|
.build()
|
||||||
.adapter(MegolmBackupAuthData::class.java)
|
.adapter(MegolmBackupAuthData::class.java)
|
||||||
val serializedAuthData = adapter.toJson(authData)
|
val serializedAuthData = adapter.toJson(authData)
|
||||||
inner.verifyBackup(serializedAuthData)
|
inner.verifyBackup(serializedAuthData).trusted
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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.crypto.store.IMXCryptoStore
|
||||||
import org.matrix.android.sdk.internal.session.SessionScope
|
import org.matrix.android.sdk.internal.session.SessionScope
|
||||||
import org.matrix.android.sdk.internal.session.room.membership.LoadRoomMembersTask
|
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 timber.log.Timber
|
||||||
import uniffi.olm.Request
|
|
||||||
import uniffi.olm.RequestType
|
|
||||||
import java.util.concurrent.ConcurrentHashMap
|
import java.util.concurrent.ConcurrentHashMap
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
@ -83,9 +86,26 @@ internal class PrepareToEncryptUseCase @Inject constructor(
|
||||||
claimMissingKeys(roomMembers)
|
claimMissingKeys(roomMembers)
|
||||||
val keyShareLock = roomKeyShareLocks.getOrPut(roomId) { Mutex() }
|
val keyShareLock = roomKeyShareLocks.getOrPut(roomId) { Mutex() }
|
||||||
var sharedKey = false
|
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 {
|
keyShareLock.withLock {
|
||||||
coroutineScope {
|
coroutineScope {
|
||||||
olmMachine.shareRoomKey(roomId, roomMembers).map {
|
olmMachine.shareRoomKey(roomId, roomMembers, settings).map {
|
||||||
when (it) {
|
when (it) {
|
||||||
is Request.ToDevice -> {
|
is Request.ToDevice -> {
|
||||||
sharedKey = true
|
sharedKey = true
|
||||||
|
|
|
@ -17,6 +17,7 @@
|
||||||
package org.matrix.android.sdk.internal.crypto
|
package org.matrix.android.sdk.internal.crypto
|
||||||
|
|
||||||
import androidx.lifecycle.LiveData
|
import androidx.lifecycle.LiveData
|
||||||
|
import kotlinx.coroutines.runBlocking
|
||||||
import org.matrix.android.sdk.api.auth.UserInteractiveAuthInterceptor
|
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.CrossSigningService
|
||||||
import org.matrix.android.sdk.api.session.crypto.crosssigning.DeviceTrustResult
|
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.PrivateKeysInfo
|
||||||
import org.matrix.android.sdk.api.session.crypto.crosssigning.UserTrustResult
|
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.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.session.crypto.model.RoomEncryptionTrustLevel
|
||||||
import org.matrix.android.sdk.api.util.Optional
|
import org.matrix.android.sdk.api.util.Optional
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
@ -213,4 +215,22 @@ internal class RustCrossSigningService @Inject constructor(
|
||||||
// TODO
|
// TODO
|
||||||
// is this needed in rust?
|
// is this needed in rust?
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun checkSelfTrust(myCrossSigningInfo: MXCrossSigningInfo?, myDevices: List<CryptoDeviceInfo>?): 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()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -683,11 +683,11 @@ internal class RustCryptoService @Inject constructor(
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun enableShareKeyOnInvite(enable: Boolean) {
|
override fun enableShareKeyOnInvite(enable: Boolean) {
|
||||||
TODO("Not yet implemented")
|
TODO("Enable share key on invite not implemented")
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun isShareKeysOnInviteEnabled(): Boolean {
|
override fun isShareKeysOnInviteEnabled(): Boolean {
|
||||||
TODO("Not yet implemented")
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun setRoomUnBlockUnverifiedDevices(roomId: String) {
|
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 prepareToEncrypt(roomId: String) = prepareToEncrypt.invoke(roomId, ensureAllMembersAreLoaded = true)
|
||||||
|
|
||||||
override suspend fun sendSharedHistoryKeys(roomId: String, userId: String, sessionInfoSet: Set<SessionInfo>?) {
|
override suspend fun sendSharedHistoryKeys(roomId: String, userId: String, sessionInfoSet: Set<SessionInfo>?) {
|
||||||
TODO("Not yet implemented")
|
// TODO("Not yet implemented")
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ==========================================================================================
|
/* ==========================================================================================
|
||||||
|
|
|
@ -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.network.RequestSender
|
||||||
import org.matrix.android.sdk.internal.crypto.verification.VerificationRequest
|
import org.matrix.android.sdk.internal.crypto.verification.VerificationRequest
|
||||||
import org.matrix.android.sdk.internal.crypto.verification.prepareMethods
|
import org.matrix.android.sdk.internal.crypto.verification.prepareMethods
|
||||||
import uniffi.olm.CryptoStoreException
|
import org.matrix.rustcomponents.sdk.crypto.CryptoStoreException
|
||||||
import uniffi.olm.OlmMachine
|
import org.matrix.rustcomponents.sdk.crypto.OlmMachine
|
||||||
import uniffi.olm.SignatureException
|
import org.matrix.rustcomponents.sdk.crypto.SignatureException
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A sealed class representing user identities.
|
* A sealed class representing user identities.
|
||||||
|
|
|
@ -16,7 +16,7 @@
|
||||||
|
|
||||||
package org.matrix.android.sdk.api.session.crypto.keysbackup
|
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 {
|
class BackupRecoveryKey internal constructor(internal val inner: InnerBackupRecoveryKey) : IBackupRecoveryKey {
|
||||||
|
|
||||||
|
|
|
@ -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.session.SessionScope
|
||||||
import org.matrix.android.sdk.internal.util.JsonCanonicalizer
|
import org.matrix.android.sdk.internal.util.JsonCanonicalizer
|
||||||
import org.matrix.olm.OlmException
|
import org.matrix.olm.OlmException
|
||||||
|
import org.matrix.rustcomponents.sdk.crypto.Request
|
||||||
|
import org.matrix.rustcomponents.sdk.crypto.RequestType
|
||||||
import timber.log.Timber
|
import timber.log.Timber
|
||||||
import uniffi.olm.Request
|
|
||||||
import uniffi.olm.RequestType
|
|
||||||
import java.security.InvalidParameterException
|
import java.security.InvalidParameterException
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
import kotlin.random.Random
|
import kotlin.random.Random
|
||||||
|
|
|
@ -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.CryptoSessionInfoProvider
|
||||||
import org.matrix.android.sdk.internal.crypto.OlmMachine
|
import org.matrix.android.sdk.internal.crypto.OlmMachine
|
||||||
import org.matrix.android.sdk.internal.session.SessionScope
|
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 timber.log.Timber
|
||||||
import uniffi.olm.Request
|
|
||||||
import uniffi.olm.RequestType
|
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
private val loggerTag = LoggerTag("OutgoingRequestsProcessor", LoggerTag.CRYPTO)
|
private val loggerTag = LoggerTag("OutgoingRequestsProcessor", LoggerTag.CRYPTO)
|
||||||
|
|
|
@ -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.DEFAULT_REQUEST_RETRY_COUNT
|
||||||
import org.matrix.android.sdk.internal.network.parsing.CheckNumberType
|
import org.matrix.android.sdk.internal.network.parsing.CheckNumberType
|
||||||
import org.matrix.android.sdk.internal.session.room.send.SendResponse
|
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 timber.log.Timber
|
||||||
import uniffi.olm.OutgoingVerificationRequest
|
|
||||||
import uniffi.olm.Request
|
|
||||||
import uniffi.olm.SignatureUploadRequest
|
|
||||||
import uniffi.olm.UploadSigningKeysRequest
|
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
internal class RequestSender @Inject constructor(
|
internal class RequestSender @Inject constructor(
|
||||||
|
|
|
@ -74,6 +74,8 @@ internal class RustVerificationService @Inject constructor(
|
||||||
private val olmMachine: OlmMachine,
|
private val olmMachine: OlmMachine,
|
||||||
private val verificationListenersHolder: VerificationListenersHolder) : VerificationService {
|
private val verificationListenersHolder: VerificationListenersHolder) : VerificationService {
|
||||||
|
|
||||||
|
override fun requestEventFlow() = verificationListenersHolder.eventFlow
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* All verification related events should be forwarded through this method to
|
* 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<MessageContent>() ?: return
|
val messageContent = event.getClearContent()?.toModel<MessageContent>() ?: return
|
||||||
if (messageContent.msgType == MessageType.MSGTYPE_VERIFICATION_REQUEST) {
|
if (messageContent.msgType == MessageType.MSGTYPE_VERIFICATION_REQUEST) {
|
||||||
onRequest(event, fromRoomMessage = true)
|
onRequest(event, fromRoomMessage = true)
|
||||||
|
@ -111,7 +113,7 @@ internal class RustVerificationService @Inject constructor(
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Dispatch updates after a verification event has been received */
|
/** 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 sender = event.senderId ?: return
|
||||||
val flowId = getFlowId(event) ?: 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 */
|
/** 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) {
|
val flowId = if (fromRoomMessage) {
|
||||||
event.eventId
|
event.eventId
|
||||||
} else {
|
} else {
|
||||||
|
@ -162,26 +164,26 @@ internal class RustVerificationService @Inject constructor(
|
||||||
verificationListenersHolder.dispatchRequestAdded(request)
|
verificationListenersHolder.dispatchRequestAdded(request)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun addListener(listener: VerificationService.Listener) {
|
// override fun addListener(listener: VerificationService.Listener) {
|
||||||
verificationListenersHolder.addListener(listener)
|
// verificationListenersHolder.addListener(listener)
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
override fun removeListener(listener: VerificationService.Listener) {
|
// override fun removeListener(listener: VerificationService.Listener) {
|
||||||
verificationListenersHolder.removeListener(listener)
|
// verificationListenersHolder.removeListener(listener)
|
||||||
}
|
// }
|
||||||
|
|
||||||
override suspend fun markedLocallyAsManuallyVerified(userId: String, deviceID: String) {
|
override suspend fun markedLocallyAsManuallyVerified(userId: String, deviceID: String) {
|
||||||
olmMachine.getDevice(userId, deviceID)?.markAsTrusted()
|
olmMachine.getDevice(userId, deviceID)?.markAsTrusted()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun getExistingTransaction(
|
override suspend fun getExistingTransaction(
|
||||||
otherUserId: String,
|
otherUserId: String,
|
||||||
tid: String,
|
tid: String,
|
||||||
): VerificationTransaction? {
|
): VerificationTransaction? {
|
||||||
return olmMachine.getVerification(otherUserId, tid)
|
return olmMachine.getVerification(otherUserId, tid)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun getExistingVerificationRequests(
|
override suspend fun getExistingVerificationRequests(
|
||||||
otherUserId: String
|
otherUserId: String
|
||||||
): List<PendingVerificationRequest> {
|
): List<PendingVerificationRequest> {
|
||||||
return olmMachine.getVerificationRequests(otherUserId).map {
|
return olmMachine.getVerificationRequests(otherUserId).map {
|
||||||
|
@ -189,7 +191,7 @@ internal class RustVerificationService @Inject constructor(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun getExistingVerificationRequest(
|
override suspend fun getExistingVerificationRequest(
|
||||||
otherUserId: String,
|
otherUserId: String,
|
||||||
tid: String?
|
tid: String?
|
||||||
): PendingVerificationRequest? {
|
): PendingVerificationRequest? {
|
||||||
|
@ -200,9 +202,9 @@ internal class RustVerificationService @Inject constructor(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun getExistingVerificationRequestInRoom(
|
override suspend fun getExistingVerificationRequestInRoom(
|
||||||
roomId: String,
|
roomId: String,
|
||||||
tid: String?
|
tid: String
|
||||||
): PendingVerificationRequest? {
|
): PendingVerificationRequest? {
|
||||||
// This is only used in `RoomDetailViewModel` to resume the verification.
|
// 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<VerificationMethod>,
|
override suspend fun requestDeviceVerification(methods: List<VerificationMethod>,
|
||||||
otherUserId: String,
|
otherUserId: String,
|
||||||
otherDeviceId: String?): PendingVerificationRequest? {
|
otherDeviceId: String?): PendingVerificationRequest {
|
||||||
// how do we send request to several devices in rust?
|
// how do we send request to several devices in rust?
|
||||||
if (otherDeviceId == null) return null
|
|
||||||
olmMachine.ensureUsersKeys(listOf(otherUserId))
|
olmMachine.ensureUsersKeys(listOf(otherUserId))
|
||||||
|
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)
|
val otherDevice = olmMachine.getDevice(otherUserId, otherDeviceId)
|
||||||
val verificationRequest = otherDevice?.requestVerification(methods)
|
otherDevice?.requestVerification(methods) ?: throw IllegalArgumentException("Unknown device $otherDeviceId")
|
||||||
return verificationRequest?.toPendingVerificationRequest()
|
}
|
||||||
|
return request.toPendingVerificationRequest()
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun readyPendingVerification(
|
override suspend fun readyPendingVerification(
|
||||||
|
@ -269,29 +281,15 @@ internal class RustVerificationService @Inject constructor(
|
||||||
return if (request != null) {
|
return if (request != null) {
|
||||||
request.acceptWithMethods(methods)
|
request.acceptWithMethods(methods)
|
||||||
|
|
||||||
if (request.isReady()) {
|
request.isReady()
|
||||||
val qrcode = request.startQrVerification()
|
|
||||||
|
|
||||||
if (qrcode != null) {
|
|
||||||
verificationListenersHolder.dispatchTxAdded(qrcode)
|
|
||||||
}
|
|
||||||
|
|
||||||
true
|
|
||||||
} else {
|
|
||||||
false
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun beginKeyVerification(
|
override suspend fun startKeyVerification(method: VerificationMethod, otherUserId: String, requestId: String): String? {
|
||||||
method: VerificationMethod,
|
|
||||||
otherUserId: String,
|
|
||||||
transactionId: String
|
|
||||||
): String? {
|
|
||||||
return if (method == VerificationMethod.SAS) {
|
return if (method == VerificationMethod.SAS) {
|
||||||
val request = olmMachine.getVerificationRequest(otherUserId, transactionId)
|
val request = olmMachine.getVerificationRequest(otherUserId, requestId)
|
||||||
|
|
||||||
val sas = request?.startSasVerification()
|
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
|
// not available in rust
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -331,7 +335,6 @@ internal class RustVerificationService @Inject constructor(
|
||||||
// }
|
// }
|
||||||
|
|
||||||
override suspend fun cancelVerificationRequest(request: PendingVerificationRequest) {
|
override suspend fun cancelVerificationRequest(request: PendingVerificationRequest) {
|
||||||
request.transactionId ?: return
|
|
||||||
cancelVerificationRequest(request.otherUserId, request.transactionId)
|
cancelVerificationRequest(request.otherUserId, request.transactionId)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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.extensions.tryOrNull
|
||||||
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.SasTransactionState
|
||||||
import org.matrix.android.sdk.api.session.crypto.verification.SasVerificationTransaction
|
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.api.session.crypto.verification.safeValueOf
|
||||||
import org.matrix.android.sdk.internal.crypto.OlmMachine
|
import org.matrix.android.sdk.internal.crypto.OlmMachine
|
||||||
import org.matrix.android.sdk.internal.crypto.network.RequestSender
|
import org.matrix.android.sdk.internal.crypto.network.RequestSender
|
||||||
import uniffi.olm.CryptoStoreException
|
import org.matrix.rustcomponents.sdk.crypto.CryptoStoreException
|
||||||
import uniffi.olm.Sas
|
import org.matrix.rustcomponents.sdk.crypto.Sas
|
||||||
import uniffi.olm.Verification
|
import org.matrix.rustcomponents.sdk.crypto.SasListener
|
||||||
|
import org.matrix.rustcomponents.sdk.crypto.SasState
|
||||||
|
|
||||||
/** Class representing a short auth string verification flow */
|
/** Class representing a short auth string verification flow */
|
||||||
internal class SasVerification @AssistedInject constructor(
|
internal class SasVerification @AssistedInject constructor(
|
||||||
|
@ -40,60 +42,67 @@ internal class SasVerification @AssistedInject constructor(
|
||||||
private val olmMachine: OlmMachine,
|
private val olmMachine: OlmMachine,
|
||||||
private val sender: RequestSender,
|
private val sender: RequestSender,
|
||||||
private val coroutineDispatchers: MatrixCoroutineDispatchers,
|
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
|
@AssistedFactory
|
||||||
interface Factory {
|
interface Factory {
|
||||||
fun create(inner: Sas): SasVerification
|
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 */
|
/** 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 */
|
/** Get the device id of the other user's device participating in this verification flow */
|
||||||
override var otherDeviceId: String?
|
override val otherDeviceId: String
|
||||||
get() = inner.otherDeviceId
|
get() = inner.otherDeviceId()
|
||||||
@Suppress("UNUSED_PARAMETER")
|
|
||||||
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() = !inner.weStarted
|
get() = !inner.weStarted()
|
||||||
|
|
||||||
override var state: VerificationTxState
|
private var decimals: List<Int>? = null
|
||||||
get() {
|
private var emojis: List<Int>? = null
|
||||||
refreshData()
|
|
||||||
val cancelInfo = inner.cancelInfo
|
|
||||||
|
|
||||||
return when {
|
override fun state(): SasTransactionState {
|
||||||
cancelInfo != null -> {
|
return when (val state = innerState) {
|
||||||
val cancelCode = safeValueOf(cancelInfo.cancelCode)
|
SasState.Started -> SasTransactionState.SasStarted
|
||||||
VerificationTxState.Cancelled(cancelCode, cancelInfo.cancelledByUs)
|
SasState.Accepted -> SasTransactionState.SasAccepted
|
||||||
|
is SasState.KeysExchanged -> {
|
||||||
|
this.decimals = state.decimals
|
||||||
|
this.emojis = state.emojis
|
||||||
|
SasTransactionState.SasShortCodeReady
|
||||||
}
|
}
|
||||||
inner.isDone -> VerificationTxState.Verified
|
SasState.Confirmed -> SasTransactionState.SasMacSent
|
||||||
inner.haveWeConfirmed -> VerificationTxState.SasMacSent
|
SasState.Done -> SasTransactionState.Done(false)
|
||||||
inner.canBePresented -> VerificationTxState.SasShortCodeReady
|
is SasState.Cancelled -> SasTransactionState.Cancelled(safeValueOf(state.cancelInfo.cancelCode), state.cancelInfo.cancelledByUs)
|
||||||
inner.hasBeenAccepted -> VerificationTxState.SasAccepted
|
|
||||||
else -> VerificationTxState.SasStarted
|
|
||||||
}
|
}
|
||||||
}
|
// refreshData()
|
||||||
@Suppress("UNUSED_PARAMETER")
|
// val cancelInfo = inner.cancelInfo
|
||||||
set(v) {
|
//
|
||||||
|
// 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 */
|
/** Get the unique id of this verification */
|
||||||
override val transactionId: String
|
override val transactionId: String
|
||||||
get() = inner.flowId
|
get() = inner.flowId()
|
||||||
|
|
||||||
/** Cancel the verification flow
|
/** Cancel the verification flow
|
||||||
*
|
*
|
||||||
|
@ -136,13 +145,15 @@ internal class SasVerification @AssistedInject constructor(
|
||||||
cancelHelper(CancelCode.MismatchedSas)
|
cancelHelper(CancelCode.MismatchedSas)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override val method: VerificationMethod
|
||||||
|
get() = VerificationMethod.QR_CODE_SCAN
|
||||||
|
|
||||||
/** Is this verification happening over to-device messages */
|
/** 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 */
|
/** Does the verification flow support showing emojis as the short auth string */
|
||||||
override fun supportsEmoji(): Boolean {
|
override fun supportsEmoji(): Boolean {
|
||||||
refreshData()
|
return 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
|
||||||
|
@ -177,8 +188,6 @@ internal class SasVerification @AssistedInject constructor(
|
||||||
* in a presentable state.
|
* in a presentable state.
|
||||||
*/
|
*/
|
||||||
override fun getDecimalCodeRepresentation(): String {
|
override fun getDecimalCodeRepresentation(): String {
|
||||||
val decimals = innerMachine.getDecimals(inner.otherUserId, inner.flowId)
|
|
||||||
|
|
||||||
return decimals?.joinToString(" ") ?: ""
|
return decimals?.joinToString(" ") ?: ""
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -189,14 +198,13 @@ internal class SasVerification @AssistedInject constructor(
|
||||||
* state.
|
* state.
|
||||||
*/
|
*/
|
||||||
override fun getEmojiCodeRepresentation(): List<EmojiRepresentation> {
|
override fun getEmojiCodeRepresentation(): List<EmojiRepresentation> {
|
||||||
val emojiIndex = innerMachine.getEmojiIndex(inner.otherUserId, inner.flowId)
|
return emojis?.map { getEmojiForCode(it) } ?: listOf()
|
||||||
|
|
||||||
return emojiIndex?.map { getEmojiForCode(it) } ?: listOf()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
internal suspend fun accept() {
|
internal suspend fun accept() {
|
||||||
val request = innerMachine.acceptSasVerification(inner.otherUserId, inner.flowId) ?: return
|
val request = inner.accept() ?: return Unit.also {
|
||||||
dispatchTxUpdated()
|
// TODO should throw here?
|
||||||
|
}
|
||||||
try {
|
try {
|
||||||
sender.sendVerificationRequest(request)
|
sender.sendVerificationRequest(request)
|
||||||
} catch (failure: Throwable) {
|
} catch (failure: Throwable) {
|
||||||
|
@ -207,10 +215,8 @@ internal class SasVerification @AssistedInject constructor(
|
||||||
@Throws(CryptoStoreException::class)
|
@Throws(CryptoStoreException::class)
|
||||||
private suspend fun confirm() {
|
private suspend fun confirm() {
|
||||||
val result = withContext(coroutineDispatchers.io) {
|
val result = withContext(coroutineDispatchers.io) {
|
||||||
innerMachine.confirmVerification(inner.otherUserId, inner.flowId)
|
inner.confirm()
|
||||||
} ?: return
|
} ?: return
|
||||||
|
|
||||||
dispatchTxUpdated()
|
|
||||||
try {
|
try {
|
||||||
for (verificationRequest in result.requests) {
|
for (verificationRequest in result.requests) {
|
||||||
sender.sendVerificationRequest(verificationRequest)
|
sender.sendVerificationRequest(verificationRequest)
|
||||||
|
@ -225,24 +231,28 @@ internal class SasVerification @AssistedInject constructor(
|
||||||
}
|
}
|
||||||
|
|
||||||
private suspend fun cancelHelper(code: CancelCode) = withContext(NonCancellable) {
|
private suspend fun cancelHelper(code: CancelCode) = withContext(NonCancellable) {
|
||||||
val request = innerMachine.cancelVerification(inner.otherUserId, inner.flowId, code.value) ?: return@withContext
|
val request = inner.cancel(code.value) ?: return@withContext
|
||||||
dispatchTxUpdated()
|
|
||||||
tryOrNull("Fail to send cancel request") {
|
tryOrNull("Fail to send cancel request") {
|
||||||
sender.sendVerificationRequest(request, retryCount = Int.MAX_VALUE)
|
sender.sendVerificationRequest(request, retryCount = Int.MAX_VALUE)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** 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 = innerMachine.getVerification(inner.otherUserId, inner.flowId)) {
|
// when (val verification = innerMachine.getVerification(inner.otherUserId, inner.flowId)) {
|
||||||
is Verification.SasV1 -> {
|
// is Verification.SasV1 -> {
|
||||||
inner = verification.sas
|
// inner = verification.sas
|
||||||
}
|
// }
|
||||||
else -> {
|
// else -> {
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
|
// return
|
||||||
|
// }
|
||||||
|
|
||||||
return
|
override fun onChange(state: SasState) {
|
||||||
|
innerState = state
|
||||||
|
verificationListenersHolder.dispatchTxUpdated(this)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun toString(): String {
|
override fun toString(): String {
|
||||||
|
@ -250,7 +260,7 @@ internal class SasVerification @AssistedInject constructor(
|
||||||
"otherUserId='$otherUserId', " +
|
"otherUserId='$otherUserId', " +
|
||||||
"otherDeviceId=$otherDeviceId, " +
|
"otherDeviceId=$otherDeviceId, " +
|
||||||
"isIncoming=$isIncoming, " +
|
"isIncoming=$isIncoming, " +
|
||||||
"state=$state, " +
|
"state=${state()}, " +
|
||||||
"transactionId='$transactionId')"
|
"transactionId='$transactionId')"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,18 +24,21 @@ import kotlinx.coroutines.withContext
|
||||||
import org.matrix.android.sdk.api.MatrixCoroutineDispatchers
|
import org.matrix.android.sdk.api.MatrixCoroutineDispatchers
|
||||||
import org.matrix.android.sdk.api.extensions.tryOrNull
|
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.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.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.VerificationMethod
|
||||||
import org.matrix.android.sdk.api.session.crypto.verification.safeValueOf
|
import org.matrix.android.sdk.api.session.crypto.verification.safeValueOf
|
||||||
import org.matrix.android.sdk.api.util.toBase64NoPadding
|
import org.matrix.android.sdk.api.util.toBase64NoPadding
|
||||||
import org.matrix.android.sdk.internal.crypto.OlmMachine
|
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_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.network.RequestSender
|
||||||
import org.matrix.android.sdk.internal.crypto.verification.qrcode.QrCodeVerification
|
import org.matrix.android.sdk.internal.crypto.verification.qrcode.QrCodeVerification
|
||||||
import org.matrix.android.sdk.internal.util.time.Clock
|
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
|
/** A verification request object
|
||||||
*
|
*
|
||||||
|
@ -74,12 +77,12 @@ internal class VerificationRequest @AssistedInject constructor(
|
||||||
* event that initiated the flow.
|
* event that initiated the flow.
|
||||||
*/
|
*/
|
||||||
internal fun flowId(): String {
|
internal fun flowId(): String {
|
||||||
return innerVerificationRequest.flowId
|
return innerVerificationRequest.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 innerVerificationRequest.otherUserId
|
return innerVerificationRequest.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
|
||||||
|
@ -89,12 +92,12 @@ internal class VerificationRequest @AssistedInject constructor(
|
||||||
* */
|
* */
|
||||||
internal fun otherDeviceId(): String? {
|
internal fun otherDeviceId(): String? {
|
||||||
refreshData()
|
refreshData()
|
||||||
return innerVerificationRequest.otherDeviceId
|
return innerVerificationRequest.otherDeviceId()
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Did we initiate this verification flow */
|
/** Did we initiate this verification flow */
|
||||||
internal fun weStarted(): Boolean {
|
internal fun weStarted(): Boolean {
|
||||||
return innerVerificationRequest.weStarted
|
return innerVerificationRequest.weStarted()
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Get the id of the room where this verification is happening
|
/** 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.
|
* Will be null if the verification is not happening inside a room.
|
||||||
*/
|
*/
|
||||||
internal fun roomId(): String? {
|
internal fun roomId(): String? {
|
||||||
return innerVerificationRequest.roomId
|
return innerVerificationRequest.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
|
||||||
|
@ -113,13 +116,13 @@ internal class VerificationRequest @AssistedInject constructor(
|
||||||
*/
|
*/
|
||||||
internal fun isReady(): Boolean {
|
internal fun isReady(): Boolean {
|
||||||
refreshData()
|
refreshData()
|
||||||
return innerVerificationRequest.isReady
|
return innerVerificationRequest.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 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
|
/** Accept the verification request advertising the given methods as supported
|
||||||
|
@ -138,20 +141,28 @@ internal class VerificationRequest @AssistedInject constructor(
|
||||||
suspend fun acceptWithMethods(methods: List<VerificationMethod>) {
|
suspend fun acceptWithMethods(methods: List<VerificationMethod>) {
|
||||||
val stringMethods = prepareMethods(methods)
|
val stringMethods = prepareMethods(methods)
|
||||||
|
|
||||||
val request = innerOlmMachine.acceptVerificationRequest(
|
val request = innerVerificationRequest.accept(stringMethods)
|
||||||
innerVerificationRequest.otherUserId,
|
?: return // should throw here?
|
||||||
innerVerificationRequest.flowId,
|
// val request = innerOlmMachine.acceptVerificationRequest(
|
||||||
stringMethods
|
// innerVerificationRequest.otherUserId(),
|
||||||
) ?: return
|
// innerVerificationRequest.flowId,
|
||||||
|
// stringMethods
|
||||||
|
// ) ?: return
|
||||||
|
|
||||||
try {
|
try {
|
||||||
dispatchRequestUpdated()
|
dispatchRequestUpdated()
|
||||||
requestSender.sendVerificationRequest(request)
|
requestSender.sendVerificationRequest(request)
|
||||||
|
|
||||||
|
if (innerVerificationRequest.isReady()) {
|
||||||
|
activeQRCode = innerVerificationRequest.startQrVerification()
|
||||||
|
}
|
||||||
} catch (failure: Throwable) {
|
} catch (failure: Throwable) {
|
||||||
cancel(CancelCode.UserError)
|
cancel(CancelCode.UserError)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var activeQRCode: QrCode? = null
|
||||||
|
|
||||||
/** Transition from a ready verification request into emoji verification
|
/** Transition from a ready verification request into emoji verification
|
||||||
*
|
*
|
||||||
* This method will move the verification forward 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? {
|
internal suspend fun startSasVerification(): SasVerification? {
|
||||||
return withContext(coroutineDispatchers.io) {
|
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 {
|
try {
|
||||||
requestSender.sendVerificationRequest(result.request)
|
requestSender.sendVerificationRequest(result.request)
|
||||||
sasVerificationFactory.create(result.sas)
|
sasVerificationFactory.create(result.sas)
|
||||||
|
@ -195,7 +209,8 @@ internal class VerificationRequest @AssistedInject constructor(
|
||||||
// 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 = innerOlmMachine.scanQrCode(otherUser(), flowId(), encodedData) ?: return null
|
// val result = innerOlmMachine.scanQrCode(otherUser(), flowId(), encodedData) ?: return null
|
||||||
|
val result = innerVerificationRequest.scanQrCode(encodedData) ?: return null
|
||||||
try {
|
try {
|
||||||
requestSender.sendVerificationRequest(result.request)
|
requestSender.sendVerificationRequest(result.request)
|
||||||
} catch (failure: Throwable) {
|
} 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.
|
* 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 = innerOlmMachine.startQrVerification(innerVerificationRequest.otherUserId, innerVerificationRequest.flowId)
|
activeQRCode = innerVerificationRequest.startQrVerification()
|
||||||
return if (qrcode != null) {
|
// val qrcode = innerOlmMachine.startQrVerification(innerVerificationRequest.otherUserId, innerVerificationRequest.flowId)
|
||||||
qrCodeVerificationFactory.create(this, qrcode)
|
return if (activeQRCode != null) {
|
||||||
|
TODO("Is this reciprocate or just doing nothing?")
|
||||||
|
// activeQRCode.
|
||||||
|
// qrCodeVerificationFactory.create(this, qrcode)
|
||||||
} else {
|
} else {
|
||||||
null
|
null
|
||||||
}
|
}
|
||||||
|
@ -242,11 +260,13 @@ internal class VerificationRequest @AssistedInject constructor(
|
||||||
* 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(cancelCode: CancelCode = CancelCode.User) = withContext(NonCancellable) {
|
internal suspend fun cancel(cancelCode: CancelCode = CancelCode.User) = withContext(NonCancellable) {
|
||||||
val request = innerOlmMachine.cancelVerification(
|
// TODO damir how to add the code?
|
||||||
innerVerificationRequest.otherUserId,
|
val request = innerVerificationRequest.cancel() ?: return@withContext
|
||||||
innerVerificationRequest.flowId,
|
// val request = innerOlmMachine.cancelVerification(
|
||||||
cancelCode.value
|
// innerVerificationRequest.otherUserId,
|
||||||
) ?: return@withContext
|
// innerVerificationRequest.flowId,
|
||||||
|
// cancelCode.value
|
||||||
|
// ) ?: return@withContext
|
||||||
dispatchRequestUpdated()
|
dispatchRequestUpdated()
|
||||||
tryOrNull("Fail to send cancel request") {
|
tryOrNull("Fail to send cancel request") {
|
||||||
requestSender.sendVerificationRequest(request, retryCount = Int.MAX_VALUE)
|
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 */
|
/** Fetch fresh data from the Rust side for our verification flow */
|
||||||
private fun refreshData() {
|
private fun refreshData() {
|
||||||
val request = innerOlmMachine.getVerificationRequest(innerVerificationRequest.otherUserId, innerVerificationRequest.flowId)
|
val request = innerOlmMachine.getVerificationRequest(innerVerificationRequest.otherUserId(), innerVerificationRequest.flowId())
|
||||||
|
|
||||||
if (request != null) {
|
if (request != null) {
|
||||||
innerVerificationRequest = request
|
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
|
/** Convert the VerificationRequest into a PendingVerificationRequest
|
||||||
*
|
*
|
||||||
* The public interface of the VerificationService dispatches the data class
|
* The public interface of the VerificationService dispatches the data class
|
||||||
|
@ -273,7 +304,7 @@ internal class VerificationRequest @AssistedInject constructor(
|
||||||
*/
|
*/
|
||||||
internal fun toPendingVerificationRequest(): PendingVerificationRequest {
|
internal fun toPendingVerificationRequest(): PendingVerificationRequest {
|
||||||
refreshData()
|
refreshData()
|
||||||
val cancelInfo = innerVerificationRequest.cancelInfo
|
val cancelInfo = innerVerificationRequest.cancelInfo()
|
||||||
val cancelCode =
|
val cancelCode =
|
||||||
if (cancelInfo != null) {
|
if (cancelInfo != null) {
|
||||||
safeValueOf(cancelInfo.cancelCode)
|
safeValueOf(cancelInfo.cancelCode)
|
||||||
|
@ -281,72 +312,79 @@ internal class VerificationRequest @AssistedInject constructor(
|
||||||
null
|
null
|
||||||
}
|
}
|
||||||
|
|
||||||
val ourMethods = innerVerificationRequest.ourMethods
|
val ourMethods = innerVerificationRequest.ourSupportedMethods()
|
||||||
val theirMethods = innerVerificationRequest.theirMethods
|
val theirMethods = innerVerificationRequest.theirSupportedMethods()
|
||||||
val otherDeviceId = innerVerificationRequest.otherDeviceId
|
val otherDeviceId = innerVerificationRequest.otherDeviceId()
|
||||||
|
|
||||||
var requestInfo: ValidVerificationInfoRequest? = null
|
// var requestInfo: ValidVerificationInfoRequest? = null
|
||||||
var readyInfo: ValidVerificationInfoReady? = 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) {
|
innerVerificationRequest.startQrVerification()
|
||||||
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(),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
return PendingVerificationRequest(
|
return PendingVerificationRequest(
|
||||||
// Creation time
|
// Creation time
|
||||||
ageLocalTs = clock.epochMillis(),
|
ageLocalTs = clock.epochMillis(),
|
||||||
|
state = state(),
|
||||||
// Who initiated the request
|
// Who initiated the request
|
||||||
isIncoming = !innerVerificationRequest.weStarted,
|
isIncoming = !innerVerificationRequest.weStarted(),
|
||||||
// Local echo id, what to do here?
|
// Local echo id, what to do here?
|
||||||
localId = innerVerificationRequest.flowId,
|
otherDeviceId = innerVerificationRequest.otherDeviceId(),
|
||||||
// other user
|
// other user
|
||||||
otherUserId = innerVerificationRequest.otherUserId,
|
otherUserId = innerVerificationRequest.otherUserId(),
|
||||||
// room id
|
// room id
|
||||||
roomId = innerVerificationRequest.roomId,
|
roomId = innerVerificationRequest.roomId(),
|
||||||
// transaction id
|
// transaction id
|
||||||
transactionId = innerVerificationRequest.flowId,
|
transactionId = innerVerificationRequest.flowId(),
|
||||||
// val requestInfo: ValidVerificationInfoRequest? = null,
|
|
||||||
requestInfo = requestInfo,
|
|
||||||
// val readyInfo: ValidVerificationInfoReady? = null,
|
|
||||||
readyInfo = readyInfo,
|
|
||||||
// cancel code if there is one
|
// cancel code if there is one
|
||||||
cancelConclusion = cancelCode,
|
cancelConclusion = cancelCode,
|
||||||
// are we done/successful
|
isFinished = innerVerificationRequest.isDone() || innerVerificationRequest.isCancelled(),
|
||||||
isSuccessful = innerVerificationRequest.isDone,
|
|
||||||
// did another device answer the request
|
// did another device answer the request
|
||||||
handledByOtherSession = innerVerificationRequest.isPassive,
|
handledByOtherSession = innerVerificationRequest.isPassive(),
|
||||||
// devices that should receive the events we send out
|
// 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<String>?.canSas() = orEmpty().contains(VERIFICATION_METHOD_SAS)
|
||||||
|
private fun List<String>?.canShowQR() = orEmpty().contains(VERIFICATION_METHOD_RECIPROCATE) && orEmpty().contains(VERIFICATION_METHOD_QR_CODE_SHOW)
|
||||||
|
private fun List<String>?.canScanQR() = orEmpty().contains(VERIFICATION_METHOD_RECIPROCATE) && orEmpty().contains(VERIFICATION_METHOD_QR_CODE_SCAN)
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,7 +21,7 @@ import org.matrix.android.sdk.internal.crypto.OlmMachine
|
||||||
import org.matrix.android.sdk.internal.crypto.verification.qrcode.QrCodeVerification
|
import org.matrix.android.sdk.internal.crypto.verification.qrcode.QrCodeVerification
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
import javax.inject.Provider
|
import javax.inject.Provider
|
||||||
import uniffi.olm.OlmMachine as InnerOlmMachine
|
import org.matrix.rustcomponents.sdk.crypto.OlmMachine as InnerOlmMachine
|
||||||
|
|
||||||
internal class VerificationsProvider @Inject constructor(
|
internal class VerificationsProvider @Inject constructor(
|
||||||
private val olmMachine: Provider<OlmMachine>,
|
private val olmMachine: Provider<OlmMachine>,
|
||||||
|
@ -49,26 +49,36 @@ internal class VerificationsProvider @Inject constructor(
|
||||||
* verification.
|
* verification.
|
||||||
*/
|
*/
|
||||||
fun getVerification(userId: String, flowId: String): VerificationTransaction? {
|
fun getVerification(userId: String, flowId: String): VerificationTransaction? {
|
||||||
return when (val verification = innerMachine.getVerification(userId, flowId)) {
|
val verification = innerMachine.getVerification(userId, flowId)
|
||||||
is uniffi.olm.Verification.QrCodeV1 -> {
|
return if (verification?.asSas() != null) {
|
||||||
val request = getVerificationRequest(userId, flowId) ?: return null
|
sasVerificationFactory.create(verification.asSas()!!)
|
||||||
qrVerificationFactory.create(request, verification.qrcode)
|
} else if (verification?.asQr() != null) {
|
||||||
}
|
// qrVerificationFactory.create(verification, verification.asQr()!!)
|
||||||
is uniffi.olm.Verification.SasV1 -> {
|
// TODO
|
||||||
sasVerificationFactory.create(verification.sas)
|
null
|
||||||
}
|
|
||||||
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 {
|
} else {
|
||||||
null
|
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
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,22 +24,21 @@ import kotlinx.coroutines.withContext
|
||||||
import org.matrix.android.sdk.api.MatrixCoroutineDispatchers
|
import org.matrix.android.sdk.api.MatrixCoroutineDispatchers
|
||||||
import org.matrix.android.sdk.api.extensions.tryOrNull
|
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.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.QrCodeVerificationTransaction
|
||||||
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.api.util.fromBase64
|
import org.matrix.android.sdk.api.util.fromBase64
|
||||||
import org.matrix.android.sdk.internal.crypto.OlmMachine
|
import org.matrix.android.sdk.internal.crypto.OlmMachine
|
||||||
import org.matrix.android.sdk.internal.crypto.network.RequestSender
|
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.VerificationListenersHolder
|
||||||
import org.matrix.android.sdk.internal.crypto.verification.VerificationRequest
|
import org.matrix.android.sdk.internal.crypto.verification.VerificationRequest
|
||||||
import uniffi.olm.CryptoStoreException
|
import org.matrix.rustcomponents.sdk.crypto.CryptoStoreException
|
||||||
import uniffi.olm.QrCode
|
import org.matrix.rustcomponents.sdk.crypto.QrCode
|
||||||
import uniffi.olm.Verification
|
|
||||||
|
|
||||||
/** Class representing a QR code based verification flow */
|
/** Class representing a QR code based verification flow */
|
||||||
internal class QrCodeVerification @AssistedInject constructor(
|
internal class QrCodeVerification @AssistedInject constructor(
|
||||||
@Assisted private var request: VerificationRequest,
|
@Assisted private var request: VerificationRequest,
|
||||||
@Assisted private var inner: QrCode?,
|
@Assisted private var inner: QrCode,
|
||||||
private val olmMachine: OlmMachine,
|
private val olmMachine: OlmMachine,
|
||||||
private val sender: RequestSender,
|
private val sender: RequestSender,
|
||||||
private val coroutineDispatchers: MatrixCoroutineDispatchers,
|
private val coroutineDispatchers: MatrixCoroutineDispatchers,
|
||||||
|
@ -48,9 +47,12 @@ internal class QrCodeVerification @AssistedInject constructor(
|
||||||
|
|
||||||
@AssistedFactory
|
@AssistedFactory
|
||||||
interface Factory {
|
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 val innerMachine = olmMachine.inner()
|
||||||
|
|
||||||
private fun dispatchTxUpdated() {
|
private fun dispatchTxUpdated() {
|
||||||
|
@ -72,17 +74,17 @@ internal class QrCodeVerification @AssistedInject constructor(
|
||||||
*/
|
*/
|
||||||
override val qrCodeText: String?
|
override val qrCodeText: String?
|
||||||
get() {
|
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?
|
// 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)
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Pass the data from a scanned QR code into the QR code verification object */
|
/** Pass the data from a scanned QR code into the QR code verification object */
|
||||||
override suspend fun userHasScannedOtherQrCode(otherQrCodeText: String) {
|
// override suspend fun userHasScannedOtherQrCode(otherQrCodeText: String) {
|
||||||
request.scanQrCode(otherQrCodeText)
|
// request.scanQrCode(otherQrCodeText)
|
||||||
dispatchTxUpdated()
|
// dispatchTxUpdated()
|
||||||
}
|
// }
|
||||||
|
|
||||||
/** Confirm that the other side has indeed scanned the QR code we presented */
|
/** Confirm that the other side has indeed scanned the QR code we presented */
|
||||||
override suspend fun otherUserScannedMyQrCode() {
|
override suspend fun otherUserScannedMyQrCode() {
|
||||||
|
@ -95,32 +97,35 @@ internal class QrCodeVerification @AssistedInject constructor(
|
||||||
cancelHelper(CancelCode.MismatchedKeys)
|
cancelHelper(CancelCode.MismatchedKeys)
|
||||||
}
|
}
|
||||||
|
|
||||||
override var state: VerificationTxState
|
override fun state(): QRCodeVerificationState {
|
||||||
get() {
|
return QRCodeVerificationState.Reciprocated
|
||||||
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 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 */
|
/** Get the unique id of this verification */
|
||||||
override val transactionId: String
|
override val transactionId: String
|
||||||
|
@ -185,7 +190,7 @@ internal class QrCodeVerification @AssistedInject constructor(
|
||||||
@Throws(CryptoStoreException::class)
|
@Throws(CryptoStoreException::class)
|
||||||
private suspend fun confirm() {
|
private suspend fun confirm() {
|
||||||
val result = withContext(coroutineDispatchers.io) {
|
val result = withContext(coroutineDispatchers.io) {
|
||||||
innerMachine.confirmVerification(request.otherUser(), request.flowId())
|
inner.confirm()
|
||||||
} ?: return
|
} ?: return
|
||||||
dispatchTxUpdated()
|
dispatchTxUpdated()
|
||||||
try {
|
try {
|
||||||
|
@ -202,7 +207,7 @@ internal class QrCodeVerification @AssistedInject constructor(
|
||||||
}
|
}
|
||||||
|
|
||||||
private suspend fun cancelHelper(code: CancelCode) = withContext(NonCancellable) {
|
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()
|
dispatchTxUpdated()
|
||||||
tryOrNull("Fail to send cancel verification request") {
|
tryOrNull("Fail to send cancel verification request") {
|
||||||
sender.sendVerificationRequest(request, retryCount = Int.MAX_VALUE)
|
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 */
|
/** Fetch fresh data from the Rust side for our verification flow */
|
||||||
private fun refreshData() {
|
private fun refreshData() {
|
||||||
when (val verification = innerMachine.getVerification(request.otherUser(), request.flowId())) {
|
innerMachine.getVerification(request.otherUser(), request.flowId())
|
||||||
is Verification.QrCodeV1 -> {
|
?.asQr()?.let {
|
||||||
inner = verification.qrcode
|
inner = it
|
||||||
}
|
|
||||||
else -> {
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
// when (val verification = innerMachine.getVerification(request.otherUser(), request.flowId())) {
|
||||||
|
// is Verification.QrCodeV1 -> {
|
||||||
|
// inner = verification.qrcode
|
||||||
|
// }
|
||||||
|
// else -> {
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -225,7 +234,7 @@ internal class QrCodeVerification @AssistedInject constructor(
|
||||||
override fun toString(): String {
|
override fun toString(): String {
|
||||||
return "QrCodeVerification(" +
|
return "QrCodeVerification(" +
|
||||||
"qrCodeText=$qrCodeText, " +
|
"qrCodeText=$qrCodeText, " +
|
||||||
"state=$state, " +
|
"state=${state()}, " +
|
||||||
"transactionId='$transactionId', " +
|
"transactionId='$transactionId', " +
|
||||||
"otherUserId='$otherUserId', " +
|
"otherUserId='$otherUserId', " +
|
||||||
"otherDeviceId=$otherDeviceId, " +
|
"otherDeviceId=$otherDeviceId, " +
|
||||||
|
|
|
@ -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"
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue