mirror of
https://github.com/signalapp/Signal-Android.git
synced 2026-07-25 15:34:49 +01:00
Update SVRB error handling.
This commit is contained in:
committed by
Jeffrey Starke
parent
03c6094ea3
commit
dfdadc9d7a
@@ -2090,15 +2090,23 @@ object BackupRepository {
|
||||
result.data.forwardSecrecyToken
|
||||
}
|
||||
is SvrBApi.RestoreResult.NetworkError -> {
|
||||
return RemoteRestoreResult.NetworkError.logW(TAG, "[remoteRestore] Network error during SVRB.", result.exception)
|
||||
Log.w(TAG, "[remoteRestore] Network error during SVRB.", result.exception)
|
||||
return RemoteRestoreResult.NetworkError
|
||||
}
|
||||
is SvrBApi.RestoreResult.RestoreFailedError,
|
||||
SvrBApi.RestoreResult.InvalidDataError -> {
|
||||
Log.w(TAG, "[remoteRestore] Permanent SVRB error! $result")
|
||||
return RemoteRestoreResult.PermanentSvrBFailure
|
||||
}
|
||||
SvrBApi.RestoreResult.DataMissingError,
|
||||
is SvrBApi.RestoreResult.RestoreFailedError,
|
||||
is SvrBApi.RestoreResult.SvrError,
|
||||
is SvrBApi.RestoreResult.UnknownError -> {
|
||||
is SvrBApi.RestoreResult.SvrError -> {
|
||||
Log.w(TAG, "[remoteRestore] Failed to fetch SVRB data: $result")
|
||||
return RemoteRestoreResult.Failure
|
||||
}
|
||||
is SvrBApi.RestoreResult.UnknownError -> {
|
||||
Log.e(TAG, "[remoteRestore] Unknown SVRB result! Crashing.", result.throwable)
|
||||
throw result.throwable
|
||||
}
|
||||
}
|
||||
|
||||
val self = Recipient.self()
|
||||
|
||||
+1
-1
@@ -249,7 +249,7 @@ class InternalBackupPlaygroundViewModel : ViewModel() {
|
||||
|
||||
val forwardSecrecyToken = when (val result = SignalNetwork.svrB.restore(svrBAuth, SignalStore.backup.messageBackupKey, forwardSecrecyMetadata)) {
|
||||
is SvrBApi.RestoreResult.Success -> result.data.forwardSecrecyToken
|
||||
else -> throw IOException("Failed to read forward secrecy metadata!")
|
||||
else -> throw IOException("Failed to read forward secrecy metadata! $result")
|
||||
}
|
||||
|
||||
val encryptedStream = tempBackupFile.inputStream().apply {
|
||||
|
||||
@@ -166,8 +166,13 @@ class BackupMessagesJob private constructor(
|
||||
|
||||
val svrBMetadata: SvrBStoreResponse = when (val result = SignalNetwork.svrB.store(auth, SignalStore.backup.messageBackupKey, backupSecretData)) {
|
||||
is SvrBApi.StoreResult.Success -> result.data
|
||||
is SvrBApi.StoreResult.NetworkError -> return Result.retry(defaultBackoff()).logW(TAG, "SVRB transient network error.", result.exception)
|
||||
is SvrBApi.StoreResult.NetworkError -> return Result.retry(result.retryAfter?.inWholeMilliseconds ?: defaultBackoff()).logW(TAG, "SVRB transient network error.", result.exception)
|
||||
is SvrBApi.StoreResult.SvrError -> return Result.retry(defaultBackoff()).logW(TAG, "SVRB error.", result.throwable)
|
||||
SvrBApi.StoreResult.InvalidDataError -> {
|
||||
Log.w(TAG, "Invalid SVRB data on the server! Clearing backup secret data and retrying.")
|
||||
SignalStore.backup.nextBackupSecretData = null
|
||||
return Result.retry(defaultBackoff())
|
||||
}
|
||||
is SvrBApi.StoreResult.UnknownError -> return Result.fatalFailure(RuntimeException(result.throwable))
|
||||
}
|
||||
|
||||
|
||||
+48
-26
@@ -5,24 +5,28 @@
|
||||
|
||||
package org.whispersystems.signalservice.api.svr
|
||||
|
||||
import org.signal.libsignal.attest.AttestationDataException
|
||||
import org.signal.libsignal.attest.AttestationFailedException
|
||||
import org.signal.libsignal.internal.CompletableFuture
|
||||
import org.signal.libsignal.messagebackup.BackupKey
|
||||
import org.signal.libsignal.net.Network
|
||||
import org.signal.libsignal.net.NetworkException
|
||||
import org.signal.libsignal.net.NetworkProtocolException
|
||||
import org.signal.libsignal.net.RetryLaterException
|
||||
import org.signal.libsignal.net.SvrB
|
||||
import org.signal.libsignal.net.SvrBRestoreResponse
|
||||
import org.signal.libsignal.net.SvrBStoreResponse
|
||||
import org.signal.libsignal.sgxsession.SgxCommunicationFailureException
|
||||
import org.signal.libsignal.svr.DataMissingException
|
||||
import org.signal.libsignal.svr.InvalidSvrBDataException
|
||||
import org.signal.libsignal.svr.RestoreFailedException
|
||||
import org.signal.libsignal.svr.SvrException
|
||||
import org.whispersystems.signalservice.api.CancelationException
|
||||
import org.whispersystems.signalservice.api.NetworkResult
|
||||
import org.whispersystems.signalservice.api.backup.MessageBackupKey
|
||||
import org.whispersystems.signalservice.internal.push.AuthCredentials
|
||||
import java.io.IOException
|
||||
import java.util.concurrent.ExecutionException
|
||||
import kotlin.time.Duration
|
||||
import kotlin.time.toKotlinDuration
|
||||
|
||||
/**
|
||||
* A collection of operations for interacting with SVRB, the SVR enclave that provides forward secrecy for backups.
|
||||
@@ -58,9 +62,13 @@ class SvrBApi(private val network: Network) {
|
||||
|
||||
when (val exception = result.exceptionOrNull()) {
|
||||
null -> StoreResult.Success(result.getOrThrow())
|
||||
is InvalidSvrBDataException -> StoreResult.InvalidDataError
|
||||
is RetryLaterException -> StoreResult.NetworkError(IOException(exception), exception.duration.toKotlinDuration())
|
||||
is NetworkException -> StoreResult.NetworkError(exception)
|
||||
is NetworkProtocolException -> StoreResult.NetworkError(exception)
|
||||
is SvrException -> StoreResult.SvrError(exception)
|
||||
is AttestationFailedException,
|
||||
is AttestationDataException,
|
||||
is SgxCommunicationFailureException -> StoreResult.SvrError(exception)
|
||||
else -> StoreResult.UnknownError(exception)
|
||||
}
|
||||
} catch (e: CancelationException) {
|
||||
@@ -88,12 +96,15 @@ class SvrBApi(private val network: Network) {
|
||||
|
||||
when (val exception = result.exceptionOrNull()) {
|
||||
null -> RestoreResult.Success(result.getOrThrow())
|
||||
is InvalidSvrBDataException -> RestoreResult.InvalidDataError
|
||||
is RestoreFailedException -> RestoreResult.RestoreFailedError(exception.triesRemaining)
|
||||
is DataMissingException -> RestoreResult.DataMissingError
|
||||
is RetryLaterException -> RestoreResult.NetworkError(okio.IOException(exception), exception.duration.toKotlinDuration())
|
||||
is NetworkException -> RestoreResult.NetworkError(exception)
|
||||
is NetworkProtocolException -> RestoreResult.NetworkError(exception)
|
||||
is DataMissingException -> RestoreResult.DataMissingError
|
||||
is RestoreFailedException -> RestoreResult.RestoreFailedError(exception.triesRemaining)
|
||||
is SvrException -> RestoreResult.SvrError(exception)
|
||||
is AttestationFailedException -> RestoreResult.SvrError(exception)
|
||||
is AttestationFailedException,
|
||||
is AttestationDataException,
|
||||
is SgxCommunicationFailureException -> RestoreResult.SvrError(exception)
|
||||
else -> RestoreResult.UnknownError(exception)
|
||||
}
|
||||
} catch (e: CancelationException) {
|
||||
@@ -105,36 +116,47 @@ class SvrBApi(private val network: Network) {
|
||||
}
|
||||
}
|
||||
|
||||
private fun <ResultType, FinalType> CompletableFuture<Result<ResultType>>.toNetworkResult(resultMapper: (Result<ResultType>) -> FinalType): NetworkResult<FinalType> {
|
||||
return try {
|
||||
val result = this.get()
|
||||
return when (val exception = result.exceptionOrNull()) {
|
||||
is NetworkException -> NetworkResult.NetworkError(exception)
|
||||
is NetworkProtocolException -> NetworkResult.NetworkError(exception)
|
||||
else -> NetworkResult.Success(resultMapper(result))
|
||||
}
|
||||
} catch (e: CancelationException) {
|
||||
NetworkResult.Success(resultMapper(Result.failure(e)))
|
||||
} catch (e: ExecutionException) {
|
||||
NetworkResult.Success(resultMapper(Result.failure(e)))
|
||||
} catch (e: InterruptedException) {
|
||||
NetworkResult.Success(resultMapper(Result.failure(e)))
|
||||
}
|
||||
}
|
||||
|
||||
sealed class StoreResult {
|
||||
/** Operation succeeded. */
|
||||
data class Success(val data: SvrBStoreResponse) : StoreResult()
|
||||
data class NetworkError(val exception: IOException) : StoreResult()
|
||||
|
||||
/** Indicates the the existing data is unreadable, and you need to start a new chain from the beginning. */
|
||||
data object InvalidDataError : StoreResult()
|
||||
|
||||
/** A retryable network error. */
|
||||
data class NetworkError(val exception: IOException, val retryAfter: Duration? = null) : StoreResult()
|
||||
|
||||
/** Indicates an issue with the enclave that is outside of our control. We should fail the operation or use a long backoff. */
|
||||
data class SvrError(val throwable: Throwable) : StoreResult()
|
||||
|
||||
/** Undocumented error. Crashing recommended. */
|
||||
data class UnknownError(val throwable: Throwable) : StoreResult()
|
||||
}
|
||||
|
||||
sealed class RestoreResult {
|
||||
/** Operation succeeded. */
|
||||
data class Success(val data: SvrBRestoreResponse) : RestoreResult()
|
||||
data class NetworkError(val exception: IOException) : RestoreResult()
|
||||
|
||||
/** A retryable network error. */
|
||||
data class NetworkError(val exception: IOException, val retryAfter: Duration? = null) : RestoreResult()
|
||||
|
||||
/** No data could be found. This could indicate the user entered their AEP incorrectly. */
|
||||
data object DataMissingError : RestoreResult()
|
||||
|
||||
/** Indicate thee existing data is malformed and therefore unrecoverable. */
|
||||
data object InvalidDataError : RestoreResult()
|
||||
|
||||
/**
|
||||
* Indicates the data was found, but we had the wrong passphrase. While there is a "tries remaining", in practice, this means the data is
|
||||
* unrecoverable. We wouldn't get here unless the AEP mapped to a real backup (since that's required to get the backupId), so if we're discovering
|
||||
* the passphrase is wrong at this point, it means that an unrecoverable error was made in the past when creating the backup.
|
||||
*/
|
||||
data class RestoreFailedError(val triesRemaining: Int) : RestoreResult()
|
||||
|
||||
/** Indicates an issue with the enclave that is outside of our control. We should fail the operation or use a long backoff. */
|
||||
data class SvrError(val throwable: Throwable) : RestoreResult()
|
||||
|
||||
/** Undocumented error. Crashing recommended. */
|
||||
data class UnknownError(val throwable: Throwable) : RestoreResult()
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user