Merge pull request #1648 from vector-im/feature/bma/secureBackup

Secure backup
This commit is contained in:
Benoit Marty 2023-10-30 21:29:54 +01:00 committed by GitHub
commit 63cf5ef5b1
77 changed files with 284 additions and 158 deletions

View file

@ -58,6 +58,7 @@ class LogoutNode @AssistedInject constructor(
state = state,
onChangeRecoveryKeyClicked = ::onChangeRecoveryKeyClicked,
onSuccessLogout = { onSuccessLogout(activity, it) },
onBackClicked = ::navigateUp,
modifier = modifier,
)
}

View file

@ -29,6 +29,7 @@ import io.element.android.libraries.architecture.Async
import io.element.android.libraries.architecture.Presenter
import io.element.android.libraries.architecture.runCatchingUpdatingState
import io.element.android.libraries.matrix.api.MatrixClient
import io.element.android.libraries.matrix.api.encryption.BackupUploadState
import io.element.android.libraries.matrix.api.encryption.EncryptionService
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.launch
@ -46,13 +47,15 @@ class LogoutPresenter @Inject constructor(
mutableStateOf(Async.Uninitialized)
}
val backupUploadState by encryptionService.backupUploadStateStateFlow.collectAsState()
val backupUploadState: BackupUploadState by remember {
encryptionService.waitForBackupUploadSteadyState()
}
.collectAsState(initial = BackupUploadState.Unknown)
var showLogoutDialog by remember { mutableStateOf(false) }
var isLastSession by remember { mutableStateOf(false) }
LaunchedEffect(Unit) {
isLastSession = encryptionService.isLastDevice().getOrNull() ?: false
encryptionService.waitForBackupUploadSteadyState()
}
fun handleEvents(event: LogoutEvents) {

View file

@ -20,6 +20,7 @@ import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.ui.Alignment
@ -32,6 +33,7 @@ import io.element.android.libraries.designsystem.atomic.molecules.ButtonColumnMo
import io.element.android.libraries.designsystem.atomic.molecules.IconTitleSubtitleMolecule
import io.element.android.libraries.designsystem.atomic.pages.HeaderFooterPage
import io.element.android.libraries.designsystem.components.ProgressDialog
import io.element.android.libraries.designsystem.components.button.BackButton
import io.element.android.libraries.designsystem.components.dialogs.ConfirmationDialog
import io.element.android.libraries.designsystem.preview.ElementPreview
import io.element.android.libraries.designsystem.preview.PreviewsDayNight
@ -39,16 +41,19 @@ import io.element.android.libraries.designsystem.theme.components.Button
import io.element.android.libraries.designsystem.theme.components.LinearProgressIndicator
import io.element.android.libraries.designsystem.theme.components.OutlinedButton
import io.element.android.libraries.designsystem.theme.components.Text
import io.element.android.libraries.designsystem.theme.components.TopAppBar
import io.element.android.libraries.designsystem.theme.progressIndicatorTrackColor
import io.element.android.libraries.designsystem.utils.CommonDrawables
import io.element.android.libraries.matrix.api.encryption.BackupUploadState
import io.element.android.libraries.theme.ElementTheme
import io.element.android.libraries.ui.strings.CommonStrings
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun LogoutView(
state: LogoutState,
onChangeRecoveryKeyClicked: () -> Unit,
onBackClicked: () -> Unit,
onSuccessLogout: (logoutUrlResult: String?) -> Unit,
modifier: Modifier = Modifier,
) {
@ -56,6 +61,12 @@ fun LogoutView(
HeaderFooterPage(
modifier = modifier,
topBar = {
TopAppBar(
navigationIcon = { BackButton(onClick = onBackClicked) },
title = {},
)
},
header = {
HeaderContent(state = state)
},
@ -134,7 +145,7 @@ private fun HeaderContent(
else -> null
}
val paddingTop = 60.dp
val paddingTop = 0.dp
IconTitleSubtitleMolecule(
modifier = modifier.padding(top = paddingTop),
iconResourceId = CommonDrawables.ic_key,
@ -219,6 +230,7 @@ internal fun LogoutViewPreview(
LogoutView(
state,
onChangeRecoveryKeyClicked = {},
onSuccessLogout = {}
onSuccessLogout = {},
onBackClicked = {},
)
}

View file

@ -28,6 +28,8 @@ import io.element.android.libraries.matrix.test.A_THROWABLE
import io.element.android.libraries.matrix.test.FakeMatrixClient
import io.element.android.libraries.matrix.test.encryption.FakeEncryptionService
import io.element.android.tests.testutils.WarmUpRule
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.flow
import kotlinx.coroutines.test.runTest
import org.junit.Rule
import org.junit.Test
@ -73,6 +75,15 @@ class LogoutPresenterTest {
@Test
fun `present - initial state - backing up`() = runTest {
val encryptionService = FakeEncryptionService()
encryptionService.givenWaitForBackupUploadSteadyStateFlow(
flow {
emit(BackupUploadState.Waiting)
delay(1)
emit(BackupUploadState.Uploading(backedUpCount = 1, totalCount = 2))
delay(1)
emit(BackupUploadState.Done)
}
)
val presenter = createLogoutPresenter(
encryptionService = encryptionService
)
@ -84,10 +95,10 @@ class LogoutPresenterTest {
assertThat(initialState.backupUploadState).isEqualTo(BackupUploadState.Unknown)
assertThat(initialState.showConfirmationDialog).isFalse()
assertThat(initialState.logoutAction).isEqualTo(Async.Uninitialized)
encryptionService.emitBackupUploadState(BackupUploadState.Uploading(backedUpCount = 1, totalCount = 2))
val state = awaitItem()
assertThat(state.backupUploadState).isEqualTo(BackupUploadState.Uploading(backedUpCount = 1, totalCount = 2))
encryptionService.emitBackupUploadState(BackupUploadState.Done)
val waitingState = awaitItem()
assertThat(waitingState.backupUploadState).isEqualTo(BackupUploadState.Waiting)
val uploadingState = awaitItem()
assertThat(uploadingState.backupUploadState).isEqualTo(BackupUploadState.Uploading(backedUpCount = 1, totalCount = 2))
val doneState = awaitItem()
assertThat(doneState.backupUploadState).isEqualTo(BackupUploadState.Done)
}