Continue removing runBlocking + some cleanup

This commit is contained in:
ganfra 2022-04-15 11:17:06 +02:00
parent d020d1f6e0
commit ba540eb861
5 changed files with 99 additions and 145 deletions

View file

@ -66,7 +66,7 @@ interface CryptoService {
suspend fun getUserDevices(userId: String): MutableList<CryptoDeviceInfo>
fun getMyDevice(): CryptoDeviceInfo
suspend fun getMyDevice(): CryptoDeviceInfo
fun getGlobalBlacklistUnverifiedDevices(): Boolean
@ -104,10 +104,9 @@ interface CryptoService {
fun isRoomEncrypted(roomId: String): Boolean
fun encryptEventContent(eventContent: Content,
suspend fun encryptEventContent(eventContent: Content,
eventType: String,
roomId: String,
callback: MatrixCallback<MXEncryptEventContentResult>)
roomId: String): MXEncryptEventContentResult
fun discardOutboundSession(roomId: String)
@ -151,7 +150,7 @@ interface CryptoService {
* Perform any background tasks that can be done before a message is ready to
* send, in order to speed up sending of the message.
*/
fun prepareToEncrypt(roomId: String, callback: MatrixCallback<Unit>)
suspend fun prepareToEncrypt(roomId: String)
/**
* When LL all room members might not be loaded when setting up encryption.

View file

@ -22,13 +22,13 @@ import androidx.lifecycle.LiveData
import androidx.paging.PagedList
import kotlinx.coroutines.CancellationException
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.NonCancellable
import kotlinx.coroutines.async
import kotlinx.coroutines.cancelChildren
import kotlinx.coroutines.coroutineScope
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.joinAll
import kotlinx.coroutines.launch
import kotlinx.coroutines.runBlocking
import kotlinx.coroutines.sync.Mutex
import kotlinx.coroutines.sync.withLock
import kotlinx.coroutines.withContext
@ -76,7 +76,6 @@ import org.matrix.android.sdk.internal.crypto.tasks.SetDeviceNameTask
import org.matrix.android.sdk.internal.crypto.verification.RustVerificationService
import org.matrix.android.sdk.internal.di.DeviceId
import org.matrix.android.sdk.internal.di.UserId
import org.matrix.android.sdk.internal.extensions.foldToCallback
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
@ -219,8 +218,8 @@ internal class DefaultCryptoService @Inject constructor(
return if (longFormat) "Rust SDK 0.3" else "0.3"
}
override fun getMyDevice(): CryptoDeviceInfo {
return runBlocking { olmMachine.ownDevice() }
override suspend fun getMyDevice(): CryptoDeviceInfo {
return olmMachine.ownDevice()
}
override suspend fun fetchDevicesList(): List<DeviceInfo> {
@ -344,9 +343,13 @@ internal class DefaultCryptoService @Inject constructor(
/**
* Close the crypto
*/
fun close() = runBlocking(coroutineDispatchers.crypto) {
fun close() {
cryptoCoroutineScope.coroutineContext.cancelChildren(CancellationException("Closing crypto module"))
cryptoStore.close()
cryptoCoroutineScope.launch {
withContext(coroutineDispatchers.crypto + NonCancellable) {
cryptoStore.close()
}
}
}
// Always enabled on Matrix Android SDK2
@ -513,34 +516,29 @@ internal class DefaultCryptoService @Inject constructor(
* @param eventContent the content of the event.
* @param eventType the type of the event.
* @param roomId the room identifier the event will be sent.
* @param callback the asynchronous callback
*/
override fun encryptEventContent(eventContent: Content,
eventType: String,
roomId: String,
callback: MatrixCallback<MXEncryptEventContentResult>) {
override suspend fun encryptEventContent(eventContent: Content,
eventType: String,
roomId: String): MXEncryptEventContentResult {
// moved to crypto scope to have up to date values
cryptoCoroutineScope.launch(coroutineDispatchers.crypto) {
return withContext(coroutineDispatchers.crypto) {
val algorithm = getEncryptionAlgorithm(roomId)
if (algorithm != null) {
val userIds = getRoomUserIds(roomId)
val t0 = System.currentTimeMillis()
Timber.tag(loggerTag.value).v("encryptEventContent() starts")
runCatching {
measureTimeMillis {
preshareRoomKey(roomId, userIds)
}.also {
Timber.d("Shared room key in room $roomId took $it ms")
}
val content = encrypt(roomId, eventType, eventContent)
Timber.tag(loggerTag.value).v("## CRYPTO | encryptEventContent() : succeeds after ${System.currentTimeMillis() - t0} ms")
MXEncryptEventContentResult(content, EventType.ENCRYPTED)
}.foldToCallback(callback)
measureTimeMillis {
preshareRoomKey(roomId, userIds)
}.also {
Timber.d("Shared room key in room $roomId took $it ms")
}
val content = encrypt(roomId, eventType, eventContent)
Timber.tag(loggerTag.value).v("## CRYPTO | encryptEventContent() : succeeds after ${System.currentTimeMillis() - t0} ms")
MXEncryptEventContentResult(content, EventType.ENCRYPTED)
} else {
val reason = String.format(MXCryptoError.UNABLE_TO_ENCRYPT_REASON, MXCryptoError.NO_MORE_ALGORITHM_REASON)
Timber.tag(loggerTag.value).e("encryptEventContent() : failed $reason")
callback.onFailure(Failure.CryptoError(MXCryptoError.Base(MXCryptoError.ErrorType.UNABLE_TO_ENCRYPT, reason)))
throw Failure.CryptoError(MXCryptoError.Base(MXCryptoError.ErrorType.UNABLE_TO_ENCRYPT, reason))
}
}
}
@ -707,26 +705,12 @@ internal class DefaultCryptoService @Inject constructor(
}
private suspend fun preshareRoomKey(roomId: String, roomMembers: List<String>) {
keyClaimLock.withLock {
val request = this.olmMachine.getMissingSessions(roomMembers)
// This request can only be a keys claim request.
if (request != null) {
when (request) {
is Request.KeysClaim -> {
claimKeys(request)
}
else -> {
}
}
}
}
val keyShareLock = roomKeyShareLocks.getOrPut(roomId, { Mutex() })
claimMissingKeys(roomMembers)
val keyShareLock = roomKeyShareLocks.getOrPut(roomId) { Mutex() }
var sharedKey = false
keyShareLock.withLock {
coroutineScope {
this@DefaultCryptoService.olmMachine.shareRoomKey(roomId, roomMembers).map {
olmMachine.shareRoomKey(roomId, roomMembers).map {
when (it) {
is Request.ToDevice -> {
sharedKey = true
@ -752,6 +736,18 @@ internal class DefaultCryptoService @Inject constructor(
}
}
private suspend fun claimMissingKeys(roomMembers: List<String>) = keyClaimLock.withLock {
val request = this.olmMachine.getMissingSessions(roomMembers)
// This request can only be a keys claim request.
when (request) {
is Request.KeysClaim -> {
claimKeys(request)
}
else -> {
}
}
}
private suspend fun encrypt(roomId: String, eventType: String, content: Content): Content {
return olmMachine.encrypt(roomId, eventType, content)
}
@ -810,7 +806,7 @@ internal class DefaultCryptoService @Inject constructor(
}
}
private suspend fun sendRoomMessage(request: Request.RoomMessage){
private suspend fun sendRoomMessage(request: Request.RoomMessage) {
try {
requestSender.sendRoomMessage(request)
} catch (throwable: Throwable) {
@ -1083,18 +1079,16 @@ internal class DefaultCryptoService @Inject constructor(
cryptoStore.logDbUsageInfo()
}
override fun prepareToEncrypt(roomId: String, callback: MatrixCallback<Unit>) {
cryptoCoroutineScope.launch(coroutineDispatchers.crypto) {
override suspend fun prepareToEncrypt(roomId: String) {
withContext(coroutineDispatchers.crypto) {
Timber.tag(loggerTag.value).d("prepareToEncrypt() roomId:$roomId Check room members up to date")
// Ensure to load all room members
try {
loadRoomMembersTask.execute(LoadRoomMembersTask.Params(roomId))
} catch (failure: Throwable) {
Timber.tag(loggerTag.value).e("prepareToEncrypt() : Failed to load room members")
callback.onFailure(failure)
return@launch
throw failure
}
val userIds = getRoomUserIds(roomId)
val algorithm = getEncryptionAlgorithm(roomId)
@ -1102,19 +1096,13 @@ internal class DefaultCryptoService @Inject constructor(
if (algorithm == null) {
val reason = String.format(MXCryptoError.UNABLE_TO_ENCRYPT_REASON, MXCryptoError.NO_MORE_ALGORITHM_REASON)
Timber.tag(loggerTag.value).e("prepareToEncrypt() : $reason")
callback.onFailure(IllegalArgumentException("Missing algorithm"))
return@launch
throw IllegalArgumentException("Missing algorithm")
}
runCatching {
try {
preshareRoomKey(roomId, userIds)
}.fold(
{ callback.onSuccess(Unit) },
{
Timber.tag(loggerTag.value).e(it, "prepareToEncrypt() failed.")
callback.onFailure(it)
}
)
}catch (failure: Throwable){
Timber.tag(loggerTag.value).e("prepareToEncrypt() : Failed to PreshareRoomKey")
}
}
}

View file

@ -22,11 +22,9 @@ import org.matrix.android.sdk.api.session.events.model.toContent
import org.matrix.android.sdk.api.session.room.send.SendState
import org.matrix.android.sdk.internal.crypto.MXCRYPTO_ALGORITHM_MEGOLM
import org.matrix.android.sdk.internal.crypto.MXEventDecryptionResult
import org.matrix.android.sdk.internal.crypto.model.MXEncryptEventContentResult
import org.matrix.android.sdk.internal.database.mapper.ContentMapper
import org.matrix.android.sdk.internal.session.room.send.LocalEchoRepository
import org.matrix.android.sdk.internal.task.Task
import org.matrix.android.sdk.internal.util.awaitCallback
import javax.inject.Inject
internal interface EncryptEventTask : Task<EncryptEventTask.Params, Event> {
@ -56,47 +54,44 @@ internal class DefaultEncryptEventTask @Inject constructor(
localMutableContent.remove(it)
}
// try {
// let it throws
awaitCallback<MXEncryptEventContentResult> {
cryptoService.encryptEventContent(localMutableContent, localEvent.type, params.roomId, it)
}.let { result ->
val modifiedContent = HashMap(result.eventContent)
params.keepKeys?.forEach { toKeep ->
localEvent.content?.get(toKeep)?.let {
// put it back in the encrypted thing
modifiedContent[toKeep] = it
}
}
val safeResult = result.copy(eventContent = modifiedContent)
// Better handling of local echo, to avoid decrypting transition on remote echo
// Should I only do it for text messages?
val decryptionLocalEcho = if (result.eventContent["algorithm"] == MXCRYPTO_ALGORITHM_MEGOLM) {
MXEventDecryptionResult(
clearEvent = Event(
type = localEvent.type,
content = localEvent.content,
roomId = localEvent.roomId
).toContent(),
forwardingCurve25519KeyChain = emptyList(),
senderCurve25519Key = result.eventContent["sender_key"] as? String,
claimedEd25519Key = cryptoService.getMyDevice().fingerprint()
)
} else {
null
}
val result = cryptoService.encryptEventContent(localMutableContent, localEvent.type, params.roomId)
localEchoRepository.updateEcho(localEvent.eventId) { _, localEcho ->
localEcho.type = EventType.ENCRYPTED
localEcho.content = ContentMapper.map(modifiedContent)
decryptionLocalEcho?.also {
localEcho.setDecryptionResult(it)
}
val modifiedContent = HashMap(result.eventContent)
params.keepKeys?.forEach { toKeep ->
localEvent.content?.get(toKeep)?.let {
// put it back in the encrypted thing
modifiedContent[toKeep] = it
}
return localEvent.copy(
type = safeResult.eventType,
content = safeResult.eventContent
)
}
val safeResult = result.copy(eventContent = modifiedContent)
// Better handling of local echo, to avoid decrypting transition on remote echo
// Should I only do it for text messages?
val decryptionLocalEcho = if (result.eventContent["algorithm"] == MXCRYPTO_ALGORITHM_MEGOLM) {
MXEventDecryptionResult(
clearEvent = Event(
type = localEvent.type,
content = localEvent.content,
roomId = localEvent.roomId
).toContent(),
forwardingCurve25519KeyChain = emptyList(),
senderCurve25519Key = result.eventContent["sender_key"] as? String,
claimedEd25519Key = cryptoService.getMyDevice().fingerprint()
)
} else {
null
}
localEchoRepository.updateEcho(localEvent.eventId) { _, localEcho ->
localEcho.type = EventType.ENCRYPTED
localEcho.content = ContentMapper.map(modifiedContent)
decryptionLocalEcho?.also {
localEcho.setDecryptionResult(it)
}
}
return localEvent.copy(
type = safeResult.eventType,
content = safeResult.eventContent
)
}
}

View file

@ -49,7 +49,6 @@ import org.matrix.android.sdk.internal.session.room.state.SendStateTask
import org.matrix.android.sdk.internal.session.room.summary.RoomSummaryDataSource
import org.matrix.android.sdk.internal.session.search.SearchTask
import org.matrix.android.sdk.internal.session.space.DefaultSpace
import org.matrix.android.sdk.internal.util.awaitCallback
import java.security.InvalidParameterException
internal class DefaultRoom(override val roomId: String,
@ -117,9 +116,7 @@ internal class DefaultRoom(override val roomId: String,
}
override suspend fun prepareToEncrypt() {
awaitCallback<Unit> {
cryptoService.prepareToEncrypt(roomId, it)
}
cryptoService.prepareToEncrypt(roomId)
}
override suspend fun enableEncryption(algorithm: String, force: Boolean) {

View file

@ -16,8 +16,6 @@
package im.vector.app.features.crypto.verification
import com.airbnb.mvrx.Async
import com.airbnb.mvrx.Fail
import com.airbnb.mvrx.Loading
import com.airbnb.mvrx.MavericksState
import com.airbnb.mvrx.MavericksViewModelFactory
import com.airbnb.mvrx.Success
@ -358,44 +356,21 @@ class VerificationBottomSheetViewModel @AssistedInject constructor(
private fun handleRequestVerificationByDM(roomId: String?, otherUserId: String) {
viewModelScope.launch {
if (roomId == null) {
val localId = LocalEcho.createLocalEchoId()
setState {
copy(
pendingLocalId = localId,
pendingRequest = Loading()
)
}
try {
val dmRoomId = session.createDirectRoom(otherUserId)
val pendingRequest = session
.cryptoService()
.verificationService()
.requestKeyVerificationInDMs(
supportedVerificationMethodsProvider.provide(),
otherUserId,
dmRoomId,
localId
)
setState {
copy(
roomId = dmRoomId,
pendingRequest = Success(pendingRequest)
)
}
} catch (failure: Throwable) {
setState {
copy(pendingRequest = Fail(failure))
}
}
} else {
val pendingRequest = session
val localId = LocalEcho.createLocalEchoId()
val dmRoomId = roomId ?: session.createDirectRoom(otherUserId)
setState { copy(pendingLocalId = localId, roomId = dmRoomId) }
suspend {
session
.cryptoService()
.verificationService()
.requestKeyVerificationInDMs(supportedVerificationMethodsProvider.provide(), otherUserId, roomId)
setState {
copy(pendingRequest = Success(pendingRequest))
}
.requestKeyVerificationInDMs(
supportedVerificationMethodsProvider.provide(),
otherUserId,
dmRoomId,
localId
)
}.execute {
copy(pendingRequest = it, roomId = dmRoomId)
}
}
}