mirror of
https://github.com/signalapp/Signal-Android.git
synced 2026-04-24 02:39:55 +01:00
Fix multiple bugs and erroneous sad path handling in registration flows.
This commit is contained in:
@@ -302,7 +302,7 @@ object RegistrationRepository {
|
||||
val result = RegistrationSessionCreationResult.from(registrationSessionResult)
|
||||
if (result is RegistrationSessionCreationResult.Success) {
|
||||
Log.d(TAG, "Updating registration session and E164 in value store.")
|
||||
SignalStore.registration.sessionId = result.getMetadata().body.id
|
||||
SignalStore.registration.sessionId = result.getMetadata().metadata.id
|
||||
SignalStore.registration.sessionE164 = e164
|
||||
}
|
||||
|
||||
@@ -467,8 +467,8 @@ object RegistrationRepository {
|
||||
if (receivedPush) {
|
||||
val challenge = subscriber.challenge
|
||||
if (challenge != null) {
|
||||
Log.w(TAG, "Push challenge token received.")
|
||||
return@withContext accountManager.submitPushChallengeToken(sessionCreationResponse.result.body.id, challenge)
|
||||
Log.i(TAG, "Push challenge token received.")
|
||||
return@withContext accountManager.submitPushChallengeToken(sessionCreationResponse.result.metadata.id, challenge)
|
||||
} else {
|
||||
Log.w(TAG, "Push received but challenge token was null.")
|
||||
}
|
||||
@@ -489,7 +489,7 @@ object RegistrationRepository {
|
||||
return 0L
|
||||
}
|
||||
|
||||
val timestamp: Long = headers.timestamp
|
||||
val timestamp: Long = headers.serverDeliveredTimestamp
|
||||
return timestamp + deltaSeconds.seconds.inWholeMilliseconds
|
||||
}
|
||||
|
||||
|
||||
@@ -48,17 +48,17 @@ import org.thoughtcrime.securesms.registration.data.network.RegistrationSessionC
|
||||
import org.thoughtcrime.securesms.registration.data.network.RegistrationSessionResult
|
||||
import org.thoughtcrime.securesms.registration.data.network.VerificationCodeRequestResult
|
||||
import org.thoughtcrime.securesms.registration.data.network.VerificationCodeRequestResult.AlreadyVerified
|
||||
import org.thoughtcrime.securesms.registration.data.network.VerificationCodeRequestResult.AttemptsExhausted
|
||||
import org.thoughtcrime.securesms.registration.data.network.VerificationCodeRequestResult.ChallengeRequired
|
||||
import org.thoughtcrime.securesms.registration.data.network.VerificationCodeRequestResult.ExternalServiceFailure
|
||||
import org.thoughtcrime.securesms.registration.data.network.VerificationCodeRequestResult.ImpossibleNumber
|
||||
import org.thoughtcrime.securesms.registration.data.network.VerificationCodeRequestResult.InvalidTransportModeFailure
|
||||
import org.thoughtcrime.securesms.registration.data.network.VerificationCodeRequestResult.MalformedRequest
|
||||
import org.thoughtcrime.securesms.registration.data.network.VerificationCodeRequestResult.MustRetry
|
||||
import org.thoughtcrime.securesms.registration.data.network.VerificationCodeRequestResult.NoSuchSession
|
||||
import org.thoughtcrime.securesms.registration.data.network.VerificationCodeRequestResult.NonNormalizedNumber
|
||||
import org.thoughtcrime.securesms.registration.data.network.VerificationCodeRequestResult.RateLimited
|
||||
import org.thoughtcrime.securesms.registration.data.network.VerificationCodeRequestResult.RegistrationLocked
|
||||
import org.thoughtcrime.securesms.registration.data.network.VerificationCodeRequestResult.RequestVerificationCodeRateLimited
|
||||
import org.thoughtcrime.securesms.registration.data.network.VerificationCodeRequestResult.SubmitVerificationCodeRateLimited
|
||||
import org.thoughtcrime.securesms.registration.data.network.VerificationCodeRequestResult.Success
|
||||
import org.thoughtcrime.securesms.registration.data.network.VerificationCodeRequestResult.TokenNotAccepted
|
||||
import org.thoughtcrime.securesms.registration.data.network.VerificationCodeRequestResult.UnknownError
|
||||
@@ -277,26 +277,26 @@ class RegistrationViewModel : ViewModel() {
|
||||
|
||||
val validSession = getOrCreateValidSession(context) ?: return@launch bail { Log.i(TAG, "Could not create valid session for confirming the entered E164.") }
|
||||
|
||||
if (validSession.body.verified) {
|
||||
if (validSession.metadata.verified) {
|
||||
Log.i(TAG, "Session is already verified, registering account.")
|
||||
registerVerifiedSession(context, validSession.body.id)
|
||||
registerVerifiedSession(context, validSession.metadata.id)
|
||||
return@launch
|
||||
}
|
||||
|
||||
if (!validSession.body.allowedToRequestCode) {
|
||||
if (System.currentTimeMillis() > (validSession.body.nextVerificationAttempt ?: Int.MAX_VALUE)) {
|
||||
if (!validSession.metadata.allowedToRequestCode) {
|
||||
if (System.currentTimeMillis() > (validSession.metadata.nextVerificationAttempt ?: Int.MAX_VALUE)) {
|
||||
store.update {
|
||||
it.copy(registrationCheckpoint = RegistrationCheckpoint.VERIFICATION_CODE_REQUESTED)
|
||||
}
|
||||
} else {
|
||||
val challenges = validSession.body.requestedInformation
|
||||
val challenges = validSession.metadata.requestedInformation
|
||||
Log.i(TAG, "Not allowed to request code! Remaining challenges: ${challenges.joinToString()}")
|
||||
handleSessionStateResult(context, ChallengeRequired(Challenge.parse(validSession.body.requestedInformation)))
|
||||
handleSessionStateResult(context, ChallengeRequired(Challenge.parse(validSession.metadata.requestedInformation)))
|
||||
}
|
||||
return@launch
|
||||
}
|
||||
|
||||
requestSmsCodeInternal(context, validSession.body.id, e164)
|
||||
requestSmsCodeInternal(context, validSession.metadata.id, e164)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -305,7 +305,7 @@ class RegistrationViewModel : ViewModel() {
|
||||
|
||||
viewModelScope.launch {
|
||||
val validSession = getOrCreateValidSession(context) ?: return@launch bail { Log.i(TAG, "Could not create valid session for requesting an SMS code.") }
|
||||
requestSmsCodeInternal(context, validSession.body.id, e164)
|
||||
requestSmsCodeInternal(context, validSession.metadata.id, e164)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -323,7 +323,7 @@ class RegistrationViewModel : ViewModel() {
|
||||
Log.d(TAG, "Requesting voice call code…")
|
||||
val codeRequestResponse = RegistrationRepository.requestSmsCode(
|
||||
context = context,
|
||||
sessionId = validSession.body.id,
|
||||
sessionId = validSession.metadata.id,
|
||||
e164 = e164,
|
||||
password = password,
|
||||
mode = RegistrationRepository.E164VerificationMode.PHONE_CALL
|
||||
@@ -397,13 +397,13 @@ class RegistrationViewModel : ViewModel() {
|
||||
successListener = { networkResult ->
|
||||
store.update {
|
||||
it.copy(
|
||||
sessionId = networkResult.body.id,
|
||||
nextSmsTimestamp = RegistrationRepository.deriveTimestamp(networkResult.headers, networkResult.body.nextSms),
|
||||
nextCallTimestamp = RegistrationRepository.deriveTimestamp(networkResult.headers, networkResult.body.nextCall),
|
||||
nextVerificationAttempt = RegistrationRepository.deriveTimestamp(networkResult.headers, networkResult.body.nextVerificationAttempt),
|
||||
allowedToRequestCode = networkResult.body.allowedToRequestCode,
|
||||
challengesRequested = Challenge.parse(networkResult.body.requestedInformation),
|
||||
verified = networkResult.body.verified
|
||||
sessionId = networkResult.metadata.id,
|
||||
nextSmsTimestamp = RegistrationRepository.deriveTimestamp(networkResult.headers, networkResult.metadata.nextSms),
|
||||
nextCallTimestamp = RegistrationRepository.deriveTimestamp(networkResult.headers, networkResult.metadata.nextCall),
|
||||
nextVerificationAttempt = RegistrationRepository.deriveTimestamp(networkResult.headers, networkResult.metadata.nextVerificationAttempt),
|
||||
allowedToRequestCode = networkResult.metadata.allowedToRequestCode,
|
||||
challengesRequested = Challenge.parse(networkResult.metadata.requestedInformation),
|
||||
verified = networkResult.metadata.verified
|
||||
)
|
||||
}
|
||||
},
|
||||
@@ -430,7 +430,7 @@ class RegistrationViewModel : ViewModel() {
|
||||
viewModelScope.launch {
|
||||
val session = getOrCreateValidSession(context) ?: return@launch bail { Log.i(TAG, "Could not create valid session for submitting a captcha token.") }
|
||||
Log.d(TAG, "Submitting captcha token…")
|
||||
val captchaSubmissionResult = RegistrationRepository.submitCaptchaToken(context, e164, password, session.body.id, captchaToken)
|
||||
val captchaSubmissionResult = RegistrationRepository.submitCaptchaToken(context, e164, password, session.metadata.id, captchaToken)
|
||||
Log.d(TAG, "Captcha token submitted.")
|
||||
|
||||
handleSessionStateResult(context, captchaSubmissionResult)
|
||||
@@ -448,12 +448,12 @@ class RegistrationViewModel : ViewModel() {
|
||||
Log.d(TAG, "Getting session in order to perform push token verification…")
|
||||
val session = getOrCreateValidSession(context) ?: return@launch bail { Log.i(TAG, "Could not create valid session for submitting a push challenge token.") }
|
||||
|
||||
if (!Challenge.parse(session.body.requestedInformation).contains(Challenge.PUSH)) {
|
||||
if (!Challenge.parse(session.metadata.requestedInformation).contains(Challenge.PUSH)) {
|
||||
return@launch bail { Log.i(TAG, "Push challenge token no longer needed, bailing.") }
|
||||
}
|
||||
|
||||
Log.d(TAG, "Requesting push challenge token…")
|
||||
val pushSubmissionResult = RegistrationRepository.requestAndVerifyPushToken(context, session.body.id, e164, password)
|
||||
val pushSubmissionResult = RegistrationRepository.requestAndVerifyPushToken(context, session.metadata.id, e164, password)
|
||||
Log.d(TAG, "Push challenge token submitted.")
|
||||
handleSessionStateResult(context, pushSubmissionResult)
|
||||
}
|
||||
@@ -495,8 +495,6 @@ class RegistrationViewModel : ViewModel() {
|
||||
return false
|
||||
}
|
||||
|
||||
is AttemptsExhausted -> Log.i(TAG, "Received AttemptsExhausted.", sessionResult.getCause())
|
||||
|
||||
is ImpossibleNumber -> Log.i(TAG, "Received ImpossibleNumber.", sessionResult.getCause())
|
||||
|
||||
is NonNormalizedNumber -> Log.i(TAG, "Received NonNormalizedNumber.", sessionResult.getCause())
|
||||
@@ -509,7 +507,24 @@ class RegistrationViewModel : ViewModel() {
|
||||
|
||||
is MalformedRequest -> Log.i(TAG, "Received MalformedRequest.", sessionResult.getCause())
|
||||
|
||||
is MustRetry -> Log.i(TAG, "Received MustRetry.", sessionResult.getCause())
|
||||
is RequestVerificationCodeRateLimited -> {
|
||||
Log.i(TAG, "Received RequestVerificationCodeRateLimited.", sessionResult.getCause())
|
||||
|
||||
if (sessionResult.willBeAbleToRequestAgain) {
|
||||
store.update {
|
||||
it.copy(
|
||||
nextSmsTimestamp = sessionResult.nextSmsTimestamp,
|
||||
nextCallTimestamp = sessionResult.nextCallTimestamp
|
||||
)
|
||||
}
|
||||
} else {
|
||||
Log.w(TAG, "Request verification code rate limit is forever, need to start new session")
|
||||
SignalStore.registration.sessionId = null
|
||||
store.update { RegistrationState() }
|
||||
}
|
||||
}
|
||||
|
||||
is SubmitVerificationCodeRateLimited -> Log.i(TAG, "Received SubmitVerificationCodeRateLimited.", sessionResult.getCause())
|
||||
|
||||
is TokenNotAccepted -> Log.i(TAG, "Received TokenNotAccepted.", sessionResult.getCause())
|
||||
|
||||
@@ -527,8 +542,8 @@ class RegistrationViewModel : ViewModel() {
|
||||
|
||||
store.update {
|
||||
it.copy(
|
||||
sessionStateError = sessionResult,
|
||||
inProgress = false
|
||||
inProgress = false,
|
||||
sessionStateError = sessionResult
|
||||
)
|
||||
}
|
||||
return false
|
||||
@@ -577,8 +592,8 @@ class RegistrationViewModel : ViewModel() {
|
||||
}
|
||||
store.update {
|
||||
it.copy(
|
||||
registerAccountError = registrationResult,
|
||||
inProgress = stayInProgress
|
||||
inProgress = stayInProgress,
|
||||
registerAccountError = registrationResult
|
||||
)
|
||||
}
|
||||
return false
|
||||
@@ -748,7 +763,7 @@ class RegistrationViewModel : ViewModel() {
|
||||
|
||||
var reglock = registrationLocked
|
||||
|
||||
val sessionId = getOrCreateValidSession(context)?.body?.id ?: return
|
||||
val sessionId = getOrCreateValidSession(context)?.metadata?.id ?: return
|
||||
val registrationData = getRegistrationData()
|
||||
|
||||
Log.d(TAG, "Submitting verification code…")
|
||||
@@ -818,8 +833,22 @@ class RegistrationViewModel : ViewModel() {
|
||||
private suspend fun registerVerifiedSession(context: Context, sessionId: String) {
|
||||
Log.v(TAG, "registerVerifiedSession()")
|
||||
val registrationData = getRegistrationData()
|
||||
val registrationResponse: RegisterAccountResult = RegistrationRepository.registerAccount(context, sessionId, registrationData)
|
||||
handleRegistrationResult(context, registrationData, registrationResponse, false)
|
||||
val registrationResult: RegisterAccountResult = RegistrationRepository.registerAccount(context = context, sessionId = sessionId, registrationData = registrationData)
|
||||
|
||||
val reglockEnabled = if (registrationResult is RegisterAccountResult.RegistrationLocked) {
|
||||
Log.i(TAG, "Received a registration lock response when trying to register verified session. Retrying with master key.")
|
||||
store.update {
|
||||
it.copy(
|
||||
svr2AuthCredentials = registrationResult.svr2Credentials,
|
||||
svr3AuthCredentials = registrationResult.svr3Credentials
|
||||
)
|
||||
}
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
|
||||
handleRegistrationResult(context, registrationData, registrationResult, reglockEnabled)
|
||||
}
|
||||
|
||||
private suspend fun onSuccessfulRegistration(context: Context, registrationData: RegistrationData, remoteResult: AccountRegistrationResult, reglockEnabled: Boolean) = withContext(Dispatchers.IO) {
|
||||
|
||||
@@ -27,6 +27,9 @@ import org.thoughtcrime.securesms.conversation.v2.registerForLifecycle
|
||||
import org.thoughtcrime.securesms.databinding.FragmentRegistrationEnterCodeBinding
|
||||
import org.thoughtcrime.securesms.registration.data.network.RegisterAccountResult
|
||||
import org.thoughtcrime.securesms.registration.data.network.RegistrationResult
|
||||
import org.thoughtcrime.securesms.registration.data.network.RegistrationSessionCheckResult
|
||||
import org.thoughtcrime.securesms.registration.data.network.RegistrationSessionCreationResult
|
||||
import org.thoughtcrime.securesms.registration.data.network.RegistrationSessionResult
|
||||
import org.thoughtcrime.securesms.registration.data.network.VerificationCodeRequestResult
|
||||
import org.thoughtcrime.securesms.registration.fragments.ContactSupportBottomSheetFragment
|
||||
import org.thoughtcrime.securesms.registration.fragments.RegistrationViewDelegate.setDebugLogSubmitMultiTapView
|
||||
@@ -37,6 +40,7 @@ import org.thoughtcrime.securesms.registrationv3.ui.RegistrationViewModel
|
||||
import org.thoughtcrime.securesms.util.concurrent.AssertedSuccessListener
|
||||
import org.thoughtcrime.securesms.util.navigation.safeNavigate
|
||||
import org.thoughtcrime.securesms.util.visible
|
||||
import kotlin.time.Duration.Companion.milliseconds
|
||||
|
||||
/**
|
||||
* The final screen of account registration, where the user enters their verification code.
|
||||
@@ -44,11 +48,11 @@ import org.thoughtcrime.securesms.util.visible
|
||||
class EnterCodeFragment : LoggingFragment(R.layout.fragment_registration_enter_code) {
|
||||
|
||||
companion object {
|
||||
private val TAG = Log.tag(EnterCodeFragment::class.java)
|
||||
|
||||
private const val BOTTOM_SHEET_TAG = "support_bottom_sheet"
|
||||
}
|
||||
|
||||
private val TAG = Log.tag(EnterCodeFragment::class.java)
|
||||
|
||||
private val sharedViewModel by activityViewModels<RegistrationViewModel>()
|
||||
private val fragmentViewModel by viewModels<EnterCodeViewModel>()
|
||||
private val bottomSheet = ContactSupportBottomSheetFragment()
|
||||
@@ -116,6 +120,11 @@ class EnterCodeFragment : LoggingFragment(R.layout.fragment_registration_enter_c
|
||||
}
|
||||
|
||||
sharedViewModel.uiState.observe(viewLifecycleOwner) {
|
||||
it.sessionCreationError?.let { error ->
|
||||
handleSessionCreationError(error)
|
||||
sharedViewModel.sessionCreationErrorShown()
|
||||
}
|
||||
|
||||
it.sessionStateError?.let { error ->
|
||||
handleSessionErrorResponse(error)
|
||||
sharedViewModel.sessionStateErrorShown()
|
||||
@@ -160,18 +169,65 @@ class EnterCodeFragment : LoggingFragment(R.layout.fragment_registration_enter_c
|
||||
}
|
||||
}
|
||||
|
||||
private fun handleSessionCreationError(result: RegistrationSessionResult) {
|
||||
if (!result.isSuccess()) {
|
||||
Log.i(TAG, "[sessionCreateError] Handling error response of ${result.javaClass.name}", result.getCause())
|
||||
}
|
||||
when (result) {
|
||||
is RegistrationSessionCheckResult.Success,
|
||||
is RegistrationSessionCreationResult.Success -> throw IllegalStateException("Session error handler called on successful response!")
|
||||
is RegistrationSessionCreationResult.AttemptsExhausted -> presentRemoteErrorDialog(getString(R.string.RegistrationActivity_rate_limited_to_service))
|
||||
is RegistrationSessionCreationResult.MalformedRequest -> presentRemoteErrorDialog(getString(R.string.RegistrationActivity_unable_to_connect_to_service))
|
||||
|
||||
is RegistrationSessionCreationResult.RateLimited -> {
|
||||
val timeRemaining = result.timeRemaining?.milliseconds
|
||||
Log.i(TAG, "Session creation rate limited! Next attempt: $timeRemaining")
|
||||
if (timeRemaining != null) {
|
||||
presentRemoteErrorDialog(getString(R.string.RegistrationActivity_rate_limited_to_try_again, timeRemaining.toString()))
|
||||
} else {
|
||||
presentRemoteErrorDialog(getString(R.string.RegistrationActivity_you_have_made_too_many_attempts_please_try_again_later))
|
||||
}
|
||||
}
|
||||
|
||||
is RegistrationSessionCreationResult.ServerUnableToParse -> presentGenericError(result)
|
||||
is RegistrationSessionCheckResult.SessionNotFound -> presentGenericError(result)
|
||||
is RegistrationSessionCheckResult.UnknownError,
|
||||
is RegistrationSessionCreationResult.UnknownError -> presentGenericError(result)
|
||||
}
|
||||
}
|
||||
|
||||
private fun handleSessionErrorResponse(result: VerificationCodeRequestResult) {
|
||||
if (!result.isSuccess()) {
|
||||
Log.i(TAG, "[sessionError] Handling error response of ${result.javaClass.name}", result.getCause())
|
||||
}
|
||||
|
||||
when (result) {
|
||||
is VerificationCodeRequestResult.Success -> throw IllegalStateException("Session error handler called on successful response!")
|
||||
is VerificationCodeRequestResult.RateLimited -> presentRateLimitedDialog()
|
||||
is VerificationCodeRequestResult.AttemptsExhausted -> presentAccountLocked()
|
||||
is VerificationCodeRequestResult.RateLimited -> {
|
||||
val timeRemaining = result.timeRemaining?.milliseconds
|
||||
Log.i(TAG, "Session patch rate limited! Next attempt: $timeRemaining")
|
||||
if (timeRemaining != null) {
|
||||
presentRemoteErrorDialog(getString(R.string.RegistrationActivity_rate_limited_to_try_again, timeRemaining.toString()))
|
||||
} else {
|
||||
presentRemoteErrorDialog(getString(R.string.RegistrationActivity_you_have_made_too_many_attempts_please_try_again_later))
|
||||
}
|
||||
}
|
||||
is VerificationCodeRequestResult.RegistrationLocked -> presentRegistrationLocked(result.timeRemaining)
|
||||
is VerificationCodeRequestResult.ExternalServiceFailure -> presentSmsGenericError(result)
|
||||
is VerificationCodeRequestResult.RequestVerificationCodeRateLimited -> {
|
||||
Log.i(TAG, result.log())
|
||||
handleRequestVerificationCodeRateLimited(result)
|
||||
}
|
||||
is VerificationCodeRequestResult.SubmitVerificationCodeRateLimited -> presentSubmitVerificationCodeRateLimited()
|
||||
else -> presentGenericError(result)
|
||||
}
|
||||
}
|
||||
|
||||
private fun handleRegistrationErrorResponse(result: RegisterAccountResult) {
|
||||
if (!result.isSuccess()) {
|
||||
Log.i(TAG, "[registrationError] Handling error response of ${result.javaClass.name}", result.getCause())
|
||||
}
|
||||
|
||||
when (result) {
|
||||
is RegisterAccountResult.Success -> throw IllegalStateException("Register account error handler called on successful response!")
|
||||
is RegisterAccountResult.RegistrationLocked -> presentRegistrationLocked(result.timeRemaining)
|
||||
@@ -248,6 +304,14 @@ class EnterCodeFragment : LoggingFragment(R.layout.fragment_registration_enter_c
|
||||
)
|
||||
}
|
||||
|
||||
private fun presentRemoteErrorDialog(message: String, positiveButtonListener: DialogInterface.OnClickListener? = null) {
|
||||
MaterialAlertDialogBuilder(requireContext()).apply {
|
||||
setMessage(message)
|
||||
setPositiveButton(android.R.string.ok, positiveButtonListener)
|
||||
show()
|
||||
}
|
||||
}
|
||||
|
||||
private fun presentGenericError(requestResult: RegistrationResult) {
|
||||
binding.keyboard.displayFailure().addListener(
|
||||
object : AssertedSuccessListener<Boolean>() {
|
||||
@@ -263,6 +327,36 @@ class EnterCodeFragment : LoggingFragment(R.layout.fragment_registration_enter_c
|
||||
)
|
||||
}
|
||||
|
||||
private fun handleRequestVerificationCodeRateLimited(result: VerificationCodeRequestResult.RequestVerificationCodeRateLimited) {
|
||||
if (result.willBeAbleToRequestAgain) {
|
||||
Log.i(TAG, "Attempted to request new code too soon, timers should be updated")
|
||||
} else {
|
||||
Log.w(TAG, "Request for new verification code impossible, need to restart registration")
|
||||
MaterialAlertDialogBuilder(requireContext()).apply {
|
||||
setMessage(R.string.RegistrationActivity_you_have_made_too_many_attempts_please_try_again_later)
|
||||
setPositiveButton(android.R.string.ok) { _, _ -> popBackStack() }
|
||||
setCancelable(false)
|
||||
show()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun presentSubmitVerificationCodeRateLimited() {
|
||||
binding.keyboard.displayFailure().addListener(
|
||||
object : AssertedSuccessListener<Boolean>() {
|
||||
override fun onSuccess(result: Boolean?) {
|
||||
Log.w(TAG, "Submit verification code impossible, need to request a new code and restart registration")
|
||||
MaterialAlertDialogBuilder(requireContext()).apply {
|
||||
setMessage(R.string.RegistrationActivity_you_have_made_too_many_attempts_please_try_again_later)
|
||||
setPositiveButton(android.R.string.ok) { _, _ -> popBackStack() }
|
||||
setCancelable(false)
|
||||
show()
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
private fun popBackStack() {
|
||||
sharedViewModel.setRegistrationCheckpoint(RegistrationCheckpoint.PUSH_NETWORK_AUDITED)
|
||||
NavHostFragment.findNavController(this).popBackStack()
|
||||
|
||||
@@ -340,8 +340,13 @@ class EnterPhoneNumberFragment : LoggingFragment(R.layout.fragment_registration_
|
||||
is RegistrationSessionCreationResult.MalformedRequest -> presentRemoteErrorDialog(getString(R.string.RegistrationActivity_unable_to_connect_to_service), skipToNextScreen)
|
||||
|
||||
is RegistrationSessionCreationResult.RateLimited -> {
|
||||
Log.i(TAG, "Session creation rate limited! Next attempt: ${result.timeRemaining.milliseconds}")
|
||||
presentRemoteErrorDialog(getString(R.string.RegistrationActivity_rate_limited_to_try_again, result.timeRemaining.milliseconds.toString()))
|
||||
val timeRemaining = result.timeRemaining?.milliseconds
|
||||
Log.i(TAG, "Session creation rate limited! Next attempt: $timeRemaining")
|
||||
if (timeRemaining != null) {
|
||||
presentRemoteErrorDialog(getString(R.string.RegistrationActivity_rate_limited_to_try_again, timeRemaining.toString()))
|
||||
} else {
|
||||
presentRemoteErrorDialog(getString(R.string.RegistrationActivity_you_have_made_too_many_attempts_please_try_again_later))
|
||||
}
|
||||
}
|
||||
|
||||
is RegistrationSessionCreationResult.ServerUnableToParse -> presentGenericError(result)
|
||||
@@ -357,7 +362,6 @@ class EnterPhoneNumberFragment : LoggingFragment(R.layout.fragment_registration_
|
||||
}
|
||||
when (result) {
|
||||
is VerificationCodeRequestResult.Success -> throw IllegalStateException("Session error handler called on successful response!")
|
||||
is VerificationCodeRequestResult.AttemptsExhausted -> presentRateLimitedDialog()
|
||||
is VerificationCodeRequestResult.ChallengeRequired -> handleChallenges(result.challenges)
|
||||
is VerificationCodeRequestResult.ExternalServiceFailure -> presentRemoteErrorDialog(getString(R.string.RegistrationActivity_sms_provider_error))
|
||||
is VerificationCodeRequestResult.ImpossibleNumber -> {
|
||||
@@ -380,11 +384,20 @@ class EnterPhoneNumberFragment : LoggingFragment(R.layout.fragment_registration_
|
||||
}
|
||||
|
||||
is VerificationCodeRequestResult.MalformedRequest -> presentRemoteErrorDialog(getString(R.string.RegistrationActivity_unable_to_connect_to_service), skipToNextScreen)
|
||||
is VerificationCodeRequestResult.MustRetry -> presentRemoteErrorDialog(getString(R.string.RegistrationActivity_unable_to_connect_to_service), skipToNextScreen)
|
||||
is VerificationCodeRequestResult.RequestVerificationCodeRateLimited -> {
|
||||
Log.i(TAG, result.log())
|
||||
handleRequestVerificationCodeRateLimited(result)
|
||||
}
|
||||
is VerificationCodeRequestResult.SubmitVerificationCodeRateLimited -> presentGenericError(result)
|
||||
is VerificationCodeRequestResult.NonNormalizedNumber -> handleNonNormalizedNumberError(result.originalNumber, result.normalizedNumber, fragmentViewModel.e164VerificationMode)
|
||||
is VerificationCodeRequestResult.RateLimited -> {
|
||||
Log.i(TAG, "Code request rate limited! Next attempt: ${result.timeRemaining.milliseconds}")
|
||||
presentRemoteErrorDialog(getString(R.string.RegistrationActivity_rate_limited_to_try_again, result.timeRemaining.milliseconds.toString()))
|
||||
val timeRemaining = result.timeRemaining?.milliseconds
|
||||
Log.i(TAG, "Session patch rate limited! Next attempt: $timeRemaining")
|
||||
if (timeRemaining != null) {
|
||||
presentRemoteErrorDialog(getString(R.string.RegistrationActivity_rate_limited_to_try_again, timeRemaining.toString()))
|
||||
} else {
|
||||
presentRemoteErrorDialog(getString(R.string.RegistrationActivity_you_have_made_too_many_attempts_please_try_again_later))
|
||||
}
|
||||
}
|
||||
|
||||
is VerificationCodeRequestResult.TokenNotAccepted -> presentRemoteErrorDialog(getString(R.string.RegistrationActivity_we_need_to_verify_that_youre_human)) { _, _ -> moveToCaptcha() }
|
||||
@@ -438,6 +451,23 @@ class EnterPhoneNumberFragment : LoggingFragment(R.layout.fragment_registration_
|
||||
}
|
||||
}
|
||||
|
||||
private fun handleRequestVerificationCodeRateLimited(result: VerificationCodeRequestResult.RequestVerificationCodeRateLimited) {
|
||||
if (result.willBeAbleToRequestAgain) {
|
||||
Log.i(TAG, "New verification code cannot be requested yet but can soon, moving to enter code to show timers")
|
||||
moveToVerificationEntryScreen()
|
||||
} else {
|
||||
Log.w(TAG, "Unable to request new verification code, prompting to start new session")
|
||||
MaterialAlertDialogBuilder(requireContext()).apply {
|
||||
setMessage(R.string.RegistrationActivity_unable_to_connect_to_service)
|
||||
setPositiveButton(R.string.NetworkFailure__retry) { _, _ ->
|
||||
onRegistrationButtonClicked()
|
||||
}
|
||||
setNegativeButton(android.R.string.cancel, null)
|
||||
show()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun handleNonNormalizedNumberError(originalNumber: String, normalizedNumber: String, mode: RegistrationRepository.E164VerificationMode) {
|
||||
try {
|
||||
val phoneNumber = PhoneNumberUtil.getInstance().parse(normalizedNumber, null)
|
||||
|
||||
@@ -148,9 +148,6 @@ class RegistrationLockFragment : LoggingFragment(R.layout.fragment_registration_
|
||||
when (requestResult) {
|
||||
is VerificationCodeRequestResult.Success -> throw IllegalStateException("Session error handler called on successful response!")
|
||||
is VerificationCodeRequestResult.RateLimited -> onRateLimited()
|
||||
is VerificationCodeRequestResult.AttemptsExhausted -> {
|
||||
findNavController().safeNavigate(RegistrationLockFragmentDirections.actionAccountLocked())
|
||||
}
|
||||
|
||||
is VerificationCodeRequestResult.RegistrationLocked -> {
|
||||
Log.i(TAG, "Registration locked response to verify account!")
|
||||
|
||||
Reference in New Issue
Block a user