mirror of
https://github.com/SchildiChat/SchildiChat-android.git
synced 2024-12-28 03:48:37 +03:00
Use ImportKeysResult to notify sessions listeners
This commit is contained in:
parent
ee6eec041a
commit
24dc52e4f6
11 changed files with 118 additions and 29 deletions
|
@ -134,6 +134,7 @@ internal class DefaultCryptoService @Inject constructor(
|
||||||
private val crossSigningService: CrossSigningService,
|
private val crossSigningService: CrossSigningService,
|
||||||
private val verificationService: RustVerificationService,
|
private val verificationService: RustVerificationService,
|
||||||
private val keysBackupService: RustKeyBackupService,
|
private val keysBackupService: RustKeyBackupService,
|
||||||
|
private val megolmSessionImportManager: MegolmSessionImportManager,
|
||||||
private val olmMachineProvider: OlmMachineProvider
|
private val olmMachineProvider: OlmMachineProvider
|
||||||
) : CryptoService {
|
) : CryptoService {
|
||||||
|
|
||||||
|
@ -152,9 +153,6 @@ internal class DefaultCryptoService @Inject constructor(
|
||||||
private val outgoingRequestsLock: Mutex = Mutex()
|
private val outgoingRequestsLock: Mutex = Mutex()
|
||||||
private val roomKeyShareLocks: ConcurrentHashMap<String, Mutex> = ConcurrentHashMap()
|
private val roomKeyShareLocks: ConcurrentHashMap<String, Mutex> = ConcurrentHashMap()
|
||||||
|
|
||||||
// TODO does this need to be concurrent?
|
|
||||||
private val newSessionListeners = ArrayList<NewSessionListener>()
|
|
||||||
|
|
||||||
fun onStateEvent(roomId: String, event: Event) {
|
fun onStateEvent(roomId: String, event: Event) {
|
||||||
when (event.getClearType()) {
|
when (event.getClearType()) {
|
||||||
EventType.STATE_ROOM_ENCRYPTION -> onRoomEncryptionEvent(roomId, event)
|
EventType.STATE_ROOM_ENCRYPTION -> onRoomEncryptionEvent(roomId, event)
|
||||||
|
@ -675,17 +673,7 @@ internal class DefaultCryptoService @Inject constructor(
|
||||||
roomId: String,
|
roomId: String,
|
||||||
sessionId: String,
|
sessionId: String,
|
||||||
) {
|
) {
|
||||||
// The sender key is actually unused since it's unimportant for megolm
|
megolmSessionImportManager.dispatchNewSession(roomId, sessionId)
|
||||||
// Our events don't contain the info so pass an empty string until we
|
|
||||||
// change the listener definition
|
|
||||||
val senderKey = ""
|
|
||||||
|
|
||||||
newSessionListeners.forEach {
|
|
||||||
try {
|
|
||||||
it.onNewSession(roomId, senderKey, sessionId)
|
|
||||||
} catch (e: Throwable) {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
suspend fun receiveSyncChanges(
|
suspend fun receiveSyncChanges(
|
||||||
|
@ -886,7 +874,9 @@ internal class DefaultCryptoService @Inject constructor(
|
||||||
override suspend fun importRoomKeys(roomKeysAsArray: ByteArray,
|
override suspend fun importRoomKeys(roomKeysAsArray: ByteArray,
|
||||||
password: String,
|
password: String,
|
||||||
progressListener: ProgressListener?): ImportRoomKeysResult {
|
progressListener: ProgressListener?): ImportRoomKeysResult {
|
||||||
val result = olmMachine.importKeys(roomKeysAsArray, password, progressListener)
|
val result = olmMachine.importKeys(roomKeysAsArray, password, progressListener).also {
|
||||||
|
megolmSessionImportManager.dispatchKeyImportResults(it)
|
||||||
|
}
|
||||||
keysBackupService.maybeBackupKeys()
|
keysBackupService.maybeBackupKeys()
|
||||||
|
|
||||||
return result
|
return result
|
||||||
|
@ -1030,11 +1020,11 @@ internal class DefaultCryptoService @Inject constructor(
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun addNewSessionListener(newSessionListener: NewSessionListener) {
|
override fun addNewSessionListener(newSessionListener: NewSessionListener) {
|
||||||
if (!newSessionListeners.contains(newSessionListener)) newSessionListeners.add(newSessionListener)
|
megolmSessionImportManager.addListener(newSessionListener)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun removeSessionListener(listener: NewSessionListener) {
|
override fun removeSessionListener(listener: NewSessionListener) {
|
||||||
newSessionListeners.remove(listener)
|
megolmSessionImportManager.removeListener(listener)
|
||||||
}
|
}
|
||||||
/* ==========================================================================================
|
/* ==========================================================================================
|
||||||
* DEBUG INFO
|
* DEBUG INFO
|
||||||
|
|
|
@ -44,6 +44,7 @@ import timber.log.Timber
|
||||||
import java.util.concurrent.Executors
|
import java.util.concurrent.Executors
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
@Deprecated("rust")
|
||||||
@SessionScope
|
@SessionScope
|
||||||
internal class IncomingGossipingRequestManager @Inject constructor(
|
internal class IncomingGossipingRequestManager @Inject constructor(
|
||||||
@SessionId private val sessionId: String,
|
@SessionId private val sessionId: String,
|
||||||
|
|
|
@ -0,0 +1,77 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2021 The Matrix.org Foundation C.I.C.
|
||||||
|
*
|
||||||
|
* 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
|
||||||
|
|
||||||
|
import kotlinx.coroutines.CoroutineScope
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
|
import org.matrix.android.sdk.api.MatrixCoroutineDispatchers
|
||||||
|
import org.matrix.android.sdk.api.extensions.tryOrNull
|
||||||
|
import org.matrix.android.sdk.internal.crypto.model.ImportRoomKeysResult
|
||||||
|
import org.matrix.android.sdk.internal.session.SessionScope
|
||||||
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Helper that allows listeners to be notified when a new megolm session
|
||||||
|
* has been added to the crypto layer (could be via room keys or forward keys via sync
|
||||||
|
* or after importing keys from key backup or manual import).
|
||||||
|
* Can be used to refresh display when the keys are received after the message
|
||||||
|
*/
|
||||||
|
@SessionScope
|
||||||
|
internal class MegolmSessionImportManager @Inject constructor(
|
||||||
|
private val coroutineDispatchers: MatrixCoroutineDispatchers,
|
||||||
|
private val cryptoCoroutineScope: CoroutineScope
|
||||||
|
) {
|
||||||
|
|
||||||
|
private val newSessionsListeners = mutableListOf<NewSessionListener>()
|
||||||
|
|
||||||
|
fun addListener(listener: NewSessionListener) {
|
||||||
|
synchronized(newSessionsListeners) {
|
||||||
|
if (!newSessionsListeners.contains(listener)) {
|
||||||
|
newSessionsListeners.add(listener)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun removeListener(listener: NewSessionListener) {
|
||||||
|
synchronized(newSessionsListeners) {
|
||||||
|
newSessionsListeners.remove(listener)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun dispatchNewSession(roomId: String?, sessionId: String) {
|
||||||
|
val copy = synchronized(newSessionsListeners) {
|
||||||
|
newSessionsListeners.toList()
|
||||||
|
}
|
||||||
|
cryptoCoroutineScope.launch(coroutineDispatchers.computation) {
|
||||||
|
copy.forEach {
|
||||||
|
tryOrNull("Failed to dispatch new session import") {
|
||||||
|
it.onNewSession(roomId, sessionId)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun dispatchKeyImportResults(result: ImportRoomKeysResult) {
|
||||||
|
result.importedSessionInfo.forEach { (roomId, senderToSessionIdMap) ->
|
||||||
|
senderToSessionIdMap.values.forEach { sessionList ->
|
||||||
|
sessionList.forEach { sessionId ->
|
||||||
|
dispatchNewSession(roomId, sessionId)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -16,5 +16,5 @@
|
||||||
package org.matrix.android.sdk.internal.crypto
|
package org.matrix.android.sdk.internal.crypto
|
||||||
|
|
||||||
interface NewSessionListener {
|
interface NewSessionListener {
|
||||||
fun onNewSession(roomId: String?, senderKey: String, sessionId: String)
|
fun onNewSession(roomId: String?, sessionId: String)
|
||||||
}
|
}
|
||||||
|
|
|
@ -510,8 +510,7 @@ internal class OlmMachine(
|
||||||
|
|
||||||
val result = inner.importKeys(decodedKeys, passphrase, rustListener)
|
val result = inner.importKeys(decodedKeys, passphrase, rustListener)
|
||||||
|
|
||||||
// TODO do we want to remove the cast here?
|
ImportRoomKeysResult.fromOlm(result)
|
||||||
ImportRoomKeysResult(result.total.toInt(), result.imported.toInt())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Throws(CryptoStoreException::class)
|
@Throws(CryptoStoreException::class)
|
||||||
|
@ -520,13 +519,14 @@ internal class OlmMachine(
|
||||||
listener: ProgressListener?
|
listener: ProgressListener?
|
||||||
): ImportRoomKeysResult =
|
): ImportRoomKeysResult =
|
||||||
withContext(Dispatchers.IO) {
|
withContext(Dispatchers.IO) {
|
||||||
|
|
||||||
val adapter = MoshiProvider.providesMoshi().adapter(List::class.java)
|
val adapter = MoshiProvider.providesMoshi().adapter(List::class.java)
|
||||||
|
|
||||||
// If the key backup is too big we take the risk of causing OOM
|
// If the key backup is too big we take the risk of causing OOM
|
||||||
|
// when serializing to json
|
||||||
// so let's chunk to avoid it
|
// so let's chunk to avoid it
|
||||||
var totalImported = 0L
|
var totalImported = 0L
|
||||||
var accTotal = 0L
|
var accTotal = 0L
|
||||||
|
val details = mutableMapOf<String, Map<String, List<String>>>()
|
||||||
keys.chunked(500)
|
keys.chunked(500)
|
||||||
.forEach { keysSlice ->
|
.forEach { keysSlice ->
|
||||||
val encodedKeys = adapter.toJson(keysSlice)
|
val encodedKeys = adapter.toJson(keysSlice)
|
||||||
|
@ -540,9 +540,10 @@ internal class OlmMachine(
|
||||||
inner.importDecryptedKeys(encodedKeys, rustListener).let {
|
inner.importDecryptedKeys(encodedKeys, rustListener).let {
|
||||||
totalImported += it.imported
|
totalImported += it.imported
|
||||||
accTotal += it.total
|
accTotal += it.total
|
||||||
|
details.putAll(it.keys)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ImportRoomKeysResult(totalImported.toInt(), accTotal.toInt())
|
ImportRoomKeysResult(totalImported.toInt(), accTotal.toInt(), details)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Throws(CryptoStoreException::class)
|
@Throws(CryptoStoreException::class)
|
||||||
|
|
|
@ -72,11 +72,11 @@ internal class RoomDecryptorProvider @Inject constructor(
|
||||||
val alg = when (algorithm) {
|
val alg = when (algorithm) {
|
||||||
MXCRYPTO_ALGORITHM_MEGOLM -> megolmDecryptionFactory.create().apply {
|
MXCRYPTO_ALGORITHM_MEGOLM -> megolmDecryptionFactory.create().apply {
|
||||||
this.newSessionListener = object : NewSessionListener {
|
this.newSessionListener = object : NewSessionListener {
|
||||||
override fun onNewSession(roomId: String?, senderKey: String, sessionId: String) {
|
override fun onNewSession(roomId: String?, sessionId: String) {
|
||||||
// PR reviewer: the parameter has been renamed so is now in conflict with the parameter of getOrCreateRoomDecryptor
|
// PR reviewer: the parameter has been renamed so is now in conflict with the parameter of getOrCreateRoomDecryptor
|
||||||
newSessionListeners.forEach {
|
newSessionListeners.forEach {
|
||||||
try {
|
try {
|
||||||
it.onNewSession(roomId, senderKey, sessionId)
|
it.onNewSession(roomId, sessionId)
|
||||||
} catch (e: Throwable) {
|
} catch (e: Throwable) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -103,6 +103,6 @@ internal class MegolmSessionDataImporter @Inject constructor(private val olmDevi
|
||||||
|
|
||||||
Timber.v("## importMegolmSessionsData : sessions import " + (t1 - t0) + " ms (" + megolmSessionsData.size + " sessions)")
|
Timber.v("## importMegolmSessionsData : sessions import " + (t1 - t0) + " ms (" + megolmSessionsData.size + " sessions)")
|
||||||
|
|
||||||
return ImportRoomKeysResult(totalNumbersOfKeys, totalNumbersOfImportedKeys)
|
return ImportRoomKeysResult(totalNumbersOfKeys, totalNumbersOfImportedKeys, emptyMap())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -317,7 +317,7 @@ internal class MXMegolmDecryption(private val userId: String,
|
||||||
*/
|
*/
|
||||||
override fun onNewSession(senderKey: String, sessionId: String) {
|
override fun onNewSession(senderKey: String, sessionId: String) {
|
||||||
Timber.tag(loggerTag.value).v("ON NEW SESSION $sessionId - $senderKey")
|
Timber.tag(loggerTag.value).v("ON NEW SESSION $sessionId - $senderKey")
|
||||||
newSessionListener?.onNewSession(null, senderKey, sessionId)
|
newSessionListener?.onNewSession(null, sessionId)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun hasKeysForKeyRequest(request: IncomingRoomKeyRequest): Boolean {
|
override fun hasKeysForKeyRequest(request: IncomingRoomKeyRequest): Boolean {
|
||||||
|
|
|
@ -39,6 +39,7 @@ import org.matrix.android.sdk.api.session.crypto.keysbackup.KeysBackupState
|
||||||
import org.matrix.android.sdk.api.session.crypto.keysbackup.KeysBackupStateListener
|
import org.matrix.android.sdk.api.session.crypto.keysbackup.KeysBackupStateListener
|
||||||
import org.matrix.android.sdk.internal.crypto.MXCRYPTO_ALGORITHM_MEGOLM_BACKUP
|
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.MegolmSessionData
|
||||||
|
import org.matrix.android.sdk.internal.crypto.MegolmSessionImportManager
|
||||||
import org.matrix.android.sdk.internal.crypto.OlmMachineProvider
|
import org.matrix.android.sdk.internal.crypto.OlmMachineProvider
|
||||||
import org.matrix.android.sdk.internal.crypto.RequestSender
|
import org.matrix.android.sdk.internal.crypto.RequestSender
|
||||||
import org.matrix.android.sdk.internal.crypto.keysbackup.model.KeysBackupVersionTrust
|
import org.matrix.android.sdk.internal.crypto.keysbackup.model.KeysBackupVersionTrust
|
||||||
|
@ -74,6 +75,7 @@ internal class RustKeyBackupService @Inject constructor(
|
||||||
olmMachineProvider: OlmMachineProvider,
|
olmMachineProvider: OlmMachineProvider,
|
||||||
private val sender: RequestSender,
|
private val sender: RequestSender,
|
||||||
private val coroutineDispatchers: MatrixCoroutineDispatchers,
|
private val coroutineDispatchers: MatrixCoroutineDispatchers,
|
||||||
|
private val megolmSessionImportManager: MegolmSessionImportManager,
|
||||||
private val cryptoCoroutineScope: CoroutineScope,
|
private val cryptoCoroutineScope: CoroutineScope,
|
||||||
) : KeysBackupService {
|
) : KeysBackupService {
|
||||||
companion object {
|
companion object {
|
||||||
|
@ -545,7 +547,9 @@ internal class RustKeyBackupService @Inject constructor(
|
||||||
null
|
null
|
||||||
}
|
}
|
||||||
|
|
||||||
val result = olmMachine.importDecryptedKeys(sessionsData, progressListener)
|
val result = olmMachine.importDecryptedKeys(sessionsData, progressListener).also {
|
||||||
|
megolmSessionImportManager.dispatchKeyImportResults(it)
|
||||||
|
}
|
||||||
|
|
||||||
// Do not back up the key if it comes from a backup recovery
|
// Do not back up the key if it comes from a backup recovery
|
||||||
if (backUp) {
|
if (backUp) {
|
||||||
|
|
|
@ -16,5 +16,21 @@
|
||||||
|
|
||||||
package org.matrix.android.sdk.internal.crypto.model
|
package org.matrix.android.sdk.internal.crypto.model
|
||||||
|
|
||||||
|
import uniffi.olm.KeysImportResult
|
||||||
|
|
||||||
data class ImportRoomKeysResult(val totalNumberOfKeys: Int,
|
data class ImportRoomKeysResult(val totalNumberOfKeys: Int,
|
||||||
val successfullyNumberOfImportedKeys: Int)
|
val successfullyNumberOfImportedKeys: Int,
|
||||||
|
/**It's a map from room id to a map of the sender key to a list of session*/
|
||||||
|
val importedSessionInfo: Map<String, Map<String, List<String>>>
|
||||||
|
) {
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
fun fromOlm(result: KeysImportResult): ImportRoomKeysResult {
|
||||||
|
return ImportRoomKeysResult(
|
||||||
|
result.total.toInt(),
|
||||||
|
result.imported.toInt(),
|
||||||
|
result.keys
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -40,7 +40,7 @@ internal class TimelineEventDecryptor @Inject constructor(
|
||||||
) {
|
) {
|
||||||
|
|
||||||
private val newSessionListener = object : NewSessionListener {
|
private val newSessionListener = object : NewSessionListener {
|
||||||
override fun onNewSession(roomId: String?, senderKey: String, sessionId: String) {
|
override fun onNewSession(roomId: String?, sessionId: String) {
|
||||||
synchronized(unknownSessionsFailure) {
|
synchronized(unknownSessionsFailure) {
|
||||||
unknownSessionsFailure[sessionId]
|
unknownSessionsFailure[sessionId]
|
||||||
?.toList()
|
?.toList()
|
||||||
|
|
Loading…
Reference in a new issue