mirror of
https://github.com/vector-im/element-android.git
synced 2024-11-15 01:35:07 +08:00
Fix / double bottomsheet effect
This commit is contained in:
parent
b84d7f0834
commit
cf70916764
@ -8,7 +8,7 @@ Improvements 🙌:
|
||||
-
|
||||
|
||||
Bugfix 🐛:
|
||||
-
|
||||
- Double bottomsheet effect after verify with passphrase
|
||||
|
||||
Translations 🗣:
|
||||
-
|
||||
|
@ -36,6 +36,7 @@ import im.vector.app.features.crypto.recover.BootstrapMigrateBackupFragment
|
||||
import im.vector.app.features.crypto.recover.BootstrapSaveRecoveryKeyFragment
|
||||
import im.vector.app.features.crypto.recover.BootstrapSetupRecoveryKeyFragment
|
||||
import im.vector.app.features.crypto.recover.BootstrapWaitingFragment
|
||||
import im.vector.app.features.crypto.verification.QuadSLoadingFragment
|
||||
import im.vector.app.features.crypto.verification.cancel.VerificationCancelFragment
|
||||
import im.vector.app.features.crypto.verification.cancel.VerificationNotMeFragment
|
||||
import im.vector.app.features.crypto.verification.choose.VerificationChooseMethodFragment
|
||||
@ -418,6 +419,11 @@ interface FragmentModule {
|
||||
@FragmentKey(VerificationCancelFragment::class)
|
||||
fun bindVerificationCancelFragment(fragment: VerificationCancelFragment): Fragment
|
||||
|
||||
@Binds
|
||||
@IntoMap
|
||||
@FragmentKey(QuadSLoadingFragment::class)
|
||||
fun bindQuadSLoadingFragment(fragment: QuadSLoadingFragment): Fragment
|
||||
|
||||
@Binds
|
||||
@IntoMap
|
||||
@FragmentKey(VerificationNotMeFragment::class)
|
||||
|
@ -0,0 +1,25 @@
|
||||
/*
|
||||
* Copyright (c) 2020 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.verification
|
||||
|
||||
import im.vector.app.R
|
||||
import im.vector.app.core.platform.VectorBaseFragment
|
||||
import javax.inject.Inject
|
||||
|
||||
class QuadSLoadingFragment @Inject constructor() : VectorBaseFragment() {
|
||||
override fun getLayoutResId() = R.layout.fragment_progress
|
||||
}
|
@ -31,5 +31,6 @@ sealed class VerificationAction : VectorViewModelAction {
|
||||
object SkipVerification : VerificationAction()
|
||||
object VerifyFromPassphrase : VerificationAction()
|
||||
data class GotResultFromSsss(val cypherData: String, val alias: String) : VerificationAction()
|
||||
object CancelledFromSsss : VerificationAction()
|
||||
object SecuredStorageHasBeenReset : VerificationAction()
|
||||
}
|
||||
|
@ -106,7 +106,7 @@ class VerificationBottomSheet : VectorBaseBottomSheetDialogFragment() {
|
||||
|
||||
viewModel.observeViewEvents {
|
||||
when (it) {
|
||||
is VerificationBottomSheetViewEvents.Dismiss -> dismiss()
|
||||
is VerificationBottomSheetViewEvents.Dismiss -> dismiss()
|
||||
is VerificationBottomSheetViewEvents.AccessSecretStore -> {
|
||||
secretStartForActivityResult.launch(SharedSecureStorageActivity.newIntent(
|
||||
requireContext(),
|
||||
@ -115,7 +115,7 @@ class VerificationBottomSheet : VectorBaseBottomSheetDialogFragment() {
|
||||
SharedSecureStorageActivity.DEFAULT_RESULT_KEYSTORE_ALIAS
|
||||
))
|
||||
}
|
||||
is VerificationBottomSheetViewEvents.ModalError -> {
|
||||
is VerificationBottomSheetViewEvents.ModalError -> {
|
||||
AlertDialog.Builder(requireContext())
|
||||
.setTitle(getString(R.string.dialog_title_error))
|
||||
.setMessage(it.errorMessage)
|
||||
@ -124,7 +124,7 @@ class VerificationBottomSheet : VectorBaseBottomSheetDialogFragment() {
|
||||
.show()
|
||||
Unit
|
||||
}
|
||||
VerificationBottomSheetViewEvents.GoToSettings -> {
|
||||
VerificationBottomSheetViewEvents.GoToSettings -> {
|
||||
dismiss()
|
||||
(activity as? VectorBaseActivity)?.navigator?.openSettings(requireContext(), VectorSettingsActivity.EXTRA_DIRECT_ACCESS_SECURITY_PRIVACY)
|
||||
}
|
||||
@ -155,6 +155,8 @@ class VerificationBottomSheet : VectorBaseBottomSheetDialogFragment() {
|
||||
// all have been reset, so we are verified?
|
||||
viewModel.handle(VerificationAction.SecuredStorageHasBeenReset)
|
||||
}
|
||||
} else {
|
||||
viewModel.handle(VerificationAction.CancelledFromSsss)
|
||||
}
|
||||
}
|
||||
|
||||
@ -209,6 +211,10 @@ class VerificationBottomSheet : VectorBaseBottomSheetDialogFragment() {
|
||||
return@withState
|
||||
}
|
||||
|
||||
if (state.selfVerificationMode && state.verifyingFrom4S) {
|
||||
showFragment(QuadSLoadingFragment::class, Bundle())
|
||||
return@withState
|
||||
}
|
||||
if (state.selfVerificationMode && state.verifiedFromPrivateKeys) {
|
||||
showFragment(VerificationConclusionFragment::class, Bundle().apply {
|
||||
putParcelable(MvRx.KEY_ARG, VerificationConclusionFragment.Args(true, null, state.isMe))
|
||||
@ -242,7 +248,7 @@ class VerificationBottomSheet : VectorBaseBottomSheetDialogFragment() {
|
||||
state.pendingRequest.invoke()?.transactionId ?: state.transactionId))
|
||||
})
|
||||
}
|
||||
is VerificationTxState.Verified -> {
|
||||
is VerificationTxState.Verified -> {
|
||||
showFragment(VerificationConclusionFragment::class, Bundle().apply {
|
||||
putParcelable(MvRx.KEY_ARG, VerificationConclusionFragment.Args(true, null, state.isMe))
|
||||
})
|
||||
@ -258,7 +264,7 @@ class VerificationBottomSheet : VectorBaseBottomSheetDialogFragment() {
|
||||
}
|
||||
|
||||
when (state.qrTransactionState) {
|
||||
is VerificationTxState.QrScannedByOther -> {
|
||||
is VerificationTxState.QrScannedByOther -> {
|
||||
showFragment(VerificationQrScannedByOtherFragment::class, Bundle())
|
||||
return@withState
|
||||
}
|
||||
@ -272,13 +278,13 @@ class VerificationBottomSheet : VectorBaseBottomSheetDialogFragment() {
|
||||
})
|
||||
return@withState
|
||||
}
|
||||
is VerificationTxState.Verified -> {
|
||||
is VerificationTxState.Verified -> {
|
||||
showFragment(VerificationConclusionFragment::class, Bundle().apply {
|
||||
putParcelable(MvRx.KEY_ARG, VerificationConclusionFragment.Args(true, null, state.isMe))
|
||||
})
|
||||
return@withState
|
||||
}
|
||||
is VerificationTxState.Cancelled -> {
|
||||
is VerificationTxState.Cancelled -> {
|
||||
showFragment(VerificationConclusionFragment::class, Bundle().apply {
|
||||
putParcelable(MvRx.KEY_ARG, VerificationConclusionFragment.Args(false, state.qrTransactionState.cancelCode.value, state.isMe))
|
||||
})
|
||||
|
@ -32,6 +32,7 @@ import im.vector.app.core.extensions.exhaustive
|
||||
import im.vector.app.core.platform.VectorViewModel
|
||||
import im.vector.app.core.resources.StringProvider
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.GlobalScope
|
||||
import kotlinx.coroutines.launch
|
||||
import org.matrix.android.sdk.api.MatrixCallback
|
||||
import org.matrix.android.sdk.api.session.Session
|
||||
@ -70,6 +71,7 @@ data class VerificationBottomSheetViewState(
|
||||
// true when we display the loading and we wait for the other (incoming request)
|
||||
val selfVerificationMode: Boolean = false,
|
||||
val verifiedFromPrivateKeys: Boolean = false,
|
||||
val verifyingFrom4S: Boolean = false,
|
||||
val isMe: Boolean = false,
|
||||
val currentDeviceCanCrossSign: Boolean = false,
|
||||
val userWantsToCancel: Boolean = false,
|
||||
@ -170,7 +172,9 @@ class VerificationBottomSheetViewModel @AssistedInject constructor(
|
||||
}
|
||||
} else {
|
||||
// if the verification is already done you can't cancel anymore
|
||||
if (state.pendingRequest.invoke()?.cancelConclusion != null || state.sasTransactionState is VerificationTxState.TerminalTxState) {
|
||||
if (state.pendingRequest.invoke()?.cancelConclusion != null
|
||||
|| state.sasTransactionState is VerificationTxState.TerminalTxState
|
||||
|| state.verifyingFrom4S) {
|
||||
// you cannot cancel anymore
|
||||
} else {
|
||||
setState {
|
||||
@ -346,6 +350,7 @@ class VerificationBottomSheetViewModel @AssistedInject constructor(
|
||||
_viewEvents.post(VerificationBottomSheetViewEvents.Dismiss)
|
||||
}
|
||||
is VerificationAction.VerifyFromPassphrase -> {
|
||||
setState { copy(verifyingFrom4S = true) }
|
||||
_viewEvents.post(VerificationBottomSheetViewEvents.AccessSecretStore)
|
||||
}
|
||||
is VerificationAction.GotResultFromSsss -> {
|
||||
@ -354,56 +359,73 @@ class VerificationBottomSheetViewModel @AssistedInject constructor(
|
||||
VerificationAction.SecuredStorageHasBeenReset -> {
|
||||
if (session.cryptoService().crossSigningService().allPrivateKeysKnown()) {
|
||||
setState {
|
||||
copy(quadSHasBeenReset = true)
|
||||
copy(quadSHasBeenReset = true, verifyingFrom4S = false)
|
||||
}
|
||||
}
|
||||
Unit
|
||||
}
|
||||
VerificationAction.CancelledFromSsss -> {
|
||||
setState {
|
||||
copy(verifyingFrom4S = false)
|
||||
}
|
||||
}
|
||||
}.exhaustive
|
||||
}
|
||||
|
||||
private fun handleSecretBackFromSSSS(action: VerificationAction.GotResultFromSsss) {
|
||||
try {
|
||||
action.cypherData.fromBase64().inputStream().use { ins ->
|
||||
val res = session.loadSecureSecret<Map<String, String>>(ins, action.alias)
|
||||
val trustResult = session.cryptoService().crossSigningService().checkTrustFromPrivateKeys(
|
||||
res?.get(MASTER_KEY_SSSS_NAME),
|
||||
res?.get(USER_SIGNING_KEY_SSSS_NAME),
|
||||
res?.get(SELF_SIGNING_KEY_SSSS_NAME)
|
||||
)
|
||||
if (trustResult.isVerified()) {
|
||||
// Sign this device and upload the signature
|
||||
session.sessionParams.deviceId?.let { deviceId ->
|
||||
session.cryptoService()
|
||||
.crossSigningService().trustDevice(deviceId, object : MatrixCallback<Unit> {
|
||||
override fun onFailure(failure: Throwable) {
|
||||
Timber.w(failure, "Failed to sign my device after recovery")
|
||||
}
|
||||
})
|
||||
}
|
||||
viewModelScope.launch(Dispatchers.IO) {
|
||||
try {
|
||||
action.cypherData.fromBase64().inputStream().use { ins ->
|
||||
val res = session.loadSecureSecret<Map<String, String>>(ins, action.alias)
|
||||
val trustResult = session.cryptoService().crossSigningService().checkTrustFromPrivateKeys(
|
||||
res?.get(MASTER_KEY_SSSS_NAME),
|
||||
res?.get(USER_SIGNING_KEY_SSSS_NAME),
|
||||
res?.get(SELF_SIGNING_KEY_SSSS_NAME)
|
||||
)
|
||||
if (trustResult.isVerified()) {
|
||||
// Sign this device and upload the signature
|
||||
session.sessionParams.deviceId?.let { deviceId ->
|
||||
session.cryptoService()
|
||||
.crossSigningService().trustDevice(deviceId, object : MatrixCallback<Unit> {
|
||||
override fun onFailure(failure: Throwable) {
|
||||
Timber.w(failure, "Failed to sign my device after recovery")
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
setState {
|
||||
copy(verifiedFromPrivateKeys = true)
|
||||
}
|
||||
setState {
|
||||
copy(
|
||||
verifyingFrom4S = false,
|
||||
verifiedFromPrivateKeys = true
|
||||
)
|
||||
}
|
||||
|
||||
// try to get keybackup key
|
||||
} else {
|
||||
// POP UP something
|
||||
_viewEvents.post(VerificationBottomSheetViewEvents.ModalError(stringProvider.getString(R.string.error_failed_to_import_keys)))
|
||||
// try the keybackup
|
||||
tentativeRestoreBackup(res)
|
||||
} else {
|
||||
setState {
|
||||
copy(
|
||||
verifyingFrom4S = false
|
||||
)
|
||||
}
|
||||
// POP UP something
|
||||
_viewEvents.post(VerificationBottomSheetViewEvents.ModalError(stringProvider.getString(R.string.error_failed_to_import_keys)))
|
||||
}
|
||||
}
|
||||
|
||||
// try the keybackup
|
||||
tentativeRestoreBackup(res)
|
||||
Unit
|
||||
} catch (failure: Throwable) {
|
||||
setState {
|
||||
copy(
|
||||
verifyingFrom4S = false
|
||||
)
|
||||
}
|
||||
_viewEvents.post(
|
||||
VerificationBottomSheetViewEvents.ModalError(failure.localizedMessage ?: stringProvider.getString(R.string.unexpected_error)))
|
||||
}
|
||||
} catch (failure: Throwable) {
|
||||
_viewEvents.post(
|
||||
VerificationBottomSheetViewEvents.ModalError(failure.localizedMessage ?: stringProvider.getString(R.string.unexpected_error)))
|
||||
}
|
||||
}
|
||||
|
||||
private fun tentativeRestoreBackup(res: Map<String, String>?) {
|
||||
viewModelScope.launch(Dispatchers.IO) {
|
||||
GlobalScope.launch(Dispatchers.IO) {
|
||||
try {
|
||||
val secret = res?.get(KEYBACKUP_SECRET_SSSS_NAME) ?: return@launch Unit.also {
|
||||
Timber.v("## Keybackup secret not restored from SSSS")
|
||||
@ -460,7 +482,7 @@ class VerificationBottomSheetViewModel @AssistedInject constructor(
|
||||
}
|
||||
|
||||
when (tx) {
|
||||
is SasVerificationTransaction -> {
|
||||
is SasVerificationTransaction -> {
|
||||
if (tx.transactionId == (state.pendingRequest.invoke()?.transactionId ?: state.transactionId)) {
|
||||
// A SAS tx has been started following this request
|
||||
setState {
|
||||
|
14
vector/src/main/res/layout/fragment_progress.xml
Normal file
14
vector/src/main/res/layout/fragment_progress.xml
Normal file
@ -0,0 +1,14 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<ProgressBar
|
||||
android:id="@+id/progressBar"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_centerInParent="true"
|
||||
android:layout_marginTop="@dimen/layout_vertical_margin_big"
|
||||
android:indeterminate="true" />
|
||||
|
||||
</RelativeLayout>
|
Loading…
Reference in New Issue
Block a user