Skip to content

Commit

Permalink
Merge pull request #8578 from vector-im/feature/bma/crashFixes
Browse files Browse the repository at this point in the history
Crash fixes
  • Loading branch information
bmarty committed Jul 17, 2023
2 parents 1359659 + ae52d4c commit 180a2ee
Show file tree
Hide file tree
Showing 9 changed files with 159 additions and 28 deletions.
Expand Up @@ -19,6 +19,7 @@ package org.matrix.android.sdk.internal.session.sync.handler
import androidx.work.BackoffPolicy
import androidx.work.ExistingWorkPolicy
import org.matrix.android.sdk.api.MatrixPatterns
import org.matrix.android.sdk.api.extensions.tryOrNull
import org.matrix.android.sdk.internal.crypto.crosssigning.UpdateTrustWorker
import org.matrix.android.sdk.internal.crypto.crosssigning.UpdateTrustWorkerDataRepository
import org.matrix.android.sdk.internal.di.SessionId
Expand Down Expand Up @@ -81,7 +82,9 @@ internal class SyncResponsePostTreatmentAggregatorHandler @Inject constructor(
}
}
if (hasUpdate) {
updateUserAccountDataTask.execute(UpdateUserAccountDataTask.DirectChatParams(directMessages = directChats))
tryOrNull("Unable to update user account data") {
updateUserAccountDataTask.execute(UpdateUserAccountDataTask.DirectChatParams(directMessages = directChats))
}
}
}

Expand Down
Expand Up @@ -20,6 +20,7 @@ import com.zhuinden.monarchy.Monarchy
import io.realm.Realm
import io.realm.RealmList
import io.realm.kotlin.where
import org.matrix.android.sdk.api.extensions.tryOrNull
import org.matrix.android.sdk.api.failure.GlobalError
import org.matrix.android.sdk.api.failure.InitialSyncRequestReason
import org.matrix.android.sdk.api.session.accountdata.UserAccountDataEvent
Expand Down Expand Up @@ -122,7 +123,7 @@ internal class UserAccountDataSyncHandler @Inject constructor(
val updateUserAccountParams = UpdateUserAccountDataTask.DirectChatParams(
directMessages = directChats
)
updateUserAccountDataTask.execute(updateUserAccountParams)
tryOrNull("Unable to update user account data") { updateUserAccountDataTask.execute(updateUserAccountParams) }
}
}

Expand Down
Expand Up @@ -20,6 +20,7 @@ import im.vector.app.core.platform.VectorViewModelAction
import java.io.OutputStream

sealed class BootstrapActions : VectorViewModelAction {
object Retry : BootstrapActions()

// Navigation

Expand Down
Expand Up @@ -212,6 +212,11 @@ class BootstrapBottomSheet : VectorBaseBottomSheetDialogFragment<BottomSheetBoot
views.bootstrapTitleText.text = getString(R.string.upgrade_security)
showFragment(BootstrapMigrateBackupFragment::class)
}
is BootstrapStep.Error -> {
views.bootstrapIcon.isVisible = true
views.bootstrapTitleText.text = getString(R.string.bottom_sheet_setup_secure_backup_title)
showFragment(BootstrapErrorFragment::class)
}
}
super.invalidate()
}
Expand Down
@@ -0,0 +1,54 @@
/*
* Copyright (c) 2023 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.app.features.crypto.recover

import android.view.LayoutInflater
import android.view.ViewGroup
import com.airbnb.mvrx.parentFragmentViewModel
import com.airbnb.mvrx.withState
import dagger.hilt.android.AndroidEntryPoint
import im.vector.app.R
import im.vector.app.core.epoxy.onClick
import im.vector.app.core.extensions.setTextOrHide
import im.vector.app.core.platform.VectorBaseFragment
import im.vector.app.databinding.FragmentBootstrapErrorBinding

@AndroidEntryPoint
class BootstrapErrorFragment :
VectorBaseFragment<FragmentBootstrapErrorBinding>() {

override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): FragmentBootstrapErrorBinding {
return FragmentBootstrapErrorBinding.inflate(inflater, container, false)
}

val sharedViewModel: BootstrapSharedViewModel by parentFragmentViewModel()

override fun invalidate() = withState(sharedViewModel) { state ->
when (state.step) {
is BootstrapStep.Error -> {
views.bootstrapDescriptionText.setTextOrHide(errorFormatter.toHumanReadable(state.step.error))
}
else -> {
// Should not happen, show a generic error
views.bootstrapDescriptionText.setTextOrHide(getString(R.string.unknown_error))
}
}
views.bootstrapRetryButton.onClick {
sharedViewModel.handle(BootstrapActions.Retry)
}
}
}
Expand Up @@ -54,6 +54,7 @@ import org.matrix.android.sdk.api.session.crypto.keysbackup.extractCurveKeyFromR
import org.matrix.android.sdk.api.session.crypto.keysbackup.toKeysVersionResult
import org.matrix.android.sdk.api.session.securestorage.RawBytesKeySpec
import org.matrix.android.sdk.api.session.uia.DefaultBaseAuth
import timber.log.Timber
import java.io.OutputStream
import kotlin.coroutines.Continuation
import kotlin.coroutines.resumeWithException
Expand Down Expand Up @@ -118,37 +119,48 @@ class BootstrapSharedViewModel @AssistedInject constructor(
}
}
SetupMode.NORMAL -> {
// need to check if user have an existing keybackup
setState {
copy(step = BootstrapStep.CheckingMigration)
}
checkMigration()
}
}
}

private fun checkMigration() {
// need to check if user have an existing keybackup
setState {
copy(step = BootstrapStep.CheckingMigration)
}

// We need to check if there is an existing backup
viewModelScope.launch(Dispatchers.IO) {
val version = tryOrNull { session.cryptoService().keysBackupService().getCurrentVersion() }?.toKeysVersionResult()
if (version == null) {
// we just resume plain bootstrap
doesKeyBackupExist = false
// We need to check if there is an existing backup
viewModelScope.launch(Dispatchers.IO) {
try {
val version = tryOrNull { session.cryptoService().keysBackupService().getCurrentVersion() }?.toKeysVersionResult()
if (version == null) {
// we just resume plain bootstrap
doesKeyBackupExist = false
setState {
copy(step = BootstrapStep.FirstForm(keyBackUpExist = doesKeyBackupExist, methods = this.secureBackupMethod))
}
} else {
// we need to get existing backup passphrase/key and convert to SSSS
val keyVersion = tryOrNull {
session.cryptoService().keysBackupService().getVersion(version.version)
}
if (keyVersion == null) {
// strange case... just finish?
_viewEvents.post(BootstrapViewEvents.Dismiss(false))
} else {
doesKeyBackupExist = true
isBackupCreatedFromPassphrase = keyVersion.getAuthDataAsMegolmBackupAuthData()?.privateKeySalt != null
setState {
copy(step = BootstrapStep.FirstForm(keyBackUpExist = doesKeyBackupExist, methods = this.secureBackupMethod))
}
} else {
// we need to get existing backup passphrase/key and convert to SSSS
val keyVersion = tryOrNull {
session.cryptoService().keysBackupService().getVersion(version.version)
}
if (keyVersion == null) {
// strange case... just finish?
_viewEvents.post(BootstrapViewEvents.Dismiss(false))
} else {
doesKeyBackupExist = true
isBackupCreatedFromPassphrase = keyVersion.getAuthDataAsMegolmBackupAuthData()?.privateKeySalt != null
setState {
copy(step = BootstrapStep.FirstForm(keyBackUpExist = doesKeyBackupExist, methods = this.secureBackupMethod))
}
}
}
}
} catch (failure: Throwable) {
Timber.e(failure, "Error while checking key backup")
setState {
copy(step = BootstrapStep.Error(failure))
}
}
}
}
Expand Down Expand Up @@ -268,6 +280,9 @@ class BootstrapSharedViewModel @AssistedInject constructor(
copy(step = BootstrapStep.AccountReAuth(stringProvider.getString(R.string.authentication_error)))
}
}
BootstrapActions.Retry -> {
checkMigration()
}
}
}

Expand Down Expand Up @@ -568,6 +583,12 @@ class BootstrapSharedViewModel @AssistedInject constructor(
)
}
}
is BootstrapStep.Error -> {
// do we let you cancel from here?
if (state.canLeave) {
_viewEvents.post(BootstrapViewEvents.SkipBootstrap(state.passphrase != null))
}
}
}
}

Expand Down
Expand Up @@ -105,6 +105,8 @@ sealed class BootstrapStep {
object Initializing : BootstrapStep()
data class SaveRecoveryKey(val isSaved: Boolean) : BootstrapStep()
object DoneSuccess : BootstrapStep()

data class Error(val error: Throwable) : BootstrapStep()
}

fun BootstrapStep.GetBackupSecretForMigration.useKey(): Boolean {
Expand Down
Expand Up @@ -71,6 +71,7 @@ import org.matrix.android.sdk.api.session.integrationmanager.IntegrationManagerC
import org.matrix.android.sdk.api.session.integrationmanager.IntegrationManagerService
import org.matrix.android.sdk.flow.flow
import org.matrix.android.sdk.flow.unwrap
import timber.log.Timber
import java.io.File
import java.net.URL
import java.util.UUID
Expand Down Expand Up @@ -265,7 +266,17 @@ class VectorSettingsGeneralFragment :
// Disable it while updating the state, will be re-enabled by the account data listener.
it.isEnabled = false
lifecycleScope.launch {
session.integrationManagerService().setIntegrationEnabled(newValue as Boolean)
try {
session.integrationManagerService().setIntegrationEnabled(newValue as Boolean)
} catch (failure: Throwable) {
Timber.e(failure, "Failed to update integration manager state")
activity?.let { activity ->
Toast.makeText(activity, errorFormatter.toHumanReadable(failure), Toast.LENGTH_SHORT).show()
}
// Restore the previous state
it.isChecked = !it.isChecked
it.isEnabled = true
}
}
true
}
Expand Down
33 changes: 33 additions & 0 deletions vector/src/main/res/layout/fragment_bootstrap_error.xml
@@ -0,0 +1,33 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:minHeight="200dp"
android:padding="16dp">

<TextView
android:id="@+id/bootstrapDescriptionText"
style="@style/Widget.Vector.TextView.Body"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:text="@string/error_check_network"
android:textColor="?vctr_content_primary"
app:layout_constraintTop_toTopOf="parent" />

<Button
android:id="@+id/bootstrapRetryButton"
style="@style/Widget.Vector.Button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/layout_vertical_margin"
android:text="@string/global_retry"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/bootstrapDescriptionText"
tools:ignore="MissingConstraints" />

</androidx.constraintlayout.widget.ConstraintLayout>

0 comments on commit 180a2ee

Please sign in to comment.