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