Merge pull request #1653 from vector-im/feature/bma/secureBackupSdk
SecureBackup: update matrix sdk module.
This commit is contained in:
@@ -142,7 +142,7 @@ class PinUnlockPresenter @Inject constructor(
|
||||
|
||||
private fun CoroutineScope.signOut(signOutAction: MutableState<Async<String?>>) = launch {
|
||||
suspend {
|
||||
matrixClient.logout()
|
||||
matrixClient.logout(ignoreSdkError = true)
|
||||
}.runCatchingUpdatingState(signOutAction)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -58,7 +58,7 @@ class DefaultLogoutPreferencePresenter @Inject constructor(private val matrixCli
|
||||
|
||||
private fun CoroutineScope.logout(logoutAction: MutableState<Async<String?>>) = launch {
|
||||
suspend {
|
||||
matrixClient.logout()
|
||||
matrixClient.logout(false /* TODO */)
|
||||
}.runCatchingUpdatingState(logoutAction)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,6 +21,7 @@ import io.element.android.libraries.matrix.api.core.RoomId
|
||||
import io.element.android.libraries.matrix.api.core.SessionId
|
||||
import io.element.android.libraries.matrix.api.core.UserId
|
||||
import io.element.android.libraries.matrix.api.createroom.CreateRoomParameters
|
||||
import io.element.android.libraries.matrix.api.encryption.EncryptionService
|
||||
import io.element.android.libraries.matrix.api.media.MatrixMediaLoader
|
||||
import io.element.android.libraries.matrix.api.notification.NotificationService
|
||||
import io.element.android.libraries.matrix.api.notificationsettings.NotificationSettingsService
|
||||
@@ -55,6 +56,7 @@ interface MatrixClient : Closeable {
|
||||
fun pushersService(): PushersService
|
||||
fun notificationService(): NotificationService
|
||||
fun notificationSettingsService(): NotificationSettingsService
|
||||
fun encryptionService(): EncryptionService
|
||||
suspend fun getCacheSize(): Long
|
||||
|
||||
/**
|
||||
@@ -66,8 +68,9 @@ interface MatrixClient : Closeable {
|
||||
* Logout the user.
|
||||
* Returns an optional URL. When the URL is there, it should be presented to the user after logout for
|
||||
* Relying Party (RP) initiated logout on their account page.
|
||||
* @param ignoreSdkError if true, the SDK will ignore any error and delete the session data anyway.
|
||||
*/
|
||||
suspend fun logout(): String?
|
||||
suspend fun logout(ignoreSdkError: Boolean): String?
|
||||
suspend fun loadUserDisplayName(): Result<String>
|
||||
suspend fun loadUserAvatarURLString(): Result<String?>
|
||||
suspend fun getAccountManagementUrl(action: AccountManagementAction?): Result<String?>
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
/*
|
||||
* 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 io.element.android.libraries.matrix.api.encryption
|
||||
|
||||
sealed interface BackupUploadState {
|
||||
data object Unknown : BackupUploadState
|
||||
|
||||
data class CheckingIfUploadNeeded(
|
||||
val backedUpCount: Int,
|
||||
val totalCount: Int,
|
||||
) : BackupUploadState
|
||||
|
||||
data object Waiting : BackupUploadState
|
||||
|
||||
data class Uploading(
|
||||
val backedUpCount: Int,
|
||||
val totalCount: Int,
|
||||
) : BackupUploadState
|
||||
|
||||
data object Done : BackupUploadState
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
/*
|
||||
* 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 io.element.android.libraries.matrix.api.encryption
|
||||
|
||||
sealed interface EnableRecoveryProgress {
|
||||
data object Unknown : EnableRecoveryProgress
|
||||
data object CreatingRecoveryKey : EnableRecoveryProgress
|
||||
data object CreatingBackup : EnableRecoveryProgress
|
||||
data class BackingUp(val backedUpCount: Int, val totalCount: Int) : EnableRecoveryProgress
|
||||
data class Done(val recoveryKey: String) : EnableRecoveryProgress
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
/*
|
||||
* 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 io.element.android.libraries.matrix.api.encryption
|
||||
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
|
||||
interface EncryptionService {
|
||||
val backupStateStateFlow: StateFlow<BackupState>
|
||||
val recoveryStateStateFlow: StateFlow<RecoveryState>
|
||||
val backupUploadStateStateFlow: StateFlow<BackupUploadState>
|
||||
val enableRecoveryProgressStateFlow: StateFlow<EnableRecoveryProgress>
|
||||
|
||||
suspend fun enableBackups(): Result<Unit>
|
||||
|
||||
suspend fun isLastDevice(): Result<Boolean>
|
||||
|
||||
/**
|
||||
* Enable recovery. Observe enableProgressStateFlow to get progress and recovery key.
|
||||
*/
|
||||
suspend fun enableRecovery(waitForBackupsToUpload: Boolean): Result<Unit>
|
||||
|
||||
/**
|
||||
* Change the recovery and return the new recovery key.
|
||||
*/
|
||||
suspend fun resetRecoveryKey(): Result<String>
|
||||
|
||||
suspend fun disableRecovery(): Result<Unit>
|
||||
|
||||
/**
|
||||
* Note: accept bot recoveryKey and passphrase.
|
||||
*/
|
||||
suspend fun fixRecoveryIssues(recoveryKey: String): Result<Unit>
|
||||
|
||||
/**
|
||||
* Observe [backupUploadStateStateFlow] to get progress.
|
||||
*/
|
||||
suspend fun waitForBackupUploadSteadyState(): Result<Unit>
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
/*
|
||||
* 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 io.element.android.libraries.matrix.api.encryption
|
||||
|
||||
enum class RecoveryState {
|
||||
UNKNOWN,
|
||||
ENABLED,
|
||||
DISABLED,
|
||||
INCOMPLETE,
|
||||
}
|
||||
@@ -27,6 +27,7 @@ import io.element.android.libraries.matrix.api.core.UserId
|
||||
import io.element.android.libraries.matrix.api.createroom.CreateRoomParameters
|
||||
import io.element.android.libraries.matrix.api.createroom.RoomPreset
|
||||
import io.element.android.libraries.matrix.api.createroom.RoomVisibility
|
||||
import io.element.android.libraries.matrix.api.encryption.EncryptionService
|
||||
import io.element.android.libraries.matrix.api.media.MatrixMediaLoader
|
||||
import io.element.android.libraries.matrix.api.notification.NotificationService
|
||||
import io.element.android.libraries.matrix.api.notificationsettings.NotificationSettingsService
|
||||
@@ -41,6 +42,7 @@ import io.element.android.libraries.matrix.api.user.MatrixSearchUserResults
|
||||
import io.element.android.libraries.matrix.api.user.MatrixUser
|
||||
import io.element.android.libraries.matrix.api.verification.SessionVerificationService
|
||||
import io.element.android.libraries.matrix.impl.core.toProgressWatcher
|
||||
import io.element.android.libraries.matrix.impl.encryption.RustEncryptionService
|
||||
import io.element.android.libraries.matrix.impl.mapper.toSessionData
|
||||
import io.element.android.libraries.matrix.impl.media.RustMediaLoader
|
||||
import io.element.android.libraries.matrix.impl.notification.RustNotificationService
|
||||
@@ -117,6 +119,7 @@ class RustMatrixClient constructor(
|
||||
private val notificationService = RustNotificationService(sessionId, notificationClient, dispatchers, clock)
|
||||
private val notificationSettingsService = RustNotificationSettingsService(notificationSettings, dispatchers)
|
||||
private val roomSyncSubscriber = RoomSyncSubscriber(innerRoomListService, dispatchers)
|
||||
private val encryptionService = RustEncryptionService(client, dispatchers).apply { start() }
|
||||
|
||||
private val isLoggingOut = AtomicBoolean(false)
|
||||
|
||||
@@ -136,7 +139,7 @@ class RustMatrixClient constructor(
|
||||
)
|
||||
sessionStore.updateData(newData)
|
||||
}
|
||||
doLogout(doRequest = false, removeSession = false)
|
||||
doLogout(doRequest = false, removeSession = false, ignoreSdkError = false)
|
||||
}
|
||||
} else {
|
||||
Timber.v("didReceiveAuthError -> already cleaning up")
|
||||
@@ -319,6 +322,8 @@ class RustMatrixClient constructor(
|
||||
|
||||
override fun notificationService(): NotificationService = notificationService
|
||||
|
||||
override fun encryptionService(): EncryptionService = encryptionService
|
||||
|
||||
override fun notificationSettingsService(): NotificationSettingsService = notificationSettingsService
|
||||
|
||||
override fun close() {
|
||||
@@ -331,6 +336,7 @@ class RustMatrixClient constructor(
|
||||
innerRoomListService.destroy()
|
||||
notificationClient.destroy()
|
||||
notificationProcessSetup.destroy()
|
||||
encryptionService.destroy()
|
||||
client.destroy()
|
||||
}
|
||||
|
||||
@@ -344,16 +350,29 @@ class RustMatrixClient constructor(
|
||||
baseDirectory.deleteSessionDirectory(userID = sessionId.value, deleteCryptoDb = false)
|
||||
}
|
||||
|
||||
override suspend fun logout(): String? = doLogout(doRequest = true, removeSession = true)
|
||||
override suspend fun logout(ignoreSdkError: Boolean): String? = doLogout(
|
||||
doRequest = true,
|
||||
removeSession = true,
|
||||
ignoreSdkError = ignoreSdkError,
|
||||
)
|
||||
|
||||
private suspend fun doLogout(doRequest: Boolean, removeSession: Boolean): String? {
|
||||
private suspend fun doLogout(
|
||||
doRequest: Boolean,
|
||||
removeSession: Boolean,
|
||||
ignoreSdkError: Boolean,
|
||||
): String? {
|
||||
var result: String? = null
|
||||
withContext(sessionDispatcher) {
|
||||
if (doRequest) {
|
||||
try {
|
||||
result = client.logout()
|
||||
} catch (failure: Throwable) {
|
||||
Timber.e(failure, "Fail to call logout on HS. Still delete local files.")
|
||||
if (ignoreSdkError) {
|
||||
Timber.e(failure, "Fail to call logout on HS. Still delete local files.")
|
||||
} else {
|
||||
Timber.e(failure, "Fail to call logout on HS.")
|
||||
throw failure
|
||||
}
|
||||
}
|
||||
}
|
||||
close()
|
||||
|
||||
@@ -21,6 +21,7 @@ import dagger.Module
|
||||
import dagger.Provides
|
||||
import io.element.android.libraries.di.SessionScope
|
||||
import io.element.android.libraries.matrix.api.MatrixClient
|
||||
import io.element.android.libraries.matrix.api.encryption.EncryptionService
|
||||
import io.element.android.libraries.matrix.api.media.MatrixMediaLoader
|
||||
import io.element.android.libraries.matrix.api.notificationsettings.NotificationSettingsService
|
||||
import io.element.android.libraries.matrix.api.room.RoomMembershipObserver
|
||||
@@ -50,6 +51,11 @@ object SessionMatrixModule {
|
||||
return matrixClient.roomListService
|
||||
}
|
||||
|
||||
@Provides
|
||||
fun providesEncryptionService(matrixClient: MatrixClient): EncryptionService {
|
||||
return matrixClient.encryptionService()
|
||||
}
|
||||
|
||||
@Provides
|
||||
fun provideMediaLoader(matrixClient: MatrixClient): MatrixMediaLoader {
|
||||
return matrixClient.mediaLoader
|
||||
|
||||
@@ -0,0 +1,41 @@
|
||||
/*
|
||||
* 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 io.element.android.libraries.matrix.impl.encryption
|
||||
|
||||
import io.element.android.libraries.matrix.api.encryption.BackupUploadState
|
||||
import org.matrix.rustcomponents.sdk.BackupUploadState as RustBackupUploadState
|
||||
|
||||
class BackupUploadStateMapper {
|
||||
fun map(rustEnableProgress: RustBackupUploadState): BackupUploadState {
|
||||
return when (rustEnableProgress) {
|
||||
is RustBackupUploadState.CheckingIfUploadNeeded ->
|
||||
BackupUploadState.CheckingIfUploadNeeded(
|
||||
backedUpCount = rustEnableProgress.backedUpCount.toInt(),
|
||||
totalCount = rustEnableProgress.totalCount.toInt(),
|
||||
)
|
||||
RustBackupUploadState.Done ->
|
||||
BackupUploadState.Done
|
||||
is RustBackupUploadState.Uploading ->
|
||||
BackupUploadState.Uploading(
|
||||
backedUpCount = rustEnableProgress.backedUpCount.toInt(),
|
||||
totalCount = rustEnableProgress.totalCount.toInt(),
|
||||
)
|
||||
RustBackupUploadState.Waiting ->
|
||||
BackupUploadState.Waiting
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
* 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 io.element.android.libraries.matrix.impl.encryption
|
||||
|
||||
import io.element.android.libraries.matrix.api.encryption.EnableRecoveryProgress
|
||||
import org.matrix.rustcomponents.sdk.EnableRecoveryProgress as RustEnableRecoveryProgress
|
||||
|
||||
class EnableRecoveryProgressMapper {
|
||||
fun map(rustEnableProgress: RustEnableRecoveryProgress): EnableRecoveryProgress {
|
||||
return when (rustEnableProgress) {
|
||||
is RustEnableRecoveryProgress.CreatingRecoveryKey -> EnableRecoveryProgress.CreatingRecoveryKey
|
||||
is RustEnableRecoveryProgress.CreatingBackup -> EnableRecoveryProgress.CreatingBackup
|
||||
is RustEnableRecoveryProgress.BackingUp -> EnableRecoveryProgress.BackingUp(
|
||||
backedUpCount = rustEnableProgress.backedUpCount.toInt(),
|
||||
totalCount = rustEnableProgress.totalCount.toInt(),
|
||||
)
|
||||
is RustEnableRecoveryProgress.Done -> EnableRecoveryProgress.Done(
|
||||
recoveryKey = rustEnableProgress.recoveryKey
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
/*
|
||||
* 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 io.element.android.libraries.matrix.impl.encryption
|
||||
|
||||
import io.element.android.libraries.matrix.api.encryption.RecoveryState
|
||||
import org.matrix.rustcomponents.sdk.RecoveryState as RustRecoveryState
|
||||
|
||||
class RecoveryStateMapper {
|
||||
fun map(state: RustRecoveryState): RecoveryState {
|
||||
return when (state) {
|
||||
RustRecoveryState.UNKNOWN -> RecoveryState.UNKNOWN
|
||||
RustRecoveryState.ENABLED -> RecoveryState.ENABLED
|
||||
RustRecoveryState.DISABLED -> RecoveryState.DISABLED
|
||||
RustRecoveryState.INCOMPLETE -> RecoveryState.INCOMPLETE
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,133 @@
|
||||
/*
|
||||
* 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 io.element.android.libraries.matrix.impl.encryption
|
||||
|
||||
import io.element.android.libraries.core.coroutine.CoroutineDispatchers
|
||||
import io.element.android.libraries.matrix.api.encryption.BackupState
|
||||
import io.element.android.libraries.matrix.api.encryption.BackupUploadState
|
||||
import io.element.android.libraries.matrix.api.encryption.EnableRecoveryProgress
|
||||
import io.element.android.libraries.matrix.api.encryption.EncryptionService
|
||||
import io.element.android.libraries.matrix.api.encryption.RecoveryState
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.withContext
|
||||
import org.matrix.rustcomponents.sdk.BackupStateListener
|
||||
import org.matrix.rustcomponents.sdk.BackupSteadyStateListener
|
||||
import org.matrix.rustcomponents.sdk.Client
|
||||
import org.matrix.rustcomponents.sdk.EnableRecoveryProgressListener
|
||||
import org.matrix.rustcomponents.sdk.Encryption
|
||||
import org.matrix.rustcomponents.sdk.RecoveryStateListener
|
||||
import org.matrix.rustcomponents.sdk.BackupState as RustBackupState
|
||||
import org.matrix.rustcomponents.sdk.BackupUploadState as RustBackupUploadState
|
||||
import org.matrix.rustcomponents.sdk.EnableRecoveryProgress as RustEnableRecoveryProgress
|
||||
import org.matrix.rustcomponents.sdk.RecoveryState as RustRecoveryState
|
||||
|
||||
internal class RustEncryptionService(
|
||||
client: Client,
|
||||
private val dispatchers: CoroutineDispatchers,
|
||||
) : EncryptionService {
|
||||
|
||||
private val service: Encryption = client.encryption()
|
||||
|
||||
private val backupStateMapper = BackupStateMapper()
|
||||
private val recoveryStateMapper = RecoveryStateMapper()
|
||||
private val enableRecoveryProgressMapper = EnableRecoveryProgressMapper()
|
||||
private val backupUploadStateMapper = BackupUploadStateMapper()
|
||||
|
||||
override val backupStateStateFlow: MutableStateFlow<BackupState> = MutableStateFlow(service.backupState().let(backupStateMapper::map))
|
||||
override val recoveryStateStateFlow: MutableStateFlow<RecoveryState> = MutableStateFlow(service.recoveryState().let(recoveryStateMapper::map))
|
||||
override val enableRecoveryProgressStateFlow: MutableStateFlow<EnableRecoveryProgress> = MutableStateFlow(EnableRecoveryProgress.Unknown)
|
||||
override val backupUploadStateStateFlow: MutableStateFlow<BackupUploadState> = MutableStateFlow(BackupUploadState.Unknown)
|
||||
|
||||
fun start() {
|
||||
service.backupStateListener(object : BackupStateListener {
|
||||
override fun onUpdate(status: RustBackupState) {
|
||||
backupStateStateFlow.value = backupStateMapper.map(status)
|
||||
}
|
||||
})
|
||||
|
||||
service.recoveryStateListener(object : RecoveryStateListener {
|
||||
override fun onUpdate(status: RustRecoveryState) {
|
||||
recoveryStateStateFlow.value = recoveryStateMapper.map(status)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
fun destroy() {
|
||||
// No way to remove the listeners...
|
||||
service.destroy()
|
||||
}
|
||||
|
||||
override suspend fun enableBackups(): Result<Unit> = withContext(dispatchers.io) {
|
||||
runCatching {
|
||||
service.enableBackups()
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun enableRecovery(
|
||||
waitForBackupsToUpload: Boolean,
|
||||
): Result<Unit> = withContext(dispatchers.io) {
|
||||
runCatching {
|
||||
service.enableRecovery(
|
||||
waitForBackupsToUpload = waitForBackupsToUpload,
|
||||
progressListener = object : EnableRecoveryProgressListener {
|
||||
override fun onUpdate(status: RustEnableRecoveryProgress) {
|
||||
enableRecoveryProgressStateFlow.value = enableRecoveryProgressMapper.map(status)
|
||||
}
|
||||
}
|
||||
)
|
||||
// enableRecovery returns the encryption key, but we read it from the state flow
|
||||
.let { }
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun waitForBackupUploadSteadyState(
|
||||
): Result<Unit> = withContext(dispatchers.io) {
|
||||
runCatching {
|
||||
service.waitForBackupUploadSteadyState(
|
||||
progressListener = object : BackupSteadyStateListener {
|
||||
override fun onUpdate(status: RustBackupUploadState) {
|
||||
backupUploadStateStateFlow.value = backupUploadStateMapper.map(status)
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun disableRecovery(): Result<Unit> = withContext(dispatchers.io) {
|
||||
runCatching {
|
||||
service.disableRecovery()
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun isLastDevice(): Result<Boolean> = withContext(dispatchers.io) {
|
||||
runCatching {
|
||||
service.isLastDevice()
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun resetRecoveryKey(): Result<String> = withContext(dispatchers.io) {
|
||||
runCatching {
|
||||
service.resetRecoveryKey()
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun fixRecoveryIssues(recoveryKey: String): Result<Unit> = withContext(dispatchers.io) {
|
||||
runCatching {
|
||||
service.fixRecoveryIssues(recoveryKey)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -33,9 +33,8 @@ import org.matrix.rustcomponents.sdk.SessionVerificationController
|
||||
import org.matrix.rustcomponents.sdk.SessionVerificationControllerDelegate
|
||||
import org.matrix.rustcomponents.sdk.SessionVerificationControllerInterface
|
||||
import org.matrix.rustcomponents.sdk.SessionVerificationEmoji
|
||||
import javax.inject.Inject
|
||||
|
||||
class RustSessionVerificationService @Inject constructor(
|
||||
class RustSessionVerificationService(
|
||||
private val syncService: RustSyncService,
|
||||
private val sessionCoroutineScope: CoroutineScope,
|
||||
) : SessionVerificationService, SessionVerificationControllerDelegate {
|
||||
|
||||
@@ -22,6 +22,7 @@ import io.element.android.libraries.matrix.api.core.RoomId
|
||||
import io.element.android.libraries.matrix.api.core.SessionId
|
||||
import io.element.android.libraries.matrix.api.core.UserId
|
||||
import io.element.android.libraries.matrix.api.createroom.CreateRoomParameters
|
||||
import io.element.android.libraries.matrix.api.encryption.EncryptionService
|
||||
import io.element.android.libraries.matrix.api.media.MatrixMediaLoader
|
||||
import io.element.android.libraries.matrix.api.notification.NotificationService
|
||||
import io.element.android.libraries.matrix.api.notificationsettings.NotificationSettingsService
|
||||
@@ -33,6 +34,7 @@ import io.element.android.libraries.matrix.api.roomlist.RoomListService
|
||||
import io.element.android.libraries.matrix.api.user.MatrixSearchUserResults
|
||||
import io.element.android.libraries.matrix.api.user.MatrixUser
|
||||
import io.element.android.libraries.matrix.api.verification.SessionVerificationService
|
||||
import io.element.android.libraries.matrix.test.encryption.FakeEncryptionService
|
||||
import io.element.android.libraries.matrix.test.media.FakeMediaLoader
|
||||
import io.element.android.libraries.matrix.test.notification.FakeNotificationService
|
||||
import io.element.android.libraries.matrix.test.notificationsettings.FakeNotificationSettingsService
|
||||
@@ -55,6 +57,7 @@ class FakeMatrixClient(
|
||||
private val notificationService: FakeNotificationService = FakeNotificationService(),
|
||||
private val notificationSettingsService: FakeNotificationSettingsService = FakeNotificationSettingsService(),
|
||||
private val syncService: FakeSyncService = FakeSyncService(),
|
||||
private val encryptionService: FakeEncryptionService = FakeEncryptionService(),
|
||||
private val accountManagementUrlString: Result<String?> = Result.success(null),
|
||||
) : MatrixClient {
|
||||
|
||||
@@ -124,9 +127,11 @@ class FakeMatrixClient(
|
||||
override suspend fun clearCache() {
|
||||
}
|
||||
|
||||
override suspend fun logout(): String? {
|
||||
override suspend fun logout(ignoreSdkError: Boolean): String? {
|
||||
delay(100)
|
||||
logoutFailure?.let { throw it }
|
||||
if (ignoreSdkError.not()) {
|
||||
logoutFailure?.let { throw it }
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
@@ -173,6 +178,7 @@ class FakeMatrixClient(
|
||||
|
||||
override fun notificationService(): NotificationService = notificationService
|
||||
override fun notificationSettingsService(): NotificationSettingsService = notificationSettingsService
|
||||
override fun encryptionService(): EncryptionService = encryptionService
|
||||
|
||||
override fun roomMembershipObserver(): RoomMembershipObserver {
|
||||
return RoomMembershipObserver()
|
||||
|
||||
@@ -72,3 +72,5 @@ const val A_FAILURE_REASON = "There has been a failure"
|
||||
|
||||
val A_THROWABLE = Throwable(A_FAILURE_REASON)
|
||||
val AN_EXCEPTION = Exception(A_FAILURE_REASON)
|
||||
|
||||
const val A_RECOVERY_KEY = "1234 5678"
|
||||
|
||||
@@ -0,0 +1,95 @@
|
||||
/*
|
||||
* 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 io.element.android.libraries.matrix.test.encryption
|
||||
|
||||
import io.element.android.libraries.matrix.api.encryption.BackupState
|
||||
import io.element.android.libraries.matrix.api.encryption.BackupUploadState
|
||||
import io.element.android.libraries.matrix.api.encryption.EnableRecoveryProgress
|
||||
import io.element.android.libraries.matrix.api.encryption.EncryptionService
|
||||
import io.element.android.libraries.matrix.api.encryption.RecoveryState
|
||||
import io.element.android.tests.testutils.simulateLongTask
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
|
||||
class FakeEncryptionService : EncryptionService {
|
||||
private var disableRecoveryFailure: Exception? = null
|
||||
override val backupStateStateFlow: MutableStateFlow<BackupState> = MutableStateFlow(BackupState.UNKNOWN)
|
||||
override val recoveryStateStateFlow: MutableStateFlow<RecoveryState> = MutableStateFlow(RecoveryState.UNKNOWN)
|
||||
override val enableRecoveryProgressStateFlow: MutableStateFlow<EnableRecoveryProgress> = MutableStateFlow(EnableRecoveryProgress.Unknown)
|
||||
override val backupUploadStateStateFlow: MutableStateFlow<BackupUploadState> = MutableStateFlow(BackupUploadState.Unknown)
|
||||
|
||||
private var fixRecoveryIssuesFailure: Exception? = null
|
||||
|
||||
override suspend fun enableBackups(): Result<Unit> = simulateLongTask {
|
||||
return Result.success(Unit)
|
||||
}
|
||||
|
||||
fun givenDisableRecoveryFailure(exception: Exception) {
|
||||
disableRecoveryFailure = exception
|
||||
}
|
||||
|
||||
fun givenFixRecoveryIssuesFailure(exception: Exception?) {
|
||||
fixRecoveryIssuesFailure = exception
|
||||
}
|
||||
|
||||
override suspend fun disableRecovery(): Result<Unit> = simulateLongTask {
|
||||
disableRecoveryFailure?.let { return Result.failure(it) }
|
||||
return Result.success(Unit)
|
||||
}
|
||||
|
||||
override suspend fun fixRecoveryIssues(recoveryKey: String): Result<Unit> = simulateLongTask {
|
||||
fixRecoveryIssuesFailure?.let { return Result.failure(it) }
|
||||
return Result.success(Unit)
|
||||
}
|
||||
|
||||
private var isLastDevice = false
|
||||
|
||||
fun givenIsLastDevice(isLastDevice: Boolean) {
|
||||
this.isLastDevice = isLastDevice
|
||||
}
|
||||
|
||||
override suspend fun isLastDevice(): Result<Boolean> {
|
||||
return Result.success(isLastDevice)
|
||||
}
|
||||
|
||||
override suspend fun resetRecoveryKey(): Result<String> = simulateLongTask {
|
||||
return Result.success(fakeRecoveryKey)
|
||||
}
|
||||
|
||||
override suspend fun enableRecovery(waitForBackupsToUpload: Boolean): Result<Unit> = simulateLongTask {
|
||||
return Result.success(Unit)
|
||||
}
|
||||
|
||||
override suspend fun waitForBackupUploadSteadyState(): Result<Unit> {
|
||||
return Result.success(Unit)
|
||||
}
|
||||
|
||||
suspend fun emitBackupUploadState(state: BackupUploadState) {
|
||||
backupUploadStateStateFlow.emit(state)
|
||||
}
|
||||
|
||||
suspend fun emitBackupState(state: BackupState) {
|
||||
backupStateStateFlow.emit(state)
|
||||
}
|
||||
|
||||
suspend fun emitEnableRecoveryProgress(state: EnableRecoveryProgress) {
|
||||
enableRecoveryProgressStateFlow.emit(state)
|
||||
}
|
||||
|
||||
companion object {
|
||||
const val fakeRecoveryKey = "fake"
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user