Continue cleaning up/adding suspend

This commit is contained in:
ganfra 2022-05-06 16:12:53 +02:00
parent 69ede523b6
commit b4bc56ff5c
35 changed files with 420 additions and 374 deletions

View File

@ -125,9 +125,9 @@ class FlowSession(private val session: Session) {
}
fun liveUserCryptoDevices(userId: String): Flow<List<CryptoDeviceInfo>> {
return session.cryptoService().getLiveCryptoDeviceInfo(userId)
return session.cryptoService().getLiveCryptoDeviceInfoList(userId)
.startWith(session.coroutineDispatchers.io) {
session.cryptoService().getCryptoDeviceInfo(userId)
session.cryptoService().getCryptoDeviceInfoList(userId)
}
}

View File

@ -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

View File

@ -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<OlmSession>(oldSession)!!), myDevice.identityKey()!!)
Thread.sleep(6_000)

View File

@ -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)

View File

@ -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
}
}

View File

@ -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)

View File

@ -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<String> = emptyList(),
codes: List<String> = 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<VerificationTransaction>()
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
)
}

View File

@ -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<VerificationMethod>): 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!!
}
}

View File

@ -50,9 +50,9 @@ interface CryptoService {
fun keysBackupService(): KeysBackupService
fun setDeviceName(deviceId: String, deviceName: String, callback: MatrixCallback<Unit>)
suspend fun setDeviceName(deviceId: String, deviceName: String)
fun deleteDevice(deviceId: String, userInteractiveAuthInterceptor: UserInteractiveAuthInterceptor, callback: MatrixCallback<Unit>)
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<CryptoDeviceInfo>
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<List<DeviceInfo>>
fun getDeviceInfo(deviceId: String, callback: MatrixCallback<DeviceInfo>)
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<MXEventDecryptionResult>)
fun getEncryptionAlgorithm(roomId: String): String?
fun shouldEncryptForInvitedMembers(roomId: String): Boolean
suspend fun downloadKeys(userIds: List<String>, forceDownload: Boolean = false): MXUsersDevicesMap<CryptoDeviceInfo>
suspend fun getCryptoDeviceInfo(userId: String): List<CryptoDeviceInfo>
suspend fun getCryptoDeviceInfoList(userId: String): List<CryptoDeviceInfo>
fun getLiveCryptoDeviceInfo(userId: String): Flow<List<CryptoDeviceInfo>>
fun getLiveCryptoDeviceInfoList(userId: String): Flow<List<CryptoDeviceInfo>>
fun getLiveCryptoDeviceInfo(userIds: List<String>): Flow<List<CryptoDeviceInfo>>
fun getLiveCryptoDeviceInfoList(userIds: List<String>): Flow<List<CryptoDeviceInfo>>
fun addNewSessionListener(newSessionListener: NewSessionListener)

View File

@ -121,5 +121,4 @@ interface VerificationService {
}
}
fun onPotentiallyInterestingEventRoomFailToDecrypt(event: Event)
}

View File

@ -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<String, Mutex> = ConcurrentHashMap()
fun onStateEvent(roomId: String, event: Event) {
@ -179,38 +173,19 @@ internal class DefaultCryptoService @Inject constructor(
private val gossipingBuffer = mutableListOf<Event>()
override fun setDeviceName(deviceId: String, deviceName: String, callback: MatrixCallback<Unit>) {
setDeviceNameTask
.configureWith(SetDeviceNameTask.Params(deviceId, deviceName)) {
this.executionThread = TaskThread.CRYPTO
this.callback = object : MatrixCallback<Unit> {
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<Unit>) {
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<DeviceInfo>) {
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<CryptoDeviceInfo> {
override suspend fun getCryptoDeviceInfoList(userId: String): List<CryptoDeviceInfo> {
return olmMachine.getCryptoDeviceInfo(userId)
}
override fun getLiveCryptoDeviceInfo(userId: String): Flow<List<CryptoDeviceInfo>> {
return getLiveCryptoDeviceInfo(listOf(userId))
}
override fun getLiveCryptoDeviceInfoList(userId: String) = getLiveCryptoDeviceInfoList(listOf(userId))
override fun getLiveCryptoDeviceInfo(userIds: List<String>): Flow<List<CryptoDeviceInfo>> {
override fun getLiveCryptoDeviceInfoList(userIds: List<String>): Flow<List<CryptoDeviceInfo>> {
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<CryptoDeviceInfo> {
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<MXEventDecryptionResult>) {
// 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
*

View File

@ -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

View File

@ -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<CryptoDeviceInfo> {
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
*/
}
/**

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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
}
}

View File

@ -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<String>): 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<String>) = 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")
}
}
}

View File

@ -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

View File

@ -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

View File

@ -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(

View File

@ -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)

View File

@ -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)

View File

@ -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
}

View File

@ -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()

View File

@ -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))
}

View File

@ -159,7 +159,7 @@ class MessageInformationDataFactory @Inject constructor(private val session: Ses
.toModel<EncryptedEventContent>()
?.deviceId
?.let { deviceId ->
session.cryptoService().getDeviceInfo(event.root.senderId ?: "", deviceId)
session.cryptoService().getCryptoDeviceInfo(event.root.senderId ?: "", deviceId)
}
when {
sendingDevice == null -> {

View File

@ -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) {

View File

@ -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

View File

@ -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) {

View File

@ -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

View File

@ -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<Unit> {
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<Unit> {
session.cryptoService().deleteDevice(deviceId, object : UserInteractiveAuthInterceptor {
override fun performStage(flowResponse: RegistrationFlowResponse, errCode: String?, promise: Continuation<UIABaseAuth>) {
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<UIABaseAuth>) {
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))))

View File

@ -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<String>) = MutableLiveData(
override fun getLiveCryptoDeviceInfoList(userIds: List<String>) = MutableLiveData(
cryptoDeviceInfos.filterKeys { userIds.contains(it) }.values.toList()
)
}