mirror of
https://github.com/element-hq/element-android
synced 2024-11-24 10:25:35 +03:00
Refactor + share secret window implementation
This commit is contained in:
parent
0c1f30208d
commit
4f70c40b1a
16 changed files with 340 additions and 36 deletions
|
@ -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)) {
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -26,6 +26,7 @@ enum class GossipingRequestState {
|
|||
PENDING,
|
||||
REJECTED,
|
||||
ACCEPTED,
|
||||
FAILED_TO_ACCEPTED,
|
||||
// USER_REJECTED,
|
||||
UNABLE_TO_PROCESS,
|
||||
CANCELLED_BY_REQUESTER,
|
||||
|
|
|
@ -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
|
||||
}
|
||||
}
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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 ?: "")
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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>) {
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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 ?: "*")))
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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(
|
||||
|
|
|
@ -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)
|
||||
|
|
Loading…
Reference in a new issue