mirror of
https://github.com/signalapp/Signal-Android.git
synced 2025-12-24 04:58:45 +00:00
Allow for multiple captchas to be solved during registration.
This commit is contained in:
committed by
Greyson Parrelli
parent
23b5a3dcb0
commit
bdf2ef5a05
@@ -5,10 +5,7 @@
|
||||
|
||||
package org.thoughtcrime.securesms.components.settings.app.changenumber
|
||||
|
||||
import android.os.Bundle
|
||||
import android.view.View
|
||||
import androidx.fragment.app.activityViewModels
|
||||
import org.thoughtcrime.securesms.registration.data.network.Challenge
|
||||
import org.thoughtcrime.securesms.registration.ui.captcha.CaptchaFragment
|
||||
|
||||
/**
|
||||
@@ -16,16 +13,8 @@ import org.thoughtcrime.securesms.registration.ui.captcha.CaptchaFragment
|
||||
*/
|
||||
class ChangeNumberCaptchaFragment : CaptchaFragment() {
|
||||
private val viewModel by activityViewModels<ChangeNumberViewModel>()
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
viewModel.addPresentedChallenge(Challenge.CAPTCHA)
|
||||
}
|
||||
|
||||
override fun handleCaptchaToken(token: String) {
|
||||
viewModel.setCaptchaResponse(token)
|
||||
}
|
||||
|
||||
override fun handleUserExit() {
|
||||
viewModel.removePresentedChallenge(Challenge.CAPTCHA)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -35,10 +35,9 @@ data class ChangeNumberState(
|
||||
val challengesPresented: Set<Challenge> = emptySet(),
|
||||
val allowedToRequestCode: Boolean = false,
|
||||
val oldCountry: Country? = null,
|
||||
val newCountry: Country? = null
|
||||
) {
|
||||
val challengesRemaining: List<Challenge> = challengesRequested.filterNot { it in challengesPresented }
|
||||
}
|
||||
val newCountry: Country? = null,
|
||||
val challengeInProgress: Boolean = false
|
||||
)
|
||||
|
||||
sealed interface ChangeNumberOutcome {
|
||||
data object RecoveryPasswordWorked : ChangeNumberOutcome
|
||||
|
||||
@@ -54,8 +54,10 @@ class ChangeNumberVerifyFragment : LoggingFragment(R.layout.fragment_change_phon
|
||||
private fun onStateUpdate(state: ChangeNumberState) {
|
||||
if (state.challengesRequested.contains(Challenge.CAPTCHA) && state.captchaToken.isNotNullOrBlank()) {
|
||||
viewModel.submitCaptchaToken(requireContext())
|
||||
} else if (state.challengesRemaining.isNotEmpty()) {
|
||||
handleChallenges(state.challengesRemaining)
|
||||
} else if (state.challengesRequested.isNotEmpty()) {
|
||||
if (!state.challengeInProgress) {
|
||||
handleChallenges(state.challengesRequested)
|
||||
}
|
||||
} else if (state.changeNumberOutcome != null) {
|
||||
handleRequestCodeResult(state.changeNumberOutcome)
|
||||
} else if (!state.inProgress) {
|
||||
|
||||
@@ -156,20 +156,6 @@ class ChangeNumberViewModel : ViewModel() {
|
||||
}
|
||||
}
|
||||
|
||||
fun addPresentedChallenge(challenge: Challenge) {
|
||||
Log.v(TAG, "addPresentedChallenge()")
|
||||
store.update {
|
||||
it.copy(challengesPresented = it.challengesPresented.plus(challenge))
|
||||
}
|
||||
}
|
||||
|
||||
fun removePresentedChallenge(challenge: Challenge) {
|
||||
Log.v(TAG, "addPresentedChallenge()")
|
||||
store.update {
|
||||
it.copy(challengesPresented = it.challengesPresented.minus(challenge))
|
||||
}
|
||||
}
|
||||
|
||||
fun resetLocalSessionState() {
|
||||
Log.v(TAG, "resetLocalSessionState()")
|
||||
store.update {
|
||||
@@ -292,7 +278,8 @@ class ChangeNumberViewModel : ViewModel() {
|
||||
it.copy(
|
||||
captchaToken = null,
|
||||
inProgress = true,
|
||||
changeNumberOutcome = null
|
||||
changeNumberOutcome = null,
|
||||
challengeInProgress = true
|
||||
)
|
||||
}
|
||||
|
||||
@@ -304,7 +291,8 @@ class ChangeNumberViewModel : ViewModel() {
|
||||
store.update {
|
||||
it.copy(
|
||||
inProgress = false,
|
||||
changeNumberOutcome = null
|
||||
changeNumberOutcome = null,
|
||||
challengeInProgress = false
|
||||
)
|
||||
}
|
||||
return@launch
|
||||
@@ -313,7 +301,7 @@ class ChangeNumberViewModel : ViewModel() {
|
||||
val captchaSubmissionResult = RegistrationRepository.submitCaptchaToken(context, e164, password, sessionData.sessionId, captchaToken)
|
||||
Log.d(TAG, "Captcha token submitted.")
|
||||
store.update {
|
||||
it.copy(inProgress = false, changeNumberOutcome = ChangeNumberOutcome.ChangeNumberRequestOutcome(captchaSubmissionResult))
|
||||
it.copy(inProgress = false, changeNumberOutcome = ChangeNumberOutcome.ChangeNumberRequestOutcome(captchaSubmissionResult), challengeInProgress = false)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -321,8 +309,6 @@ class ChangeNumberViewModel : ViewModel() {
|
||||
fun requestAndSubmitPushToken(context: Context) {
|
||||
Log.v(TAG, "validatePushToken()")
|
||||
|
||||
addPresentedChallenge(Challenge.PUSH)
|
||||
|
||||
val e164 = number.e164Number
|
||||
|
||||
viewModelScope.launch {
|
||||
|
||||
@@ -27,8 +27,4 @@ enum class Challenge(val key: String) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun stringify(challenges: List<Challenge>): String {
|
||||
return challenges.joinToString { it.key }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,8 +16,6 @@ enum class RegistrationCheckpoint {
|
||||
PUSH_NETWORK_AUDITED,
|
||||
PHONE_NUMBER_CONFIRMED,
|
||||
PIN_CONFIRMED,
|
||||
CHALLENGE_RECEIVED,
|
||||
CHALLENGE_COMPLETED,
|
||||
VERIFICATION_CODE_REQUESTED,
|
||||
VERIFICATION_CODE_ENTERED,
|
||||
PIN_ENTERED,
|
||||
|
||||
@@ -41,7 +41,6 @@ data class RegistrationState(
|
||||
val isAllowedToRequestCode: Boolean = false,
|
||||
val fcmToken: String? = null,
|
||||
val challengesRequested: List<Challenge> = emptyList(),
|
||||
val challengesPresented: Set<Challenge> = emptySet(),
|
||||
val captchaToken: String? = null,
|
||||
val allowedToRequestCode: Boolean = false,
|
||||
val nextSmsTimestamp: Duration = 0.seconds,
|
||||
@@ -53,10 +52,9 @@ data class RegistrationState(
|
||||
val networkError: Throwable? = null,
|
||||
val sessionCreationError: RegistrationSessionResult? = null,
|
||||
val sessionStateError: VerificationCodeRequestResult? = null,
|
||||
val registerAccountError: RegisterAccountResult? = null
|
||||
val registerAccountError: RegisterAccountResult? = null,
|
||||
val challengeInProgress: Boolean = false
|
||||
) {
|
||||
val challengesRemaining: List<Challenge> = challengesRequested.filterNot { it in challengesPresented }
|
||||
|
||||
companion object {
|
||||
private val TAG = Log.tag(RegistrationState::class)
|
||||
|
||||
|
||||
@@ -74,7 +74,6 @@ import java.io.IOException
|
||||
import java.nio.charset.StandardCharsets
|
||||
import java.util.concurrent.TimeUnit
|
||||
import kotlin.jvm.optionals.getOrNull
|
||||
import kotlin.time.Duration.Companion.milliseconds
|
||||
import kotlin.time.Duration.Companion.minutes
|
||||
|
||||
/**
|
||||
@@ -164,7 +163,6 @@ class RegistrationViewModel : ViewModel() {
|
||||
fun setCaptchaResponse(token: String) {
|
||||
store.update {
|
||||
it.copy(
|
||||
registrationCheckpoint = RegistrationCheckpoint.CHALLENGE_COMPLETED,
|
||||
captchaToken = token
|
||||
)
|
||||
}
|
||||
@@ -194,18 +192,6 @@ class RegistrationViewModel : ViewModel() {
|
||||
}
|
||||
}
|
||||
|
||||
fun addPresentedChallenge(challenge: Challenge) {
|
||||
store.update {
|
||||
it.copy(challengesPresented = it.challengesPresented.plus(challenge))
|
||||
}
|
||||
}
|
||||
|
||||
fun removePresentedChallenge(challenge: Challenge) {
|
||||
store.update {
|
||||
it.copy(challengesPresented = it.challengesPresented.minus(challenge))
|
||||
}
|
||||
}
|
||||
|
||||
fun fetchFcmToken(context: Context) {
|
||||
viewModelScope.launch(context = coroutineExceptionHandler) {
|
||||
val fcmToken = RegistrationRepository.getFcmToken(context)
|
||||
@@ -290,14 +276,8 @@ class RegistrationViewModel : ViewModel() {
|
||||
}
|
||||
|
||||
if (!validSession.allowedToRequestCode) {
|
||||
if (System.currentTimeMillis().milliseconds > validSession.nextVerificationAttempt) {
|
||||
store.update {
|
||||
it.copy(registrationCheckpoint = RegistrationCheckpoint.VERIFICATION_CODE_REQUESTED)
|
||||
}
|
||||
} else {
|
||||
Log.i(TAG, "Not allowed to request code! Remaining challenges: ${validSession.challengesRequested.joinToString()}")
|
||||
handleSessionStateResult(context, ChallengeRequired(validSession.challengesRequested))
|
||||
}
|
||||
Log.i(TAG, "Not allowed to request code! Remaining challenges: ${validSession.challengesRequested.joinToString()}")
|
||||
handleSessionStateResult(context, ChallengeRequired(validSession.challengesRequested))
|
||||
return@launch
|
||||
}
|
||||
|
||||
@@ -383,6 +363,8 @@ class RegistrationViewModel : ViewModel() {
|
||||
registrationCheckpoint = RegistrationCheckpoint.VERIFICATION_CODE_REQUESTED
|
||||
)
|
||||
}
|
||||
} else {
|
||||
Log.i(TAG, "SMS code request failed: ${codeRequestResponse::class.simpleName}")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -400,6 +382,7 @@ class RegistrationViewModel : ViewModel() {
|
||||
mcc = mccMncProducer.mcc,
|
||||
mnc = mccMncProducer.mnc,
|
||||
successListener = { sessionData ->
|
||||
Log.i(TAG, "[getOrCreateValidSession] Challenges requested: ${sessionData.challengesRequested}", true)
|
||||
store.update {
|
||||
it.copy(
|
||||
sessionId = sessionData.sessionId,
|
||||
@@ -429,7 +412,7 @@ class RegistrationViewModel : ViewModel() {
|
||||
val captchaToken = store.value.captchaToken ?: throw IllegalStateException("Can't submit captcha token if no captcha token is set!")
|
||||
|
||||
store.update {
|
||||
it.copy(captchaToken = null)
|
||||
it.copy(captchaToken = null, challengeInProgress = true, inProgress = true)
|
||||
}
|
||||
|
||||
viewModelScope.launch {
|
||||
@@ -439,14 +422,20 @@ class RegistrationViewModel : ViewModel() {
|
||||
Log.d(TAG, "Captcha token submitted.")
|
||||
|
||||
handleSessionStateResult(context, captchaSubmissionResult)
|
||||
|
||||
store.update { it.copy(challengeInProgress = false) }
|
||||
|
||||
if (captchaSubmissionResult is Success) {
|
||||
requestSmsCode(context)
|
||||
} else {
|
||||
setInProgress(false)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun requestAndSubmitPushToken(context: Context) {
|
||||
Log.v(TAG, "validatePushToken()")
|
||||
|
||||
addPresentedChallenge(Challenge.PUSH)
|
||||
|
||||
val e164 = getCurrentE164() ?: throw IllegalStateException("Can't submit captcha token if no phone number is set!")
|
||||
|
||||
viewModelScope.launch {
|
||||
@@ -493,7 +482,6 @@ class RegistrationViewModel : ViewModel() {
|
||||
Log.d(TAG, "[${sessionResult.challenges.joinToString()}] registration challenges received.")
|
||||
store.update {
|
||||
it.copy(
|
||||
registrationCheckpoint = RegistrationCheckpoint.CHALLENGE_RECEIVED,
|
||||
challengesRequested = sessionResult.challenges
|
||||
)
|
||||
}
|
||||
|
||||
@@ -10,8 +10,6 @@ import android.os.Bundle
|
||||
import android.view.View
|
||||
import android.webkit.WebView
|
||||
import android.webkit.WebViewClient
|
||||
import androidx.activity.OnBackPressedCallback
|
||||
import androidx.activity.addCallback
|
||||
import androidx.navigation.fragment.findNavController
|
||||
import org.thoughtcrime.securesms.BuildConfig
|
||||
import org.thoughtcrime.securesms.LoggingFragment
|
||||
@@ -24,12 +22,6 @@ abstract class CaptchaFragment : LoggingFragment(R.layout.fragment_registration_
|
||||
|
||||
private val binding: FragmentRegistrationCaptchaBinding by ViewBinderDelegate(FragmentRegistrationCaptchaBinding::bind)
|
||||
|
||||
private val backListener = object : OnBackPressedCallback(true) {
|
||||
override fun handleOnBackPressed() {
|
||||
handleUserExit()
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressLint("SetJavaScriptEnabled")
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
@@ -42,20 +34,14 @@ abstract class CaptchaFragment : LoggingFragment(R.layout.fragment_registration_
|
||||
if (url.startsWith(RegistrationConstants.SIGNAL_CAPTCHA_SCHEME)) {
|
||||
val token = url.substring(RegistrationConstants.SIGNAL_CAPTCHA_SCHEME.length)
|
||||
handleCaptchaToken(token)
|
||||
backListener.isEnabled = false
|
||||
findNavController().navigateUp()
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
}
|
||||
requireActivity().onBackPressedDispatcher.addCallback(viewLifecycleOwner) {
|
||||
handleUserExit()
|
||||
}
|
||||
binding.registrationCaptchaWebView.loadUrl(BuildConfig.SIGNAL_CAPTCHA_URL)
|
||||
}
|
||||
|
||||
abstract fun handleCaptchaToken(token: String)
|
||||
|
||||
abstract fun handleUserExit()
|
||||
}
|
||||
|
||||
@@ -5,10 +5,7 @@
|
||||
|
||||
package org.thoughtcrime.securesms.registration.ui.captcha
|
||||
|
||||
import android.os.Bundle
|
||||
import android.view.View
|
||||
import androidx.fragment.app.activityViewModels
|
||||
import org.thoughtcrime.securesms.registration.data.network.Challenge
|
||||
import org.thoughtcrime.securesms.registration.ui.RegistrationViewModel
|
||||
|
||||
/**
|
||||
@@ -19,16 +16,8 @@ import org.thoughtcrime.securesms.registration.ui.RegistrationViewModel
|
||||
*/
|
||||
class RegistrationCaptchaFragment : CaptchaFragment() {
|
||||
private val sharedViewModel by activityViewModels<RegistrationViewModel>()
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
sharedViewModel.addPresentedChallenge(Challenge.CAPTCHA)
|
||||
}
|
||||
|
||||
override fun handleCaptchaToken(token: String) {
|
||||
sharedViewModel.setCaptchaResponse(token)
|
||||
}
|
||||
|
||||
override fun handleUserExit() {
|
||||
sharedViewModel.removePresentedChallenge(Challenge.CAPTCHA)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -140,8 +140,8 @@ class EnterCodeFragment : LoggingFragment(R.layout.fragment_registration_enter_c
|
||||
|
||||
if (sharedState.challengesRequested.contains(Challenge.CAPTCHA) && sharedState.captchaToken.isNotNullOrBlank()) {
|
||||
sharedViewModel.submitCaptchaToken(requireContext())
|
||||
} else if (sharedState.challengesRemaining.isNotEmpty()) {
|
||||
handleChallenges(sharedState.challengesRemaining)
|
||||
} else if (sharedState.challengesRequested.isNotEmpty() && !sharedState.challengeInProgress) {
|
||||
handleChallenges(sharedState.challengesRequested)
|
||||
}
|
||||
|
||||
binding.resendSmsCountDown.startCountDownTo(sharedState.nextSmsTimestamp)
|
||||
|
||||
@@ -159,8 +159,10 @@ class EnterPhoneNumberFragment : LoggingFragment(R.layout.fragment_registration_
|
||||
|
||||
if (sharedState.challengesRequested.contains(Challenge.CAPTCHA) && sharedState.captchaToken.isNotNullOrBlank()) {
|
||||
sharedViewModel.submitCaptchaToken(requireContext())
|
||||
} else if (sharedState.challengesRemaining.isNotEmpty()) {
|
||||
handleChallenges(sharedState.challengesRemaining)
|
||||
} else if (sharedState.challengesRequested.isNotEmpty()) {
|
||||
if (!sharedState.challengeInProgress) {
|
||||
handleChallenges(sharedState.challengesRequested)
|
||||
}
|
||||
} else if (sharedState.registrationCheckpoint >= RegistrationCheckpoint.PHONE_NUMBER_CONFIRMED && sharedState.canSkipSms) {
|
||||
moveToEnterPinScreen()
|
||||
} else if (sharedState.registrationCheckpoint >= RegistrationCheckpoint.VERIFICATION_CODE_REQUESTED) {
|
||||
|
||||
@@ -16,8 +16,6 @@ enum class RegistrationCheckpoint {
|
||||
PUSH_NETWORK_AUDITED,
|
||||
PHONE_NUMBER_CONFIRMED,
|
||||
PIN_CONFIRMED,
|
||||
CHALLENGE_RECEIVED,
|
||||
CHALLENGE_COMPLETED,
|
||||
VERIFICATION_CODE_REQUESTED,
|
||||
VERIFICATION_CODE_ENTERED,
|
||||
PIN_ENTERED,
|
||||
|
||||
@@ -42,7 +42,6 @@ data class RegistrationState(
|
||||
val isAllowedToRequestCode: Boolean = false,
|
||||
val fcmToken: String? = null,
|
||||
val challengesRequested: List<Challenge> = emptyList(),
|
||||
val challengesPresented: Set<Challenge> = emptySet(),
|
||||
val captchaToken: String? = null,
|
||||
val allowedToRequestCode: Boolean = false,
|
||||
val nextSmsTimestamp: Duration = 0.seconds,
|
||||
@@ -54,10 +53,9 @@ data class RegistrationState(
|
||||
val networkError: Throwable? = null,
|
||||
val sessionCreationError: RegistrationSessionResult? = null,
|
||||
val sessionStateError: VerificationCodeRequestResult? = null,
|
||||
val registerAccountError: RegisterAccountResult? = null
|
||||
val registerAccountError: RegisterAccountResult? = null,
|
||||
val challengeInProgress: Boolean = false
|
||||
) {
|
||||
val challengesRemaining: List<Challenge> = challengesRequested.filterNot { it in challengesPresented }
|
||||
|
||||
companion object {
|
||||
private val TAG = Log.tag(RegistrationState::class)
|
||||
|
||||
@@ -77,7 +75,7 @@ data class RegistrationState(
|
||||
}
|
||||
|
||||
fun toNavigationStateOnly(): NavigationState {
|
||||
return NavigationState(challengesRequested, challengesPresented, captchaToken, registrationCheckpoint, canSkipSms)
|
||||
return NavigationState(challengesRequested, captchaToken, registrationCheckpoint, canSkipSms, challengeInProgress)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -86,11 +84,9 @@ data class RegistrationState(
|
||||
*/
|
||||
data class NavigationState(
|
||||
val challengesRequested: List<Challenge>,
|
||||
val challengesPresented: Set<Challenge>,
|
||||
val captchaToken: String? = null,
|
||||
val registrationCheckpoint: RegistrationCheckpoint,
|
||||
val canSkipSms: Boolean
|
||||
) {
|
||||
val challengesRemaining: List<Challenge> = challengesRequested.filterNot { it in challengesPresented }
|
||||
}
|
||||
val canSkipSms: Boolean,
|
||||
val challengeInProgress: Boolean
|
||||
)
|
||||
}
|
||||
|
||||
@@ -98,7 +98,6 @@ import java.io.IOException
|
||||
import java.nio.charset.StandardCharsets
|
||||
import kotlin.jvm.optionals.getOrNull
|
||||
import kotlin.math.max
|
||||
import kotlin.time.Duration.Companion.milliseconds
|
||||
import kotlin.time.Duration.Companion.minutes
|
||||
import kotlin.time.Duration.Companion.seconds
|
||||
|
||||
@@ -191,7 +190,6 @@ class RegistrationViewModel : ViewModel() {
|
||||
fun setCaptchaResponse(token: String) {
|
||||
store.update {
|
||||
it.copy(
|
||||
registrationCheckpoint = RegistrationCheckpoint.CHALLENGE_COMPLETED,
|
||||
captchaToken = token
|
||||
)
|
||||
}
|
||||
@@ -221,18 +219,6 @@ class RegistrationViewModel : ViewModel() {
|
||||
}
|
||||
}
|
||||
|
||||
fun addPresentedChallenge(challenge: Challenge) {
|
||||
store.update {
|
||||
it.copy(challengesPresented = it.challengesPresented.plus(challenge))
|
||||
}
|
||||
}
|
||||
|
||||
fun removePresentedChallenge(challenge: Challenge) {
|
||||
store.update {
|
||||
it.copy(challengesPresented = it.challengesPresented.minus(challenge))
|
||||
}
|
||||
}
|
||||
|
||||
fun fetchFcmToken(context: Context) {
|
||||
viewModelScope.launch(context = coroutineExceptionHandler) {
|
||||
val fcmToken = RegistrationRepository.getFcmToken(context)
|
||||
@@ -317,14 +303,8 @@ class RegistrationViewModel : ViewModel() {
|
||||
}
|
||||
|
||||
if (!validSession.allowedToRequestCode) {
|
||||
if (System.currentTimeMillis().milliseconds > validSession.nextVerificationAttempt) {
|
||||
store.update {
|
||||
it.copy(registrationCheckpoint = RegistrationCheckpoint.VERIFICATION_CODE_REQUESTED)
|
||||
}
|
||||
} else {
|
||||
Log.i(TAG, "Not allowed to request code! Remaining challenges: ${validSession.challengesRequested.joinToString()}")
|
||||
handleSessionStateResult(context, ChallengeRequired(validSession.challengesRequested))
|
||||
}
|
||||
Log.i(TAG, "Not allowed to request code! Remaining challenges: ${validSession.challengesRequested.joinToString()}")
|
||||
handleSessionStateResult(context, ChallengeRequired(validSession.challengesRequested))
|
||||
return@launch
|
||||
}
|
||||
|
||||
@@ -410,6 +390,8 @@ class RegistrationViewModel : ViewModel() {
|
||||
registrationCheckpoint = RegistrationCheckpoint.VERIFICATION_CODE_REQUESTED
|
||||
)
|
||||
}
|
||||
} else {
|
||||
Log.i(TAG, "SMS code request failed: ${codeRequestResponse::class.simpleName}")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -427,6 +409,7 @@ class RegistrationViewModel : ViewModel() {
|
||||
mcc = mccMncProducer.mcc,
|
||||
mnc = mccMncProducer.mnc,
|
||||
successListener = { sessionData ->
|
||||
Log.i(TAG, "[getOrCreateValidSession] Challenges requested: ${sessionData.challengesRequested}", true)
|
||||
store.update {
|
||||
it.copy(
|
||||
sessionId = sessionData.sessionId,
|
||||
@@ -456,7 +439,7 @@ class RegistrationViewModel : ViewModel() {
|
||||
val captchaToken = store.value.captchaToken ?: throw IllegalStateException("Can't submit captcha token if no captcha token is set!")
|
||||
|
||||
store.update {
|
||||
it.copy(captchaToken = null)
|
||||
it.copy(captchaToken = null, challengeInProgress = true, inProgress = true)
|
||||
}
|
||||
|
||||
viewModelScope.launch {
|
||||
@@ -466,14 +449,20 @@ class RegistrationViewModel : ViewModel() {
|
||||
Log.d(TAG, "Captcha token submitted.", true)
|
||||
|
||||
handleSessionStateResult(context, captchaSubmissionResult)
|
||||
|
||||
store.update { it.copy(challengeInProgress = false) }
|
||||
|
||||
if (captchaSubmissionResult is Success) {
|
||||
requestSmsCode(context)
|
||||
} else {
|
||||
setInProgress(false)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun requestAndSubmitPushToken(context: Context) {
|
||||
Log.v(TAG, "validatePushToken()")
|
||||
|
||||
addPresentedChallenge(Challenge.PUSH)
|
||||
|
||||
val e164 = getCurrentE164() ?: throw IllegalStateException("Can't submit captcha token if no phone number is set!")
|
||||
|
||||
viewModelScope.launch {
|
||||
@@ -520,7 +509,6 @@ class RegistrationViewModel : ViewModel() {
|
||||
Log.d(TAG, "[${sessionResult.challenges.joinToString()}] registration challenges received.", true)
|
||||
store.update {
|
||||
it.copy(
|
||||
registrationCheckpoint = RegistrationCheckpoint.CHALLENGE_RECEIVED,
|
||||
challengesRequested = sessionResult.challenges
|
||||
)
|
||||
}
|
||||
|
||||
@@ -10,8 +10,6 @@ import android.os.Bundle
|
||||
import android.view.View
|
||||
import android.webkit.WebView
|
||||
import android.webkit.WebViewClient
|
||||
import androidx.activity.OnBackPressedCallback
|
||||
import androidx.activity.addCallback
|
||||
import androidx.navigation.fragment.findNavController
|
||||
import org.thoughtcrime.securesms.BuildConfig
|
||||
import org.thoughtcrime.securesms.LoggingFragment
|
||||
@@ -24,12 +22,6 @@ abstract class CaptchaFragment : LoggingFragment(R.layout.fragment_registration_
|
||||
|
||||
private val binding: FragmentRegistrationCaptchaBinding by ViewBinderDelegate(FragmentRegistrationCaptchaBinding::bind)
|
||||
|
||||
private val backListener = object : OnBackPressedCallback(true) {
|
||||
override fun handleOnBackPressed() {
|
||||
handleUserExit()
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressLint("SetJavaScriptEnabled")
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
@@ -42,20 +34,14 @@ abstract class CaptchaFragment : LoggingFragment(R.layout.fragment_registration_
|
||||
if (url.startsWith(RegistrationConstants.SIGNAL_CAPTCHA_SCHEME)) {
|
||||
val token = url.substring(RegistrationConstants.SIGNAL_CAPTCHA_SCHEME.length)
|
||||
handleCaptchaToken(token)
|
||||
backListener.isEnabled = false
|
||||
findNavController().navigateUp()
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
}
|
||||
requireActivity().onBackPressedDispatcher.addCallback(viewLifecycleOwner) {
|
||||
handleUserExit()
|
||||
}
|
||||
binding.registrationCaptchaWebView.loadUrl(BuildConfig.SIGNAL_CAPTCHA_URL)
|
||||
}
|
||||
|
||||
abstract fun handleCaptchaToken(token: String)
|
||||
|
||||
abstract fun handleUserExit()
|
||||
}
|
||||
|
||||
@@ -5,10 +5,7 @@
|
||||
|
||||
package org.thoughtcrime.securesms.registrationv3.ui.captcha
|
||||
|
||||
import android.os.Bundle
|
||||
import android.view.View
|
||||
import androidx.fragment.app.activityViewModels
|
||||
import org.thoughtcrime.securesms.registration.data.network.Challenge
|
||||
import org.thoughtcrime.securesms.registrationv3.ui.RegistrationViewModel
|
||||
|
||||
/**
|
||||
@@ -19,16 +16,8 @@ import org.thoughtcrime.securesms.registrationv3.ui.RegistrationViewModel
|
||||
*/
|
||||
class RegistrationCaptchaFragment : CaptchaFragment() {
|
||||
private val sharedViewModel by activityViewModels<RegistrationViewModel>()
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
sharedViewModel.addPresentedChallenge(Challenge.CAPTCHA)
|
||||
}
|
||||
|
||||
override fun handleCaptchaToken(token: String) {
|
||||
sharedViewModel.setCaptchaResponse(token)
|
||||
}
|
||||
|
||||
override fun handleUserExit() {
|
||||
sharedViewModel.removePresentedChallenge(Challenge.CAPTCHA)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -140,8 +140,8 @@ class EnterCodeFragment : LoggingFragment(R.layout.fragment_registration_enter_c
|
||||
|
||||
if (sharedState.challengesRequested.contains(Challenge.CAPTCHA) && sharedState.captchaToken.isNotNullOrBlank()) {
|
||||
sharedViewModel.submitCaptchaToken(requireContext())
|
||||
} else if (sharedState.challengesRemaining.isNotEmpty()) {
|
||||
handleChallenges(sharedState.challengesRemaining)
|
||||
} else if (sharedState.challengesRequested.isNotEmpty() && !sharedState.challengeInProgress) {
|
||||
handleChallenges(sharedState.challengesRequested)
|
||||
}
|
||||
|
||||
binding.resendSmsCountDown.startCountDownTo(sharedState.nextSmsTimestamp)
|
||||
|
||||
@@ -170,8 +170,10 @@ class EnterPhoneNumberFragment : LoggingFragment(R.layout.fragment_registration_
|
||||
.observe(viewLifecycleOwner) { sharedState ->
|
||||
if (sharedState.challengesRequested.contains(Challenge.CAPTCHA) && sharedState.captchaToken.isNotNullOrBlank()) {
|
||||
sharedViewModel.submitCaptchaToken(requireContext())
|
||||
} else if (sharedState.challengesRemaining.isNotEmpty()) {
|
||||
handleChallenges(sharedState.challengesRemaining)
|
||||
} else if (sharedState.challengesRequested.isNotEmpty()) {
|
||||
if (!sharedState.challengeInProgress) {
|
||||
handleChallenges(sharedState.challengesRequested)
|
||||
}
|
||||
} else if (sharedState.registrationCheckpoint >= RegistrationCheckpoint.PHONE_NUMBER_CONFIRMED && sharedState.canSkipSms) {
|
||||
moveToEnterPinScreen()
|
||||
} else if (sharedState.registrationCheckpoint >= RegistrationCheckpoint.VERIFICATION_CODE_REQUESTED) {
|
||||
|
||||
Reference in New Issue
Block a user