mirror of
https://github.com/signalapp/Signal-Android.git
synced 2025-12-26 14:09:58 +00:00
Allow for captcha solving for reg v2.
This commit is contained in:
committed by
Alex Hart
parent
ba4cdea75d
commit
ca14ed9b2c
@@ -1,11 +1,11 @@
|
||||
package org.thoughtcrime.securesms.registration.fragments;
|
||||
|
||||
final class RegistrationConstants {
|
||||
public final class RegistrationConstants {
|
||||
|
||||
private RegistrationConstants() {
|
||||
}
|
||||
|
||||
static final String TERMS_AND_CONDITIONS_URL = "https://signal.org/legal";
|
||||
static final String SIGNAL_CAPTCHA_SCHEME = "signalcaptcha://";
|
||||
public static final String TERMS_AND_CONDITIONS_URL = "https://signal.org/legal";
|
||||
public static final String SIGNAL_CAPTCHA_SCHEME = "signalcaptcha://";
|
||||
|
||||
}
|
||||
|
||||
@@ -265,33 +265,31 @@ object RegistrationRepository {
|
||||
val fcmToken: String? = FcmUtil.getToken(context).orElse(null)
|
||||
val api: RegistrationApi = AccountManagerFactory.getInstance().createUnauthenticated(context, e164, SignalServiceAddress.DEFAULT_DEVICE_ID, password).registrationApi
|
||||
|
||||
val result = (
|
||||
if (fcmToken == null) {
|
||||
api.createRegistrationSession(null, mcc, mnc)
|
||||
} else {
|
||||
createSessionAndBlockForPushChallenge(api, fcmToken, mcc, mnc)
|
||||
}
|
||||
).then { session ->
|
||||
val sessionId = session.body.id
|
||||
SignalStore.registrationValues().sessionId = sessionId
|
||||
SignalStore.registrationValues().sessionE164 = e164
|
||||
if (!session.body.allowedToRequestCode) {
|
||||
val challenges = session.body.requestedInformation.joinToString()
|
||||
Log.w(TAG, "Not allowed to request code! Remaining challenges: $challenges")
|
||||
// TODO [regv2]: actually handle challenges
|
||||
}
|
||||
// TODO [regv2]: support other verification code [Mode] options
|
||||
if (mode == Mode.PHONE_CALL) {
|
||||
// TODO [regv2]
|
||||
val notImplementedError = NotImplementedError()
|
||||
Log.w(TAG, "Not yet implemented!", notImplementedError)
|
||||
NetworkResult.ApplicationError(notImplementedError)
|
||||
} else {
|
||||
api.requestSmsVerificationCode(sessionId, Locale.getDefault(), mode.isSmsRetrieverSupported)
|
||||
}
|
||||
val registrationSessionResult = if (fcmToken == null) {
|
||||
api.createRegistrationSession(null, mcc, mnc)
|
||||
} else {
|
||||
createSessionAndBlockForPushChallenge(api, fcmToken, mcc, mnc)
|
||||
}
|
||||
val session = registrationSessionResult.successOrThrow()
|
||||
val sessionId = session.body.id
|
||||
SignalStore.registrationValues().sessionId = sessionId
|
||||
SignalStore.registrationValues().sessionE164 = e164
|
||||
if (!session.body.allowedToRequestCode) {
|
||||
val challenges = session.body.requestedInformation.joinToString()
|
||||
Log.w(TAG, "Not allowed to request code! Remaining challenges: $challenges")
|
||||
return@withContext VerificationCodeRequestResult.from(registrationSessionResult)
|
||||
}
|
||||
// TODO [regv2]: support other verification code [Mode] options
|
||||
if (mode == Mode.PHONE_CALL) {
|
||||
// TODO [regv2]
|
||||
val notImplementedError = NotImplementedError()
|
||||
Log.w(TAG, "Not yet implemented!", notImplementedError)
|
||||
NetworkResult.ApplicationError(notImplementedError)
|
||||
} else {
|
||||
api.requestSmsVerificationCode(sessionId, Locale.getDefault(), mode.isSmsRetrieverSupported)
|
||||
}
|
||||
|
||||
return@withContext VerificationCodeRequestResult.from(result)
|
||||
return@withContext VerificationCodeRequestResult.from(registrationSessionResult)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -300,7 +298,17 @@ object RegistrationRepository {
|
||||
suspend fun submitVerificationCode(context: Context, e164: String, password: String, sessionId: String, registrationData: RegistrationData): NetworkResult<RegistrationSessionMetadataResponse> =
|
||||
withContext(Dispatchers.IO) {
|
||||
val api: RegistrationApi = AccountManagerFactory.getInstance().createUnauthenticated(context, e164, SignalServiceAddress.DEFAULT_DEVICE_ID, password).registrationApi
|
||||
api.verifyAccount(registrationData.code, sessionId)
|
||||
api.verifyAccount(sessionId = sessionId, verificationCode = registrationData.code)
|
||||
}
|
||||
|
||||
/**
|
||||
* Submits the solved captcha token to the service.
|
||||
*/
|
||||
suspend fun submitCaptchaToken(context: Context, e164: String, password: String, sessionId: String, captchaToken: String) =
|
||||
withContext(Dispatchers.IO) {
|
||||
val api: RegistrationApi = AccountManagerFactory.getInstance().createUnauthenticated(context, e164, SignalServiceAddress.DEFAULT_DEVICE_ID, password).registrationApi
|
||||
val captchaSubmissionResult = api.submitCaptchaToken(sessionId = sessionId, captchaToken = captchaToken)
|
||||
return@withContext VerificationCodeRequestResult.from(captchaSubmissionResult)
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
/*
|
||||
* Copyright 2024 Signal Messenger, LLC
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
|
||||
package org.thoughtcrime.securesms.registration.v2.data.network
|
||||
|
||||
import org.signal.core.util.logging.Log
|
||||
import org.whispersystems.signalservice.api.NetworkResult
|
||||
import org.whispersystems.signalservice.internal.push.RegistrationSessionMetadataResponse
|
||||
|
||||
sealed class SubmitCaptchaResult(cause: Throwable?) : RegistrationResult(cause) {
|
||||
companion object {
|
||||
private val TAG = Log.tag(SubmitCaptchaResult::class.java)
|
||||
|
||||
fun from(networkResult: NetworkResult<RegistrationSessionMetadataResponse>): SubmitCaptchaResult {
|
||||
return when (networkResult) {
|
||||
is NetworkResult.Success -> Success()
|
||||
is NetworkResult.ApplicationError -> UnknownError(networkResult.throwable)
|
||||
is NetworkResult.NetworkError -> UnknownError(networkResult.exception)
|
||||
is NetworkResult.StatusCodeError -> UnknownError(networkResult.exception)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class Success : SubmitCaptchaResult(null)
|
||||
class ChallengeRequired(val challenges: List<String>) : SubmitCaptchaResult(null)
|
||||
class UnknownError(cause: Throwable) : SubmitCaptchaResult(cause)
|
||||
}
|
||||
@@ -41,6 +41,7 @@ sealed class VerificationCodeRequestResult(cause: Throwable?) : RegistrationResu
|
||||
} else {
|
||||
Success(
|
||||
sessionId = networkResult.result.body.id,
|
||||
allowedToRequestCode = networkResult.result.body.allowedToRequestCode,
|
||||
nextSms = RegistrationRepository.deriveTimestamp(networkResult.result.headers, networkResult.result.body.nextSms),
|
||||
nextCall = RegistrationRepository.deriveTimestamp(networkResult.result.headers, networkResult.result.body.nextCall)
|
||||
)
|
||||
@@ -91,7 +92,7 @@ sealed class VerificationCodeRequestResult(cause: Throwable?) : RegistrationResu
|
||||
}
|
||||
}
|
||||
|
||||
class Success(val sessionId: String, val nextSms: Long, val nextCall: Long) : VerificationCodeRequestResult(null)
|
||||
class Success(val sessionId: String, val allowedToRequestCode: Boolean, val nextSms: Long, val nextCall: Long) : VerificationCodeRequestResult(null)
|
||||
|
||||
class ChallengeRequired(val challenges: List<String>) : VerificationCodeRequestResult(null)
|
||||
|
||||
|
||||
@@ -16,9 +16,9 @@ enum class RegistrationCheckpoint {
|
||||
PUSH_NETWORK_AUDITED,
|
||||
PHONE_NUMBER_CONFIRMED,
|
||||
PIN_CONFIRMED,
|
||||
VERIFICATION_CODE_REQUESTED,
|
||||
CHALLENGE_RECEIVED,
|
||||
CHALLENGE_COMPLETED,
|
||||
VERIFICATION_CODE_REQUESTED,
|
||||
VERIFICATION_CODE_ENTERED,
|
||||
VERIFICATION_CODE_VALIDATED,
|
||||
SERVICE_REGISTRATION_COMPLETED,
|
||||
|
||||
@@ -25,6 +25,7 @@ data class RegistrationV2State(
|
||||
val userSkippedReregistration: Boolean = false,
|
||||
val isFcmSupported: Boolean = false,
|
||||
val fcmToken: String? = null,
|
||||
val captchaToken: String? = null,
|
||||
val nextSms: Long = 0L,
|
||||
val nextCall: Long = 0L,
|
||||
val registrationCheckpoint: RegistrationCheckpoint = RegistrationCheckpoint.INITIALIZATION,
|
||||
|
||||
@@ -29,15 +29,16 @@ import org.thoughtcrime.securesms.registration.RegistrationData
|
||||
import org.thoughtcrime.securesms.registration.RegistrationUtil
|
||||
import org.thoughtcrime.securesms.registration.v2.data.RegistrationRepository
|
||||
import org.thoughtcrime.securesms.registration.v2.data.network.BackupAuthCheckResult
|
||||
import org.thoughtcrime.securesms.registration.v2.data.network.VerificationCodeRequestResult
|
||||
import org.thoughtcrime.securesms.registration.v2.data.network.VerificationCodeRequestResult.AttemptsExhausted
|
||||
import org.thoughtcrime.securesms.registration.v2.data.network.VerificationCodeRequestResult.ChallengeRequired
|
||||
import org.thoughtcrime.securesms.registration.v2.data.network.VerificationCodeRequestResult.ExternalServiceFailure
|
||||
import org.thoughtcrime.securesms.registration.v2.data.network.VerificationCodeRequestResult.ImpossibleNumber
|
||||
import org.thoughtcrime.securesms.registration.v2.data.network.VerificationCodeRequestResult.InvalidTransportModeFailure
|
||||
import org.thoughtcrime.securesms.registration.v2.data.network.VerificationCodeRequestResult.MalformedRequest
|
||||
import org.thoughtcrime.securesms.registration.v2.data.network.VerificationCodeRequestResult.MustRetry
|
||||
import org.thoughtcrime.securesms.registration.v2.data.network.VerificationCodeRequestResult.NonNormalizedNumber
|
||||
import org.thoughtcrime.securesms.registration.v2.data.network.VerificationCodeRequestResult.RateLimited
|
||||
import org.thoughtcrime.securesms.registration.v2.data.network.VerificationCodeRequestResult.MustRetry
|
||||
import org.thoughtcrime.securesms.registration.v2.data.network.VerificationCodeRequestResult.Success
|
||||
import org.thoughtcrime.securesms.registration.v2.data.network.VerificationCodeRequestResult.TokenNotAccepted
|
||||
import org.thoughtcrime.securesms.registration.v2.data.network.VerificationCodeRequestResult.UnknownError
|
||||
@@ -99,6 +100,15 @@ class RegistrationV2ViewModel : ViewModel() {
|
||||
}
|
||||
}
|
||||
|
||||
fun setCaptchaResponse(token: String) {
|
||||
store.update {
|
||||
it.copy(
|
||||
registrationCheckpoint = RegistrationCheckpoint.CHALLENGE_COMPLETED,
|
||||
captchaToken = token
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
fun fetchFcmToken(context: Context) {
|
||||
viewModelScope.launch(context = coroutineExceptionHandler) {
|
||||
val fcmToken = RegistrationRepository.getFcmToken(context)
|
||||
@@ -165,38 +175,63 @@ class RegistrationV2ViewModel : ViewModel() {
|
||||
|
||||
val codeRequestResponse = RegistrationRepository.requestSmsCode(context, e164, password, mccMncProducer.mcc, mccMncProducer.mnc)
|
||||
|
||||
when (codeRequestResponse) {
|
||||
is UnknownError -> {
|
||||
handleGenericError(codeRequestResponse.getCause())
|
||||
return@launch
|
||||
}
|
||||
|
||||
is Success -> {
|
||||
updateFcmToken(context)
|
||||
store.update {
|
||||
it.copy(
|
||||
sessionId = codeRequestResponse.sessionId,
|
||||
nextSms = codeRequestResponse.nextSms,
|
||||
nextCall = codeRequestResponse.nextCall,
|
||||
registrationCheckpoint = RegistrationCheckpoint.VERIFICATION_CODE_REQUESTED
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
is AttemptsExhausted -> Log.w(TAG, "TODO")
|
||||
is ChallengeRequired -> Log.w(TAG, "TODO")
|
||||
is ImpossibleNumber -> Log.w(TAG, "TODO")
|
||||
is NonNormalizedNumber -> Log.w(TAG, "TODO")
|
||||
is RateLimited -> Log.w(TAG, "TODO")
|
||||
is ExternalServiceFailure -> Log.w(TAG, "TODO")
|
||||
is InvalidTransportModeFailure -> Log.w(TAG, "TODO")
|
||||
is MalformedRequest -> Log.w(TAG, "TODO")
|
||||
is MustRetry -> Log.w(TAG, "TODO")
|
||||
is TokenNotAccepted -> Log.w(TAG, "TODO")
|
||||
}
|
||||
handleSessionStateResult(context, codeRequestResponse)
|
||||
}
|
||||
}
|
||||
|
||||
fun submitCaptchaToken(context: Context) {
|
||||
val e164 = getCurrentE164() ?: throw IllegalStateException("TODO")
|
||||
val sessionId = store.value.sessionId ?: throw IllegalStateException("TODO")
|
||||
val captchaToken = store.value.captchaToken ?: throw IllegalStateException("TODO")
|
||||
|
||||
viewModelScope.launch {
|
||||
val captchaSubmissionResult = RegistrationRepository.submitCaptchaToken(context, e164, password, sessionId, captchaToken)
|
||||
|
||||
handleSessionStateResult(context, captchaSubmissionResult)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return whether the request was successful and execution should continue
|
||||
*/
|
||||
private suspend fun handleSessionStateResult(context: Context, sessionResult: VerificationCodeRequestResult): Boolean {
|
||||
when (sessionResult) {
|
||||
is UnknownError -> {
|
||||
handleGenericError(sessionResult.getCause())
|
||||
return false
|
||||
}
|
||||
|
||||
is Success -> {
|
||||
updateFcmToken(context)
|
||||
store.update {
|
||||
it.copy(
|
||||
sessionId = sessionResult.sessionId,
|
||||
nextSms = sessionResult.nextSms,
|
||||
nextCall = sessionResult.nextCall,
|
||||
registrationCheckpoint = RegistrationCheckpoint.VERIFICATION_CODE_REQUESTED
|
||||
)
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
is AttemptsExhausted -> Log.w(TAG, "TODO")
|
||||
is ChallengeRequired -> store.update {
|
||||
it.copy(
|
||||
registrationCheckpoint = RegistrationCheckpoint.CHALLENGE_RECEIVED
|
||||
)
|
||||
}
|
||||
is ImpossibleNumber -> Log.w(TAG, "TODO")
|
||||
is NonNormalizedNumber -> Log.w(TAG, "TODO")
|
||||
is RateLimited -> Log.w(TAG, "TODO")
|
||||
is ExternalServiceFailure -> Log.w(TAG, "TODO")
|
||||
is InvalidTransportModeFailure -> Log.w(TAG, "TODO")
|
||||
is MalformedRequest -> Log.w(TAG, "TODO")
|
||||
is MustRetry -> Log.w(TAG, "TODO")
|
||||
is TokenNotAccepted -> Log.w(TAG, "TODO")
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
private fun handleGenericError(cause: Throwable) {
|
||||
Log.w(TAG, "Encountered unknown error!", cause)
|
||||
store.update {
|
||||
|
||||
@@ -0,0 +1,49 @@
|
||||
/*
|
||||
* Copyright 2024 Signal Messenger, LLC
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
|
||||
package org.thoughtcrime.securesms.registration.v2.ui.captcha
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.os.Bundle
|
||||
import android.view.View
|
||||
import android.webkit.WebView
|
||||
import android.webkit.WebViewClient
|
||||
import androidx.fragment.app.activityViewModels
|
||||
import androidx.navigation.fragment.findNavController
|
||||
import org.thoughtcrime.securesms.BuildConfig
|
||||
import org.thoughtcrime.securesms.LoggingFragment
|
||||
import org.thoughtcrime.securesms.R
|
||||
import org.thoughtcrime.securesms.components.ViewBinderDelegate
|
||||
import org.thoughtcrime.securesms.databinding.FragmentRegistrationCaptchaV2Binding
|
||||
import org.thoughtcrime.securesms.registration.fragments.RegistrationConstants
|
||||
import org.thoughtcrime.securesms.registration.v2.ui.RegistrationV2ViewModel
|
||||
|
||||
class CaptchaFragment : LoggingFragment(R.layout.fragment_registration_captcha_v2) {
|
||||
|
||||
private val sharedViewModel by activityViewModels<RegistrationV2ViewModel>()
|
||||
private val binding: FragmentRegistrationCaptchaV2Binding by ViewBinderDelegate(FragmentRegistrationCaptchaV2Binding::bind)
|
||||
|
||||
@SuppressLint("SetJavaScriptEnabled")
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
binding.registrationCaptchaWebView.settings.javaScriptEnabled = true
|
||||
binding.registrationCaptchaWebView.clearCache(true)
|
||||
|
||||
binding.registrationCaptchaWebView.webViewClient = object : WebViewClient() {
|
||||
@Deprecated("Deprecated in Java")
|
||||
override fun shouldOverrideUrlLoading(view: WebView, url: String): Boolean {
|
||||
if (url.startsWith(RegistrationConstants.SIGNAL_CAPTCHA_SCHEME)) {
|
||||
val token = url.substring(RegistrationConstants.SIGNAL_CAPTCHA_SCHEME.length)
|
||||
sharedViewModel.setCaptchaResponse(token)
|
||||
findNavController().navigateUp()
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
binding.registrationCaptchaWebView.loadUrl(BuildConfig.SIGNAL_CAPTCHA_URL)
|
||||
}
|
||||
}
|
||||
@@ -100,10 +100,15 @@ class EnterPhoneNumberV2Fragment : LoggingFragment(R.layout.fragment_registratio
|
||||
sharedState.networkError?.let {
|
||||
presentNetworkError(it)
|
||||
}
|
||||
|
||||
if (sharedState.registrationCheckpoint >= RegistrationCheckpoint.PHONE_NUMBER_CONFIRMED && sharedState.canSkipSms) {
|
||||
moveToEnterPinScreen()
|
||||
} else if (sharedState.registrationCheckpoint >= RegistrationCheckpoint.VERIFICATION_CODE_REQUESTED) {
|
||||
moveToVerificationEntryScreen()
|
||||
} else if (sharedState.registrationCheckpoint >= RegistrationCheckpoint.CHALLENGE_COMPLETED) {
|
||||
sharedViewModel.submitCaptchaToken(requireContext())
|
||||
} else if (sharedState.registrationCheckpoint >= RegistrationCheckpoint.CHALLENGE_RECEIVED) {
|
||||
findNavController().safeNavigate(EnterPhoneNumberV2FragmentDirections.actionRequestCaptcha())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -370,18 +375,18 @@ class EnterPhoneNumberV2Fragment : LoggingFragment(R.layout.fragment_registratio
|
||||
}
|
||||
|
||||
private fun moveToEnterPinScreen() {
|
||||
sharedViewModel.setInProgress(false)
|
||||
findNavController().safeNavigate(EnterPhoneNumberV2FragmentDirections.actionReRegisterWithPinV2Fragment())
|
||||
sharedViewModel.setInProgress(false)
|
||||
}
|
||||
|
||||
private fun moveToVerificationEntryScreen() {
|
||||
NavHostFragment.findNavController(this).safeNavigate(EnterPhoneNumberV2FragmentDirections.actionEnterVerificationCode())
|
||||
findNavController().safeNavigate(EnterPhoneNumberV2FragmentDirections.actionEnterVerificationCode())
|
||||
sharedViewModel.setInProgress(false)
|
||||
}
|
||||
|
||||
private fun popBackStack() {
|
||||
sharedViewModel.setRegistrationCheckpoint(RegistrationCheckpoint.INITIALIZATION)
|
||||
NavHostFragment.findNavController(this).popBackStack()
|
||||
findNavController().popBackStack()
|
||||
}
|
||||
|
||||
private inner class FcmTokenRetrievedObserver : LiveDataObserverCallback<RegistrationV2State>(sharedViewModel.uiState) {
|
||||
|
||||
44
app/src/main/res/layout/fragment_registration_captcha_v2.xml
Normal file
44
app/src/main/res/layout/fragment_registration_captcha_v2.xml
Normal file
@@ -0,0 +1,44 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:fillViewport="true">
|
||||
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
android:background="@color/signal_colorSurface"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="0dp">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/registration_captcha_title"
|
||||
style="@style/Signal.Text.HeadlineMedium"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="24dp"
|
||||
android:layout_marginTop="24dp"
|
||||
android:layout_marginEnd="24dp"
|
||||
android:gravity="center"
|
||||
android:text="@string/RegistrationActivity_we_need_to_verify_that_youre_human"
|
||||
android:textColor="@color/signal_colorOnSurface"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
<WebView
|
||||
android:id="@+id/registration_captcha_web_view"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="0dp"
|
||||
android:layout_marginStart="16dp"
|
||||
android:layout_marginTop="16dp"
|
||||
android:layout_marginEnd="16dp"
|
||||
android:layout_marginBottom="16dp"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/registration_captcha_title" />
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
|
||||
</ScrollView>
|
||||
@@ -215,7 +215,7 @@
|
||||
|
||||
<fragment
|
||||
android:id="@+id/captchaV2Fragment"
|
||||
android:name="org.thoughtcrime.securesms.registration.fragments.CaptchaFragment"
|
||||
android:name="org.thoughtcrime.securesms.registration.v2.ui.captcha.CaptchaFragment"
|
||||
android:label="fragment_captcha"
|
||||
tools:layout="@layout/fragment_registration_captcha" />
|
||||
|
||||
|
||||
@@ -54,12 +54,21 @@ class RegistrationApi(
|
||||
/**
|
||||
* Submit a verification code sent by the service via one of the supported channels (SMS, phone call) to prove the registrant's control of the phone number.
|
||||
*/
|
||||
fun verifyAccount(verificationCode: String, sessionId: String): NetworkResult<RegistrationSessionMetadataResponse> {
|
||||
fun verifyAccount(sessionId: String, verificationCode: String): NetworkResult<RegistrationSessionMetadataResponse> {
|
||||
return NetworkResult.fromFetch {
|
||||
pushServiceSocket.submitVerificationCode(sessionId, verificationCode)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Submits the solved captcha token to the service.
|
||||
*/
|
||||
fun submitCaptchaToken(sessionId: String, captchaToken: String): NetworkResult<RegistrationSessionMetadataResponse> {
|
||||
return NetworkResult.fromFetch {
|
||||
pushServiceSocket.patchVerificationSession(sessionId, null, null, null, captchaToken, null)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Submit the cryptographic assets required for an account to use the service.
|
||||
*/
|
||||
|
||||
Reference in New Issue
Block a user