Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Crash fixes #8578

Merged
merged 3 commits into from
Jul 17, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
@@ -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)
}
}
}
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
@@ -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>