Refactor + share secret window implementation

This commit is contained in:
Valere 2020-03-23 11:13:26 +01:00
parent 0c1f30208d
commit 4f70c40b1a
16 changed files with 340 additions and 36 deletions

View file

@ -266,8 +266,8 @@ class CommonTestHelper(context: Context) {
* @param latch
* @throws InterruptedException
*/
fun await(latch: CountDownLatch) {
assertTrue(latch.await(TestConstants.timeOutMillis, TimeUnit.MILLISECONDS))
fun await(latch: CountDownLatch, timout: Long? = TestConstants.timeOutMillis) {
assertTrue(latch.await(timout ?: TestConstants.timeOutMillis, TimeUnit.MILLISECONDS))
}
fun retryPeriodicallyWithLatch(latch: CountDownLatch, condition: (() -> Boolean)) {

View file

@ -19,6 +19,12 @@ package im.vector.matrix.android.internal.crypto.gossiping
import android.util.Log
import androidx.test.ext.junit.runners.AndroidJUnit4
import im.vector.matrix.android.InstrumentedTest
import im.vector.matrix.android.api.session.crypto.verification.IncomingSasVerificationTransaction
import im.vector.matrix.android.api.session.crypto.verification.SasVerificationTransaction
import im.vector.matrix.android.api.session.crypto.verification.VerificationMethod
import im.vector.matrix.android.api.session.crypto.verification.VerificationService
import im.vector.matrix.android.api.session.crypto.verification.VerificationTransaction
import im.vector.matrix.android.api.session.crypto.verification.VerificationTxState
import im.vector.matrix.android.api.session.events.model.toModel
import im.vector.matrix.android.api.session.room.model.RoomDirectoryVisibility
import im.vector.matrix.android.api.session.room.model.create.CreateRoomParams
@ -28,7 +34,11 @@ import im.vector.matrix.android.common.TestConstants
import im.vector.matrix.android.internal.crypto.GossipingRequestState
import im.vector.matrix.android.internal.crypto.OutgoingGossipingRequestState
import im.vector.matrix.android.internal.crypto.crosssigning.DeviceTrustLevel
import im.vector.matrix.android.internal.crypto.model.CryptoDeviceInfo
import im.vector.matrix.android.internal.crypto.model.MXUsersDevicesMap
import im.vector.matrix.android.internal.crypto.model.event.EncryptedEventContent
import im.vector.matrix.android.internal.crypto.model.rest.UserPasswordAuth
import junit.framework.TestCase.assertEquals
import junit.framework.TestCase.assertNotNull
import junit.framework.TestCase.assertTrue
import junit.framework.TestCase.fail
@ -174,4 +184,104 @@ class KeyShareTests : InstrumentedTest {
mTestHelper.signOutAndClose(aliceSession)
mTestHelper.signOutAndClose(aliceSession2)
}
@Test
fun test_ShareSSSSSecret() {
val aliceSession1 = mTestHelper.createAccount(TestConstants.USER_ALICE, SessionTestParams(true))
mTestHelper.doSync<Unit> {
aliceSession1.cryptoService().crossSigningService()
.initializeCrossSigning(UserPasswordAuth(
user = aliceSession1.myUserId,
password = TestConstants.PASSWORD
), it)
}
val aliceSession2 = mTestHelper.logIntoAccount(aliceSession1.myUserId, SessionTestParams(true))
val aliceVerificationService1 = aliceSession1.cryptoService().verificationService()
val aliceVerificationService2 = aliceSession2.cryptoService().verificationService()
//force keys download
mTestHelper.doSync<MXUsersDevicesMap<CryptoDeviceInfo>> {
aliceSession1.cryptoService().downloadKeys(listOf(aliceSession1.myUserId), true, it)
}
mTestHelper.doSync<MXUsersDevicesMap<CryptoDeviceInfo>> {
aliceSession2.cryptoService().downloadKeys(listOf(aliceSession2.myUserId), true, it)
}
var session1ShortCode: String? = null
var session2ShortCode: String? = null
aliceVerificationService1.addListener(object : VerificationService.Listener {
override fun transactionUpdated(tx: VerificationTransaction) {
Log.d("TEST", "AA: tx incoming?:${tx.isIncoming} state ${tx.state}")
if (tx is SasVerificationTransaction) {
if (tx.state == VerificationTxState.OnStarted) {
(tx as IncomingSasVerificationTransaction).performAccept()
}
if (tx.state == VerificationTxState.ShortCodeReady) {
session1ShortCode = tx.getDecimalCodeRepresentation()
tx.userHasVerifiedShortCode()
}
}
}
})
aliceVerificationService2.addListener(object : VerificationService.Listener {
override fun transactionUpdated(tx: VerificationTransaction) {
Log.d("TEST", "BB: tx incoming?:${tx.isIncoming} state ${tx.state}")
if (tx is SasVerificationTransaction) {
if (tx.state == VerificationTxState.ShortCodeReady) {
session2ShortCode = tx.getDecimalCodeRepresentation()
tx.userHasVerifiedShortCode()
}
}
}
})
val txId: String = "m.testVerif12"
aliceVerificationService2.beginKeyVerification(VerificationMethod.SAS, aliceSession1.myUserId, aliceSession1.sessionParams.credentials.deviceId
?: "", txId)
waitWithLatch { latch ->
retryPeriodicallyWithLatch(latch) {
aliceSession1.cryptoService().getDeviceInfo(aliceSession1.myUserId, aliceSession2.sessionParams.credentials.deviceId ?: "")?.isVerified == true
}
}
assertNotNull(session1ShortCode)
Log.d("TEST", "session1ShortCode: $session1ShortCode")
assertNotNull(session2ShortCode)
Log.d("TEST", "session2ShortCode: $session2ShortCode")
assertEquals(session1ShortCode, session2ShortCode)
// SSK and USK private keys should have been shared
waitWithLatch(300_000) { latch ->
retryPeriodicallyWithLatch(latch) {
aliceSession2.cryptoService().crossSigningService().canCrossSign()
}
}
}
fun retryPeriodicallyWithLatch(latch: CountDownLatch, condition: (() -> Boolean)) {
GlobalScope.launch {
while (true) {
delay(1000)
if (condition()) {
latch.countDown()
return@launch
}
}
}
}
fun waitWithLatch(timeout: Long? = null, block: (CountDownLatch) -> Unit) {
val latch = CountDownLatch(1)
block(latch)
mTestHelper.await(latch, timeout)
}
}

View file

@ -140,7 +140,7 @@ internal class DefaultCryptoService @Inject constructor(
private val crossSigningService: DefaultCrossSigningService,
//
private val incomingRoomKeyRequestManager: IncomingRoomKeyRequestManager,
private val incomingGossipingRequestManager: IncomingGossipingRequestManager,
//
private val outgoingGossipingRequestManager: OutgoingGossipingRequestManager,
// Actions
@ -317,7 +317,7 @@ internal class DefaultCryptoService @Inject constructor(
deviceListManager.invalidateAllDeviceLists()
deviceListManager.refreshOutdatedDeviceLists()
} else {
incomingRoomKeyRequestManager.processReceivedGossipingRequests()
incomingGossipingRequestManager.processReceivedGossipingRequests()
}
}.fold(
{
@ -376,7 +376,7 @@ internal class DefaultCryptoService @Inject constructor(
// Make sure we process to-device messages before generating new one-time-keys #2782
deviceListManager.refreshOutdatedDeviceLists()
oneTimeKeysUploader.maybeUploadOneTimeKeys()
incomingRoomKeyRequestManager.processReceivedGossipingRequests()
incomingGossipingRequestManager.processReceivedGossipingRequests()
}
}
}
@ -709,7 +709,7 @@ internal class DefaultCryptoService @Inject constructor(
// save audit trail
cryptoStore.saveGossipingEvent(event)
// Requests are stacked, and will be handled one by one at the end of the sync (onSyncComplete)
incomingRoomKeyRequestManager.onGossipingRequestEvent(event)
incomingGossipingRequestManager.onGossipingRequestEvent(event)
}
EventType.SEND_SECRET -> {
cryptoStore.saveGossipingEvent(event)
@ -1111,7 +1111,7 @@ internal class DefaultCryptoService @Inject constructor(
* @param listener listener
*/
override fun addRoomKeysRequestListener(listener: GossipingRequestListener) {
incomingRoomKeyRequestManager.addRoomKeysRequestListener(listener)
incomingGossipingRequestManager.addRoomKeysRequestListener(listener)
}
/**
@ -1120,7 +1120,7 @@ internal class DefaultCryptoService @Inject constructor(
* @param listener listener
*/
override fun removeRoomKeysRequestListener(listener: GossipingRequestListener) {
incomingRoomKeyRequestManager.removeRoomKeysRequestListener(listener)
incomingGossipingRequestManager.removeRoomKeysRequestListener(listener)
}
/**

View file

@ -26,6 +26,7 @@ enum class GossipingRequestState {
PENDING,
REJECTED,
ACCEPTED,
FAILED_TO_ACCEPTED,
// USER_REJECTED,
UNABLE_TO_PROCESS,
CANCELLED_BY_REQUESTER,

View file

@ -32,7 +32,7 @@ import timber.log.Timber
import javax.inject.Inject
@SessionScope
internal class IncomingRoomKeyRequestManager @Inject constructor(
internal class IncomingGossipingRequestManager @Inject constructor(
private val credentials: Credentials,
private val cryptoStore: IMXCryptoStore,
private val cryptoConfig: MXCryptoConfig,
@ -51,6 +51,32 @@ internal class IncomingRoomKeyRequestManager @Inject constructor(
receivedGossipingRequests.addAll(cryptoStore.getPendingIncomingGossipingRequests())
}
// Recently verified devices (map of deviceId and timestamp)
private val recentlyVerifiedDevices = HashMap<String, Long>()
/**
* Called when a session has been verified.
* This information can be used by the manager to decide whether or not to fullfil gossiping requests
*/
fun onVerificationCompleteForDevice(deviceId: String) {
// For now we just keep an in memory cache
synchronized(recentlyVerifiedDevices) {
recentlyVerifiedDevices[deviceId] = System.currentTimeMillis()
}
}
private fun hasBeenVerifiedLessThanFiveMinutesFromNow(deviceId: String): Boolean {
val verifTimestamp: Long?
synchronized(recentlyVerifiedDevices) {
verifTimestamp = recentlyVerifiedDevices[deviceId]
}
if (verifTimestamp == null) return false
val age = System.currentTimeMillis() - verifTimestamp
return age < FIVE_MINUTES_IN_MILLIS
}
/**
* Called when we get an m.room_key_request event
* It must be called on CryptoThread
@ -257,9 +283,12 @@ internal class IncomingRoomKeyRequestManager @Inject constructor(
}?.let { secretValue ->
// TODO check if locally trusted and not outdated
Timber.i("## processIncomingSecretShareRequest() : Sharing secret $secretName with $device locally trusted")
if (isDeviceLocallyVerified == true) {
if (isDeviceLocallyVerified == true && hasBeenVerifiedLessThanFiveMinutesFromNow(deviceId)) {
secretSecretCryptoProvider.shareSecretWithDevice(request, secretValue)
cryptoStore.updateGossipingRequestState(request, GossipingRequestState.ACCEPTED)
} else {
Timber.v("## processIncomingSecretShareRequest() : Can't share secret $secretName with $device, verification too old")
cryptoStore.updateGossipingRequestState(request, GossipingRequestState.REJECTED)
}
return
}
@ -340,4 +369,8 @@ internal class IncomingRoomKeyRequestManager @Inject constructor(
gossipingRequestListeners.remove(listener)
}
}
companion object {
private const val FIVE_MINUTES_IN_MILLIS = 5 * 60 * 1000
}
}

View file

@ -0,0 +1,127 @@
/*
* Copyright (c) 2020 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 im.vector.matrix.android.internal.crypto
import android.content.Context
import androidx.work.CoroutineWorker
import androidx.work.Data
import androidx.work.WorkerParameters
import com.squareup.moshi.JsonClass
import im.vector.matrix.android.api.auth.data.Credentials
import im.vector.matrix.android.api.failure.shouldBeRetried
import im.vector.matrix.android.api.session.events.model.Event
import im.vector.matrix.android.api.session.events.model.EventType
import im.vector.matrix.android.api.session.events.model.LocalEcho
import im.vector.matrix.android.api.session.events.model.toContent
import im.vector.matrix.android.internal.crypto.actions.MessageEncrypter
import im.vector.matrix.android.internal.crypto.model.MXUsersDevicesMap
import im.vector.matrix.android.internal.crypto.model.event.SecretSendEventContent
import im.vector.matrix.android.internal.crypto.store.IMXCryptoStore
import im.vector.matrix.android.internal.crypto.tasks.SendToDeviceTask
import im.vector.matrix.android.internal.worker.WorkerParamsFactory
import im.vector.matrix.android.internal.worker.getSessionComponent
import org.greenrobot.eventbus.EventBus
import timber.log.Timber
import javax.inject.Inject
internal class SendGossipWorker(context: Context,
params: WorkerParameters)
: CoroutineWorker(context, params) {
@JsonClass(generateAdapter = true)
internal data class Params(
val sessionId: String,
val secretValue: String,
val request: IncomingSecretShareRequest
)
@Inject lateinit var sendToDeviceTask: SendToDeviceTask
@Inject lateinit var cryptoStore: IMXCryptoStore
@Inject lateinit var eventBus: EventBus
@Inject lateinit var credentials: Credentials
// @Inject lateinit var secretSecretCryptoProvider: ShareSecretCryptoProvider
@Inject lateinit var messageEncrypter: MessageEncrypter
override suspend fun doWork(): Result {
val errorOutputData = Data.Builder().putBoolean("failed", true).build()
val params = WorkerParamsFactory.fromData<Params>(inputData)
?: return Result.success(errorOutputData)
val sessionComponent = getSessionComponent(params.sessionId)
?: return Result.success(errorOutputData).also {
// TODO, can this happen? should I update local echo?
Timber.e("Unknown Session, cannot send message, sessionId: ${params.sessionId}")
}
sessionComponent.inject(this)
val localId = LocalEcho.createLocalEchoId()
val eventType: String = EventType.SEND_SECRET
val toDeviceContent = SecretSendEventContent(
requestId = params.request.requestId ?: "",
secretValue = params.secretValue
)
val requestingUserId = params.request.userId ?: ""
val requestingDeviceId = params.request.deviceId ?: ""
val deviceInfo = cryptoStore.getUserDevice(requestingUserId, requestingDeviceId)
?: return Result.success(errorOutputData).also {
cryptoStore.updateGossipingRequestState(params.request, GossipingRequestState.FAILED_TO_ACCEPTED)
Timber.e("Unknown deviceInfo, cannot send message, sessionId: ${params.request.deviceId}")
}
val payloadJson = mutableMapOf<String, Any>("type" to EventType.SEND_SECRET)
payloadJson["content"] = toDeviceContent.toContent()
val sendToDeviceMap = MXUsersDevicesMap<Any>()
try {
val encodedPayload = messageEncrypter.encryptMessage(payloadJson, listOf(deviceInfo))
sendToDeviceMap.setObject(requestingUserId, requestingDeviceId, encodedPayload)
} catch (failure: Throwable) {
Timber.e("## Fail to encrypt gossip + ${failure.localizedMessage}")
}
cryptoStore.saveGossipingEvent(Event(
type = eventType,
content = toDeviceContent.toContent(),
senderId = credentials.userId
).also {
it.ageLocalTs = System.currentTimeMillis()
})
try {
sendToDeviceTask.execute(
SendToDeviceTask.Params(
eventType = eventType,
contentMap = sendToDeviceMap,
transactionId = localId
)
)
cryptoStore.updateGossipingRequestState(params.request, GossipingRequestState.ACCEPTED)
return Result.success()
} catch (exception: Throwable) {
return if (exception.shouldBeRetried()) {
Result.retry()
} else {
cryptoStore.updateGossipingRequestState(params.request, GossipingRequestState.FAILED_TO_ACCEPTED)
Result.success(errorOutputData)
}
}
}
}

View file

@ -18,16 +18,17 @@ package im.vector.matrix.android.internal.crypto
import im.vector.matrix.android.api.session.events.model.Event
import im.vector.matrix.android.api.session.events.model.EventType
import im.vector.matrix.android.api.session.events.model.toContent
import im.vector.matrix.android.internal.crypto.actions.MessageEncrypter
import im.vector.matrix.android.internal.crypto.algorithms.olm.MXOlmDecryptionFactory
import im.vector.matrix.android.internal.crypto.model.MXUsersDevicesMap
import im.vector.matrix.android.internal.crypto.model.event.SecretSendEventContent
import im.vector.matrix.android.internal.crypto.store.IMXCryptoStore
import im.vector.matrix.android.internal.crypto.tasks.SendToDeviceTask
import im.vector.matrix.android.internal.di.UserId
import im.vector.matrix.android.internal.util.MatrixCoroutineDispatchers
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.launch
import kotlinx.coroutines.runBlocking
import timber.log.Timber
import javax.inject.Inject
@ -35,6 +36,7 @@ internal class ShareSecretCryptoProvider @Inject constructor(
val messageEncrypter: MessageEncrypter,
val sendToDeviceTask: SendToDeviceTask,
val deviceListManager: DeviceListManager,
@UserId val myUserId: String,
private val olmDecryptionFactory: MXOlmDecryptionFactory,
val cryptoCoroutineScope: CoroutineScope,
val cryptoStore: IMXCryptoStore,
@ -43,32 +45,38 @@ internal class ShareSecretCryptoProvider @Inject constructor(
fun shareSecretWithDevice(request: IncomingSecretShareRequest, secretValue: String) {
val userId = request.userId ?: return
cryptoCoroutineScope.launch(coroutineDispatchers.crypto) {
runCatching { deviceListManager.downloadKeys(listOf(userId), false) }
.mapCatching {
val deviceId = request.deviceId
val deviceInfo = cryptoStore.getUserDevice(userId, deviceId ?: "") ?: throw RuntimeException()
// runCatching { deviceListManager.downloadKeys(listOf(userId), false) }
// .mapCatching {
val deviceId = request.deviceId
val deviceInfo = cryptoStore.getUserDevice(userId, deviceId ?: "") ?: return@launch
Timber.i("## shareSecretWithDevice() : sharing secret ${request.secretName} with device $userId:$deviceId")
val payloadJson = mutableMapOf<String, Any>("type" to EventType.SEND_SECRET)
payloadJson["content"] = SecretSendEventContent(
requestId = request.requestId ?: "",
secretValue = secretValue
)
Timber.i("## shareSecretWithDevice() : sharing secret ${request.secretName} with device $userId:$deviceId")
val encodedPayload = messageEncrypter.encryptMessage(payloadJson, listOf(deviceInfo))
val sendToDeviceMap = MXUsersDevicesMap<Any>()
sendToDeviceMap.setObject(userId, deviceId, encodedPayload)
Timber.i("## shareSecretWithDevice() : sending to $userId:$deviceId")
val sendToDeviceParams = SendToDeviceTask.Params(EventType.ENCRYPTED, sendToDeviceMap)
sendToDeviceTask.execute(sendToDeviceParams)
}
val payloadJson = mutableMapOf<String, Any>("type" to EventType.SEND_SECRET)
val secretContent = SecretSendEventContent(
requestId = request.requestId ?: "",
secretValue = secretValue
)
payloadJson["content"] = secretContent.toContent()
cryptoStore.saveGossipingEvent(Event(
type = EventType.SEND_SECRET,
content = secretContent.toContent(),
senderId = myUserId
))
val encodedPayload = messageEncrypter.encryptMessage(payloadJson, listOf(deviceInfo))
val sendToDeviceMap = MXUsersDevicesMap<Any>()
sendToDeviceMap.setObject(userId, deviceId, encodedPayload)
Timber.i("## shareSecretWithDevice() : sending to $userId:$deviceId")
val sendToDeviceParams = SendToDeviceTask.Params(EventType.ENCRYPTED, sendToDeviceMap)
sendToDeviceTask.execute(sendToDeviceParams)
// }
}
}
fun decryptEvent(event: Event): MXEventDecryptionResult {
return runBlocking(coroutineDispatchers.crypto) {
olmDecryptionFactory.create().decryptEvent(event, ShareSecretCryptoProvider::class.java.name ?: "")
}
return olmDecryptionFactory.create().decryptEvent(event, ShareSecretCryptoProvider::class.java.name ?: "")
}
}

View file

@ -25,7 +25,6 @@ import im.vector.matrix.android.api.util.Optional
import im.vector.matrix.android.internal.crypto.DeviceListManager
import im.vector.matrix.android.internal.crypto.MXOlmDevice
import im.vector.matrix.android.internal.crypto.MyDeviceInfoHolder
import im.vector.matrix.android.internal.crypto.OutgoingGossipingRequestManager
import im.vector.matrix.android.internal.crypto.model.CryptoCrossSigningKey
import im.vector.matrix.android.internal.crypto.model.KeyUsage
import im.vector.matrix.android.internal.crypto.model.rest.UploadSignatureQueryBuilder
@ -62,7 +61,6 @@ internal class DefaultCrossSigningService @Inject constructor(
private val taskExecutor: TaskExecutor,
private val coroutineDispatchers: MatrixCoroutineDispatchers,
private val cryptoCoroutineScope: CoroutineScope,
private val outgoingGossipingRequestManager: OutgoingGossipingRequestManager,
private val eventBus: EventBus) : CrossSigningService, DeviceListManager.UserDevicesUpdateListener {
private var olmUtility: OlmUtility? = null
@ -598,7 +596,7 @@ internal class DefaultCrossSigningService @Inject constructor(
}
override fun canCrossSign(): Boolean {
return checkSelfTrust().isVerified() && cryptoStore.getCrossSigningPrivateKeys()?.selfSigned != null
return cryptoStore.getCrossSigningPrivateKeys()?.selfSigned != null
}
override fun trustUser(otherUserId: String, callback: MatrixCallback<Unit>) {

View file

@ -23,6 +23,7 @@ import im.vector.matrix.android.api.session.crypto.verification.IncomingSasVerif
import im.vector.matrix.android.api.session.crypto.verification.SasMode
import im.vector.matrix.android.api.session.crypto.verification.VerificationTxState
import im.vector.matrix.android.api.session.events.model.EventType
import im.vector.matrix.android.internal.crypto.IncomingGossipingRequestManager
import im.vector.matrix.android.internal.crypto.OutgoingGossipingRequestManager
import im.vector.matrix.android.internal.crypto.actions.SetDeviceVerificationAction
import im.vector.matrix.android.internal.crypto.store.IMXCryptoStore
@ -35,6 +36,7 @@ internal class DefaultIncomingSASDefaultVerificationTransaction(
private val cryptoStore: IMXCryptoStore,
crossSigningService: CrossSigningService,
outgoingGossipingRequestManager: OutgoingGossipingRequestManager,
incomingGossipingRequestManager: IncomingGossipingRequestManager,
deviceFingerprint: String,
transactionId: String,
otherUserID: String,
@ -46,6 +48,7 @@ internal class DefaultIncomingSASDefaultVerificationTransaction(
cryptoStore,
crossSigningService,
outgoingGossipingRequestManager,
incomingGossipingRequestManager,
deviceFingerprint,
transactionId,
otherUserID,

View file

@ -20,6 +20,7 @@ import im.vector.matrix.android.api.session.crypto.verification.CancelCode
import im.vector.matrix.android.api.session.crypto.verification.OutgoingSasVerificationTransaction
import im.vector.matrix.android.api.session.crypto.verification.VerificationTxState
import im.vector.matrix.android.api.session.events.model.EventType
import im.vector.matrix.android.internal.crypto.IncomingGossipingRequestManager
import im.vector.matrix.android.internal.crypto.OutgoingGossipingRequestManager
import im.vector.matrix.android.internal.crypto.actions.SetDeviceVerificationAction
import im.vector.matrix.android.internal.crypto.store.IMXCryptoStore
@ -32,6 +33,7 @@ internal class DefaultOutgoingSASDefaultVerificationTransaction(
cryptoStore: IMXCryptoStore,
crossSigningService: CrossSigningService,
outgoingGossipingRequestManager: OutgoingGossipingRequestManager,
incomingGossipingRequestManager: IncomingGossipingRequestManager,
deviceFingerprint: String,
transactionId: String,
otherUserId: String,
@ -43,6 +45,7 @@ internal class DefaultOutgoingSASDefaultVerificationTransaction(
cryptoStore,
crossSigningService,
outgoingGossipingRequestManager,
incomingGossipingRequestManager,
deviceFingerprint,
transactionId,
otherUserId,

View file

@ -50,6 +50,7 @@ import im.vector.matrix.android.api.session.room.model.message.MessageVerificati
import im.vector.matrix.android.api.session.room.model.message.MessageVerificationStartContent
import im.vector.matrix.android.api.session.room.model.message.ValidVerificationDone
import im.vector.matrix.android.internal.crypto.DeviceListManager
import im.vector.matrix.android.internal.crypto.IncomingGossipingRequestManager
import im.vector.matrix.android.internal.crypto.MyDeviceInfoHolder
import im.vector.matrix.android.internal.crypto.OutgoingGossipingRequestManager
import im.vector.matrix.android.internal.crypto.actions.SetDeviceVerificationAction
@ -90,6 +91,7 @@ internal class DefaultVerificationService @Inject constructor(
@DeviceId private val deviceId: String?,
private val cryptoStore: IMXCryptoStore,
private val outgoingGossipingRequestManager: OutgoingGossipingRequestManager,
private val incomingGossipingRequestManager: IncomingGossipingRequestManager,
private val myDeviceInfoHolder: Lazy<MyDeviceInfoHolder>,
private val deviceListManager: DeviceListManager,
private val setDeviceVerificationAction: SetDeviceVerificationAction,
@ -530,6 +532,7 @@ internal class DefaultVerificationService @Inject constructor(
cryptoStore,
crossSigningService,
outgoingGossipingRequestManager,
incomingGossipingRequestManager,
myDeviceInfoHolder.get().myDevice.fingerprint()!!,
startReq.transactionId,
otherUserId,
@ -840,6 +843,7 @@ internal class DefaultVerificationService @Inject constructor(
readyReq.fromDevice,
crossSigningService,
outgoingGossipingRequestManager,
incomingGossipingRequestManager,
cryptoStore,
qrCodeData,
userId,
@ -1022,6 +1026,7 @@ internal class DefaultVerificationService @Inject constructor(
cryptoStore,
crossSigningService,
outgoingGossipingRequestManager,
incomingGossipingRequestManager,
myDeviceInfoHolder.get().myDevice.fingerprint()!!,
txID,
otherUserId,
@ -1198,6 +1203,7 @@ internal class DefaultVerificationService @Inject constructor(
cryptoStore,
crossSigningService,
outgoingGossipingRequestManager,
incomingGossipingRequestManager,
myDeviceInfoHolder.get().myDevice.fingerprint()!!,
transactionId,
otherUserId,
@ -1335,6 +1341,7 @@ internal class DefaultVerificationService @Inject constructor(
otherDeviceId,
crossSigningService,
outgoingGossipingRequestManager,
incomingGossipingRequestManager,
cryptoStore,
qrCodeData,
userId,

View file

@ -21,6 +21,7 @@ import im.vector.matrix.android.api.session.crypto.crosssigning.SELF_SIGNING_KEY
import im.vector.matrix.android.api.session.crypto.crosssigning.USER_SIGNING_KEY_SSSS_NAME
import im.vector.matrix.android.api.session.crypto.verification.VerificationTransaction
import im.vector.matrix.android.api.session.crypto.verification.VerificationTxState
import im.vector.matrix.android.internal.crypto.IncomingGossipingRequestManager
import im.vector.matrix.android.internal.crypto.OutgoingGossipingRequestManager
import im.vector.matrix.android.internal.crypto.actions.SetDeviceVerificationAction
import im.vector.matrix.android.internal.crypto.crosssigning.DeviceTrustLevel
@ -33,6 +34,7 @@ internal abstract class DefaultVerificationTransaction(
private val setDeviceVerificationAction: SetDeviceVerificationAction,
private val crossSigningService: CrossSigningService,
private val outgoingGossipingRequestManager: OutgoingGossipingRequestManager,
private val incomingGossipingRequestManager: IncomingGossipingRequestManager,
private val userId: String,
override val transactionId: String,
override val otherUserId: String,
@ -86,6 +88,8 @@ internal abstract class DefaultVerificationTransaction(
}
if (otherUserId == userId) {
incomingGossipingRequestManager.onVerificationCompleteForDevice(otherDeviceId!!)
// If me it's reasonable to sign and upload the device signature
// Notice that i might not have the private keys, so may not be able to do it
crossSigningService.trustDevice(otherDeviceId!!, object : MatrixCallback<Unit> {
@ -96,7 +100,7 @@ internal abstract class DefaultVerificationTransaction(
}
transport.done(transactionId) {
if (otherUserId == userId) {
if (otherUserId == userId && !crossSigningService.canCrossSign()) {
outgoingGossipingRequestManager.sendSecretShareRequest(SELF_SIGNING_KEY_SSSS_NAME, mapOf(userId to listOf(otherDeviceId ?: "*")))
outgoingGossipingRequestManager.sendSecretShareRequest(USER_SIGNING_KEY_SSSS_NAME, mapOf(userId to listOf(otherDeviceId ?: "*")))
}

View file

@ -24,6 +24,7 @@ import im.vector.matrix.android.api.session.crypto.verification.SasMode
import im.vector.matrix.android.api.session.crypto.verification.SasVerificationTransaction
import im.vector.matrix.android.api.session.crypto.verification.VerificationTxState
import im.vector.matrix.android.api.session.events.model.EventType
import im.vector.matrix.android.internal.crypto.IncomingGossipingRequestManager
import im.vector.matrix.android.internal.crypto.OutgoingGossipingRequestManager
import im.vector.matrix.android.internal.crypto.actions.SetDeviceVerificationAction
import im.vector.matrix.android.internal.crypto.model.MXKey
@ -44,6 +45,7 @@ internal abstract class SASDefaultVerificationTransaction(
private val cryptoStore: IMXCryptoStore,
crossSigningService: CrossSigningService,
outgoingGossipingRequestManager: OutgoingGossipingRequestManager,
incomingGossipingRequestManager: IncomingGossipingRequestManager,
private val deviceFingerprint: String,
transactionId: String,
otherUserId: String,
@ -53,6 +55,7 @@ internal abstract class SASDefaultVerificationTransaction(
setDeviceVerificationAction,
crossSigningService,
outgoingGossipingRequestManager,
incomingGossipingRequestManager,
userId,
transactionId,
otherUserId,

View file

@ -21,6 +21,7 @@ import im.vector.matrix.android.api.session.crypto.verification.CancelCode
import im.vector.matrix.android.api.session.crypto.verification.QrCodeVerificationTransaction
import im.vector.matrix.android.api.session.crypto.verification.VerificationTxState
import im.vector.matrix.android.api.session.events.model.EventType
import im.vector.matrix.android.internal.crypto.IncomingGossipingRequestManager
import im.vector.matrix.android.internal.crypto.OutgoingGossipingRequestManager
import im.vector.matrix.android.internal.crypto.actions.SetDeviceVerificationAction
import im.vector.matrix.android.internal.crypto.crosssigning.fromBase64
@ -38,6 +39,7 @@ internal class DefaultQrCodeVerificationTransaction(
override var otherDeviceId: String?,
private val crossSigningService: CrossSigningService,
outgoingGossipingRequestManager: OutgoingGossipingRequestManager,
incomingGossipingRequestManager: IncomingGossipingRequestManager,
private val cryptoStore: IMXCryptoStore,
// Not null only if other user is able to scan QR code
private val qrCodeData: QrCodeData?,
@ -48,6 +50,7 @@ internal class DefaultQrCodeVerificationTransaction(
setDeviceVerificationAction,
crossSigningService,
outgoingGossipingRequestManager,
incomingGossipingRequestManager,
userId,
transactionId,
otherUserId,

View file

@ -23,6 +23,7 @@ import im.vector.matrix.android.api.session.Session
import im.vector.matrix.android.internal.crypto.CancelGossipRequestWorker
import im.vector.matrix.android.internal.crypto.CryptoModule
import im.vector.matrix.android.internal.crypto.SendGossipRequestWorker
import im.vector.matrix.android.internal.crypto.SendGossipWorker
import im.vector.matrix.android.internal.crypto.verification.SendVerificationMessageWorker
import im.vector.matrix.android.internal.di.MatrixComponent
import im.vector.matrix.android.internal.di.SessionAssistedInjectModule
@ -109,8 +110,11 @@ internal interface SessionComponent {
fun inject(worker: SendVerificationMessageWorker)
fun inject(worker: SendGossipRequestWorker)
fun inject(worker: CancelGossipRequestWorker)
fun inject(worker: SendGossipWorker)
@Component.Factory
interface Factory {
fun create(

View file

@ -128,7 +128,7 @@ internal class TimelineEventDecryptor @Inject constructor(
}
}
} catch (t: Throwable) {
Timber.e(t, "Failed to decrypt event $eventId")
Timber.e( "Failed to decrypt event $eventId, ${t.localizedMessage}")
} finally {
synchronized(existingRequests) {
existingRequests.remove(request)