Convert provisioning and certificate endpoints to WebSocket and finalize attachments.

This commit is contained in:
Cody Henthorne
2025-03-14 18:26:36 -04:00
parent aeec3a6f7e
commit c66819449d
27 changed files with 208 additions and 183 deletions

View File

@@ -206,8 +206,8 @@ class ChangeNumberRepository(
for (certificateType in certificateTypes) {
val certificate: ByteArray? = when (certificateType) {
CertificateType.ACI_AND_E164 -> accountManager.senderCertificate
CertificateType.ACI_ONLY -> accountManager.senderCertificateForPhoneNumberPrivacy
CertificateType.ACI_AND_E164 -> SignalNetwork.certificate.getSenderCertificate().successOrThrow()
CertificateType.ACI_ONLY -> SignalNetwork.certificate.getSenderCertificateForPhoneNumberPrivacy().successOrThrow()
else -> throw AssertionError()
}

View File

@@ -47,11 +47,13 @@ import org.whispersystems.signalservice.api.archive.ArchiveApi
import org.whispersystems.signalservice.api.attachment.AttachmentApi
import org.whispersystems.signalservice.api.calling.CallingApi
import org.whispersystems.signalservice.api.cds.CdsApi
import org.whispersystems.signalservice.api.certificate.CertificateApi
import org.whispersystems.signalservice.api.groupsv2.GroupsV2Operations
import org.whispersystems.signalservice.api.keys.KeysApi
import org.whispersystems.signalservice.api.link.LinkDeviceApi
import org.whispersystems.signalservice.api.message.MessageApi
import org.whispersystems.signalservice.api.payments.PaymentsApi
import org.whispersystems.signalservice.api.provisioning.ProvisioningApi
import org.whispersystems.signalservice.api.ratelimit.RateLimitChallengeApi
import org.whispersystems.signalservice.api.registration.RegistrationApi
import org.whispersystems.signalservice.api.services.DonationsService
@@ -334,6 +336,12 @@ object AppDependencies {
val messageApi: MessageApi
get() = networkModule.messageApi
val provisioningApi: ProvisioningApi
get() = networkModule.provisioningApi
val certificateApi: CertificateApi
get() = networkModule.certificateApi
@JvmStatic
val okHttpClient: OkHttpClient
get() = networkModule.okHttpClient
@@ -362,7 +370,7 @@ object AppDependencies {
fun providePushServiceSocket(signalServiceConfiguration: SignalServiceConfiguration, groupsV2Operations: GroupsV2Operations): PushServiceSocket
fun provideGroupsV2Operations(signalServiceConfiguration: SignalServiceConfiguration): GroupsV2Operations
fun provideSignalServiceAccountManager(authWebSocket: SignalWebSocket.AuthenticatedWebSocket, accountApi: AccountApi, pushServiceSocket: PushServiceSocket, groupsV2Operations: GroupsV2Operations): SignalServiceAccountManager
fun provideSignalServiceMessageSender(authWebSocket: SignalWebSocket.AuthenticatedWebSocket, protocolStore: SignalServiceDataStore, pushServiceSocket: PushServiceSocket, messageApi: MessageApi, keysApi: KeysApi): SignalServiceMessageSender
fun provideSignalServiceMessageSender(protocolStore: SignalServiceDataStore, pushServiceSocket: PushServiceSocket, attachmentApi: AttachmentApi, messageApi: MessageApi, keysApi: KeysApi): SignalServiceMessageSender
fun provideSignalServiceMessageReceiver(pushServiceSocket: PushServiceSocket): SignalServiceMessageReceiver
fun provideSignalServiceNetworkAccess(): SignalServiceNetworkAccess
fun provideRecipientCache(): LiveRecipientCache
@@ -411,5 +419,7 @@ object AppDependencies {
fun provideCdsApi(authWebSocket: SignalWebSocket.AuthenticatedWebSocket): CdsApi
fun provideRateLimitChallengeApi(authWebSocket: SignalWebSocket.AuthenticatedWebSocket): RateLimitChallengeApi
fun provideMessageApi(authWebSocket: SignalWebSocket.AuthenticatedWebSocket, unauthWebSocket: SignalWebSocket.UnauthenticatedWebSocket): MessageApi
fun provideProvisioningApi(authWebSocket: SignalWebSocket.AuthenticatedWebSocket): ProvisioningApi
fun provideCertificateApi(authWebSocket: SignalWebSocket.AuthenticatedWebSocket): CertificateApi
}
}

View File

@@ -86,12 +86,14 @@ import org.whispersystems.signalservice.api.archive.ArchiveApi;
import org.whispersystems.signalservice.api.attachment.AttachmentApi;
import org.whispersystems.signalservice.api.calling.CallingApi;
import org.whispersystems.signalservice.api.cds.CdsApi;
import org.whispersystems.signalservice.api.certificate.CertificateApi;
import org.whispersystems.signalservice.api.groupsv2.ClientZkOperations;
import org.whispersystems.signalservice.api.groupsv2.GroupsV2Operations;
import org.whispersystems.signalservice.api.keys.KeysApi;
import org.whispersystems.signalservice.api.link.LinkDeviceApi;
import org.whispersystems.signalservice.api.message.MessageApi;
import org.whispersystems.signalservice.api.payments.PaymentsApi;
import org.whispersystems.signalservice.api.provisioning.ProvisioningApi;
import org.whispersystems.signalservice.api.push.ServiceId.ACI;
import org.whispersystems.signalservice.api.push.ServiceId.PNI;
import org.whispersystems.signalservice.api.ratelimit.RateLimitChallengeApi;
@@ -151,15 +153,15 @@ public class ApplicationDependencyProvider implements AppDependencies.Provider {
}
@Override
public @NonNull SignalServiceMessageSender provideSignalServiceMessageSender(@NonNull SignalWebSocket.AuthenticatedWebSocket authWebSocket,
@NonNull SignalServiceDataStore protocolStore,
public @NonNull SignalServiceMessageSender provideSignalServiceMessageSender(@NonNull SignalServiceDataStore protocolStore,
@NonNull PushServiceSocket pushServiceSocket,
@NonNull AttachmentApi attachmentApi,
@NonNull MessageApi messageApi,
@NonNull KeysApi keysApi) {
return new SignalServiceMessageSender(pushServiceSocket,
protocolStore,
ReentrantSessionLock.INSTANCE,
authWebSocket,
attachmentApi,
messageApi,
keysApi,
Optional.of(new SecurityEventListener(context)),
@@ -535,6 +537,16 @@ public class ApplicationDependencyProvider implements AppDependencies.Provider {
return new MessageApi(authWebSocket, unauthWebSocket);
}
@Override
public @NonNull ProvisioningApi provideProvisioningApi(@NonNull SignalWebSocket.AuthenticatedWebSocket authWebSocket) {
return new ProvisioningApi(authWebSocket);
}
@Override
public @NonNull CertificateApi provideCertificateApi(@NonNull SignalWebSocket.AuthenticatedWebSocket authWebSocket) {
return new CertificateApi(authWebSocket);
}
@VisibleForTesting
static class DynamicCredentialsProvider implements CredentialsProvider {

View File

@@ -32,11 +32,13 @@ import org.whispersystems.signalservice.api.archive.ArchiveApi
import org.whispersystems.signalservice.api.attachment.AttachmentApi
import org.whispersystems.signalservice.api.calling.CallingApi
import org.whispersystems.signalservice.api.cds.CdsApi
import org.whispersystems.signalservice.api.certificate.CertificateApi
import org.whispersystems.signalservice.api.groupsv2.GroupsV2Operations
import org.whispersystems.signalservice.api.keys.KeysApi
import org.whispersystems.signalservice.api.link.LinkDeviceApi
import org.whispersystems.signalservice.api.message.MessageApi
import org.whispersystems.signalservice.api.payments.PaymentsApi
import org.whispersystems.signalservice.api.provisioning.ProvisioningApi
import org.whispersystems.signalservice.api.push.TrustStore
import org.whispersystems.signalservice.api.ratelimit.RateLimitChallengeApi
import org.whispersystems.signalservice.api.registration.RegistrationApi
@@ -82,7 +84,7 @@ class NetworkDependenciesModule(
val protocolStore: SignalServiceDataStoreImpl by _protocolStore
private val _signalServiceMessageSender = resettableLazy {
provider.provideSignalServiceMessageSender(authWebSocket, protocolStore, pushServiceSocket, messageApi, keysApi)
provider.provideSignalServiceMessageSender(protocolStore, pushServiceSocket, attachmentApi, messageApi, keysApi)
}
val signalServiceMessageSender: SignalServiceMessageSender by _signalServiceMessageSender
@@ -193,6 +195,14 @@ class NetworkDependenciesModule(
provider.provideMessageApi(authWebSocket, unauthWebSocket)
}
val provisioningApi: ProvisioningApi by lazy {
provider.provideProvisioningApi(authWebSocket)
}
val certificateApi: CertificateApi by lazy {
provider.provideCertificateApi(authWebSocket)
}
val okHttpClient: OkHttpClient by lazy {
OkHttpClient.Builder()
.addInterceptor(StandardUserAgentInterceptor())

View File

@@ -4,13 +4,13 @@ import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import org.signal.core.util.logging.Log;
import org.thoughtcrime.securesms.dependencies.AppDependencies;
import org.thoughtcrime.securesms.jobmanager.Job;
import org.thoughtcrime.securesms.jobmanager.impl.NetworkConstraint;
import org.thoughtcrime.securesms.keyvalue.CertificateType;
import org.thoughtcrime.securesms.keyvalue.SignalStore;
import org.whispersystems.signalservice.api.SignalServiceAccountManager;
import org.whispersystems.signalservice.api.push.exceptions.PushNetworkException;
import org.thoughtcrime.securesms.net.SignalNetwork;
import org.thoughtcrime.securesms.util.ExceptionHelper;
import org.whispersystems.signalservice.api.NetworkResultUtil;
import java.io.IOException;
import java.util.Collection;
@@ -56,7 +56,6 @@ public final class RotateCertificateJob extends BaseJob {
}
synchronized (RotateCertificateJob.class) {
SignalServiceAccountManager accountManager = AppDependencies.getSignalServiceAccountManager();
Collection<CertificateType> certificateTypes = SignalStore.phoneNumberPrivacy()
.getAllCertificateTypes();
@@ -66,8 +65,8 @@ public final class RotateCertificateJob extends BaseJob {
byte[] certificate;
switch (certificateType) {
case ACI_AND_E164: certificate = accountManager.getSenderCertificate(); break;
case ACI_ONLY : certificate = accountManager.getSenderCertificateForPhoneNumberPrivacy(); break;
case ACI_AND_E164: certificate = NetworkResultUtil.toBasicLegacy(SignalNetwork.certificate().getSenderCertificate()); break;
case ACI_ONLY : certificate = NetworkResultUtil.toBasicLegacy(SignalNetwork.certificate().getSenderCertificateForPhoneNumberPrivacy()); break;
default : throw new AssertionError();
}
@@ -80,7 +79,7 @@ public final class RotateCertificateJob extends BaseJob {
@Override
public boolean onShouldRetry(@NonNull Exception e) {
return e instanceof PushNetworkException;
return ExceptionHelper.isRetryableIOException(e);
}
@Override

View File

@@ -11,10 +11,12 @@ import org.whispersystems.signalservice.api.archive.ArchiveApi
import org.whispersystems.signalservice.api.attachment.AttachmentApi
import org.whispersystems.signalservice.api.calling.CallingApi
import org.whispersystems.signalservice.api.cds.CdsApi
import org.whispersystems.signalservice.api.certificate.CertificateApi
import org.whispersystems.signalservice.api.keys.KeysApi
import org.whispersystems.signalservice.api.link.LinkDeviceApi
import org.whispersystems.signalservice.api.message.MessageApi
import org.whispersystems.signalservice.api.payments.PaymentsApi
import org.whispersystems.signalservice.api.provisioning.ProvisioningApi
import org.whispersystems.signalservice.api.ratelimit.RateLimitChallengeApi
import org.whispersystems.signalservice.api.storage.StorageServiceApi
import org.whispersystems.signalservice.api.username.UsernameApi
@@ -42,6 +44,11 @@ object SignalNetwork {
val cdsApi: CdsApi
get() = AppDependencies.cdsApi
@JvmStatic
@get:JvmName("certificate")
val certificate: CertificateApi
get() = AppDependencies.certificateApi
@JvmStatic
@get:JvmName("keys")
val keys: KeysApi
@@ -60,6 +67,9 @@ object SignalNetwork {
val payments: PaymentsApi
get() = AppDependencies.paymentsApi
val provisioning: ProvisioningApi
get() = AppDependencies.provisioningApi
@JvmStatic
@get:JvmName("rateLimitChallenge")
val rateLimitChallenge: RateLimitChallengeApi

View File

@@ -19,8 +19,9 @@ import org.signal.registration.proto.RegistrationProvisionMessage
import org.thoughtcrime.securesms.backup.v2.MessageBackupTier
import org.thoughtcrime.securesms.dependencies.AppDependencies
import org.thoughtcrime.securesms.keyvalue.SignalStore
import org.thoughtcrime.securesms.net.SignalNetwork
import org.whispersystems.signalservice.api.NetworkResult
import org.whispersystems.signalservice.api.registration.RestoreMethod
import org.whispersystems.signalservice.api.provisioning.RestoreMethod
import java.io.IOException
import kotlin.coroutines.coroutineContext
import kotlin.time.Duration.Companion.seconds
@@ -71,9 +72,8 @@ object QuickRegistrationRepository {
return TransferAccountResult.FAILED
}
AppDependencies
.signalServiceAccountManager
.registrationApi
SignalNetwork
.provisioning
.sendReRegisterDeviceProvisioningMessage(
ephemeralId,
publicKey,
@@ -147,8 +147,7 @@ object QuickRegistrationRepository {
Log.d(TAG, "Waiting for restore method with token: ***${restoreMethodToken.takeLast(4)}")
while (retries-- > 0 && result !is NetworkResult.Success && coroutineContext.isActive) {
Log.d(TAG, "Waiting, remaining tries: $retries")
val api = AppDependencies.registrationApi
result = api.waitForRestoreMethod(restoreMethodToken)
result = SignalNetwork.provisioning.waitForRestoreMethod(restoreMethodToken)
Log.d(TAG, "Result: $result")
}

View File

@@ -69,7 +69,7 @@ import org.thoughtcrime.securesms.util.DynamicNoActionBarTheme
import org.thoughtcrime.securesms.util.DynamicTheme
import org.thoughtcrime.securesms.util.SpanUtil
import org.thoughtcrime.securesms.util.viewModel
import org.whispersystems.signalservice.api.registration.RestoreMethod
import org.whispersystems.signalservice.api.provisioning.RestoreMethod
/**
* Launched after scanning QR code from new device to start the transfer/reregistration process from

View File

@@ -14,7 +14,7 @@ import kotlinx.coroutines.flow.update
import kotlinx.coroutines.launch
import org.thoughtcrime.securesms.keyvalue.SignalStore
import org.thoughtcrime.securesms.registrationv3.data.QuickRegistrationRepository
import org.whispersystems.signalservice.api.registration.RestoreMethod
import org.whispersystems.signalservice.api.provisioning.RestoreMethod
import java.util.UUID
class TransferAccountViewModel(reRegisterUri: String) : ViewModel() {

View File

@@ -32,7 +32,7 @@ import org.thoughtcrime.securesms.keyvalue.Completed
import org.thoughtcrime.securesms.keyvalue.SignalStore
import org.thoughtcrime.securesms.keyvalue.Skipped
import org.thoughtcrime.securesms.registrationv3.data.QuickRegistrationRepository
import org.whispersystems.signalservice.api.registration.RestoreMethod
import org.whispersystems.signalservice.api.provisioning.RestoreMethod
class RemoteRestoreViewModel(isOnlyRestoreOption: Boolean) : ViewModel() {

View File

@@ -23,7 +23,7 @@ import org.thoughtcrime.securesms.crypto.IdentityKeyUtil
import org.thoughtcrime.securesms.dependencies.AppDependencies
import org.thoughtcrime.securesms.keyvalue.SignalStore
import org.thoughtcrime.securesms.registration.data.network.RegisterAccountResult
import org.whispersystems.signalservice.api.registration.ProvisioningSocket
import org.whispersystems.signalservice.api.provisioning.ProvisioningSocket
import org.whispersystems.signalservice.internal.crypto.SecondaryProvisioningCipher
import java.io.Closeable

View File

@@ -25,7 +25,7 @@ import org.thoughtcrime.securesms.registrationv3.data.QuickRegistrationRepositor
import org.thoughtcrime.securesms.registrationv3.ui.restore.RestoreMethod
import org.thoughtcrime.securesms.registrationv3.ui.restore.StorageServiceRestore
import org.thoughtcrime.securesms.restore.transferorrestore.BackupRestorationType
import org.whispersystems.signalservice.api.registration.RestoreMethod as ApiRestoreMethod
import org.whispersystems.signalservice.api.provisioning.RestoreMethod as ApiRestoreMethod
/**
* Shared view model for the restore flow.

View File

@@ -22,7 +22,7 @@ import org.thoughtcrime.securesms.registrationv3.ui.restore.RestoreMethod
import org.thoughtcrime.securesms.registrationv3.ui.restore.SelectRestoreMethodScreen
import org.thoughtcrime.securesms.restore.RestoreViewModel
import org.thoughtcrime.securesms.util.navigation.safeNavigate
import org.whispersystems.signalservice.api.registration.RestoreMethod as ApiRestoreMethod
import org.whispersystems.signalservice.api.provisioning.RestoreMethod as ApiRestoreMethod
/**
* Provide options to select restore/transfer operation during quick/post registration.