diff --git a/matrix-sdk-android-flow/src/main/java/org/matrix/android/sdk/flow/FlowSession.kt b/matrix-sdk-android-flow/src/main/java/org/matrix/android/sdk/flow/FlowSession.kt index 4dc1d04599..2dbc5c99db 100644 --- a/matrix-sdk-android-flow/src/main/java/org/matrix/android/sdk/flow/FlowSession.kt +++ b/matrix-sdk-android-flow/src/main/java/org/matrix/android/sdk/flow/FlowSession.kt @@ -125,9 +125,9 @@ class FlowSession(private val session: Session) { } fun liveUserCryptoDevices(userId: String): Flow> { - return session.cryptoService().getLiveCryptoDeviceInfo(userId) + return session.cryptoService().getLiveCryptoDeviceInfoList(userId) .startWith(session.coroutineDispatchers.io) { - session.cryptoService().getCryptoDeviceInfo(userId) + session.cryptoService().getCryptoDeviceInfoList(userId) } } diff --git a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/common/CryptoTestHelper.kt b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/common/CryptoTestHelper.kt index ba0b467122..bf0a25d42d 100644 --- a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/common/CryptoTestHelper.kt +++ b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/common/CryptoTestHelper.kt @@ -301,12 +301,10 @@ class CryptoTestHelper(private val testHelper: CommonTestHelper) { val bobVerificationService = bob.cryptoService().verificationService() runBlocking { - aliceVerificationService.beginKeyVerificationInDMs( + aliceVerificationService.beginKeyVerification( VerificationMethod.SAS, - requestID, roomId, - bob.myUserId, - bob.sessionParams.credentials.deviceId!!) + bob.myUserId, ) } // we should reach SHOW SAS on both diff --git a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/crypto/UnwedgingTest.kt b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/crypto/UnwedgingTest.kt index dba5ad4a4f..21fcc4e1ce 100644 --- a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/crypto/UnwedgingTest.kt +++ b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/crypto/UnwedgingTest.kt @@ -145,7 +145,7 @@ class UnwedgingTest : InstrumentedTest { // Let us pickle our session with bob here so we can later unpickle it // and wedge our session. var myDevice = testHelper.runBlockingTest { - bobSession.cryptoService().getMyDevice() + bobSession.cryptoService().getMyCryptoDevice() } val sessionIdsForBob = aliceCryptoStore.getDeviceSessionIds(myDevice.identityKey()!!) sessionIdsForBob!!.size shouldBe 1 @@ -178,7 +178,7 @@ class UnwedgingTest : InstrumentedTest { Timber.i("## CRYPTO | testUnwedging: wedge the session now. Set crypto state like after the first message") myDevice = testHelper.runBlockingTest { - bobSession.cryptoService().getMyDevice() + bobSession.cryptoService().getMyCryptoDevice() } aliceCryptoStore.storeSession(OlmSessionWrapper(deserializeFromRealm(oldSession)!!), myDevice.identityKey()!!) Thread.sleep(6_000) diff --git a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/crypto/crosssigning/XSigningTest.kt b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/crypto/crosssigning/XSigningTest.kt index fc8aa57de0..ef49e67029 100644 --- a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/crypto/crosssigning/XSigningTest.kt +++ b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/crypto/crosssigning/XSigningTest.kt @@ -203,7 +203,7 @@ class XSigningTest : InstrumentedTest { } val bobSecondDevicePOVFirstDevice = runBlocking { - bobSession.cryptoService().getDeviceInfo(bobUserId, bobSecondDeviceId) + bobSession.cryptoService().getCryptoDeviceInfo(bobUserId, bobSecondDeviceId) } assertNotNull("Bob Second device should be known and persisted from first", bobSecondDevicePOVFirstDevice) diff --git a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/crypto/gossiping/KeyShareTests.kt b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/crypto/gossiping/KeyShareTests.kt index 613a54a6b9..9307c8b93a 100644 --- a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/crypto/gossiping/KeyShareTests.kt +++ b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/crypto/gossiping/KeyShareTests.kt @@ -50,7 +50,6 @@ import org.matrix.android.sdk.common.SessionTestParams import org.matrix.android.sdk.common.TestConstants import org.matrix.android.sdk.internal.crypto.GossipingRequestState import org.matrix.android.sdk.internal.crypto.OutgoingGossipingRequestState -import org.matrix.android.sdk.internal.crypto.crosssigning.DeviceTrustLevel import org.matrix.android.sdk.internal.crypto.model.event.EncryptedEventContent import kotlin.coroutines.Continuation import kotlin.coroutines.resume @@ -158,8 +157,9 @@ class KeyShareTests : InstrumentedTest { } // Mark the device as trusted - aliceSession.cryptoService().setDeviceVerification(DeviceTrustLevel(crossSigningVerified = false, locallyVerified = true), aliceSession.myUserId, - aliceSession2.sessionParams.deviceId ?: "") + commonTestHelper.runBlockingTest { + aliceSession.cryptoService().verificationService().markedLocallyAsManuallyVerified(aliceSession.myUserId, aliceSession2.sessionParams.deviceId ?: "") + } // Re request aliceSession2.cryptoService().reRequestRoomKeyForEvent(receivedEvent.root) @@ -280,13 +280,12 @@ class KeyShareTests : InstrumentedTest { val txId = "m.testVerif12" commonTestHelper.runBlockingTest { - aliceVerificationService2.beginKeyVerification(VerificationMethod.SAS, aliceSession1.myUserId, aliceSession1.sessionParams.deviceId - ?: "", txId) + aliceVerificationService2.beginKeyVerification(VerificationMethod.SAS, aliceSession1.myUserId, txId) } commonTestHelper.waitWithLatch { latch -> commonTestHelper.retryPeriodicallyWithLatch(latch) { - aliceSession1.cryptoService().getDeviceInfo(aliceSession1.myUserId, aliceSession2.sessionParams.deviceId ?: "")?.isVerified == true + aliceSession1.cryptoService().getCryptoDeviceInfo(aliceSession1.myUserId, aliceSession2.sessionParams.deviceId ?: "")?.isVerified == true } } diff --git a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/crypto/keysbackup/KeysBackupTest.kt b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/crypto/keysbackup/KeysBackupTest.kt index 524046c416..ac0a8e23d8 100644 --- a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/crypto/keysbackup/KeysBackupTest.kt +++ b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/crypto/keysbackup/KeysBackupTest.kt @@ -39,7 +39,6 @@ import org.matrix.android.sdk.common.CommonTestHelper import org.matrix.android.sdk.common.CryptoTestHelper import org.matrix.android.sdk.common.TestConstants import org.matrix.android.sdk.internal.crypto.MXCRYPTO_ALGORITHM_MEGOLM_BACKUP -import org.matrix.android.sdk.internal.crypto.crosssigning.DeviceTrustLevel import org.matrix.android.sdk.internal.crypto.model.ImportRoomKeysResult import java.util.concurrent.CountDownLatch @@ -840,7 +839,7 @@ class KeysBackupTest : InstrumentedTest { val signature = keysBackupVersionTrust.signatures[0] val device = runBlocking { - cryptoTestData.firstSession.cryptoService().getMyDevice() + cryptoTestData.firstSession.cryptoService().getMyCryptoDevice() } assertTrue(signature.valid) assertNotNull(signature.device) @@ -1065,7 +1064,9 @@ class KeysBackupTest : InstrumentedTest { assertFalse(keysBackup2.isEnabled) // - Validate the old device from the new one - aliceSession2.cryptoService().setDeviceVerification(DeviceTrustLevel(crossSigningVerified = false, locallyVerified = true), aliceSession2.myUserId, oldDeviceId) + testHelper.runBlockingTest { + aliceSession2.cryptoService().verificationService().markedLocallyAsManuallyVerified(aliceSession2.myUserId, oldDeviceId) + } // -> Backup should automatically enable on the new device val latch4 = CountDownLatch(1) diff --git a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/crypto/verification/SASTest.kt b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/crypto/verification/SASTest.kt index 395e86ac92..72f25edaac 100644 --- a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/crypto/verification/SASTest.kt +++ b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/crypto/verification/SASTest.kt @@ -22,7 +22,6 @@ import kotlinx.coroutines.runBlocking import org.junit.Assert.assertEquals import org.junit.Assert.assertFalse import org.junit.Assert.assertNotNull -import org.junit.Assert.assertNull import org.junit.Assert.assertTrue import org.junit.Assert.fail import org.junit.FixMethodOrder @@ -49,7 +48,6 @@ import org.matrix.android.sdk.internal.crypto.model.rest.KeyVerificationCancel import org.matrix.android.sdk.internal.crypto.model.rest.KeyVerificationStart import org.matrix.android.sdk.internal.crypto.model.rest.toValue import timber.log.Timber -import java.util.UUID import java.util.concurrent.CountDownLatch @RunWith(AndroidJUnit4::class) @@ -76,14 +74,12 @@ class SASTest : InstrumentedTest { } bobVerificationService.addListener(bobListener) - val myDevice = testHelper.runBlockingTest { - bobSession.cryptoService().getMyDevice() + val bobDevice = testHelper.runBlockingTest { + bobSession.cryptoService().getMyCryptoDevice() } val txID = testHelper.runBlockingTest { - aliceVerificationService.beginKeyVerification(VerificationMethod.SAS, - bobSession.myUserId, - myDevice.deviceId, - null) + aliceSession.cryptoService().downloadKeys(listOf(bobSession.myUserId), forceDownload = true) + aliceVerificationService.beginDeviceVerification(bobSession.myUserId, bobDevice.deviceId) } assertNotNull("Alice should have a started transaction", txID) @@ -102,7 +98,7 @@ class SASTest : InstrumentedTest { assertEquals("Alice and Bob have same transaction id", aliceKeyTx!!.transactionId, bobKeyTx!!.transactionId) - assertEquals("Alice state should be started", VerificationTxState.Started, aliceKeyTx.state) + assertEquals("Alice state should be started", VerificationTxState.OnStarted, aliceKeyTx.state) assertEquals("Bob state should be started by alice", VerificationTxState.OnStarted, bobKeyTx.state) // Let's cancel from alice side @@ -137,9 +133,6 @@ class SASTest : InstrumentedTest { assertEquals("Should be User cancelled on alice side", CancelCode.User, aliceCancelState.cancelCode) assertEquals("Should be User cancelled on bob side", CancelCode.User, bobCancelState.cancelCode) - assertNull(bobVerificationService.getExistingTransaction(aliceSession.myUserId, txID)) - assertNull(aliceVerificationService.getExistingTransaction(bobSession.myUserId, txID)) - cryptoTestData.cleanUp(testHelper) } @@ -184,7 +177,7 @@ class SASTest : InstrumentedTest { val aliceSession = cryptoTestData.firstSession val aliceUserID = aliceSession.myUserId val aliceDevice = testHelper.runBlockingTest { - aliceSession.cryptoService().getMyDevice().deviceId + aliceSession.cryptoService().getMyCryptoDevice().deviceId } val aliceListener = object : VerificationService.Listener { @@ -237,7 +230,7 @@ class SASTest : InstrumentedTest { val aliceSession = cryptoTestData.firstSession val aliceUserID = aliceSession.myUserId val aliceDevice = testHelper.runBlockingTest { - aliceSession.cryptoService().getMyDevice().deviceId + aliceSession.cryptoService().getMyCryptoDevice().deviceId } fakeBobStart(bobSession, aliceUserID, aliceDevice, tid, mac = mac) @@ -280,7 +273,7 @@ class SASTest : InstrumentedTest { val aliceSession = cryptoTestData.firstSession val aliceUserID = aliceSession.myUserId val aliceDevice = testHelper.runBlockingTest { - aliceSession.cryptoService().getMyDevice().deviceId + aliceSession.cryptoService().getMyCryptoDevice().deviceId } fakeBobStart(bobSession, aliceUserID, aliceDevice, tid, codes = codes) @@ -302,7 +295,7 @@ class SASTest : InstrumentedTest { mac: List = emptyList(), codes: List = emptyList()) { val deviceId = runBlocking { - bobSession.cryptoService().getMyDevice().deviceId + bobSession.cryptoService().getMyCryptoDevice().deviceId } val startMessage = KeyVerificationStart( fromDevice = deviceId, @@ -340,7 +333,7 @@ class SASTest : InstrumentedTest { val aliceVerificationService = aliceSession.cryptoService().verificationService() val aliceCreatedLatch = CountDownLatch(2) - val aliceCancelledLatch = CountDownLatch(2) + val aliceCancelledLatch = CountDownLatch(1) val createdTx = mutableListOf() val aliceListener = object : VerificationService.Listener { override fun transactionCreated(tx: VerificationTransaction) { @@ -358,11 +351,12 @@ class SASTest : InstrumentedTest { val bobUserId = bobSession!!.myUserId val bobDeviceId = testHelper.runBlockingTest { - bobSession.cryptoService().getMyDevice().deviceId + bobSession.cryptoService().getMyCryptoDevice().deviceId } testHelper.runBlockingTest { - aliceVerificationService.beginKeyVerification(VerificationMethod.SAS, bobUserId, bobDeviceId, null) - aliceVerificationService.beginKeyVerification(VerificationMethod.SAS, bobUserId, bobDeviceId, null) + aliceSession.cryptoService().downloadKeys(listOf(bobUserId), forceDownload = true) + aliceVerificationService.beginDeviceVerification(bobUserId, bobDeviceId) + aliceVerificationService.beginDeviceVerification(bobUserId, bobDeviceId) } testHelper.await(aliceCreatedLatch) testHelper.await(aliceCancelledLatch) @@ -410,10 +404,10 @@ class SASTest : InstrumentedTest { val bobUserId = bobSession.myUserId val bobDeviceId = runBlocking { - bobSession.cryptoService().getMyDevice().deviceId + bobSession.cryptoService().getMyCryptoDevice().deviceId } testHelper.runBlockingTest { - aliceVerificationService.beginKeyVerification(VerificationMethod.SAS, bobUserId, bobDeviceId, null) + //aliceVerificationService.beginKeyVerification(VerificationMethod.SAS, bobUserId, bobDeviceId, null) } testHelper.await(aliceAcceptedLatch) @@ -422,71 +416,40 @@ class SASTest : InstrumentedTest { @Test fun test_aliceAndBobSASCode() { + val supportedMethods = listOf(VerificationMethod.SAS) val testHelper = CommonTestHelper(context()) val cryptoTestHelper = CryptoTestHelper(testHelper) val cryptoTestData = cryptoTestHelper.doE2ETestWithAliceAndBobInARoom() - + val sasTestHelper = SasVerificationTestHelper(testHelper, cryptoTestHelper) val aliceSession = cryptoTestData.firstSession val bobSession = cryptoTestData.secondSession!! + val transactionId = sasTestHelper.requestVerificationAndWaitForReadyState(cryptoTestData, supportedMethods) - cryptoTestHelper.initializeCrossSigning(aliceSession) - cryptoTestHelper.initializeCrossSigning(bobSession) - - val aliceVerificationService = aliceSession.cryptoService().verificationService() - val bobVerificationService = bobSession.cryptoService().verificationService() - - val aliceSASLatch = CountDownLatch(1) + val latch = CountDownLatch(2) val aliceListener = object : VerificationService.Listener { override fun transactionUpdated(tx: VerificationTransaction) { - when (tx.state) { - VerificationTxState.ShortCodeReady -> { - aliceSASLatch.countDown() - } - else -> Unit - } + Timber.v("Alice transactionUpdated: ${tx.state}") + latch.countDown() } - } - aliceVerificationService.addListener(aliceListener) - val bobSASLatch = CountDownLatch(1) + } + aliceSession.cryptoService().verificationService().addListener(aliceListener) val bobListener = object : VerificationService.Listener { - - override fun verificationRequestCreated(pr: PendingVerificationRequest) { - - } - override fun transactionUpdated(tx: VerificationTransaction) { - val sasVerification = tx as SasVerificationTransaction - when (tx.state) { - VerificationTxState.OnStarted -> testHelper.runBlockingTest { - sasVerification.acceptVerification() - } - VerificationTxState.ShortCodeReady -> { - bobSASLatch.countDown() - } - else -> Unit - } + Timber.v("Bob transactionUpdated: ${tx.state}") + latch.countDown() } } - bobVerificationService.addListener(bobListener) - - val bobUserId = bobSession.myUserId + bobSession.cryptoService().verificationService().addListener(bobListener) testHelper.runBlockingTest { - aliceSession.cryptoService().downloadKeys(listOf(bobUserId), forceDownload = true) - aliceVerificationService.requestKeyVerificationInDMs(listOf(VerificationMethod.SAS),bobUserId, cryptoTestData.roomId) + aliceSession.cryptoService().verificationService().beginKeyVerification(VerificationMethod.SAS, bobSession.myUserId, transactionId) } - testHelper.await(aliceSASLatch) - testHelper.await(bobSASLatch) - - /* - val aliceTx = aliceVerificationService.getExistingTransaction(bobUserId, verificationSAS!!) as SasVerificationTransaction - val bobTx = bobVerificationService.getExistingTransaction(aliceSession.myUserId, verificationSAS) as SasVerificationTransaction - + testHelper.await(latch) + val aliceTx = aliceSession.cryptoService().verificationService().getExistingTransaction(bobSession.myUserId, transactionId) as SasVerificationTransaction + val bobTx = bobSession.cryptoService().verificationService().getExistingTransaction(aliceSession.myUserId, transactionId) as SasVerificationTransaction assertEquals("Should have same SAS", aliceTx.getDecimalCodeRepresentation(), bobTx.getDecimalCodeRepresentation()) - */ - cryptoTestData.cleanUp(testHelper) } @@ -495,7 +458,8 @@ class SASTest : InstrumentedTest { val testHelper = CommonTestHelper(context()) val cryptoTestHelper = CryptoTestHelper(testHelper) val cryptoTestData = cryptoTestHelper.doE2ETestWithAliceAndBobInARoom() - + val sasVerificationTestHelper = SasVerificationTestHelper(testHelper, cryptoTestHelper) + val transactionId = sasVerificationTestHelper.requestVerificationAndWaitForReadyState(cryptoTestData, listOf(VerificationMethod.SAS)) val aliceSession = cryptoTestData.firstSession val bobSession = cryptoTestData.secondSession @@ -504,8 +468,14 @@ class SASTest : InstrumentedTest { val aliceSASLatch = CountDownLatch(1) val aliceListener = object : VerificationService.Listener { + + override fun verificationRequestUpdated(pr: PendingVerificationRequest) { + Timber.v("RequestUpdated pr=$pr") + } + var matchOnce = true override fun transactionUpdated(tx: VerificationTransaction) { + Timber.v("Alice transactionUpdated: ${tx.state}") if (tx !is SasVerificationTransaction) return when (tx.state) { VerificationTxState.ShortCodeReady -> testHelper.runBlockingTest { @@ -527,7 +497,13 @@ class SASTest : InstrumentedTest { val bobListener = object : VerificationService.Listener { var acceptOnce = true var matchOnce = true + + override fun verificationRequestUpdated(pr: PendingVerificationRequest) { + Timber.v("RequestUpdated: pr=$pr") + } + override fun transactionUpdated(tx: VerificationTransaction) { + Timber.v("Bob transactionUpdated: ${tx.state}") if (tx !is SasVerificationTransaction) return when (tx.state) { VerificationTxState.OnStarted -> testHelper.runBlockingTest { @@ -542,7 +518,7 @@ class SASTest : InstrumentedTest { tx.userHasVerifiedShortCode() } } - VerificationTxState.Verified -> { + VerificationTxState.ShortCodeAccepted -> { bobSASLatch.countDown() } else -> Unit @@ -553,20 +529,20 @@ class SASTest : InstrumentedTest { val bobUserId = bobSession.myUserId val bobDeviceId = runBlocking { - bobSession.cryptoService().getMyDevice().deviceId + bobSession.cryptoService().getMyCryptoDevice().deviceId } testHelper.runBlockingTest { - aliceVerificationService.beginKeyVerification(VerificationMethod.SAS, bobUserId, bobDeviceId, null) + aliceVerificationService.beginKeyVerification(VerificationMethod.SAS, bobUserId, transactionId) } testHelper.await(aliceSASLatch) testHelper.await(bobSASLatch) // Assert that devices are verified val bobDeviceInfoFromAlicePOV: CryptoDeviceInfo? = testHelper.runBlockingTest { - aliceSession.cryptoService().getDeviceInfo(bobUserId, bobDeviceId) + aliceSession.cryptoService().getCryptoDeviceInfo(bobUserId, bobDeviceId) } val aliceDeviceInfoFromBobPOV: CryptoDeviceInfo? = testHelper.runBlockingTest { - bobSession.cryptoService().getDeviceInfo(aliceSession.myUserId, aliceSession.cryptoService().getMyDevice().deviceId) + bobSession.cryptoService().getCryptoDeviceInfo(aliceSession.myUserId, aliceSession.cryptoService().getMyCryptoDevice().deviceId) } assertTrue("alice device should be verified from bob point of view", aliceDeviceInfoFromBobPOV!!.isVerified) assertTrue("bob device should be verified from alice point of view", bobDeviceInfoFromAlicePOV!!.isVerified) @@ -633,19 +609,17 @@ class SASTest : InstrumentedTest { // Start concurrent! testHelper.runBlockingTest { - aliceVerificationService.beginKeyVerificationInDMs( - VerificationMethod.SAS, - requestID!!, - cryptoTestData.roomId, - bobSession.myUserId, - bobSession.sessionParams.deviceId!!) + aliceVerificationService.requestKeyVerificationInDMs( + methods = listOf(VerificationMethod.SAS), + otherUserId = bobSession.myUserId, + roomId = cryptoTestData.roomId + ) - bobVerificationService.beginKeyVerificationInDMs( - VerificationMethod.SAS, - requestID!!, - cryptoTestData.roomId, - aliceSession.myUserId, - aliceSession.sessionParams.deviceId!!) + bobVerificationService.requestKeyVerificationInDMs( + methods = listOf(VerificationMethod.SAS), + otherUserId = aliceSession.myUserId, + roomId = cryptoTestData.roomId + ) } diff --git a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/crypto/verification/SasVerificationTestHelper.kt b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/crypto/verification/SasVerificationTestHelper.kt new file mode 100644 index 0000000000..f6ac15eecb --- /dev/null +++ b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/crypto/verification/SasVerificationTestHelper.kt @@ -0,0 +1,88 @@ +/* + * Copyright (c) 2022 New Vector Ltd + * + * 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.verification + +import org.matrix.android.sdk.api.session.crypto.verification.PendingVerificationRequest +import org.matrix.android.sdk.api.session.crypto.verification.VerificationMethod +import org.matrix.android.sdk.api.session.crypto.verification.VerificationService +import org.matrix.android.sdk.common.CommonTestHelper +import org.matrix.android.sdk.common.CryptoTestData +import org.matrix.android.sdk.common.CryptoTestHelper +import timber.log.Timber +import java.util.concurrent.CountDownLatch + +class SasVerificationTestHelper (private val testHelper: CommonTestHelper, private val cryptoTestHelper: CryptoTestHelper){ + fun requestVerificationAndWaitForReadyState(cryptoTestData: CryptoTestData, supportedMethods: List): String { + val aliceSession = cryptoTestData.firstSession + val bobSession = cryptoTestData.secondSession!! + cryptoTestHelper.initializeCrossSigning(aliceSession) + cryptoTestHelper.initializeCrossSigning(bobSession) + + val aliceVerificationService = aliceSession.cryptoService().verificationService() + val bobVerificationService = bobSession.cryptoService().verificationService() + + var bobReadyPendingVerificationRequest: PendingVerificationRequest? = null + + val latch = CountDownLatch(2) + val aliceListener = object : VerificationService.Listener { + override fun verificationRequestUpdated(pr: PendingVerificationRequest) { + // Step 4: Alice receive the ready request + Timber.v("Alice request updated: $pr") + if (pr.isReady) { + latch.countDown() + } + } + } + aliceVerificationService.addListener(aliceListener) + + val bobListener = object : VerificationService.Listener { + override fun verificationRequestCreated(pr: PendingVerificationRequest) { + // Step 2: Bob accepts the verification request + Timber.v("Bob accepts the verification request") + testHelper.runBlockingTest { + bobVerificationService.readyPendingVerification( + supportedMethods, + aliceSession.myUserId, + pr.transactionId!! + ) + } + } + + override fun verificationRequestUpdated(pr: PendingVerificationRequest) { + // Step 3: Bob is ready + Timber.v("Bob request updated $pr") + if (pr.isReady) { + bobReadyPendingVerificationRequest = pr + latch.countDown() + } + } + } + bobVerificationService.addListener(bobListener) + + val bobUserId = bobSession.myUserId + // Step 1: Alice starts a verification request + testHelper.runBlockingTest { + aliceVerificationService.requestKeyVerificationInDMs(supportedMethods, bobUserId, cryptoTestData.roomId) + } + testHelper.await(latch) + bobVerificationService.removeListener(bobListener) + aliceVerificationService.removeListener(aliceListener) + return bobReadyPendingVerificationRequest?.transactionId!! + } +} + + diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/crypto/CryptoService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/crypto/CryptoService.kt index 671128f268..8104ed7e7a 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/crypto/CryptoService.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/crypto/CryptoService.kt @@ -50,9 +50,9 @@ interface CryptoService { fun keysBackupService(): KeysBackupService - fun setDeviceName(deviceId: String, deviceName: String, callback: MatrixCallback) + suspend fun setDeviceName(deviceId: String, deviceName: String) - fun deleteDevice(deviceId: String, userInteractiveAuthInterceptor: UserInteractiveAuthInterceptor, callback: MatrixCallback) + suspend fun deleteDevice(deviceId: String, userInteractiveAuthInterceptor: UserInteractiveAuthInterceptor) fun getCryptoVersion(context: Context, longFormat: Boolean): String @@ -62,11 +62,9 @@ interface CryptoService { fun setWarnOnUnknownDevices(warn: Boolean) - fun setDeviceVerification(trustLevel: DeviceTrustLevel, userId: String, deviceId: String) - suspend fun getUserDevices(userId: String): MutableList - suspend fun getMyDevice(): CryptoDeviceInfo + suspend fun getMyCryptoDevice(): CryptoDeviceInfo fun getGlobalBlacklistUnverifiedDevices(): Boolean @@ -74,8 +72,6 @@ interface CryptoService { fun setRoomUnBlacklistUnverifiedDevices(roomId: String) - fun getDeviceTrackingStatus(userId: String): Int - suspend fun importRoomKeys(roomKeysAsArray: ByteArray, password: String, progressListener: ProgressListener?): ImportRoomKeysResult @@ -84,7 +80,7 @@ interface CryptoService { fun setRoomBlacklistUnverifiedDevices(roomId: String) - suspend fun getDeviceInfo(userId: String, deviceId: String?): CryptoDeviceInfo? + suspend fun getCryptoDeviceInfo(userId: String, deviceId: String?): CryptoDeviceInfo? fun reRequestRoomKeyForEvent(event: Event) @@ -98,7 +94,7 @@ interface CryptoService { fun getLiveMyDevicesInfo(): LiveData> - fun getDeviceInfo(deviceId: String, callback: MatrixCallback) + suspend fun fetchDeviceInfo(deviceId: String): DeviceInfo suspend fun inboundGroupSessionsCount(onlyBackedUp: Boolean): Int @@ -113,19 +109,17 @@ interface CryptoService { @Throws(MXCryptoError::class) suspend fun decryptEvent(event: Event, timeline: String): MXEventDecryptionResult - fun decryptEventAsync(event: Event, timeline: String, callback: MatrixCallback) - fun getEncryptionAlgorithm(roomId: String): String? fun shouldEncryptForInvitedMembers(roomId: String): Boolean suspend fun downloadKeys(userIds: List, forceDownload: Boolean = false): MXUsersDevicesMap - suspend fun getCryptoDeviceInfo(userId: String): List + suspend fun getCryptoDeviceInfoList(userId: String): List - fun getLiveCryptoDeviceInfo(userId: String): Flow> + fun getLiveCryptoDeviceInfoList(userId: String): Flow> - fun getLiveCryptoDeviceInfo(userIds: List): Flow> + fun getLiveCryptoDeviceInfoList(userIds: List): Flow> fun addNewSessionListener(newSessionListener: NewSessionListener) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/crypto/verification/VerificationService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/crypto/verification/VerificationService.kt index 8a8f80426b..867e3a0d2e 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/crypto/verification/VerificationService.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/crypto/verification/VerificationService.kt @@ -121,5 +121,4 @@ interface VerificationService { } } - fun onPotentiallyInterestingEventRoomFailToDecrypt(event: Event) } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/DefaultCryptoService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/DefaultCryptoService.kt index bec86a3812..cfc3e43be9 100755 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/DefaultCryptoService.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/DefaultCryptoService.kt @@ -32,9 +32,7 @@ import kotlinx.coroutines.launch import kotlinx.coroutines.sync.Mutex import kotlinx.coroutines.sync.withLock import kotlinx.coroutines.withContext -import org.matrix.android.sdk.api.MatrixCallback import org.matrix.android.sdk.api.MatrixCoroutineDispatchers -import org.matrix.android.sdk.api.NoOpMatrixCallback import org.matrix.android.sdk.api.auth.UserInteractiveAuthInterceptor import org.matrix.android.sdk.api.crypto.MXCryptoConfig import org.matrix.android.sdk.api.extensions.tryOrNull @@ -56,7 +54,6 @@ import org.matrix.android.sdk.api.session.room.model.RoomMemberContent import org.matrix.android.sdk.api.session.sync.model.DeviceListResponse import org.matrix.android.sdk.api.session.sync.model.DeviceOneTimeKeysCountSyncResponse import org.matrix.android.sdk.api.session.sync.model.ToDeviceSyncResponse -import org.matrix.android.sdk.internal.crypto.crosssigning.DeviceTrustLevel import org.matrix.android.sdk.internal.crypto.keysbackup.RustKeyBackupService import org.matrix.android.sdk.internal.crypto.model.CryptoDeviceInfo import org.matrix.android.sdk.internal.crypto.model.ImportRoomKeysResult @@ -67,6 +64,8 @@ import org.matrix.android.sdk.internal.crypto.model.event.RoomKeyWithHeldContent import org.matrix.android.sdk.internal.crypto.model.event.SecretSendEventContent import org.matrix.android.sdk.internal.crypto.model.rest.DeviceInfo import org.matrix.android.sdk.internal.crypto.model.rest.ForwardedRoomKeyContent +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.repository.WarnOnUnknownDeviceRepository import org.matrix.android.sdk.internal.crypto.store.IMXCryptoStore import org.matrix.android.sdk.internal.crypto.tasks.DeleteDeviceTask @@ -79,10 +78,6 @@ import org.matrix.android.sdk.internal.di.UserId import org.matrix.android.sdk.internal.session.SessionScope import org.matrix.android.sdk.internal.session.StreamEventsManager import org.matrix.android.sdk.internal.session.room.membership.LoadRoomMembersTask -import org.matrix.android.sdk.internal.task.TaskExecutor -import org.matrix.android.sdk.internal.task.TaskThread -import org.matrix.android.sdk.internal.task.configureWith -import org.matrix.android.sdk.internal.task.launchToCallback import timber.log.Timber import uniffi.olm.Request import uniffi.olm.RequestType @@ -129,7 +124,6 @@ internal class DefaultCryptoService @Inject constructor( private val loadRoomMembersTask: LoadRoomMembersTask, private val cryptoSessionInfoProvider: CryptoSessionInfoProvider, private val coroutineDispatchers: MatrixCoroutineDispatchers, - private val taskExecutor: TaskExecutor, private val cryptoCoroutineScope: CoroutineScope, private val requestSender: RequestSender, private val crossSigningService: CrossSigningService, @@ -152,7 +146,7 @@ internal class DefaultCryptoService @Inject constructor( // Locks for some of our operations private val keyClaimLock: Mutex = Mutex() - private val outgoingRequestsLock: Mutex = Mutex() + private val outgoingRequestsProcessor = OutgoingRequestsProcessor(requestSender, cryptoCoroutineScope, cryptoSessionInfoProvider, crossSigningService::shieldForGroup) private val roomKeyShareLocks: ConcurrentHashMap = ConcurrentHashMap() fun onStateEvent(roomId: String, event: Event) { @@ -179,38 +173,19 @@ internal class DefaultCryptoService @Inject constructor( private val gossipingBuffer = mutableListOf() - override fun setDeviceName(deviceId: String, deviceName: String, callback: MatrixCallback) { - setDeviceNameTask - .configureWith(SetDeviceNameTask.Params(deviceId, deviceName)) { - this.executionThread = TaskThread.CRYPTO - this.callback = object : MatrixCallback { - override fun onSuccess(data: Unit) { - // bg refresh of crypto device - cryptoCoroutineScope.launch { - try { - downloadKeys(listOf(userId), true) - } catch (failure: Throwable) { - Timber.tag(loggerTag.value).w(failure, "setDeviceName: Failed to refresh of crypto device") - } - } - callback.onSuccess(data) - } - - override fun onFailure(failure: Throwable) { - callback.onFailure(failure) - } - } - } - .executeBy(taskExecutor) + override suspend fun setDeviceName(deviceId: String, deviceName: String) { + val params = SetDeviceNameTask.Params(deviceId, deviceName) + setDeviceNameTask.execute(params) + try { + downloadKeys(listOf(userId), true) + } catch (failure: Throwable) { + Timber.tag(loggerTag.value).w(failure, "setDeviceName: Failed to refresh of crypto device") + } } - override fun deleteDevice(deviceId: String, userInteractiveAuthInterceptor: UserInteractiveAuthInterceptor, callback: MatrixCallback) { - deleteDeviceTask - .configureWith(DeleteDeviceTask.Params(deviceId, userInteractiveAuthInterceptor, null)) { - this.executionThread = TaskThread.CRYPTO - this.callback = callback - } - .executeBy(taskExecutor) + override suspend fun deleteDevice(deviceId: String, userInteractiveAuthInterceptor: UserInteractiveAuthInterceptor) { + val params = DeleteDeviceTask.Params(deviceId, userInteractiveAuthInterceptor, null) + deleteDeviceTask.execute(params) } override fun getCryptoVersion(context: Context, longFormat: Boolean): String { @@ -218,7 +193,7 @@ internal class DefaultCryptoService @Inject constructor( return if (longFormat) "Rust SDK 0.3" else "0.3" } - override suspend fun getMyDevice(): CryptoDeviceInfo { + override suspend fun getMyCryptoDevice(): CryptoDeviceInfo { return olmMachine.ownDevice() } @@ -238,13 +213,9 @@ internal class DefaultCryptoService @Inject constructor( return cryptoStore.getMyDevicesInfo() } - override fun getDeviceInfo(deviceId: String, callback: MatrixCallback) { - getDeviceInfoTask - .configureWith(GetDeviceInfoTask.Params(deviceId)) { - this.executionThread = TaskThread.CRYPTO - this.callback = callback - } - .executeBy(taskExecutor) + override suspend fun fetchDeviceInfo(deviceId: String): DeviceInfo { + val params = GetDeviceInfoTask.Params(deviceId) + return getDeviceInfoTask.execute(params) } override suspend fun inboundGroupSessionsCount(onlyBackedUp: Boolean): Int { @@ -256,20 +227,6 @@ internal class DefaultCryptoService @Inject constructor( // return cryptoStore.inboundGroupSessionsCount(onlyBackedUp) } - /** - * Provides the tracking status - * - * @param userId the user id - * @return the tracking status - */ - override fun getDeviceTrackingStatus(userId: String): Int { - return if (olmMachine.isUserTracked(userId)) { - 3 - } else { - -1 - } - } - /** * Tell if the MXCrypto is started * @@ -288,28 +245,13 @@ internal class DefaultCryptoService @Inject constructor( */ fun start() { internalStart() - cryptoCoroutineScope.launch(coroutineDispatchers.crypto) { + cryptoCoroutineScope.launch { // Just update fetchDevicesList() cryptoStore.tidyUpDataBase() } } - fun ensureDevice() { - cryptoCoroutineScope.launchToCallback(coroutineDispatchers.crypto, NoOpMatrixCallback()) { - // Open the store - cryptoStore.open() - - // this can throw if no backup - /* - TODO - tryOrNull { - keysBackupService.checkAndStartKeysBackup() - } - */ - } - } - private fun internalStart() { if (isStarted.get() || isStarting.get()) { return @@ -372,7 +314,7 @@ internal class DefaultCryptoService @Inject constructor( */ suspend fun onSyncCompleted() { if (isStarted()) { - sendOutgoingRequests() + outgoingRequestsProcessor.process(olmMachine) // This isn't a copy paste error. Sending the outgoing requests may // claim one-time keys and establish 1-to-1 Olm sessions with devices, while some // outgoing requests are waiting for an Olm session to be established (e.g. forwarding @@ -381,7 +323,7 @@ internal class DefaultCryptoService @Inject constructor( // The second call sends out those requests that are waiting for the // keys claim request to be sent out. // This could be omitted but then devices might be waiting for the next - sendOutgoingRequests() + outgoingRequestsProcessor.process(olmMachine) keysBackupService.maybeBackupKeys() } @@ -402,34 +344,21 @@ internal class DefaultCryptoService @Inject constructor( * @param userId the user id * @param deviceId the device id */ - override suspend fun getDeviceInfo(userId: String, deviceId: String?): CryptoDeviceInfo? { + override suspend fun getCryptoDeviceInfo(userId: String, deviceId: String?): CryptoDeviceInfo? { if (userId.isEmpty() || deviceId.isNullOrEmpty()) return null return olmMachine.getCryptoDeviceInfo(userId, deviceId) } - override suspend fun getCryptoDeviceInfo(userId: String): List { + override suspend fun getCryptoDeviceInfoList(userId: String): List { return olmMachine.getCryptoDeviceInfo(userId) } - override fun getLiveCryptoDeviceInfo(userId: String): Flow> { - return getLiveCryptoDeviceInfo(listOf(userId)) - } + override fun getLiveCryptoDeviceInfoList(userId: String) = getLiveCryptoDeviceInfoList(listOf(userId)) - override fun getLiveCryptoDeviceInfo(userIds: List): Flow> { + override fun getLiveCryptoDeviceInfoList(userIds: List): Flow> { return olmMachine.getLiveDevices(userIds) } - /** - * Update the blocked/verified state of the given device. - * - * @param trustLevel the new trust level - * @param userId the owner of the device - * @param deviceId the unique identifier for the device. - */ - override fun setDeviceVerification(trustLevel: DeviceTrustLevel, userId: String, deviceId: String) { - // TODO - } - /** * Configure a room to use encryption. * @@ -487,7 +416,7 @@ internal class DefaultCryptoService @Inject constructor( * @return the stored device keys for a user. */ override suspend fun getUserDevices(userId: String): MutableList { - return this.getCryptoDeviceInfo(userId).toMutableList() + return this.getCryptoDeviceInfoList(userId).toMutableList() } private fun isEncryptionEnabledForInvitedUser(): Boolean { @@ -559,18 +488,6 @@ internal class DefaultCryptoService @Inject constructor( return olmMachine.decryptRoomEvent(event) } - /** - * Decrypt an event asynchronously - * - * @param event the raw event. - * @param timeline the id of the timeline where the event is decrypted. It is used to prevent replay attack. - * @param callback the callback to return data or null - */ - override fun decryptEventAsync(event: Event, timeline: String, callback: MatrixCallback) { - // This isn't really used anywhere, maybe just remove it? - // TODO - } - /** * Handle an m.room.encryption event. * @@ -816,54 +733,6 @@ internal class DefaultCryptoService @Inject constructor( } } - private suspend fun sendOutgoingRequests() { - outgoingRequestsLock.withLock { - coroutineScope { - Timber.v("OutgoingRequests: ${olmMachine.outgoingRequests()}") - olmMachine.outgoingRequests().map { - when (it) { - is Request.KeysUpload -> { - async { - uploadKeys(it) - } - } - is Request.KeysQuery -> { - async { - queryKeys(it) - } - } - is Request.ToDevice -> { - async { - sendToDevice(it) - } - } - is Request.KeysClaim -> { - async { - claimKeys(it) - } - } - is Request.RoomMessage -> { - async { - sendRoomMessage(it) - } - } - is Request.SignatureUpload -> { - async { - signatureUpload(it) - } - } - is Request.KeysBackup -> { - async { - // The rust-sdk won't ever produce KeysBackup requests here, - // those only get explicitly created. - } - } - } - }.joinAll() - } - } - } - /** * Export the crypto keys * diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/Device.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/Device.kt index e07ab4db2a..8f3491bf0a 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/Device.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/Device.kt @@ -23,6 +23,7 @@ import org.matrix.android.sdk.api.session.crypto.verification.VerificationServic import org.matrix.android.sdk.internal.crypto.crosssigning.DeviceTrustLevel import org.matrix.android.sdk.internal.crypto.model.CryptoDeviceInfo import org.matrix.android.sdk.internal.crypto.model.rest.UnsignedDeviceInfo +import org.matrix.android.sdk.internal.crypto.network.RequestSender import org.matrix.android.sdk.internal.crypto.verification.prepareMethods import uniffi.olm.CryptoStoreException import uniffi.olm.OlmMachine diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/OlmMachine.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/OlmMachine.kt index 76972a74c6..fd8f00d650 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/OlmMachine.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/OlmMachine.kt @@ -47,6 +47,7 @@ import org.matrix.android.sdk.internal.crypto.model.ImportRoomKeysResult import org.matrix.android.sdk.internal.crypto.model.MXUsersDevicesMap import org.matrix.android.sdk.internal.crypto.model.rest.RestKeyInfo import org.matrix.android.sdk.internal.crypto.model.rest.UnsignedDeviceInfo +import org.matrix.android.sdk.internal.crypto.network.RequestSender import org.matrix.android.sdk.internal.crypto.store.PrivateKeysInfo import org.matrix.android.sdk.internal.network.parsing.CheckNumberType import timber.log.Timber @@ -549,13 +550,7 @@ internal class OlmMachine( */ @Throws(CryptoStoreException::class) suspend fun getCryptoDeviceInfo(userId: String, deviceId: String): CryptoDeviceInfo? { - return if (userId == userId() && deviceId == deviceId()) { - // Our own device isn't part of our store on the Rust side, return it - // using our ownDevice method - ownDevice() - } else { - getDevice(userId, deviceId)?.toCryptoDeviceInfo() - } + return getDevice(userId, deviceId)?.toCryptoDeviceInfo() } @Throws(CryptoStoreException::class) @@ -596,8 +591,8 @@ internal class OlmMachine( */ @Throws(CryptoStoreException::class) suspend fun getCryptoDeviceInfo(userId: String): List { - val devices = getUserDevices(userId).map { it.toCryptoDeviceInfo() }.toMutableList() - + return getUserDevices(userId).map { it.toCryptoDeviceInfo() } +/* // EA doesn't differentiate much between our own and other devices of // while the rust-sdk does, append our own device here. if (userId == userId()) { @@ -605,6 +600,8 @@ internal class OlmMachine( } return devices + + */ } /** diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/OlmMachineProvider.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/OlmMachineProvider.kt index 95a117d676..a46fcddcaf 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/OlmMachineProvider.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/OlmMachineProvider.kt @@ -18,6 +18,7 @@ package org.matrix.android.sdk.internal.crypto import com.squareup.moshi.Moshi import org.matrix.android.sdk.api.MatrixCoroutineDispatchers +import org.matrix.android.sdk.internal.crypto.network.RequestSender import org.matrix.android.sdk.internal.di.DeviceId import org.matrix.android.sdk.internal.di.SessionFilesDirectory import org.matrix.android.sdk.internal.di.UserId diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/QrCodeVerification.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/QrCodeVerification.kt index 23044c2a22..b6e5cdd8a2 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/QrCodeVerification.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/QrCodeVerification.kt @@ -24,6 +24,7 @@ import org.matrix.android.sdk.api.session.crypto.verification.VerificationServic 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.internal.crypto.crosssigning.fromBase64 +import org.matrix.android.sdk.internal.crypto.network.RequestSender import org.matrix.android.sdk.internal.crypto.verification.UpdateDispatcher import uniffi.olm.CryptoStoreException import uniffi.olm.OlmMachine diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/SasVerification.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/SasVerification.kt index b9225940d9..eac7fd4938 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/SasVerification.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/SasVerification.kt @@ -24,6 +24,7 @@ import org.matrix.android.sdk.api.session.crypto.verification.SasVerificationTra import org.matrix.android.sdk.api.session.crypto.verification.VerificationService 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.internal.crypto.network.RequestSender import org.matrix.android.sdk.internal.crypto.verification.UpdateDispatcher import org.matrix.android.sdk.internal.crypto.verification.getEmojiForCode import uniffi.olm.CryptoStoreException diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/UserIdentities.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/UserIdentities.kt index 9fcedc8034..3cc94dae86 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/UserIdentities.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/UserIdentities.kt @@ -23,6 +23,7 @@ import org.matrix.android.sdk.api.session.crypto.verification.VerificationMethod import org.matrix.android.sdk.api.session.events.model.EventType import org.matrix.android.sdk.internal.crypto.crosssigning.DeviceTrustLevel import org.matrix.android.sdk.internal.crypto.model.CryptoCrossSigningKey +import org.matrix.android.sdk.internal.crypto.network.RequestSender import org.matrix.android.sdk.internal.crypto.verification.prepareMethods import uniffi.olm.CryptoStoreException import uniffi.olm.SignatureException diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/VerificationRequest.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/VerificationRequest.kt index 9075423f9d..9c1b892bfd 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/VerificationRequest.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/VerificationRequest.kt @@ -18,7 +18,6 @@ package org.matrix.android.sdk.internal.crypto import android.os.Handler import android.os.Looper -import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.withContext import org.matrix.android.sdk.api.MatrixCoroutineDispatchers import org.matrix.android.sdk.api.session.crypto.verification.CancelCode @@ -30,6 +29,7 @@ import org.matrix.android.sdk.api.session.crypto.verification.VerificationServic import org.matrix.android.sdk.api.session.crypto.verification.safeValueOf import org.matrix.android.sdk.internal.crypto.crosssigning.toBase64NoPadding import org.matrix.android.sdk.internal.crypto.model.rest.VERIFICATION_METHOD_QR_CODE_SCAN +import org.matrix.android.sdk.internal.crypto.network.RequestSender import org.matrix.android.sdk.internal.crypto.verification.prepareMethods import timber.log.Timber import uniffi.olm.OlmMachine diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/keysbackup/RustKeyBackupService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/keysbackup/RustKeyBackupService.kt index 0c1d6946e1..8efa1f5686 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/keysbackup/RustKeyBackupService.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/keysbackup/RustKeyBackupService.kt @@ -40,7 +40,7 @@ import org.matrix.android.sdk.internal.crypto.MXCRYPTO_ALGORITHM_MEGOLM_BACKUP import org.matrix.android.sdk.internal.crypto.MegolmSessionData import org.matrix.android.sdk.internal.crypto.MegolmSessionImportManager import org.matrix.android.sdk.internal.crypto.OlmMachineProvider -import org.matrix.android.sdk.internal.crypto.RequestSender +import org.matrix.android.sdk.internal.crypto.network.RequestSender import org.matrix.android.sdk.internal.crypto.keysbackup.model.KeysBackupVersionTrust import org.matrix.android.sdk.internal.crypto.keysbackup.model.MegolmBackupAuthData import org.matrix.android.sdk.internal.crypto.keysbackup.model.MegolmBackupCreationInfo @@ -580,16 +580,12 @@ internal class RustKeyBackupService @Inject constructor( } override suspend fun getVersion(version: String): KeysVersionResult? { - return withContext(coroutineDispatchers.io) { - sender.getKeyBackupVersion(version) - } + return sender.getKeyBackupVersion(version) } @Throws override suspend fun getCurrentVersion(): KeysVersionResult? { - return withContext(coroutineDispatchers.io) { - sender.getKeyBackupVersion() - } + return sender.getKeyBackupVersion() } override suspend fun forceUsingLastVersion(): Boolean { @@ -645,18 +641,16 @@ internal class RustKeyBackupService @Inject constructor( Timber.w("checkAndStartKeysBackup: invalid state: $state") return@withContext } - keysBackupVersion = null keysBackupStateManager.state = KeysBackupState.CheckingBackUpOnHomeserver - - withContext(coroutineDispatchers.io) { - try { - val data = getCurrentVersion() - withContext(coroutineDispatchers.crypto) { - checkAndStartWithKeysBackupVersion(data) - } - } catch (failure: Throwable) { - Timber.e(failure, "checkAndStartKeysBackup: Failed to get current version") + try { + val data = getCurrentVersion() + withContext(coroutineDispatchers.crypto) { + checkAndStartWithKeysBackupVersion(data) + } + } catch (failure: Throwable) { + Timber.e(failure, "checkAndStartKeysBackup: Failed to get current version") + withContext(coroutineDispatchers.crypto) { keysBackupStateManager.state = KeysBackupState.Unknown } } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/network/OutgoingRequestsProcessor.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/network/OutgoingRequestsProcessor.kt new file mode 100644 index 0000000000..1773369575 --- /dev/null +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/network/OutgoingRequestsProcessor.kt @@ -0,0 +1,157 @@ +/* + * Copyright (c) 2022 New Vector Ltd + * + * 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.network + +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.async +import kotlinx.coroutines.coroutineScope +import kotlinx.coroutines.joinAll +import kotlinx.coroutines.launch +import kotlinx.coroutines.sync.Mutex +import kotlinx.coroutines.sync.withLock +import org.matrix.android.sdk.api.crypto.RoomEncryptionTrustLevel +import org.matrix.android.sdk.api.logger.LoggerTag +import org.matrix.android.sdk.internal.crypto.CryptoSessionInfoProvider +import org.matrix.android.sdk.internal.crypto.OlmMachine +import timber.log.Timber +import uniffi.olm.Request +import uniffi.olm.RequestType + +private val loggerTag = LoggerTag("OutgoingRequestsProcessor", LoggerTag.CRYPTO) + +internal class OutgoingRequestsProcessor(private val requestSender: RequestSender, + private val coroutineScope: CoroutineScope, + private val cryptoSessionInfoProvider: CryptoSessionInfoProvider, + private val shieldComputer: ShieldComputer) { + + fun interface ShieldComputer { + suspend fun compute(userIds: List): RoomEncryptionTrustLevel + } + + private val lock: Mutex = Mutex() + + suspend fun process(olmMachine: OlmMachine) { + lock.withLock { + coroutineScope { + Timber.v("OutgoingRequests: ${olmMachine.outgoingRequests()}") + olmMachine.outgoingRequests().map { + when (it) { + is Request.KeysUpload -> { + async { + uploadKeys(olmMachine, it) + } + } + is Request.KeysQuery -> { + async { + queryKeys(olmMachine, it) + } + } + is Request.ToDevice -> { + async { + sendToDevice(olmMachine, it) + } + } + is Request.KeysClaim -> { + async { + claimKeys(olmMachine, it) + } + } + is Request.RoomMessage -> { + async { + sendRoomMessage(olmMachine, it) + } + } + is Request.SignatureUpload -> { + async { + signatureUpload(olmMachine, it) + } + } + is Request.KeysBackup -> { + async { + // The rust-sdk won't ever produce KeysBackup requests here, + // those only get explicitly created. + } + } + } + }.joinAll() + } + } + } + + private suspend fun uploadKeys(olmMachine: OlmMachine, request: Request.KeysUpload) { + try { + val response = requestSender.uploadKeys(request) + olmMachine.markRequestAsSent(request.requestId, RequestType.KEYS_UPLOAD, response) + } catch (throwable: Throwable) { + Timber.tag(loggerTag.value).e(throwable, "## uploadKeys(): error") + } + } + + private suspend fun queryKeys(olmMachine: OlmMachine, request: Request.KeysQuery) { + try { + val response = requestSender.queryKeys(request) + olmMachine.markRequestAsSent(request.requestId, RequestType.KEYS_QUERY, response) + coroutineScope.updateShields(request.users) + } catch (throwable: Throwable) { + Timber.tag(loggerTag.value).e(throwable, "## queryKeys(): error") + } + } + + private fun CoroutineScope.updateShields(userIds: List) = launch { + cryptoSessionInfoProvider.getRoomsWhereUsersAreParticipating(userIds).forEach { roomId -> + val userGroup = cryptoSessionInfoProvider.getUserListForShieldComputation(roomId) + val shield = shieldComputer.compute(userGroup) + cryptoSessionInfoProvider.updateShieldForRoom(roomId, shield) + } + } + + private suspend fun sendToDevice(olmMachine: OlmMachine, request: Request.ToDevice) { + try { + requestSender.sendToDevice(request) + olmMachine.markRequestAsSent(request.requestId, RequestType.TO_DEVICE, "{}") + } catch (throwable: Throwable) { + Timber.tag(loggerTag.value).e(throwable, "## sendToDevice(): error") + } + } + + private suspend fun claimKeys(olmMachine: OlmMachine, request: Request.KeysClaim) { + try { + val response = requestSender.claimKeys(request) + olmMachine.markRequestAsSent(request.requestId, RequestType.KEYS_CLAIM, response) + } catch (throwable: Throwable) { + Timber.tag(loggerTag.value).e(throwable, "## claimKeys(): error") + } + } + + private suspend fun signatureUpload(olmMachine: OlmMachine, request: Request.SignatureUpload) { + try { + val response = requestSender.sendSignatureUpload(request) + olmMachine.markRequestAsSent(request.requestId, RequestType.SIGNATURE_UPLOAD, response) + } catch (throwable: Throwable) { + Timber.tag(loggerTag.value).e(throwable, "## signatureUpload(): error") + } + } + + private suspend fun sendRoomMessage(olmMachine: OlmMachine, request: Request.RoomMessage) { + try { + val response = requestSender.sendRoomMessage(request) + olmMachine.markRequestAsSent(request.requestId, RequestType.ROOM_MESSAGE, response) + } catch (throwable: Throwable) { + Timber.tag(loggerTag.value).e(throwable, "## sendRoomMessage(): error") + } + } +} diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/RequestSender.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/network/RequestSender.kt similarity index 98% rename from matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/RequestSender.kt rename to matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/network/RequestSender.kt index 2f593c0cad..9e54c33669 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/RequestSender.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/network/RequestSender.kt @@ -1,5 +1,5 @@ /* - * Copyright 2021 The Matrix.org Foundation C.I.C. + * Copyright (c) 2022 New Vector Ltd * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -14,7 +14,7 @@ * limitations under the License. */ -package org.matrix.android.sdk.internal.crypto +package org.matrix.android.sdk.internal.crypto.network import com.squareup.moshi.Moshi import com.squareup.moshi.Types @@ -59,7 +59,6 @@ import org.matrix.android.sdk.internal.crypto.tasks.UploadSigningKeysTask import org.matrix.android.sdk.internal.di.MoshiProvider 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.queue.EventSenderProcessor import timber.log.Timber import uniffi.olm.OutgoingVerificationRequest import uniffi.olm.Request diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/tasks/EncryptEventTask.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/tasks/EncryptEventTask.kt index b582930ab4..259f4cc34b 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/tasks/EncryptEventTask.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/tasks/EncryptEventTask.kt @@ -60,7 +60,7 @@ internal class DefaultEncryptEventTask @Inject constructor( ).toContent(), forwardingCurve25519KeyChain = emptyList(), senderCurve25519Key = result.eventContent["sender_key"] as? String, - claimedEd25519Key = cryptoService.getMyDevice().fingerprint() + claimedEd25519Key = cryptoService.getMyCryptoDevice().fingerprint() ) } else { null diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/verification/RustVerificationService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/verification/RustVerificationService.kt index 19ca332b42..3e5f200edc 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/verification/RustVerificationService.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/verification/RustVerificationService.kt @@ -176,13 +176,7 @@ internal class RustVerificationService @Inject constructor(private val olmMachin } override suspend fun markedLocallyAsManuallyVerified(userId: String, deviceID: String) { - // TODO this doesn't seem to be used anymore? - val device = olmMachine.getDevice(userId, deviceID) - device?.markAsTrusted() - } - - override fun onPotentiallyInterestingEventRoomFailToDecrypt(event: Event) { - // TODO This should be handled inside the rust-sdk decryption method + olmMachine.getDevice(userId, deviceID)?.markAsTrusted() } override fun getExistingTransaction( diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/DefaultSession.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/DefaultSession.kt index 1e533158a7..6327b28d0c 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/DefaultSession.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/DefaultSession.kt @@ -177,7 +177,6 @@ internal class DefaultSession @Inject constructor( assert(!isOpen) isOpen = true globalErrorHandler.listener = this - cryptoService.get().ensureDevice() uiHandler.post { lifecycleObservers.forEach { it.onSessionStarted(this) diff --git a/vector/src/main/java/im/vector/app/features/crypto/keysrequest/KeyRequestHandler.kt b/vector/src/main/java/im/vector/app/features/crypto/keysrequest/KeyRequestHandler.kt index 949037bc3c..274ac4a144 100644 --- a/vector/src/main/java/im/vector/app/features/crypto/keysrequest/KeyRequestHandler.kt +++ b/vector/src/main/java/im/vector/app/features/crypto/keysrequest/KeyRequestHandler.kt @@ -128,7 +128,7 @@ class KeyRequestHandler @Inject constructor( } if (deviceInfo.isUnknown) { - session?.cryptoService()?.setDeviceVerification(DeviceTrustLevel(crossSigningVerified = false, locallyVerified = false), userId, deviceId) + session?.cryptoService()?.verificationService()?.markedLocallyAsManuallyVerified(userId, deviceId) deviceInfo.trustLevel = DeviceTrustLevel(crossSigningVerified = false, locallyVerified = false) diff --git a/vector/src/main/java/im/vector/app/features/crypto/verification/VerificationBottomSheetViewModel.kt b/vector/src/main/java/im/vector/app/features/crypto/verification/VerificationBottomSheetViewModel.kt index 5a338cfb45..446f2f61d1 100644 --- a/vector/src/main/java/im/vector/app/features/crypto/verification/VerificationBottomSheetViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/crypto/verification/VerificationBottomSheetViewModel.kt @@ -132,7 +132,7 @@ class VerificationBottomSheetViewModel @AssistedInject constructor( viewModelScope.launch { val hasAnyOtherSession = session.cryptoService() - .getCryptoDeviceInfo(session.myUserId) + .getCryptoDeviceInfoList(session.myUserId) .any { it.deviceId != session.sessionParams.deviceId } diff --git a/vector/src/main/java/im/vector/app/features/home/UnknownDeviceDetectorSharedViewModel.kt b/vector/src/main/java/im/vector/app/features/home/UnknownDeviceDetectorSharedViewModel.kt index 537adcf00d..d374b97baa 100644 --- a/vector/src/main/java/im/vector/app/features/home/UnknownDeviceDetectorSharedViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/home/UnknownDeviceDetectorSharedViewModel.kt @@ -155,7 +155,7 @@ class UnknownDeviceDetectorSharedViewModel @AssistedInject constructor(@Assisted } private fun Session.firstTimeDeviceSeen() = flow { - val value = cryptoService().getCryptoDeviceInfo(myUserId) + val value = cryptoService().getCryptoDeviceInfoList(myUserId) .firstOrNull { it.deviceId == sessionParams.deviceId } ?.firstTimeSeenLocalTs ?: System.currentTimeMillis() diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/action/MessageActionsViewModel.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/action/MessageActionsViewModel.kt index db8629defb..46777f63f8 100644 --- a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/action/MessageActionsViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/action/MessageActionsViewModel.kt @@ -401,7 +401,7 @@ class MessageActionsViewModel @AssistedInject constructor(@Assisted ) { add(EventSharedAction.UseKeyBackup) } - if (session.cryptoService().getCryptoDeviceInfo(session.myUserId).size > 1 || + if (session.cryptoService().getCryptoDeviceInfoList(session.myUserId).size > 1 || timelineEvent.senderInfo.userId != session.myUserId) { add(EventSharedAction.ReRequestKey(timelineEvent.eventId)) } diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/helper/MessageInformationDataFactory.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/helper/MessageInformationDataFactory.kt index e2283fef81..18b50527bd 100644 --- a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/helper/MessageInformationDataFactory.kt +++ b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/helper/MessageInformationDataFactory.kt @@ -159,7 +159,7 @@ class MessageInformationDataFactory @Inject constructor(private val session: Ses .toModel() ?.deviceId ?.let { deviceId -> - session.cryptoService().getDeviceInfo(event.root.senderId ?: "", deviceId) + session.cryptoService().getCryptoDeviceInfo(event.root.senderId ?: "", deviceId) } when { sendingDevice == null -> { diff --git a/vector/src/main/java/im/vector/app/features/navigation/DefaultNavigator.kt b/vector/src/main/java/im/vector/app/features/navigation/DefaultNavigator.kt index e4ead15183..e7c1193858 100644 --- a/vector/src/main/java/im/vector/app/features/navigation/DefaultNavigator.kt +++ b/vector/src/main/java/im/vector/app/features/navigation/DefaultNavigator.kt @@ -234,7 +234,7 @@ class DefaultNavigator @Inject constructor( coroutineScope.launch { val session = sessionHolder.getSafeActiveSession() ?: return@launch val otherSessions = session.cryptoService() - .getCryptoDeviceInfo(session.myUserId) + .getCryptoDeviceInfoList(session.myUserId) .filter { it.deviceId != session.sessionParams.deviceId } .map { it.deviceId } if (context is AppCompatActivity) { diff --git a/vector/src/main/java/im/vector/app/features/roomprofile/members/RoomMemberListViewModel.kt b/vector/src/main/java/im/vector/app/features/roomprofile/members/RoomMemberListViewModel.kt index af57f3de99..f1a8173d53 100644 --- a/vector/src/main/java/im/vector/app/features/roomprofile/members/RoomMemberListViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/roomprofile/members/RoomMemberListViewModel.kt @@ -16,7 +16,6 @@ package im.vector.app.features.roomprofile.members -import androidx.lifecycle.asFlow import com.airbnb.mvrx.MavericksViewModelFactory import dagger.assisted.Assisted import dagger.assisted.AssistedFactory @@ -94,7 +93,7 @@ class RoomMemberListViewModel @AssistedInject constructor(@Assisted initialState if (room.isEncrypted()) { room.flow().liveRoomMembers(roomMemberQueryParams) .flatMapLatest { membersSummary -> - session.cryptoService().getLiveCryptoDeviceInfo(membersSummary.map { it.userId }) + session.cryptoService().getLiveCryptoDeviceInfoList(membersSummary.map { it.userId }) .catch { Timber.e(it) } .map { deviceList -> // If any key change, emit the userIds list diff --git a/vector/src/main/java/im/vector/app/features/settings/VectorSettingsSecurityPrivacyFragment.kt b/vector/src/main/java/im/vector/app/features/settings/VectorSettingsSecurityPrivacyFragment.kt index 67cca1a083..b7c04ac559 100644 --- a/vector/src/main/java/im/vector/app/features/settings/VectorSettingsSecurityPrivacyFragment.kt +++ b/vector/src/main/java/im/vector/app/features/settings/VectorSettingsSecurityPrivacyFragment.kt @@ -552,7 +552,7 @@ class VectorSettingsSecurityPrivacyFragment @Inject constructor( } // crypto section: device key (fingerprint) - val deviceInfo = session.cryptoService().getDeviceInfo(userId, deviceId) + val deviceInfo = session.cryptoService().getCryptoDeviceInfo(userId, deviceId) val fingerprint = deviceInfo?.fingerprint() if (fingerprint?.isNotEmpty() == true) { diff --git a/vector/src/main/java/im/vector/app/features/settings/crosssigning/CrossSigningSettingsViewModel.kt b/vector/src/main/java/im/vector/app/features/settings/crosssigning/CrossSigningSettingsViewModel.kt index 744a6eedd4..270cc93cc2 100644 --- a/vector/src/main/java/im/vector/app/features/settings/crosssigning/CrossSigningSettingsViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/settings/crosssigning/CrossSigningSettingsViewModel.kt @@ -131,7 +131,7 @@ class CrossSigningSettingsViewModel @AssistedInject constructor( private fun observeCrossSigning() { combine( - session.flow().liveMyDevicesInfo(), + session.flow().liveUserCryptoDevices(session.myUserId), session.flow().liveCrossSigningInfo(session.myUserId) ) { myDevicesInfo, mxCrossSigningInfo -> myDevicesInfo to mxCrossSigningInfo diff --git a/vector/src/main/java/im/vector/app/features/settings/devices/DevicesViewModel.kt b/vector/src/main/java/im/vector/app/features/settings/devices/DevicesViewModel.kt index 768a52cfb2..17d91f893c 100644 --- a/vector/src/main/java/im/vector/app/features/settings/devices/DevicesViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/settings/devices/DevicesViewModel.kt @@ -35,7 +35,6 @@ import im.vector.app.core.utils.PublishDataSource import im.vector.app.features.auth.ReAuthActivity import im.vector.app.features.login.ReAuthHelper import im.vector.lib.core.utils.flow.throttleFirst -import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.distinctUntilChanged import kotlinx.coroutines.flow.launchIn @@ -43,8 +42,6 @@ import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.onEach import kotlinx.coroutines.flow.sample import kotlinx.coroutines.launch -import org.matrix.android.sdk.api.MatrixCallback -import org.matrix.android.sdk.api.NoOpMatrixCallback import org.matrix.android.sdk.api.auth.UIABaseAuth import org.matrix.android.sdk.api.auth.UserInteractiveAuthInterceptor import org.matrix.android.sdk.api.auth.UserPasswordAuth @@ -53,17 +50,14 @@ import org.matrix.android.sdk.api.auth.registration.RegistrationFlowResponse import org.matrix.android.sdk.api.auth.registration.nextUncompletedStage import org.matrix.android.sdk.api.failure.Failure import org.matrix.android.sdk.api.session.Session -import org.matrix.android.sdk.api.session.crypto.verification.VerificationMethod import org.matrix.android.sdk.api.session.crypto.verification.VerificationService import org.matrix.android.sdk.api.session.crypto.verification.VerificationTransaction import org.matrix.android.sdk.api.session.crypto.verification.VerificationTxState import org.matrix.android.sdk.flow.flow -import org.matrix.android.sdk.internal.crypto.crosssigning.DeviceTrustLevel import org.matrix.android.sdk.internal.crypto.crosssigning.fromBase64 import org.matrix.android.sdk.internal.crypto.model.CryptoDeviceInfo import org.matrix.android.sdk.internal.crypto.model.rest.DefaultBaseAuth import org.matrix.android.sdk.internal.crypto.model.rest.DeviceInfo -import org.matrix.android.sdk.internal.util.awaitCallback import timber.log.Timber import javax.net.ssl.HttpsURLConnection import kotlin.coroutines.Continuation @@ -277,8 +271,7 @@ class DevicesViewModel @AssistedInject constructor( } } else { // legacy - session.cryptoService().setDeviceVerification( - DeviceTrustLevel(crossSigningVerified = false, locallyVerified = true), + session.cryptoService().verificationService().markedLocallyAsManuallyVerified( action.cryptoDeviceInfo.userId, action.cryptoDeviceInfo.deviceId) } @@ -297,27 +290,21 @@ class DevicesViewModel @AssistedInject constructor( } private fun handleRename(action: DevicesAction.Rename) { - session.cryptoService().setDeviceName(action.deviceId, action.newName, object : MatrixCallback { - override fun onSuccess(data: Unit) { + viewModelScope.launch { + try { + session.cryptoService().setDeviceName(action.deviceId, action.newName) setState { - copy( - request = Success(data) - ) + copy(request = Success(Unit)) } // force settings update queryRefreshDevicesList() - } - - override fun onFailure(failure: Throwable) { + } catch (failure: Throwable) { setState { - copy( - request = Fail(failure) - ) + copy(request = Fail(failure)) } - _viewEvents.post(DevicesViewEvents.Failure(failure)) } - }) + } } /** @@ -332,39 +319,32 @@ class DevicesViewModel @AssistedInject constructor( ) } - viewModelScope.launch(Dispatchers.IO) { + viewModelScope.launch { try { - awaitCallback { - session.cryptoService().deleteDevice(deviceId, object : UserInteractiveAuthInterceptor { - override fun performStage(flowResponse: RegistrationFlowResponse, errCode: String?, promise: Continuation) { - Timber.d("## UIA : deleteDevice UIA") - if (flowResponse.nextUncompletedStage() == LoginFlowTypes.PASSWORD && reAuthHelper.data != null && errCode == null) { - UserPasswordAuth( - session = null, - user = session.myUserId, - password = reAuthHelper.data - ).let { promise.resume(it) } - } else { - Timber.d("## UIA : deleteDevice UIA > start reauth activity") - _viewEvents.post(DevicesViewEvents.RequestReAuth(flowResponse, errCode)) - pendingAuth = DefaultBaseAuth(session = flowResponse.session) - uiaContinuation = promise - } + session.cryptoService().deleteDevice(deviceId, object : UserInteractiveAuthInterceptor { + override fun performStage(flowResponse: RegistrationFlowResponse, errCode: String?, promise: Continuation) { + Timber.d("## UIA : deleteDevice UIA") + if (flowResponse.nextUncompletedStage() == LoginFlowTypes.PASSWORD && reAuthHelper.data != null && errCode == null) { + UserPasswordAuth( + session = null, + user = session.myUserId, + password = reAuthHelper.data + ).let { promise.resume(it) } + } else { + Timber.d("## UIA : deleteDevice UIA > start reauth activity") + _viewEvents.post(DevicesViewEvents.RequestReAuth(flowResponse, errCode)) + pendingAuth = DefaultBaseAuth(session = flowResponse.session) + uiaContinuation = promise } - }, it) - } + } + }) setState { - copy( - request = Success(Unit) - ) + copy(request = Success(Unit)) } - // force settings update queryRefreshDevicesList() } catch (failure: Throwable) { setState { - copy( - request = Fail(failure) - ) + copy(request = Fail(failure)) } if (failure is Failure.OtherServerError && failure.httpCode == HttpsURLConnection.HTTP_UNAUTHORIZED) { _viewEvents.post(DevicesViewEvents.Failure(Exception(stringProvider.getString(R.string.authentication_error)))) diff --git a/vector/src/test/java/im/vector/app/test/fakes/FakeCryptoService.kt b/vector/src/test/java/im/vector/app/test/fakes/FakeCryptoService.kt index 1ec1f31b45..625c0675c1 100644 --- a/vector/src/test/java/im/vector/app/test/fakes/FakeCryptoService.kt +++ b/vector/src/test/java/im/vector/app/test/fakes/FakeCryptoService.kt @@ -30,9 +30,9 @@ class FakeCryptoService : CryptoService by mockk() { override fun getLiveCryptoDeviceInfo() = MutableLiveData(cryptoDeviceInfos.values.toList()) - override fun getLiveCryptoDeviceInfo(userId: String) = getLiveCryptoDeviceInfo(listOf(userId)) + override fun getLiveCryptoDeviceInfoList(userId: String) = getLiveCryptoDeviceInfo(listOf(userId)) - override fun getLiveCryptoDeviceInfo(userIds: List) = MutableLiveData( + override fun getLiveCryptoDeviceInfoList(userIds: List) = MutableLiveData( cryptoDeviceInfos.filterKeys { userIds.contains(it) }.values.toList() ) }