diff --git a/app/src/main/java/org/thoughtcrime/securesms/registration/data/network/VerificationCodeRequestResult.kt b/app/src/main/java/org/thoughtcrime/securesms/registration/data/network/VerificationCodeRequestResult.kt index 4de0b2fbdc..da5f126095 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/registration/data/network/VerificationCodeRequestResult.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/registration/data/network/VerificationCodeRequestResult.kt @@ -5,19 +5,17 @@ package org.thoughtcrime.securesms.registration.data.network -import okio.IOException import org.signal.core.util.logging.Log import org.thoughtcrime.securesms.registration.data.RegistrationRepository import org.whispersystems.signalservice.api.NetworkResult import org.whispersystems.signalservice.api.push.exceptions.AlreadyVerifiedException -import org.whispersystems.signalservice.api.push.exceptions.CaptchaRequiredException +import org.whispersystems.signalservice.api.push.exceptions.ChallengeRequiredException import org.whispersystems.signalservice.api.push.exceptions.ExternalServiceFailureException import org.whispersystems.signalservice.api.push.exceptions.ImpossiblePhoneNumberException import org.whispersystems.signalservice.api.push.exceptions.InvalidTransportModeException import org.whispersystems.signalservice.api.push.exceptions.MalformedRequestException import org.whispersystems.signalservice.api.push.exceptions.NoSuchSessionException import org.whispersystems.signalservice.api.push.exceptions.NonNormalizedPhoneNumberException -import org.whispersystems.signalservice.api.push.exceptions.PushChallengeRequiredException import org.whispersystems.signalservice.api.push.exceptions.RateLimitException import org.whispersystems.signalservice.api.push.exceptions.RegistrationRetryException import org.whispersystems.signalservice.api.push.exceptions.TokenNotAcceptedException @@ -26,7 +24,6 @@ import org.whispersystems.signalservice.internal.push.AuthCredentials import org.whispersystems.signalservice.internal.push.LockedException import org.whispersystems.signalservice.internal.push.RegistrationSessionMetadataJson import org.whispersystems.signalservice.internal.push.RegistrationSessionMetadataResponse -import org.whispersystems.signalservice.internal.util.JsonUtil /** * This is a processor to map a [RegistrationSessionMetadataResponse] to all the known outcomes. @@ -61,8 +58,7 @@ sealed class VerificationCodeRequestResult(cause: Throwable?) : RegistrationResu is NetworkResult.NetworkError -> UnknownError(networkResult.exception) is NetworkResult.StatusCodeError -> { when (val cause = networkResult.exception) { - is PushChallengeRequiredException -> createChallengeRequiredProcessor(networkResult) - is CaptchaRequiredException -> createChallengeRequiredProcessor(networkResult) + is ChallengeRequiredException -> createChallengeRequiredProcessor(cause.response) is RateLimitException -> createRateLimitProcessor(cause) is ImpossiblePhoneNumberException -> ImpossibleNumber(cause) is NonNormalizedPhoneNumberException -> NonNormalizedNumber(cause = cause, originalNumber = cause.originalNumber, normalizedNumber = cause.normalizedNumber) @@ -80,19 +76,8 @@ sealed class VerificationCodeRequestResult(cause: Throwable?) : RegistrationResu } } - private fun createChallengeRequiredProcessor(errorResult: NetworkResult.StatusCodeError): VerificationCodeRequestResult { - if (errorResult.stringBody == null) { - Log.w(TAG, "Attempted to parse error body with response code ${errorResult.code} for list of requested information, but body was null.") - return UnknownError(errorResult.exception) - } - - try { - val response = JsonUtil.fromJson(errorResult.stringBody, RegistrationSessionMetadataJson::class.java) - return ChallengeRequired(Challenge.parse(response.requestedInformation)) - } catch (parseException: IOException) { - Log.w(TAG, "Attempted to parse error body for list of requested information, but encountered exception.", parseException) - return UnknownError(parseException) - } + private fun createChallengeRequiredProcessor(response: RegistrationSessionMetadataJson): VerificationCodeRequestResult { + return ChallengeRequired(Challenge.parse(response.requestedInformation)) } private fun createRateLimitProcessor(exception: RateLimitException): VerificationCodeRequestResult { diff --git a/libsignal-service/src/main/java/org/whispersystems/signalservice/api/push/exceptions/CaptchaRequiredException.java b/libsignal-service/src/main/java/org/whispersystems/signalservice/api/push/exceptions/CaptchaRequiredException.java deleted file mode 100644 index 87852c02c9..0000000000 --- a/libsignal-service/src/main/java/org/whispersystems/signalservice/api/push/exceptions/CaptchaRequiredException.java +++ /dev/null @@ -1,7 +0,0 @@ -package org.whispersystems.signalservice.api.push.exceptions; - -public class CaptchaRequiredException extends NonSuccessfulResponseCodeException { - public CaptchaRequiredException() { - super(402); - } -} diff --git a/libsignal-service/src/main/java/org/whispersystems/signalservice/api/push/exceptions/ChallengeRequiredException.kt b/libsignal-service/src/main/java/org/whispersystems/signalservice/api/push/exceptions/ChallengeRequiredException.kt new file mode 100644 index 0000000000..93b74f8727 --- /dev/null +++ b/libsignal-service/src/main/java/org/whispersystems/signalservice/api/push/exceptions/ChallengeRequiredException.kt @@ -0,0 +1,14 @@ +/* + * Copyright 2025 Signal Messenger, LLC + * SPDX-License-Identifier: AGPL-3.0-only + */ + +package org.whispersystems.signalservice.api.push.exceptions + +import org.whispersystems.signalservice.internal.push.RegistrationSessionMetadataJson + +/** + * We tried to do something on registration endpoints that didn't go well, so now we have to do a challenge. And not a + * fun one involving ice buckets. + */ +class ChallengeRequiredException(val response: RegistrationSessionMetadataJson) : NonSuccessfulResponseCodeException(409) diff --git a/libsignal-service/src/main/java/org/whispersystems/signalservice/api/push/exceptions/PushChallengeRequiredException.kt b/libsignal-service/src/main/java/org/whispersystems/signalservice/api/push/exceptions/PushChallengeRequiredException.kt deleted file mode 100644 index 343116afd8..0000000000 --- a/libsignal-service/src/main/java/org/whispersystems/signalservice/api/push/exceptions/PushChallengeRequiredException.kt +++ /dev/null @@ -1,3 +0,0 @@ -package org.whispersystems.signalservice.api.push.exceptions - -class PushChallengeRequiredException : NonSuccessfulResponseCodeException(409) diff --git a/libsignal-service/src/main/java/org/whispersystems/signalservice/internal/push/PushServiceSocket.java b/libsignal-service/src/main/java/org/whispersystems/signalservice/internal/push/PushServiceSocket.java index aeb37fb43e..55080238af 100644 --- a/libsignal-service/src/main/java/org/whispersystems/signalservice/internal/push/PushServiceSocket.java +++ b/libsignal-service/src/main/java/org/whispersystems/signalservice/internal/push/PushServiceSocket.java @@ -84,7 +84,7 @@ import org.whispersystems.signalservice.api.push.SignalServiceAddress; import org.whispersystems.signalservice.api.push.SignedPreKeyEntity; import org.whispersystems.signalservice.api.push.exceptions.AlreadyVerifiedException; import org.whispersystems.signalservice.api.push.exceptions.AuthorizationFailedException; -import org.whispersystems.signalservice.api.push.exceptions.CaptchaRequiredException; +import org.whispersystems.signalservice.api.push.exceptions.ChallengeRequiredException; import org.whispersystems.signalservice.api.push.exceptions.ConflictException; import org.whispersystems.signalservice.api.push.exceptions.ContactManifestMismatchException; import org.whispersystems.signalservice.api.push.exceptions.DeprecatedVersionException; @@ -103,7 +103,6 @@ import org.whispersystems.signalservice.api.push.exceptions.NonSuccessfulRespons import org.whispersystems.signalservice.api.push.exceptions.NonSuccessfulResumableUploadResponseCodeException; import org.whispersystems.signalservice.api.push.exceptions.NotFoundException; import org.whispersystems.signalservice.api.push.exceptions.ProofRequiredException; -import org.whispersystems.signalservice.api.push.exceptions.PushChallengeRequiredException; import org.whispersystems.signalservice.api.push.exceptions.PushNetworkException; import org.whispersystems.signalservice.api.push.exceptions.RangeException; import org.whispersystems.signalservice.api.push.exceptions.RateLimitException; @@ -3155,10 +3154,8 @@ public class PushServiceSocket { } if (response.getVerified()) { throw new AlreadyVerifiedException(); - } else if (response.pushChallengedRequired()) { - throw new PushChallengeRequiredException(); - } else if (response.captchaRequired()) { - throw new CaptchaRequiredException(); + } else if (response.pushChallengedRequired() || response.captchaRequired()) { + throw new ChallengeRequiredException(response); } else { Log.i(TAG, "Received 409 in reg session handler that is not verified, with required information: " + String.join(", ", response.getRequestedInformation())); throw new HttpConflictException(); @@ -3198,10 +3195,8 @@ public class PushServiceSocket { } if (response.getVerified()) { throw new AlreadyVerifiedException(); - } else if (response.pushChallengedRequired()) { - throw new PushChallengeRequiredException(); - } else if (response.captchaRequired()) { - throw new CaptchaRequiredException(); + } else if (response.pushChallengedRequired() || response.captchaRequired()) { + throw new ChallengeRequiredException(response); } else { Log.i(TAG, "Received 409 in for reg code request that is not verified, with required information: " + String.join(", ", response.getRequestedInformation())); throw new HttpConflictException(); @@ -3243,10 +3238,8 @@ public class PushServiceSocket { } if (response.getVerified()) { throw new AlreadyVerifiedException(); - } else if (response.pushChallengedRequired()) { - throw new PushChallengeRequiredException(); - } else if (response.captchaRequired()) { - throw new CaptchaRequiredException(); + } else if (response.pushChallengedRequired() || response.captchaRequired()) { + throw new ChallengeRequiredException(response); } else { Log.i(TAG, "Received 409 for patching reg session that is not verified, with required information: " + String.join(", ", response.getRequestedInformation())); throw new HttpConflictException(); diff --git a/libsignal-service/src/main/java/org/whispersystems/signalservice/internal/websocket/DefaultErrorMapper.java b/libsignal-service/src/main/java/org/whispersystems/signalservice/internal/websocket/DefaultErrorMapper.java index d90c919720..a83fea1fbc 100644 --- a/libsignal-service/src/main/java/org/whispersystems/signalservice/internal/websocket/DefaultErrorMapper.java +++ b/libsignal-service/src/main/java/org/whispersystems/signalservice/internal/websocket/DefaultErrorMapper.java @@ -3,7 +3,6 @@ package org.whispersystems.signalservice.internal.websocket; import org.whispersystems.signalservice.api.push.exceptions.AuthorizationFailedException; -import org.whispersystems.signalservice.api.push.exceptions.CaptchaRequiredException; import org.whispersystems.signalservice.api.push.exceptions.DeprecatedVersionException; import org.whispersystems.signalservice.api.push.exceptions.ExpectationFailedException; import org.whispersystems.signalservice.api.push.exceptions.MalformedResponseException; @@ -12,7 +11,6 @@ import org.whispersystems.signalservice.api.push.exceptions.NotFoundException; import org.whispersystems.signalservice.api.push.exceptions.ProofRequiredException; import org.whispersystems.signalservice.api.push.exceptions.RateLimitException; import org.whispersystems.signalservice.api.push.exceptions.ServerRejectedException; -import org.whispersystems.signalservice.internal.push.AuthCredentials; import org.whispersystems.signalservice.internal.push.DeviceLimit; import org.whispersystems.signalservice.internal.push.DeviceLimitExceededException; import org.whispersystems.signalservice.internal.push.LockedException; @@ -81,8 +79,6 @@ public final class DefaultErrorMapper implements ErrorMapper { case 401: case 403: return new AuthorizationFailedException(status, "Authorization failed!"); - case 402: - return new CaptchaRequiredException(); case 404: return new NotFoundException("Not found"); case 409: