Adapt change number flow to use V2 API.
This commit is contained in:
parent
a552a5a5bc
commit
e4d4a5d9e0
9 changed files with 66 additions and 28 deletions
|
@ -45,7 +45,7 @@ class ChangeNumberConfirmFragment : LoggingFragment(R.layout.fragment_change_num
|
|||
|
||||
task.addOnSuccessListener {
|
||||
Log.i(TAG, "Successfully registered SMS listener.")
|
||||
navigateToVerify()
|
||||
navigateToVerify(smsListenerEnabled = true)
|
||||
}
|
||||
|
||||
task.addOnFailureListener { e ->
|
||||
|
@ -57,8 +57,8 @@ class ChangeNumberConfirmFragment : LoggingFragment(R.layout.fragment_change_num
|
|||
}
|
||||
}
|
||||
|
||||
private fun navigateToVerify() {
|
||||
findNavController().safeNavigate(R.id.action_changePhoneNumberConfirmFragment_to_changePhoneNumberVerifyFragment)
|
||||
private fun navigateToVerify(smsListenerEnabled: Boolean = false) {
|
||||
findNavController().safeNavigate(R.id.action_changePhoneNumberConfirmFragment_to_changePhoneNumberVerifyFragment, ChangeNumberVerifyFragmentArgs.Builder().setSmsListenerEnabled(smsListenerEnabled).build().toBundle())
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
|
|
@ -37,6 +37,7 @@ import org.whispersystems.signalservice.api.push.SignalServiceAddress
|
|||
import org.whispersystems.signalservice.api.push.SignedPreKeyEntity
|
||||
import org.whispersystems.signalservice.internal.ServiceResponse
|
||||
import org.whispersystems.signalservice.internal.push.OutgoingPushMessage
|
||||
import org.whispersystems.signalservice.internal.push.RegistrationSessionMetadataResponse
|
||||
import org.whispersystems.signalservice.internal.push.SignalServiceProtos.SyncMessage
|
||||
import org.whispersystems.signalservice.internal.push.VerifyAccountResponse
|
||||
import org.whispersystems.signalservice.internal.push.WhoAmIResponse
|
||||
|
@ -94,7 +95,7 @@ class ChangeNumberRepository(
|
|||
.timeout(15, TimeUnit.SECONDS)
|
||||
}
|
||||
|
||||
fun changeNumber(code: String, newE164: String, pniUpdateMode: Boolean = false): Single<ServiceResponse<VerifyResponse>> {
|
||||
fun changeNumber(sessionId: String, newE164: String, pniUpdateMode: Boolean = false): Single<ServiceResponse<VerifyResponse>> {
|
||||
return Single.fromCallable {
|
||||
var completed = false
|
||||
var attempts = 0
|
||||
|
@ -102,7 +103,7 @@ class ChangeNumberRepository(
|
|||
|
||||
while (!completed && attempts < 5) {
|
||||
val (request: ChangePhoneNumberRequest, metadata: PendingChangeNumberMetadata) = createChangeNumberRequest(
|
||||
code = code,
|
||||
sessionId = sessionId,
|
||||
newE164 = newE164,
|
||||
registrationLock = null,
|
||||
pniUpdateMode = pniUpdateMode
|
||||
|
@ -127,7 +128,7 @@ class ChangeNumberRepository(
|
|||
}
|
||||
|
||||
fun changeNumber(
|
||||
code: String,
|
||||
sessionId: String,
|
||||
newE164: String,
|
||||
pin: String,
|
||||
tokenData: TokenData
|
||||
|
@ -153,7 +154,7 @@ class ChangeNumberRepository(
|
|||
|
||||
while (!completed && attempts < 5) {
|
||||
val (request: ChangePhoneNumberRequest, metadata: PendingChangeNumberMetadata) = createChangeNumberRequest(
|
||||
code = code,
|
||||
sessionId = sessionId,
|
||||
newE164 = newE164,
|
||||
registrationLock = registrationLock,
|
||||
pniUpdateMode = false
|
||||
|
@ -280,7 +281,7 @@ class ChangeNumberRepository(
|
|||
@Suppress("UsePropertyAccessSyntax")
|
||||
@WorkerThread
|
||||
private fun createChangeNumberRequest(
|
||||
code: String,
|
||||
sessionId: String,
|
||||
newE164: String,
|
||||
registrationLock: String?,
|
||||
pniUpdateMode: Boolean
|
||||
|
@ -336,8 +337,9 @@ class ChangeNumberRepository(
|
|||
}
|
||||
|
||||
val request = ChangePhoneNumberRequest(
|
||||
sessionId,
|
||||
null,
|
||||
newE164,
|
||||
code,
|
||||
registrationLock,
|
||||
pniIdentity.publicKey,
|
||||
deviceMessages,
|
||||
|
@ -355,5 +357,11 @@ class ChangeNumberRepository(
|
|||
return ChangeNumberRequestData(request, metadata)
|
||||
}
|
||||
|
||||
fun verifyAccount(sessionId: String, code: String): Single<ServiceResponse<RegistrationSessionMetadataResponse>> {
|
||||
return Single.fromCallable {
|
||||
accountManager.verifyAccount(code, sessionId)
|
||||
}.subscribeOn(Schedulers.io())
|
||||
}
|
||||
|
||||
data class ChangeNumberRequestData(val changeNumberRequest: ChangePhoneNumberRequest, val pendingChangeNumberMetadata: PendingChangeNumberMetadata)
|
||||
}
|
||||
|
|
|
@ -49,11 +49,12 @@ class ChangeNumberVerifyFragment : LoggingFragment(R.layout.fragment_change_phon
|
|||
}
|
||||
|
||||
private fun requestCode() {
|
||||
val mode = if (ChangeNumberVerifyFragmentArgs.fromBundle(requireArguments()).smsListenerEnabled) VerifyAccountRepository.Mode.SMS_WITH_LISTENER else VerifyAccountRepository.Mode.SMS_WITHOUT_LISTENER
|
||||
val mccMncProducer = MccMncProducer(requireContext())
|
||||
lifecycleDisposable += viewModel
|
||||
.ensureDecryptionsDrained()
|
||||
.onErrorComplete()
|
||||
.andThen(viewModel.requestVerificationCode(VerifyAccountRepository.Mode.SMS_WITHOUT_LISTENER, mccMncProducer.mcc, mccMncProducer.mnc))
|
||||
.andThen(viewModel.requestVerificationCode(mode, mccMncProducer.mcc, mccMncProducer.mnc))
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe { processor ->
|
||||
if (processor.hasResult()) {
|
||||
|
|
|
@ -9,13 +9,16 @@ import androidx.lifecycle.ViewModel
|
|||
import androidx.savedstate.SavedStateRegistryOwner
|
||||
import com.google.i18n.phonenumbers.NumberParseException
|
||||
import com.google.i18n.phonenumbers.PhoneNumberUtil
|
||||
import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers
|
||||
import io.reactivex.rxjava3.core.Completable
|
||||
import io.reactivex.rxjava3.core.Single
|
||||
import io.reactivex.rxjava3.schedulers.Schedulers
|
||||
import org.signal.core.util.logging.Log
|
||||
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies
|
||||
import org.thoughtcrime.securesms.keyvalue.SignalStore
|
||||
import org.thoughtcrime.securesms.pin.KbsRepository
|
||||
import org.thoughtcrime.securesms.pin.TokenData
|
||||
import org.thoughtcrime.securesms.registration.RegistrationSessionProcessor
|
||||
import org.thoughtcrime.securesms.registration.SmsRetrieverReceiver
|
||||
import org.thoughtcrime.securesms.registration.VerifyAccountRepository
|
||||
import org.thoughtcrime.securesms.registration.VerifyResponse
|
||||
|
@ -26,6 +29,7 @@ import org.thoughtcrime.securesms.registration.viewmodel.BaseRegistrationViewMod
|
|||
import org.thoughtcrime.securesms.registration.viewmodel.NumberViewState
|
||||
import org.thoughtcrime.securesms.util.DefaultValueLiveData
|
||||
import org.whispersystems.signalservice.api.push.PNI
|
||||
import org.whispersystems.signalservice.api.push.exceptions.IncorrectCodeException
|
||||
import org.whispersystems.signalservice.internal.ServiceResponse
|
||||
import java.util.Objects
|
||||
|
||||
|
@ -152,11 +156,32 @@ class ChangeNumberViewModel(
|
|||
}
|
||||
|
||||
override fun verifyAccountWithoutRegistrationLock(): Single<ServiceResponse<VerifyResponse>> {
|
||||
return changeNumberRepository.changeNumber(textCodeEntered, number.e164Number)
|
||||
val sessionId = sessionId ?: throw IllegalStateException("No valid registration session")
|
||||
|
||||
return changeNumberRepository.verifyAccount(sessionId, textCodeEntered)
|
||||
.map { RegistrationSessionProcessor.RegistrationSessionProcessorForVerification(it) }
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.doOnSuccess {
|
||||
if (it.hasResult()) {
|
||||
setCanSmsAtTime(it.getNextCodeViaSmsAttempt())
|
||||
setCanCallAtTime(it.getNextCodeViaCallAttempt())
|
||||
}
|
||||
}
|
||||
.observeOn(Schedulers.io())
|
||||
.flatMap { processor ->
|
||||
if (processor.isAlreadyVerified() || processor.hasResult() && processor.isVerified()) {
|
||||
changeNumberRepository.changeNumber(sessionId, number.e164Number)
|
||||
} else if (processor.error == null) {
|
||||
Single.just<ServiceResponse<VerifyResponse>>(ServiceResponse.forApplicationError(IncorrectCodeException(), 403, null))
|
||||
} else {
|
||||
Single.just<ServiceResponse<VerifyResponse>>(ServiceResponse.coerceError(processor.response))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun verifyAccountWithRegistrationLock(pin: String, kbsTokenData: TokenData): Single<ServiceResponse<VerifyResponse>> {
|
||||
return changeNumberRepository.changeNumber(textCodeEntered, number.e164Number, pin, kbsTokenData)
|
||||
val sessionId = sessionId ?: throw IllegalStateException("No valid registration session")
|
||||
return changeNumberRepository.changeNumber(sessionId, number.e164Number, pin, kbsTokenData)
|
||||
}
|
||||
|
||||
@WorkerThread
|
||||
|
|
|
@ -24,7 +24,7 @@ class PnpInitializeDevicesJob private constructor(parameters: Parameters) : Base
|
|||
companion object {
|
||||
const val KEY = "PnpInitializeDevicesJob"
|
||||
private val TAG = Log.tag(PnpInitializeDevicesJob::class.java)
|
||||
private const val PLACEHOLDER_CODE = "123456"
|
||||
private const val PLACEHOLDER_SESSION_ID = "123456789"
|
||||
|
||||
@JvmStatic
|
||||
fun enqueueIfNecessary() {
|
||||
|
@ -88,7 +88,7 @@ class PnpInitializeDevicesJob private constructor(parameters: Parameters) : Base
|
|||
try {
|
||||
Log.i(TAG, "Calling change number with our current number to distribute PNI messages")
|
||||
changeNumberRepository
|
||||
.changeNumber(code = PLACEHOLDER_CODE, newE164 = e164, pniUpdateMode = true)
|
||||
.changeNumber(sessionId = PLACEHOLDER_SESSION_ID, newE164 = e164, pniUpdateMode = true)
|
||||
.map(::VerifyResponseWithoutKbs)
|
||||
.safeBlockingGet()
|
||||
.resultOrThrow
|
||||
|
|
|
@ -73,6 +73,10 @@
|
|||
android:name="org.thoughtcrime.securesms.components.settings.app.changenumber.ChangeNumberVerifyFragment"
|
||||
tools:layout="@layout/fragment_change_phone_number_verify">
|
||||
|
||||
<argument android:name="sms_listener_enabled"
|
||||
android:defaultValue="false"
|
||||
app:argType="boolean" />
|
||||
|
||||
<action
|
||||
android:id="@+id/action_changePhoneNumberVerifyFragment_to_captchaFragment"
|
||||
app:destination="@id/captchaFragment"
|
||||
|
|
|
@ -20,7 +20,6 @@ import org.signal.libsignal.zkgroup.profiles.ExpiringProfileKeyCredential;
|
|||
import org.signal.libsignal.zkgroup.profiles.ProfileKey;
|
||||
import org.whispersystems.signalservice.api.account.AccountAttributes;
|
||||
import org.whispersystems.signalservice.api.account.ChangePhoneNumberRequest;
|
||||
import org.whispersystems.signalservice.internal.push.RegistrationSessionMetadataResponse;
|
||||
import org.whispersystems.signalservice.api.crypto.ProfileCipher;
|
||||
import org.whispersystems.signalservice.api.crypto.ProfileCipherOutputStream;
|
||||
import org.whispersystems.signalservice.api.groupsv2.ClientZkOperations;
|
||||
|
@ -61,6 +60,7 @@ import org.whispersystems.signalservice.internal.push.BackupAuthCheckResponse;
|
|||
import org.whispersystems.signalservice.internal.push.CdsiAuthResponse;
|
||||
import org.whispersystems.signalservice.internal.push.ProfileAvatarData;
|
||||
import org.whispersystems.signalservice.internal.push.PushServiceSocket;
|
||||
import org.whispersystems.signalservice.internal.push.RegistrationSessionMetadataResponse;
|
||||
import org.whispersystems.signalservice.internal.push.RemoteConfigResponse;
|
||||
import org.whispersystems.signalservice.internal.push.ReserveUsernameResponse;
|
||||
import org.whispersystems.signalservice.internal.push.SignalServiceProtos;
|
||||
|
@ -315,9 +315,7 @@ public class SignalServiceAccountManager {
|
|||
* @return The UUID of the user that was registered.
|
||||
* @throws IOException for various HTTP and networking errors
|
||||
*/
|
||||
public ServiceResponse<RegistrationSessionMetadataResponse> verifyAccount(String verificationCode,
|
||||
String sessionId)
|
||||
{
|
||||
public ServiceResponse<RegistrationSessionMetadataResponse> verifyAccount(@Nonnull String verificationCode, @Nonnull String sessionId) {
|
||||
try {
|
||||
RegistrationSessionMetadataResponse response = pushServiceSocket.submitVerificationCode(sessionId, verificationCode);
|
||||
return ServiceResponse.forResult(response, 200, null);
|
||||
|
|
|
@ -14,10 +14,13 @@ import java.util.Map;
|
|||
|
||||
public final class ChangePhoneNumberRequest {
|
||||
@JsonProperty
|
||||
private String number;
|
||||
private String sessionId;
|
||||
|
||||
@JsonProperty
|
||||
private String code;
|
||||
private String recoveryPassword;
|
||||
|
||||
@JsonProperty
|
||||
private String number;
|
||||
|
||||
@JsonProperty("reglock")
|
||||
private String registrationLock;
|
||||
|
@ -36,18 +39,21 @@ public final class ChangePhoneNumberRequest {
|
|||
@JsonProperty
|
||||
private Map<String, Integer> pniRegistrationIds;
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
public ChangePhoneNumberRequest() {}
|
||||
|
||||
public ChangePhoneNumberRequest(String number,
|
||||
String code,
|
||||
public ChangePhoneNumberRequest(String sessionId,
|
||||
String recoveryPassword,
|
||||
String number,
|
||||
String registrationLock,
|
||||
IdentityKey pniIdentityKey,
|
||||
List<OutgoingPushMessage> deviceMessages,
|
||||
Map<String, SignedPreKeyEntity> devicePniSignedPrekeys,
|
||||
Map<String, Integer> pniRegistrationIds)
|
||||
{
|
||||
this.sessionId = sessionId;
|
||||
this.recoveryPassword = recoveryPassword;
|
||||
this.number = number;
|
||||
this.code = code;
|
||||
this.registrationLock = registrationLock;
|
||||
this.pniIdentityKey = pniIdentityKey;
|
||||
this.deviceMessages = deviceMessages;
|
||||
|
@ -59,10 +65,6 @@ public final class ChangePhoneNumberRequest {
|
|||
return number;
|
||||
}
|
||||
|
||||
public String getCode() {
|
||||
return code;
|
||||
}
|
||||
|
||||
public String getRegistrationLock() {
|
||||
return registrationLock;
|
||||
}
|
||||
|
|
|
@ -210,7 +210,7 @@ public class PushServiceSocket {
|
|||
private static final String RESERVE_USERNAME_PATH = "/v1/accounts/username_hash/reserve";
|
||||
private static final String CONFIRM_USERNAME_PATH = "/v1/accounts/username_hash/confirm";
|
||||
private static final String DELETE_ACCOUNT_PATH = "/v1/accounts/me";
|
||||
private static final String CHANGE_NUMBER_PATH = "/v1/accounts/number";
|
||||
private static final String CHANGE_NUMBER_PATH = "/v2/accounts/number";
|
||||
private static final String IDENTIFIER_REGISTERED_PATH = "/v1/accounts/account/%s";
|
||||
|
||||
private static final String PREKEY_METADATA_PATH = "/v2/keys?identity=%s";
|
||||
|
|
Loading…
Add table
Reference in a new issue