From 5f0d1d9536b55207fa3993ed7ae38624b27cda3e Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Thu, 13 Jun 2019 19:08:51 +0200 Subject: [PATCH 1/7] Crypto: export room keys --- .../im/vector/matrix/android/api/util/Try.kt | 30 -------- .../android/internal/crypto/CryptoManager.kt | 55 +++++++------ .../internal/crypto/DeviceListManager.kt | 2 +- .../matrix/android/internal/extensions/Try.kt | 33 ++++++++ .../core/dialogs/ExportKeysDialog.kt | 32 ++++---- .../features/crypto/keys/KeysExporter.kt | 77 +++++++++++++++++++ .../setup/KeysBackupSetupActivity.kt | 60 +++++++-------- .../VectorSettingsPreferencesFragment.kt | 48 +++++------- .../res/layout/dialog_export_e2e_keys.xml | 53 +++++++++---- 9 files changed, 240 insertions(+), 150 deletions(-) delete mode 100644 matrix-sdk-android/src/main/java/im/vector/matrix/android/api/util/Try.kt create mode 100644 matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/extensions/Try.kt create mode 100644 vector/src/main/java/im/vector/riotredesign/features/crypto/keys/KeysExporter.kt 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 365d5472..00000000 --- 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/crypto/CryptoManager.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/CryptoManager.kt index 5e422571..6c46a5b9 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 @@ -64,6 +64,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 @@ -560,10 +561,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))) } } } @@ -700,7 +701,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 +788,32 @@ 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,6 +828,7 @@ internal class CryptoManager( password: String, progressListener: ProgressListener?, callback: MatrixCallback) { + // TODO Use coroutines Timber.v("## importRoomKeys starts") val t0 = System.currentTimeMillis() @@ -898,7 +897,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))) } } ) 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 2217a796..ffda9507 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/extensions/Try.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/extensions/Try.kt new file mode 100644 index 00000000..18ab0e47 --- /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/vector/src/main/java/im/vector/riotredesign/core/dialogs/ExportKeysDialog.kt b/vector/src/main/java/im/vector/riotredesign/core/dialogs/ExportKeysDialog.kt index 90c12de4..22ec2f90 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