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 5390c5ed..c0342c00 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 @@ -223,13 +223,17 @@ internal abstract class SASVerificationTransaction( cancel(CancelCode.MismatchedKeys) return } + + val verifiedDevices = ArrayList() + //cannot be empty because it has been validated theirMac!!.mac!!.keys.forEach { val keyIDNoPrefix = if (it.startsWith("ed25519:")) it.substring("ed25519:".length) else it val otherDeviceKey = otherUserKnownDevices?.get(keyIDNoPrefix)?.fingerprint() if (otherDeviceKey == null) { - cancel(CancelCode.MismatchedKeys) - return + Timber.e("Verification: Could not find device $keyIDNoPrefix to verify") + //just ignore and continue + return@forEach } val mac = macUsingAgreedMethod(otherDeviceKey, baseInfo + it) if (mac != theirMac?.mac?.get(it)) { @@ -237,13 +241,21 @@ internal abstract class SASVerificationTransaction( cancel(CancelCode.MismatchedKeys) return } + verifiedDevices.add(keyIDNoPrefix) } - setDeviceVerified( - otherDeviceId ?: "", - otherUserId) + // if none of the keys could be verified, then error because the app + // should be informed about that + if (verifiedDevices.isEmpty()) { + Timber.e("Verification: No devices verified") + cancel(CancelCode.MismatchedKeys) + return + } - state = SasVerificationTxState.Verified + //TODO what if the otherDevice is not in this list? and should we + verifiedDevices.forEach { + setDeviceVerified(it, otherUserId) + } } private fun setDeviceVerified(deviceId: String, userId: String) { diff --git a/vector/src/main/java/im/vector/riotredesign/features/crypto/keysbackup/setup/KeysBackupSetupActivity.kt b/vector/src/main/java/im/vector/riotredesign/features/crypto/keysbackup/setup/KeysBackupSetupActivity.kt index a109f66f..fb0056bc 100644 --- a/vector/src/main/java/im/vector/riotredesign/features/crypto/keysbackup/setup/KeysBackupSetupActivity.kt +++ b/vector/src/main/java/im/vector/riotredesign/features/crypto/keysbackup/setup/KeysBackupSetupActivity.kt @@ -22,7 +22,6 @@ import androidx.core.view.isVisible import androidx.fragment.app.FragmentManager import androidx.lifecycle.Observer import androidx.lifecycle.ViewModelProviders -import im.vector.fragments.keysbackup.setup.KeysBackupSetupSharedViewModel import im.vector.matrix.android.api.MatrixCallback import im.vector.riotredesign.R import im.vector.riotredesign.core.dialogs.ExportKeysDialog @@ -67,19 +66,19 @@ class KeysBackupSetupActivity : SimpleFragmentActivity() { viewModel.navigateEvent.observeEvent(this) { uxStateEvent -> when (uxStateEvent) { - KeysBackupSetupSharedViewModel.NAVIGATE_TO_STEP_2 -> { + KeysBackupSetupSharedViewModel.NAVIGATE_TO_STEP_2 -> { supportFragmentManager.popBackStack(null, FragmentManager.POP_BACK_STACK_INCLUSIVE) supportFragmentManager.beginTransaction() .replace(R.id.container, KeysBackupSetupStep2Fragment.newInstance()) .commit() } - KeysBackupSetupSharedViewModel.NAVIGATE_TO_STEP_3 -> { + KeysBackupSetupSharedViewModel.NAVIGATE_TO_STEP_3 -> { supportFragmentManager.popBackStack(null, FragmentManager.POP_BACK_STACK_INCLUSIVE) supportFragmentManager.beginTransaction() .replace(R.id.container, KeysBackupSetupStep3Fragment.newInstance()) .commit() } - KeysBackupSetupSharedViewModel.NAVIGATE_FINISH -> { + KeysBackupSetupSharedViewModel.NAVIGATE_FINISH -> { val resultIntent = Intent() viewModel.keysVersion.value?.version?.let { resultIntent.putExtra(KEYS_VERSION, it) @@ -87,7 +86,18 @@ class KeysBackupSetupActivity : SimpleFragmentActivity() { setResult(RESULT_OK, resultIntent) finish() } - KeysBackupSetupSharedViewModel.NAVIGATE_MANUAL_EXPORT -> { + KeysBackupSetupSharedViewModel.NAVIGATE_PROMPT_REPLACE -> { + AlertDialog.Builder(this) + .setTitle(R.string.keys_backup_setup_override_backup_prompt_tile) + .setMessage(R.string.keys_backup_setup_override_backup_prompt_description) + .setPositiveButton(R.string.keys_backup_setup_override_replace) { _, _ -> + viewModel.forceCreateKeyBackup(this) + }.setNegativeButton(R.string.keys_backup_setup_override_stop) { _, _ -> + viewModel.stopAndKeepAfterDetectingExistingOnServer() + } + .show() + } + KeysBackupSetupSharedViewModel.NAVIGATE_MANUAL_EXPORT -> { exportKeysManually() } } diff --git a/vector/src/main/java/im/vector/riotredesign/features/crypto/keysbackup/setup/KeysBackupSetupSharedViewModel.kt b/vector/src/main/java/im/vector/riotredesign/features/crypto/keysbackup/setup/KeysBackupSetupSharedViewModel.kt index c9d11d16..eaf534f0 100644 --- a/vector/src/main/java/im/vector/riotredesign/features/crypto/keysbackup/setup/KeysBackupSetupSharedViewModel.kt +++ b/vector/src/main/java/im/vector/riotredesign/features/crypto/keysbackup/setup/KeysBackupSetupSharedViewModel.kt @@ -14,7 +14,7 @@ * limitations under the License. */ -package im.vector.fragments.keysbackup.setup +package im.vector.riotredesign.features.crypto.keysbackup.setup import android.content.Context import androidx.lifecycle.MutableLiveData @@ -26,6 +26,7 @@ import im.vector.matrix.android.api.session.Session import im.vector.matrix.android.api.session.crypto.keysbackup.KeysBackupService import im.vector.matrix.android.internal.crypto.keysbackup.model.MegolmBackupCreationInfo import im.vector.matrix.android.internal.crypto.keysbackup.model.rest.KeysVersion +import im.vector.matrix.android.internal.crypto.keysbackup.model.rest.KeysVersionResult import im.vector.riotredesign.R import im.vector.riotredesign.core.platform.WaitingViewData import im.vector.riotredesign.core.utils.LiveEvent @@ -39,6 +40,7 @@ class KeysBackupSetupSharedViewModel : ViewModel() { companion object { const val NAVIGATE_TO_STEP_2 = "NAVIGATE_TO_STEP_2" const val NAVIGATE_TO_STEP_3 = "NAVIGATE_TO_STEP_3" + const val NAVIGATE_PROMPT_REPLACE = "NAVIGATE_PROMPT_REPLACE" const val NAVIGATE_FINISH = "NAVIGATE_FINISH" const val NAVIGATE_MANUAL_EXPORT = "NAVIGATE_MANUAL_EXPORT" } @@ -123,15 +125,8 @@ class KeysBackupSetupSharedViewModel : ViewModel() { megolmBackupCreationInfo = data copyHasBeenMade = false - val keyBackup = session?.getKeysBackupService() - if (keyBackup != null) { - createKeysBackup(context, keyBackup) - } else { - loadingStatus.value = null - - isCreatingBackupVersion.value = false - prepareRecoverFailError.value = Exception() - } + val keyBackup = session.getKeysBackupService() + createKeysBackup(context, keyBackup) } override fun onFailure(failure: Throwable) { @@ -149,18 +144,32 @@ class KeysBackupSetupSharedViewModel : ViewModel() { } } - private fun createKeysBackup(context: Context, keysBackup: KeysBackupService) { + fun forceCreateKeyBackup(context: Context) { + val keyBackup = session.getKeysBackupService() + createKeysBackup(context, keyBackup, true) + } + + fun stopAndKeepAfterDetectingExistingOnServer() { + loadingStatus.value = null + navigateEvent.value = LiveEvent(NAVIGATE_FINISH) + session.getKeysBackupService().checkAndStartKeysBackup() + } + + private fun createKeysBackup(context: Context, keysBackup: KeysBackupService, forceOverride: Boolean = false) { loadingStatus.value = WaitingViewData(context.getString(R.string.keys_backup_setup_creating_backup), isIndeterminate = true) creatingBackupError.value = null - keysBackup.createKeysBackupVersion(megolmBackupCreationInfo!!, object : MatrixCallback { - override fun onSuccess(data: KeysVersion) { - loadingStatus.value = null - - isCreatingBackupVersion.value = false - keysVersion.value = data - navigateEvent.value = LiveEvent(NAVIGATE_TO_STEP_3) + keysBackup.getCurrentVersion(object : MatrixCallback { + override fun onSuccess(data: KeysVersionResult?) { + if (data?.version.isNullOrBlank() || forceOverride) { + processOnCreate() + } else { + loadingStatus.value = null + // we should prompt + isCreatingBackupVersion.value = false + navigateEvent.value = LiveEvent(NAVIGATE_PROMPT_REPLACE) + } } override fun onFailure(failure: Throwable) { @@ -170,7 +179,26 @@ class KeysBackupSetupSharedViewModel : ViewModel() { isCreatingBackupVersion.value = false creatingBackupError.value = failure } + + fun processOnCreate() { + keysBackup.createKeysBackupVersion(megolmBackupCreationInfo!!, object : MatrixCallback { + override fun onSuccess(data: KeysVersion) { + loadingStatus.value = null + + isCreatingBackupVersion.value = false + keysVersion.value = data + navigateEvent.value = LiveEvent(NAVIGATE_TO_STEP_3) + } + + override fun onFailure(failure: Throwable) { + Timber.e(failure, "## createKeyBackupVersion") + loadingStatus.value = null + + isCreatingBackupVersion.value = false + creatingBackupError.value = failure + } + }) + } }) } - } \ No newline at end of file diff --git a/vector/src/main/java/im/vector/riotredesign/features/crypto/keysbackup/setup/KeysBackupSetupStep1Fragment.kt b/vector/src/main/java/im/vector/riotredesign/features/crypto/keysbackup/setup/KeysBackupSetupStep1Fragment.kt index 0fccd510..574c5dd7 100644 --- a/vector/src/main/java/im/vector/riotredesign/features/crypto/keysbackup/setup/KeysBackupSetupStep1Fragment.kt +++ b/vector/src/main/java/im/vector/riotredesign/features/crypto/keysbackup/setup/KeysBackupSetupStep1Fragment.kt @@ -24,7 +24,6 @@ import androidx.lifecycle.Observer import androidx.lifecycle.ViewModelProviders import butterknife.BindView import butterknife.OnClick -import im.vector.fragments.keysbackup.setup.KeysBackupSetupSharedViewModel import im.vector.riotredesign.R import im.vector.riotredesign.core.platform.VectorBaseFragment import im.vector.riotredesign.core.utils.LiveEvent diff --git a/vector/src/main/java/im/vector/riotredesign/features/crypto/keysbackup/setup/KeysBackupSetupStep2Fragment.kt b/vector/src/main/java/im/vector/riotredesign/features/crypto/keysbackup/setup/KeysBackupSetupStep2Fragment.kt index 47ade276..df708dc0 100644 --- a/vector/src/main/java/im/vector/riotredesign/features/crypto/keysbackup/setup/KeysBackupSetupStep2Fragment.kt +++ b/vector/src/main/java/im/vector/riotredesign/features/crypto/keysbackup/setup/KeysBackupSetupStep2Fragment.kt @@ -30,7 +30,6 @@ import butterknife.OnClick import butterknife.OnTextChanged import com.google.android.material.textfield.TextInputLayout import com.nulabinc.zxcvbn.Zxcvbn -import im.vector.fragments.keysbackup.setup.KeysBackupSetupSharedViewModel import im.vector.riotredesign.R import im.vector.riotredesign.core.extensions.showPassword import im.vector.riotredesign.core.platform.VectorBaseFragment diff --git a/vector/src/main/java/im/vector/riotredesign/features/crypto/keysbackup/setup/KeysBackupSetupStep3Fragment.kt b/vector/src/main/java/im/vector/riotredesign/features/crypto/keysbackup/setup/KeysBackupSetupStep3Fragment.kt index 2a18a9d6..eaa4da21 100644 --- a/vector/src/main/java/im/vector/riotredesign/features/crypto/keysbackup/setup/KeysBackupSetupStep3Fragment.kt +++ b/vector/src/main/java/im/vector/riotredesign/features/crypto/keysbackup/setup/KeysBackupSetupStep3Fragment.kt @@ -29,7 +29,6 @@ import arrow.core.Try import butterknife.BindView import butterknife.OnClick import com.google.android.material.bottomsheet.BottomSheetDialog -import im.vector.fragments.keysbackup.setup.KeysBackupSetupSharedViewModel import im.vector.riotredesign.R import im.vector.riotredesign.core.files.addEntryToDownloadManager import im.vector.riotredesign.core.files.writeToFile diff --git a/vector/src/main/java/im/vector/riotredesign/features/home/HomeActivity.kt b/vector/src/main/java/im/vector/riotredesign/features/home/HomeActivity.kt index c507224d..ffe59919 100644 --- a/vector/src/main/java/im/vector/riotredesign/features/home/HomeActivity.kt +++ b/vector/src/main/java/im/vector/riotredesign/features/home/HomeActivity.kt @@ -46,6 +46,8 @@ import kotlinx.android.synthetic.main.activity_home.* import org.koin.android.ext.android.inject import org.koin.android.scope.ext.android.bindScope import org.koin.android.scope.ext.android.getOrCreateScope +import im.vector.riotredesign.features.workers.signout.SignOutViewModel + class HomeActivity : VectorBaseActivity(), ToolbarConfigurable { @@ -130,6 +132,9 @@ class HomeActivity : VectorBaseActivity(), ToolbarConfigurable { .setNegativeButton(R.string.no) { _, _ -> BugReporter.deleteCrashFile(this) } .show() } + + //Force remote backup state update to update the banner if needed + ViewModelProviders.of(this).get(SignOutViewModel::class.java).refreshRemoteStateIfNeeded() } override fun configure(toolbar: Toolbar) { diff --git a/vector/src/main/java/im/vector/riotredesign/features/workers/signout/SignOutViewModel.kt b/vector/src/main/java/im/vector/riotredesign/features/workers/signout/SignOutViewModel.kt index ea3989ee..a56681ce 100644 --- a/vector/src/main/java/im/vector/riotredesign/features/workers/signout/SignOutViewModel.kt +++ b/vector/src/main/java/im/vector/riotredesign/features/workers/signout/SignOutViewModel.kt @@ -81,6 +81,12 @@ class SignOutViewModel : ViewModel(), KeysBackupStateListener { keysBackupState.value = newState } + fun refreshRemoteStateIfNeeded() { + if (keysBackupState.value == KeysBackupState.Disabled) { + mxSession?.getKeysBackupService()?.checkAndStartKeysBackup() + } + } + companion object { /** * The backup check on logout flow has to be displayed if there are keys in the store, and the keys backup state is not Ready