forked from GitHub-Mirror/riotX-android
Crypto: start reworking threading - WIP (to squash)
This commit is contained in:
parent
3d50393b33
commit
e125862794
@ -25,7 +25,7 @@ import kotlin.random.Random
|
||||
|
||||
internal class FakeGetContextOfEventTask(private val tokenChunkEventPersistor: TokenChunkEventPersistor) : GetContextOfEventTask {
|
||||
|
||||
override fun execute(params: GetContextOfEventTask.Params): Try<TokenChunkEventPersistor.Result> {
|
||||
override suspend fun execute(params: GetContextOfEventTask.Params): Try<TokenChunkEventPersistor.Result> {
|
||||
val fakeEvents = RoomDataHelper.createFakeListOfEvents(30)
|
||||
val tokenChunkEvent = FakeTokenChunkEvent(
|
||||
Random.nextLong(System.currentTimeMillis()).toString(),
|
||||
|
@ -23,7 +23,7 @@ import kotlin.random.Random
|
||||
|
||||
internal class FakePaginationTask(private val tokenChunkEventPersistor: TokenChunkEventPersistor) : PaginationTask {
|
||||
|
||||
override fun execute(params: PaginationTask.Params): Try<TokenChunkEventPersistor.Result> {
|
||||
override suspend fun execute(params: PaginationTask.Params): Try<TokenChunkEventPersistor.Result> {
|
||||
val fakeEvents = RoomDataHelper.createFakeListOfEvents(30)
|
||||
val tokenChunkEvent = FakeTokenChunkEvent(params.from, Random.nextLong(System.currentTimeMillis()).toString(), fakeEvents)
|
||||
return tokenChunkEventPersistor.insertInDb(tokenChunkEvent, params.roomId, params.direction)
|
||||
|
@ -21,6 +21,8 @@ package im.vector.matrix.android.internal.crypto
|
||||
import android.content.Context
|
||||
import android.os.Handler
|
||||
import android.text.TextUtils
|
||||
import arrow.core.Try
|
||||
import arrow.instances.`try`.applicativeError.handleError
|
||||
import com.zhuinden.monarchy.Monarchy
|
||||
import im.vector.matrix.android.api.MatrixCallback
|
||||
import im.vector.matrix.android.api.auth.data.Credentials
|
||||
@ -66,14 +68,16 @@ import im.vector.matrix.android.internal.session.room.members.LoadRoomMembersTas
|
||||
import im.vector.matrix.android.internal.session.room.members.RoomMembers
|
||||
import im.vector.matrix.android.internal.session.sync.model.SyncResponse
|
||||
import im.vector.matrix.android.internal.task.TaskExecutor
|
||||
import im.vector.matrix.android.internal.task.TaskThread
|
||||
import im.vector.matrix.android.internal.task.configureWith
|
||||
import im.vector.matrix.android.internal.util.MatrixCoroutineDispatchers
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import kotlinx.coroutines.withContext
|
||||
import org.matrix.olm.OlmManager
|
||||
import timber.log.Timber
|
||||
import java.util.*
|
||||
import java.util.concurrent.atomic.AtomicBoolean
|
||||
|
||||
/**
|
||||
* A `CryptoService` class instance manages the end-to-end crypto for a session.
|
||||
@ -137,10 +141,10 @@ internal class CryptoManager(
|
||||
private val roomEncryptors: MutableMap<String, IMXEncrypting> = HashMap()
|
||||
|
||||
// the encryption is starting
|
||||
private var isStarting: Boolean = false
|
||||
private var isStarting = AtomicBoolean(false)
|
||||
|
||||
// tell if the crypto is started
|
||||
private var isStarted: Boolean = false
|
||||
private var isStarted = AtomicBoolean(false)
|
||||
|
||||
// TODO
|
||||
//private val mNetworkListener = object : IMXNetworkEventListener {
|
||||
@ -220,7 +224,7 @@ internal class CryptoManager(
|
||||
* @return true if the crypto is started
|
||||
*/
|
||||
fun isStarted(): Boolean {
|
||||
return isStarted
|
||||
return isStarted.get()
|
||||
}
|
||||
|
||||
/**
|
||||
@ -229,7 +233,7 @@ internal class CryptoManager(
|
||||
* @return true if the crypto is starting
|
||||
*/
|
||||
fun isStarting(): Boolean {
|
||||
return isStarting
|
||||
return isStarting.get()
|
||||
}
|
||||
|
||||
/**
|
||||
@ -241,7 +245,7 @@ internal class CryptoManager(
|
||||
* @param isInitialSync true if it starts from an initial sync
|
||||
*/
|
||||
fun start(isInitialSync: Boolean) {
|
||||
if (isStarting) {
|
||||
if (isStarting.get()) {
|
||||
return
|
||||
}
|
||||
|
||||
@ -254,65 +258,43 @@ internal class CryptoManager(
|
||||
// return
|
||||
//}
|
||||
|
||||
isStarting = true
|
||||
|
||||
isStarting.set(true)
|
||||
// Open the store
|
||||
cryptoStore.open()
|
||||
|
||||
uploadDeviceKeys(object : MatrixCallback<KeysUploadResponse> {
|
||||
private fun onError() {
|
||||
Handler().postDelayed({
|
||||
if (!isStarted()) {
|
||||
isStarting = false
|
||||
start(isInitialSync)
|
||||
}
|
||||
}, 1000)
|
||||
}
|
||||
|
||||
override fun onSuccess(data: KeysUploadResponse) {
|
||||
Timber.v("###########################################################")
|
||||
Timber.v("uploadDeviceKeys done for " + credentials.userId)
|
||||
Timber.v(" - device id : " + credentials.deviceId)
|
||||
Timber.v(" - ed25519 : " + olmDevice.deviceEd25519Key)
|
||||
Timber.v(" - curve25519 : " + olmDevice.deviceCurve25519Key)
|
||||
Timber.v(" - oneTimeKeys: " + oneTimeKeysUploader.mLastPublishedOneTimeKeys)
|
||||
Timber.v("")
|
||||
|
||||
oneTimeKeysUploader.maybeUploadOneTimeKeys(object : MatrixCallback<Unit> {
|
||||
override fun onSuccess(data: Unit) {
|
||||
// TODO
|
||||
//if (null != mNetworkConnectivityReceiver) {
|
||||
// mNetworkConnectivityReceiver!!.removeEventListener(mNetworkListener)
|
||||
//}
|
||||
|
||||
isStarting = false
|
||||
isStarted = true
|
||||
|
||||
outgoingRoomKeyRequestManager.start()
|
||||
|
||||
keysBackup.checkAndStartKeysBackup()
|
||||
|
||||
if (isInitialSync) {
|
||||
// refresh the devices list for each known room members
|
||||
deviceListManager.invalidateAllDeviceLists()
|
||||
deviceListManager.refreshOutdatedDeviceLists()
|
||||
} else {
|
||||
incomingRoomKeyRequestManager.processReceivedRoomKeyRequests()
|
||||
}
|
||||
CoroutineScope(coroutineDispatchers.crypto).launch {
|
||||
uploadDeviceKeys()
|
||||
.flatMap {
|
||||
oneTimeKeysUploader.maybeUploadOneTimeKeys()
|
||||
}
|
||||
|
||||
override fun onFailure(failure: Throwable) {
|
||||
Timber.e(failure, "## start failed")
|
||||
onError()
|
||||
.handleError {
|
||||
Handler().postDelayed(
|
||||
{
|
||||
if (!isStarted()) {
|
||||
isStarting.set(false)
|
||||
start(isInitialSync)
|
||||
}
|
||||
}, 1000
|
||||
)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
override fun onFailure(failure: Throwable) {
|
||||
Timber.e(failure, "## start failed")
|
||||
onError()
|
||||
}
|
||||
})
|
||||
.fold(
|
||||
{
|
||||
Timber.e("Start failed: $it")
|
||||
},
|
||||
{
|
||||
isStarting.set(false)
|
||||
isStarted.set(true)
|
||||
outgoingRoomKeyRequestManager.start()
|
||||
keysBackup.checkAndStartKeysBackup()
|
||||
if (isInitialSync) {
|
||||
// refresh the devices list for each known room members
|
||||
deviceListManager.invalidateAllDeviceLists()
|
||||
deviceListManager.refreshOutdatedDeviceLists()
|
||||
} else {
|
||||
incomingRoomKeyRequestManager.processReceivedRoomKeyRequests()
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -320,9 +302,7 @@ internal class CryptoManager(
|
||||
*/
|
||||
fun close() {
|
||||
olmDevice.release()
|
||||
|
||||
cryptoStore.close()
|
||||
|
||||
outgoingRoomKeyRequestManager.stop()
|
||||
}
|
||||
|
||||
@ -351,19 +331,20 @@ internal class CryptoManager(
|
||||
* @param syncResponse the syncResponse
|
||||
*/
|
||||
fun onSyncCompleted(syncResponse: SyncResponse) {
|
||||
if (syncResponse.deviceLists != null) {
|
||||
deviceListManager.handleDeviceListsChanges(syncResponse.deviceLists.changed, syncResponse.deviceLists.left)
|
||||
}
|
||||
if (syncResponse.deviceOneTimeKeysCount != null) {
|
||||
val currentCount = syncResponse.deviceOneTimeKeysCount.signedCurve25519 ?: 0
|
||||
oneTimeKeysUploader.updateOneTimeKeyCount(currentCount)
|
||||
}
|
||||
|
||||
if (isStarted()) {
|
||||
// Make sure we process to-device messages before generating new one-time-keys #2782
|
||||
deviceListManager.refreshOutdatedDeviceLists()
|
||||
oneTimeKeysUploader.maybeUploadOneTimeKeys()
|
||||
incomingRoomKeyRequestManager.processReceivedRoomKeyRequests()
|
||||
CoroutineScope(coroutineDispatchers.crypto).launch {
|
||||
if (syncResponse.deviceLists != null) {
|
||||
deviceListManager.handleDeviceListsChanges(syncResponse.deviceLists.changed, syncResponse.deviceLists.left)
|
||||
}
|
||||
if (syncResponse.deviceOneTimeKeysCount != null) {
|
||||
val currentCount = syncResponse.deviceOneTimeKeysCount.signedCurve25519 ?: 0
|
||||
oneTimeKeysUploader.updateOneTimeKeyCount(currentCount)
|
||||
}
|
||||
if (isStarted()) {
|
||||
// Make sure we process to-device messages before generating new one-time-keys #2782
|
||||
deviceListManager.refreshOutdatedDeviceLists()
|
||||
oneTimeKeysUploader.maybeUploadOneTimeKeys()
|
||||
incomingRoomKeyRequestManager.processReceivedRoomKeyRequests()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -398,7 +379,7 @@ internal class CryptoManager(
|
||||
/**
|
||||
* Set the devices as known
|
||||
*
|
||||
* @param devices the devices. Note that the mVerified member of the devices in this list will not be updated by this method.
|
||||
* @param devices the devices. Note that the verified member of the devices in this list will not be updated by this method.
|
||||
* @param callback the asynchronous callback
|
||||
*/
|
||||
override fun setDevicesKnown(devices: List<MXDeviceInfo>, callback: MatrixCallback<Unit>?) {
|
||||
@ -431,7 +412,7 @@ internal class CryptoManager(
|
||||
// assume if the device is either verified or blocked
|
||||
// it means that the device is known
|
||||
if (null != device && device.isUnknown) {
|
||||
device.mVerified = MXDeviceInfo.DEVICE_VERIFICATION_UNVERIFIED
|
||||
device.verified = MXDeviceInfo.DEVICE_VERIFICATION_UNVERIFIED
|
||||
isUpdated = true
|
||||
}
|
||||
}
|
||||
@ -459,7 +440,6 @@ internal class CryptoManager(
|
||||
|
||||
/**
|
||||
* Configure a room to use encryption.
|
||||
* This method must be called in getEncryptingThreadHandler
|
||||
*
|
||||
* @param roomId the room id to enable encryption in.
|
||||
* @param algorithm the encryption config for the room.
|
||||
@ -467,7 +447,7 @@ internal class CryptoManager(
|
||||
* @param membersId list of members to start tracking their devices
|
||||
* @return true if the operation succeeds.
|
||||
*/
|
||||
private fun setEncryptionInRoom(roomId: String, algorithm: String?, inhibitDeviceQuery: Boolean, membersId: List<String>): Boolean {
|
||||
private suspend fun setEncryptionInRoom(roomId: String, algorithm: String?, inhibitDeviceQuery: Boolean, membersId: List<String>): Boolean {
|
||||
// If we already have encryption in this room, we should ignore this event
|
||||
// (for now at least. Maybe we should alert the user somehow?)
|
||||
val existingAlgorithm = cryptoStore.getRoomAlgorithm(roomId)
|
||||
@ -578,49 +558,47 @@ internal class CryptoManager(
|
||||
// wait that the crypto is really started
|
||||
if (!isStarted()) {
|
||||
Timber.v("## encryptEventContent() : wait after e2e init")
|
||||
|
||||
start(false)
|
||||
return
|
||||
}
|
||||
|
||||
val userIds = getRoomUserIds(roomId)
|
||||
var alg = synchronized(roomEncryptors) {
|
||||
roomEncryptors[roomId]
|
||||
}
|
||||
if (alg == null) {
|
||||
val algorithm = getEncryptionAlgorithm(roomId)
|
||||
if (null != algorithm) {
|
||||
if (setEncryptionInRoom(roomId, algorithm, false, userIds)) {
|
||||
synchronized(roomEncryptors) {
|
||||
alg = roomEncryptors[roomId]
|
||||
CoroutineScope(coroutineDispatchers.crypto).launch {
|
||||
val userIds = getRoomUserIds(roomId)
|
||||
var alg = synchronized(roomEncryptors) {
|
||||
roomEncryptors[roomId]
|
||||
}
|
||||
if (alg == null) {
|
||||
val algorithm = getEncryptionAlgorithm(roomId)
|
||||
if (algorithm != null) {
|
||||
if (setEncryptionInRoom(roomId, algorithm, false, userIds)) {
|
||||
synchronized(roomEncryptors) {
|
||||
alg = roomEncryptors[roomId]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
val safeAlgorithm = alg
|
||||
if (safeAlgorithm != null) {
|
||||
val t0 = System.currentTimeMillis()
|
||||
Timber.v("## encryptEventContent() starts")
|
||||
safeAlgorithm.encryptEventContent(eventContent, eventType, userIds, object : MatrixCallback<Content> {
|
||||
override fun onSuccess(data: Content) {
|
||||
Timber.v("## encryptEventContent() : succeeds after " + (System.currentTimeMillis() - t0) + " ms")
|
||||
callback.onSuccess(MXEncryptEventContentResult(data, EventType.ENCRYPTED))
|
||||
}
|
||||
|
||||
if (alg != null) {
|
||||
val t0 = System.currentTimeMillis()
|
||||
Timber.v("## encryptEventContent() starts")
|
||||
override fun onFailure(failure: Throwable) {
|
||||
callback.onFailure(failure)
|
||||
}
|
||||
})
|
||||
} else {
|
||||
val algorithm = getEncryptionAlgorithm(roomId)
|
||||
val reason = String.format(MXCryptoError.UNABLE_TO_ENCRYPT_REASON,
|
||||
algorithm ?: MXCryptoError.NO_MORE_ALGORITHM_REASON)
|
||||
Timber.e("## encryptEventContent() : $reason")
|
||||
|
||||
alg!!.encryptEventContent(eventContent, eventType, userIds, object : MatrixCallback<Content> {
|
||||
override fun onSuccess(data: Content) {
|
||||
Timber.v("## encryptEventContent() : succeeds after " + (System.currentTimeMillis() - t0) + " ms")
|
||||
|
||||
callback.onSuccess(MXEncryptEventContentResult(data, EventType.ENCRYPTED))
|
||||
}
|
||||
|
||||
override fun onFailure(failure: Throwable) {
|
||||
callback.onFailure(failure)
|
||||
}
|
||||
})
|
||||
} else {
|
||||
val algorithm = getEncryptionAlgorithm(roomId)
|
||||
val reason = String.format(MXCryptoError.UNABLE_TO_ENCRYPT_REASON,
|
||||
algorithm ?: MXCryptoError.NO_MORE_ALGORITHM_REASON)
|
||||
Timber.e("## encryptEventContent() : $reason")
|
||||
|
||||
callback.onFailure(Failure.CryptoError(MXCryptoError(MXCryptoError.UNABLE_TO_ENCRYPT_ERROR_CODE,
|
||||
MXCryptoError.UNABLE_TO_ENCRYPT, reason)))
|
||||
callback.onFailure(Failure.CryptoError(MXCryptoError(MXCryptoError.UNABLE_TO_ENCRYPT_ERROR_CODE,
|
||||
MXCryptoError.UNABLE_TO_ENCRYPT, reason)))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -633,43 +611,23 @@ internal class CryptoManager(
|
||||
*/
|
||||
@Throws(MXDecryptionException::class)
|
||||
override fun decryptEvent(event: Event, timeline: String): MXEventDecryptionResult? {
|
||||
val eventContent = event.content //wireEventContent?
|
||||
|
||||
if (null == eventContent) {
|
||||
val eventContent = event.content
|
||||
if (eventContent == null) {
|
||||
Timber.e("## decryptEvent : empty event content")
|
||||
return null
|
||||
}
|
||||
|
||||
val results = ArrayList<MXEventDecryptionResult>()
|
||||
val exceptions = ArrayList<MXDecryptionException>()
|
||||
|
||||
var result: MXEventDecryptionResult? = null
|
||||
val alg = roomDecryptorProvider.getOrCreateRoomDecryptor(event.roomId, eventContent["algorithm"] as String)
|
||||
|
||||
if (null == alg) {
|
||||
if (alg == null) {
|
||||
val reason = String.format(MXCryptoError.UNABLE_TO_DECRYPT_REASON, event.eventId, eventContent["algorithm"] as String)
|
||||
Timber.e("## decryptEvent() : $reason")
|
||||
exceptions.add(MXDecryptionException(MXCryptoError(MXCryptoError.UNABLE_TO_DECRYPT_ERROR_CODE,
|
||||
MXCryptoError.UNABLE_TO_DECRYPT, reason)))
|
||||
throw MXDecryptionException(MXCryptoError(MXCryptoError.UNABLE_TO_DECRYPT_ERROR_CODE, MXCryptoError.UNABLE_TO_DECRYPT, reason))
|
||||
} else {
|
||||
try {
|
||||
result = alg.decryptEvent(event, timeline)
|
||||
} catch (decryptionException: MXDecryptionException) {
|
||||
exceptions.add(decryptionException)
|
||||
}
|
||||
|
||||
if (null != result) {
|
||||
results.add(result) // TODO simplify
|
||||
return runBlocking {
|
||||
withContext(coroutineDispatchers.crypto) {
|
||||
alg.decryptEvent(event, timeline)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!exceptions.isEmpty()) {
|
||||
throw exceptions[0]
|
||||
}
|
||||
|
||||
return if (!results.isEmpty()) {
|
||||
results[0]
|
||||
} else null
|
||||
}
|
||||
|
||||
/**
|
||||
@ -687,16 +645,17 @@ internal class CryptoManager(
|
||||
* @param event the event
|
||||
*/
|
||||
fun onToDeviceEvent(event: Event) {
|
||||
if (event.getClearType() == EventType.ROOM_KEY || event.getClearType() == EventType.FORWARDED_ROOM_KEY) {
|
||||
onRoomKeyEvent(event)
|
||||
} else if (event.getClearType() == EventType.ROOM_KEY_REQUEST) {
|
||||
incomingRoomKeyRequestManager.onRoomKeyRequestEvent(event)
|
||||
CoroutineScope(coroutineDispatchers.crypto).launch {
|
||||
if (event.getClearType() == EventType.ROOM_KEY || event.getClearType() == EventType.FORWARDED_ROOM_KEY) {
|
||||
onRoomKeyEvent(event)
|
||||
} else if (event.getClearType() == EventType.ROOM_KEY_REQUEST) {
|
||||
incomingRoomKeyRequestManager.onRoomKeyRequestEvent(event)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle a key event.
|
||||
* This method must be called on getDecryptingThreadHandler() thread.
|
||||
*
|
||||
* @param event the key event.
|
||||
*/
|
||||
@ -798,25 +757,17 @@ internal class CryptoManager(
|
||||
|
||||
/**
|
||||
* Upload my user's device keys.
|
||||
* This method must called on getEncryptingThreadHandler() thread.
|
||||
* The callback will called on UI thread.
|
||||
*
|
||||
* @param callback the asynchronous callback
|
||||
*/
|
||||
private fun uploadDeviceKeys(callback: MatrixCallback<KeysUploadResponse>) {
|
||||
private suspend fun uploadDeviceKeys(): Try<KeysUploadResponse> {
|
||||
// Prepare the device keys data to send
|
||||
// Sign it
|
||||
val canonicalJson = MoshiProvider.getCanonicalJson(Map::class.java, getMyDevice().signalableJSONDictionary())
|
||||
|
||||
getMyDevice().signatures = objectSigner.signObject(canonicalJson)
|
||||
|
||||
// For now, we set the device id explicitly, as we may not be using the
|
||||
// same one as used in login.
|
||||
uploadKeysTask
|
||||
.configureWith(UploadKeysTask.Params(getMyDevice().toDeviceKeys(), null, getMyDevice().deviceId))
|
||||
.executeOn(TaskThread.ENCRYPTION)
|
||||
.dispatchTo(callback)
|
||||
.executeBy(taskExecutor)
|
||||
val uploadDeviceKeysParams = UploadKeysTask.Params(getMyDevice().toDeviceKeys(), null, getMyDevice().deviceId)
|
||||
return uploadKeysTask.execute(uploadDeviceKeysParams)
|
||||
}
|
||||
|
||||
/**
|
||||
@ -934,24 +885,24 @@ internal class CryptoManager(
|
||||
*/
|
||||
fun checkUnknownDevices(userIds: List<String>, callback: MatrixCallback<Unit>) {
|
||||
// force the refresh to ensure that the devices list is up-to-date
|
||||
deviceListManager.downloadKeys(userIds, true, object : MatrixCallback<MXUsersDevicesMap<MXDeviceInfo>> {
|
||||
override fun onSuccess(data: MXUsersDevicesMap<MXDeviceInfo>) {
|
||||
val unknownDevices = getUnknownDevices(data)
|
||||
|
||||
if (unknownDevices.map.isEmpty()) {
|
||||
callback.onSuccess(Unit)
|
||||
} else {
|
||||
// trigger an an unknown devices exception
|
||||
callback.onFailure(
|
||||
Failure.CryptoError(MXCryptoError(MXCryptoError.UNKNOWN_DEVICES_CODE,
|
||||
MXCryptoError.UNABLE_TO_ENCRYPT, MXCryptoError.UNKNOWN_DEVICES_REASON, unknownDevices)))
|
||||
}
|
||||
}
|
||||
|
||||
override fun onFailure(failure: Throwable) {
|
||||
callback.onFailure(failure)
|
||||
}
|
||||
})
|
||||
CoroutineScope(coroutineDispatchers.crypto).launch {
|
||||
deviceListManager
|
||||
.downloadKeys(userIds, true)
|
||||
.fold(
|
||||
{ callback.onFailure(it) },
|
||||
{
|
||||
val unknownDevices = getUnknownDevices(it)
|
||||
if (unknownDevices.map.isEmpty()) {
|
||||
callback.onSuccess(Unit)
|
||||
} else {
|
||||
// trigger an an unknown devices exception
|
||||
callback.onFailure(
|
||||
Failure.CryptoError(MXCryptoError(MXCryptoError.UNKNOWN_DEVICES_CODE,
|
||||
MXCryptoError.UNABLE_TO_ENCRYPT, MXCryptoError.UNKNOWN_DEVICES_REASON, unknownDevices)))
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1091,7 +1042,6 @@ internal class CryptoManager(
|
||||
*/
|
||||
private fun getUnknownDevices(devicesInRoom: MXUsersDevicesMap<MXDeviceInfo>): MXUsersDevicesMap<MXDeviceInfo> {
|
||||
val unknownDevices = MXUsersDevicesMap<MXDeviceInfo>()
|
||||
|
||||
val userIds = devicesInRoom.userIds
|
||||
for (userId in userIds) {
|
||||
val deviceIds = devicesInRoom.getUserDeviceIds(userId)
|
||||
|
@ -19,7 +19,11 @@ package im.vector.matrix.android.internal.crypto
|
||||
import android.content.Context
|
||||
import im.vector.matrix.android.api.auth.data.Credentials
|
||||
import im.vector.matrix.android.api.session.crypto.CryptoService
|
||||
import im.vector.matrix.android.internal.crypto.actions.*
|
||||
import im.vector.matrix.android.internal.crypto.actions.EnsureOlmSessionsForDevicesAction
|
||||
import im.vector.matrix.android.internal.crypto.actions.EnsureOlmSessionsForUsersAction
|
||||
import im.vector.matrix.android.internal.crypto.actions.MegolmSessionDataImporter
|
||||
import im.vector.matrix.android.internal.crypto.actions.MessageEncrypter
|
||||
import im.vector.matrix.android.internal.crypto.actions.SetDeviceVerificationAction
|
||||
import im.vector.matrix.android.internal.crypto.algorithms.megolm.MXMegolmDecryptionFactory
|
||||
import im.vector.matrix.android.internal.crypto.algorithms.megolm.MXMegolmEncryptionFactory
|
||||
import im.vector.matrix.android.internal.crypto.algorithms.olm.MXOlmDecryptionFactory
|
||||
@ -27,14 +31,56 @@ import im.vector.matrix.android.internal.crypto.algorithms.olm.MXOlmEncryptionFa
|
||||
import im.vector.matrix.android.internal.crypto.api.CryptoApi
|
||||
import im.vector.matrix.android.internal.crypto.keysbackup.KeysBackup
|
||||
import im.vector.matrix.android.internal.crypto.keysbackup.api.RoomKeysApi
|
||||
import im.vector.matrix.android.internal.crypto.keysbackup.tasks.*
|
||||
import im.vector.matrix.android.internal.crypto.keysbackup.tasks.CreateKeysBackupVersionTask
|
||||
import im.vector.matrix.android.internal.crypto.keysbackup.tasks.DefaultCreateKeysBackupVersionTask
|
||||
import im.vector.matrix.android.internal.crypto.keysbackup.tasks.DefaultDeleteBackupTask
|
||||
import im.vector.matrix.android.internal.crypto.keysbackup.tasks.DefaultDeleteRoomSessionDataTask
|
||||
import im.vector.matrix.android.internal.crypto.keysbackup.tasks.DefaultDeleteRoomSessionsDataTask
|
||||
import im.vector.matrix.android.internal.crypto.keysbackup.tasks.DefaultDeleteSessionsDataTask
|
||||
import im.vector.matrix.android.internal.crypto.keysbackup.tasks.DefaultGetKeysBackupLastVersionTask
|
||||
import im.vector.matrix.android.internal.crypto.keysbackup.tasks.DefaultGetKeysBackupVersionTask
|
||||
import im.vector.matrix.android.internal.crypto.keysbackup.tasks.DefaultGetRoomSessionDataTask
|
||||
import im.vector.matrix.android.internal.crypto.keysbackup.tasks.DefaultGetRoomSessionsDataTask
|
||||
import im.vector.matrix.android.internal.crypto.keysbackup.tasks.DefaultGetSessionsDataTask
|
||||
import im.vector.matrix.android.internal.crypto.keysbackup.tasks.DefaultStoreRoomSessionDataTask
|
||||
import im.vector.matrix.android.internal.crypto.keysbackup.tasks.DefaultStoreRoomSessionsDataTask
|
||||
import im.vector.matrix.android.internal.crypto.keysbackup.tasks.DefaultStoreSessionsDataTask
|
||||
import im.vector.matrix.android.internal.crypto.keysbackup.tasks.DefaultUpdateKeysBackupVersionTask
|
||||
import im.vector.matrix.android.internal.crypto.keysbackup.tasks.DeleteBackupTask
|
||||
import im.vector.matrix.android.internal.crypto.keysbackup.tasks.DeleteRoomSessionDataTask
|
||||
import im.vector.matrix.android.internal.crypto.keysbackup.tasks.DeleteRoomSessionsDataTask
|
||||
import im.vector.matrix.android.internal.crypto.keysbackup.tasks.DeleteSessionsDataTask
|
||||
import im.vector.matrix.android.internal.crypto.keysbackup.tasks.GetKeysBackupLastVersionTask
|
||||
import im.vector.matrix.android.internal.crypto.keysbackup.tasks.GetKeysBackupVersionTask
|
||||
import im.vector.matrix.android.internal.crypto.keysbackup.tasks.GetRoomSessionDataTask
|
||||
import im.vector.matrix.android.internal.crypto.keysbackup.tasks.GetRoomSessionsDataTask
|
||||
import im.vector.matrix.android.internal.crypto.keysbackup.tasks.GetSessionsDataTask
|
||||
import im.vector.matrix.android.internal.crypto.keysbackup.tasks.StoreRoomSessionDataTask
|
||||
import im.vector.matrix.android.internal.crypto.keysbackup.tasks.StoreRoomSessionsDataTask
|
||||
import im.vector.matrix.android.internal.crypto.keysbackup.tasks.StoreSessionsDataTask
|
||||
import im.vector.matrix.android.internal.crypto.keysbackup.tasks.UpdateKeysBackupVersionTask
|
||||
import im.vector.matrix.android.internal.crypto.repository.WarnOnUnknownDeviceRepository
|
||||
import im.vector.matrix.android.internal.crypto.store.IMXCryptoStore
|
||||
import im.vector.matrix.android.internal.crypto.store.db.RealmCryptoStore
|
||||
import im.vector.matrix.android.internal.crypto.store.db.RealmCryptoStoreMigration
|
||||
import im.vector.matrix.android.internal.crypto.store.db.RealmCryptoStoreModule
|
||||
import im.vector.matrix.android.internal.crypto.store.db.hash
|
||||
import im.vector.matrix.android.internal.crypto.tasks.*
|
||||
import im.vector.matrix.android.internal.crypto.tasks.ClaimOneTimeKeysForUsersDeviceTask
|
||||
import im.vector.matrix.android.internal.crypto.tasks.DefaultClaimOneTimeKeysForUsersDevice
|
||||
import im.vector.matrix.android.internal.crypto.tasks.DefaultDeleteDeviceTask
|
||||
import im.vector.matrix.android.internal.crypto.tasks.DefaultDownloadKeysForUsers
|
||||
import im.vector.matrix.android.internal.crypto.tasks.DefaultGetDevicesTask
|
||||
import im.vector.matrix.android.internal.crypto.tasks.DefaultGetKeyChangesTask
|
||||
import im.vector.matrix.android.internal.crypto.tasks.DefaultSendToDeviceTask
|
||||
import im.vector.matrix.android.internal.crypto.tasks.DefaultSetDeviceNameTask
|
||||
import im.vector.matrix.android.internal.crypto.tasks.DefaultUploadKeysTask
|
||||
import im.vector.matrix.android.internal.crypto.tasks.DeleteDeviceTask
|
||||
import im.vector.matrix.android.internal.crypto.tasks.DownloadKeysForUsersTask
|
||||
import im.vector.matrix.android.internal.crypto.tasks.GetDevicesTask
|
||||
import im.vector.matrix.android.internal.crypto.tasks.GetKeyChangesTask
|
||||
import im.vector.matrix.android.internal.crypto.tasks.SendToDeviceTask
|
||||
import im.vector.matrix.android.internal.crypto.tasks.SetDeviceNameTask
|
||||
import im.vector.matrix.android.internal.crypto.tasks.UploadKeysTask
|
||||
import im.vector.matrix.android.internal.crypto.verification.DefaultSasVerificationService
|
||||
import im.vector.matrix.android.internal.session.DefaultSession
|
||||
import io.realm.RealmConfiguration
|
||||
@ -109,7 +155,7 @@ internal class CryptoModule {
|
||||
|
||||
// OneTimeKeysUploader
|
||||
scope(DefaultSession.SCOPE) {
|
||||
OneTimeKeysUploader(get(), get(), get(), get(), get())
|
||||
OneTimeKeysUploader(get(), get(), get(), get())
|
||||
}
|
||||
|
||||
// Actions
|
||||
@ -164,7 +210,7 @@ internal class CryptoModule {
|
||||
|
||||
scope(DefaultSession.SCOPE) {
|
||||
MXOlmEncryptionFactory(
|
||||
get(), get(), get(), get(), get(),get()
|
||||
get(), get(), get(), get(), get(), get()
|
||||
)
|
||||
}
|
||||
|
||||
@ -217,7 +263,7 @@ internal class CryptoModule {
|
||||
|
||||
// Device list
|
||||
scope(DefaultSession.SCOPE) {
|
||||
DeviceListManager(get(), get(), get(), get(), get(), get(), get())
|
||||
DeviceListManager(get(), get(), get(), get(), get())
|
||||
}
|
||||
|
||||
// Crypto tasks
|
||||
@ -319,7 +365,7 @@ internal class CryptoModule {
|
||||
* ========================================================================================== */
|
||||
|
||||
scope(DefaultSession.SCOPE) {
|
||||
DefaultSasVerificationService(get(), get(), get(), get(), get(), get(), get())
|
||||
DefaultSasVerificationService(get(), get(), get(), get(), get(), get(), get(), get())
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -18,19 +18,15 @@
|
||||
package im.vector.matrix.android.internal.crypto
|
||||
|
||||
import android.text.TextUtils
|
||||
import im.vector.matrix.android.api.MatrixCallback
|
||||
import arrow.core.Try
|
||||
import arrow.instances.`try`.applicativeError.handleError
|
||||
import im.vector.matrix.android.api.MatrixPatterns
|
||||
import im.vector.matrix.android.api.auth.data.Credentials
|
||||
import im.vector.matrix.android.internal.crypto.model.MXDeviceInfo
|
||||
import im.vector.matrix.android.internal.crypto.model.MXUsersDevicesMap
|
||||
import im.vector.matrix.android.internal.crypto.model.rest.KeysQueryResponse
|
||||
import im.vector.matrix.android.internal.crypto.store.IMXCryptoStore
|
||||
import im.vector.matrix.android.internal.crypto.tasks.DownloadKeysForUsersTask
|
||||
import im.vector.matrix.android.internal.session.sync.SyncTokenStore
|
||||
import im.vector.matrix.android.internal.task.TaskExecutor
|
||||
import im.vector.matrix.android.internal.task.TaskThread
|
||||
import im.vector.matrix.android.internal.task.configureWith
|
||||
import im.vector.matrix.android.internal.util.MatrixCoroutineDispatchers
|
||||
import timber.log.Timber
|
||||
import java.util.*
|
||||
|
||||
@ -39,59 +35,22 @@ internal class DeviceListManager(private val cryptoStore: IMXCryptoStore,
|
||||
private val olmDevice: MXOlmDevice,
|
||||
private val syncTokenStore: SyncTokenStore,
|
||||
private val credentials: Credentials,
|
||||
private val downloadKeysForUsersTask: DownloadKeysForUsersTask,
|
||||
private val coroutineDispatchers: MatrixCoroutineDispatchers,
|
||||
private val taskExecutor: TaskExecutor) {
|
||||
|
||||
// keys in progress
|
||||
private val userKeyDownloadsInProgress = HashSet<String>()
|
||||
private val downloadKeysForUsersTask: DownloadKeysForUsersTask) {
|
||||
|
||||
// HS not ready for retry
|
||||
private val notReadyToRetryHS = HashSet<String>()
|
||||
|
||||
// indexed by UserId
|
||||
private val pendingDownloadKeysRequestToken = HashMap<String, String>()
|
||||
|
||||
// pending queues list
|
||||
private val downloadKeysQueues = ArrayList<DownloadKeysPromise>()
|
||||
|
||||
// tells if there is a download keys request in progress
|
||||
private var isDownloadingKeys = false
|
||||
|
||||
/**
|
||||
* Creator
|
||||
*
|
||||
* @param userIds the user ids list
|
||||
* @param callback the asynchronous callback
|
||||
*/
|
||||
internal inner class DownloadKeysPromise(userIds: List<String>,
|
||||
val callback: MatrixCallback<MXUsersDevicesMap<MXDeviceInfo>>?) {
|
||||
// list of remain pending device keys
|
||||
val mPendingUserIdsList: MutableList<String>
|
||||
|
||||
// the unfiltered user ids list
|
||||
val mUserIdsList: List<String>
|
||||
|
||||
init {
|
||||
mPendingUserIdsList = ArrayList(userIds)
|
||||
mUserIdsList = ArrayList(userIds)
|
||||
}
|
||||
}
|
||||
|
||||
init {
|
||||
var isUpdated = false
|
||||
|
||||
val deviceTrackingStatuses = cryptoStore.getDeviceTrackingStatuses().toMutableMap()
|
||||
for (userId in deviceTrackingStatuses.keys) {
|
||||
val status = deviceTrackingStatuses[userId]!!
|
||||
|
||||
if (TRACKING_STATUS_DOWNLOAD_IN_PROGRESS == status || TRACKING_STATUS_UNREACHABLE_SERVER == status) {
|
||||
// if a download was in progress when we got shut down, it isn't any more.
|
||||
deviceTrackingStatuses.put(userId, TRACKING_STATUS_PENDING_DOWNLOAD)
|
||||
isUpdated = true
|
||||
}
|
||||
}
|
||||
|
||||
if (isUpdated) {
|
||||
cryptoStore.saveDeviceTrackingStatuses(deviceTrackingStatuses)
|
||||
}
|
||||
@ -120,43 +79,6 @@ internal class DeviceListManager(private val cryptoStore: IMXCryptoStore,
|
||||
return res
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a download keys promise
|
||||
*
|
||||
* @param userIds the user ids list
|
||||
* @param callback the asynchronous callback
|
||||
* @return the filtered user ids list i.e the one which require a remote request
|
||||
*/
|
||||
private fun addDownloadKeysPromise(userIds: MutableList<String>?, callback: MatrixCallback<MXUsersDevicesMap<MXDeviceInfo>>?): MutableList<String>? {
|
||||
if (null != userIds) {
|
||||
val filteredUserIds = ArrayList<String>()
|
||||
val invalidUserIds = ArrayList<String>()
|
||||
|
||||
for (userId in userIds) {
|
||||
if (MatrixPatterns.isUserId(userId)) {
|
||||
filteredUserIds.add(userId)
|
||||
} else {
|
||||
Timber.e("## userId " + userId + "is not a valid user id")
|
||||
invalidUserIds.add(userId)
|
||||
}
|
||||
}
|
||||
|
||||
synchronized(userKeyDownloadsInProgress) {
|
||||
filteredUserIds.removeAll(userKeyDownloadsInProgress)
|
||||
userKeyDownloadsInProgress.addAll(userIds)
|
||||
// got some email addresses instead of matrix ids
|
||||
userKeyDownloadsInProgress.removeAll(invalidUserIds)
|
||||
userIds.removeAll(invalidUserIds)
|
||||
}
|
||||
|
||||
downloadKeysQueues.add(DownloadKeysPromise(userIds, callback))
|
||||
|
||||
return filteredUserIds
|
||||
} else {
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear the unavailable server lists
|
||||
*/
|
||||
@ -180,7 +102,7 @@ internal class DeviceListManager(private val cryptoStore: IMXCryptoStore,
|
||||
for (userId in userIds) {
|
||||
if (!deviceTrackingStatuses.containsKey(userId) || TRACKING_STATUS_NOT_TRACKED == deviceTrackingStatuses[userId]) {
|
||||
Timber.v("## startTrackingDeviceList() : Now tracking device list for $userId")
|
||||
deviceTrackingStatuses.put(userId, TRACKING_STATUS_PENDING_DOWNLOAD)
|
||||
deviceTrackingStatuses[userId] = TRACKING_STATUS_PENDING_DOWNLOAD
|
||||
isUpdated = true
|
||||
}
|
||||
}
|
||||
@ -202,24 +124,20 @@ internal class DeviceListManager(private val cryptoStore: IMXCryptoStore,
|
||||
val deviceTrackingStatuses = cryptoStore.getDeviceTrackingStatuses().toMutableMap()
|
||||
|
||||
if (changed?.isNotEmpty() == true) {
|
||||
clearUnavailableServersList()
|
||||
|
||||
for (userId in changed) {
|
||||
if (deviceTrackingStatuses.containsKey(userId)) {
|
||||
Timber.v("## invalidateUserDeviceList() : Marking device list outdated for $userId")
|
||||
deviceTrackingStatuses.put(userId, TRACKING_STATUS_PENDING_DOWNLOAD)
|
||||
deviceTrackingStatuses[userId] = TRACKING_STATUS_PENDING_DOWNLOAD
|
||||
isUpdated = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (left?.isNotEmpty() == true) {
|
||||
clearUnavailableServersList()
|
||||
|
||||
for (userId in left) {
|
||||
if (deviceTrackingStatuses.containsKey(userId)) {
|
||||
Timber.v("## invalidateUserDeviceList() : No longer tracking device list for $userId")
|
||||
deviceTrackingStatuses.put(userId, TRACKING_STATUS_NOT_TRACKED)
|
||||
deviceTrackingStatuses[userId] = TRACKING_STATUS_NOT_TRACKED
|
||||
isUpdated = true
|
||||
}
|
||||
}
|
||||
@ -243,21 +161,12 @@ internal class DeviceListManager(private val cryptoStore: IMXCryptoStore,
|
||||
*
|
||||
* @param userIds the user ids list
|
||||
*/
|
||||
private fun onKeysDownloadFailed(userIds: List<String>?) {
|
||||
if (null != userIds) {
|
||||
synchronized(userKeyDownloadsInProgress) {
|
||||
val deviceTrackingStatuses = cryptoStore.getDeviceTrackingStatuses().toMutableMap()
|
||||
|
||||
for (userId in userIds) {
|
||||
userKeyDownloadsInProgress.remove(userId)
|
||||
deviceTrackingStatuses.put(userId, TRACKING_STATUS_PENDING_DOWNLOAD)
|
||||
}
|
||||
|
||||
cryptoStore.saveDeviceTrackingStatuses(deviceTrackingStatuses)
|
||||
}
|
||||
private fun onKeysDownloadFailed(userIds: List<String>) {
|
||||
val deviceTrackingStatuses = cryptoStore.getDeviceTrackingStatuses().toMutableMap()
|
||||
for (userId in userIds) {
|
||||
deviceTrackingStatuses[userId] = TRACKING_STATUS_PENDING_DOWNLOAD
|
||||
}
|
||||
|
||||
isDownloadingKeys = false
|
||||
cryptoStore.saveDeviceTrackingStatuses(deviceTrackingStatuses)
|
||||
}
|
||||
|
||||
/**
|
||||
@ -266,23 +175,19 @@ internal class DeviceListManager(private val cryptoStore: IMXCryptoStore,
|
||||
* @param userIds the userIds list
|
||||
* @param failures the failure map.
|
||||
*/
|
||||
private fun onKeysDownloadSucceed(userIds: List<String>?, failures: Map<String, Map<String, Any>>?) {
|
||||
if (null != failures) {
|
||||
private fun onKeysDownloadSucceed(userIds: List<String>, failures: Map<String, Map<String, Any>>?): MXUsersDevicesMap<MXDeviceInfo> {
|
||||
if (failures != null) {
|
||||
val keys = failures.keys
|
||||
|
||||
for (k in keys) {
|
||||
val value = failures[k]
|
||||
|
||||
if (value!!.containsKey("status")) {
|
||||
val statusCodeAsVoid = value["status"]
|
||||
var statusCode = 0
|
||||
|
||||
if (statusCodeAsVoid is Double) {
|
||||
statusCode = statusCodeAsVoid.toInt()
|
||||
} else if (statusCodeAsVoid is Int) {
|
||||
statusCode = statusCodeAsVoid.toInt()
|
||||
}
|
||||
|
||||
if (statusCode == 503) {
|
||||
synchronized(notReadyToRetryHS) {
|
||||
notReadyToRetryHS.add(k)
|
||||
@ -291,65 +196,33 @@ internal class DeviceListManager(private val cryptoStore: IMXCryptoStore,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
val deviceTrackingStatuses = cryptoStore.getDeviceTrackingStatuses().toMutableMap()
|
||||
|
||||
if (null != userIds) {
|
||||
if (downloadKeysQueues.size > 0) {
|
||||
val promisesToRemove = ArrayList<DownloadKeysPromise>()
|
||||
|
||||
for (promise in downloadKeysQueues) {
|
||||
promise.mPendingUserIdsList.removeAll(userIds)
|
||||
|
||||
if (promise.mPendingUserIdsList.size == 0) {
|
||||
// private members
|
||||
val usersDevicesInfoMap = MXUsersDevicesMap<MXDeviceInfo>()
|
||||
|
||||
for (userId in promise.mUserIdsList) {
|
||||
val devices = cryptoStore.getUserDevices(userId)
|
||||
if (null == devices) {
|
||||
if (canRetryKeysDownload(userId)) {
|
||||
deviceTrackingStatuses.put(userId, TRACKING_STATUS_PENDING_DOWNLOAD)
|
||||
Timber.e("failed to retry the devices of $userId : retry later")
|
||||
} else {
|
||||
if (deviceTrackingStatuses.containsKey(userId) && TRACKING_STATUS_DOWNLOAD_IN_PROGRESS == deviceTrackingStatuses[userId]) {
|
||||
deviceTrackingStatuses.put(userId, TRACKING_STATUS_UNREACHABLE_SERVER)
|
||||
Timber.e("failed to retry the devices of $userId : the HS is not available")
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (deviceTrackingStatuses.containsKey(userId) && TRACKING_STATUS_DOWNLOAD_IN_PROGRESS == deviceTrackingStatuses[userId]) {
|
||||
// we didn't get any new invalidations since this download started:
|
||||
// this user's device list is now up to date.
|
||||
deviceTrackingStatuses.put(userId, TRACKING_STATUS_UP_TO_DATE)
|
||||
Timber.v("Device list for $userId now up to date")
|
||||
}
|
||||
|
||||
// And the response result
|
||||
usersDevicesInfoMap.setObjects(devices, userId)
|
||||
}
|
||||
}
|
||||
|
||||
val callback = promise.callback
|
||||
|
||||
if (null != callback) {
|
||||
CryptoAsyncHelper.getUiHandler().post { callback.onSuccess(usersDevicesInfoMap) }
|
||||
}
|
||||
|
||||
promisesToRemove.add(promise)
|
||||
val usersDevicesInfoMap = MXUsersDevicesMap<MXDeviceInfo>()
|
||||
for (userId in userIds) {
|
||||
val devices = cryptoStore.getUserDevices(userId)
|
||||
if (null == devices) {
|
||||
if (canRetryKeysDownload(userId)) {
|
||||
deviceTrackingStatuses[userId] = TRACKING_STATUS_PENDING_DOWNLOAD
|
||||
Timber.e("failed to retry the devices of $userId : retry later")
|
||||
} else {
|
||||
if (deviceTrackingStatuses.containsKey(userId) && TRACKING_STATUS_DOWNLOAD_IN_PROGRESS == deviceTrackingStatuses[userId]) {
|
||||
deviceTrackingStatuses[userId] = TRACKING_STATUS_UNREACHABLE_SERVER
|
||||
Timber.e("failed to retry the devices of $userId : the HS is not available")
|
||||
}
|
||||
}
|
||||
downloadKeysQueues.removeAll(promisesToRemove)
|
||||
} else {
|
||||
if (deviceTrackingStatuses.containsKey(userId) && TRACKING_STATUS_DOWNLOAD_IN_PROGRESS == deviceTrackingStatuses[userId]) {
|
||||
// we didn't get any new invalidations since this download started:
|
||||
// this user's device list is now up to date.
|
||||
deviceTrackingStatuses[userId] = TRACKING_STATUS_UP_TO_DATE
|
||||
Timber.v("Device list for $userId now up to date")
|
||||
}
|
||||
// And the response result
|
||||
usersDevicesInfoMap.setObjects(devices, userId)
|
||||
}
|
||||
|
||||
for (userId in userIds) {
|
||||
userKeyDownloadsInProgress.remove(userId)
|
||||
}
|
||||
|
||||
cryptoStore.saveDeviceTrackingStatuses(deviceTrackingStatuses)
|
||||
}
|
||||
|
||||
isDownloadingKeys = false
|
||||
cryptoStore.saveDeviceTrackingStatuses(deviceTrackingStatuses)
|
||||
return usersDevicesInfoMap
|
||||
}
|
||||
|
||||
/**
|
||||
@ -361,31 +234,27 @@ internal class DeviceListManager(private val cryptoStore: IMXCryptoStore,
|
||||
* @param forceDownload Always download the keys even if cached.
|
||||
* @param callback the asynchronous callback
|
||||
*/
|
||||
fun downloadKeys(userIds: List<String>?, forceDownload: Boolean, callback: MatrixCallback<MXUsersDevicesMap<MXDeviceInfo>>?) {
|
||||
suspend fun downloadKeys(userIds: List<String>?, forceDownload: Boolean): Try<MXUsersDevicesMap<MXDeviceInfo>> {
|
||||
Timber.v("## downloadKeys() : forceDownload $forceDownload : $userIds")
|
||||
|
||||
// Map from userid -> deviceid -> DeviceInfo
|
||||
val stored = MXUsersDevicesMap<MXDeviceInfo>()
|
||||
|
||||
// List of user ids we need to download keys for
|
||||
val downloadUsers = ArrayList<String>()
|
||||
|
||||
if (null != userIds) {
|
||||
if (forceDownload) {
|
||||
downloadUsers.addAll(userIds)
|
||||
} else {
|
||||
for (userId in userIds) {
|
||||
val status = cryptoStore.getDeviceTrackingStatus(userId, TRACKING_STATUS_NOT_TRACKED)
|
||||
|
||||
// downloading keys ->the keys download won't be triggered twice but the callback requires the dedicated keys
|
||||
// not yet retrieved
|
||||
if (userKeyDownloadsInProgress.contains(userId) || TRACKING_STATUS_UP_TO_DATE != status && TRACKING_STATUS_UNREACHABLE_SERVER != status) {
|
||||
if (TRACKING_STATUS_UP_TO_DATE != status && TRACKING_STATUS_UNREACHABLE_SERVER != status) {
|
||||
downloadUsers.add(userId)
|
||||
} else {
|
||||
val devices = cryptoStore.getUserDevices(userId)
|
||||
|
||||
// should always be true
|
||||
if (null != devices) {
|
||||
if (devices != null) {
|
||||
stored.setObjects(devices, userId)
|
||||
} else {
|
||||
downloadUsers.add(userId)
|
||||
@ -394,31 +263,18 @@ internal class DeviceListManager(private val cryptoStore: IMXCryptoStore,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (0 == downloadUsers.size) {
|
||||
return if (downloadUsers.isEmpty()) {
|
||||
Timber.v("## downloadKeys() : no new user device")
|
||||
|
||||
if (null != callback) {
|
||||
CryptoAsyncHelper.getUiHandler().post { callback.onSuccess(stored) }
|
||||
}
|
||||
Try.just(stored)
|
||||
} else {
|
||||
Timber.v("## downloadKeys() : starts")
|
||||
val t0 = System.currentTimeMillis()
|
||||
|
||||
doKeyDownloadForUsers(downloadUsers, object : MatrixCallback<MXUsersDevicesMap<MXDeviceInfo>> {
|
||||
override fun onSuccess(data: MXUsersDevicesMap<MXDeviceInfo>) {
|
||||
Timber.v("## downloadKeys() : doKeyDownloadForUsers succeeds after " + (System.currentTimeMillis() - t0) + " ms")
|
||||
|
||||
data.addEntriesFromMap(stored)
|
||||
|
||||
callback?.onSuccess(data)
|
||||
}
|
||||
|
||||
override fun onFailure(failure: Throwable) {
|
||||
Timber.e(failure, "## downloadKeys() : doKeyDownloadForUsers onFailure")
|
||||
callback?.onFailure(failure)
|
||||
}
|
||||
})
|
||||
doKeyDownloadForUsers(downloadUsers)
|
||||
.flatMap {
|
||||
Timber.v("## downloadKeys() : doKeyDownloadForUsers succeeds after " + (System.currentTimeMillis() - t0) + " ms")
|
||||
it.addEntriesFromMap(stored)
|
||||
Try.just(it)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -430,134 +286,61 @@ internal class DeviceListManager(private val cryptoStore: IMXCryptoStore,
|
||||
* @param downloadUsers the user ids list
|
||||
* @param callback the asynchronous callback
|
||||
*/
|
||||
private fun doKeyDownloadForUsers(downloadUsers: MutableList<String>, callback: MatrixCallback<MXUsersDevicesMap<MXDeviceInfo>>?) {
|
||||
private suspend fun doKeyDownloadForUsers(downloadUsers: MutableList<String>): Try<MXUsersDevicesMap<MXDeviceInfo>> {
|
||||
Timber.v("## doKeyDownloadForUsers() : doKeyDownloadForUsers $downloadUsers")
|
||||
|
||||
// get the user ids which did not already trigger a keys download
|
||||
val filteredUsers = addDownloadKeysPromise(downloadUsers, callback)
|
||||
|
||||
// if there is no new keys request
|
||||
if (0 == filteredUsers!!.size) {
|
||||
val filteredUsers = downloadUsers.filter { MatrixPatterns.isUserId(it) }
|
||||
if (filteredUsers.isEmpty()) {
|
||||
// trigger nothing
|
||||
return
|
||||
return Try.just(MXUsersDevicesMap())
|
||||
}
|
||||
val params = DownloadKeysForUsersTask.Params(filteredUsers, syncTokenStore.getLastToken())
|
||||
return downloadKeysForUsersTask.execute(params)
|
||||
.map { response ->
|
||||
Timber.v("## doKeyDownloadForUsers() : Got keys for " + filteredUsers.size + " users")
|
||||
for (userId in filteredUsers) {
|
||||
val devices = response.deviceKeys?.get(userId)
|
||||
Timber.v("## doKeyDownloadForUsers() : Got keys for $userId : $devices")
|
||||
if (devices != null) {
|
||||
val mutableDevices = HashMap(devices)
|
||||
val deviceIds = ArrayList(mutableDevices.keys)
|
||||
for (deviceId in deviceIds) {
|
||||
// Get the potential previously store device keys for this device
|
||||
val previouslyStoredDeviceKeys = cryptoStore.getUserDevice(deviceId, userId)
|
||||
val deviceInfo = mutableDevices[deviceId]
|
||||
|
||||
// sanity check
|
||||
//if (null == mxSession.dataHandler || null == mxSession.dataHandler.store) {
|
||||
// return
|
||||
//}
|
||||
|
||||
isDownloadingKeys = true
|
||||
|
||||
// track the race condition while sending requests
|
||||
// we defines a tag for each request
|
||||
// and test if the response is the latest request one
|
||||
val downloadToken = filteredUsers.hashCode().toString() + " " + System.currentTimeMillis()
|
||||
|
||||
for (userId in filteredUsers) {
|
||||
pendingDownloadKeysRequestToken[userId] = downloadToken
|
||||
}
|
||||
|
||||
downloadKeysForUsersTask
|
||||
.configureWith(DownloadKeysForUsersTask.Params(filteredUsers, syncTokenStore.getLastToken()))
|
||||
.executeOn(TaskThread.ENCRYPTION)
|
||||
.dispatchTo(object : MatrixCallback<KeysQueryResponse> {
|
||||
override fun onSuccess(data: KeysQueryResponse) {
|
||||
CryptoAsyncHelper.getEncryptBackgroundHandler().post {
|
||||
Timber.v("## doKeyDownloadForUsers() : Got keys for " + filteredUsers.size + " users")
|
||||
val userIdsList = ArrayList(filteredUsers)
|
||||
|
||||
for (userId in userIdsList) {
|
||||
// test if the response is the latest request one
|
||||
if (!TextUtils.equals(pendingDownloadKeysRequestToken[userId], downloadToken)) {
|
||||
Timber.e("## doKeyDownloadForUsers() : Another update in the queue for "
|
||||
+ userId + " not marking up-to-date")
|
||||
filteredUsers.remove(userId)
|
||||
} else {
|
||||
val devices = data.deviceKeys!![userId]
|
||||
|
||||
Timber.v("## doKeyDownloadForUsers() : Got keys for $userId : $devices")
|
||||
|
||||
if (null != devices) {
|
||||
val mutableDevices = HashMap(devices)
|
||||
val deviceIds = ArrayList(mutableDevices.keys)
|
||||
|
||||
for (deviceId in deviceIds) {
|
||||
// the user has been logged out
|
||||
// TODO
|
||||
//if (null == cryptoStore) {
|
||||
// break
|
||||
//}
|
||||
|
||||
// Get the potential previously store device keys for this device
|
||||
val previouslyStoredDeviceKeys = cryptoStore.getUserDevice(deviceId, userId)
|
||||
val deviceInfo = mutableDevices[deviceId]
|
||||
|
||||
// in some race conditions (like unit tests)
|
||||
// the self device must be seen as verified
|
||||
if (TextUtils.equals(deviceInfo!!.deviceId, credentials.deviceId) && TextUtils.equals(userId, credentials.userId)) {
|
||||
deviceInfo.mVerified = MXDeviceInfo.DEVICE_VERIFICATION_VERIFIED
|
||||
}
|
||||
|
||||
// Validate received keys
|
||||
if (!validateDeviceKeys(deviceInfo, userId, deviceId, previouslyStoredDeviceKeys)) {
|
||||
// New device keys are not valid. Do not store them
|
||||
mutableDevices.remove(deviceId)
|
||||
|
||||
if (null != previouslyStoredDeviceKeys) {
|
||||
// But keep old validated ones if any
|
||||
mutableDevices[deviceId] = previouslyStoredDeviceKeys
|
||||
}
|
||||
} else if (null != previouslyStoredDeviceKeys) {
|
||||
// The verified status is not sync'ed with hs.
|
||||
// This is a client side information, valid only for this client.
|
||||
// So, transfer its previous value
|
||||
mutableDevices[deviceId]!!.mVerified = previouslyStoredDeviceKeys.mVerified
|
||||
}
|
||||
}
|
||||
|
||||
// Update the store
|
||||
// Note that devices which aren't in the response will be removed from the stores
|
||||
cryptoStore.storeUserDevices(userId, mutableDevices)
|
||||
// in some race conditions (like unit tests)
|
||||
// the self device must be seen as verified
|
||||
if (TextUtils.equals(deviceInfo!!.deviceId, credentials.deviceId) && TextUtils.equals(userId, credentials.userId)) {
|
||||
deviceInfo.verified = MXDeviceInfo.DEVICE_VERIFICATION_VERIFIED
|
||||
}
|
||||
// Validate received keys
|
||||
if (!validateDeviceKeys(deviceInfo, userId, deviceId, previouslyStoredDeviceKeys)) {
|
||||
// New device keys are not valid. Do not store them
|
||||
mutableDevices.remove(deviceId)
|
||||
if (null != previouslyStoredDeviceKeys) {
|
||||
// But keep old validated ones if any
|
||||
mutableDevices[deviceId] = previouslyStoredDeviceKeys
|
||||
}
|
||||
|
||||
// the response is the latest request one
|
||||
pendingDownloadKeysRequestToken.remove(userId)
|
||||
} else if (null != previouslyStoredDeviceKeys) {
|
||||
// The verified status is not sync'ed with hs.
|
||||
// This is a client side information, valid only for this client.
|
||||
// So, transfer its previous value
|
||||
mutableDevices[deviceId]!!.verified = previouslyStoredDeviceKeys.verified
|
||||
}
|
||||
}
|
||||
|
||||
onKeysDownloadSucceed(filteredUsers, data.failures)
|
||||
// Update the store
|
||||
// Note that devices which aren't in the response will be removed from the stores
|
||||
cryptoStore.storeUserDevices(userId, mutableDevices)
|
||||
}
|
||||
}
|
||||
|
||||
private fun onFailed() {
|
||||
CryptoAsyncHelper.getEncryptBackgroundHandler().post {
|
||||
val userIdsList = ArrayList(filteredUsers)
|
||||
|
||||
// test if the response is the latest request one
|
||||
for (userId in userIdsList) {
|
||||
if (!TextUtils.equals(pendingDownloadKeysRequestToken[userId], downloadToken)) {
|
||||
Timber.e("## doKeyDownloadForUsers() : Another update in the queue for $userId not marking up-to-date")
|
||||
filteredUsers.remove(userId)
|
||||
} else {
|
||||
// the response is the latest request one
|
||||
pendingDownloadKeysRequestToken.remove(userId)
|
||||
}
|
||||
}
|
||||
|
||||
onKeysDownloadFailed(filteredUsers)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onFailure(failure: Throwable) {
|
||||
Timber.e(failure, "##doKeyDownloadForUsers() : onNetworkError")
|
||||
|
||||
onFailed()
|
||||
|
||||
callback?.onFailure(failure)
|
||||
}
|
||||
})
|
||||
.executeBy(taskExecutor)
|
||||
onKeysDownloadSucceed(filteredUsers, response.failures)
|
||||
}
|
||||
.handleError {
|
||||
Timber.e(it, "##doKeyDownloadForUsers(): error")
|
||||
onKeysDownloadFailed(filteredUsers)
|
||||
throw it
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -631,7 +414,7 @@ internal class DeviceListManager(private val cryptoStore: IMXCryptoStore,
|
||||
|
||||
if (!isVerified) {
|
||||
Timber.e("## validateDeviceKeys() : Unable to verify signature on device " + userId + ":"
|
||||
+ deviceKeys.deviceId + " with error " + errorMessage)
|
||||
+ deviceKeys.deviceId + " with error " + errorMessage)
|
||||
return false
|
||||
}
|
||||
|
||||
@ -642,8 +425,8 @@ internal class DeviceListManager(private val cryptoStore: IMXCryptoStore,
|
||||
//
|
||||
// Should we warn the user about it somehow?
|
||||
Timber.e("## validateDeviceKeys() : WARNING:Ed25519 key for device " + userId + ":"
|
||||
+ deviceKeys.deviceId + " has changed : "
|
||||
+ previouslyStoredDeviceKeys.fingerprint() + " -> " + signKey)
|
||||
+ deviceKeys.deviceId + " has changed : "
|
||||
+ previouslyStoredDeviceKeys.fingerprint() + " -> " + signKey)
|
||||
|
||||
Timber.e("## validateDeviceKeys() : $previouslyStoredDeviceKeys -> $deviceKeys")
|
||||
Timber.e("## validateDeviceKeys() : " + previouslyStoredDeviceKeys.keys + " -> " + deviceKeys.keys)
|
||||
@ -659,7 +442,7 @@ internal class DeviceListManager(private val cryptoStore: IMXCryptoStore,
|
||||
* Start device queries for any users who sent us an m.new_device recently
|
||||
* This method must be called on getEncryptingThreadHandler() thread.
|
||||
*/
|
||||
fun refreshOutdatedDeviceLists() {
|
||||
suspend fun refreshOutdatedDeviceLists() {
|
||||
val users = ArrayList<String>()
|
||||
|
||||
val deviceTrackingStatuses = cryptoStore.getDeviceTrackingStatuses().toMutableMap()
|
||||
@ -674,33 +457,24 @@ internal class DeviceListManager(private val cryptoStore: IMXCryptoStore,
|
||||
return
|
||||
}
|
||||
|
||||
if (isDownloadingKeys) {
|
||||
// request already in progress - do nothing. (We will automatically
|
||||
// make another request if there are more users with outdated
|
||||
// device lists when the current request completes).
|
||||
return
|
||||
}
|
||||
|
||||
// update the statuses
|
||||
for (userId in users) {
|
||||
val status = deviceTrackingStatuses[userId]
|
||||
|
||||
if (null != status && TRACKING_STATUS_PENDING_DOWNLOAD == status) {
|
||||
deviceTrackingStatuses.put(userId, TRACKING_STATUS_DOWNLOAD_IN_PROGRESS)
|
||||
}
|
||||
}
|
||||
|
||||
cryptoStore.saveDeviceTrackingStatuses(deviceTrackingStatuses)
|
||||
|
||||
doKeyDownloadForUsers(users, object : MatrixCallback<MXUsersDevicesMap<MXDeviceInfo>> {
|
||||
override fun onSuccess(data: MXUsersDevicesMap<MXDeviceInfo>) {
|
||||
CryptoAsyncHelper.getEncryptBackgroundHandler().post { Timber.v("## refreshOutdatedDeviceLists() : done") }
|
||||
}
|
||||
|
||||
override fun onFailure(failure: Throwable) {
|
||||
Timber.e(failure, "## refreshOutdatedDeviceLists() : ERROR updating device keys for users $users")
|
||||
}
|
||||
})
|
||||
doKeyDownloadForUsers(users)
|
||||
.fold(
|
||||
{
|
||||
Timber.e(it, "## refreshOutdatedDeviceLists() : ERROR updating device keys for users $users")
|
||||
},
|
||||
{
|
||||
Timber.v("## refreshOutdatedDeviceLists() : done")
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
@ -133,7 +133,7 @@ internal class IncomingRoomKeyRequestManager(
|
||||
if (device.isVerified) {
|
||||
Timber.v("## processReceivedRoomKeyRequests() : device is already verified: sharing keys")
|
||||
mCryptoStore.deleteIncomingRoomKeyRequest(request)
|
||||
request.share!!.run()
|
||||
request.share?.run()
|
||||
continue
|
||||
}
|
||||
|
||||
|
@ -38,7 +38,7 @@ internal class MXOlmDevice(
|
||||
/**
|
||||
* The store where crypto data is saved.
|
||||
*/
|
||||
private val mStore: IMXCryptoStore) {
|
||||
private val store: IMXCryptoStore) {
|
||||
|
||||
/**
|
||||
* @return the Curve25519 key for the account.
|
||||
@ -53,16 +53,16 @@ internal class MXOlmDevice(
|
||||
private set
|
||||
|
||||
// The OLM lib account instance.
|
||||
private var mOlmAccount: OlmAccount? = null
|
||||
private var olmAccount: OlmAccount? = null
|
||||
|
||||
// The OLM lib utility instance.
|
||||
private var mOlmUtility: OlmUtility? = null
|
||||
private var olmUtility: OlmUtility? = null
|
||||
|
||||
// The outbound group session.
|
||||
// They are not stored in 'store' to avoid to remember to which devices we sent the session key.
|
||||
// Plus, in cryptography, it is good to refresh sessions from time to time.
|
||||
// The key is the session id, the value the outbound group session.
|
||||
private val mOutboundGroupSessionStore: MutableMap<String, OlmOutboundGroupSession> = HashMap()
|
||||
private val outboundGroupSessionStore: MutableMap<String, OlmOutboundGroupSession> = HashMap()
|
||||
|
||||
// Store a set of decrypted message indexes for each group session.
|
||||
// This partially mitigates a replay attack where a MITM resends a group
|
||||
@ -76,25 +76,25 @@ internal class MXOlmDevice(
|
||||
// The first level keys are timeline ids.
|
||||
// The second level keys are strings of form "<senderKey>|<session_id>|<message_index>"
|
||||
// Values are true.
|
||||
private val mInboundGroupSessionMessageIndexes: MutableMap<String, MutableMap<String, Boolean>> = HashMap()
|
||||
private val inboundGroupSessionMessageIndexes: MutableMap<String, MutableMap<String, Boolean>> = HashMap()
|
||||
|
||||
/**
|
||||
* inboundGroupSessionWithId error
|
||||
*/
|
||||
private var mInboundGroupSessionWithIdError: MXCryptoError? = null
|
||||
private var inboundGroupSessionWithIdError: MXCryptoError? = null
|
||||
|
||||
init {
|
||||
// Retrieve the account from the store
|
||||
mOlmAccount = mStore.getAccount()
|
||||
olmAccount = store.getAccount()
|
||||
|
||||
if (null == mOlmAccount) {
|
||||
if (null == olmAccount) {
|
||||
Timber.v("MXOlmDevice : create a new olm account")
|
||||
// Else, create it
|
||||
try {
|
||||
mOlmAccount = OlmAccount()
|
||||
mStore.storeAccount(mOlmAccount!!)
|
||||
olmAccount = OlmAccount()
|
||||
store.storeAccount(olmAccount!!)
|
||||
} catch (e: Exception) {
|
||||
Timber.e(e, "MXOlmDevice : cannot initialize mOlmAccount")
|
||||
Timber.e(e, "MXOlmDevice : cannot initialize olmAccount")
|
||||
}
|
||||
|
||||
} else {
|
||||
@ -102,20 +102,20 @@ internal class MXOlmDevice(
|
||||
}
|
||||
|
||||
try {
|
||||
mOlmUtility = OlmUtility()
|
||||
olmUtility = OlmUtility()
|
||||
} catch (e: Exception) {
|
||||
Timber.e(e, "## MXOlmDevice : OlmUtility failed with error")
|
||||
mOlmUtility = null
|
||||
olmUtility = null
|
||||
}
|
||||
|
||||
try {
|
||||
deviceCurve25519Key = mOlmAccount!!.identityKeys()[OlmAccount.JSON_KEY_IDENTITY_KEY]
|
||||
deviceCurve25519Key = olmAccount!!.identityKeys()[OlmAccount.JSON_KEY_IDENTITY_KEY]
|
||||
} catch (e: Exception) {
|
||||
Timber.e(e, "## MXOlmDevice : cannot find " + OlmAccount.JSON_KEY_IDENTITY_KEY + " with error")
|
||||
}
|
||||
|
||||
try {
|
||||
deviceEd25519Key = mOlmAccount!!.identityKeys()[OlmAccount.JSON_KEY_FINGER_PRINT_KEY]
|
||||
deviceEd25519Key = olmAccount!!.identityKeys()[OlmAccount.JSON_KEY_FINGER_PRINT_KEY]
|
||||
} catch (e: Exception) {
|
||||
Timber.e(e, "## MXOlmDevice : cannot find " + OlmAccount.JSON_KEY_FINGER_PRINT_KEY + " with error")
|
||||
}
|
||||
@ -126,7 +126,7 @@ internal class MXOlmDevice(
|
||||
*/
|
||||
fun getOneTimeKeys(): Map<String, Map<String, String>>? {
|
||||
try {
|
||||
return mOlmAccount!!.oneTimeKeys()
|
||||
return olmAccount!!.oneTimeKeys()
|
||||
} catch (e: Exception) {
|
||||
Timber.e(e, "## getOneTimeKeys() : failed")
|
||||
}
|
||||
@ -138,14 +138,14 @@ internal class MXOlmDevice(
|
||||
* @return The maximum number of one-time keys the olm account can store.
|
||||
*/
|
||||
fun getMaxNumberOfOneTimeKeys(): Long {
|
||||
return mOlmAccount?.maxOneTimeKeys() ?: -1
|
||||
return olmAccount?.maxOneTimeKeys() ?: -1
|
||||
}
|
||||
|
||||
/**
|
||||
* Release the instance
|
||||
*/
|
||||
fun release() {
|
||||
mOlmAccount?.releaseAccount()
|
||||
olmAccount?.releaseAccount()
|
||||
}
|
||||
|
||||
/**
|
||||
@ -156,7 +156,7 @@ internal class MXOlmDevice(
|
||||
*/
|
||||
fun signMessage(message: String): String? {
|
||||
try {
|
||||
return mOlmAccount!!.signMessage(message)
|
||||
return olmAccount!!.signMessage(message)
|
||||
} catch (e: Exception) {
|
||||
Timber.e(e, "## signMessage() : failed")
|
||||
}
|
||||
@ -169,8 +169,8 @@ internal class MXOlmDevice(
|
||||
*/
|
||||
fun markKeysAsPublished() {
|
||||
try {
|
||||
mOlmAccount!!.markOneTimeKeysAsPublished()
|
||||
mStore.storeAccount(mOlmAccount!!)
|
||||
olmAccount!!.markOneTimeKeysAsPublished()
|
||||
store.storeAccount(olmAccount!!)
|
||||
} catch (e: Exception) {
|
||||
Timber.e(e, "## markKeysAsPublished() : failed")
|
||||
}
|
||||
@ -183,8 +183,8 @@ internal class MXOlmDevice(
|
||||
*/
|
||||
fun generateOneTimeKeys(numKeys: Int) {
|
||||
try {
|
||||
mOlmAccount!!.generateOneTimeKeys(numKeys)
|
||||
mStore.storeAccount(mOlmAccount!!)
|
||||
olmAccount!!.generateOneTimeKeys(numKeys)
|
||||
store.storeAccount(olmAccount!!)
|
||||
} catch (e: Exception) {
|
||||
Timber.e(e, "## generateOneTimeKeys() : failed")
|
||||
}
|
||||
@ -204,7 +204,7 @@ internal class MXOlmDevice(
|
||||
|
||||
try {
|
||||
olmSession = OlmSession()
|
||||
olmSession.initOutboundSession(mOlmAccount!!, theirIdentityKey, theirOneTimeKey)
|
||||
olmSession.initOutboundSession(olmAccount!!, theirIdentityKey, theirOneTimeKey)
|
||||
|
||||
val mxOlmSession = MXOlmSession(olmSession, 0)
|
||||
|
||||
@ -213,7 +213,7 @@ internal class MXOlmDevice(
|
||||
// this session
|
||||
mxOlmSession.onMessageReceived()
|
||||
|
||||
mStore.storeSession(mxOlmSession, theirIdentityKey)
|
||||
store.storeSession(mxOlmSession, theirIdentityKey)
|
||||
|
||||
val sessionIdentifier = olmSession.sessionIdentifier()
|
||||
|
||||
@ -246,7 +246,7 @@ internal class MXOlmDevice(
|
||||
try {
|
||||
try {
|
||||
olmSession = OlmSession()
|
||||
olmSession.initInboundSessionFrom(mOlmAccount!!, theirDeviceIdentityKey, ciphertext)
|
||||
olmSession.initInboundSessionFrom(olmAccount!!, theirDeviceIdentityKey, ciphertext)
|
||||
} catch (e: Exception) {
|
||||
Timber.e(e, "## createInboundSession() : the session creation failed")
|
||||
return null
|
||||
@ -255,15 +255,15 @@ internal class MXOlmDevice(
|
||||
Timber.v("## createInboundSession() : sessionId: " + olmSession.sessionIdentifier())
|
||||
|
||||
try {
|
||||
mOlmAccount!!.removeOneTimeKeys(olmSession)
|
||||
mStore.storeAccount(mOlmAccount!!)
|
||||
olmAccount!!.removeOneTimeKeys(olmSession)
|
||||
store.storeAccount(olmAccount!!)
|
||||
} catch (e: Exception) {
|
||||
Timber.e(e, "## createInboundSession() : removeOneTimeKeys failed")
|
||||
}
|
||||
|
||||
Timber.v("## createInboundSession() : ciphertext: $ciphertext")
|
||||
try {
|
||||
val sha256 = mOlmUtility!!.sha256(URLEncoder.encode(ciphertext, "utf-8"))
|
||||
val sha256 = olmUtility!!.sha256(URLEncoder.encode(ciphertext, "utf-8"))
|
||||
Timber.v("## createInboundSession() :ciphertext: SHA256:" + sha256)
|
||||
} catch (e: Exception) {
|
||||
Timber.e(e, "## createInboundSession() :ciphertext: cannot encode ciphertext")
|
||||
@ -282,7 +282,7 @@ internal class MXOlmDevice(
|
||||
// This counts as a received message: set last received message time to now
|
||||
mxOlmSession.onMessageReceived()
|
||||
|
||||
mStore.storeSession(mxOlmSession, theirDeviceIdentityKey)
|
||||
store.storeSession(mxOlmSession, theirDeviceIdentityKey)
|
||||
} catch (e: Exception) {
|
||||
Timber.e(e, "## createInboundSession() : decryptMessage failed")
|
||||
}
|
||||
@ -316,7 +316,7 @@ internal class MXOlmDevice(
|
||||
* @return a list of known session ids for the device.
|
||||
*/
|
||||
fun getSessionIds(theirDeviceIdentityKey: String): Set<String>? {
|
||||
return mStore.getDeviceSessionIds(theirDeviceIdentityKey)
|
||||
return store.getDeviceSessionIds(theirDeviceIdentityKey)
|
||||
}
|
||||
|
||||
/**
|
||||
@ -326,7 +326,7 @@ internal class MXOlmDevice(
|
||||
* @return the session id, or null if no established session.
|
||||
*/
|
||||
fun getSessionId(theirDeviceIdentityKey: String): String? {
|
||||
return mStore.getLastUsedSessionId(theirDeviceIdentityKey)
|
||||
return store.getLastUsedSessionId(theirDeviceIdentityKey)
|
||||
}
|
||||
|
||||
/**
|
||||
@ -348,7 +348,7 @@ internal class MXOlmDevice(
|
||||
//Timber.v("## encryptMessage() : payloadString: " + payloadString);
|
||||
|
||||
olmMessage = mxOlmSession.olmSession.encryptMessage(payloadString)
|
||||
mStore.storeSession(mxOlmSession, theirDeviceIdentityKey)
|
||||
store.storeSession(mxOlmSession, theirDeviceIdentityKey)
|
||||
res = HashMap()
|
||||
|
||||
res["body"] = olmMessage.mCipherText
|
||||
@ -384,7 +384,7 @@ internal class MXOlmDevice(
|
||||
try {
|
||||
payloadString = mxOlmSession.olmSession.decryptMessage(olmMessage)
|
||||
mxOlmSession.onMessageReceived()
|
||||
mStore.storeSession(mxOlmSession, theirDeviceIdentityKey)
|
||||
store.storeSession(mxOlmSession, theirDeviceIdentityKey)
|
||||
} catch (e: Exception) {
|
||||
Timber.e(e, "## decryptMessage() : decryptMessage failed " + e.message)
|
||||
}
|
||||
@ -424,7 +424,7 @@ internal class MXOlmDevice(
|
||||
var session: OlmOutboundGroupSession? = null
|
||||
try {
|
||||
session = OlmOutboundGroupSession()
|
||||
mOutboundGroupSessionStore[session.sessionIdentifier()] = session
|
||||
outboundGroupSessionStore[session.sessionIdentifier()] = session
|
||||
return session.sessionIdentifier()
|
||||
} catch (e: Exception) {
|
||||
Timber.e(e, "createOutboundGroupSession " + e.message)
|
||||
@ -444,7 +444,7 @@ internal class MXOlmDevice(
|
||||
fun getSessionKey(sessionId: String): String? {
|
||||
if (!TextUtils.isEmpty(sessionId)) {
|
||||
try {
|
||||
return mOutboundGroupSessionStore[sessionId]!!.sessionKey()
|
||||
return outboundGroupSessionStore[sessionId]!!.sessionKey()
|
||||
} catch (e: Exception) {
|
||||
Timber.e(e, "## getSessionKey() : failed " + e.message)
|
||||
}
|
||||
@ -461,7 +461,7 @@ internal class MXOlmDevice(
|
||||
*/
|
||||
fun getMessageIndex(sessionId: String): Int {
|
||||
return if (!TextUtils.isEmpty(sessionId)) {
|
||||
mOutboundGroupSessionStore[sessionId]!!.messageIndex()
|
||||
outboundGroupSessionStore[sessionId]!!.messageIndex()
|
||||
} else 0
|
||||
}
|
||||
|
||||
@ -475,7 +475,7 @@ internal class MXOlmDevice(
|
||||
fun encryptGroupMessage(sessionId: String, payloadString: String): String? {
|
||||
if (!TextUtils.isEmpty(sessionId) && !TextUtils.isEmpty(payloadString)) {
|
||||
try {
|
||||
return mOutboundGroupSessionStore[sessionId]!!.encryptMessage(payloadString)
|
||||
return outboundGroupSessionStore[sessionId]!!.encryptMessage(payloadString)
|
||||
} catch (e: Exception) {
|
||||
Timber.e(e, "## encryptGroupMessage() : failed " + e.message)
|
||||
}
|
||||
@ -547,7 +547,7 @@ internal class MXOlmDevice(
|
||||
session.mKeysClaimed = keysClaimed
|
||||
session.mForwardingCurve25519KeyChain = forwardingCurve25519KeyChain
|
||||
|
||||
mStore.storeInboundGroupSessions(listOf(session))
|
||||
store.storeInboundGroupSessions(listOf(session))
|
||||
|
||||
return true
|
||||
}
|
||||
@ -609,7 +609,7 @@ internal class MXOlmDevice(
|
||||
sessions.add(session)
|
||||
}
|
||||
|
||||
mStore.storeInboundGroupSessions(sessions)
|
||||
store.storeInboundGroupSessions(sessions)
|
||||
|
||||
return sessions
|
||||
}
|
||||
@ -622,7 +622,7 @@ internal class MXOlmDevice(
|
||||
*/
|
||||
fun removeInboundGroupSession(sessionId: String?, sessionKey: String?) {
|
||||
if (null != sessionId && null != sessionKey) {
|
||||
mStore.removeInboundGroupSession(sessionId, sessionKey)
|
||||
store.removeInboundGroupSession(sessionId, sessionKey)
|
||||
}
|
||||
}
|
||||
|
||||
@ -660,41 +660,41 @@ internal class MXOlmDevice(
|
||||
|
||||
if (null != decryptResult) {
|
||||
if (null != timeline) {
|
||||
if (!mInboundGroupSessionMessageIndexes.containsKey(timeline)) {
|
||||
mInboundGroupSessionMessageIndexes[timeline] = HashMap()
|
||||
if (!inboundGroupSessionMessageIndexes.containsKey(timeline)) {
|
||||
inboundGroupSessionMessageIndexes[timeline] = HashMap()
|
||||
}
|
||||
|
||||
val messageIndexKey = senderKey + "|" + sessionId + "|" + decryptResult.mIndex
|
||||
|
||||
if (null != mInboundGroupSessionMessageIndexes[timeline]!![messageIndexKey]) {
|
||||
if (null != inboundGroupSessionMessageIndexes[timeline]!![messageIndexKey]) {
|
||||
val reason = String.format(MXCryptoError.DUPLICATE_MESSAGE_INDEX_REASON, decryptResult.mIndex)
|
||||
Timber.e("## decryptGroupMessage() : $reason")
|
||||
throw MXDecryptionException(MXCryptoError(MXCryptoError.DUPLICATED_MESSAGE_INDEX_ERROR_CODE,
|
||||
MXCryptoError.UNABLE_TO_DECRYPT, reason))
|
||||
}
|
||||
|
||||
mInboundGroupSessionMessageIndexes[timeline]!!.put(messageIndexKey, true)
|
||||
inboundGroupSessionMessageIndexes[timeline]!!.put(messageIndexKey, true)
|
||||
}
|
||||
|
||||
mStore.storeInboundGroupSessions(listOf(session))
|
||||
store.storeInboundGroupSessions(listOf(session))
|
||||
try {
|
||||
val adapter = MoshiProvider.providesMoshi().adapter<JsonDict>(JSON_DICT_PARAMETERIZED_TYPE)
|
||||
val payloadString = convertFromUTF8(decryptResult.mDecryptedMessage)
|
||||
val payload = adapter.fromJson(payloadString)
|
||||
result.mPayload = payload
|
||||
result.payload = payload
|
||||
} catch (e: Exception) {
|
||||
Timber.e(e, "## decryptGroupMessage() : RLEncoder.encode failed " + e.message)
|
||||
return null
|
||||
}
|
||||
|
||||
if (null == result.mPayload) {
|
||||
if (null == result.payload) {
|
||||
Timber.e("## decryptGroupMessage() : fails to parse the payload")
|
||||
return null
|
||||
}
|
||||
|
||||
result.mKeysClaimed = session.mKeysClaimed
|
||||
result.mSenderKey = senderKey
|
||||
result.mForwardingCurve25519KeyChain = session.mForwardingCurve25519KeyChain
|
||||
result.keysClaimed = session.mKeysClaimed
|
||||
result.senderKey = senderKey
|
||||
result.forwardingCurve25519KeyChain = session.mForwardingCurve25519KeyChain
|
||||
} else {
|
||||
Timber.e("## decryptGroupMessage() : failed to decode the message")
|
||||
throw MXDecryptionException(MXCryptoError(MXCryptoError.OLM_ERROR_CODE, errorMessage, null))
|
||||
@ -707,7 +707,7 @@ internal class MXOlmDevice(
|
||||
}
|
||||
} else {
|
||||
Timber.e("## decryptGroupMessage() : Cannot retrieve inbound group session $sessionId")
|
||||
throw MXDecryptionException(mInboundGroupSessionWithIdError)
|
||||
throw MXDecryptionException(inboundGroupSessionWithIdError)
|
||||
}
|
||||
|
||||
return result
|
||||
@ -720,7 +720,7 @@ internal class MXOlmDevice(
|
||||
*/
|
||||
fun resetReplayAttackCheckInTimeline(timeline: String?) {
|
||||
if (null != timeline) {
|
||||
mInboundGroupSessionMessageIndexes.remove(timeline)
|
||||
inboundGroupSessionMessageIndexes.remove(timeline)
|
||||
}
|
||||
}
|
||||
|
||||
@ -737,7 +737,7 @@ internal class MXOlmDevice(
|
||||
@Throws(Exception::class)
|
||||
fun verifySignature(key: String, jsonDictionary: Map<String, Any>, signature: String) {
|
||||
// Check signature on the canonical version of the JSON
|
||||
mOlmUtility!!.verifyEd25519Signature(signature, key, MoshiProvider.getCanonicalJson<Map<*, *>>(Map::class.java, jsonDictionary))
|
||||
olmUtility!!.verifyEd25519Signature(signature, key, MoshiProvider.getCanonicalJson<Map<*, *>>(Map::class.java, jsonDictionary))
|
||||
}
|
||||
|
||||
/**
|
||||
@ -747,7 +747,7 @@ internal class MXOlmDevice(
|
||||
* @return the base64-encoded hash value.
|
||||
*/
|
||||
fun sha256(message: String): String {
|
||||
return mOlmUtility!!.sha256(convertToUTF8(message))
|
||||
return olmUtility!!.sha256(convertToUTF8(message))
|
||||
}
|
||||
|
||||
/**
|
||||
@ -760,14 +760,14 @@ internal class MXOlmDevice(
|
||||
private fun getSessionForDevice(theirDeviceIdentityKey: String, sessionId: String): MXOlmSession? {
|
||||
// sanity check
|
||||
return if (!TextUtils.isEmpty(theirDeviceIdentityKey) && !TextUtils.isEmpty(sessionId)) {
|
||||
mStore.getDeviceSession(sessionId, theirDeviceIdentityKey)
|
||||
store.getDeviceSession(sessionId, theirDeviceIdentityKey)
|
||||
} else null
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Extract an InboundGroupSession from the session store and do some check.
|
||||
* mInboundGroupSessionWithIdError describes the failure reason.
|
||||
* inboundGroupSessionWithIdError describes the failure reason.
|
||||
*
|
||||
* @param roomId the room where the session is used.
|
||||
* @param sessionId the session identifier.
|
||||
@ -775,9 +775,9 @@ internal class MXOlmDevice(
|
||||
* @return the inbound group session.
|
||||
*/
|
||||
fun getInboundGroupSession(sessionId: String?, senderKey: String?, roomId: String?): MXOlmInboundGroupSession2? {
|
||||
mInboundGroupSessionWithIdError = null
|
||||
inboundGroupSessionWithIdError = null
|
||||
|
||||
val session = mStore.getInboundGroupSession(sessionId!!, senderKey!!)
|
||||
val session = store.getInboundGroupSession(sessionId!!, senderKey!!)
|
||||
|
||||
if (null != session) {
|
||||
// Check that the room id matches the original one for the session. This stops
|
||||
@ -785,13 +785,13 @@ internal class MXOlmDevice(
|
||||
if (!TextUtils.equals(roomId, session.mRoomId)) {
|
||||
val errorDescription = String.format(MXCryptoError.INBOUND_SESSION_MISMATCH_ROOM_ID_REASON, roomId, session.mRoomId)
|
||||
Timber.e("## getInboundGroupSession() : $errorDescription")
|
||||
mInboundGroupSessionWithIdError = MXCryptoError(MXCryptoError.INBOUND_SESSION_MISMATCH_ROOM_ID_ERROR_CODE,
|
||||
MXCryptoError.UNABLE_TO_DECRYPT, errorDescription)
|
||||
inboundGroupSessionWithIdError = MXCryptoError(MXCryptoError.INBOUND_SESSION_MISMATCH_ROOM_ID_ERROR_CODE,
|
||||
MXCryptoError.UNABLE_TO_DECRYPT, errorDescription)
|
||||
}
|
||||
} else {
|
||||
Timber.e("## getInboundGroupSession() : Cannot retrieve inbound group session $sessionId")
|
||||
mInboundGroupSessionWithIdError = MXCryptoError(MXCryptoError.UNKNOWN_INBOUND_SESSION_ID_ERROR_CODE,
|
||||
MXCryptoError.UNKNOWN_INBOUND_SESSION_ID_REASON, null)
|
||||
inboundGroupSessionWithIdError = MXCryptoError(MXCryptoError.UNKNOWN_INBOUND_SESSION_ID_ERROR_CODE,
|
||||
MXCryptoError.UNKNOWN_INBOUND_SESSION_ID_REASON, null)
|
||||
}
|
||||
return session
|
||||
}
|
||||
|
@ -50,7 +50,7 @@ internal class MyDeviceInfoHolder(
|
||||
myDevice.keys = keys
|
||||
|
||||
myDevice.algorithms = MXCryptoAlgorithms.supportedAlgorithms()
|
||||
myDevice.mVerified = MXDeviceInfo.DEVICE_VERIFICATION_VERIFIED
|
||||
myDevice.verified = MXDeviceInfo.DEVICE_VERIFICATION_VERIFIED
|
||||
|
||||
// Add our own deviceinfo to the store
|
||||
val endToEndDevicesForUser = cryptoStore.getUserDevices(credentials.userId)
|
||||
|
@ -16,15 +16,13 @@
|
||||
|
||||
package im.vector.matrix.android.internal.crypto
|
||||
|
||||
import im.vector.matrix.android.api.MatrixCallback
|
||||
import arrow.core.Try
|
||||
import arrow.instances.`try`.applicativeError.handleError
|
||||
import im.vector.matrix.android.api.auth.data.Credentials
|
||||
import im.vector.matrix.android.internal.crypto.model.MXKey
|
||||
import im.vector.matrix.android.internal.crypto.model.rest.KeysUploadResponse
|
||||
import im.vector.matrix.android.internal.crypto.tasks.UploadKeysTask
|
||||
import im.vector.matrix.android.internal.di.MoshiProvider
|
||||
import im.vector.matrix.android.internal.task.TaskExecutor
|
||||
import im.vector.matrix.android.internal.task.TaskThread
|
||||
import im.vector.matrix.android.internal.task.configureWith
|
||||
import org.matrix.olm.OlmAccount
|
||||
import timber.log.Timber
|
||||
import java.util.*
|
||||
@ -33,15 +31,13 @@ internal class OneTimeKeysUploader(
|
||||
private val mCredentials: Credentials,
|
||||
private val mOlmDevice: MXOlmDevice,
|
||||
private val mObjectSigner: ObjectSigner,
|
||||
private val mUploadKeysTask: UploadKeysTask,
|
||||
private val mTaskExecutor: TaskExecutor
|
||||
private val mUploadKeysTask: UploadKeysTask
|
||||
) {
|
||||
// tell if there is a OTK check in progress
|
||||
private var mOneTimeKeyCheckInProgress = false
|
||||
|
||||
// last OTK check timestamp
|
||||
private var mLastOneTimeKeyCheck: Long = 0
|
||||
|
||||
private var mOneTimeKeyCount: Int? = null
|
||||
|
||||
var mLastPublishedOneTimeKeys: Map<String, Map<String, String>>? = null
|
||||
@ -60,23 +56,17 @@ internal class OneTimeKeysUploader(
|
||||
|
||||
/**
|
||||
* Check if the OTK must be uploaded.
|
||||
*
|
||||
* @param callback the asynchronous callback
|
||||
*/
|
||||
fun maybeUploadOneTimeKeys(callback: MatrixCallback<Unit>? = null) {
|
||||
suspend fun maybeUploadOneTimeKeys(): Try<Unit> {
|
||||
if (mOneTimeKeyCheckInProgress) {
|
||||
callback?.onSuccess(Unit)
|
||||
return
|
||||
return Try.just(Unit)
|
||||
}
|
||||
|
||||
if (System.currentTimeMillis() - mLastOneTimeKeyCheck < ONE_TIME_KEY_UPLOAD_PERIOD) {
|
||||
// we've done a key upload recently.
|
||||
callback?.onSuccess(Unit)
|
||||
return
|
||||
return Try.just(Unit)
|
||||
}
|
||||
|
||||
mLastOneTimeKeyCheck = System.currentTimeMillis()
|
||||
|
||||
mOneTimeKeyCheckInProgress = true
|
||||
|
||||
// We then check how many keys we can store in the Account object.
|
||||
@ -89,44 +79,34 @@ internal class OneTimeKeysUploader(
|
||||
// discard the oldest private keys first. This will eventually clean
|
||||
// out stale private keys that won't receive a message.
|
||||
val keyLimit = Math.floor(maxOneTimeKeys / 2.0).toInt()
|
||||
|
||||
if (null != mOneTimeKeyCount) {
|
||||
uploadOTK(mOneTimeKeyCount!!, keyLimit, callback)
|
||||
if (mOneTimeKeyCount != null) {
|
||||
return uploadOTK(mOneTimeKeyCount!!, keyLimit)
|
||||
} else {
|
||||
// ask the server how many keys we have
|
||||
mUploadKeysTask
|
||||
.configureWith(UploadKeysTask.Params(null, null, mCredentials.deviceId!!))
|
||||
.executeOn(TaskThread.ENCRYPTION)
|
||||
.dispatchTo(object : MatrixCallback<KeysUploadResponse> {
|
||||
|
||||
override fun onSuccess(data: KeysUploadResponse) {
|
||||
// We need to keep a pool of one time public keys on the server so that
|
||||
// other devices can start conversations with us. But we can only store
|
||||
// a finite number of private keys in the olm Account object.
|
||||
// To complicate things further then can be a delay between a device
|
||||
// claiming a public one time key from the server and it sending us a
|
||||
// message. We need to keep the corresponding private key locally until
|
||||
// we receive the message.
|
||||
// But that message might never arrive leaving us stuck with duff
|
||||
// private keys clogging up our local storage.
|
||||
// So we need some kind of engineering compromise to balance all of
|
||||
// these factors.
|
||||
// TODO Why we do not set mOneTimeKeyCount here?
|
||||
// TODO This is not needed anymore, see https://github.com/matrix-org/matrix-js-sdk/pull/493 (TODO on iOS also)
|
||||
val keyCount = data.oneTimeKeyCountsForAlgorithm(MXKey.KEY_SIGNED_CURVE_25519_TYPE)
|
||||
uploadOTK(keyCount, keyLimit, callback)
|
||||
}
|
||||
|
||||
override fun onFailure(failure: Throwable) {
|
||||
Timber.e(failure, "## uploadKeys() : failed")
|
||||
|
||||
mOneTimeKeyCount = null
|
||||
mOneTimeKeyCheckInProgress = false
|
||||
|
||||
callback?.onFailure(failure)
|
||||
}
|
||||
})
|
||||
.executeBy(mTaskExecutor)
|
||||
val uploadKeysParams = UploadKeysTask.Params(null, null, mCredentials.deviceId!!)
|
||||
return mUploadKeysTask.execute(uploadKeysParams)
|
||||
.flatMap {
|
||||
// We need to keep a pool of one time public keys on the server so that
|
||||
// other devices can start conversations with us. But we can only store
|
||||
// a finite number of private keys in the olm Account object.
|
||||
// To complicate things further then can be a delay between a device
|
||||
// claiming a public one time key from the server and it sending us a
|
||||
// message. We need to keep the corresponding private key locally until
|
||||
// we receive the message.
|
||||
// But that message might never arrive leaving us stuck with duff
|
||||
// private keys clogging up our local storage.
|
||||
// So we need some kind of engineering compromise to balance all of
|
||||
// these factors.
|
||||
// TODO Why we do not set mOneTimeKeyCount here?
|
||||
// TODO This is not needed anymore, see https://github.com/matrix-org/matrix-js-sdk/pull/493 (TODO on iOS also)
|
||||
val keyCount = it.oneTimeKeyCountsForAlgorithm(MXKey.KEY_SIGNED_CURVE_25519_TYPE)
|
||||
uploadOTK(keyCount, keyLimit)
|
||||
}
|
||||
.handleError {
|
||||
Timber.e(it, "## uploadKeys() : failed")
|
||||
mOneTimeKeyCount = null
|
||||
mOneTimeKeyCheckInProgress = false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -135,42 +115,40 @@ internal class OneTimeKeysUploader(
|
||||
*
|
||||
* @param keyCount the key count
|
||||
* @param keyLimit the limit
|
||||
* @param callback the asynchronous callback
|
||||
*/
|
||||
private fun uploadOTK(keyCount: Int, keyLimit: Int, callback: MatrixCallback<Unit>?) {
|
||||
uploadLoop(keyCount, keyLimit, object : MatrixCallback<Unit> {
|
||||
private fun uploadKeysDone(errorMessage: String?) {
|
||||
if (null != errorMessage) {
|
||||
Timber.e("## maybeUploadOneTimeKeys() : failed $errorMessage")
|
||||
private suspend fun uploadOTK(keyCount: Int, keyLimit: Int): Try<Unit> {
|
||||
return uploadLoop(keyCount, keyLimit)
|
||||
}
|
||||
|
||||
/**
|
||||
* OTK upload loop
|
||||
*
|
||||
* @param keyCount the number of key to generate
|
||||
* @param keyLimit the limit
|
||||
*/
|
||||
private suspend fun uploadLoop(keyCount: Int, keyLimit: Int): Try<Unit> {
|
||||
if (keyLimit <= keyCount) {
|
||||
// If we don't need to generate any more keys then we are done.
|
||||
return Try.just(Unit)
|
||||
}
|
||||
|
||||
val keysThisLoop = Math.min(keyLimit - keyCount, ONE_TIME_KEY_GENERATION_MAX_NUMBER)
|
||||
mOlmDevice.generateOneTimeKeys(keysThisLoop)
|
||||
return uploadOneTimeKeys()
|
||||
.flatMap {
|
||||
if (it.hasOneTimeKeyCountsForAlgorithm(MXKey.KEY_SIGNED_CURVE_25519_TYPE)) {
|
||||
uploadLoop(it.oneTimeKeyCountsForAlgorithm(MXKey.KEY_SIGNED_CURVE_25519_TYPE), keyLimit)
|
||||
} else {
|
||||
Timber.e("## uploadLoop() : response for uploading keys does not contain one_time_key_counts.signed_curve25519")
|
||||
Try.raise(Exception("response for uploading keys does not contain one_time_key_counts.signed_curve25519"))
|
||||
}
|
||||
}
|
||||
mOneTimeKeyCount = null
|
||||
mOneTimeKeyCheckInProgress = false
|
||||
}
|
||||
|
||||
override fun onSuccess(data: Unit) {
|
||||
Timber.v("## maybeUploadOneTimeKeys() : succeeded")
|
||||
uploadKeysDone(null)
|
||||
|
||||
callback?.onSuccess(Unit)
|
||||
}
|
||||
|
||||
override fun onFailure(failure: Throwable) {
|
||||
uploadKeysDone(failure.message)
|
||||
|
||||
callback?.onFailure(failure)
|
||||
}
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Upload my user's one time keys.
|
||||
* This method must called on getEncryptingThreadHandler() thread.
|
||||
* The callback will called on UI thread.
|
||||
*
|
||||
* @param callback the asynchronous callback
|
||||
*/
|
||||
private fun uploadOneTimeKeys(callback: MatrixCallback<KeysUploadResponse>?) {
|
||||
private suspend fun uploadOneTimeKeys(): Try<KeysUploadResponse> {
|
||||
val oneTimeKeys = mOlmDevice.getOneTimeKeys()
|
||||
val oneTimeJson = HashMap<String, Any>()
|
||||
|
||||
@ -192,57 +170,14 @@ internal class OneTimeKeysUploader(
|
||||
|
||||
// For now, we set the device id explicitly, as we may not be using the
|
||||
// same one as used in login.
|
||||
mUploadKeysTask
|
||||
.configureWith(UploadKeysTask.Params(null, oneTimeJson, mCredentials.deviceId!!))
|
||||
.executeOn(TaskThread.ENCRYPTION)
|
||||
.dispatchTo(object : MatrixCallback<KeysUploadResponse> {
|
||||
override fun onSuccess(data: KeysUploadResponse) {
|
||||
mLastPublishedOneTimeKeys = oneTimeKeys
|
||||
mOlmDevice.markKeysAsPublished()
|
||||
|
||||
callback?.onSuccess(data)
|
||||
}
|
||||
|
||||
override fun onFailure(failure: Throwable) {
|
||||
callback?.onFailure(failure)
|
||||
}
|
||||
})
|
||||
.executeBy(mTaskExecutor)
|
||||
}
|
||||
|
||||
/**
|
||||
* OTK upload loop
|
||||
*
|
||||
* @param keyCount the number of key to generate
|
||||
* @param keyLimit the limit
|
||||
* @param callback the asynchronous callback
|
||||
*/
|
||||
private fun uploadLoop(keyCount: Int, keyLimit: Int, callback: MatrixCallback<Unit>) {
|
||||
if (keyLimit <= keyCount) {
|
||||
// If we don't need to generate any more keys then we are done.
|
||||
callback.onSuccess(Unit)
|
||||
return
|
||||
}
|
||||
|
||||
val keysThisLoop = Math.min(keyLimit - keyCount, ONE_TIME_KEY_GENERATION_MAX_NUMBER)
|
||||
|
||||
mOlmDevice.generateOneTimeKeys(keysThisLoop)
|
||||
|
||||
uploadOneTimeKeys(object : MatrixCallback<KeysUploadResponse> {
|
||||
override fun onSuccess(data: KeysUploadResponse) {
|
||||
if (data.hasOneTimeKeyCountsForAlgorithm(MXKey.KEY_SIGNED_CURVE_25519_TYPE)) {
|
||||
uploadLoop(data.oneTimeKeyCountsForAlgorithm(MXKey.KEY_SIGNED_CURVE_25519_TYPE), keyLimit, callback)
|
||||
} else {
|
||||
Timber.e("## uploadLoop() : response for uploading keys does not contain one_time_key_counts.signed_curve25519")
|
||||
callback.onFailure(
|
||||
Exception("response for uploading keys does not contain one_time_key_counts.signed_curve25519"))
|
||||
val uploadParams = UploadKeysTask.Params(null, oneTimeJson, mCredentials.deviceId!!)
|
||||
return mUploadKeysTask
|
||||
.execute(uploadParams)
|
||||
.map {
|
||||
mLastPublishedOneTimeKeys = oneTimeKeys
|
||||
mOlmDevice.markKeysAsPublished()
|
||||
it
|
||||
}
|
||||
}
|
||||
|
||||
override fun onFailure(failure: Throwable) {
|
||||
callback.onFailure(failure)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
@ -27,6 +27,7 @@ import im.vector.matrix.android.internal.crypto.model.rest.RoomKeyShareRequest
|
||||
import im.vector.matrix.android.internal.crypto.store.IMXCryptoStore
|
||||
import im.vector.matrix.android.internal.crypto.tasks.SendToDeviceTask
|
||||
import im.vector.matrix.android.internal.task.TaskExecutor
|
||||
import im.vector.matrix.android.internal.task.TaskThread
|
||||
import im.vector.matrix.android.internal.task.configureWith
|
||||
import timber.log.Timber
|
||||
import java.util.*
|
||||
@ -87,7 +88,7 @@ internal class OutgoingRoomKeyRequestManager(
|
||||
OutgoingRoomKeyRequest(requestBody, recipients, makeTxnId(), OutgoingRoomKeyRequest.RequestState.UNSENT))
|
||||
|
||||
|
||||
if (req!!.mState === OutgoingRoomKeyRequest.RequestState.UNSENT) {
|
||||
if (req?.mState == OutgoingRoomKeyRequest.RequestState.UNSENT) {
|
||||
startTimer()
|
||||
}
|
||||
}
|
||||
|
@ -24,12 +24,12 @@ import timber.log.Timber
|
||||
import java.util.*
|
||||
|
||||
internal class RoomDecryptorProvider(
|
||||
private val mMXOlmDecryptionFactory: MXOlmDecryptionFactory,
|
||||
private val mMXMegolmDecryptionFactory: MXMegolmDecryptionFactory
|
||||
private val olmDecryptionFactory: MXOlmDecryptionFactory,
|
||||
private val megolmDecryptionFactory: MXMegolmDecryptionFactory
|
||||
) {
|
||||
|
||||
// A map from algorithm to MXDecrypting instance, for each room
|
||||
private val mRoomDecryptors: MutableMap<String /* room id */, MutableMap<String /* algorithm */, IMXDecrypting>> = HashMap()
|
||||
private val roomDecryptors: MutableMap<String /* room id */, MutableMap<String /* algorithm */, IMXDecrypting>> = HashMap()
|
||||
|
||||
/**
|
||||
* Get a decryptor for a given room and algorithm.
|
||||
@ -43,44 +43,36 @@ internal class RoomDecryptorProvider(
|
||||
*/
|
||||
fun getOrCreateRoomDecryptor(roomId: String?, algorithm: String?): IMXDecrypting? {
|
||||
// sanity check
|
||||
if (TextUtils.isEmpty(algorithm)) {
|
||||
if (algorithm.isNullOrEmpty() || roomId.isNullOrEmpty()) {
|
||||
Timber.e("## getRoomDecryptor() : null algorithm")
|
||||
return null
|
||||
}
|
||||
|
||||
var alg: IMXDecrypting? = null
|
||||
|
||||
if (!TextUtils.isEmpty(roomId)) {
|
||||
synchronized(mRoomDecryptors) {
|
||||
if (!mRoomDecryptors.containsKey(roomId)) {
|
||||
mRoomDecryptors[roomId!!] = HashMap()
|
||||
}
|
||||
|
||||
alg = mRoomDecryptors[roomId]!![algorithm]
|
||||
var alg: IMXDecrypting?
|
||||
synchronized(roomDecryptors) {
|
||||
if (!roomDecryptors.containsKey(roomId)) {
|
||||
roomDecryptors[roomId!!] = HashMap()
|
||||
}
|
||||
|
||||
if (null != alg) {
|
||||
return alg
|
||||
}
|
||||
alg = roomDecryptors[roomId]!![algorithm]
|
||||
}
|
||||
if (alg != null) {
|
||||
return alg
|
||||
}
|
||||
|
||||
val decryptingClass = MXCryptoAlgorithms.hasDecryptorClassForAlgorithm(algorithm)
|
||||
|
||||
if (decryptingClass) {
|
||||
alg = when (algorithm) {
|
||||
MXCRYPTO_ALGORITHM_MEGOLM -> mMXMegolmDecryptionFactory.create()
|
||||
else -> mMXOlmDecryptionFactory.create()
|
||||
MXCRYPTO_ALGORITHM_MEGOLM -> megolmDecryptionFactory.create()
|
||||
else -> olmDecryptionFactory.create()
|
||||
}
|
||||
|
||||
if (null != alg) {
|
||||
if (!TextUtils.isEmpty(roomId)) {
|
||||
synchronized(mRoomDecryptors) {
|
||||
mRoomDecryptors[roomId]!!.put(algorithm!!, alg!!)
|
||||
synchronized(roomDecryptors) {
|
||||
roomDecryptors[roomId]!!.put(algorithm!!, alg!!)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return alg
|
||||
}
|
||||
|
||||
@ -88,7 +80,6 @@ internal class RoomDecryptorProvider(
|
||||
if (roomId == null || algorithm == null) {
|
||||
return null
|
||||
}
|
||||
|
||||
return mRoomDecryptors[roomId]?.get(algorithm)
|
||||
return roomDecryptors[roomId]?.get(algorithm)
|
||||
}
|
||||
}
|
@ -18,7 +18,11 @@ package im.vector.matrix.android.internal.crypto.actions
|
||||
|
||||
import im.vector.matrix.android.api.MatrixCallback
|
||||
import im.vector.matrix.android.api.listeners.ProgressListener
|
||||
import im.vector.matrix.android.internal.crypto.*
|
||||
import im.vector.matrix.android.internal.crypto.CryptoAsyncHelper
|
||||
import im.vector.matrix.android.internal.crypto.MXOlmDevice
|
||||
import im.vector.matrix.android.internal.crypto.MegolmSessionData
|
||||
import im.vector.matrix.android.internal.crypto.OutgoingRoomKeyRequestManager
|
||||
import im.vector.matrix.android.internal.crypto.RoomDecryptorProvider
|
||||
import im.vector.matrix.android.internal.crypto.model.ImportRoomKeysResult
|
||||
import im.vector.matrix.android.internal.crypto.model.rest.RoomKeyRequestBody
|
||||
import im.vector.matrix.android.internal.crypto.store.IMXCryptoStore
|
||||
@ -53,7 +57,6 @@ internal class MegolmSessionDataImporter(private val mOlmDevice: MXOlmDevice,
|
||||
progressListener.onProgress(0, 100)
|
||||
}
|
||||
}
|
||||
|
||||
val sessions = mOlmDevice.importInboundGroupSessions(megolmSessionsData)
|
||||
|
||||
for (megolmSessionData in megolmSessionsData) {
|
||||
@ -65,7 +68,7 @@ internal class MegolmSessionDataImporter(private val mOlmDevice: MXOlmDevice,
|
||||
if (null != decrypting) {
|
||||
try {
|
||||
val sessionId = megolmSessionData.sessionId
|
||||
Timber.v("## importRoomKeys retrieve mSenderKey " + megolmSessionData.senderKey + " sessionId " + sessionId)
|
||||
Timber.v("## importRoomKeys retrieve senderKey " + megolmSessionData.senderKey + " sessionId " + sessionId)
|
||||
|
||||
totalNumbersOfImportedKeys++
|
||||
|
||||
|
@ -34,8 +34,8 @@ internal class SetDeviceVerificationAction(private val mCryptoStore: IMXCryptoSt
|
||||
return
|
||||
}
|
||||
|
||||
if (device.mVerified != verificationStatus) {
|
||||
device.mVerified = verificationStatus
|
||||
if (device.verified != verificationStatus) {
|
||||
device.verified = verificationStatus
|
||||
mCryptoStore.storeUserDevice(userId, device)
|
||||
|
||||
if (userId == mCredentials.userId) {
|
||||
|
@ -25,21 +25,21 @@ data class MXDecryptionResult(
|
||||
/**
|
||||
* The decrypted payload (with properties 'type', 'content')
|
||||
*/
|
||||
var mPayload: JsonDict? = null,
|
||||
var payload: JsonDict? = null,
|
||||
|
||||
/**
|
||||
* keys that the sender of the event claims ownership of:
|
||||
* map from key type to base64-encoded key.
|
||||
*/
|
||||
var mKeysClaimed: Map<String, String>? = null,
|
||||
var keysClaimed: Map<String, String>? = null,
|
||||
|
||||
/**
|
||||
* The curve25519 key that the sender of the event is known to have ownership of.
|
||||
*/
|
||||
var mSenderKey: String? = null,
|
||||
var senderKey: String? = null,
|
||||
|
||||
/**
|
||||
* Devices which forwarded this session to us (normally empty).
|
||||
*/
|
||||
var mForwardingCurve25519KeyChain: List<String>? = null
|
||||
var forwardingCurve25519KeyChain: List<String>? = null
|
||||
)
|
@ -74,7 +74,6 @@ internal class MXMegolmDecryption(private val credentials: Credentials,
|
||||
}
|
||||
|
||||
@Throws(MXDecryptionException::class)
|
||||
|
||||
private fun decryptEvent(event: Event, timeline: String, requestKeysOnFail: Boolean): MXEventDecryptionResult? {
|
||||
val encryptedEventContent = event.content.toModel<EncryptedEventContent>()!!
|
||||
if (TextUtils.isEmpty(encryptedEventContent.senderKey) || TextUtils.isEmpty(encryptedEventContent.sessionId) || TextUtils.isEmpty(encryptedEventContent.ciphertext)) {
|
||||
@ -93,17 +92,17 @@ internal class MXMegolmDecryption(private val credentials: Credentials,
|
||||
}
|
||||
|
||||
// the decryption succeeds
|
||||
if (decryptGroupMessageResult?.mPayload != null && cryptoError == null) {
|
||||
if (decryptGroupMessageResult?.payload != null && cryptoError == null) {
|
||||
eventDecryptionResult = MXEventDecryptionResult()
|
||||
|
||||
eventDecryptionResult.clearEvent = decryptGroupMessageResult.mPayload
|
||||
eventDecryptionResult.senderCurve25519Key = decryptGroupMessageResult.mSenderKey
|
||||
eventDecryptionResult.clearEvent = decryptGroupMessageResult.payload
|
||||
eventDecryptionResult.senderCurve25519Key = decryptGroupMessageResult.senderKey
|
||||
|
||||
if (null != decryptGroupMessageResult.mKeysClaimed) {
|
||||
eventDecryptionResult.claimedEd25519Key = decryptGroupMessageResult.mKeysClaimed!!["ed25519"]
|
||||
if (null != decryptGroupMessageResult.keysClaimed) {
|
||||
eventDecryptionResult.claimedEd25519Key = decryptGroupMessageResult.keysClaimed!!["ed25519"]
|
||||
}
|
||||
|
||||
eventDecryptionResult.forwardingCurve25519KeyChain = decryptGroupMessageResult.mForwardingCurve25519KeyChain!!
|
||||
eventDecryptionResult.forwardingCurve25519KeyChain = decryptGroupMessageResult.forwardingCurve25519KeyChain!!
|
||||
} else if (cryptoError != null) {
|
||||
if (cryptoError.isOlmError) {
|
||||
if (TextUtils.equals("UNKNOWN_MESSAGE_INDEX", cryptoError.message)) {
|
||||
|
@ -387,7 +387,7 @@ internal class KeysBackup(
|
||||
callback: MatrixCallback<KeysBackupVersionTrust>) {
|
||||
// TODO Validate with François that this is correct
|
||||
object : Task<KeysVersionResult, KeysBackupVersionTrust> {
|
||||
override fun execute(params: KeysVersionResult): Try<KeysBackupVersionTrust> {
|
||||
override suspend fun execute(params: KeysVersionResult): Try<KeysBackupVersionTrust> {
|
||||
return Try {
|
||||
getKeysBackupTrustBg(params)
|
||||
}
|
||||
|
@ -30,7 +30,7 @@ internal class DefaultCreateKeysBackupVersionTask(private val roomKeysApi: RoomK
|
||||
: CreateKeysBackupVersionTask {
|
||||
|
||||
|
||||
override fun execute(params: CreateKeysBackupVersionBody): Try<KeysVersion> {
|
||||
override suspend fun execute(params: CreateKeysBackupVersionBody): Try<KeysVersion> {
|
||||
return executeRequest {
|
||||
apiCall = roomKeysApi.createKeysBackupVersion(params)
|
||||
}
|
||||
|
@ -32,7 +32,7 @@ internal interface DeleteBackupTask : Task<DeleteBackupTask.Params, Unit> {
|
||||
internal class DefaultDeleteBackupTask(private val roomKeysApi: RoomKeysApi)
|
||||
: DeleteBackupTask {
|
||||
|
||||
override fun execute(params: DeleteBackupTask.Params): Try<Unit> {
|
||||
override suspend fun execute(params: DeleteBackupTask.Params): Try<Unit> {
|
||||
return executeRequest {
|
||||
apiCall = roomKeysApi.deleteBackup(
|
||||
params.version)
|
||||
|
@ -33,7 +33,7 @@ internal interface DeleteRoomSessionDataTask : Task<DeleteRoomSessionDataTask.Pa
|
||||
internal class DefaultDeleteRoomSessionDataTask(private val roomKeysApi: RoomKeysApi)
|
||||
: DeleteRoomSessionDataTask {
|
||||
|
||||
override fun execute(params: DeleteRoomSessionDataTask.Params): Try<Unit> {
|
||||
override suspend fun execute(params: DeleteRoomSessionDataTask.Params): Try<Unit> {
|
||||
return executeRequest {
|
||||
apiCall = roomKeysApi.deleteRoomSessionData(
|
||||
params.roomId,
|
||||
|
@ -32,7 +32,7 @@ internal interface DeleteRoomSessionsDataTask : Task<DeleteRoomSessionsDataTask.
|
||||
internal class DefaultDeleteRoomSessionsDataTask(private val roomKeysApi: RoomKeysApi)
|
||||
: DeleteRoomSessionsDataTask {
|
||||
|
||||
override fun execute(params: DeleteRoomSessionsDataTask.Params): Try<Unit> {
|
||||
override suspend fun execute(params: DeleteRoomSessionsDataTask.Params): Try<Unit> {
|
||||
return executeRequest {
|
||||
apiCall = roomKeysApi.deleteRoomSessionsData(
|
||||
params.roomId,
|
||||
|
@ -31,7 +31,7 @@ internal interface DeleteSessionsDataTask : Task<DeleteSessionsDataTask.Params,
|
||||
internal class DefaultDeleteSessionsDataTask(private val roomKeysApi: RoomKeysApi)
|
||||
: DeleteSessionsDataTask {
|
||||
|
||||
override fun execute(params: DeleteSessionsDataTask.Params): Try<Unit> {
|
||||
override suspend fun execute(params: DeleteSessionsDataTask.Params): Try<Unit> {
|
||||
return executeRequest {
|
||||
apiCall = roomKeysApi.deleteSessionsData(
|
||||
params.version)
|
||||
|
@ -29,7 +29,7 @@ internal class DefaultGetKeysBackupLastVersionTask(private val roomKeysApi: Room
|
||||
: GetKeysBackupLastVersionTask {
|
||||
|
||||
|
||||
override fun execute(params: Unit): Try<KeysVersionResult> {
|
||||
override suspend fun execute(params: Unit): Try<KeysVersionResult> {
|
||||
return executeRequest {
|
||||
apiCall = roomKeysApi.getKeysBackupLastVersion()
|
||||
}
|
||||
|
@ -29,7 +29,7 @@ internal class DefaultGetKeysBackupVersionTask(private val roomKeysApi: RoomKeys
|
||||
: GetKeysBackupVersionTask {
|
||||
|
||||
|
||||
override fun execute(params: String): Try<KeysVersionResult> {
|
||||
override suspend fun execute(params: String): Try<KeysVersionResult> {
|
||||
return executeRequest {
|
||||
apiCall = roomKeysApi.getKeysBackupVersion(params)
|
||||
}
|
||||
|
@ -34,7 +34,7 @@ internal interface GetRoomSessionDataTask : Task<GetRoomSessionDataTask.Params,
|
||||
internal class DefaultGetRoomSessionDataTask(private val roomKeysApi: RoomKeysApi)
|
||||
: GetRoomSessionDataTask {
|
||||
|
||||
override fun execute(params: GetRoomSessionDataTask.Params): Try<KeyBackupData> {
|
||||
override suspend fun execute(params: GetRoomSessionDataTask.Params): Try<KeyBackupData> {
|
||||
return executeRequest {
|
||||
apiCall = roomKeysApi.getRoomSessionData(
|
||||
params.roomId,
|
||||
|
@ -34,7 +34,7 @@ internal interface GetRoomSessionsDataTask : Task<GetRoomSessionsDataTask.Params
|
||||
internal class DefaultGetRoomSessionsDataTask(private val roomKeysApi: RoomKeysApi)
|
||||
: GetRoomSessionsDataTask {
|
||||
|
||||
override fun execute(params: GetRoomSessionsDataTask.Params): Try<RoomKeysBackupData> {
|
||||
override suspend fun execute(params: GetRoomSessionsDataTask.Params): Try<RoomKeysBackupData> {
|
||||
return executeRequest {
|
||||
apiCall = roomKeysApi.getRoomSessionsData(
|
||||
params.roomId,
|
||||
|
@ -32,7 +32,7 @@ internal interface GetSessionsDataTask : Task<GetSessionsDataTask.Params, KeysBa
|
||||
internal class DefaultGetSessionsDataTask(private val roomKeysApi: RoomKeysApi)
|
||||
: GetSessionsDataTask {
|
||||
|
||||
override fun execute(params: GetSessionsDataTask.Params): Try<KeysBackupData> {
|
||||
override suspend fun execute(params: GetSessionsDataTask.Params): Try<KeysBackupData> {
|
||||
return executeRequest {
|
||||
apiCall = roomKeysApi.getSessionsData(
|
||||
params.version)
|
||||
|
@ -36,7 +36,7 @@ internal interface StoreRoomSessionDataTask : Task<StoreRoomSessionDataTask.Para
|
||||
internal class DefaultStoreRoomSessionDataTask(private val roomKeysApi: RoomKeysApi)
|
||||
: StoreRoomSessionDataTask {
|
||||
|
||||
override fun execute(params: StoreRoomSessionDataTask.Params): Try<BackupKeysResult> {
|
||||
override suspend fun execute(params: StoreRoomSessionDataTask.Params): Try<BackupKeysResult> {
|
||||
return executeRequest {
|
||||
apiCall = roomKeysApi.storeRoomSessionData(
|
||||
params.roomId,
|
||||
|
@ -35,7 +35,7 @@ internal interface StoreRoomSessionsDataTask : Task<StoreRoomSessionsDataTask.Pa
|
||||
internal class DefaultStoreRoomSessionsDataTask(private val roomKeysApi: RoomKeysApi)
|
||||
: StoreRoomSessionsDataTask {
|
||||
|
||||
override fun execute(params: StoreRoomSessionsDataTask.Params): Try<BackupKeysResult> {
|
||||
override suspend fun execute(params: StoreRoomSessionsDataTask.Params): Try<BackupKeysResult> {
|
||||
return executeRequest {
|
||||
apiCall = roomKeysApi.storeRoomSessionsData(
|
||||
params.roomId,
|
||||
|
@ -34,7 +34,7 @@ internal interface StoreSessionsDataTask : Task<StoreSessionsDataTask.Params, Ba
|
||||
internal class DefaultStoreSessionsDataTask(private val roomKeysApi: RoomKeysApi)
|
||||
: StoreSessionsDataTask {
|
||||
|
||||
override fun execute(params: StoreSessionsDataTask.Params): Try<BackupKeysResult> {
|
||||
override suspend fun execute(params: StoreSessionsDataTask.Params): Try<BackupKeysResult> {
|
||||
return executeRequest {
|
||||
apiCall = roomKeysApi.storeSessionsData(
|
||||
params.version,
|
||||
|
@ -34,7 +34,7 @@ internal class DefaultUpdateKeysBackupVersionTask(private val roomKeysApi: RoomK
|
||||
: UpdateKeysBackupVersionTask {
|
||||
|
||||
|
||||
override fun execute(params: UpdateKeysBackupVersionTask.Params): Try<Unit> {
|
||||
override suspend fun execute(params: UpdateKeysBackupVersionTask.Params): Try<Unit> {
|
||||
return executeRequest {
|
||||
apiCall = roomKeysApi.updateKeysBackupVersion(params.version, params.keysBackupVersionBody)
|
||||
}
|
||||
|
@ -69,7 +69,7 @@ data class MXDeviceInfo(
|
||||
/**
|
||||
* Verification state of this device.
|
||||
*/
|
||||
var mVerified: Int = DEVICE_VERIFICATION_UNKNOWN
|
||||
var verified: Int = DEVICE_VERIFICATION_UNKNOWN
|
||||
) : Serializable {
|
||||
/**
|
||||
* Tells if the device is unknown
|
||||
@ -77,7 +77,7 @@ data class MXDeviceInfo(
|
||||
* @return true if the device is unknown
|
||||
*/
|
||||
val isUnknown: Boolean
|
||||
get() = mVerified == DEVICE_VERIFICATION_UNKNOWN
|
||||
get() = verified == DEVICE_VERIFICATION_UNKNOWN
|
||||
|
||||
/**
|
||||
* Tells if the device is verified.
|
||||
@ -85,7 +85,7 @@ data class MXDeviceInfo(
|
||||
* @return true if the device is verified
|
||||
*/
|
||||
val isVerified: Boolean
|
||||
get() = mVerified == DEVICE_VERIFICATION_VERIFIED
|
||||
get() = verified == DEVICE_VERIFICATION_VERIFIED
|
||||
|
||||
/**
|
||||
* Tells if the device is unverified.
|
||||
@ -93,7 +93,7 @@ data class MXDeviceInfo(
|
||||
* @return true if the device is unverified
|
||||
*/
|
||||
val isUnverified: Boolean
|
||||
get() = mVerified == DEVICE_VERIFICATION_UNVERIFIED
|
||||
get() = verified == DEVICE_VERIFICATION_UNVERIFIED
|
||||
|
||||
/**
|
||||
* Tells if the device is blocked.
|
||||
@ -101,7 +101,7 @@ data class MXDeviceInfo(
|
||||
* @return true if the device is blocked
|
||||
*/
|
||||
val isBlocked: Boolean
|
||||
get() = mVerified == DEVICE_VERIFICATION_BLOCKED
|
||||
get() = verified == DEVICE_VERIFICATION_BLOCKED
|
||||
|
||||
/**
|
||||
* @return the fingerprint
|
||||
|
@ -37,7 +37,7 @@ internal interface ClaimOneTimeKeysForUsersDeviceTask : Task<ClaimOneTimeKeysFor
|
||||
internal class DefaultClaimOneTimeKeysForUsersDevice(private val cryptoApi: CryptoApi)
|
||||
: ClaimOneTimeKeysForUsersDeviceTask {
|
||||
|
||||
override fun execute(params: ClaimOneTimeKeysForUsersDeviceTask.Params): Try<MXUsersDevicesMap<MXKey>> {
|
||||
override suspend fun execute(params: ClaimOneTimeKeysForUsersDeviceTask.Params): Try<MXUsersDevicesMap<MXKey>> {
|
||||
val body = KeysClaimBody(oneTimeKeys = params.usersDevicesKeyTypesMap.map)
|
||||
|
||||
return executeRequest<KeysClaimResponse> {
|
||||
|
@ -32,7 +32,7 @@ internal interface DeleteDeviceTask : Task<DeleteDeviceTask.Params, Unit> {
|
||||
internal class DefaultDeleteDeviceTask(private val cryptoApi: CryptoApi)
|
||||
: DeleteDeviceTask {
|
||||
|
||||
override fun execute(params: DeleteDeviceTask.Params): Try<Unit> {
|
||||
override suspend fun execute(params: DeleteDeviceTask.Params): Try<Unit> {
|
||||
return executeRequest {
|
||||
apiCall = cryptoApi.deleteDevice(params.deviceId,
|
||||
DeleteDeviceParams())
|
||||
|
@ -36,7 +36,7 @@ internal interface DownloadKeysForUsersTask : Task<DownloadKeysForUsersTask.Para
|
||||
internal class DefaultDownloadKeysForUsers(private val cryptoApi: CryptoApi)
|
||||
: DownloadKeysForUsersTask {
|
||||
|
||||
override fun execute(params: DownloadKeysForUsersTask.Params): Try<KeysQueryResponse> {
|
||||
override suspend fun execute(params: DownloadKeysForUsersTask.Params): Try<KeysQueryResponse> {
|
||||
val downloadQuery = HashMap<String, Map<String, Any>>()
|
||||
|
||||
if (null != params.userIds) {
|
||||
|
@ -27,7 +27,7 @@ internal interface GetDevicesTask : Task<Unit, DevicesListResponse>
|
||||
internal class DefaultGetDevicesTask(private val cryptoApi: CryptoApi)
|
||||
: GetDevicesTask {
|
||||
|
||||
override fun execute(params: Unit): Try<DevicesListResponse> {
|
||||
override suspend fun execute(params: Unit): Try<DevicesListResponse> {
|
||||
return executeRequest {
|
||||
apiCall = cryptoApi.getDevices()
|
||||
}
|
||||
|
@ -34,7 +34,7 @@ internal interface GetKeyChangesTask : Task<GetKeyChangesTask.Params, KeyChanges
|
||||
internal class DefaultGetKeyChangesTask(private val cryptoApi: CryptoApi)
|
||||
: GetKeyChangesTask {
|
||||
|
||||
override fun execute(params: GetKeyChangesTask.Params): Try<KeyChangesResponse> {
|
||||
override suspend fun execute(params: GetKeyChangesTask.Params): Try<KeyChangesResponse> {
|
||||
return executeRequest {
|
||||
apiCall = cryptoApi.getKeyChanges(params.from,
|
||||
params.to)
|
||||
|
@ -38,7 +38,7 @@ internal interface SendToDeviceTask : Task<SendToDeviceTask.Params, Unit> {
|
||||
internal class DefaultSendToDeviceTask(private val cryptoApi: CryptoApi)
|
||||
: SendToDeviceTask {
|
||||
|
||||
override fun execute(params: SendToDeviceTask.Params): Try<Unit> {
|
||||
override suspend fun execute(params: SendToDeviceTask.Params): Try<Unit> {
|
||||
val sendToDeviceBody = SendToDeviceBody()
|
||||
sendToDeviceBody.messages = params.contentMap.map
|
||||
|
||||
|
@ -35,7 +35,7 @@ internal interface SetDeviceNameTask : Task<SetDeviceNameTask.Params, Unit> {
|
||||
internal class DefaultSetDeviceNameTask(private val cryptoApi: CryptoApi)
|
||||
: SetDeviceNameTask {
|
||||
|
||||
override fun execute(params: SetDeviceNameTask.Params): Try<Unit> {
|
||||
override suspend fun execute(params: SetDeviceNameTask.Params): Try<Unit> {
|
||||
val body = UpdateDeviceInfoBody(
|
||||
displayName = if (TextUtils.isEmpty(params.deviceName)) "" else params.deviceName
|
||||
)
|
||||
|
@ -39,7 +39,7 @@ internal interface UploadKeysTask : Task<UploadKeysTask.Params, KeysUploadRespon
|
||||
internal class DefaultUploadKeysTask(private val cryptoApi: CryptoApi)
|
||||
: UploadKeysTask {
|
||||
|
||||
override fun execute(params: UploadKeysTask.Params): Try<KeysUploadResponse> {
|
||||
override suspend fun execute(params: UploadKeysTask.Params): Try<KeysUploadResponse> {
|
||||
val encodedDeviceId = convertToUTF8(params.deviceId)
|
||||
|
||||
val body = KeysUploadBody()
|
||||
|
@ -33,11 +33,18 @@ import im.vector.matrix.android.internal.crypto.MyDeviceInfoHolder
|
||||
import im.vector.matrix.android.internal.crypto.actions.SetDeviceVerificationAction
|
||||
import im.vector.matrix.android.internal.crypto.model.MXDeviceInfo
|
||||
import im.vector.matrix.android.internal.crypto.model.MXUsersDevicesMap
|
||||
import im.vector.matrix.android.internal.crypto.model.rest.*
|
||||
import im.vector.matrix.android.internal.crypto.model.rest.KeyVerificationAccept
|
||||
import im.vector.matrix.android.internal.crypto.model.rest.KeyVerificationCancel
|
||||
import im.vector.matrix.android.internal.crypto.model.rest.KeyVerificationKey
|
||||
import im.vector.matrix.android.internal.crypto.model.rest.KeyVerificationMac
|
||||
import im.vector.matrix.android.internal.crypto.model.rest.KeyVerificationStart
|
||||
import im.vector.matrix.android.internal.crypto.store.IMXCryptoStore
|
||||
import im.vector.matrix.android.internal.crypto.tasks.SendToDeviceTask
|
||||
import im.vector.matrix.android.internal.task.TaskExecutor
|
||||
import im.vector.matrix.android.internal.task.configureWith
|
||||
import im.vector.matrix.android.internal.util.MatrixCoroutineDispatchers
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.launch
|
||||
import timber.log.Timber
|
||||
import java.util.*
|
||||
import kotlin.collections.HashMap
|
||||
@ -53,6 +60,7 @@ internal class DefaultSasVerificationService(private val mCredentials: Credentia
|
||||
private val deviceListManager: DeviceListManager,
|
||||
private val setDeviceVerificationAction: SetDeviceVerificationAction,
|
||||
private val mSendToDeviceTask: SendToDeviceTask,
|
||||
private val coroutineDispatchers: MatrixCoroutineDispatchers,
|
||||
private val mTaskExecutor: TaskExecutor)
|
||||
: VerificationTransaction.Listener, SasVerificationService {
|
||||
|
||||
@ -63,8 +71,7 @@ internal class DefaultSasVerificationService(private val mCredentials: Credentia
|
||||
|
||||
// Event received from the sync
|
||||
fun onToDeviceEvent(event: Event) {
|
||||
CryptoAsyncHelper.getDecryptBackgroundHandler().post {
|
||||
// TODO We are already in a BG thread
|
||||
CoroutineScope(coroutineDispatchers.crypto).launch {
|
||||
when (event.getClearType()) {
|
||||
EventType.KEY_VERIFICATION_START -> {
|
||||
onStartRequestReceived(event)
|
||||
@ -131,8 +138,8 @@ internal class DefaultSasVerificationService(private val mCredentials: Credentia
|
||||
|
||||
override fun markedLocallyAsManuallyVerified(userId: String, deviceID: String) {
|
||||
setDeviceVerificationAction.handle(MXDeviceInfo.DEVICE_VERIFICATION_VERIFIED,
|
||||
deviceID,
|
||||
userId)
|
||||
deviceID,
|
||||
userId)
|
||||
|
||||
listeners.forEach {
|
||||
try {
|
||||
@ -143,7 +150,7 @@ internal class DefaultSasVerificationService(private val mCredentials: Credentia
|
||||
}
|
||||
}
|
||||
|
||||
private fun onStartRequestReceived(event: Event) {
|
||||
private suspend fun onStartRequestReceived(event: Event) {
|
||||
val startReq = event.getClearContent().toModel<KeyVerificationStart>()!!
|
||||
|
||||
val otherUserId = event.sender
|
||||
@ -199,7 +206,7 @@ internal class DefaultSasVerificationService(private val mCredentials: Credentia
|
||||
} else {
|
||||
Timber.e("## SAS onStartRequestReceived - unknown method ${startReq.method}")
|
||||
cancelTransaction(tid, otherUserId, startReq.fromDevice
|
||||
?: event.getSenderKey()!!, CancelCode.UnknownMethod)
|
||||
?: event.getSenderKey()!!, CancelCode.UnknownMethod)
|
||||
}
|
||||
}
|
||||
},
|
||||
@ -208,30 +215,24 @@ internal class DefaultSasVerificationService(private val mCredentials: Credentia
|
||||
})
|
||||
}
|
||||
|
||||
private fun checkKeysAreDownloaded(otherUserId: String,
|
||||
startReq: KeyVerificationStart,
|
||||
success: (MXUsersDevicesMap<MXDeviceInfo>) -> Unit,
|
||||
error: () -> Unit) {
|
||||
deviceListManager.downloadKeys(listOf(otherUserId), true, object : MatrixCallback<MXUsersDevicesMap<MXDeviceInfo>> {
|
||||
override fun onFailure(failure: Throwable) {
|
||||
CryptoAsyncHelper.getDecryptBackgroundHandler().post {
|
||||
error()
|
||||
}
|
||||
}
|
||||
|
||||
override fun onSuccess(data: MXUsersDevicesMap<MXDeviceInfo>) {
|
||||
CryptoAsyncHelper.getDecryptBackgroundHandler().post {
|
||||
if (data.getUserDeviceIds(otherUserId).contains(startReq.fromDevice)) {
|
||||
success(data)
|
||||
} else {
|
||||
error()
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
private suspend fun checkKeysAreDownloaded(otherUserId: String,
|
||||
startReq: KeyVerificationStart,
|
||||
success: (MXUsersDevicesMap<MXDeviceInfo>) -> Unit,
|
||||
error: () -> Unit) {
|
||||
deviceListManager.downloadKeys(listOf(otherUserId), true)
|
||||
.fold(
|
||||
{ error() },
|
||||
{
|
||||
if (it != null && it.getUserDeviceIds(otherUserId).contains(startReq.fromDevice)) {
|
||||
success(it)
|
||||
} else {
|
||||
error()
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
private fun onCancelReceived(event: Event) {
|
||||
private suspend fun onCancelReceived(event: Event) {
|
||||
Timber.v("## SAS onCancelReceived")
|
||||
val cancelReq = event.getClearContent().toModel<KeyVerificationCancel>()!!
|
||||
|
||||
@ -254,7 +255,7 @@ internal class DefaultSasVerificationService(private val mCredentials: Credentia
|
||||
}
|
||||
}
|
||||
|
||||
private fun onAcceptReceived(event: Event) {
|
||||
private suspend fun onAcceptReceived(event: Event) {
|
||||
val acceptReq = event.getClearContent().toModel<KeyVerificationAccept>()!!
|
||||
|
||||
if (!acceptReq.isValid()) {
|
||||
@ -278,7 +279,7 @@ internal class DefaultSasVerificationService(private val mCredentials: Credentia
|
||||
}
|
||||
|
||||
|
||||
private fun onKeyReceived(event: Event) {
|
||||
private suspend fun onKeyReceived(event: Event) {
|
||||
val keyReq = event.getClearContent().toModel<KeyVerificationKey>()!!
|
||||
|
||||
if (!keyReq.isValid()) {
|
||||
@ -299,7 +300,7 @@ internal class DefaultSasVerificationService(private val mCredentials: Credentia
|
||||
}
|
||||
}
|
||||
|
||||
private fun onMacReceived(event: Event) {
|
||||
private suspend fun onMacReceived(event: Event) {
|
||||
val macReq = event.getClearContent().toModel<KeyVerificationMac>()!!
|
||||
|
||||
if (!macReq.isValid()) {
|
||||
@ -398,9 +399,9 @@ internal class DefaultSasVerificationService(private val mCredentials: Credentia
|
||||
override fun transactionUpdated(tx: VerificationTransaction) {
|
||||
dispatchTxUpdated(tx)
|
||||
if (tx is SASVerificationTransaction
|
||||
&& (tx.state == SasVerificationTxState.Cancelled
|
||||
|| tx.state == SasVerificationTxState.OnCancelled
|
||||
|| tx.state == SasVerificationTxState.Verified)
|
||||
&& (tx.state == SasVerificationTxState.Cancelled
|
||||
|| tx.state == SasVerificationTxState.OnCancelled
|
||||
|| tx.state == SasVerificationTxState.Verified)
|
||||
) {
|
||||
//remove
|
||||
this.removeTransaction(tx.otherUserId, tx.transactionId)
|
||||
|
@ -25,7 +25,7 @@ internal interface ClearCacheTask : Task<Unit, Unit>
|
||||
|
||||
internal class RealmClearCacheTask(val realmConfiguration: RealmConfiguration) : ClearCacheTask {
|
||||
|
||||
override fun execute(params: Unit): Try<Unit> {
|
||||
override suspend fun execute(params: Unit): Try<Unit> {
|
||||
return Try {
|
||||
val realm = Realm.getInstance(realmConfiguration)
|
||||
|
||||
|
@ -38,7 +38,7 @@ internal class DefaultSaveFilterTask(private val sessionParams: SessionParams,
|
||||
private val filterRepository: FilterRepository
|
||||
) : SaveFilterTask {
|
||||
|
||||
override fun execute(params: SaveFilterTask.Params): Try<Unit> {
|
||||
override suspend fun execute(params: SaveFilterTask.Params): Try<Unit> {
|
||||
return executeRequest<FilterResponse> {
|
||||
// TODO auto retry
|
||||
apiCall = filterAPI.uploadFilter(sessionParams.credentials.userId, params.filter)
|
||||
|
@ -43,7 +43,7 @@ internal class DefaultGetGroupDataTask(
|
||||
private val monarchy: Monarchy
|
||||
) : GetGroupDataTask {
|
||||
|
||||
override fun execute(params: GetGroupDataTask.Params): Try<Unit> {
|
||||
override suspend fun execute(params: GetGroupDataTask.Params): Try<Unit> {
|
||||
val groupId = params.groupId
|
||||
return Try.monad().binding {
|
||||
|
||||
|
@ -17,6 +17,7 @@
|
||||
package im.vector.matrix.android.internal.session.group
|
||||
|
||||
import android.content.Context
|
||||
import androidx.work.CoroutineWorker
|
||||
import androidx.work.Worker
|
||||
import androidx.work.WorkerParameters
|
||||
import arrow.core.Try
|
||||
@ -27,7 +28,7 @@ import org.koin.standalone.inject
|
||||
|
||||
internal class GetGroupDataWorker(context: Context,
|
||||
workerParameters: WorkerParameters
|
||||
) : Worker(context, workerParameters), MatrixKoinComponent {
|
||||
) : CoroutineWorker(context, workerParameters), MatrixKoinComponent {
|
||||
|
||||
@JsonClass(generateAdapter = true)
|
||||
internal data class Params(
|
||||
@ -36,7 +37,7 @@ internal class GetGroupDataWorker(context: Context,
|
||||
|
||||
private val getGroupDataTask by inject<GetGroupDataTask>()
|
||||
|
||||
override fun doWork(): Result {
|
||||
override suspend fun doWork(): Result {
|
||||
val params = WorkerParamsFactory.fromData<Params>(inputData)
|
||||
?: return Result.failure()
|
||||
|
||||
@ -47,7 +48,7 @@ internal class GetGroupDataWorker(context: Context,
|
||||
return if (isSuccessful) Result.success() else Result.retry()
|
||||
}
|
||||
|
||||
private fun fetchGroupData(groupId: String): Try<Unit> {
|
||||
private suspend fun fetchGroupData(groupId: String): Try<Unit> {
|
||||
return getGroupDataTask.execute(GetGroupDataTask.Params(groupId))
|
||||
}
|
||||
|
||||
|
@ -41,7 +41,7 @@ internal class DefaultCreateRoomTask(private val roomAPI: RoomAPI,
|
||||
private val realmConfiguration: RealmConfiguration) : CreateRoomTask {
|
||||
|
||||
|
||||
override fun execute(params: CreateRoomParams): Try<String> {
|
||||
override suspend fun execute(params: CreateRoomParams): Try<String> {
|
||||
return executeRequest<CreateRoomResponse> {
|
||||
apiCall = roomAPI.createRoom(params)
|
||||
}.flatMap { createRoomResponse ->
|
||||
|
@ -31,7 +31,7 @@ internal interface InviteTask : Task<InviteTask.Params, Unit> {
|
||||
|
||||
internal class DefaultInviteTask(private val roomAPI: RoomAPI) : InviteTask {
|
||||
|
||||
override fun execute(params: InviteTask.Params): Try<Unit> {
|
||||
override suspend fun execute(params: InviteTask.Params): Try<Unit> {
|
||||
return executeRequest {
|
||||
val body = InviteBody(params.userId)
|
||||
apiCall = roomAPI.invite(params.roomId, body)
|
||||
|
@ -44,7 +44,7 @@ internal class DefaultLoadRoomMembersTask(private val roomAPI: RoomAPI,
|
||||
private val roomSummaryUpdater: RoomSummaryUpdater
|
||||
) : LoadRoomMembersTask {
|
||||
|
||||
override fun execute(params: LoadRoomMembersTask.Params): Try<Boolean> {
|
||||
override suspend fun execute(params: LoadRoomMembersTask.Params): Try<Boolean> {
|
||||
return if (areAllMembersAlreadyLoaded(params.roomId)) {
|
||||
Try.just(true)
|
||||
} else {
|
||||
|
@ -50,7 +50,7 @@ internal class DefaultSetReadMarkersTask(private val roomAPI: RoomAPI,
|
||||
private val monarchy: Monarchy
|
||||
) : SetReadMarkersTask {
|
||||
|
||||
override fun execute(params: SetReadMarkersTask.Params): Try<Unit> {
|
||||
override suspend fun execute(params: SetReadMarkersTask.Params): Try<Unit> {
|
||||
val markers = HashMap<String, String>()
|
||||
if (params.fullyReadEventId != null && MatrixPatterns.isEventId(params.fullyReadEventId)) {
|
||||
markers[READ_MARKER] = params.fullyReadEventId
|
||||
|
@ -30,7 +30,7 @@ internal interface SendStateTask : Task<SendStateTask.Params, Unit> {
|
||||
}
|
||||
|
||||
internal class DefaultSendStateTask(private val roomAPI: RoomAPI) : SendStateTask {
|
||||
override fun execute(params: SendStateTask.Params): Try<Unit> {
|
||||
override suspend fun execute(params: SendStateTask.Params): Try<Unit> {
|
||||
return executeRequest {
|
||||
apiCall = roomAPI.sendStateEvent(params.roomId, params.eventType, params.body)
|
||||
}
|
||||
|
@ -36,7 +36,7 @@ internal class DefaultGetContextOfEventTask(private val roomAPI: RoomAPI,
|
||||
private val tokenChunkEventPersistor: TokenChunkEventPersistor
|
||||
) : GetContextOfEventTask {
|
||||
|
||||
override fun execute(params: GetContextOfEventTask.Params): Try<TokenChunkEventPersistor.Result> {
|
||||
override suspend fun execute(params: GetContextOfEventTask.Params): Try<TokenChunkEventPersistor.Result> {
|
||||
val filter = filterRepository.getRoomFilter()
|
||||
return executeRequest<EventContextResponse> {
|
||||
apiCall = roomAPI.getContextOfEvent(params.roomId, params.eventId, 0, filter)
|
||||
|
@ -39,7 +39,7 @@ internal class DefaultPaginationTask(private val roomAPI: RoomAPI,
|
||||
private val tokenChunkEventPersistor: TokenChunkEventPersistor
|
||||
) : PaginationTask {
|
||||
|
||||
override fun execute(params: PaginationTask.Params): Try<TokenChunkEventPersistor.Result> {
|
||||
override suspend fun execute(params: PaginationTask.Params): Try<TokenChunkEventPersistor.Result> {
|
||||
val filter = filterRepository.getRoomFilter()
|
||||
return executeRequest<PaginationResponse> {
|
||||
apiCall = roomAPI.getRoomMessagesFrom(params.roomId, params.from, params.direction.value, params.limit, filter)
|
||||
|
@ -30,7 +30,7 @@ internal class GetEventTask(private val roomAPI: RoomAPI
|
||||
val eventId: String
|
||||
)
|
||||
|
||||
override fun execute(params: Params): Try<Event> {
|
||||
override suspend fun execute(params: Params): Try<Event> {
|
||||
return executeRequest {
|
||||
apiCall = roomAPI.getEvent(params.roomId, params.eventId)
|
||||
}
|
||||
|
@ -27,7 +27,7 @@ internal interface SignOutTask : Task<Unit, Unit>
|
||||
internal class DefaultSignOutTask(private val signOutAPI: SignOutAPI,
|
||||
private val sessionParamsStore: SessionParamsStore) : SignOutTask {
|
||||
|
||||
override fun execute(params: Unit): Try<Unit> {
|
||||
override suspend fun execute(params: Unit): Try<Unit> {
|
||||
return executeRequest<Unit> {
|
||||
apiCall = signOutAPI.signOut()
|
||||
}.flatMap {
|
||||
|
@ -37,7 +37,6 @@ internal class CryptoSyncHandler(private val cryptoManager: CryptoManager,
|
||||
toDevice.events?.forEach { event ->
|
||||
// Decrypt event if necessary
|
||||
decryptEvent(event, null)
|
||||
|
||||
if (TextUtils.equals(event.getClearType(), EventType.MESSAGE)
|
||||
&& event.mClearEvent?.content?.toModel<MessageContent>()?.type == "m.bad.encrypted") {
|
||||
Timber.e("## handleToDeviceEvent() : Warning: Unable to decrypt to-device event : " + event.content)
|
||||
|
@ -40,7 +40,7 @@ internal class DefaultSyncTask(private val syncAPI: SyncAPI,
|
||||
) : SyncTask {
|
||||
|
||||
|
||||
override fun execute(params: SyncTask.Params): Try<SyncResponse> {
|
||||
override suspend fun execute(params: SyncTask.Params): Try<SyncResponse> {
|
||||
val requestParams = HashMap<String, String>()
|
||||
var timeout = 0
|
||||
if (params.token != null) {
|
||||
|
@ -35,7 +35,7 @@ internal interface UpdateUserTask : Task<UpdateUserTask.Params, Unit> {
|
||||
|
||||
internal class DefaultUpdateUserTask(private val monarchy: Monarchy) : UpdateUserTask {
|
||||
|
||||
override fun execute(params: UpdateUserTask.Params): Try<Unit> {
|
||||
override suspend fun execute(params: UpdateUserTask.Params): Try<Unit> {
|
||||
return monarchy.tryTransactionSync { realm ->
|
||||
params.eventIds.forEach { eventId ->
|
||||
val event = EventEntity.where(realm, eventId).findFirst()?.asDomain()
|
||||
|
@ -34,7 +34,7 @@ internal data class ConfigurableTask<PARAMS, RESULT>(
|
||||
) : Task<PARAMS, RESULT> {
|
||||
|
||||
|
||||
override fun execute(params: PARAMS): Try<RESULT> {
|
||||
override suspend fun execute(params: PARAMS): Try<RESULT> {
|
||||
return task.execute(params)
|
||||
}
|
||||
|
||||
|
@ -20,7 +20,7 @@ import arrow.core.Try
|
||||
|
||||
internal interface Task<PARAMS, RESULT> {
|
||||
|
||||
fun execute(params: PARAMS): Try<RESULT>
|
||||
suspend fun execute(params: PARAMS): Try<RESULT>
|
||||
|
||||
}
|
||||
|
||||
|
@ -68,8 +68,7 @@ internal class TaskExecutor(private val coroutineDispatchers: MatrixCoroutineDis
|
||||
TaskThread.COMPUTATION -> coroutineDispatchers.computation
|
||||
TaskThread.IO -> coroutineDispatchers.io
|
||||
TaskThread.CALLER -> EmptyCoroutineContext
|
||||
TaskThread.ENCRYPTION -> coroutineDispatchers.crypto
|
||||
TaskThread.DECRYPTION -> coroutineDispatchers.crypto
|
||||
TaskThread.CRYPTO -> coroutineDispatchers.crypto
|
||||
}
|
||||
|
||||
|
||||
|
@ -21,6 +21,5 @@ internal enum class TaskThread {
|
||||
COMPUTATION,
|
||||
IO,
|
||||
CALLER,
|
||||
ENCRYPTION,
|
||||
DECRYPTION
|
||||
CRYPTO
|
||||
}
|
Loading…
Reference in New Issue
Block a user