diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/util/Try.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/util/Try.kt
deleted file mode 100644
index 365d5472b8..0000000000
--- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/util/Try.kt
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
- *
- * * Copyright 2019 New Vector Ltd
- * *
- * * Licensed under the Apache License, Version 2.0 (the "License");
- * * you may not use this file except in compliance with the License.
- * * You may obtain a copy of the License at
- * *
- * * http://www.apache.org/licenses/LICENSE-2.0
- * *
- * * Unless required by applicable law or agreed to in writing, software
- * * distributed under the License is distributed on an "AS IS" BASIS,
- * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * * See the License for the specific language governing permissions and
- * * limitations under the License.
- *
- */
-
-package im.vector.matrix.android.api.util
-
-import arrow.core.*
-
-inline fun TryOf.onError(f: (Throwable) -> Unit): Try = fix()
- .fold(
- {
- f(it)
- Failure(it)
- },
- { Success(it) }
- )
diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/auth/DefaultAuthenticator.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/auth/DefaultAuthenticator.kt
index d2474f3750..1552083517 100644
--- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/auth/DefaultAuthenticator.kt
+++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/auth/DefaultAuthenticator.kt
@@ -26,6 +26,7 @@ import im.vector.matrix.android.api.auth.data.Credentials
import im.vector.matrix.android.internal.auth.data.PasswordLoginParams
import im.vector.matrix.android.api.auth.data.SessionParams
import im.vector.matrix.android.internal.auth.data.ThreePidMedium
+import im.vector.matrix.android.internal.extensions.foldToCallback
import im.vector.matrix.android.internal.network.executeRequest
import im.vector.matrix.android.internal.session.DefaultSession
import im.vector.matrix.android.internal.util.CancelableCoroutine
@@ -57,7 +58,7 @@ internal class DefaultAuthenticator(private val retrofitBuilder: Retrofit.Builde
val job = GlobalScope.launch(coroutineDispatchers.main) {
val sessionOrFailure = authenticate(homeServerConnectionConfig, login, password)
- sessionOrFailure.fold({ callback.onFailure(it) }, { callback.onSuccess(it) })
+ sessionOrFailure.foldToCallback(callback)
}
return CancelableCoroutine(job)
diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/CryptoAsyncHelper.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/CryptoAsyncHelper.kt
deleted file mode 100644
index 411bcbf640..0000000000
--- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/CryptoAsyncHelper.kt
+++ /dev/null
@@ -1,61 +0,0 @@
-/*
- *
- * * Copyright 2019 New Vector Ltd
- * *
- * * Licensed under the Apache License, Version 2.0 (the "License");
- * * you may not use this file except in compliance with the License.
- * * You may obtain a copy of the License at
- * *
- * * http://www.apache.org/licenses/LICENSE-2.0
- * *
- * * Unless required by applicable law or agreed to in writing, software
- * * distributed under the License is distributed on an "AS IS" BASIS,
- * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * * See the License for the specific language governing permissions and
- * * limitations under the License.
- *
- */
-
-package im.vector.matrix.android.internal.crypto
-
-import android.os.Handler
-import android.os.HandlerThread
-import android.os.Looper
-
-private const val THREAD_CRYPTO_NAME = "Crypto_Thread"
-
-// TODO Remove and replace by Task
-internal object CryptoAsyncHelper {
-
- private var uiHandler: Handler? = null
- private var cryptoBackgroundHandler: Handler? = null
-
- fun getUiHandler(): Handler {
- return uiHandler
- ?: Handler(Looper.getMainLooper())
- .also { uiHandler = it }
- }
-
-
- fun getDecryptBackgroundHandler(): Handler {
- return getCryptoBackgroundHandler()
- }
-
- fun getEncryptBackgroundHandler(): Handler {
- return getCryptoBackgroundHandler()
- }
-
- private fun getCryptoBackgroundHandler(): Handler {
- return cryptoBackgroundHandler
- ?: createCryptoBackgroundHandler()
- .also { cryptoBackgroundHandler = it }
- }
-
- private fun createCryptoBackgroundHandler(): Handler {
- val handlerThread = HandlerThread(THREAD_CRYPTO_NAME)
- handlerThread.start()
- return Handler(handlerThread.looper)
- }
-
-
-}
\ No newline at end of file
diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/CryptoManager.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/CryptoManager.kt
index 5e422571b5..cb5ed9688f 100755
--- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/CryptoManager.kt
+++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/CryptoManager.kt
@@ -19,8 +19,11 @@
package im.vector.matrix.android.internal.crypto
import android.content.Context
+import android.os.Handler
+import android.os.Looper
import android.text.TextUtils
import arrow.core.Try
+import com.squareup.moshi.Types
import com.zhuinden.monarchy.Monarchy
import im.vector.matrix.android.api.MatrixCallback
import im.vector.matrix.android.api.auth.data.Credentials
@@ -64,6 +67,7 @@ import im.vector.matrix.android.internal.crypto.verification.DefaultSasVerificat
import im.vector.matrix.android.internal.database.model.EventEntity
import im.vector.matrix.android.internal.database.query.where
import im.vector.matrix.android.internal.di.MoshiProvider
+import im.vector.matrix.android.internal.extensions.foldToCallback
import im.vector.matrix.android.internal.session.cache.ClearCacheTask
import im.vector.matrix.android.internal.session.room.membership.LoadRoomMembersTask
import im.vector.matrix.android.internal.session.room.membership.RoomMembers
@@ -137,6 +141,8 @@ internal class CryptoManager(
private val taskExecutor: TaskExecutor
) : CryptoService {
+ private val uiHandler = Handler(Looper.getMainLooper())
+
// MXEncrypting instance for each room.
private val roomEncryptors: MutableMap = HashMap()
private val isStarting = AtomicBoolean(false)
@@ -560,10 +566,10 @@ internal class CryptoManager(
} else {
val algorithm = getEncryptionAlgorithm(roomId)
val reason = String.format(MXCryptoError.UNABLE_TO_ENCRYPT_REASON,
- algorithm ?: MXCryptoError.NO_MORE_ALGORITHM_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)))
+ MXCryptoError.UNABLE_TO_ENCRYPT, reason)))
}
}
}
@@ -597,10 +603,7 @@ internal class CryptoManager(
val result = withContext(coroutineDispatchers.crypto) {
internalDecryptEvent(event, timeline)
}
- result.fold(
- { callback.onFailure(it) },
- { callback.onSuccess(it) }
- )
+ result.foldToCallback(callback)
}
}
@@ -700,7 +703,7 @@ internal class CryptoManager(
monarchy.doWithRealm { realm ->
// Check whether the event content must be encrypted for the invited members.
val encryptForInvitedMembers = isEncryptionEnabledForInvitedUser()
- && shouldEncryptForInvitedMembers(roomId)
+ && shouldEncryptForInvitedMembers(roomId)
userIds = if (encryptForInvitedMembers) {
RoomMembers(realm, roomId).getActiveRoomMemberIds()
@@ -787,35 +790,31 @@ internal class CryptoManager(
* @param anIterationCount the encryption iteration count (0 means no encryption)
* @param callback the exported keys
*/
- fun exportRoomKeys(password: String, anIterationCount: Int, callback: MatrixCallback) {
- val iterationCount = Math.max(0, anIterationCount)
+ private fun exportRoomKeys(password: String, anIterationCount: Int, callback: MatrixCallback) {
+ GlobalScope.launch(coroutineDispatchers.main) {
+ withContext(coroutineDispatchers.crypto) {
+ Try {
+ val iterationCount = Math.max(0, anIterationCount)
- val exportedSessions = ArrayList()
+ val exportedSessions = ArrayList()
- val inboundGroupSessions = cryptoStore.getInboundGroupSessions()
+ val inboundGroupSessions = cryptoStore.getInboundGroupSessions()
- for (session in inboundGroupSessions) {
- val megolmSessionData = session.exportKeys()
+ for (session in inboundGroupSessions) {
+ val megolmSessionData = session.exportKeys()
- if (null != megolmSessionData) {
- exportedSessions.add(megolmSessionData)
- }
+ if (null != megolmSessionData) {
+ exportedSessions.add(megolmSessionData)
+ }
+ }
+
+ val adapter = MoshiProvider.providesMoshi()
+ .adapter(List::class.java)
+
+ MXMegolmExportEncryption.encryptMegolmKeyFile(adapter.toJson(exportedSessions), password, iterationCount)
+ }
+ }.foldToCallback(callback)
}
-
- val encryptedRoomKeys: ByteArray
-
- try {
- val adapter = MoshiProvider.providesMoshi()
- .adapter(List::class.java)
-
- encryptedRoomKeys = MXMegolmExportEncryption
- .encryptMegolmKeyFile(adapter.toJson(exportedSessions), password, iterationCount)
- } catch (e: Exception) {
- callback.onFailure(e)
- return
- }
-
- callback.onSuccess(encryptedRoomKeys)
}
/**
@@ -830,40 +829,33 @@ internal class CryptoManager(
password: String,
progressListener: ProgressListener?,
callback: MatrixCallback) {
- Timber.v("## importRoomKeys starts")
+ GlobalScope.launch(coroutineDispatchers.main) {
+ withContext(coroutineDispatchers.crypto) {
+ Try {
+ Timber.v("## importRoomKeys starts")
- val t0 = System.currentTimeMillis()
- val roomKeys: String
+ val t0 = System.currentTimeMillis()
+ val roomKeys = MXMegolmExportEncryption.decryptMegolmKeyFile(roomKeysAsArray, password)
+ val t1 = System.currentTimeMillis()
- try {
- roomKeys = MXMegolmExportEncryption.decryptMegolmKeyFile(roomKeysAsArray, password)
- } catch (e: Exception) {
- callback.onFailure(e)
- return
+ Timber.v("## importRoomKeys : decryptMegolmKeyFile done in " + (t1 - t0) + " ms")
+
+ val importedSessions = MoshiProvider.providesMoshi()
+ .adapter>(Types.newParameterizedType(List::class.java, MegolmSessionData::class.java))
+ .fromJson(roomKeys)
+
+ val t2 = System.currentTimeMillis()
+
+ Timber.v("## importRoomKeys : JSON parsing " + (t2 - t1) + " ms")
+
+ if (importedSessions == null) {
+ throw Exception("Error")
+ }
+
+ megolmSessionDataImporter.handle(importedSessions, true, uiHandler, progressListener)
+ }
+ }.foldToCallback(callback)
}
-
- val importedSessions: List
-
- val t1 = System.currentTimeMillis()
-
- Timber.v("## importRoomKeys : decryptMegolmKeyFile done in " + (t1 - t0) + " ms")
-
- try {
- val list = MoshiProvider.providesMoshi()
- .adapter(List::class.java)
- .fromJson(roomKeys)
- importedSessions = list as List
- } catch (e: Exception) {
- Timber.e(e, "## importRoomKeys failed")
- callback.onFailure(e)
- return
- }
-
- val t2 = System.currentTimeMillis()
-
- Timber.v("## importRoomKeys : JSON parsing " + (t2 - t1) + " ms")
-
- megolmSessionDataImporter.handle(importedSessions, true, progressListener, callback)
}
/**
@@ -898,7 +890,7 @@ internal class CryptoManager(
// trigger an an unknown devices exception
callback.onFailure(
Failure.CryptoError(MXCryptoError(MXCryptoError.UNKNOWN_DEVICES_CODE,
- MXCryptoError.UNABLE_TO_ENCRYPT, MXCryptoError.UNKNOWN_DEVICES_REASON, unknownDevices)))
+ MXCryptoError.UNABLE_TO_ENCRYPT, MXCryptoError.UNKNOWN_DEVICES_REASON, unknownDevices)))
}
}
)
@@ -1061,10 +1053,7 @@ internal class CryptoManager(
CoroutineScope(coroutineDispatchers.crypto).launch {
deviceListManager
.downloadKeys(userIds, forceDownload)
- .fold(
- { callback.onFailure(it) },
- { callback.onSuccess(it) }
- )
+ .foldToCallback(callback)
}
}
diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/CryptoModule.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/CryptoModule.kt
index 761318ace6..495bd6b13f 100644
--- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/CryptoModule.kt
+++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/CryptoModule.kt
@@ -277,6 +277,7 @@ internal class CryptoModule {
// Task
get(), get(), get(), get(), get(), get(), get(), get(), get(), get(), get(), get(), get(), get(),
// Task executor
+ get(),
get())
}
diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/DeviceListManager.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/DeviceListManager.kt
index 2217a79616..ffda9507de 100755
--- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/DeviceListManager.kt
+++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/DeviceListManager.kt
@@ -21,7 +21,7 @@ import android.text.TextUtils
import arrow.core.Try
import im.vector.matrix.android.api.MatrixPatterns
import im.vector.matrix.android.api.auth.data.Credentials
-import im.vector.matrix.android.api.util.onError
+import im.vector.matrix.android.internal.extensions.onError
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.store.IMXCryptoStore
diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/MXMegolmExportEncryption.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/MXMegolmExportEncryption.kt
index 6a99101897..82b2c95d89 100755
--- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/MXMegolmExportEncryption.kt
+++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/MXMegolmExportEncryption.kt
@@ -18,6 +18,7 @@ package im.vector.matrix.android.internal.crypto
import android.text.TextUtils
import android.util.Base64
+import im.vector.matrix.android.internal.extensions.toUnsignedInt
import timber.log.Timber
import java.io.ByteArrayOutputStream
import java.nio.charset.Charset
@@ -43,16 +44,6 @@ object MXMegolmExportEncryption {
// default iteration count to export the e2e keys
const val DEFAULT_ITERATION_COUNT = 500000
- /**
- * Convert a signed byte to a int value
- *
- * @param bVal the byte value to convert
- * @return the matched int value
- */
- private fun byteToInt(bVal: Byte): Int {
- return (bVal and 0xFF.toByte()).toInt()
- }
-
/**
* Extract the AES key from the deriveKeys result.
*
@@ -108,7 +99,8 @@ object MXMegolmExportEncryption {
val salt = Arrays.copyOfRange(body, 1, 1 + 16)
val iv = Arrays.copyOfRange(body, 17, 17 + 16)
- val iterations = byteToInt(body[33]) shl 24 or (byteToInt(body[34]) shl 16) or (byteToInt(body[35]) shl 8) or byteToInt(body[36])
+ val iterations =
+ (body[33].toUnsignedInt() shl 24) or (body[34].toUnsignedInt() shl 16) or (body[35].toUnsignedInt() shl 8) or body[36].toUnsignedInt()
val ciphertext = Arrays.copyOfRange(body, 37, 37 + ciphertextLength)
val hmac = Arrays.copyOfRange(body, body.size - 32, body.size)
diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/actions/MegolmSessionDataImporter.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/actions/MegolmSessionDataImporter.kt
index 07c8b465f4..433114df6f 100644
--- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/actions/MegolmSessionDataImporter.kt
+++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/actions/MegolmSessionDataImporter.kt
@@ -16,9 +16,9 @@
package im.vector.matrix.android.internal.crypto.actions
-import im.vector.matrix.android.api.MatrixCallback
+import android.os.Handler
+import androidx.annotation.WorkerThread
import im.vector.matrix.android.api.listeners.ProgressListener
-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
@@ -35,34 +35,32 @@ internal class MegolmSessionDataImporter(private val olmDevice: MXOlmDevice,
/**
* Import a list of megolm session keys.
+ * Must be call on the crypto coroutine thread
*
* @param megolmSessionsData megolm sessions.
* @param backUpKeys true to back up them to the homeserver.
* @param progressListener the progress listener
- * @param callback
+ * @return import room keys result
*/
+ @WorkerThread
fun handle(megolmSessionsData: List,
fromBackup: Boolean,
- progressListener: ProgressListener?,
- callback: MatrixCallback) {
+ uiHandler: Handler,
+ progressListener: ProgressListener?): ImportRoomKeysResult {
val t0 = System.currentTimeMillis()
val totalNumbersOfKeys = megolmSessionsData.size
- var cpt = 0
var lastProgress = 0
var totalNumbersOfImportedKeys = 0
if (progressListener != null) {
- CryptoAsyncHelper.getUiHandler().post {
+ uiHandler.post {
progressListener.onProgress(0, 100)
}
}
val olmInboundGroupSessionWrappers = olmDevice.importInboundGroupSessions(megolmSessionsData)
- for (megolmSessionData in megolmSessionsData) {
- cpt++
-
-
+ megolmSessionsData.forEachIndexed { cpt, megolmSessionData ->
val decrypting = roomDecryptorProvider.getOrCreateRoomDecryptor(megolmSessionData.roomId, megolmSessionData.algorithm)
if (null != decrypting) {
@@ -90,7 +88,7 @@ internal class MegolmSessionDataImporter(private val olmDevice: MXOlmDevice,
}
if (progressListener != null) {
- CryptoAsyncHelper.getUiHandler().post {
+ uiHandler.post {
val progress = 100 * cpt / totalNumbersOfKeys
if (lastProgress != progress) {
@@ -111,10 +109,6 @@ internal class MegolmSessionDataImporter(private val olmDevice: MXOlmDevice,
Timber.v("## importMegolmSessionsData : sessions import " + (t1 - t0) + " ms (" + megolmSessionsData.size + " sessions)")
- val finalTotalNumbersOfImportedKeys = totalNumbersOfImportedKeys
-
- CryptoAsyncHelper.getUiHandler().post {
- callback.onSuccess(ImportRoomKeysResult(totalNumbersOfKeys, finalTotalNumbersOfImportedKeys))
- }
+ return ImportRoomKeysResult(totalNumbersOfKeys, totalNumbersOfImportedKeys)
}
}
\ No newline at end of file
diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/keysbackup/KeysBackup.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/keysbackup/KeysBackup.kt
index b80b063fbc..60e19e465e 100644
--- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/keysbackup/KeysBackup.kt
+++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/keysbackup/KeysBackup.kt
@@ -31,7 +31,10 @@ import im.vector.matrix.android.api.listeners.StepProgressListener
import im.vector.matrix.android.api.session.crypto.keysbackup.KeysBackupService
import im.vector.matrix.android.api.session.crypto.keysbackup.KeysBackupState
import im.vector.matrix.android.api.session.crypto.keysbackup.KeysBackupStateListener
-import im.vector.matrix.android.internal.crypto.*
+import im.vector.matrix.android.internal.crypto.MXCRYPTO_ALGORITHM_MEGOLM_BACKUP
+import im.vector.matrix.android.internal.crypto.MXOlmDevice
+import im.vector.matrix.android.internal.crypto.MegolmSessionData
+import im.vector.matrix.android.internal.crypto.ObjectSigner
import im.vector.matrix.android.internal.crypto.actions.MegolmSessionDataImporter
import im.vector.matrix.android.internal.crypto.keysbackup.model.KeysBackupVersionTrust
import im.vector.matrix.android.internal.crypto.keysbackup.model.KeysBackupVersionTrustSignature
@@ -47,10 +50,15 @@ import im.vector.matrix.android.internal.crypto.model.OlmInboundGroupSessionWrap
import im.vector.matrix.android.internal.crypto.store.IMXCryptoStore
import im.vector.matrix.android.internal.crypto.store.db.model.KeysBackupDataEntity
import im.vector.matrix.android.internal.di.MoshiProvider
+import im.vector.matrix.android.internal.extensions.foldToCallback
import im.vector.matrix.android.internal.task.Task
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.GlobalScope
+import kotlinx.coroutines.launch
+import kotlinx.coroutines.withContext
import org.matrix.olm.OlmException
import org.matrix.olm.OlmPkDecryption
import org.matrix.olm.OlmPkEncryption
@@ -87,7 +95,8 @@ internal class KeysBackup(
private val storeSessionDataTask: StoreSessionsDataTask,
private val updateKeysBackupVersionTask: UpdateKeysBackupVersionTask,
// Task executor
- private val taskExecutor: TaskExecutor
+ private val taskExecutor: TaskExecutor,
+ private val coroutineDispatchers: MatrixCoroutineDispatchers
) : KeysBackupService {
private val uiHandler = Handler(Looper.getMainLooper())
@@ -130,55 +139,53 @@ internal class KeysBackup(
override fun prepareKeysBackupVersion(password: String?,
progressListener: ProgressListener?,
callback: MatrixCallback) {
- CryptoAsyncHelper.getDecryptBackgroundHandler().post {
- try {
- val olmPkDecryption = OlmPkDecryption()
- val megolmBackupAuthData = MegolmBackupAuthData()
+ GlobalScope.launch(coroutineDispatchers.main) {
+ withContext(coroutineDispatchers.crypto) {
+ Try {
+ val olmPkDecryption = OlmPkDecryption()
+ val megolmBackupAuthData = MegolmBackupAuthData()
- if (password != null) {
- // Generate a private key from the password
- val backgroundProgressListener = if (progressListener == null) {
- null
- } else {
- object : ProgressListener {
- override fun onProgress(progress: Int, total: Int) {
- uiHandler.post {
- try {
- progressListener.onProgress(progress, total)
- } catch (e: Exception) {
- Timber.e(e, "prepareKeysBackupVersion: onProgress failure")
+ if (password != null) {
+ // Generate a private key from the password
+ val backgroundProgressListener = if (progressListener == null) {
+ null
+ } else {
+ object : ProgressListener {
+ override fun onProgress(progress: Int, total: Int) {
+ uiHandler.post {
+ try {
+ progressListener.onProgress(progress, total)
+ } catch (e: Exception) {
+ Timber.e(e, "prepareKeysBackupVersion: onProgress failure")
+ }
}
}
}
}
+
+ val generatePrivateKeyResult = generatePrivateKeyWithPassword(password, backgroundProgressListener)
+ megolmBackupAuthData.publicKey = olmPkDecryption.setPrivateKey(generatePrivateKeyResult.privateKey)
+ megolmBackupAuthData.privateKeySalt = generatePrivateKeyResult.salt
+ megolmBackupAuthData.privateKeyIterations = generatePrivateKeyResult.iterations
+ } else {
+ val publicKey = olmPkDecryption.generateKey()
+
+ megolmBackupAuthData.publicKey = publicKey
}
- val generatePrivateKeyResult = generatePrivateKeyWithPassword(password, backgroundProgressListener)
- megolmBackupAuthData.publicKey = olmPkDecryption.setPrivateKey(generatePrivateKeyResult.privateKey)
- megolmBackupAuthData.privateKeySalt = generatePrivateKeyResult.salt
- megolmBackupAuthData.privateKeyIterations = generatePrivateKeyResult.iterations
- } else {
- val publicKey = olmPkDecryption.generateKey()
+ val canonicalJson = MoshiProvider.getCanonicalJson(Map::class.java, megolmBackupAuthData.signalableJSONDictionary())
- megolmBackupAuthData.publicKey = publicKey
+ megolmBackupAuthData.signatures = objectSigner.signObject(canonicalJson)
+
+
+ val megolmBackupCreationInfo = MegolmBackupCreationInfo()
+ megolmBackupCreationInfo.algorithm = MXCRYPTO_ALGORITHM_MEGOLM_BACKUP
+ megolmBackupCreationInfo.authData = megolmBackupAuthData
+ megolmBackupCreationInfo.recoveryKey = computeRecoveryKey(olmPkDecryption.privateKey())
+
+ megolmBackupCreationInfo
}
-
- val canonicalJson = MoshiProvider.getCanonicalJson(Map::class.java, megolmBackupAuthData.signalableJSONDictionary())
-
- megolmBackupAuthData.signatures = objectSigner.signObject(canonicalJson)
-
-
- val megolmBackupCreationInfo = MegolmBackupCreationInfo()
- megolmBackupCreationInfo.algorithm = MXCRYPTO_ALGORITHM_MEGOLM_BACKUP
- megolmBackupCreationInfo.authData = megolmBackupAuthData
- megolmBackupCreationInfo.recoveryKey = computeRecoveryKey(olmPkDecryption.privateKey())
-
- uiHandler.post { callback.onSuccess(megolmBackupCreationInfo) }
- } catch (e: OlmException) {
- Timber.e(e, "OlmException")
-
- uiHandler.post { callback.onFailure(e) }
- }
+ }.foldToCallback(callback)
}
}
@@ -221,37 +228,39 @@ internal class KeysBackup(
}
override fun deleteBackup(version: String, callback: MatrixCallback?) {
- CryptoAsyncHelper.getDecryptBackgroundHandler().post {
- // If we're currently backing up to this backup... stop.
- // (We start using it automatically in createKeysBackupVersion so this is symmetrical).
- if (keysBackupVersion != null && version == keysBackupVersion!!.version) {
- resetKeysBackupData()
- keysBackupVersion = null
- keysBackupStateManager.state = KeysBackupState.Unknown
- }
+ GlobalScope.launch(coroutineDispatchers.main) {
+ withContext(coroutineDispatchers.crypto) {
+ // If we're currently backing up to this backup... stop.
+ // (We start using it automatically in createKeysBackupVersion so this is symmetrical).
+ if (keysBackupVersion != null && version == keysBackupVersion!!.version) {
+ resetKeysBackupData()
+ keysBackupVersion = null
+ keysBackupStateManager.state = KeysBackupState.Unknown
+ }
- deleteBackupTask.configureWith(DeleteBackupTask.Params(version))
- .dispatchTo(object : MatrixCallback {
- private fun eventuallyRestartBackup() {
- // Do not stay in KeysBackupState.Unknown but check what is available on the homeserver
- if (state == KeysBackupState.Unknown) {
- checkAndStartKeysBackup()
+ deleteBackupTask.configureWith(DeleteBackupTask.Params(version))
+ .dispatchTo(object : MatrixCallback {
+ private fun eventuallyRestartBackup() {
+ // Do not stay in KeysBackupState.Unknown but check what is available on the homeserver
+ if (state == KeysBackupState.Unknown) {
+ checkAndStartKeysBackup()
+ }
}
- }
- override fun onSuccess(data: Unit) {
- eventuallyRestartBackup()
+ override fun onSuccess(data: Unit) {
+ eventuallyRestartBackup()
- uiHandler.post { callback?.onSuccess(Unit) }
- }
+ uiHandler.post { callback?.onSuccess(Unit) }
+ }
- override fun onFailure(failure: Throwable) {
- eventuallyRestartBackup()
+ override fun onFailure(failure: Throwable) {
+ eventuallyRestartBackup()
- uiHandler.post { callback?.onFailure(failure) }
- }
- })
- .executeBy(taskExecutor)
+ uiHandler.post { callback?.onFailure(failure) }
+ }
+ })
+ .executeBy(taskExecutor)
+ }
}
}
@@ -426,85 +435,80 @@ internal class KeysBackup(
callback: MatrixCallback) {
Timber.v("trustKeyBackupVersion: $trust, version ${keysBackupVersion.version}")
- CryptoAsyncHelper.getDecryptBackgroundHandler().post {
- val myUserId = credentials.userId
+ // Get auth data to update it
+ val authData = getMegolmBackupAuthData(keysBackupVersion)
- // Get auth data to update it
- val authData = getMegolmBackupAuthData(keysBackupVersion)
+ if (authData == null) {
+ Timber.w("trustKeyBackupVersion:trust: Key backup is missing required data")
- if (authData == null) {
- Timber.w("trustKeyBackupVersion:trust: Key backup is missing required data")
+ callback.onFailure(IllegalArgumentException("Missing element"))
+ } else {
+ GlobalScope.launch(coroutineDispatchers.main) {
+ val updateKeysBackupVersionBody = withContext(coroutineDispatchers.crypto) {
+ val myUserId = credentials.userId
- uiHandler.post {
- callback.onFailure(IllegalArgumentException("Missing element"))
+ // Get current signatures, or create an empty set
+ val myUserSignatures = (authData.signatures!![myUserId]?.toMutableMap() ?: HashMap())
+
+ if (trust) {
+ // Add current device signature
+ val canonicalJson = MoshiProvider.getCanonicalJson(Map::class.java, authData.signalableJSONDictionary())
+
+ val deviceSignatures = objectSigner.signObject(canonicalJson)
+
+ deviceSignatures[myUserId]?.forEach { entry ->
+ myUserSignatures[entry.key] = entry.value
+ }
+ } else {
+ // Remove current device signature
+ myUserSignatures.remove("ed25519:${credentials.deviceId}")
+ }
+
+ // Create an updated version of KeysVersionResult
+ val updateKeysBackupVersionBody = UpdateKeysBackupVersionBody(keysBackupVersion.version!!)
+
+ updateKeysBackupVersionBody.algorithm = keysBackupVersion.algorithm
+
+ val newMegolmBackupAuthData = authData.copy()
+
+ val newSignatures = newMegolmBackupAuthData.signatures!!.toMutableMap()
+ newSignatures[myUserId] = myUserSignatures
+
+ newMegolmBackupAuthData.signatures = newSignatures
+
+ val moshi = MoshiProvider.providesMoshi()
+ val adapter = moshi.adapter(Map::class.java)
+
+ updateKeysBackupVersionBody.authData = adapter.fromJson(newMegolmBackupAuthData.toJsonString()) as Map?
+
+ updateKeysBackupVersionBody
}
- return@post
- }
+ // And send it to the homeserver
+ updateKeysBackupVersionTask
+ .configureWith(UpdateKeysBackupVersionTask.Params(keysBackupVersion.version!!, updateKeysBackupVersionBody))
+ .dispatchTo(object : MatrixCallback {
+ override fun onSuccess(data: Unit) {
+ // Relaunch the state machine on this updated backup version
+ val newKeysBackupVersion = KeysVersionResult()
- // Get current signatures, or create an empty set
- val myUserSignatures = (authData.signatures!![myUserId]?.toMutableMap() ?: HashMap())
+ newKeysBackupVersion.version = keysBackupVersion.version
+ newKeysBackupVersion.algorithm = keysBackupVersion.algorithm
+ newKeysBackupVersion.count = keysBackupVersion.count
+ newKeysBackupVersion.hash = keysBackupVersion.hash
+ newKeysBackupVersion.authData = updateKeysBackupVersionBody.authData
- if (trust) {
- // Add current device signature
- val canonicalJson = MoshiProvider.getCanonicalJson(Map::class.java, authData.signalableJSONDictionary())
+ checkAndStartWithKeysBackupVersion(newKeysBackupVersion)
- val deviceSignatures = objectSigner.signObject(canonicalJson)
-
- deviceSignatures[myUserId]?.forEach { entry ->
- myUserSignatures[entry.key] = entry.value
- }
- } else {
- // Remove current device signature
- myUserSignatures.remove("ed25519:${credentials.deviceId}")
- }
-
- // Create an updated version of KeysVersionResult
- val updateKeysBackupVersionBody = UpdateKeysBackupVersionBody(keysBackupVersion.version!!)
-
- updateKeysBackupVersionBody.algorithm = keysBackupVersion.algorithm
-
- val newMegolmBackupAuthData = authData.copy()
-
- val newSignatures = newMegolmBackupAuthData.signatures!!.toMutableMap()
- newSignatures[myUserId] = myUserSignatures
-
- newMegolmBackupAuthData.signatures = newSignatures
-
- val moshi = MoshiProvider.providesMoshi()
- val adapter = moshi.adapter(Map::class.java)
-
-
- updateKeysBackupVersionBody.authData = adapter.fromJson(newMegolmBackupAuthData.toJsonString()) as Map?
-
- // And send it to the homeserver
- updateKeysBackupVersionTask
- .configureWith(UpdateKeysBackupVersionTask.Params(keysBackupVersion.version!!, updateKeysBackupVersionBody))
- .dispatchTo(object : MatrixCallback {
- override fun onSuccess(data: Unit) {
- // Relaunch the state machine on this updated backup version
- val newKeysBackupVersion = KeysVersionResult()
-
- newKeysBackupVersion.version = keysBackupVersion.version
- newKeysBackupVersion.algorithm = keysBackupVersion.algorithm
- newKeysBackupVersion.count = keysBackupVersion.count
- newKeysBackupVersion.hash = keysBackupVersion.hash
- newKeysBackupVersion.authData = updateKeysBackupVersionBody.authData
-
- checkAndStartWithKeysBackupVersion(newKeysBackupVersion)
-
- uiHandler.post {
callback.onSuccess(data)
}
- }
- override fun onFailure(failure: Throwable) {
- uiHandler.post {
+ override fun onFailure(failure: Throwable) {
callback.onFailure(failure)
}
- }
- })
- .executeBy(taskExecutor)
+ })
+ .executeBy(taskExecutor)
+ }
}
}
@@ -513,17 +517,18 @@ internal class KeysBackup(
callback: MatrixCallback) {
Timber.v("trustKeysBackupVersionWithRecoveryKey: version ${keysBackupVersion.version}")
- CryptoAsyncHelper.getDecryptBackgroundHandler().post {
- if (!isValidRecoveryKeyForKeysBackupVersion(recoveryKey, keysBackupVersion)) {
- Timber.w("trustKeyBackupVersionWithRecoveryKey: Invalid recovery key.")
-
- uiHandler.post {
- callback.onFailure(IllegalArgumentException("Invalid recovery key or password"))
- }
- return@post
+ GlobalScope.launch(coroutineDispatchers.main) {
+ val isValid = withContext(coroutineDispatchers.crypto) {
+ isValidRecoveryKeyForKeysBackupVersion(recoveryKey, keysBackupVersion)
}
- trustKeysBackupVersion(keysBackupVersion, true, callback)
+ if (!isValid) {
+ Timber.w("trustKeyBackupVersionWithRecoveryKey: Invalid recovery key.")
+
+ callback.onFailure(IllegalArgumentException("Invalid recovery key or password"))
+ } else {
+ trustKeysBackupVersion(keysBackupVersion, true, callback)
+ }
}
}
@@ -532,21 +537,19 @@ internal class KeysBackup(
callback: MatrixCallback) {
Timber.v("trustKeysBackupVersionWithPassphrase: version ${keysBackupVersion.version}")
- CryptoAsyncHelper.getDecryptBackgroundHandler().post {
- val recoveryKey = recoveryKeyFromPassword(password, keysBackupVersion, null)
+ GlobalScope.launch(coroutineDispatchers.main) {
+ val recoveryKey = withContext(coroutineDispatchers.crypto) {
+ recoveryKeyFromPassword(password, keysBackupVersion, null)
+ }
if (recoveryKey == null) {
Timber.w("trustKeysBackupVersionWithPassphrase: Key backup is missing required data")
- uiHandler.post {
- callback.onFailure(IllegalArgumentException("Missing element"))
- }
-
- return@post
+ callback.onFailure(IllegalArgumentException("Missing element"))
+ } else {
+ // Check trust using the recovery key
+ trustKeysBackupVersionWithRecoveryKey(keysBackupVersion, recoveryKey, callback)
}
-
- // Check trust using the recovery key
- trustKeysBackupVersionWithRecoveryKey(keysBackupVersion, recoveryKey, callback)
}
}
@@ -591,12 +594,10 @@ internal class KeysBackup(
}
override fun getBackupProgress(progressListener: ProgressListener) {
- CryptoAsyncHelper.getDecryptBackgroundHandler().post {
- val backedUpKeys = cryptoStore.inboundGroupSessionsCount(true)
- val total = cryptoStore.inboundGroupSessionsCount(false)
+ val backedUpKeys = cryptoStore.inboundGroupSessionsCount(true)
+ val total = cryptoStore.inboundGroupSessionsCount(false)
- uiHandler.post { progressListener.onProgress(backedUpKeys, total) }
- }
+ progressListener.onProgress(backedUpKeys, total)
}
override fun restoreKeysWithRecoveryKey(keysVersionResult: KeysVersionResult,
@@ -607,88 +608,95 @@ internal class KeysBackup(
callback: MatrixCallback) {
Timber.v("restoreKeysWithRecoveryKey: From backup version: ${keysVersionResult.version}")
- CryptoAsyncHelper.getDecryptBackgroundHandler().post(Runnable {
- // Check if the recovery is valid before going any further
- if (!isValidRecoveryKeyForKeysBackupVersion(recoveryKey, keysVersionResult)) {
- Timber.e("restoreKeysWithRecoveryKey: Invalid recovery key for this keys version")
- uiHandler.post { callback.onFailure(InvalidParameterException("Invalid recovery key")) }
- return@Runnable
- }
-
- // Get a PK decryption instance
- val decryption = pkDecryptionFromRecoveryKey(recoveryKey)
- if (decryption == null) {
- // This should not happen anymore
- Timber.e("restoreKeysWithRecoveryKey: Invalid recovery key. Error")
- uiHandler.post { callback.onFailure(InvalidParameterException("Invalid recovery key")) }
- return@Runnable
- }
-
- if (stepProgressListener != null) {
- uiHandler.post { stepProgressListener.onStepProgress(StepProgressListener.Step.DownloadingKey) }
- }
-
- // Get backed up keys from the homeserver
- getKeys(sessionId, roomId, keysVersionResult.version!!, object : MatrixCallback {
- override fun onSuccess(data: KeysBackupData) {
- val sessionsData = ArrayList()
- // Restore that data
- var sessionsFromHsCount = 0
- for (roomIdLoop in data.roomIdToRoomKeysBackupData.keys) {
- for (sessionIdLoop in data.roomIdToRoomKeysBackupData[roomIdLoop]!!.sessionIdToKeyBackupData.keys) {
- sessionsFromHsCount++
-
- val keyBackupData = data.roomIdToRoomKeysBackupData[roomIdLoop]!!.sessionIdToKeyBackupData[sessionIdLoop]!!
-
- val sessionData = decryptKeyBackupData(keyBackupData, sessionIdLoop, roomIdLoop, decryption)
-
- sessionData?.let {
- sessionsData.add(it)
- }
- }
- }
- Timber.v("restoreKeysWithRecoveryKey: Decrypted " + sessionsData.size + " keys out of "
- + sessionsFromHsCount + " from the backup store on the homeserver")
-
- // Do not trigger a backup for them if they come from the backup version we are using
- val backUp = keysVersionResult.version != keysBackupVersion?.version
- if (backUp) {
- Timber.v("restoreKeysWithRecoveryKey: Those keys will be backed up to backup version: " + keysBackupVersion?.version)
+ GlobalScope.launch(coroutineDispatchers.main) {
+ withContext(coroutineDispatchers.crypto) {
+ Try {
+ // Check if the recovery is valid before going any further
+ if (!isValidRecoveryKeyForKeysBackupVersion(recoveryKey, keysVersionResult)) {
+ Timber.e("restoreKeysWithRecoveryKey: Invalid recovery key for this keys version")
+ throw InvalidParameterException("Invalid recovery key")
}
- // Import them into the crypto store
- val progressListener = if (stepProgressListener != null) {
- object : ProgressListener {
- override fun onProgress(progress: Int, total: Int) {
- // Note: no need to post to UI thread, importMegolmSessionsData() will do it
- stepProgressListener.onStepProgress(StepProgressListener.Step.ImportingKey(progress, total))
- }
- }
- } else {
- null
+ // Get a PK decryption instance
+ val decryption = pkDecryptionFromRecoveryKey(recoveryKey)
+ if (decryption == null) {
+ // This should not happen anymore
+ Timber.e("restoreKeysWithRecoveryKey: Invalid recovery key. Error")
+ throw InvalidParameterException("Invalid recovery key")
}
- megolmSessionDataImporter.handle(sessionsData, !backUp, progressListener, object : MatrixCallback {
- override fun onSuccess(data: ImportRoomKeysResult) {
- // Do not back up the key if it comes from a backup recovery
- if (backUp) {
- maybeBackupKeys()
- }
-
- callback.onSuccess(data)
- }
-
- override fun onFailure(failure: Throwable) {
- callback.onFailure(failure)
- }
- })
+ decryption!!
}
+ }.fold(
+ {
+ callback.onFailure(it)
+ },
+ { decryption ->
+ stepProgressListener?.onStepProgress(StepProgressListener.Step.DownloadingKey)
- override fun onFailure(failure: Throwable) {
- uiHandler.post { callback.onFailure(failure) }
- }
- })
- })
+ // Get backed up keys from the homeserver
+ getKeys(sessionId, roomId, keysVersionResult.version!!, object : MatrixCallback {
+ override fun onSuccess(data: KeysBackupData) {
+ GlobalScope.launch(coroutineDispatchers.main) {
+ val importRoomKeysResult = withContext(coroutineDispatchers.crypto) {
+ val sessionsData = ArrayList()
+ // Restore that data
+ var sessionsFromHsCount = 0
+ for (roomIdLoop in data.roomIdToRoomKeysBackupData.keys) {
+ for (sessionIdLoop in data.roomIdToRoomKeysBackupData[roomIdLoop]!!.sessionIdToKeyBackupData.keys) {
+ sessionsFromHsCount++
+
+ val keyBackupData = data.roomIdToRoomKeysBackupData[roomIdLoop]!!.sessionIdToKeyBackupData[sessionIdLoop]!!
+
+ val sessionData = decryptKeyBackupData(keyBackupData, sessionIdLoop, roomIdLoop, decryption)
+
+ sessionData?.let {
+ sessionsData.add(it)
+ }
+ }
+ }
+ Timber.v("restoreKeysWithRecoveryKey: Decrypted " + sessionsData.size + " keys out of "
+ + sessionsFromHsCount + " from the backup store on the homeserver")
+
+ // Do not trigger a backup for them if they come from the backup version we are using
+ val backUp = keysVersionResult.version != keysBackupVersion?.version
+ if (backUp) {
+ Timber.v("restoreKeysWithRecoveryKey: Those keys will be backed up to backup version: " + keysBackupVersion?.version)
+ }
+
+ // Import them into the crypto store
+ val progressListener = if (stepProgressListener != null) {
+ object : ProgressListener {
+ override fun onProgress(progress: Int, total: Int) {
+ // Note: no need to post to UI thread, importMegolmSessionsData() will do it
+ stepProgressListener.onStepProgress(StepProgressListener.Step.ImportingKey(progress, total))
+ }
+ }
+ } else {
+ null
+ }
+
+ val result = megolmSessionDataImporter.handle(sessionsData, !backUp, uiHandler, progressListener)
+
+ // Do not back up the key if it comes from a backup recovery
+ if (backUp) {
+ maybeBackupKeys()
+ }
+
+ result
+ }
+
+ callback.onSuccess(importRoomKeysResult)
+ }
+ }
+
+ override fun onFailure(failure: Throwable) {
+ callback.onFailure(failure)
+ }
+ })
+ }
+ )
+ }
}
override fun restoreKeyBackupWithPassword(keysBackupVersion: KeysVersionResult,
@@ -699,31 +707,36 @@ internal class KeysBackup(
callback: MatrixCallback) {
Timber.v("[MXKeyBackup] restoreKeyBackup with password: From backup version: ${keysBackupVersion.version}")
- CryptoAsyncHelper.getDecryptBackgroundHandler().post {
- val progressListener = if (stepProgressListener != null) {
- object : ProgressListener {
- override fun onProgress(progress: Int, total: Int) {
- uiHandler.post {
- stepProgressListener.onStepProgress(StepProgressListener.Step.ComputingKey(progress, total))
+ GlobalScope.launch(coroutineDispatchers.main) {
+ withContext(coroutineDispatchers.crypto) {
+ val progressListener = if (stepProgressListener != null) {
+ object : ProgressListener {
+ override fun onProgress(progress: Int, total: Int) {
+ uiHandler.post {
+ stepProgressListener.onStepProgress(StepProgressListener.Step.ComputingKey(progress, total))
+ }
}
}
- }
- } else {
- null
- }
-
- val recoveryKey = recoveryKeyFromPassword(password, keysBackupVersion, progressListener)
-
- if (recoveryKey == null) {
- uiHandler.post {
- Timber.v("backupKeys: Invalid configuration")
- callback.onFailure(IllegalStateException("Invalid configuration"))
+ } else {
+ null
}
- return@post
- }
-
- restoreKeysWithRecoveryKey(keysBackupVersion, recoveryKey, roomId, sessionId, stepProgressListener, callback)
+ Try {
+ recoveryKeyFromPassword(password, keysBackupVersion, progressListener)
+ }
+ }.fold(
+ {
+ callback.onFailure(it)
+ },
+ { recoveryKey ->
+ if (recoveryKey == null) {
+ Timber.v("backupKeys: Invalid configuration")
+ callback.onFailure(IllegalStateException("Invalid configuration"))
+ } else {
+ restoreKeysWithRecoveryKey(keysBackupVersion, recoveryKey, roomId, sessionId, stepProgressListener, callback)
+ }
+ }
+ )
}
}
@@ -989,9 +1002,9 @@ internal class KeysBackup(
}
}
- /* ==========================================================================================
- * Private
- * ========================================================================================== */
+/* ==========================================================================================
+ * Private
+ * ========================================================================================== */
/**
* Extract MegolmBackupAuthData data from a backup version.
@@ -1190,94 +1203,96 @@ internal class KeysBackup(
keysBackupStateManager.state = KeysBackupState.BackingUp
- CryptoAsyncHelper.getEncryptBackgroundHandler().post {
- Timber.v("backupKeys: 2 - Encrypting keys")
+ GlobalScope.launch(coroutineDispatchers.main) {
+ withContext(coroutineDispatchers.crypto) {
+ Timber.v("backupKeys: 2 - Encrypting keys")
- // Gather data to send to the homeserver
- // roomId -> sessionId -> MXKeyBackupData
- val keysBackupData = KeysBackupData()
- keysBackupData.roomIdToRoomKeysBackupData = HashMap()
+ // Gather data to send to the homeserver
+ // roomId -> sessionId -> MXKeyBackupData
+ val keysBackupData = KeysBackupData()
+ keysBackupData.roomIdToRoomKeysBackupData = HashMap()
- for (olmInboundGroupSessionWrapper in olmInboundGroupSessionWrappers) {
- val keyBackupData = encryptGroupSession(olmInboundGroupSessionWrapper)
- if (keysBackupData.roomIdToRoomKeysBackupData[olmInboundGroupSessionWrapper.roomId] == null) {
- val roomKeysBackupData = RoomKeysBackupData()
- roomKeysBackupData.sessionIdToKeyBackupData = HashMap()
- keysBackupData.roomIdToRoomKeysBackupData[olmInboundGroupSessionWrapper.roomId!!] = roomKeysBackupData
+ for (olmInboundGroupSessionWrapper in olmInboundGroupSessionWrappers) {
+ val keyBackupData = encryptGroupSession(olmInboundGroupSessionWrapper)
+ if (keysBackupData.roomIdToRoomKeysBackupData[olmInboundGroupSessionWrapper.roomId] == null) {
+ val roomKeysBackupData = RoomKeysBackupData()
+ roomKeysBackupData.sessionIdToKeyBackupData = HashMap()
+ keysBackupData.roomIdToRoomKeysBackupData[olmInboundGroupSessionWrapper.roomId!!] = roomKeysBackupData
+ }
+
+ try {
+ keysBackupData.roomIdToRoomKeysBackupData[olmInboundGroupSessionWrapper.roomId]!!.sessionIdToKeyBackupData[olmInboundGroupSessionWrapper.olmInboundGroupSession!!.sessionIdentifier()] = keyBackupData
+ } catch (e: OlmException) {
+ Timber.e(e, "OlmException")
+ }
}
- try {
- keysBackupData.roomIdToRoomKeysBackupData[olmInboundGroupSessionWrapper.roomId]!!.sessionIdToKeyBackupData[olmInboundGroupSessionWrapper.olmInboundGroupSession!!.sessionIdentifier()] = keyBackupData
- } catch (e: OlmException) {
- Timber.e(e, "OlmException")
- }
- }
+ Timber.v("backupKeys: 4 - Sending request")
- Timber.v("backupKeys: 4 - Sending request")
-
- // Make the request
- storeSessionDataTask
- .configureWith(StoreSessionsDataTask.Params(keysBackupVersion!!.version!!, keysBackupData))
- .dispatchTo(object : MatrixCallback {
- override fun onSuccess(data: BackupKeysResult) {
- uiHandler.post {
- Timber.v("backupKeys: 5a - Request complete")
-
- // Mark keys as backed up
- cryptoStore.markBackupDoneForInboundGroupSessions(olmInboundGroupSessionWrappers)
-
- if (olmInboundGroupSessionWrappers.size < KEY_BACKUP_SEND_KEYS_MAX_COUNT) {
- Timber.v("backupKeys: All keys have been backed up")
- onServerDataRetrieved(data.count, data.hash)
-
- // Note: Changing state will trigger the call to backupAllGroupSessionsCallback.onSuccess()
- keysBackupStateManager.state = KeysBackupState.ReadyToBackUp
- } else {
- Timber.v("backupKeys: Continue to back up keys")
- keysBackupStateManager.state = KeysBackupState.WillBackUp
-
- backupKeys()
- }
- }
- }
-
- override fun onFailure(failure: Throwable) {
- if (failure is Failure.ServerError) {
+ // Make the request
+ storeSessionDataTask
+ .configureWith(StoreSessionsDataTask.Params(keysBackupVersion!!.version!!, keysBackupData))
+ .dispatchTo(object : MatrixCallback {
+ override fun onSuccess(data: BackupKeysResult) {
uiHandler.post {
- Timber.e(failure, "backupKeys: backupKeys failed.")
+ Timber.v("backupKeys: 5a - Request complete")
- when (failure.error.code) {
- MatrixError.NOT_FOUND,
- MatrixError.WRONG_ROOM_KEYS_VERSION -> {
- // Backup has been deleted on the server, or we are not using the last backup version
- keysBackupStateManager.state = KeysBackupState.WrongBackUpVersion
- backupAllGroupSessionsCallback?.onFailure(failure)
- resetBackupAllGroupSessionsListeners()
- resetKeysBackupData()
- keysBackupVersion = null
+ // Mark keys as backed up
+ cryptoStore.markBackupDoneForInboundGroupSessions(olmInboundGroupSessionWrappers)
- // Do not stay in KeysBackupState.WrongBackUpVersion but check what is available on the homeserver
- checkAndStartKeysBackup()
- }
- else -> // Come back to the ready state so that we will retry on the next received key
- keysBackupStateManager.state = KeysBackupState.ReadyToBackUp
+ if (olmInboundGroupSessionWrappers.size < KEY_BACKUP_SEND_KEYS_MAX_COUNT) {
+ Timber.v("backupKeys: All keys have been backed up")
+ onServerDataRetrieved(data.count, data.hash)
+
+ // Note: Changing state will trigger the call to backupAllGroupSessionsCallback.onSuccess()
+ keysBackupStateManager.state = KeysBackupState.ReadyToBackUp
+ } else {
+ Timber.v("backupKeys: Continue to back up keys")
+ keysBackupStateManager.state = KeysBackupState.WillBackUp
+
+ backupKeys()
}
}
- } else {
- uiHandler.post {
- backupAllGroupSessionsCallback?.onFailure(failure)
- resetBackupAllGroupSessionsListeners()
+ }
- Timber.e("backupKeys: backupKeys failed.")
+ override fun onFailure(failure: Throwable) {
+ if (failure is Failure.ServerError) {
+ uiHandler.post {
+ Timber.e(failure, "backupKeys: backupKeys failed.")
- // Retry a bit later
- keysBackupStateManager.state = KeysBackupState.ReadyToBackUp
- maybeBackupKeys()
+ when (failure.error.code) {
+ MatrixError.NOT_FOUND,
+ MatrixError.WRONG_ROOM_KEYS_VERSION -> {
+ // Backup has been deleted on the server, or we are not using the last backup version
+ keysBackupStateManager.state = KeysBackupState.WrongBackUpVersion
+ backupAllGroupSessionsCallback?.onFailure(failure)
+ resetBackupAllGroupSessionsListeners()
+ resetKeysBackupData()
+ keysBackupVersion = null
+
+ // Do not stay in KeysBackupState.WrongBackUpVersion but check what is available on the homeserver
+ checkAndStartKeysBackup()
+ }
+ else -> // Come back to the ready state so that we will retry on the next received key
+ keysBackupStateManager.state = KeysBackupState.ReadyToBackUp
+ }
+ }
+ } else {
+ uiHandler.post {
+ backupAllGroupSessionsCallback?.onFailure(failure)
+ resetBackupAllGroupSessionsListeners()
+
+ Timber.e("backupKeys: backupKeys failed.")
+
+ // Retry a bit later
+ keysBackupStateManager.state = KeysBackupState.ReadyToBackUp
+ maybeBackupKeys()
+ }
}
}
- }
- })
- .executeBy(taskExecutor)
+ })
+ .executeBy(taskExecutor)
+ }
}
}
@@ -1376,9 +1391,9 @@ internal class KeysBackup(
private const val KEY_BACKUP_SEND_KEYS_MAX_COUNT = 100
}
- /* ==========================================================================================
- * DEBUG INFO
- * ========================================================================================== */
+/* ==========================================================================================
+ * DEBUG INFO
+ * ========================================================================================== */
override fun toString() = "KeysBackup for ${credentials.userId}"
}
diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/verification/DefaultSasVerificationService.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/verification/DefaultSasVerificationService.kt
index 81556052a7..a1595c10e8 100644
--- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/verification/DefaultSasVerificationService.kt
+++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/verification/DefaultSasVerificationService.kt
@@ -27,17 +27,12 @@ import im.vector.matrix.android.api.session.crypto.sas.safeValueOf
import im.vector.matrix.android.api.session.events.model.Event
import im.vector.matrix.android.api.session.events.model.EventType
import im.vector.matrix.android.api.session.events.model.toModel
-import im.vector.matrix.android.internal.crypto.CryptoAsyncHelper
import im.vector.matrix.android.internal.crypto.DeviceListManager
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.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.model.rest.*
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
@@ -138,8 +133,8 @@ internal class DefaultSasVerificationService(private val credentials: Credential
override fun markedLocallyAsManuallyVerified(userId: String, deviceID: String) {
setDeviceVerificationAction.handle(MXDeviceInfo.DEVICE_VERIFICATION_VERIFIED,
- deviceID,
- userId)
+ deviceID,
+ userId)
listeners.forEach {
try {
@@ -206,7 +201,7 @@ internal class DefaultSasVerificationService(private val credentials: Credential
} else {
Timber.e("## SAS onStartRequestReceived - unknown method ${startReq.method}")
cancelTransaction(tid, otherUserId, startReq.fromDevice
- ?: event.getSenderKey()!!, CancelCode.UnknownMethod)
+ ?: event.getSenderKey()!!, CancelCode.UnknownMethod)
}
}
},
@@ -372,9 +367,8 @@ internal class DefaultSasVerificationService(private val credentials: Credential
userId,
deviceID)
addTransaction(tx)
- CryptoAsyncHelper.getDecryptBackgroundHandler().post {
- tx.start()
- }
+
+ tx.start()
return txID
} else {
throw IllegalArgumentException("Unknown verification method")
@@ -399,9 +393,9 @@ internal class DefaultSasVerificationService(private val credentials: Credential
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)
diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/verification/IncomingSASVerificationTransaction.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/verification/IncomingSASVerificationTransaction.kt
index 1d40337b9f..2a4f0a1dde 100644
--- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/verification/IncomingSASVerificationTransaction.kt
+++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/verification/IncomingSASVerificationTransaction.kt
@@ -22,13 +22,12 @@ import im.vector.matrix.android.api.session.crypto.sas.IncomingSasVerificationTr
import im.vector.matrix.android.api.session.crypto.sas.SasMode
import im.vector.matrix.android.api.session.crypto.sas.SasVerificationTxState
import im.vector.matrix.android.api.session.events.model.EventType
-import im.vector.matrix.android.internal.crypto.CryptoAsyncHelper
import im.vector.matrix.android.internal.crypto.actions.SetDeviceVerificationAction
-import im.vector.matrix.android.internal.crypto.store.IMXCryptoStore
import im.vector.matrix.android.internal.crypto.model.rest.KeyVerificationAccept
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.di.MoshiProvider
import im.vector.matrix.android.internal.task.TaskExecutor
@@ -61,21 +60,21 @@ internal class IncomingSASVerificationTransaction(
override val uxState: IncomingSasVerificationTransaction.UxState
get() {
return when (state) {
- SasVerificationTxState.OnStarted -> IncomingSasVerificationTransaction.UxState.SHOW_ACCEPT
+ SasVerificationTxState.OnStarted -> IncomingSasVerificationTransaction.UxState.SHOW_ACCEPT
SasVerificationTxState.SendingAccept,
SasVerificationTxState.Accepted,
SasVerificationTxState.OnKeyReceived,
SasVerificationTxState.SendingKey,
- SasVerificationTxState.KeySent -> IncomingSasVerificationTransaction.UxState.WAIT_FOR_KEY_AGREEMENT
+ SasVerificationTxState.KeySent -> IncomingSasVerificationTransaction.UxState.WAIT_FOR_KEY_AGREEMENT
SasVerificationTxState.ShortCodeReady -> IncomingSasVerificationTransaction.UxState.SHOW_SAS
SasVerificationTxState.ShortCodeAccepted,
SasVerificationTxState.SendingMac,
SasVerificationTxState.MacSent,
- SasVerificationTxState.Verifying -> IncomingSasVerificationTransaction.UxState.WAIT_FOR_VERIFICATION
- SasVerificationTxState.Verified -> IncomingSasVerificationTransaction.UxState.VERIFIED
- SasVerificationTxState.Cancelled -> IncomingSasVerificationTransaction.UxState.CANCELLED_BY_ME
- SasVerificationTxState.OnCancelled -> IncomingSasVerificationTransaction.UxState.CANCELLED_BY_OTHER
- else -> IncomingSasVerificationTransaction.UxState.UNKNOWN
+ SasVerificationTxState.Verifying -> IncomingSasVerificationTransaction.UxState.WAIT_FOR_VERIFICATION
+ SasVerificationTxState.Verified -> IncomingSasVerificationTransaction.UxState.VERIFIED
+ SasVerificationTxState.Cancelled -> IncomingSasVerificationTransaction.UxState.CANCELLED_BY_ME
+ SasVerificationTxState.OnCancelled -> IncomingSasVerificationTransaction.UxState.CANCELLED_BY_OTHER
+ else -> IncomingSasVerificationTransaction.UxState.UNKNOWN
}
}
@@ -125,9 +124,7 @@ internal class IncomingSASVerificationTransaction(
//TODO force download keys!!
//would be probably better to download the keys
//for now I cancel
- CryptoAsyncHelper.getDecryptBackgroundHandler().post {
- cancel(CancelCode.User)
- }
+ cancel(CancelCode.User)
} else {
// val otherKey = info.identityKey()
//need to jump back to correct thread
@@ -139,9 +136,7 @@ internal class IncomingSASVerificationTransaction(
shortAuthenticationStrings = agreedShortCode,
commitment = Base64.encodeToString("temporary commitment".toByteArray(), Base64.DEFAULT)
)
- CryptoAsyncHelper.getDecryptBackgroundHandler().post {
- doAccept(accept)
- }
+ doAccept(accept)
}
}
diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/verification/OutgoingSASVerificationRequest.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/verification/OutgoingSASVerificationRequest.kt
index aa18133f05..2210c25abd 100644
--- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/verification/OutgoingSASVerificationRequest.kt
+++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/verification/OutgoingSASVerificationRequest.kt
@@ -86,7 +86,6 @@ internal class OutgoingSASVerificationRequest(
}
fun start() {
-
if (state != SasVerificationTxState.None) {
Timber.e("## start verification from invalid state")
//should I cancel??
diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/verification/SASVerificationTransaction.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/verification/SASVerificationTransaction.kt
index 858c48b4e6..5390c5ed3c 100644
--- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/verification/SASVerificationTransaction.kt
+++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/verification/SASVerificationTransaction.kt
@@ -23,7 +23,6 @@ import im.vector.matrix.android.api.session.crypto.sas.EmojiRepresentation
import im.vector.matrix.android.api.session.crypto.sas.SasMode
import im.vector.matrix.android.api.session.crypto.sas.SasVerificationTxState
import im.vector.matrix.android.api.session.events.model.EventType
-import im.vector.matrix.android.internal.crypto.CryptoAsyncHelper
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.MXKey
@@ -31,6 +30,7 @@ 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.store.IMXCryptoStore
import im.vector.matrix.android.internal.crypto.tasks.SendToDeviceTask
+import im.vector.matrix.android.internal.extensions.toUnsignedInt
import im.vector.matrix.android.internal.task.TaskExecutor
import im.vector.matrix.android.internal.task.configureWith
import org.matrix.olm.OlmSAS
@@ -278,21 +278,17 @@ internal abstract class SASVerificationTransaction(
.dispatchTo(object : MatrixCallback {
override fun onSuccess(data: Unit) {
Timber.v("## SAS verification [$transactionId] toDevice type '$type' success.")
- CryptoAsyncHelper.getDecryptBackgroundHandler().post {
- if (onDone != null) {
- onDone()
- } else {
- state = nextState
- }
+ if (onDone != null) {
+ onDone()
+ } else {
+ state = nextState
}
}
override fun onFailure(failure: Throwable) {
Timber.e("## SAS verification [$transactionId] failed to send toDevice in state : $state")
- CryptoAsyncHelper.getDecryptBackgroundHandler().post {
- cancel(onErrorReason)
- }
+ cancel(onErrorReason)
}
})
.executeBy(taskExecutor)
@@ -359,11 +355,11 @@ internal abstract class SASVerificationTransaction(
* or with the three numbers on separate lines.
*/
fun getDecimalCodeRepresentation(byteArray: ByteArray): String {
- val b0 = byteArray[0].toInt().and(0xff) //need unsigned byte
- val b1 = byteArray[1].toInt().and(0xff) //need unsigned byte
- val b2 = byteArray[2].toInt().and(0xff) //need unsigned byte
- val b3 = byteArray[3].toInt().and(0xff) //need unsigned byte
- val b4 = byteArray[4].toInt().and(0xff) //need unsigned byte
+ val b0 = byteArray[0].toUnsignedInt() //need unsigned byte
+ val b1 = byteArray[1].toUnsignedInt() //need unsigned byte
+ val b2 = byteArray[2].toUnsignedInt() //need unsigned byte
+ val b3 = byteArray[3].toUnsignedInt() //need unsigned byte
+ val b4 = byteArray[4].toUnsignedInt() //need unsigned byte
//(B0 << 5 | B1 >> 3) + 1000
val first = (b0.shl(5) or b1.shr(3)) + 1000
//((B1 & 0x7) << 10 | B2 << 2 | B3 >> 6) + 1000
@@ -384,12 +380,12 @@ internal abstract class SASVerificationTransaction(
* to that number 7 emoji are selected from a list of 64 emoji (see Appendix A)
*/
fun getEmojiCodeRepresentation(byteArray: ByteArray): List {
- val b0 = byteArray[0].toInt().and(0xff)
- val b1 = byteArray[1].toInt().and(0xff)
- val b2 = byteArray[2].toInt().and(0xff)
- val b3 = byteArray[3].toInt().and(0xff)
- val b4 = byteArray[4].toInt().and(0xff)
- val b5 = byteArray[5].toInt().and(0xff)
+ val b0 = byteArray[0].toUnsignedInt()
+ val b1 = byteArray[1].toUnsignedInt()
+ val b2 = byteArray[2].toUnsignedInt()
+ val b3 = byteArray[3].toUnsignedInt()
+ val b4 = byteArray[4].toUnsignedInt()
+ val b5 = byteArray[5].toUnsignedInt()
return listOf(
getEmojiForCode((b0 and 0xFC).shr(2)),
getEmojiForCode((b0 and 0x3).shl(4) or (b1 and 0xF0).shr(4)),
diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/di/MatrixModule.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/di/MatrixModule.kt
index 8f9447c6c0..84f6786b05 100644
--- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/di/MatrixModule.kt
+++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/di/MatrixModule.kt
@@ -17,7 +17,8 @@
package im.vector.matrix.android.internal.di
import android.content.Context
-import im.vector.matrix.android.internal.crypto.CryptoAsyncHelper
+import android.os.Handler
+import android.os.HandlerThread
import im.vector.matrix.android.internal.task.TaskExecutor
import im.vector.matrix.android.internal.util.BackgroundDetectionObserver
import im.vector.matrix.android.internal.util.MatrixCoroutineDispatchers
@@ -36,11 +37,14 @@ class MatrixModule(private val context: Context) {
}
single {
- val cryptoHandler = CryptoAsyncHelper.getDecryptBackgroundHandler()
+ val THREAD_CRYPTO_NAME = "Crypto_Thread"
+ val handlerThread = HandlerThread(THREAD_CRYPTO_NAME)
+ handlerThread.start()
+
MatrixCoroutineDispatchers(io = Dispatchers.IO,
computation = Dispatchers.IO,
main = Dispatchers.Main,
- crypto = cryptoHandler.asCoroutineDispatcher("crypto")
+ crypto = Handler(handlerThread.looper).asCoroutineDispatcher("crypto")
)
}
diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/extensions/Primitives.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/extensions/Primitives.kt
new file mode 100644
index 0000000000..0a0ca1a1bd
--- /dev/null
+++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/extensions/Primitives.kt
@@ -0,0 +1,22 @@
+/*
+ * Copyright 2019 New Vector Ltd
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package im.vector.matrix.android.internal.extensions
+
+/**
+ * Convert a signed byte to a int value
+ */
+fun Byte.toUnsignedInt() = toInt() and 0xff
diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/extensions/Try.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/extensions/Try.kt
new file mode 100644
index 0000000000..18ab0e4735
--- /dev/null
+++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/extensions/Try.kt
@@ -0,0 +1,33 @@
+/*
+ * Copyright 2019 New Vector Ltd
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package im.vector.matrix.android.internal.extensions
+
+import arrow.core.*
+import im.vector.matrix.android.api.MatrixCallback
+
+inline fun TryOf.onError(f: (Throwable) -> Unit): Try = fix()
+ .fold(
+ {
+ f(it)
+ Failure(it)
+ },
+ { Success(it) }
+ )
+
+fun Try.foldToCallback(callback: MatrixCallback): Unit = fold(
+ { callback.onFailure(it) },
+ { callback.onSuccess(it) })
diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/task/TaskExecutor.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/task/TaskExecutor.kt
index 986fe81bee..263c381d33 100644
--- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/task/TaskExecutor.kt
+++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/task/TaskExecutor.kt
@@ -18,6 +18,8 @@ package im.vector.matrix.android.internal.task
import arrow.core.Try
import im.vector.matrix.android.api.util.Cancelable
+import im.vector.matrix.android.internal.extensions.foldToCallback
+import im.vector.matrix.android.internal.extensions.onError
import im.vector.matrix.android.internal.util.CancelableCoroutine
import im.vector.matrix.android.internal.util.MatrixCoroutineDispatchers
import kotlinx.coroutines.GlobalScope
@@ -38,12 +40,10 @@ internal class TaskExecutor(private val coroutineDispatchers: MatrixCoroutineDis
task.execute(task.params)
}
}
- resultOrFailure.fold({
+ resultOrFailure.onError {
Timber.d(it, "Task failed")
- task.callback.onFailure(it)
- }, {
- task.callback.onSuccess(it)
- })
+ }
+ .foldToCallback(task.callback)
}
return CancelableCoroutine(job)
}
diff --git a/vector/src/main/java/im/vector/riotredesign/core/dialogs/ExportKeysDialog.kt b/vector/src/main/java/im/vector/riotredesign/core/dialogs/ExportKeysDialog.kt
index 90c12de42b..22ec2f906b 100644
--- a/vector/src/main/java/im/vector/riotredesign/core/dialogs/ExportKeysDialog.kt
+++ b/vector/src/main/java/im/vector/riotredesign/core/dialogs/ExportKeysDialog.kt
@@ -19,34 +19,30 @@ package im.vector.riotredesign.core.dialogs
import android.app.Activity
import android.text.Editable
import android.text.TextUtils
-import android.text.TextWatcher
import android.widget.Button
+import android.widget.ImageView
import androidx.appcompat.app.AlertDialog
import com.google.android.material.textfield.TextInputEditText
import com.google.android.material.textfield.TextInputLayout
import im.vector.riotredesign.R
+import im.vector.riotredesign.core.extensions.showPassword
+import im.vector.riotredesign.core.platform.SimpleTextWatcher
class ExportKeysDialog {
+ var passwordVisible = false
+
fun show(activity: Activity, exportKeyDialogListener: ExportKeyDialogListener) {
val dialogLayout = activity.layoutInflater.inflate(R.layout.dialog_export_e2e_keys, null)
val builder = AlertDialog.Builder(activity)
.setTitle(R.string.encryption_export_room_keys)
.setView(dialogLayout)
- val passPhrase1EditText = dialogLayout.findViewById(R.id.dialog_e2e_keys_passphrase_edit_text)
- val passPhrase2EditText = dialogLayout.findViewById(R.id.dialog_e2e_keys_confirm_passphrase_edit_text)
- val passPhrase2Til = dialogLayout.findViewById(R.id.dialog_e2e_keys_confirm_passphrase_til)
- val exportButton = dialogLayout.findViewById