Improve regV5 restore flows.

This commit is contained in:
Greyson Parrelli
2026-04-15 14:12:28 -04:00
committed by jeffrey-signal
parent f1b61f8f7e
commit fcdbf93626
19 changed files with 331 additions and 164 deletions

View File

@@ -57,6 +57,7 @@ import org.thoughtcrime.securesms.registration.fcm.PushChallengeRequest
import org.thoughtcrime.securesms.registration.viewmodel.SvrAuthCredentialSet
import org.whispersystems.signalservice.api.NetworkResult
import org.whispersystems.signalservice.api.SvrNoDataException
import org.whispersystems.signalservice.api.archive.ArchiveServiceAccess
import org.whispersystems.signalservice.api.provisioning.ProvisioningSocket
import org.whispersystems.signalservice.api.svr.SecureValueRecovery.BackupResponse
import org.whispersystems.signalservice.internal.crypto.SecondaryProvisioningCipher
@@ -65,6 +66,7 @@ import org.whispersystems.signalservice.internal.push.PushServiceSocket
import java.io.IOException
import java.util.Locale
import kotlin.time.Duration
import kotlin.time.Duration.Companion.milliseconds
import kotlin.time.Duration.Companion.seconds
import org.whispersystems.signalservice.api.account.AccountAttributes as ServiceAccountAttributes
import org.whispersystems.signalservice.api.account.PreKeyCollection as ServicePreKeyCollection
@@ -536,6 +538,57 @@ class AppRegistrationNetworkController(
}
}
override suspend fun getRemoteBackupInfo(): RequestResult<NetworkController.GetBackupInfoResponse, NetworkController.GetBackupInfoError> = withContext(Dispatchers.IO) {
val aci = SignalStore.account.aci ?: return@withContext RequestResult.ApplicationError(IllegalStateException("ACI not available"))
val currentTime = System.currentTimeMillis()
val messageCredential = SignalStore.backup.messageCredentials.byDay.getForCurrentTime(currentTime.milliseconds)
val access = if (messageCredential != null) {
ArchiveServiceAccess(messageCredential, SignalStore.backup.messageBackupKey)
} else {
when (val credResult = SignalNetwork.archive.getServiceCredentials(currentTime)) {
is NetworkResult.Success -> {
SignalStore.backup.messageCredentials.add(credResult.result.messageCredentials)
SignalStore.backup.messageCredentials.clearOlderThan(currentTime)
val credential = SignalStore.backup.messageCredentials.byDay.getForCurrentTime(currentTime.milliseconds)
?: return@withContext RequestResult.ApplicationError(IllegalStateException("Failed to obtain backup credentials after fetch"))
ArchiveServiceAccess(credential, SignalStore.backup.messageBackupKey)
}
is NetworkResult.StatusCodeError -> return@withContext RequestResult.ApplicationError(IllegalStateException("Failed to fetch backup credentials: ${credResult.code}"))
is NetworkResult.NetworkError -> return@withContext RequestResult.RetryableNetworkError(credResult.exception)
is NetworkResult.ApplicationError -> return@withContext RequestResult.ApplicationError(credResult.throwable)
}
}
when (val result = SignalNetwork.archive.getBackupInfo(aci, access)) {
is NetworkResult.Success -> {
val info = result.result
RequestResult.Success(
NetworkController.GetBackupInfoResponse(
cdn = info.cdn,
backupDir = info.backupDir,
mediaDir = info.mediaDir,
backupName = info.backupName,
usedSpace = info.usedSpace
)
)
}
is NetworkResult.StatusCodeError -> {
when (result.code) {
400 -> RequestResult.NonSuccess(NetworkController.GetBackupInfoError.BadArguments(result.stringBody))
401 -> RequestResult.NonSuccess(NetworkController.GetBackupInfoError.BadAuthCredential(result.stringBody))
403 -> RequestResult.NonSuccess(NetworkController.GetBackupInfoError.Forbidden(result.stringBody))
404 -> RequestResult.NonSuccess(NetworkController.GetBackupInfoError.NoBackup)
429 -> RequestResult.NonSuccess(NetworkController.GetBackupInfoError.RateLimited(0.seconds))
else -> RequestResult.ApplicationError(IllegalStateException("Unexpected response code: ${result.code}"))
}
}
is NetworkResult.NetworkError -> RequestResult.RetryableNetworkError(result.exception)
is NetworkResult.ApplicationError -> RequestResult.ApplicationError(result.throwable)
}
}
override fun startProvisioning(): Flow<ProvisioningEvent> = callbackFlow {
val socketHandles = mutableListOf<java.io.Closeable>()
val configuration = AppDependencies.signalServiceNetworkAccess.getConfiguration()

View File

@@ -22,7 +22,6 @@ import org.signal.registration.PreExistingRegistrationData
import org.signal.registration.StorageController
import org.signal.registration.proto.RegistrationData
import org.signal.registration.screens.localbackuprestore.LocalBackupInfo
import org.signal.registration.screens.restoreselection.ArchiveRestoreOption
import org.thoughtcrime.securesms.backup.FullBackupImporter
import org.thoughtcrime.securesms.backup.v2.BackupRepository
import org.thoughtcrime.securesms.backup.v2.local.LocalArchiver
@@ -178,16 +177,6 @@ class AppRegistrationStorageController(private val context: Context) : StorageCo
Unit
}
override suspend fun getAvailableRestoreOptions(): Set<ArchiveRestoreOption> = withContext(Dispatchers.IO) {
// TODO [greyson] Real options
val options = mutableSetOf<ArchiveRestoreOption>()
options.add(ArchiveRestoreOption.LocalBackup)
options.add(ArchiveRestoreOption.DeviceTransfer)
options
}
override fun restoreLocalBackupV1(uri: Uri, passphrase: String): Flow<LocalBackupRestoreProgress> = flow {
// TODO [greyson] better progress
Log.d(TAG, "Starting V1 local backup restore from: $uri")