Skip to content

Commit

Permalink
Adapt change number flow to use V2 API.
Browse files Browse the repository at this point in the history
  • Loading branch information
nicholas-signal committed Feb 24, 2023
1 parent a552a5a commit e4d4a5d
Show file tree
Hide file tree
Showing 9 changed files with 66 additions and 28 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -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 ->
Expand All @@ -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 {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -94,15 +95,15 @@ 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
lateinit var changeNumberResponse: ServiceResponse<VerifyAccountResponse>

while (!completed && attempts < 5) {
val (request: ChangePhoneNumberRequest, metadata: PendingChangeNumberMetadata) = createChangeNumberRequest(
code = code,
sessionId = sessionId,
newE164 = newE164,
registrationLock = null,
pniUpdateMode = pniUpdateMode
Expand All @@ -127,7 +128,7 @@ class ChangeNumberRepository(
}

fun changeNumber(
code: String,
sessionId: String,
newE164: String,
pin: String,
tokenData: TokenData
Expand All @@ -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
Expand Down Expand Up @@ -280,7 +281,7 @@ class ChangeNumberRepository(
@Suppress("UsePropertyAccessSyntax")
@WorkerThread
private fun createChangeNumberRequest(
code: String,
sessionId: String,
newE164: String,
registrationLock: String?,
pniUpdateMode: Boolean
Expand Down Expand Up @@ -336,8 +337,9 @@ class ChangeNumberRepository(
}

val request = ChangePhoneNumberRequest(
sessionId,
null,
newE164,
code,
registrationLock,
pniIdentity.publicKey,
deviceMessages,
Expand All @@ -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)
}
Original file line number Diff line number Diff line change
Expand Up @@ -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()) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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

Expand Down Expand Up @@ -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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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() {
Expand Down Expand Up @@ -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
Expand Down
4 changes: 4 additions & 0 deletions app/src/main/res/navigation/app_settings_change_number.xml
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@
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;
Expand Down Expand Up @@ -61,6 +60,7 @@
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;
Expand Down Expand Up @@ -315,9 +315,7 @@ public ServiceResponse<RegistrationSessionMetadataResponse> requestVoiceVerifica
* @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);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,13 @@

public final class ChangePhoneNumberRequest {
@JsonProperty
private String number;
private String sessionId;

@JsonProperty
private String recoveryPassword;

@JsonProperty
private String code;
private String number;

@JsonProperty("reglock")
private String registrationLock;
Expand All @@ -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;
Expand All @@ -59,10 +65,6 @@ public String getNumber() {
return number;
}

public String getCode() {
return code;
}

public String getRegistrationLock() {
return registrationLock;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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";
Expand Down

0 comments on commit e4d4a5d

Please sign in to comment.