Skip to content

Commit

Permalink
Implement session-based account registration API.
Browse files Browse the repository at this point in the history
  • Loading branch information
nicholas-signal authored and greyson-signal committed Feb 23, 2023
1 parent 3de17fa commit a47e390
Show file tree
Hide file tree
Showing 40 changed files with 1,212 additions and 415 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,7 @@ object KbsAuthTokens : AndroidBackupItem {
}

override fun getDataForBackup(): ByteArray {
val registrationRecoveryTokenList = SignalStore.kbsValues().kbsAuthTokenList
val proto = KbsAuthToken(tokens = registrationRecoveryTokenList)
val proto = KbsAuthToken(tokens = SignalStore.kbsValues().kbsAuthTokenList)
return proto.encode()
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,21 @@ package org.thoughtcrime.securesms.components.registration

import android.content.Context
import android.util.AttributeSet
import androidx.annotation.StringRes
import com.google.android.material.button.MaterialButton
import org.thoughtcrime.securesms.R
import java.util.concurrent.TimeUnit

class ActionCountDownButton @JvmOverloads constructor(
context: Context,
attrs: AttributeSet? = null,
defStyle: Int = 0
) : MaterialButton(context, attrs, defStyle) {
@StringRes
private var enabledText = 0

@StringRes
private var disabledText = 0

private var countDownToTime: Long = 0
private var listener: Listener? = null

Expand All @@ -24,8 +30,8 @@ class ActionCountDownButton @JvmOverloads constructor(
}
}

fun setCallEnabled() {
setText(R.string.RegistrationActivity_call)
private fun setActionEnabled() {
setText(enabledText)
isEnabled = true
alpha = 1.0f
}
Expand All @@ -38,18 +44,23 @@ class ActionCountDownButton @JvmOverloads constructor(
val totalRemainingSeconds = TimeUnit.MILLISECONDS.toSeconds(remainingMillis).toInt()
val minutesRemaining = totalRemainingSeconds / 60
val secondsRemaining = totalRemainingSeconds % 60
text = resources.getString(R.string.RegistrationActivity_call_me_instead_available_in, minutesRemaining, secondsRemaining)
text = resources.getString(disabledText, minutesRemaining, secondsRemaining)
listener?.onRemaining(this, totalRemainingSeconds)
postDelayed({ updateCountDown() }, 250)
} else {
setCallEnabled()
setActionEnabled()
}
}

fun setListener(listener: Listener?) {
this.listener = listener
}

fun setTextResources(@StringRes enabled: Int, @StringRes disabled: Int) {
enabledText = enabled
disabledText = disabled
}

interface Listener {
fun onRemaining(view: ActionCountDownButton, secondsRemaining: Int)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import org.thoughtcrime.securesms.components.settings.app.changenumber.ChangeNum
import org.thoughtcrime.securesms.components.settings.app.changenumber.ChangeNumberUtil.getViewModel
import org.thoughtcrime.securesms.registration.VerifyAccountRepository
import org.thoughtcrime.securesms.util.LifecycleDisposable
import org.thoughtcrime.securesms.util.dualsim.MccMncProducer
import org.thoughtcrime.securesms.util.navigation.safeNavigate

private val TAG: String = Log.tag(ChangeNumberVerifyFragment::class.java)
Expand Down Expand Up @@ -48,17 +49,15 @@ class ChangeNumberVerifyFragment : LoggingFragment(R.layout.fragment_change_phon
}

private fun requestCode() {
val mccMncProducer = MccMncProducer(requireContext())
lifecycleDisposable += viewModel
.ensureDecryptionsDrained()
.onErrorComplete()
.andThen(viewModel.requestVerificationCode(VerifyAccountRepository.Mode.SMS_WITHOUT_LISTENER))
.andThen(viewModel.requestVerificationCode(VerifyAccountRepository.Mode.SMS_WITHOUT_LISTENER, mccMncProducer.mcc, mccMncProducer.mnc))
.observeOn(AndroidSchedulers.mainThread())
.subscribe { processor ->
if (processor.hasResult()) {
findNavController().safeNavigate(R.id.action_changePhoneNumberVerifyFragment_to_changeNumberEnterCodeFragment)
} else if (processor.localRateLimit()) {
Log.i(TAG, "Unable to request sms code due to local rate limit")
findNavController().safeNavigate(R.id.action_changePhoneNumberVerifyFragment_to_changeNumberEnterCodeFragment)
} else if (processor.captchaRequired()) {
Log.i(TAG, "Unable to request sms code due to captcha required")
findNavController().safeNavigate(R.id.action_changePhoneNumberVerifyFragment_to_captchaFragment, getCaptchaArguments())
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -83,14 +83,15 @@ public void onRun() throws IOException {
return;
}

int registrationId = SignalStore.account().getRegistrationId();
boolean fetchesMessages = !SignalStore.account().isFcmEnabled() || SignalStore.internalValues().isWebsocketModeForced();
byte[] unidentifiedAccessKey = UnidentifiedAccess.deriveAccessKeyFrom(ProfileKeyUtil.getSelfProfileKey());
boolean universalUnidentifiedAccess = TextSecurePreferences.isUniversalUnidentifiedAccess(context);
String registrationLockV1 = null;
String registrationLockV2 = null;
KbsValues kbsValues = SignalStore.kbsValues();
int pniRegistrationId = new RegistrationRepository(ApplicationDependencies.getApplication()).getPniRegistrationId();
int registrationId = SignalStore.account().getRegistrationId();
boolean fetchesMessages = !SignalStore.account().isFcmEnabled() || SignalStore.internalValues().isWebsocketModeForced();
byte[] unidentifiedAccessKey = UnidentifiedAccess.deriveAccessKeyFrom(ProfileKeyUtil.getSelfProfileKey());
boolean universalUnidentifiedAccess = TextSecurePreferences.isUniversalUnidentifiedAccess(context);
String registrationLockV1 = null;
String registrationLockV2 = null;
KbsValues kbsValues = SignalStore.kbsValues();
int pniRegistrationId = new RegistrationRepository(ApplicationDependencies.getApplication()).getPniRegistrationId();
String registrationRecoveryPassword = kbsValues.getRegistrationRecoveryPassword();

if (kbsValues.isV2RegistrationLockEnabled()) {
registrationLockV2 = kbsValues.getRegistrationLockToken();
Expand Down Expand Up @@ -121,7 +122,8 @@ public void onRun() throws IOException {
capabilities,
phoneNumberDiscoverable,
encryptedDeviceName,
pniRegistrationId);
pniRegistrationId,
registrationRecoveryPassword);

hasRefreshedThisAppCycle = true;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,15 @@ public synchronized boolean lastPinCreateFailed() {
}
}

public synchronized @Nullable String getRegistrationRecoveryPassword() {
MasterKey masterKey = getPinBackedMasterKey();
if (masterKey == null) {
return null;
} else {
return masterKey.deriveRegistrationRecoveryPassword();
}
}

public synchronized @Nullable String getPin() {
return getString(PIN, null);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import androidx.annotation.CheckResult;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;

import java.util.Collections;
import java.util.List;
Expand All @@ -11,6 +12,8 @@ public final class RegistrationValues extends SignalStoreValues {
private static final String REGISTRATION_COMPLETE = "registration.complete";
private static final String PIN_REQUIRED = "registration.pin_required";
private static final String HAS_UPLOADED_PROFILE = "registration.has_uploaded_profile";
private static final String SESSION_E164 = "registration.session_e164";
private static final String SESSION_ID = "registration.session_id";

RegistrationValues(@NonNull KeyValueStore store) {
super(store);
Expand Down Expand Up @@ -60,4 +63,22 @@ public void markHasUploadedProfile() {
public void clearHasUploadedProfile() {
putBoolean(HAS_UPLOADED_PROFILE, false);
}

public void setSessionId(String sessionId) {
putString(SESSION_ID, sessionId);
}

@Nullable
public String getSessionId() {
return getString(SESSION_ID, null);
}

public void setSessionE164(String sessionE164) {
putString(SESSION_E164, sessionE164);
}

@Nullable
public String getSessionE164() {
return getString(SESSION_E164, null);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import org.greenrobot.eventbus.Subscribe;
import org.greenrobot.eventbus.ThreadMode;
import org.signal.core.util.logging.Log;
import org.thoughtcrime.securesms.keyvalue.SignalStore;
import org.whispersystems.signalservice.api.SignalServiceAccountManager;

import java.io.IOException;
Expand All @@ -27,14 +28,14 @@ public final class PushChallengeRequest {
*
* @param accountManager Account manager to request the push from.
* @param fcmToken Optional FCM token. If not present will return absent.
* @param e164number Local number.
* @param sessionId Local number.
* @param timeoutMs Timeout in milliseconds
* @return Either returns a challenge, or absent.
*/
@WorkerThread
public static Optional<String> getPushChallengeBlocking(@NonNull SignalServiceAccountManager accountManager,
@NonNull String sessionId,
@NonNull Optional<String> fcmToken,
@NonNull String e164number,
long timeoutMs)
{
if (!fcmToken.isPresent()) {
Expand All @@ -44,8 +45,7 @@ public static Optional<String> getPushChallengeBlocking(@NonNull SignalServiceAc

long startTime = System.currentTimeMillis();
Log.i(TAG, "Requesting a push challenge");

Request request = new Request(accountManager, fcmToken.get(), e164number, timeoutMs);
Request request = new Request(accountManager, fcmToken.get(), sessionId, timeoutMs);

Optional<String> challenge = request.requestAndReceiveChallengeBlocking();

Expand All @@ -69,19 +69,19 @@ public static class Request {
private final AtomicReference<String> challenge;
private final SignalServiceAccountManager accountManager;
private final String fcmToken;
private final String e164number;
private final String sessionId;
private final long timeoutMs;

private Request(@NonNull SignalServiceAccountManager accountManager,
@NonNull String fcmToken,
@NonNull String e164number,
@NonNull String sessionId,
long timeoutMs)
{
this.latch = new CountDownLatch(1);
this.challenge = new AtomicReference<>();
this.accountManager = accountManager;
this.fcmToken = fcmToken;
this.e164number = e164number;
this.sessionId = sessionId;
this.timeoutMs = timeoutMs;
}

Expand All @@ -91,7 +91,7 @@ private Optional<String> requestAndReceiveChallengeBlocking() {

eventBus.register(this);
try {
accountManager.requestRegistrationPushChallenge(fcmToken, e164number);
accountManager.requestRegistrationPushChallenge(sessionId, fcmToken);

latch.await(timeoutMs, TimeUnit.MILLISECONDS);

Expand All @@ -117,5 +117,9 @@ static class PushChallengeEvent {
PushChallengeEvent(String challenge) {
this.challenge = challenge;
}

public String getChallenge() {
return challenge;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@ data class RegistrationData(
val registrationId: Int,
val profileKey: ProfileKey,
val fcmToken: String?,
val pniRegistrationId: Int
val pniRegistrationId: Int,
val recoveryPassword: String?
) {
val isFcm: Boolean = fcmToken != null
val isNotFcm: Boolean = fcmToken == null
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -209,4 +209,9 @@ private void saveOwnIdentityKey(@NonNull RecipientId selfId, @NonNull SignalServ

return null;
}

@Nullable
public String getRecoveryPassword() {
return SignalStore.kbsValues().getRegistrationRecoveryPassword();
}
}

0 comments on commit a47e390

Please sign in to comment.