Start mirroring to SVR2.

This commit is contained in:
Greyson Parrelli
2023-07-05 19:05:30 -04:00
committed by Clark Chen
parent dfb7304626
commit e1570e9512
111 changed files with 1828 additions and 2299 deletions

View File

@@ -29,7 +29,7 @@ import org.thoughtcrime.securesms.jobs.PreKeysSyncJob;
import org.thoughtcrime.securesms.jobs.RotateCertificateJob;
import org.thoughtcrime.securesms.keyvalue.SignalStore;
import org.thoughtcrime.securesms.notifications.NotificationIds;
import org.thoughtcrime.securesms.pin.PinState;
import org.thoughtcrime.securesms.pin.SvrRepository;
import org.thoughtcrime.securesms.push.AccountManagerFactory;
import org.thoughtcrime.securesms.recipients.Recipient;
import org.thoughtcrime.securesms.recipients.RecipientId;
@@ -102,13 +102,8 @@ public final class RegistrationRepository {
{
return Single.<ServiceResponse<VerifyResponse>>fromCallable(() -> {
try {
String pin = response.getPin();
registerAccountInternal(registrationData, response, setRegistrationLockEnabled);
if (pin != null && !pin.isEmpty()) {
PinState.onPinChangedOrCreated(context, pin, SignalStore.pinValues().getKeyboardType());
}
JobManager jobManager = ApplicationDependencies.getJobManager();
jobManager.add(new DirectoryRefreshJob(false));
jobManager.add(new RotateCertificateJob());
@@ -176,7 +171,7 @@ public final class RegistrationRepository {
TextSecurePreferences.setUnauthorizedReceived(context, false);
NotificationManagerCompat.from(context).cancel(NotificationIds.UNREGISTERED_NOTIFICATION_ID);
PinState.onRegistration(context, response.getKbsData(), response.getPin(), hasPin, setRegistrationLockEnabled);
SvrRepository.onRegistrationComplete(response.getMasterKey(), response.getPin(), hasPin, setRegistrationLockEnabled);
ApplicationDependencies.closeConnections();
ApplicationDependencies.getIncomingMessageObserver();
@@ -226,13 +221,13 @@ public final class RegistrationRepository {
return null;
}
public Single<BackupAuthCheckProcessor> getKbsAuthCredential(@NonNull RegistrationData registrationData, List<String> usernamePasswords) {
public Single<BackupAuthCheckProcessor> getSvrAuthCredential(@NonNull RegistrationData registrationData, List<String> usernamePasswords) {
SignalServiceAccountManager accountManager = AccountManagerFactory.getInstance().createUnauthenticated(context, registrationData.getE164(), SignalServiceAddress.DEFAULT_DEVICE_ID, registrationData.getPassword());
return accountManager.checkBackupAuthCredentials(registrationData.getE164(), usernamePasswords)
.map(BackupAuthCheckProcessor::new)
.doOnSuccess(processor -> {
if (SignalStore.kbsValues().removeAuthTokens(processor.getInvalid())) {
if (SignalStore.svr().removeAuthTokens(processor.getInvalid())) {
new BackupManager(context).dataChanged();
}
});

View File

@@ -22,7 +22,7 @@ public final class RegistrationUtil {
if (!SignalStore.registrationValues().isRegistrationComplete() &&
SignalStore.account().isRegistered() &&
!Recipient.self().getProfileName().isEmpty() &&
(SignalStore.kbsValues().hasPin() || SignalStore.kbsValues().hasOptedOut()))
(SignalStore.svr().hasPin() || SignalStore.svr().hasOptedOut()))
{
Log.i(TAG, "Marking registration completed.", new Throwable());
SignalStore.registrationValues().setRegistrationComplete();

View File

@@ -10,15 +10,15 @@ import org.signal.libsignal.protocol.IdentityKeyPair
import org.thoughtcrime.securesms.AppCapabilities
import org.thoughtcrime.securesms.gcm.FcmUtil
import org.thoughtcrime.securesms.keyvalue.SignalStore
import org.thoughtcrime.securesms.pin.KeyBackupSystemWrongPinException
import org.thoughtcrime.securesms.pin.SvrWrongPinException
import org.thoughtcrime.securesms.push.AccountManagerFactory
import org.thoughtcrime.securesms.registration.PushChallengeRequest.PushChallengeEvent
import org.thoughtcrime.securesms.util.TextSecurePreferences
import org.whispersystems.signalservice.api.KbsPinData
import org.whispersystems.signalservice.api.KeyBackupSystemNoDataException
import org.whispersystems.signalservice.api.SignalServiceAccountManager
import org.whispersystems.signalservice.api.SvrNoDataException
import org.whispersystems.signalservice.api.account.AccountAttributes
import org.whispersystems.signalservice.api.crypto.UnidentifiedAccess
import org.whispersystems.signalservice.api.kbs.MasterKey
import org.whispersystems.signalservice.api.push.SignalServiceAddress
import org.whispersystems.signalservice.api.push.exceptions.NoSuchSessionException
import org.whispersystems.signalservice.internal.ServiceResponse
@@ -157,7 +157,7 @@ class VerifyAccountRepository(private val context: Application) {
}.subscribeOn(Schedulers.io())
}
fun registerAccount(sessionId: String?, registrationData: RegistrationData, pin: String? = null, kbsPinDataProducer: KbsPinDataProducer? = null): Single<ServiceResponse<VerifyResponse>> {
fun registerAccount(sessionId: String?, registrationData: RegistrationData, pin: String? = null, masterKeyProducer: MasterKeyProducer? = null): Single<ServiceResponse<VerifyResponse>> {
val universalUnidentifiedAccess: Boolean = TextSecurePreferences.isUniversalUnidentifiedAccess(context)
val unidentifiedAccessKey: ByteArray = UnidentifiedAccess.deriveAccessKeyFrom(registrationData.profileKey)
@@ -168,15 +168,14 @@ class VerifyAccountRepository(private val context: Application) {
registrationData.password
)
val kbsData = kbsPinDataProducer?.produceKbsPinData()
val registrationLockV2: String? = kbsData?.masterKey?.deriveRegistrationLock()
val masterKey: MasterKey? = masterKeyProducer?.produceMasterKey()
val registrationLock: String? = masterKey?.deriveRegistrationLock()
val accountAttributes = AccountAttributes(
signalingKey = null,
registrationId = registrationData.registrationId,
fetchesMessages = registrationData.isNotFcm,
pin = pin,
registrationLock = registrationLockV2,
registrationLock = registrationLock,
unidentifiedAccessKey = unidentifiedAccessKey,
unrestrictedUnidentifiedAccess = universalUnidentifiedAccess,
capabilities = AppCapabilities.getCapabilities(true),
@@ -197,7 +196,7 @@ class VerifyAccountRepository(private val context: Application) {
return Single.fromCallable {
val response = accountManager.registerAccount(sessionId, registrationData.recoveryPassword, accountAttributes, aciPreKeyCollection, pniPreKeyCollection, registrationData.fcmToken, true)
VerifyResponse.from(response, kbsData, pin, aciPreKeyCollection, pniPreKeyCollection)
VerifyResponse.from(response, masterKey, pin, aciPreKeyCollection, pniPreKeyCollection)
}.subscribeOn(Schedulers.io())
}
@@ -207,9 +206,9 @@ class VerifyAccountRepository(private val context: Application) {
}.subscribeOn(Schedulers.io())
}
interface KbsPinDataProducer {
@Throws(IOException::class, KeyBackupSystemWrongPinException::class, KeyBackupSystemNoDataException::class)
fun produceKbsPinData(): KbsPinData
interface MasterKeyProducer {
@Throws(IOException::class, SvrWrongPinException::class, SvrNoDataException::class)
fun produceMasterKey(): MasterKey
}
enum class Mode(val isSmsRetrieverSupported: Boolean) {

View File

@@ -1,13 +1,13 @@
package org.thoughtcrime.securesms.registration
import org.whispersystems.signalservice.api.KbsPinData
import org.whispersystems.signalservice.api.account.PreKeyCollection
import org.whispersystems.signalservice.api.kbs.MasterKey
import org.whispersystems.signalservice.internal.ServiceResponse
import org.whispersystems.signalservice.internal.push.VerifyAccountResponse
data class VerifyResponse(
val verifyAccountResponse: VerifyAccountResponse,
val kbsData: KbsPinData?,
val masterKey: MasterKey?,
val pin: String?,
val aciPreKeyCollection: PreKeyCollection?,
val pniPreKeyCollection: PreKeyCollection?
@@ -15,13 +15,13 @@ data class VerifyResponse(
companion object {
fun from(
response: ServiceResponse<VerifyAccountResponse>,
kbsData: KbsPinData?,
masterKey: MasterKey?,
pin: String?,
aciPreKeyCollection: PreKeyCollection?,
pniPreKeyCollection: PreKeyCollection?
): ServiceResponse<VerifyResponse> {
return if (response.result.isPresent) {
ServiceResponse.forResult(VerifyResponse(response.result.get(), kbsData, pin, aciPreKeyCollection, pniPreKeyCollection), 200, null)
ServiceResponse.forResult(VerifyResponse(response.result.get(), masterKey, pin, aciPreKeyCollection, pniPreKeyCollection), 200, null)
} else {
ServiceResponse.coerceError(response)
}

View File

@@ -1,14 +1,12 @@
package org.thoughtcrime.securesms.registration
import org.thoughtcrime.securesms.pin.KeyBackupSystemWrongPinException
import org.thoughtcrime.securesms.pin.TokenData
import org.whispersystems.signalservice.api.KeyBackupSystemNoDataException
import org.thoughtcrime.securesms.pin.SvrWrongPinException
import org.thoughtcrime.securesms.registration.viewmodel.SvrAuthCredentialSet
import org.whispersystems.signalservice.api.SvrNoDataException
import org.whispersystems.signalservice.api.push.exceptions.IncorrectRegistrationRecoveryPasswordException
import org.whispersystems.signalservice.api.push.exceptions.NoSuchSessionException
import org.whispersystems.signalservice.api.push.exceptions.NonSuccessfulResponseCodeException
import org.whispersystems.signalservice.internal.ServiceResponse
import org.whispersystems.signalservice.internal.ServiceResponseProcessor
import org.whispersystems.signalservice.internal.contacts.entities.TokenResponse
import org.whispersystems.signalservice.internal.push.LockedException
/**
@@ -16,7 +14,19 @@ import org.whispersystems.signalservice.internal.push.LockedException
*/
sealed class VerifyResponseProcessor(response: ServiceResponse<VerifyResponse>) : ServiceResponseProcessor<VerifyResponse>(response) {
open val tokenData: TokenData? = null
open val svrTriesRemaining: Int?
get() = (error as? SvrWrongPinException)?.triesRemaining
open val svrAuthCredentials: SvrAuthCredentialSet?
get() {
return error?.let {
if (it is LockedException) {
SvrAuthCredentialSet(it.svr1Credentials, it.svr2Credentials)
} else {
null
}
}
}
public override fun authorizationFailed(): Boolean {
return super.authorizationFailed()
@@ -34,10 +44,6 @@ sealed class VerifyResponseProcessor(response: ServiceResponse<VerifyResponse>)
return super.getError()
}
fun invalidSession(): Boolean {
return error is NoSuchSessionException
}
fun getLockedException(): LockedException {
return error as LockedException
}
@@ -50,34 +56,24 @@ sealed class VerifyResponseProcessor(response: ServiceResponse<VerifyResponse>)
return error is IncorrectRegistrationRecoveryPasswordException
}
abstract fun isKbsLocked(): Boolean
/** True if the account has reglock enabled but all guesses have been exhausted, otherwise false. */
abstract fun isRegistrationLockPresentAndSvrExhausted(): Boolean
}
/**
* Verify processor specific to verifying without needing to handle registration lock.
*/
class VerifyResponseWithoutKbs(response: ServiceResponse<VerifyResponse>) : VerifyResponseProcessor(response) {
override fun isKbsLocked(): Boolean {
return registrationLock() && getLockedException().basicStorageCredentials == null
override fun isRegistrationLockPresentAndSvrExhausted(): Boolean {
return registrationLock() && getLockedException().svr1Credentials == null && getLockedException().svr2Credentials == null
}
}
/**
* Verify processor specific to verifying and successfully retrieving KBS information to
* later attempt to verif with registration lock data (pin).
* Verify processor indicating we cannot register until registration lock has been resolved.
*/
class VerifyResponseWithSuccessfulKbs(response: ServiceResponse<VerifyResponse>, override val tokenData: TokenData) : VerifyResponseProcessor(response) {
override fun isKbsLocked(): Boolean {
return registrationLock() && tokenData.triesRemaining == 0
}
}
/**
* Verify processor specific to verifying and unsuccessfully retrieving KBS information that
* is required for attempting to verify a registration locked account.
*/
class VerifyResponseWithFailedKbs(response: ServiceResponse<TokenData>) : VerifyResponseProcessor(ServiceResponse.coerceError(response)) {
override fun isKbsLocked(): Boolean {
class VerifyResponseHitRegistrationLock(response: ServiceResponse<VerifyResponse>) : VerifyResponseProcessor(response) {
override fun isRegistrationLockPresentAndSvrExhausted(): Boolean {
return false
}
}
@@ -86,18 +82,14 @@ class VerifyResponseWithFailedKbs(response: ServiceResponse<TokenData>) : Verify
* Process responses from attempting to verify an account with registration lock for use in
* account registration.
*/
class VerifyResponseWithRegistrationLockProcessor(response: ServiceResponse<VerifyResponse>, override val tokenData: TokenData?) : VerifyResponseProcessor(response) {
class VerifyResponseWithRegistrationLockProcessor(response: ServiceResponse<VerifyResponse>, override val svrAuthCredentials: SvrAuthCredentialSet?) : VerifyResponseProcessor(response) {
fun wrongPin(): Boolean {
return error is KeyBackupSystemWrongPinException
return error is SvrWrongPinException
}
fun getTokenResponse(): TokenResponse {
return (error as KeyBackupSystemWrongPinException).tokenResponse
}
override fun isKbsLocked(): Boolean {
return error is KeyBackupSystemNoDataException
override fun isRegistrationLockPresentAndSvrExhausted(): Boolean {
return error is SvrNoDataException
}
fun updatedIfRegistrationFailed(response: ServiceResponse<VerifyResponse>): VerifyResponseWithRegistrationLockProcessor {
@@ -105,12 +97,12 @@ class VerifyResponseWithRegistrationLockProcessor(response: ServiceResponse<Veri
return this
}
return VerifyResponseWithRegistrationLockProcessor(ServiceResponse.coerceError(response), tokenData)
return VerifyResponseWithRegistrationLockProcessor(ServiceResponse.coerceError(response), svrAuthCredentials)
}
override fun isServerSentError(): Boolean {
return super.isServerSentError() ||
error is KeyBackupSystemWrongPinException ||
error is KeyBackupSystemNoDataException
error is SvrWrongPinException ||
error is SvrNoDataException
}
}

View File

@@ -172,11 +172,9 @@ public abstract class BaseEnterSmsCodeFragment<ViewModel extends BaseRegistratio
handleSuccessfulVerify();
} else if (processor.rateLimit()) {
handleRateLimited();
} else if (processor.registrationLock() && !processor.isKbsLocked()) {
} else if (processor.registrationLock() && !processor.isRegistrationLockPresentAndSvrExhausted()) {
LockedException lockedException = processor.getLockedException();
handleRegistrationLock(lockedException.getTimeRemaining());
} else if (processor.isKbsLocked()) {
handleKbsAccountLocked();
} else if (processor.authorizationFailed()) {
handleIncorrectCodeError();
} else {
@@ -227,7 +225,7 @@ public abstract class BaseEnterSmsCodeFragment<ViewModel extends BaseRegistratio
});
}
protected void handleKbsAccountLocked() {
protected void handleSvrAccountLocked() {
navigateToKbsAccountLocked();
}

View File

@@ -21,12 +21,12 @@ import org.signal.core.util.logging.Log;
import org.thoughtcrime.securesms.LoggingFragment;
import org.thoughtcrime.securesms.R;
import org.thoughtcrime.securesms.lock.v2.PinKeyboardType;
import org.thoughtcrime.securesms.pin.TokenData;
import org.thoughtcrime.securesms.registration.viewmodel.BaseRegistrationViewModel;
import org.signal.core.util.concurrent.LifecycleDisposable;
import org.thoughtcrime.securesms.util.ViewUtil;
import org.thoughtcrime.securesms.util.views.CircularProgressMaterialButton;
import java.util.Objects;
import java.util.concurrent.TimeUnit;
import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers;
@@ -114,10 +114,9 @@ public abstract class BaseRegistrationLockFragment extends LoggingFragment {
viewModel.getLockedTimeRemaining()
.observe(getViewLifecycleOwner(), t -> timeRemaining = t);
TokenData keyBackupCurrentToken = viewModel.getKeyBackupCurrentToken();
Integer triesRemaining = viewModel.getSvrTriesRemaining();
if (keyBackupCurrentToken != null) {
int triesRemaining = keyBackupCurrentToken.getTriesRemaining();
if (triesRemaining != null) {
if (triesRemaining <= 3) {
int daysRemaining = getLockoutDays(timeRemaining);
@@ -177,8 +176,8 @@ public abstract class BaseRegistrationLockFragment extends LoggingFragment {
if (processor.hasResult()) {
handleSuccessfulPinEntry(pin);
} else if (processor.wrongPin()) {
onIncorrectKbsRegistrationLockPin(processor.getTokenData());
} else if (processor.isKbsLocked() || processor.registrationLock()) {
onIncorrectKbsRegistrationLockPin(Objects.requireNonNull(processor.getSvrTriesRemaining()));
} else if (processor.isRegistrationLockPresentAndSvrExhausted() || processor.registrationLock()) {
onKbsAccountLocked();
} else if (processor.rateLimit()) {
onRateLimited();
@@ -191,35 +190,33 @@ public abstract class BaseRegistrationLockFragment extends LoggingFragment {
disposables.add(verify);
}
public void onIncorrectKbsRegistrationLockPin(@NonNull TokenData tokenData) {
public void onIncorrectKbsRegistrationLockPin(int svrTriesRemaining) {
pinButton.cancelSpinning();
pinEntry.getText().clear();
enableAndFocusPinEntry();
viewModel.setKeyBackupTokenData(tokenData);
viewModel.setSvrTriesRemaining(svrTriesRemaining);
int triesRemaining = tokenData.getTriesRemaining();
if (triesRemaining == 0) {
if (svrTriesRemaining == 0) {
Log.w(TAG, "Account locked. User out of attempts on KBS.");
onAccountLocked();
return;
}
if (triesRemaining == 3) {
if (svrTriesRemaining == 3) {
int daysRemaining = getLockoutDays(timeRemaining);
new MaterialAlertDialogBuilder(requireContext())
.setTitle(R.string.RegistrationLockFragment__incorrect_pin)
.setMessage(getTriesRemainingDialogMessage(triesRemaining, daysRemaining))
.setMessage(getTriesRemainingDialogMessage(svrTriesRemaining, daysRemaining))
.setPositiveButton(android.R.string.ok, null)
.show();
}
if (triesRemaining > 5) {
if (svrTriesRemaining > 5) {
errorLabel.setText(R.string.RegistrationLockFragment__incorrect_pin_try_again);
} else {
errorLabel.setText(requireContext().getResources().getQuantityString(R.plurals.RegistrationLockFragment__incorrect_pin_d_attempts_remaining, triesRemaining, triesRemaining));
errorLabel.setText(requireContext().getResources().getQuantityString(R.plurals.RegistrationLockFragment__incorrect_pin_d_attempts_remaining, svrTriesRemaining, svrTriesRemaining));
forgotPin.setVisibility(View.VISIBLE);
}
}

View File

@@ -470,7 +470,6 @@ public final class EnterPhoneNumberFragment extends LoggingFragment implements R
: R.string.RegistrationActivity_a_verification_code_will_be_sent_to_this_number,
e164number,
() -> {
exitInProgressUiState();
ViewUtil.hideKeyboard(context, number.getEditText());
onConfirmed.run();
},

View File

@@ -14,8 +14,8 @@ import org.signal.core.util.logging.Log
import org.thoughtcrime.securesms.LoggingFragment
import org.thoughtcrime.securesms.R
import org.thoughtcrime.securesms.databinding.PinRestoreEntryFragmentBinding
import org.thoughtcrime.securesms.lock.v2.KbsConstants
import org.thoughtcrime.securesms.lock.v2.PinKeyboardType
import org.thoughtcrime.securesms.lock.v2.SvrConstants
import org.thoughtcrime.securesms.registration.VerifyResponseWithRegistrationLockProcessor
import org.thoughtcrime.securesms.registration.viewmodel.ReRegisterWithPinViewModel
import org.thoughtcrime.securesms.registration.viewmodel.RegistrationViewModel
@@ -80,7 +80,7 @@ class ReRegisterWithPinFragment : LoggingFragment(R.layout.pin_restore_entry_fra
binding.pinRestoreKeyboardToggle.setIconResource(getPinEntryKeyboardType().other.iconResource)
reRegisterViewModel.updateTokenData(registrationViewModel.keyBackupCurrentToken)
reRegisterViewModel.updateSvrTriesRemaining(registrationViewModel.svrTriesRemaining)
disposables += reRegisterViewModel.triesRemaining.subscribe(this::updateTriesRemaining)
}
@@ -93,7 +93,7 @@ class ReRegisterWithPinFragment : LoggingFragment(R.layout.pin_restore_entry_fra
private fun handlePinEntry() {
val pin: String? = binding.pinRestorePinInput.text?.toString()
val trimmedLength = pin?.replace(" ", "")?.length ?: 0
val trimmedLength = pin?.trim()?.length ?: 0
if (trimmedLength == 0) {
Toast.makeText(requireContext(), R.string.RegistrationActivity_you_must_enter_your_registration_lock_PIN, Toast.LENGTH_LONG).show()
enableAndFocusPinEntry()
@@ -126,12 +126,12 @@ class ReRegisterWithPinFragment : LoggingFragment(R.layout.pin_restore_entry_fra
reRegisterViewModel.hasIncorrectGuess = true
if (processor is VerifyResponseWithRegistrationLockProcessor && processor.wrongPin()) {
reRegisterViewModel.updateTokenData(processor.tokenData)
if (processor.tokenData != null) {
registrationViewModel.setKeyBackupTokenData(processor.tokenData)
reRegisterViewModel.updateSvrTriesRemaining(processor.svrTriesRemaining)
if (processor.svrTriesRemaining != null) {
registrationViewModel.svrTriesRemaining = processor.svrTriesRemaining
}
return@subscribe
} else if (processor.isKbsLocked()) {
} else if (processor.isRegistrationLockPresentAndSvrExhausted()) {
Log.w(TAG, "Unable to continue skip flow, KBS is locked")
onAccountLocked()
} else if (processor.isIncorrectRegistrationRecoveryPassword()) {
@@ -215,7 +215,7 @@ class ReRegisterWithPinFragment : LoggingFragment(R.layout.pin_restore_entry_fra
MaterialAlertDialogBuilder(requireContext())
.setTitle(R.string.PinRestoreEntryFragment_need_help)
.setMessage(getString(message, KbsConstants.MINIMUM_PIN_LENGTH))
.setMessage(getString(message, SvrConstants.MINIMUM_PIN_LENGTH))
.setPositiveButton(R.string.PinRestoreEntryFragment_skip) { _, _ -> onSkipPinEntry() }
.setNeutralButton(R.string.PinRestoreEntryFragment_contact_support) { _, _ ->
val body = SupportEmailUtil.generateSupportEmailBody(requireContext(), R.string.ReRegisterWithPinFragment_support_email_subject, null, null)

View File

@@ -16,7 +16,7 @@ import org.thoughtcrime.securesms.jobs.MultiDeviceProfileContentUpdateJob
import org.thoughtcrime.securesms.jobs.MultiDeviceProfileKeyUpdateJob
import org.thoughtcrime.securesms.jobs.ProfileUploadJob
import org.thoughtcrime.securesms.keyvalue.SignalStore
import org.thoughtcrime.securesms.lock.v2.CreateKbsPinActivity
import org.thoughtcrime.securesms.lock.v2.CreateSvrPinActivity
import org.thoughtcrime.securesms.pin.PinRestoreActivity
import org.thoughtcrime.securesms.profiles.AvatarHelper
import org.thoughtcrime.securesms.profiles.edit.EditProfileActivity
@@ -51,7 +51,7 @@ class RegistrationCompleteFragment : LoggingFragment() {
val isProfileNameEmpty = Recipient.self().profileName.isEmpty
val isAvatarEmpty = !AvatarHelper.hasAvatar(activity, Recipient.self().id)
val needsProfile = isProfileNameEmpty || isAvatarEmpty
val needsPin = !SignalStore.kbsValues().hasPin() && !viewModel.isReregister
val needsPin = !SignalStore.svr().hasPin() && !viewModel.isReregister
Log.i(TAG, "Pin restore flow not required. Profile name: $isProfileNameEmpty | Profile avatar: $isAvatarEmpty | Needs PIN: $needsPin")
@@ -66,7 +66,7 @@ class RegistrationCompleteFragment : LoggingFragment() {
var startIntent = MainActivity.clearTop(activity)
if (needsPin) {
startIntent = chainIntents(CreateKbsPinActivity.getIntentForPinCreate(activity), startIntent)
startIntent = chainIntents(CreateSvrPinActivity.getIntentForPinCreate(activity), startIntent)
}
if (needsProfile) {

View File

@@ -58,7 +58,7 @@ object RegistrationViewDelegate {
setMessage(message)
setPositiveButton(android.R.string.ok) { _, _ -> onConfirmed.run() }
setNegativeButton(R.string.RegistrationActivity_edit_number) { _, _ -> onEditNumber.run() }
setOnDismissListener { onEditNumber.run() }
setOnCancelListener { onEditNumber.run() }
}.show()
}
}

View File

@@ -12,16 +12,13 @@ import com.google.i18n.phonenumbers.Phonenumber;
import org.signal.core.util.logging.Log;
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.VerifyAccountRepository;
import org.thoughtcrime.securesms.registration.VerifyAccountRepository.Mode;
import org.thoughtcrime.securesms.registration.VerifyResponse;
import org.thoughtcrime.securesms.registration.VerifyResponseProcessor;
import org.thoughtcrime.securesms.registration.VerifyResponseWithFailedKbs;
import org.thoughtcrime.securesms.registration.VerifyResponseWithRegistrationLockProcessor;
import org.thoughtcrime.securesms.registration.VerifyResponseWithSuccessfulKbs;
import org.thoughtcrime.securesms.registration.VerifyResponseHitRegistrationLock;
import org.thoughtcrime.securesms.registration.VerifyResponseWithoutKbs;
import org.whispersystems.signalservice.internal.ServiceResponse;
@@ -48,7 +45,8 @@ public abstract class BaseRegistrationViewModel extends ViewModel {
private static final String STATE_PUSH_TIMED_OUT = "PUSH_TIMED_OUT";
private static final String STATE_INCORRECT_CODE_ATTEMPTS = "STATE_INCORRECT_CODE_ATTEMPTS";
private static final String STATE_REQUEST_RATE_LIMITER = "REQUEST_RATE_LIMITER";
private static final String STATE_KBS_TOKEN = "KBS_TOKEN";
private static final String STATE_SVR_AUTH = "SVR_AUTH";
private static final String STATE_SVR_TRIES_REMAINING = "SVR_TRIES_REMAINING";
private static final String STATE_TIME_REMAINING = "TIME_REMAINING";
private static final String STATE_CAN_CALL_AT_TIME = "CAN_CALL_AT_TIME";
private static final String STATE_CAN_SMS_AT_TIME = "CAN_SMS_AT_TIME";
@@ -56,24 +54,21 @@ public abstract class BaseRegistrationViewModel extends ViewModel {
protected final SavedStateHandle savedState;
protected final VerifyAccountRepository verifyAccountRepository;
protected final KbsRepository kbsRepository;
public BaseRegistrationViewModel(@NonNull SavedStateHandle savedStateHandle,
@NonNull VerifyAccountRepository verifyAccountRepository,
@NonNull KbsRepository kbsRepository,
@NonNull String password)
{
this.savedState = savedStateHandle;
this.verifyAccountRepository = verifyAccountRepository;
this.kbsRepository = kbsRepository;
setInitialDefaultValue(STATE_NUMBER, NumberViewState.INITIAL);
setInitialDefaultValue(STATE_REGISTRATION_SECRET, password);
setInitialDefaultValue(STATE_VERIFICATION_CODE, "");
setInitialDefaultValue(STATE_INCORRECT_CODE_ATTEMPTS, 0);
setInitialDefaultValue(STATE_REQUEST_RATE_LIMITER, new LocalCodeRequestRateLimiter(60_000));
setInitialDefaultValue(STATE_RECOVERY_PASSWORD, SignalStore.kbsValues().getRecoveryPassword());
setInitialDefaultValue(STATE_RECOVERY_PASSWORD, SignalStore.svr().getRecoveryPassword());
setInitialDefaultValue(STATE_PUSH_TIMED_OUT, false);
}
@@ -188,12 +183,20 @@ public abstract class BaseRegistrationViewModel extends ViewModel {
return challengeKeys;
}
public @Nullable TokenData getKeyBackupCurrentToken() {
return savedState.get(STATE_KBS_TOKEN);
protected void setSvrAuthCredentials(SvrAuthCredentialSet credentials) {
savedState.set(STATE_SVR_AUTH, credentials);
}
public void setKeyBackupTokenData(@Nullable TokenData tokenData) {
savedState.set(STATE_KBS_TOKEN, tokenData);
protected @Nullable SvrAuthCredentialSet getSvrAuthCredentials() {
return savedState.get(STATE_SVR_AUTH);
}
public @Nullable Integer getSvrTriesRemaining() {
return savedState.get(STATE_SVR_TRIES_REMAINING);
}
public void setSvrTriesRemaining(@Nullable Integer triesRemaining) {
savedState.set(STATE_SVR_TRIES_REMAINING, triesRemaining);
}
public void setRecoveryPassword(@Nullable String recoveryPassword) {
@@ -338,56 +341,54 @@ public abstract class BaseRegistrationViewModel extends ViewModel {
return verifyAccountWithoutRegistrationLock()
.flatMap(response -> {
if (response.getResult().isPresent() && response.getResult().get().getKbsData() != null) {
if (response.getResult().isPresent() && response.getResult().get().getMasterKey() != null) {
return onVerifySuccessWithRegistrationLock(new VerifyResponseWithRegistrationLockProcessor(response, null), response.getResult().get().getPin());
}
VerifyResponseProcessor processor = new VerifyResponseWithoutKbs(response);
if (processor.hasResult()) {
return onVerifySuccess(processor);
} else if (processor.registrationLock() && !processor.isKbsLocked()) {
return kbsRepository.getToken(processor.getLockedException().getBasicStorageCredentials())
.map(r -> r.getResult().isPresent() ? new VerifyResponseWithSuccessfulKbs(processor.getResponse(), r.getResult().get())
: new VerifyResponseWithFailedKbs(r));
} else if (processor.registrationLock() && !processor.isRegistrationLockPresentAndSvrExhausted()) {
return Single.just(new VerifyResponseHitRegistrationLock(processor.getResponse()));
}
return Single.just(processor);
})
.observeOn(AndroidSchedulers.mainThread())
.doOnSuccess(processor -> {
if (processor.registrationLock() && !processor.isKbsLocked()) {
if (processor.registrationLock() && !processor.isRegistrationLockPresentAndSvrExhausted()) {
setLockedTimeRemaining(processor.getLockedException().getTimeRemaining());
setKeyBackupTokenData(processor.getTokenData());
} else if (processor.isKbsLocked()) {
setSvrTriesRemaining(processor.getSvrTriesRemaining());
setSvrAuthCredentials(processor.getSvrAuthCredentials());
} else if (processor.isRegistrationLockPresentAndSvrExhausted()) {
setLockedTimeRemaining(processor.getLockedException().getTimeRemaining());
}
});
}
public Single<VerifyResponseWithRegistrationLockProcessor> verifyCodeAndRegisterAccountWithRegistrationLock(@NonNull String pin) {
TokenData kbsTokenData = Objects.requireNonNull(getKeyBackupCurrentToken());
SvrAuthCredentialSet authCredentials = Objects.requireNonNull(getSvrAuthCredentials());
return verifyAccountWithRegistrationLock(pin, kbsTokenData)
.map(r -> new VerifyResponseWithRegistrationLockProcessor(r, kbsTokenData))
return verifyAccountWithRegistrationLock(pin, authCredentials)
.map(r -> new VerifyResponseWithRegistrationLockProcessor(r, authCredentials))
.flatMap(processor -> {
if (processor.hasResult()) {
return onVerifySuccessWithRegistrationLock(processor, pin);
} else if (processor.wrongPin()) {
TokenData newToken = TokenData.withResponse(kbsTokenData, processor.getTokenResponse());
return Single.just(new VerifyResponseWithRegistrationLockProcessor(processor.getResponse(), newToken));
return Single.just(new VerifyResponseWithRegistrationLockProcessor(processor.getResponse(), authCredentials));
}
return Single.just(processor);
})
.observeOn(AndroidSchedulers.mainThread())
.doOnSuccess(processor -> {
if (processor.wrongPin()) {
setKeyBackupTokenData(processor.getTokenData());
setSvrTriesRemaining(processor.getSvrTriesRemaining());
}
});
}
protected abstract Single<ServiceResponse<VerifyResponse>> verifyAccountWithoutRegistrationLock();
protected abstract Single<ServiceResponse<VerifyResponse>> verifyAccountWithRegistrationLock(@NonNull String pin, @NonNull TokenData kbsTokenData);
protected abstract Single<ServiceResponse<VerifyResponse>> verifyAccountWithRegistrationLock(@NonNull String pin, @NonNull SvrAuthCredentialSet svrAuthCredentials);
protected abstract Single<VerifyResponseProcessor> onVerifySuccess(@NonNull VerifyResponseProcessor processor);

View File

@@ -4,7 +4,6 @@ import androidx.lifecycle.ViewModel
import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers
import io.reactivex.rxjava3.core.Observable
import io.reactivex.rxjava3.subjects.BehaviorSubject
import org.thoughtcrime.securesms.pin.TokenData
/**
* Used during re-registration flow when pin entry is required to skip SMS verification. Mostly tracks
@@ -19,14 +18,14 @@ class ReRegisterWithPinViewModel : ViewModel() {
private val _triesRemaining: BehaviorSubject<Int> = BehaviorSubject.createDefault(10)
val triesRemaining: Observable<Int> = _triesRemaining.observeOn(AndroidSchedulers.mainThread())
fun updateTokenData(tokenData: TokenData?) {
if (tokenData == null) {
fun updateSvrTriesRemaining(triesRemaining: Int?) {
if (triesRemaining == null) {
isLocalVerification = true
if (hasIncorrectGuess) {
_triesRemaining.onNext((_triesRemaining.value!! - 1).coerceAtLeast(0))
}
} else {
_triesRemaining.onNext(tokenData.triesRemaining)
_triesRemaining.onNext(triesRemaining)
}
}
}

View File

@@ -16,9 +16,8 @@ import org.thoughtcrime.securesms.jobs.NewRegistrationUsernameSyncJob;
import org.thoughtcrime.securesms.jobs.StorageAccountRestoreJob;
import org.thoughtcrime.securesms.jobs.StorageSyncJob;
import org.thoughtcrime.securesms.keyvalue.SignalStore;
import org.thoughtcrime.securesms.pin.KbsRepository;
import org.thoughtcrime.securesms.pin.KeyBackupSystemWrongPinException;
import org.thoughtcrime.securesms.pin.TokenData;
import org.thoughtcrime.securesms.pin.SvrWrongPinException;
import org.thoughtcrime.securesms.pin.SvrRepository;
import org.thoughtcrime.securesms.registration.RegistrationData;
import org.thoughtcrime.securesms.registration.RegistrationRepository;
import org.thoughtcrime.securesms.registration.RegistrationSessionProcessor;
@@ -29,13 +28,13 @@ import org.thoughtcrime.securesms.registration.VerifyResponseWithRegistrationLoc
import org.thoughtcrime.securesms.registration.VerifyResponseWithoutKbs;
import org.thoughtcrime.securesms.util.FeatureFlags;
import org.thoughtcrime.securesms.util.Util;
import org.whispersystems.signalservice.api.KbsPinData;
import org.whispersystems.signalservice.api.KeyBackupSystemNoDataException;
import org.whispersystems.signalservice.api.SvrNoDataException;
import org.whispersystems.signalservice.api.kbs.MasterKey;
import org.whispersystems.signalservice.api.kbs.PinHashUtil;
import org.whispersystems.signalservice.api.push.ServiceIdType;
import org.whispersystems.signalservice.api.push.exceptions.IncorrectCodeException;
import org.whispersystems.signalservice.api.push.exceptions.IncorrectRegistrationRecoveryPasswordException;
import org.whispersystems.signalservice.internal.ServiceResponse;
import org.whispersystems.signalservice.internal.contacts.entities.TokenResponse;
import org.whispersystems.signalservice.internal.push.RegistrationSessionMetadataResponse;
import org.whispersystems.util.Base64;
@@ -67,10 +66,9 @@ public final class RegistrationViewModel extends BaseRegistrationViewModel {
public RegistrationViewModel(@NonNull SavedStateHandle savedStateHandle,
boolean isReregister,
@NonNull VerifyAccountRepository verifyAccountRepository,
@NonNull KbsRepository kbsRepository,
@NonNull RegistrationRepository registrationRepository)
{
super(savedStateHandle, verifyAccountRepository, kbsRepository, Util.getSecret(18));
super(savedStateHandle, verifyAccountRepository, Util.getSecret(18));
this.registrationRepository = registrationRepository;
@@ -174,14 +172,12 @@ public final class RegistrationViewModel extends BaseRegistrationViewModel {
})
.flatMap(verifyAccountWithoutKbsResponse -> {
VerifyResponseProcessor processor = new VerifyResponseWithoutKbs(verifyAccountWithoutKbsResponse);
String pin = SignalStore.kbsValues().getPin();
String pin = SignalStore.svr().getPin();
if ((processor.isKbsLocked() || processor.registrationLock()) && SignalStore.kbsValues().getRegistrationLockToken() != null && pin != null) {
KbsPinData pinData = new KbsPinData(SignalStore.kbsValues().getOrCreateMasterKey(), SignalStore.kbsValues().getRegistrationLockTokenResponse());
return verifyAccountRepository.registerAccount(sessionId, getRegistrationData(), pin, () -> pinData)
if ((processor.isRegistrationLockPresentAndSvrExhausted() || processor.registrationLock()) && SignalStore.svr().getRegistrationLockToken() != null && pin != null) {
return verifyAccountRepository.registerAccount(sessionId, getRegistrationData(), pin, () -> SignalStore.svr().getOrCreateMasterKey())
.map(verifyAccountWithPinResponse -> {
if (verifyAccountWithPinResponse.getResult().isPresent() && verifyAccountWithPinResponse.getResult().get().getKbsData() != null) {
if (verifyAccountWithPinResponse.getResult().isPresent() && verifyAccountWithPinResponse.getResult().get().getMasterKey() != null) {
return verifyAccountWithPinResponse;
} else {
return verifyAccountWithoutKbsResponse;
@@ -195,7 +191,7 @@ public final class RegistrationViewModel extends BaseRegistrationViewModel {
}
@Override
protected Single<ServiceResponse<VerifyResponse>> verifyAccountWithRegistrationLock(@NonNull String pin, @NonNull TokenData kbsTokenData) {
protected Single<ServiceResponse<VerifyResponse>> verifyAccountWithRegistrationLock(@NonNull String pin, @NonNull SvrAuthCredentialSet svrAuthCredentials) {
final String sessionId = getSessionId();
if (sessionId == null) {
throw new IllegalStateException("No valid registration session");
@@ -210,7 +206,7 @@ public final class RegistrationViewModel extends BaseRegistrationViewModel {
})
.<ServiceResponse<VerifyResponse>>flatMap(processor -> {
if (processor.isAlreadyVerified() || (processor.hasResult() && processor.isVerified())) {
return verifyAccountRepository.registerAccount(sessionId, getRegistrationData(), pin, () -> Objects.requireNonNull(KbsRepository.restoreMasterKey(pin, kbsTokenData.getEnclave(), kbsTokenData.getBasicAuth(), kbsTokenData.getTokenResponse())));
return verifyAccountRepository.registerAccount(sessionId, getRegistrationData(), pin, () -> SvrRepository.restoreMasterKeyPreRegistration(svrAuthCredentials, pin));
} else {
return Single.just(ServiceResponse.coerceError(processor.getResponse()));
}
@@ -250,18 +246,17 @@ public final class RegistrationViewModel extends BaseRegistrationViewModel {
return updateFcmTokenValue().subscribeOn(Schedulers.io())
.observeOn(Schedulers.io())
.onErrorReturnItem("")
.flatMap(s -> verifyReRegisterWithRecoveryPassword(pin, data.pinData));
.flatMap(s -> verifyReRegisterWithRecoveryPassword(pin, data.masterKey));
} else {
throw new IllegalStateException("Unable to get token or master key");
throw new IncorrectRegistrationRecoveryPasswordException();
}
})
.onErrorReturn(t -> new VerifyResponseWithRegistrationLockProcessor(ServiceResponse.forUnknownError(t), getKeyBackupCurrentToken()))
.onErrorReturn(t -> new VerifyResponseWithRegistrationLockProcessor(ServiceResponse.forUnknownError(t), getSvrAuthCredentials()))
.map(p -> {
if (p instanceof VerifyResponseWithRegistrationLockProcessor) {
VerifyResponseWithRegistrationLockProcessor lockProcessor = (VerifyResponseWithRegistrationLockProcessor) p;
if (lockProcessor.wrongPin() && lockProcessor.getTokenData() != null) {
TokenData newToken = TokenData.withResponse(lockProcessor.getTokenData(), lockProcessor.getTokenResponse());
return new VerifyResponseWithRegistrationLockProcessor(lockProcessor.getResponse(), newToken);
if (lockProcessor.wrongPin() && lockProcessor.getSvrTriesRemaining() != null) {
return new VerifyResponseWithRegistrationLockProcessor(lockProcessor.getResponse(), lockProcessor.getSvrAuthCredentials());
}
}
@@ -277,37 +272,33 @@ public final class RegistrationViewModel extends BaseRegistrationViewModel {
@WorkerThread
private @NonNull ReRegistrationData verifyReRegisterWithPinInternal(@NonNull String pin)
throws KeyBackupSystemWrongPinException, IOException, KeyBackupSystemNoDataException
throws SvrWrongPinException, IOException, SvrNoDataException
{
String localPinHash = SignalStore.kbsValues().getLocalPinHash();
String localPinHash = SignalStore.svr().getLocalPinHash();
if (hasRecoveryPassword() && localPinHash != null) {
if (PinHashUtil.verifyLocalPinHash(localPinHash, pin)) {
Log.i(TAG, "Local pin matches input, attempting registration");
return ReRegistrationData.canProceed(new KbsPinData(SignalStore.kbsValues().getOrCreateMasterKey(), SignalStore.kbsValues().getRegistrationLockTokenResponse()));
return ReRegistrationData.canProceed(SignalStore.svr().getOrCreateMasterKey());
} else {
throw new KeyBackupSystemWrongPinException(new TokenResponse(null, null, 0));
throw new SvrWrongPinException(0);
}
} else {
TokenData data = getKeyBackupCurrentToken();
if (data == null) {
Log.w(TAG, "No token data, abort skip flow");
SvrAuthCredentialSet authCredentials = getSvrAuthCredentials();
if (authCredentials == null) {
Log.w(TAG, "No SVR auth credentials, abort skip flow");
return ReRegistrationData.cannotProceed();
}
KbsPinData kbsPinData = KbsRepository.restoreMasterKey(pin, data.getEnclave(), data.getBasicAuth(), data.getTokenResponse());
if (kbsPinData == null || kbsPinData.getMasterKey() == null) {
Log.w(TAG, "No kbs data, abort skip flow");
return ReRegistrationData.cannotProceed();
}
MasterKey masterKey = SvrRepository.restoreMasterKeyPreRegistration(authCredentials, pin);
setRecoveryPassword(kbsPinData.getMasterKey().deriveRegistrationRecoveryPassword());
setKeyBackupTokenData(data);
return ReRegistrationData.canProceed(kbsPinData);
setRecoveryPassword(masterKey.deriveRegistrationRecoveryPassword());
setSvrTriesRemaining(10);
return ReRegistrationData.canProceed(masterKey);
}
}
private Single<VerifyResponseProcessor> verifyReRegisterWithRecoveryPassword(@NonNull String pin, @NonNull KbsPinData pinData) {
private Single<VerifyResponseProcessor> verifyReRegisterWithRecoveryPassword(@NonNull String pin, @NonNull MasterKey masterKey) {
RegistrationData registrationData = getRegistrationData();
if (registrationData.getRecoveryPassword() == null) {
throw new IllegalStateException("No valid recovery password");
@@ -319,9 +310,10 @@ public final class RegistrationViewModel extends BaseRegistrationViewModel {
.map(VerifyResponseWithoutKbs::new)
.flatMap(processor -> {
if (processor.registrationLock()) {
return verifyAccountRepository.registerAccount(null, registrationData, pin, () -> pinData)
setSvrAuthCredentials(processor.getSvrAuthCredentials());
return verifyAccountRepository.registerAccount(null, registrationData, pin, () -> masterKey)
.onErrorReturn(ServiceResponse::forUnknownError)
.map(r -> new VerifyResponseWithRegistrationLockProcessor(r, getKeyBackupCurrentToken()));
.map(r -> new VerifyResponseWithRegistrationLockProcessor(r, processor.getSvrAuthCredentials()));
} else {
return Single.just(processor);
}
@@ -329,14 +321,14 @@ public final class RegistrationViewModel extends BaseRegistrationViewModel {
.flatMap(processor -> {
if (processor.hasResult()) {
VerifyResponse verifyResponse = processor.getResult();
boolean setRegistrationLockEnabled = verifyResponse.getKbsData() != null;
boolean setRegistrationLockEnabled = verifyResponse.getMasterKey() != null;
if (!setRegistrationLockEnabled) {
verifyResponse = new VerifyResponse(processor.getResult().getVerifyAccountResponse(), pinData, pin, verifyResponse.getAciPreKeyCollection(), verifyResponse.getPniPreKeyCollection());
verifyResponse = new VerifyResponse(processor.getResult().getVerifyAccountResponse(), masterKey, pin, verifyResponse.getAciPreKeyCollection(), verifyResponse.getPniPreKeyCollection());
}
return registrationRepository.registerAccount(registrationData, verifyResponse, setRegistrationLockEnabled)
.map(r -> new VerifyResponseWithRegistrationLockProcessor(r, getKeyBackupCurrentToken()));
.map(r -> new VerifyResponseWithRegistrationLockProcessor(r, getSvrAuthCredentials()));
} else {
return Single.just(processor);
}
@@ -360,8 +352,8 @@ public final class RegistrationViewModel extends BaseRegistrationViewModel {
}
private Single<Boolean> checkForValidKbsAuthCredentials() {
final List<String> kbsAuthTokenList = SignalStore.kbsValues().getKbsAuthTokenList();
List<String> usernamePasswords = kbsAuthTokenList
final List<String> svrAuthTokenList = SignalStore.svr().getAuthTokenList();
List<String> usernamePasswords = svrAuthTokenList
.stream()
.limit(10)
.map(t -> {
@@ -377,23 +369,8 @@ public final class RegistrationViewModel extends BaseRegistrationViewModel {
return Single.just(false);
}
return registrationRepository.getKbsAuthCredential(getRegistrationData(), usernamePasswords)
.flatMap(p -> {
if (p.getValid() != null) {
return kbsRepository.getToken(p.getValid())
.flatMap(r -> {
if (r.getResult().isPresent()) {
TokenData tokenData = r.getResult().get();
setKeyBackupTokenData(tokenData);
return Single.just(tokenData.getTriesRemaining() > 0);
} else {
return Single.just(false);
}
});
} else {
return Single.just(false);
}
})
return registrationRepository.getSvrAuthCredential(getRegistrationData(), usernamePasswords)
.flatMap(p -> Single.just(p.getValid() != null))
.onErrorReturnItem(false)
.observeOn(AndroidSchedulers.mainThread());
}
@@ -432,20 +409,20 @@ public final class RegistrationViewModel extends BaseRegistrationViewModel {
}
private static class ReRegistrationData {
public boolean canProceed;
public KbsPinData pinData;
public boolean canProceed;
public MasterKey masterKey;
private ReRegistrationData(boolean canProceed, @Nullable KbsPinData pinData) {
private ReRegistrationData(boolean canProceed, @Nullable MasterKey masterKey) {
this.canProceed = canProceed;
this.pinData = pinData;
this.masterKey = masterKey;
}
public static ReRegistrationData cannotProceed() {
return new ReRegistrationData(false, null);
}
public static ReRegistrationData canProceed(@NonNull KbsPinData pinData) {
return new ReRegistrationData(true, pinData);
public static ReRegistrationData canProceed(@NonNull MasterKey masterKey) {
return new ReRegistrationData(true, masterKey);
}
}
@@ -463,7 +440,6 @@ public final class RegistrationViewModel extends BaseRegistrationViewModel {
return modelClass.cast(new RegistrationViewModel(handle,
isReregister,
new VerifyAccountRepository(ApplicationDependencies.getApplication()),
new KbsRepository(),
new RegistrationRepository(ApplicationDependencies.getApplication())));
}
}

View File

@@ -0,0 +1,42 @@
/*
* Copyright 2023 Signal Messenger, LLC
* SPDX-License-Identifier: AGPL-3.0-only
*/
package org.thoughtcrime.securesms.registration.viewmodel
import android.os.Parcelable
import kotlinx.parcelize.Parcelize
import org.whispersystems.signalservice.internal.push.AuthCredentials
@Parcelize
data class SvrAuthCredentialSet(
private val svr1Credentials: ParcelableAuthCredentials?,
private val svr2Credentials: ParcelableAuthCredentials?
) : Parcelable {
constructor(
svr1Credentials: AuthCredentials?,
svr2Credentials: AuthCredentials?
) : this(ParcelableAuthCredentials.createOrNull(svr1Credentials), ParcelableAuthCredentials.createOrNull(svr2Credentials))
val svr1: AuthCredentials? = svr1Credentials?.credentials()
val svr2: AuthCredentials? = svr2Credentials?.credentials()
@Parcelize
data class ParcelableAuthCredentials(private val username: String, private val password: String) : Parcelable {
companion object {
fun createOrNull(creds: AuthCredentials?): ParcelableAuthCredentials? {
return if (creds != null) {
ParcelableAuthCredentials(creds.username(), creds.password())
} else {
null
}
}
}
fun credentials(): AuthCredentials {
return AuthCredentials.create(username, password)
}
}
}