mirror of
https://github.com/signalapp/Signal-Android.git
synced 2026-05-08 09:18:39 +01:00
Convert registration error handling from callbacks to observers.
This commit is contained in:
@@ -11,6 +11,9 @@ import com.google.i18n.phonenumbers.Phonenumber
|
|||||||
import org.signal.core.util.logging.Log
|
import org.signal.core.util.logging.Log
|
||||||
import org.thoughtcrime.securesms.keyvalue.SignalStore
|
import org.thoughtcrime.securesms.keyvalue.SignalStore
|
||||||
import org.thoughtcrime.securesms.registration.data.network.Challenge
|
import org.thoughtcrime.securesms.registration.data.network.Challenge
|
||||||
|
import org.thoughtcrime.securesms.registration.data.network.RegisterAccountResult
|
||||||
|
import org.thoughtcrime.securesms.registration.data.network.RegistrationSessionResult
|
||||||
|
import org.thoughtcrime.securesms.registration.data.network.VerificationCodeRequestResult
|
||||||
import org.whispersystems.signalservice.api.svr.Svr3Credentials
|
import org.whispersystems.signalservice.api.svr.Svr3Credentials
|
||||||
import org.whispersystems.signalservice.internal.push.AuthCredentials
|
import org.whispersystems.signalservice.internal.push.AuthCredentials
|
||||||
|
|
||||||
@@ -45,7 +48,10 @@ data class RegistrationState(
|
|||||||
val verified: Boolean = false,
|
val verified: Boolean = false,
|
||||||
val smsListenerTimeout: Long = 0L,
|
val smsListenerTimeout: Long = 0L,
|
||||||
val registrationCheckpoint: RegistrationCheckpoint = RegistrationCheckpoint.INITIALIZATION,
|
val registrationCheckpoint: RegistrationCheckpoint = RegistrationCheckpoint.INITIALIZATION,
|
||||||
val networkError: Throwable? = null
|
val networkError: Throwable? = null,
|
||||||
|
val sessionCreationError: RegistrationSessionResult? = null,
|
||||||
|
val sessionStateError: VerificationCodeRequestResult? = null,
|
||||||
|
val registerAccountError: RegisterAccountResult? = null
|
||||||
) {
|
) {
|
||||||
val challengesRemaining: List<Challenge> = challengesRequested.filterNot { it in challengesPresented }
|
val challengesRemaining: List<Challenge> = challengesRequested.filterNot { it in challengesPresented }
|
||||||
|
|
||||||
|
|||||||
+75
-48
@@ -39,10 +39,10 @@ import org.thoughtcrime.securesms.registration.data.RegistrationRepository
|
|||||||
import org.thoughtcrime.securesms.registration.data.network.BackupAuthCheckResult
|
import org.thoughtcrime.securesms.registration.data.network.BackupAuthCheckResult
|
||||||
import org.thoughtcrime.securesms.registration.data.network.Challenge
|
import org.thoughtcrime.securesms.registration.data.network.Challenge
|
||||||
import org.thoughtcrime.securesms.registration.data.network.RegisterAccountResult
|
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.RegistrationSessionCheckResult
|
||||||
import org.thoughtcrime.securesms.registration.data.network.RegistrationSessionCreationResult
|
import org.thoughtcrime.securesms.registration.data.network.RegistrationSessionCreationResult
|
||||||
import org.thoughtcrime.securesms.registration.data.network.RegistrationSessionResult
|
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.AlreadyVerified
|
||||||
import org.thoughtcrime.securesms.registration.data.network.VerificationCodeRequestResult.AttemptsExhausted
|
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.ChallengeRequired
|
||||||
@@ -96,8 +96,6 @@ class RegistrationViewModel : ViewModel() {
|
|||||||
|
|
||||||
val incorrectCodeAttempts = store.map { it.incorrectCodeAttempts }.asLiveData()
|
val incorrectCodeAttempts = store.map { it.incorrectCodeAttempts }.asLiveData()
|
||||||
|
|
||||||
val inProgress = store.map { it.inProgress }.asLiveData()
|
|
||||||
|
|
||||||
val svrTriesRemaining: Int
|
val svrTriesRemaining: Int
|
||||||
get() = store.value.svrTriesRemaining
|
get() = store.value.svrTriesRemaining
|
||||||
|
|
||||||
@@ -158,6 +156,24 @@ class RegistrationViewModel : ViewModel() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun sessionCreationErrorShown() {
|
||||||
|
store.update {
|
||||||
|
it.copy(sessionCreationError = null)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun sessionStateErrorShown() {
|
||||||
|
store.update {
|
||||||
|
it.copy(sessionStateError = null)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun registerAccountErrorShown() {
|
||||||
|
store.update {
|
||||||
|
it.copy(registerAccountError = null)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fun incrementIncorrectCodeAttempts() {
|
fun incrementIncorrectCodeAttempts() {
|
||||||
store.update {
|
store.update {
|
||||||
it.copy(incorrectCodeAttempts = it.incorrectCodeAttempts + 1)
|
it.copy(incorrectCodeAttempts = it.incorrectCodeAttempts + 1)
|
||||||
@@ -202,7 +218,7 @@ class RegistrationViewModel : ViewModel() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun onUserConfirmedPhoneNumber(context: Context, errorHandler: (RegistrationResult) -> Unit) {
|
fun onUserConfirmedPhoneNumber(context: Context) {
|
||||||
setRegistrationCheckpoint(RegistrationCheckpoint.PHONE_NUMBER_CONFIRMED)
|
setRegistrationCheckpoint(RegistrationCheckpoint.PHONE_NUMBER_CONFIRMED)
|
||||||
val state = store.value
|
val state = store.value
|
||||||
|
|
||||||
@@ -253,11 +269,11 @@ class RegistrationViewModel : ViewModel() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
val validSession = getOrCreateValidSession(context, errorHandler) ?: return@launch bail { Log.i(TAG, "Could not create valid session for confirming the entered E164.") }
|
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.body.verified) {
|
||||||
Log.i(TAG, "Session is already verified, registering account.")
|
Log.i(TAG, "Session is already verified, registering account.")
|
||||||
registerVerifiedSession(context, validSession.body.id, errorHandler)
|
registerVerifiedSession(context, validSession.body.id)
|
||||||
return@launch
|
return@launch
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -269,25 +285,25 @@ class RegistrationViewModel : ViewModel() {
|
|||||||
} else {
|
} else {
|
||||||
val challenges = validSession.body.requestedInformation
|
val challenges = validSession.body.requestedInformation
|
||||||
Log.i(TAG, "Not allowed to request code! Remaining challenges: ${challenges.joinToString()}")
|
Log.i(TAG, "Not allowed to request code! Remaining challenges: ${challenges.joinToString()}")
|
||||||
handleSessionStateResult(context, ChallengeRequired(Challenge.parse(validSession.body.requestedInformation)), errorHandler)
|
handleSessionStateResult(context, ChallengeRequired(Challenge.parse(validSession.body.requestedInformation)))
|
||||||
}
|
}
|
||||||
return@launch
|
return@launch
|
||||||
}
|
}
|
||||||
|
|
||||||
requestSmsCodeInternal(context, validSession.body.id, e164, errorHandler)
|
requestSmsCodeInternal(context, validSession.body.id, e164)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun requestSmsCode(context: Context, errorHandler: (RegistrationResult) -> Unit) {
|
fun requestSmsCode(context: Context) {
|
||||||
val e164 = getCurrentE164() ?: return bail { Log.i(TAG, "Phone number was null after confirmation.") }
|
val e164 = getCurrentE164() ?: return bail { Log.i(TAG, "Phone number was null after confirmation.") }
|
||||||
|
|
||||||
viewModelScope.launch {
|
viewModelScope.launch {
|
||||||
val validSession = getOrCreateValidSession(context, errorHandler) ?: return@launch bail { Log.i(TAG, "Could not create valid session for requesting an SMS code.") }
|
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, errorHandler)
|
requestSmsCodeInternal(context, validSession.body.id, e164)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun requestVerificationCall(context: Context, errorHandler: (RegistrationResult) -> Unit) {
|
fun requestVerificationCall(context: Context) {
|
||||||
val e164 = getCurrentE164()
|
val e164 = getCurrentE164()
|
||||||
|
|
||||||
if (e164 == null) {
|
if (e164 == null) {
|
||||||
@@ -297,7 +313,7 @@ class RegistrationViewModel : ViewModel() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
viewModelScope.launch {
|
viewModelScope.launch {
|
||||||
val validSession = getOrCreateValidSession(context, errorHandler) ?: return@launch bail { Log.i(TAG, "Could not create valid session for requesting a verification call.") }
|
val validSession = getOrCreateValidSession(context) ?: return@launch bail { Log.i(TAG, "Could not create valid session for requesting a verification call.") }
|
||||||
Log.d(TAG, "Requesting voice call code…")
|
Log.d(TAG, "Requesting voice call code…")
|
||||||
val codeRequestResponse = RegistrationRepository.requestSmsCode(
|
val codeRequestResponse = RegistrationRepository.requestSmsCode(
|
||||||
context = context,
|
context = context,
|
||||||
@@ -308,14 +324,14 @@ class RegistrationViewModel : ViewModel() {
|
|||||||
)
|
)
|
||||||
Log.d(TAG, "Voice code request network call completed.")
|
Log.d(TAG, "Voice code request network call completed.")
|
||||||
|
|
||||||
handleSessionStateResult(context, codeRequestResponse, errorHandler)
|
handleSessionStateResult(context, codeRequestResponse)
|
||||||
if (codeRequestResponse is Success) {
|
if (codeRequestResponse is Success) {
|
||||||
Log.d(TAG, "Voice code request was successful.")
|
Log.d(TAG, "Voice code request was successful.")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private suspend fun requestSmsCodeInternal(context: Context, sessionId: String, e164: String, errorHandler: (RegistrationResult) -> Unit) {
|
private suspend fun requestSmsCodeInternal(context: Context, sessionId: String, e164: String) {
|
||||||
var smsListenerReady = false
|
var smsListenerReady = false
|
||||||
Log.d(TAG, "Initializing SMS listener.")
|
Log.d(TAG, "Initializing SMS listener.")
|
||||||
if (store.value.smsListenerTimeout < System.currentTimeMillis()) {
|
if (store.value.smsListenerTimeout < System.currentTimeMillis()) {
|
||||||
@@ -341,7 +357,7 @@ class RegistrationViewModel : ViewModel() {
|
|||||||
)
|
)
|
||||||
Log.d(TAG, "SMS code request network call completed.")
|
Log.d(TAG, "SMS code request network call completed.")
|
||||||
|
|
||||||
handleSessionStateResult(context, codeRequestResponse, errorHandler)
|
handleSessionStateResult(context, codeRequestResponse)
|
||||||
|
|
||||||
if (codeRequestResponse is Success) {
|
if (codeRequestResponse is Success) {
|
||||||
Log.d(TAG, "SMS code request was successful.")
|
Log.d(TAG, "SMS code request was successful.")
|
||||||
@@ -353,7 +369,7 @@ class RegistrationViewModel : ViewModel() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private suspend fun getOrCreateValidSession(context: Context, errorHandler: (RegistrationResult) -> Unit): RegistrationSessionMetadataResponse? {
|
private suspend fun getOrCreateValidSession(context: Context): RegistrationSessionMetadataResponse? {
|
||||||
Log.v(TAG, "getOrCreateValidSession()")
|
Log.v(TAG, "getOrCreateValidSession()")
|
||||||
val e164 = getCurrentE164() ?: throw IllegalStateException("E164 required to create session!")
|
val e164 = getCurrentE164() ?: throw IllegalStateException("E164 required to create session!")
|
||||||
val mccMncProducer = MccMncProducer(context)
|
val mccMncProducer = MccMncProducer(context)
|
||||||
@@ -379,11 +395,17 @@ class RegistrationViewModel : ViewModel() {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
errorHandler = errorHandler
|
errorHandler = { error ->
|
||||||
|
store.update {
|
||||||
|
it.copy(
|
||||||
|
sessionCreationError = error
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun submitCaptchaToken(context: Context, errorHandler: (RegistrationResult) -> Unit) {
|
fun submitCaptchaToken(context: Context) {
|
||||||
val e164 = getCurrentE164() ?: throw IllegalStateException("Can't submit captcha token if no phone number is set!")
|
val e164 = getCurrentE164() ?: throw IllegalStateException("Can't submit captcha token if no phone number is set!")
|
||||||
val captchaToken = store.value.captchaToken ?: throw IllegalStateException("Can't submit captcha token if no captcha token is set!")
|
val captchaToken = store.value.captchaToken ?: throw IllegalStateException("Can't submit captcha token if no captcha token is set!")
|
||||||
|
|
||||||
@@ -392,16 +414,16 @@ class RegistrationViewModel : ViewModel() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
viewModelScope.launch {
|
viewModelScope.launch {
|
||||||
val session = getOrCreateValidSession(context, errorHandler) ?: return@launch bail { Log.i(TAG, "Could not create valid session for submitting a captcha token.") }
|
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…")
|
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.body.id, captchaToken)
|
||||||
Log.d(TAG, "Captcha token submitted.")
|
Log.d(TAG, "Captcha token submitted.")
|
||||||
|
|
||||||
handleSessionStateResult(context, captchaSubmissionResult, errorHandler)
|
handleSessionStateResult(context, captchaSubmissionResult)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun requestAndSubmitPushToken(context: Context, errorHandler: (RegistrationResult) -> Unit) {
|
fun requestAndSubmitPushToken(context: Context) {
|
||||||
Log.v(TAG, "validatePushToken()")
|
Log.v(TAG, "validatePushToken()")
|
||||||
|
|
||||||
addPresentedChallenge(Challenge.PUSH)
|
addPresentedChallenge(Challenge.PUSH)
|
||||||
@@ -410,7 +432,7 @@ class RegistrationViewModel : ViewModel() {
|
|||||||
|
|
||||||
viewModelScope.launch {
|
viewModelScope.launch {
|
||||||
Log.d(TAG, "Getting session in order to perform push token verification…")
|
Log.d(TAG, "Getting session in order to perform push token verification…")
|
||||||
val session = getOrCreateValidSession(context, errorHandler) ?: return@launch bail { Log.i(TAG, "Could not create valid session for submitting a push challenge token.") }
|
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.body.requestedInformation).contains(Challenge.PUSH)) {
|
||||||
Log.d(TAG, "Push submission no longer necessary, bailing.")
|
Log.d(TAG, "Push submission no longer necessary, bailing.")
|
||||||
@@ -425,14 +447,14 @@ class RegistrationViewModel : ViewModel() {
|
|||||||
Log.d(TAG, "Requesting push challenge token…")
|
Log.d(TAG, "Requesting push challenge token…")
|
||||||
val pushSubmissionResult = RegistrationRepository.requestAndVerifyPushToken(context, session.body.id, e164, password)
|
val pushSubmissionResult = RegistrationRepository.requestAndVerifyPushToken(context, session.body.id, e164, password)
|
||||||
Log.d(TAG, "Push challenge token submitted.")
|
Log.d(TAG, "Push challenge token submitted.")
|
||||||
handleSessionStateResult(context, pushSubmissionResult, errorHandler)
|
handleSessionStateResult(context, pushSubmissionResult)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return whether the request was successful and execution should continue
|
* @return whether the request was successful and execution should continue
|
||||||
*/
|
*/
|
||||||
private suspend fun handleSessionStateResult(context: Context, sessionResult: RegistrationResult, errorHandler: (RegistrationResult) -> Unit): Boolean {
|
private suspend fun handleSessionStateResult(context: Context, sessionResult: VerificationCodeRequestResult): Boolean {
|
||||||
Log.v(TAG, "handleSessionStateResult()")
|
Log.v(TAG, "handleSessionStateResult()")
|
||||||
when (sessionResult) {
|
when (sessionResult) {
|
||||||
is UnknownError -> {
|
is UnknownError -> {
|
||||||
@@ -492,14 +514,18 @@ class RegistrationViewModel : ViewModel() {
|
|||||||
is AlreadyVerified -> Log.i(TAG, "Received AlreadyVerified", sessionResult.getCause())
|
is AlreadyVerified -> Log.i(TAG, "Received AlreadyVerified", sessionResult.getCause())
|
||||||
}
|
}
|
||||||
setInProgress(false)
|
setInProgress(false)
|
||||||
errorHandler(sessionResult)
|
store.update {
|
||||||
|
it.copy(
|
||||||
|
sessionStateError = sessionResult
|
||||||
|
)
|
||||||
|
}
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return whether the request was successful and execution should continue
|
* @return whether the request was successful and execution should continue
|
||||||
*/
|
*/
|
||||||
private suspend fun handleRegistrationResult(context: Context, registrationData: RegistrationData, registrationResult: RegisterAccountResult, reglockEnabled: Boolean, errorHandler: (RegisterAccountResult) -> Unit): Boolean {
|
private suspend fun handleRegistrationResult(context: Context, registrationData: RegistrationData, registrationResult: RegisterAccountResult, reglockEnabled: Boolean): Boolean {
|
||||||
Log.v(TAG, "handleRegistrationResult()")
|
Log.v(TAG, "handleRegistrationResult()")
|
||||||
when (registrationResult) {
|
when (registrationResult) {
|
||||||
is RegisterAccountResult.Success -> {
|
is RegisterAccountResult.Success -> {
|
||||||
@@ -521,6 +547,7 @@ class RegistrationViewModel : ViewModel() {
|
|||||||
is RegisterAccountResult.RegistrationLocked -> {
|
is RegisterAccountResult.RegistrationLocked -> {
|
||||||
Log.i(TAG, "Account is registration locked!", registrationResult.getCause())
|
Log.i(TAG, "Account is registration locked!", registrationResult.getCause())
|
||||||
}
|
}
|
||||||
|
|
||||||
is RegisterAccountResult.SvrWrongPin -> {
|
is RegisterAccountResult.SvrWrongPin -> {
|
||||||
Log.i(TAG, "Received wrong SVR PIN response! ${registrationResult.triesRemaining} tries remaining.")
|
Log.i(TAG, "Received wrong SVR PIN response! ${registrationResult.triesRemaining} tries remaining.")
|
||||||
updateSvrTriesRemaining(registrationResult.triesRemaining)
|
updateSvrTriesRemaining(registrationResult.triesRemaining)
|
||||||
@@ -535,7 +562,11 @@ class RegistrationViewModel : ViewModel() {
|
|||||||
is RegisterAccountResult.UnknownError -> Log.i(TAG, "Received error when trying to register!", registrationResult.getCause())
|
is RegisterAccountResult.UnknownError -> Log.i(TAG, "Received error when trying to register!", registrationResult.getCause())
|
||||||
}
|
}
|
||||||
setInProgress(false)
|
setInProgress(false)
|
||||||
errorHandler(registrationResult)
|
store.update {
|
||||||
|
it.copy(
|
||||||
|
registerAccountError = registrationResult
|
||||||
|
)
|
||||||
|
}
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -564,7 +595,7 @@ class RegistrationViewModel : ViewModel() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun verifyReRegisterWithPin(context: Context, pin: String, wrongPinHandler: () -> Unit, registrationErrorHandler: (RegisterAccountResult) -> Unit) {
|
fun verifyReRegisterWithPin(context: Context, pin: String, wrongPinHandler: () -> Unit) {
|
||||||
setInProgress(true)
|
setInProgress(true)
|
||||||
|
|
||||||
// Local recovery password
|
// Local recovery password
|
||||||
@@ -572,7 +603,7 @@ class RegistrationViewModel : ViewModel() {
|
|||||||
if (RegistrationRepository.doesPinMatchLocalHash(pin)) {
|
if (RegistrationRepository.doesPinMatchLocalHash(pin)) {
|
||||||
Log.d(TAG, "Found recovery password, attempting to re-register.")
|
Log.d(TAG, "Found recovery password, attempting to re-register.")
|
||||||
viewModelScope.launch(context = coroutineExceptionHandler) {
|
viewModelScope.launch(context = coroutineExceptionHandler) {
|
||||||
verifyReRegisterInternal(context, pin, SignalStore.svr.getOrCreateMasterKey(), registrationErrorHandler)
|
verifyReRegisterInternal(context, pin, SignalStore.svr.getOrCreateMasterKey())
|
||||||
setInProgress(false)
|
setInProgress(false)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@@ -594,7 +625,7 @@ class RegistrationViewModel : ViewModel() {
|
|||||||
val masterKey = RegistrationRepository.fetchMasterKeyFromSvrRemote(pin, svr2Credentials, svr3Credentials)
|
val masterKey = RegistrationRepository.fetchMasterKeyFromSvrRemote(pin, svr2Credentials, svr3Credentials)
|
||||||
setRecoveryPassword(masterKey.deriveRegistrationRecoveryPassword())
|
setRecoveryPassword(masterKey.deriveRegistrationRecoveryPassword())
|
||||||
updateSvrTriesRemaining(10)
|
updateSvrTriesRemaining(10)
|
||||||
verifyReRegisterInternal(context, pin, masterKey, registrationErrorHandler)
|
verifyReRegisterInternal(context, pin, masterKey)
|
||||||
} catch (rejectedPin: SvrWrongPinException) {
|
} catch (rejectedPin: SvrWrongPinException) {
|
||||||
Log.w(TAG, "Submitted PIN was rejected by SVR.", rejectedPin)
|
Log.w(TAG, "Submitted PIN was rejected by SVR.", rejectedPin)
|
||||||
updateSvrTriesRemaining(rejectedPin.triesRemaining)
|
updateSvrTriesRemaining(rejectedPin.triesRemaining)
|
||||||
@@ -615,7 +646,7 @@ class RegistrationViewModel : ViewModel() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private suspend fun verifyReRegisterInternal(context: Context, pin: String, masterKey: MasterKey, registrationErrorHandler: (RegisterAccountResult) -> Unit) {
|
private suspend fun verifyReRegisterInternal(context: Context, pin: String, masterKey: MasterKey) {
|
||||||
Log.v(TAG, "verifyReRegisterInternal()")
|
Log.v(TAG, "verifyReRegisterInternal()")
|
||||||
updateFcmToken(context)
|
updateFcmToken(context)
|
||||||
|
|
||||||
@@ -625,7 +656,7 @@ class RegistrationViewModel : ViewModel() {
|
|||||||
val result = resultAndRegLockStatus.first
|
val result = resultAndRegLockStatus.first
|
||||||
val reglockEnabled = resultAndRegLockStatus.second
|
val reglockEnabled = resultAndRegLockStatus.second
|
||||||
|
|
||||||
handleRegistrationResult(context, registrationData, result, reglockEnabled, registrationErrorHandler)
|
handleRegistrationResult(context, registrationData, result, reglockEnabled)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -652,7 +683,7 @@ class RegistrationViewModel : ViewModel() {
|
|||||||
return Pair(RegistrationRepository.registerAccount(context = context, sessionId = sessionId, registrationData = registrationData, pin = pin) { masterKey }, true)
|
return Pair(RegistrationRepository.registerAccount(context = context, sessionId = sessionId, registrationData = registrationData, pin = pin) { masterKey }, true)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun verifyCodeWithoutRegistrationLock(context: Context, code: String, submissionErrorHandler: (RegistrationResult) -> Unit, registrationErrorHandler: (RegisterAccountResult) -> Unit) {
|
fun verifyCodeWithoutRegistrationLock(context: Context, code: String) {
|
||||||
Log.v(TAG, "verifyCodeWithoutRegistrationLock()")
|
Log.v(TAG, "verifyCodeWithoutRegistrationLock()")
|
||||||
store.update {
|
store.update {
|
||||||
it.copy(
|
it.copy(
|
||||||
@@ -665,15 +696,13 @@ class RegistrationViewModel : ViewModel() {
|
|||||||
viewModelScope.launch(context = coroutineExceptionHandler) {
|
viewModelScope.launch(context = coroutineExceptionHandler) {
|
||||||
verifyCodeInternal(
|
verifyCodeInternal(
|
||||||
context = context,
|
context = context,
|
||||||
pin = null,
|
|
||||||
registrationLocked = false,
|
registrationLocked = false,
|
||||||
submissionErrorHandler = submissionErrorHandler,
|
pin = null
|
||||||
registrationErrorHandler = registrationErrorHandler
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun verifyCodeAndRegisterAccountWithRegistrationLock(context: Context, pin: String, submissionErrorHandler: (RegistrationResult) -> Unit, registrationErrorHandler: (RegisterAccountResult) -> Unit) {
|
fun verifyCodeAndRegisterAccountWithRegistrationLock(context: Context, pin: String) {
|
||||||
Log.v(TAG, "verifyCodeAndRegisterAccountWithRegistrationLock()")
|
Log.v(TAG, "verifyCodeAndRegisterAccountWithRegistrationLock()")
|
||||||
store.update {
|
store.update {
|
||||||
it.copy(
|
it.copy(
|
||||||
@@ -684,15 +713,13 @@ class RegistrationViewModel : ViewModel() {
|
|||||||
viewModelScope.launch {
|
viewModelScope.launch {
|
||||||
verifyCodeInternal(
|
verifyCodeInternal(
|
||||||
context = context,
|
context = context,
|
||||||
pin = pin,
|
|
||||||
registrationLocked = true,
|
registrationLocked = true,
|
||||||
submissionErrorHandler = submissionErrorHandler,
|
pin = pin
|
||||||
registrationErrorHandler = registrationErrorHandler
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private suspend fun verifyCodeInternal(context: Context, registrationLocked: Boolean, pin: String?, submissionErrorHandler: (RegistrationResult) -> Unit, registrationErrorHandler: (RegisterAccountResult) -> Unit) {
|
private suspend fun verifyCodeInternal(context: Context, registrationLocked: Boolean, pin: String?) {
|
||||||
Log.d(TAG, "Getting valid session in order to submit verification code.")
|
Log.d(TAG, "Getting valid session in order to submit verification code.")
|
||||||
|
|
||||||
if (registrationLocked && pin.isNullOrBlank()) {
|
if (registrationLocked && pin.isNullOrBlank()) {
|
||||||
@@ -701,7 +728,7 @@ class RegistrationViewModel : ViewModel() {
|
|||||||
|
|
||||||
var reglock = registrationLocked
|
var reglock = registrationLocked
|
||||||
|
|
||||||
val sessionId = getOrCreateValidSession(context, submissionErrorHandler)?.body?.id ?: return
|
val sessionId = getOrCreateValidSession(context)?.body?.id ?: return
|
||||||
val registrationData = getRegistrationData()
|
val registrationData = getRegistrationData()
|
||||||
|
|
||||||
Log.d(TAG, "Submitting verification code…")
|
Log.d(TAG, "Submitting verification code…")
|
||||||
@@ -714,7 +741,7 @@ class RegistrationViewModel : ViewModel() {
|
|||||||
Log.d(TAG, "Verification code submission network call completed. Submission successful? $submissionSuccessful Account already verified? $alreadyVerified")
|
Log.d(TAG, "Verification code submission network call completed. Submission successful? $submissionSuccessful Account already verified? $alreadyVerified")
|
||||||
|
|
||||||
if (!submissionSuccessful && !alreadyVerified) {
|
if (!submissionSuccessful && !alreadyVerified) {
|
||||||
handleSessionStateResult(context, verificationResponse, submissionErrorHandler)
|
handleSessionStateResult(context, verificationResponse)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -758,16 +785,16 @@ class RegistrationViewModel : ViewModel() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (result != null) {
|
if (result != null) {
|
||||||
handleRegistrationResult(context, registrationData, result, reglock, registrationErrorHandler)
|
handleRegistrationResult(context, registrationData, result, reglock)
|
||||||
} else {
|
} else {
|
||||||
Log.w(TAG, "No registration response received!")
|
Log.w(TAG, "No registration response received!")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private suspend fun registerVerifiedSession(context: Context, sessionId: String, registrationErrorHandler: (RegisterAccountResult) -> Unit) {
|
private suspend fun registerVerifiedSession(context: Context, sessionId: String) {
|
||||||
val registrationData = getRegistrationData()
|
val registrationData = getRegistrationData()
|
||||||
val registrationResponse: RegisterAccountResult = RegistrationRepository.registerAccount(context, sessionId, registrationData)
|
val registrationResponse: RegisterAccountResult = RegistrationRepository.registerAccount(context, sessionId, registrationData)
|
||||||
handleRegistrationResult(context, registrationData, registrationResponse, false, registrationErrorHandler)
|
handleRegistrationResult(context, registrationData, registrationResponse, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
private suspend fun onSuccessfulRegistration(context: Context, registrationData: RegistrationData, remoteResult: RegistrationRepository.AccountRegistrationResult, reglockEnabled: Boolean) {
|
private suspend fun onSuccessfulRegistration(context: Context, registrationData: RegistrationData, remoteResult: RegistrationRepository.AccountRegistrationResult, reglockEnabled: Boolean) {
|
||||||
@@ -813,7 +840,7 @@ class RegistrationViewModel : ViewModel() {
|
|||||||
RegistrationUtil.maybeMarkRegistrationComplete()
|
RegistrationUtil.maybeMarkRegistrationComplete()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun clearNetworkError() {
|
fun networkErrorShown() {
|
||||||
store.update {
|
store.update {
|
||||||
it.copy(networkError = null)
|
it.copy(networkError = null)
|
||||||
}
|
}
|
||||||
|
|||||||
+37
-35
@@ -11,12 +11,10 @@ import android.view.View
|
|||||||
import android.widget.Toast
|
import android.widget.Toast
|
||||||
import androidx.activity.OnBackPressedCallback
|
import androidx.activity.OnBackPressedCallback
|
||||||
import androidx.fragment.app.activityViewModels
|
import androidx.fragment.app.activityViewModels
|
||||||
import androidx.lifecycle.lifecycleScope
|
|
||||||
import androidx.navigation.fragment.NavHostFragment
|
import androidx.navigation.fragment.NavHostFragment
|
||||||
import androidx.navigation.fragment.findNavController
|
import androidx.navigation.fragment.findNavController
|
||||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||||
import com.google.i18n.phonenumbers.PhoneNumberUtil
|
import com.google.i18n.phonenumbers.PhoneNumberUtil
|
||||||
import kotlinx.coroutines.launch
|
|
||||||
import org.greenrobot.eventbus.Subscribe
|
import org.greenrobot.eventbus.Subscribe
|
||||||
import org.greenrobot.eventbus.ThreadMode
|
import org.greenrobot.eventbus.ThreadMode
|
||||||
import org.signal.core.util.logging.Log
|
import org.signal.core.util.logging.Log
|
||||||
@@ -76,7 +74,7 @@ class EnterCodeFragment : LoggingFragment(R.layout.fragment_registration_enter_c
|
|||||||
}
|
}
|
||||||
|
|
||||||
binding.code.setOnCompleteListener {
|
binding.code.setOnCompleteListener {
|
||||||
sharedViewModel.verifyCodeWithoutRegistrationLock(requireContext(), it, ::handleSessionErrorResponse, ::handleRegistrationErrorResponse)
|
sharedViewModel.verifyCodeWithoutRegistrationLock(requireContext(), it)
|
||||||
}
|
}
|
||||||
|
|
||||||
binding.havingTroubleButton.setOnClickListener {
|
binding.havingTroubleButton.setOnClickListener {
|
||||||
@@ -86,14 +84,14 @@ class EnterCodeFragment : LoggingFragment(R.layout.fragment_registration_enter_c
|
|||||||
binding.callMeCountDown.apply {
|
binding.callMeCountDown.apply {
|
||||||
setTextResources(R.string.RegistrationActivity_call, R.string.RegistrationActivity_call_me_instead_available_in)
|
setTextResources(R.string.RegistrationActivity_call, R.string.RegistrationActivity_call_me_instead_available_in)
|
||||||
setOnClickListener {
|
setOnClickListener {
|
||||||
sharedViewModel.requestVerificationCall(requireContext(), ::handleSessionErrorResponse)
|
sharedViewModel.requestVerificationCall(requireContext())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
binding.resendSmsCountDown.apply {
|
binding.resendSmsCountDown.apply {
|
||||||
setTextResources(R.string.RegistrationActivity_resend_code, R.string.RegistrationActivity_resend_sms_available_in)
|
setTextResources(R.string.RegistrationActivity_resend_code, R.string.RegistrationActivity_resend_sms_available_in)
|
||||||
setOnClickListener {
|
setOnClickListener {
|
||||||
sharedViewModel.requestSmsCode(requireContext(), ::handleSessionErrorResponse)
|
sharedViewModel.requestSmsCode(requireContext())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -114,6 +112,16 @@ class EnterCodeFragment : LoggingFragment(R.layout.fragment_registration_enter_c
|
|||||||
}
|
}
|
||||||
|
|
||||||
sharedViewModel.uiState.observe(viewLifecycleOwner) {
|
sharedViewModel.uiState.observe(viewLifecycleOwner) {
|
||||||
|
it.sessionStateError?.let { error ->
|
||||||
|
handleSessionErrorResponse(error)
|
||||||
|
sharedViewModel.sessionStateErrorShown()
|
||||||
|
}
|
||||||
|
|
||||||
|
it.registerAccountError?.let { error ->
|
||||||
|
handleRegistrationErrorResponse(error)
|
||||||
|
sharedViewModel.registerAccountErrorShown()
|
||||||
|
}
|
||||||
|
|
||||||
binding.resendSmsCountDown.startCountDownTo(it.nextSmsTimestamp)
|
binding.resendSmsCountDown.startCountDownTo(it.nextSmsTimestamp)
|
||||||
binding.callMeCountDown.startCountDownTo(it.nextCallTimestamp)
|
binding.callMeCountDown.startCountDownTo(it.nextCallTimestamp)
|
||||||
if (it.inProgress) {
|
if (it.inProgress) {
|
||||||
@@ -132,29 +140,25 @@ class EnterCodeFragment : LoggingFragment(R.layout.fragment_registration_enter_c
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun handleSessionErrorResponse(result: RegistrationResult) {
|
private fun handleSessionErrorResponse(result: VerificationCodeRequestResult) {
|
||||||
viewLifecycleOwner.lifecycleScope.launch {
|
when (result) {
|
||||||
when (result) {
|
is VerificationCodeRequestResult.Success -> throw IllegalStateException("Session error handler called on successful response!")
|
||||||
is VerificationCodeRequestResult.Success -> binding.keyboard.displaySuccess()
|
is VerificationCodeRequestResult.RateLimited -> presentRateLimitedDialog()
|
||||||
is VerificationCodeRequestResult.RateLimited -> presentRateLimitedDialog()
|
is VerificationCodeRequestResult.AttemptsExhausted -> presentAccountLocked()
|
||||||
is VerificationCodeRequestResult.AttemptsExhausted -> presentAccountLocked()
|
is VerificationCodeRequestResult.RegistrationLocked -> presentRegistrationLocked(result.timeRemaining)
|
||||||
is VerificationCodeRequestResult.RegistrationLocked -> presentRegistrationLocked(result.timeRemaining)
|
else -> presentGenericError(result)
|
||||||
else -> presentGenericError(result)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun handleRegistrationErrorResponse(result: RegisterAccountResult) {
|
private fun handleRegistrationErrorResponse(result: RegisterAccountResult) {
|
||||||
viewLifecycleOwner.lifecycleScope.launch {
|
when (result) {
|
||||||
when (result) {
|
is RegisterAccountResult.Success -> throw IllegalStateException("Register account error handler called on successful response!")
|
||||||
is RegisterAccountResult.Success -> binding.keyboard.displaySuccess()
|
is RegisterAccountResult.RegistrationLocked -> presentRegistrationLocked(result.timeRemaining)
|
||||||
is RegisterAccountResult.RegistrationLocked -> presentRegistrationLocked(result.timeRemaining)
|
is RegisterAccountResult.AuthorizationFailed -> presentIncorrectCodeDialog()
|
||||||
is RegisterAccountResult.AuthorizationFailed -> presentIncorrectCodeDialog()
|
is RegisterAccountResult.AttemptsExhausted -> presentAccountLocked()
|
||||||
is RegisterAccountResult.AttemptsExhausted -> presentAccountLocked()
|
is RegisterAccountResult.RateLimited -> presentRateLimitedDialog()
|
||||||
is RegisterAccountResult.RateLimited -> presentRateLimitedDialog()
|
|
||||||
|
|
||||||
else -> presentGenericError(result)
|
else -> presentGenericError(result)
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -202,19 +206,17 @@ class EnterCodeFragment : LoggingFragment(R.layout.fragment_registration_enter_c
|
|||||||
private fun presentIncorrectCodeDialog() {
|
private fun presentIncorrectCodeDialog() {
|
||||||
sharedViewModel.incrementIncorrectCodeAttempts()
|
sharedViewModel.incrementIncorrectCodeAttempts()
|
||||||
|
|
||||||
viewLifecycleOwner.lifecycleScope.launch {
|
Toast.makeText(requireContext(), R.string.RegistrationActivity_incorrect_code, Toast.LENGTH_LONG).show()
|
||||||
Toast.makeText(requireContext(), R.string.RegistrationActivity_incorrect_code, Toast.LENGTH_LONG).show()
|
|
||||||
|
|
||||||
binding.keyboard.displayFailure().addListener(object : AssertedSuccessListener<Boolean?>() {
|
binding.keyboard.displayFailure().addListener(object : AssertedSuccessListener<Boolean?>() {
|
||||||
override fun onSuccess(result: Boolean?) {
|
override fun onSuccess(result: Boolean?) {
|
||||||
binding.callMeCountDown.visibility = View.VISIBLE
|
binding.callMeCountDown.visibility = View.VISIBLE
|
||||||
binding.resendSmsCountDown.visibility = View.VISIBLE
|
binding.resendSmsCountDown.visibility = View.VISIBLE
|
||||||
binding.wrongNumber.visibility = View.VISIBLE
|
binding.wrongNumber.visibility = View.VISIBLE
|
||||||
binding.code.clear()
|
binding.code.clear()
|
||||||
binding.keyboard.displayKeyboard()
|
binding.keyboard.displayKeyboard()
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun presentGenericError(requestResult: RegistrationResult) {
|
private fun presentGenericError(requestResult: RegistrationResult) {
|
||||||
|
|||||||
+85
-60
@@ -25,7 +25,6 @@ import androidx.core.view.MenuProvider
|
|||||||
import androidx.core.widget.addTextChangedListener
|
import androidx.core.widget.addTextChangedListener
|
||||||
import androidx.fragment.app.activityViewModels
|
import androidx.fragment.app.activityViewModels
|
||||||
import androidx.fragment.app.viewModels
|
import androidx.fragment.app.viewModels
|
||||||
import androidx.lifecycle.lifecycleScope
|
|
||||||
import androidx.navigation.fragment.NavHostFragment
|
import androidx.navigation.fragment.NavHostFragment
|
||||||
import androidx.navigation.fragment.findNavController
|
import androidx.navigation.fragment.findNavController
|
||||||
import com.google.android.gms.common.ConnectionResult
|
import com.google.android.gms.common.ConnectionResult
|
||||||
@@ -36,7 +35,6 @@ import com.google.android.material.textfield.TextInputEditText
|
|||||||
import com.google.i18n.phonenumbers.NumberParseException
|
import com.google.i18n.phonenumbers.NumberParseException
|
||||||
import com.google.i18n.phonenumbers.PhoneNumberUtil
|
import com.google.i18n.phonenumbers.PhoneNumberUtil
|
||||||
import com.google.i18n.phonenumbers.Phonenumber.PhoneNumber
|
import com.google.i18n.phonenumbers.Phonenumber.PhoneNumber
|
||||||
import kotlinx.coroutines.launch
|
|
||||||
import org.signal.core.util.isNotNullOrBlank
|
import org.signal.core.util.isNotNullOrBlank
|
||||||
import org.signal.core.util.logging.Log
|
import org.signal.core.util.logging.Log
|
||||||
import org.thoughtcrime.securesms.LoggingFragment
|
import org.thoughtcrime.securesms.LoggingFragment
|
||||||
@@ -46,8 +44,9 @@ import org.thoughtcrime.securesms.databinding.FragmentRegistrationEnterPhoneNumb
|
|||||||
import org.thoughtcrime.securesms.phonenumbers.PhoneNumberFormatter
|
import org.thoughtcrime.securesms.phonenumbers.PhoneNumberFormatter
|
||||||
import org.thoughtcrime.securesms.registration.data.RegistrationRepository
|
import org.thoughtcrime.securesms.registration.data.RegistrationRepository
|
||||||
import org.thoughtcrime.securesms.registration.data.network.Challenge
|
import org.thoughtcrime.securesms.registration.data.network.Challenge
|
||||||
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.RegistrationSessionCreationResult
|
||||||
|
import org.thoughtcrime.securesms.registration.data.network.RegistrationSessionResult
|
||||||
import org.thoughtcrime.securesms.registration.data.network.VerificationCodeRequestResult
|
import org.thoughtcrime.securesms.registration.data.network.VerificationCodeRequestResult
|
||||||
import org.thoughtcrime.securesms.registration.fragments.RegistrationViewDelegate.setDebugLogSubmitMultiTapView
|
import org.thoughtcrime.securesms.registration.fragments.RegistrationViewDelegate.setDebugLogSubmitMultiTapView
|
||||||
import org.thoughtcrime.securesms.registration.ui.RegistrationCheckpoint
|
import org.thoughtcrime.securesms.registration.ui.RegistrationCheckpoint
|
||||||
@@ -116,10 +115,21 @@ class EnterPhoneNumberFragment : LoggingFragment(R.layout.fragment_registration_
|
|||||||
|
|
||||||
sharedState.networkError?.let {
|
sharedState.networkError?.let {
|
||||||
presentNetworkError(it)
|
presentNetworkError(it)
|
||||||
|
sharedViewModel.networkErrorShown()
|
||||||
|
}
|
||||||
|
|
||||||
|
sharedState.sessionCreationError?.let {
|
||||||
|
handleSessionCreationError(it)
|
||||||
|
sharedViewModel.sessionCreationErrorShown()
|
||||||
|
}
|
||||||
|
|
||||||
|
sharedState.sessionStateError?.let {
|
||||||
|
handleSessionStateError(it)
|
||||||
|
sharedViewModel.sessionStateErrorShown()
|
||||||
}
|
}
|
||||||
|
|
||||||
if (sharedState.challengesRequested.contains(Challenge.CAPTCHA) && sharedState.captchaToken.isNotNullOrBlank()) {
|
if (sharedState.challengesRequested.contains(Challenge.CAPTCHA) && sharedState.captchaToken.isNotNullOrBlank()) {
|
||||||
sharedViewModel.submitCaptchaToken(requireContext(), ::handleErrorResponse)
|
sharedViewModel.submitCaptchaToken(requireContext())
|
||||||
} else if (sharedState.challengesRemaining.isNotEmpty()) {
|
} else if (sharedState.challengesRemaining.isNotEmpty()) {
|
||||||
handleChallenges(sharedState.challengesRemaining)
|
handleChallenges(sharedState.challengesRemaining)
|
||||||
} else if (sharedState.registrationCheckpoint >= RegistrationCheckpoint.PHONE_NUMBER_CONFIRMED && sharedState.canSkipSms) {
|
} else if (sharedState.registrationCheckpoint >= RegistrationCheckpoint.PHONE_NUMBER_CONFIRMED && sharedState.canSkipSms) {
|
||||||
@@ -184,7 +194,7 @@ class EnterPhoneNumberFragment : LoggingFragment(R.layout.fragment_registration_
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun performPushChallenge() {
|
private fun performPushChallenge() {
|
||||||
sharedViewModel.requestAndSubmitPushToken(requireContext(), ::handleErrorResponse)
|
sharedViewModel.requestAndSubmitPushToken(requireContext())
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun initializeInputFields() {
|
private fun initializeInputFields() {
|
||||||
@@ -294,67 +304,82 @@ class EnterPhoneNumberFragment : LoggingFragment(R.layout.fragment_registration_
|
|||||||
Log.i(TAG, "Unknown error during verification code request", networkError)
|
Log.i(TAG, "Unknown error during verification code request", networkError)
|
||||||
MaterialAlertDialogBuilder(requireContext()).apply {
|
MaterialAlertDialogBuilder(requireContext()).apply {
|
||||||
setMessage(R.string.RegistrationActivity_unable_to_connect_to_service)
|
setMessage(R.string.RegistrationActivity_unable_to_connect_to_service)
|
||||||
setPositiveButton(android.R.string.ok) { _, _ -> sharedViewModel.clearNetworkError() }
|
setPositiveButton(android.R.string.ok, null)
|
||||||
setOnCancelListener { sharedViewModel.clearNetworkError() }
|
|
||||||
setOnDismissListener { sharedViewModel.clearNetworkError() }
|
|
||||||
show()
|
show()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun handleErrorResponse(result: RegistrationResult) {
|
private fun handleSessionCreationError(result: RegistrationSessionResult) {
|
||||||
viewLifecycleOwner.lifecycleScope.launch {
|
if (!result.isSuccess()) {
|
||||||
if (!result.isSuccess()) {
|
Log.i(TAG, "Handling error response.", result.getCause())
|
||||||
Log.i(TAG, "Handling error response.", 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), 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()))
|
||||||
}
|
}
|
||||||
when (result) {
|
|
||||||
is RegistrationSessionCreationResult.Success,
|
|
||||||
is VerificationCodeRequestResult.Success -> Unit
|
|
||||||
|
|
||||||
is RegistrationSessionCreationResult.AttemptsExhausted,
|
is RegistrationSessionCreationResult.ServerUnableToParse -> presentRemoteErrorDialog(getString(R.string.RegistrationActivity_unable_to_connect_to_service))
|
||||||
is VerificationCodeRequestResult.AttemptsExhausted -> presentRemoteErrorDialog(getString(R.string.RegistrationActivity_rate_limited_to_service))
|
is RegistrationSessionCheckResult.SessionNotFound -> presentRemoteErrorDialog(getString(R.string.RegistrationActivity_unable_to_connect_to_service))
|
||||||
|
is RegistrationSessionCheckResult.UnknownError,
|
||||||
|
is RegistrationSessionCreationResult.UnknownError -> presentRemoteErrorDialog(getString(R.string.RegistrationActivity_unable_to_connect_to_service))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
is VerificationCodeRequestResult.ChallengeRequired -> {
|
private fun handleSessionStateError(result: VerificationCodeRequestResult) {
|
||||||
handleChallenges(result.challenges)
|
if (!result.isSuccess()) {
|
||||||
}
|
Log.i(TAG, "Handling error response.", result.getCause())
|
||||||
|
}
|
||||||
|
when (result) {
|
||||||
|
is VerificationCodeRequestResult.Success -> throw IllegalStateException("Session error handler called on successful response!")
|
||||||
|
|
||||||
is VerificationCodeRequestResult.ExternalServiceFailure -> presentRemoteErrorDialog(getString(R.string.RegistrationActivity_unable_to_connect_to_service), skipToNextScreen)
|
is VerificationCodeRequestResult.AttemptsExhausted -> presentRemoteErrorDialog(getString(R.string.RegistrationActivity_rate_limited_to_service))
|
||||||
is VerificationCodeRequestResult.ImpossibleNumber -> {
|
|
||||||
MaterialAlertDialogBuilder(requireContext()).apply {
|
|
||||||
setMessage(getString(R.string.RegistrationActivity_the_number_you_specified_s_is_invalid, fragmentViewModel.phoneNumber?.toE164()))
|
|
||||||
setPositiveButton(android.R.string.ok, null)
|
|
||||||
show()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
is VerificationCodeRequestResult.InvalidTransportModeFailure -> {
|
is VerificationCodeRequestResult.ChallengeRequired -> {
|
||||||
MaterialAlertDialogBuilder(requireContext()).apply {
|
handleChallenges(result.challenges)
|
||||||
setMessage(R.string.RegistrationActivity_we_couldnt_send_you_a_verification_code)
|
|
||||||
setPositiveButton(R.string.RegistrationActivity_voice_call) { _, _ ->
|
|
||||||
sharedViewModel.requestVerificationCall(requireContext(), ::handleErrorResponse)
|
|
||||||
}
|
|
||||||
setNegativeButton(R.string.RegistrationActivity_cancel, null)
|
|
||||||
show()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
is RegistrationSessionCreationResult.MalformedRequest,
|
|
||||||
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.NonNormalizedNumber -> handleNonNormalizedNumberError(result.originalNumber, result.normalizedNumber, fragmentViewModel.mode)
|
|
||||||
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()))
|
|
||||||
}
|
|
||||||
|
|
||||||
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()))
|
|
||||||
}
|
|
||||||
|
|
||||||
is VerificationCodeRequestResult.TokenNotAccepted -> presentRemoteErrorDialog(getString(R.string.RegistrationActivity_we_need_to_verify_that_youre_human)) { _, _ -> moveToCaptcha() }
|
|
||||||
else -> presentRemoteErrorDialog(getString(R.string.RegistrationActivity_unable_to_connect_to_service))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
is VerificationCodeRequestResult.ExternalServiceFailure -> presentRemoteErrorDialog(getString(R.string.RegistrationActivity_unable_to_connect_to_service), skipToNextScreen)
|
||||||
|
is VerificationCodeRequestResult.ImpossibleNumber -> {
|
||||||
|
MaterialAlertDialogBuilder(requireContext()).apply {
|
||||||
|
setMessage(getString(R.string.RegistrationActivity_the_number_you_specified_s_is_invalid, fragmentViewModel.phoneNumber?.toE164()))
|
||||||
|
setPositiveButton(android.R.string.ok, null)
|
||||||
|
show()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
is VerificationCodeRequestResult.InvalidTransportModeFailure -> {
|
||||||
|
MaterialAlertDialogBuilder(requireContext()).apply {
|
||||||
|
setMessage(R.string.RegistrationActivity_we_couldnt_send_you_a_verification_code)
|
||||||
|
setPositiveButton(R.string.RegistrationActivity_voice_call) { _, _ ->
|
||||||
|
sharedViewModel.requestVerificationCall(requireContext())
|
||||||
|
}
|
||||||
|
setNegativeButton(R.string.RegistrationActivity_cancel, null)
|
||||||
|
show()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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.NonNormalizedNumber -> handleNonNormalizedNumberError(result.originalNumber, result.normalizedNumber, fragmentViewModel.mode)
|
||||||
|
|
||||||
|
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()))
|
||||||
|
}
|
||||||
|
|
||||||
|
is VerificationCodeRequestResult.TokenNotAccepted -> presentRemoteErrorDialog(getString(R.string.RegistrationActivity_we_need_to_verify_that_youre_human)) { _, _ -> moveToCaptcha() }
|
||||||
|
|
||||||
|
is VerificationCodeRequestResult.RegistrationLocked -> presentRemoteErrorDialog(getString(R.string.RegistrationActivity_unable_to_connect_to_service))
|
||||||
|
is VerificationCodeRequestResult.AlreadyVerified -> presentRemoteErrorDialog(getString(R.string.RegistrationActivity_unable_to_connect_to_service))
|
||||||
|
is VerificationCodeRequestResult.NoSuchSession -> presentRemoteErrorDialog(getString(R.string.RegistrationActivity_unable_to_connect_to_service))
|
||||||
|
is VerificationCodeRequestResult.UnknownError -> presentRemoteErrorDialog(getString(R.string.RegistrationActivity_unable_to_connect_to_service))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -390,8 +415,8 @@ class EnterPhoneNumberFragment : LoggingFragment(R.layout.fragment_registration_
|
|||||||
phoneNumberInputLayout.setText(phoneNumber.nationalNumber.toString())
|
phoneNumberInputLayout.setText(phoneNumber.nationalNumber.toString())
|
||||||
when (mode) {
|
when (mode) {
|
||||||
RegistrationRepository.Mode.SMS_WITH_LISTENER,
|
RegistrationRepository.Mode.SMS_WITH_LISTENER,
|
||||||
RegistrationRepository.Mode.SMS_WITHOUT_LISTENER -> sharedViewModel.requestSmsCode(requireContext(), ::handleErrorResponse)
|
RegistrationRepository.Mode.SMS_WITHOUT_LISTENER -> sharedViewModel.requestSmsCode(requireContext())
|
||||||
RegistrationRepository.Mode.PHONE_CALL -> sharedViewModel.requestVerificationCall(requireContext(), ::handleErrorResponse)
|
RegistrationRepository.Mode.PHONE_CALL -> sharedViewModel.requestVerificationCall(requireContext())
|
||||||
}
|
}
|
||||||
dialogInterface.dismiss()
|
dialogInterface.dismiss()
|
||||||
}
|
}
|
||||||
@@ -510,7 +535,7 @@ class EnterPhoneNumberFragment : LoggingFragment(R.layout.fragment_registration_
|
|||||||
if (missingFcmConsentRequired) {
|
if (missingFcmConsentRequired) {
|
||||||
handlePromptForNoPlayServices()
|
handlePromptForNoPlayServices()
|
||||||
} else {
|
} else {
|
||||||
sharedViewModel.onUserConfirmedPhoneNumber(requireContext(), ::handleErrorResponse)
|
sharedViewModel.onUserConfirmedPhoneNumber(requireContext())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
setNegativeButton(R.string.RegistrationActivity_edit_number) { _, _ -> handleConfirmNumberDialogCanceled() }
|
setNegativeButton(R.string.RegistrationActivity_edit_number) { _, _ -> handleConfirmNumberDialogCanceled() }
|
||||||
@@ -525,7 +550,7 @@ class EnterPhoneNumberFragment : LoggingFragment(R.layout.fragment_registration_
|
|||||||
setMessage(R.string.RegistrationActivity_this_device_is_missing_google_play_services)
|
setMessage(R.string.RegistrationActivity_this_device_is_missing_google_play_services)
|
||||||
setPositiveButton(R.string.RegistrationActivity_i_understand) { _, _ ->
|
setPositiveButton(R.string.RegistrationActivity_i_understand) { _, _ ->
|
||||||
Log.d(TAG, "User confirmed number.")
|
Log.d(TAG, "User confirmed number.")
|
||||||
sharedViewModel.onUserConfirmedPhoneNumber(requireContext(), ::handleErrorResponse)
|
sharedViewModel.onUserConfirmedPhoneNumber(requireContext())
|
||||||
}
|
}
|
||||||
setNegativeButton(android.R.string.cancel, null)
|
setNegativeButton(android.R.string.cancel, null)
|
||||||
setOnCancelListener { fragmentViewModel.clearError() }
|
setOnCancelListener { fragmentViewModel.clearError() }
|
||||||
|
|||||||
+16
-7
@@ -24,7 +24,6 @@ import org.thoughtcrime.securesms.keyvalue.SignalStore
|
|||||||
import org.thoughtcrime.securesms.lock.v2.PinKeyboardType
|
import org.thoughtcrime.securesms.lock.v2.PinKeyboardType
|
||||||
import org.thoughtcrime.securesms.lock.v2.SvrConstants
|
import org.thoughtcrime.securesms.lock.v2.SvrConstants
|
||||||
import org.thoughtcrime.securesms.registration.data.network.RegisterAccountResult
|
import org.thoughtcrime.securesms.registration.data.network.RegisterAccountResult
|
||||||
import org.thoughtcrime.securesms.registration.data.network.RegistrationResult
|
|
||||||
import org.thoughtcrime.securesms.registration.data.network.VerificationCodeRequestResult
|
import org.thoughtcrime.securesms.registration.data.network.VerificationCodeRequestResult
|
||||||
import org.thoughtcrime.securesms.registration.fragments.RegistrationViewDelegate.setDebugLogSubmitMultiTapView
|
import org.thoughtcrime.securesms.registration.fragments.RegistrationViewDelegate.setDebugLogSubmitMultiTapView
|
||||||
import org.thoughtcrime.securesms.registration.ui.RegistrationViewModel
|
import org.thoughtcrime.securesms.registration.ui.RegistrationViewModel
|
||||||
@@ -101,12 +100,22 @@ class RegistrationLockFragment : LoggingFragment(R.layout.fragment_registration_
|
|||||||
binding.kbsLockPinInputLabel.text = requireContext().resources.getQuantityString(R.plurals.RegistrationLockFragment__d_attempts_remaining, triesRemaining, triesRemaining)
|
binding.kbsLockPinInputLabel.text = requireContext().resources.getQuantityString(R.plurals.RegistrationLockFragment__d_attempts_remaining, triesRemaining, triesRemaining)
|
||||||
}
|
}
|
||||||
|
|
||||||
viewModel.inProgress.observe(viewLifecycleOwner) {
|
viewModel.uiState.observe(viewLifecycleOwner) {
|
||||||
if (it) {
|
if (it.inProgress) {
|
||||||
binding.kbsLockPinConfirm.setSpinning()
|
binding.kbsLockPinConfirm.setSpinning()
|
||||||
} else {
|
} else {
|
||||||
binding.kbsLockPinConfirm.cancelSpinning()
|
binding.kbsLockPinConfirm.cancelSpinning()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
it.sessionStateError?.let { error ->
|
||||||
|
handleSessionErrorResponse(error)
|
||||||
|
viewModel.sessionStateErrorShown()
|
||||||
|
}
|
||||||
|
|
||||||
|
it.registerAccountError?.let { error ->
|
||||||
|
handleRegistrationErrorResponse(error)
|
||||||
|
viewModel.registerAccountErrorShown()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -132,12 +141,12 @@ class RegistrationLockFragment : LoggingFragment(R.layout.fragment_registration_
|
|||||||
|
|
||||||
binding.kbsLockPinConfirm.setSpinning()
|
binding.kbsLockPinConfirm.setSpinning()
|
||||||
|
|
||||||
viewModel.verifyCodeAndRegisterAccountWithRegistrationLock(requireContext(), pin, ::handleSessionErrorResponse, ::handleRegistrationErrorResponse)
|
viewModel.verifyCodeAndRegisterAccountWithRegistrationLock(requireContext(), pin)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun handleSessionErrorResponse(requestResult: RegistrationResult) {
|
private fun handleSessionErrorResponse(requestResult: VerificationCodeRequestResult) {
|
||||||
when (requestResult) {
|
when (requestResult) {
|
||||||
is VerificationCodeRequestResult.Success -> Unit
|
is VerificationCodeRequestResult.Success -> throw IllegalStateException("Session error handler called on successful response!")
|
||||||
is VerificationCodeRequestResult.RateLimited -> onRateLimited()
|
is VerificationCodeRequestResult.RateLimited -> onRateLimited()
|
||||||
is VerificationCodeRequestResult.AttemptsExhausted -> {
|
is VerificationCodeRequestResult.AttemptsExhausted -> {
|
||||||
findNavController().safeNavigate(RegistrationLockFragmentDirections.actionAccountLocked())
|
findNavController().safeNavigate(RegistrationLockFragmentDirections.actionAccountLocked())
|
||||||
@@ -159,7 +168,7 @@ class RegistrationLockFragment : LoggingFragment(R.layout.fragment_registration_
|
|||||||
|
|
||||||
private fun handleRegistrationErrorResponse(result: RegisterAccountResult) {
|
private fun handleRegistrationErrorResponse(result: RegisterAccountResult) {
|
||||||
when (result) {
|
when (result) {
|
||||||
is RegisterAccountResult.Success -> Unit
|
is RegisterAccountResult.Success -> throw IllegalStateException("Register account error handler called on successful response!")
|
||||||
is RegisterAccountResult.RateLimited -> onRateLimited()
|
is RegisterAccountResult.RateLimited -> onRateLimited()
|
||||||
is RegisterAccountResult.AttemptsExhausted -> {
|
is RegisterAccountResult.AttemptsExhausted -> {
|
||||||
findNavController().safeNavigate(RegistrationLockFragmentDirections.actionAccountLocked())
|
findNavController().safeNavigate(RegistrationLockFragmentDirections.actionAccountLocked())
|
||||||
|
|||||||
+8
-3
@@ -82,6 +82,7 @@ class ReRegisterWithPinFragment : LoggingFragment(R.layout.fragment_registration
|
|||||||
private fun updateViewState(state: RegistrationState) {
|
private fun updateViewState(state: RegistrationState) {
|
||||||
if (state.networkError != null) {
|
if (state.networkError != null) {
|
||||||
genericErrorDialog()
|
genericErrorDialog()
|
||||||
|
registrationViewModel.networkErrorShown()
|
||||||
} else if (!state.canSkipSms) {
|
} else if (!state.canSkipSms) {
|
||||||
findNavController().safeNavigate(ReRegisterWithPinFragmentDirections.actionReRegisterWithPinFragmentToEnterPhoneNumberFragment())
|
findNavController().safeNavigate(ReRegisterWithPinFragmentDirections.actionReRegisterWithPinFragmentToEnterPhoneNumberFragment())
|
||||||
} else if (state.isRegistrationLockEnabled && state.svrTriesRemaining == 0) {
|
} else if (state.isRegistrationLockEnabled && state.svrTriesRemaining == 0) {
|
||||||
@@ -91,6 +92,11 @@ class ReRegisterWithPinFragment : LoggingFragment(R.layout.fragment_registration
|
|||||||
presentProgress(state.inProgress)
|
presentProgress(state.inProgress)
|
||||||
presentTriesRemaining(state.svrTriesRemaining)
|
presentTriesRemaining(state.svrTriesRemaining)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
state.registerAccountError?.let { error ->
|
||||||
|
registrationErrorHandler(error)
|
||||||
|
registrationViewModel.registerAccountErrorShown()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun presentProgress(inProgress: Boolean) {
|
private fun presentProgress(inProgress: Boolean) {
|
||||||
@@ -126,8 +132,7 @@ class ReRegisterWithPinFragment : LoggingFragment(R.layout.fragment_registration
|
|||||||
pin = pin,
|
pin = pin,
|
||||||
wrongPinHandler = {
|
wrongPinHandler = {
|
||||||
reRegisterViewModel.markIncorrectGuess()
|
reRegisterViewModel.markIncorrectGuess()
|
||||||
},
|
}
|
||||||
registrationErrorHandler = ::registrationErrorHandler
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -251,7 +256,7 @@ class ReRegisterWithPinFragment : LoggingFragment(R.layout.fragment_registration
|
|||||||
|
|
||||||
private fun registrationErrorHandler(result: RegisterAccountResult) {
|
private fun registrationErrorHandler(result: RegisterAccountResult) {
|
||||||
when (result) {
|
when (result) {
|
||||||
is RegisterAccountResult.Success -> Log.d(TAG, "Register account was successful.")
|
is RegisterAccountResult.Success -> throw IllegalStateException("Register account error handler called on successful response!")
|
||||||
is RegisterAccountResult.AuthorizationFailed,
|
is RegisterAccountResult.AuthorizationFailed,
|
||||||
is RegisterAccountResult.MalformedRequest,
|
is RegisterAccountResult.MalformedRequest,
|
||||||
is RegisterAccountResult.UnknownError,
|
is RegisterAccountResult.UnknownError,
|
||||||
|
|||||||
Reference in New Issue
Block a user