diff --git a/app/src/main/java/org/thoughtcrime/securesms/dependencies/AppDependencies.kt b/app/src/main/java/org/thoughtcrime/securesms/dependencies/AppDependencies.kt index f525fed2d5..cecc9bc490 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/dependencies/AppDependencies.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/dependencies/AppDependencies.kt @@ -45,11 +45,12 @@ import org.whispersystems.signalservice.api.SignalServiceMessageSender import org.whispersystems.signalservice.api.account.AccountApi 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.groupsv2.GroupsV2Operations import org.whispersystems.signalservice.api.keys.KeysApi import org.whispersystems.signalservice.api.link.LinkDeviceApi +import org.whispersystems.signalservice.api.payments.PaymentsApi import org.whispersystems.signalservice.api.registration.RegistrationApi -import org.whispersystems.signalservice.api.services.CallLinksService import org.whispersystems.signalservice.api.services.DonationsService import org.whispersystems.signalservice.api.services.ProfileService import org.whispersystems.signalservice.api.storage.StorageServiceApi @@ -278,10 +279,6 @@ object AppDependencies { val payments: Payments get() = networkModule.payments - @JvmStatic - val callLinksService: CallLinksService - get() = networkModule.callLinksService - @JvmStatic val profileService: ProfileService get() = networkModule.profileService @@ -319,6 +316,12 @@ object AppDependencies { val usernameApi: UsernameApi get() = networkModule.usernameApi + val callingApi: CallingApi + get() = networkModule.callingApi + + val paymentsApi: PaymentsApi + get() = networkModule.paymentsApi + @JvmStatic val okHttpClient: OkHttpClient get() = networkModule.okHttpClient @@ -365,7 +368,7 @@ object AppDependencies { fun provideTypingStatusRepository(): TypingStatusRepository fun provideTypingStatusSender(): TypingStatusSender fun provideDatabaseObserver(): DatabaseObserver - fun providePayments(signalServiceAccountManager: SignalServiceAccountManager): Payments + fun providePayments(paymentsApi: PaymentsApi): Payments fun provideShakeToReport(): ShakeToReport fun provideSignalCallManager(): SignalCallManager fun providePendingRetryReceiptManager(): PendingRetryReceiptManager @@ -375,7 +378,6 @@ object AppDependencies { fun provideExoPlayerPool(): SimpleExoPlayerPool fun provideAndroidCallAudioManager(): AudioManagerCompat fun provideDonationsService(pushServiceSocket: PushServiceSocket): DonationsService - fun provideCallLinksService(pushServiceSocket: PushServiceSocket): CallLinksService fun provideProfileService(profileOperations: ClientZkProfileOperations, signalServiceMessageReceiver: SignalServiceMessageReceiver, authWebSocket: SignalWebSocket.AuthenticatedWebSocket, unauthWebSocket: SignalWebSocket.UnauthenticatedWebSocket): ProfileService fun provideDeadlockDetector(): DeadlockDetector fun provideClientZkReceiptOperations(signalServiceConfiguration: SignalServiceConfiguration): ClientZkReceiptOperations @@ -392,5 +394,7 @@ object AppDependencies { fun provideUnauthWebSocket(signalServiceConfigurationSupplier: Supplier, libSignalNetworkSupplier: Supplier): SignalWebSocket.UnauthenticatedWebSocket fun provideAccountApi(authWebSocket: SignalWebSocket.AuthenticatedWebSocket): AccountApi fun provideUsernameApi(unauthWebSocket: SignalWebSocket.UnauthenticatedWebSocket): UsernameApi + fun provideCallingApi(authWebSocket: SignalWebSocket.AuthenticatedWebSocket, pushServiceSocket: PushServiceSocket): CallingApi + fun providePaymentsApi(authWebSocket: SignalWebSocket.AuthenticatedWebSocket): PaymentsApi } } diff --git a/app/src/main/java/org/thoughtcrime/securesms/dependencies/ApplicationDependencyProvider.java b/app/src/main/java/org/thoughtcrime/securesms/dependencies/ApplicationDependencyProvider.java index baad843873..18cef51232 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/dependencies/ApplicationDependencyProvider.java +++ b/app/src/main/java/org/thoughtcrime/securesms/dependencies/ApplicationDependencyProvider.java @@ -83,14 +83,15 @@ import org.whispersystems.signalservice.api.SignalServiceMessageSender; import org.whispersystems.signalservice.api.account.AccountApi; 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.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.payments.PaymentsApi; import org.whispersystems.signalservice.api.push.ServiceId.ACI; import org.whispersystems.signalservice.api.push.ServiceId.PNI; import org.whispersystems.signalservice.api.registration.RegistrationApi; -import org.whispersystems.signalservice.api.services.CallLinksService; import org.whispersystems.signalservice.api.services.DonationsService; import org.whispersystems.signalservice.api.services.ProfileService; import org.whispersystems.signalservice.api.storage.StorageServiceApi; @@ -267,11 +268,11 @@ public class ApplicationDependencyProvider implements AppDependencies.Provider { @SuppressWarnings("ConstantConditions") @Override - public @NonNull Payments providePayments(@NonNull SignalServiceAccountManager signalServiceAccountManager) { + public @NonNull Payments providePayments(@NonNull PaymentsApi paymentsApi) { MobileCoinConfig network; - if (BuildConfig.MOBILE_COIN_ENVIRONMENT.equals("mainnet")) network = MobileCoinConfig.getMainNet(signalServiceAccountManager); - else if (BuildConfig.MOBILE_COIN_ENVIRONMENT.equals("testnet")) network = MobileCoinConfig.getTestNet(signalServiceAccountManager); + if (BuildConfig.MOBILE_COIN_ENVIRONMENT.equals("mainnet")) network = MobileCoinConfig.getMainNet(paymentsApi); + else if (BuildConfig.MOBILE_COIN_ENVIRONMENT.equals("testnet")) network = MobileCoinConfig.getTestNet(paymentsApi); else throw new AssertionError("Unknown network " + BuildConfig.MOBILE_COIN_ENVIRONMENT); return new Payments(network); @@ -388,11 +389,6 @@ public class ApplicationDependencyProvider implements AppDependencies.Provider { return new DonationsService(pushServiceSocket); } - @Override - public @NonNull CallLinksService provideCallLinksService(@NonNull PushServiceSocket pushServiceSocket) { - return new CallLinksService(pushServiceSocket); - } - @Override public @NonNull ProfileService provideProfileService(@NonNull ClientZkProfileOperations clientZkProfileOperations, @NonNull SignalServiceMessageReceiver receiver, @@ -504,6 +500,16 @@ public class ApplicationDependencyProvider implements AppDependencies.Provider { return new UsernameApi(unauthWebSocket); } + @Override + public @NonNull CallingApi provideCallingApi(@NonNull SignalWebSocket.AuthenticatedWebSocket authWebSocket, @NonNull PushServiceSocket pushServiceSocket) { + return new CallingApi(authWebSocket, pushServiceSocket); + } + + @Override + public @NonNull PaymentsApi providePaymentsApi(@NonNull SignalWebSocket.AuthenticatedWebSocket authWebSocket) { + return new PaymentsApi(authWebSocket); + } + @VisibleForTesting static class DynamicCredentialsProvider implements CredentialsProvider { diff --git a/app/src/main/java/org/thoughtcrime/securesms/dependencies/NetworkDependenciesModule.kt b/app/src/main/java/org/thoughtcrime/securesms/dependencies/NetworkDependenciesModule.kt index 8dd4c6bcec..3fdcf4de15 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/dependencies/NetworkDependenciesModule.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/dependencies/NetworkDependenciesModule.kt @@ -29,12 +29,13 @@ import org.whispersystems.signalservice.api.SignalServiceMessageSender import org.whispersystems.signalservice.api.account.AccountApi 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.groupsv2.GroupsV2Operations import org.whispersystems.signalservice.api.keys.KeysApi import org.whispersystems.signalservice.api.link.LinkDeviceApi +import org.whispersystems.signalservice.api.payments.PaymentsApi import org.whispersystems.signalservice.api.push.TrustStore import org.whispersystems.signalservice.api.registration.RegistrationApi -import org.whispersystems.signalservice.api.services.CallLinksService import org.whispersystems.signalservice.api.services.DonationsService import org.whispersystems.signalservice.api.services.ProfileService import org.whispersystems.signalservice.api.storage.StorageServiceApi @@ -120,11 +121,7 @@ class NetworkDependenciesModule( } val payments: Payments by lazy { - provider.providePayments(signalServiceAccountManager) - } - - val callLinksService: CallLinksService by lazy { - provider.provideCallLinksService(pushServiceSocket) + provider.providePayments(paymentsApi) } val profileService: ProfileService by lazy { @@ -167,6 +164,14 @@ class NetworkDependenciesModule( provider.provideUsernameApi(unauthWebSocket) } + val callingApi: CallingApi by lazy { + provider.provideCallingApi(authWebSocket, pushServiceSocket) + } + + val paymentsApi: PaymentsApi by lazy { + provider.providePaymentsApi(authWebSocket) + } + val okHttpClient: OkHttpClient by lazy { OkHttpClient.Builder() .addInterceptor(StandardUserAgentInterceptor()) diff --git a/app/src/main/java/org/thoughtcrime/securesms/net/SignalNetwork.kt b/app/src/main/java/org/thoughtcrime/securesms/net/SignalNetwork.kt index 5f828c3773..acf3c4302c 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/net/SignalNetwork.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/net/SignalNetwork.kt @@ -9,8 +9,10 @@ import org.thoughtcrime.securesms.dependencies.AppDependencies import org.whispersystems.signalservice.api.account.AccountApi 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.keys.KeysApi import org.whispersystems.signalservice.api.link.LinkDeviceApi +import org.whispersystems.signalservice.api.payments.PaymentsApi import org.whispersystems.signalservice.api.storage.StorageServiceApi import org.whispersystems.signalservice.api.username.UsernameApi @@ -29,12 +31,22 @@ object SignalNetwork { val attachments: AttachmentApi get() = AppDependencies.attachmentApi + @JvmStatic + @get:JvmName("calling") + val calling: CallingApi + get() = AppDependencies.callingApi + val keys: KeysApi get() = AppDependencies.keysApi val linkDevice: LinkDeviceApi get() = AppDependencies.linkDeviceApi + @JvmStatic + @get:JvmName("payments") + val payments: PaymentsApi + get() = AppDependencies.paymentsApi + val storageService: StorageServiceApi get() = AppDependencies.storageServiceApi diff --git a/app/src/main/java/org/thoughtcrime/securesms/payments/MobileCoinConfig.java b/app/src/main/java/org/thoughtcrime/securesms/payments/MobileCoinConfig.java index 00171b0ec6..46117527e2 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/payments/MobileCoinConfig.java +++ b/app/src/main/java/org/thoughtcrime/securesms/payments/MobileCoinConfig.java @@ -9,6 +9,7 @@ import com.mobilecoin.lib.ClientConfig; import org.thoughtcrime.securesms.dependencies.AppDependencies; import org.whispersystems.signalservice.api.SignalServiceAccountManager; +import org.whispersystems.signalservice.api.payments.PaymentsApi; import org.whispersystems.signalservice.internal.push.AuthCredentials; import java.io.IOException; @@ -36,12 +37,12 @@ public abstract class MobileCoinConfig { abstract @NonNull ClientConfig getConfig(); - public static MobileCoinConfig getTestNet(SignalServiceAccountManager signalServiceAccountManager) { - return new MobileCoinTestNetConfig(signalServiceAccountManager); + public static MobileCoinConfig getTestNet(PaymentsApi paymentsApi) { + return new MobileCoinTestNetConfig(paymentsApi); } - public static MobileCoinConfig getMainNet(SignalServiceAccountManager signalServiceAccountManager) { - return new MobileCoinMainNetConfig(signalServiceAccountManager); + public static MobileCoinConfig getMainNet(PaymentsApi paymentsApi) { + return new MobileCoinMainNetConfig(paymentsApi); } protected static Set getTrustRoots(@RawRes int pemResource) { diff --git a/app/src/main/java/org/thoughtcrime/securesms/payments/MobileCoinMainNetConfig.java b/app/src/main/java/org/thoughtcrime/securesms/payments/MobileCoinMainNetConfig.java index 6c801900d1..b8822e5b2c 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/payments/MobileCoinMainNetConfig.java +++ b/app/src/main/java/org/thoughtcrime/securesms/payments/MobileCoinMainNetConfig.java @@ -10,7 +10,9 @@ import com.mobilecoin.lib.exceptions.AttestationException; import org.thoughtcrime.securesms.R; import org.signal.core.util.Base64; +import org.whispersystems.signalservice.api.NetworkResultUtil; import org.whispersystems.signalservice.api.SignalServiceAccountManager; +import org.whispersystems.signalservice.api.payments.PaymentsApi; import org.whispersystems.signalservice.internal.push.AuthCredentials; import java.io.IOException; @@ -20,11 +22,10 @@ import java.util.List; import java.util.Set; final class MobileCoinMainNetConfig extends MobileCoinConfig { + private final PaymentsApi paymentsApi; - private final SignalServiceAccountManager signalServiceAccountManager; - - public MobileCoinMainNetConfig(@NonNull SignalServiceAccountManager signalServiceAccountManager) { - this.signalServiceAccountManager = signalServiceAccountManager; + public MobileCoinMainNetConfig(@NonNull PaymentsApi paymentsApi) { + this.paymentsApi = paymentsApi; } @Override @@ -63,7 +64,7 @@ final class MobileCoinMainNetConfig extends MobileCoinConfig { @Override @NonNull AuthCredentials getAuth() throws IOException { - return signalServiceAccountManager.getPaymentsAuthorization(); + return NetworkResultUtil.toBasicLegacy(paymentsApi.getAuthorization()); } @Override diff --git a/app/src/main/java/org/thoughtcrime/securesms/payments/MobileCoinTestNetConfig.java b/app/src/main/java/org/thoughtcrime/securesms/payments/MobileCoinTestNetConfig.java index d60dc43361..a93551c226 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/payments/MobileCoinTestNetConfig.java +++ b/app/src/main/java/org/thoughtcrime/securesms/payments/MobileCoinTestNetConfig.java @@ -7,9 +7,10 @@ import androidx.annotation.NonNull; import com.mobilecoin.lib.ClientConfig; import com.mobilecoin.lib.exceptions.AttestationException; -import org.thoughtcrime.securesms.R; import org.signal.core.util.Base64; -import org.whispersystems.signalservice.api.SignalServiceAccountManager; +import org.thoughtcrime.securesms.R; +import org.whispersystems.signalservice.api.NetworkResultUtil; +import org.whispersystems.signalservice.api.payments.PaymentsApi; import org.whispersystems.signalservice.internal.push.AuthCredentials; import java.io.IOException; @@ -19,11 +20,10 @@ import java.util.List; import java.util.Set; final class MobileCoinTestNetConfig extends MobileCoinConfig { + private final PaymentsApi paymentsApi; - private final SignalServiceAccountManager signalServiceAccountManager; - - public MobileCoinTestNetConfig(@NonNull SignalServiceAccountManager signalServiceAccountManager) { - this.signalServiceAccountManager = signalServiceAccountManager; + public MobileCoinTestNetConfig(@NonNull PaymentsApi paymentsApi) { + this.paymentsApi = paymentsApi; } @Override @@ -51,7 +51,7 @@ final class MobileCoinTestNetConfig extends MobileCoinConfig { @Override @NonNull AuthCredentials getAuth() throws IOException { - return signalServiceAccountManager.getPaymentsAuthorization(); + return NetworkResultUtil.toBasicLegacy(paymentsApi.getAuthorization()); } @Override diff --git a/app/src/main/java/org/thoughtcrime/securesms/payments/Payments.java b/app/src/main/java/org/thoughtcrime/securesms/payments/Payments.java index 6a10a4429d..ae4d4345cc 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/payments/Payments.java +++ b/app/src/main/java/org/thoughtcrime/securesms/payments/Payments.java @@ -4,9 +4,10 @@ import androidx.annotation.NonNull; import androidx.annotation.WorkerThread; import org.signal.core.util.logging.Log; -import org.thoughtcrime.securesms.dependencies.AppDependencies; import org.thoughtcrime.securesms.keyvalue.SignalStore; +import org.thoughtcrime.securesms.net.SignalNetwork; import org.thoughtcrime.securesms.payments.currency.CurrencyExchange; +import org.whispersystems.signalservice.api.NetworkResultUtil; import org.whispersystems.signalservice.api.payments.CurrencyConversion; import org.whispersystems.signalservice.api.payments.CurrencyConversions; @@ -46,7 +47,7 @@ public final class Payments { public synchronized @NonNull CurrencyExchange getCurrencyExchange(boolean refreshIfAble) throws IOException { if (currencyConversions == null || shouldRefresh(refreshIfAble, currencyConversions.getTimestamp())) { Log.i(TAG, "Currency conversion data is unavailable or a refresh was requested and available"); - CurrencyConversions newCurrencyConversions = AppDependencies.getSignalServiceAccountManager().getCurrencyConversions(); + CurrencyConversions newCurrencyConversions = NetworkResultUtil.toBasicLegacy(SignalNetwork.payments().getCurrencyConversions()); if (currencyConversions == null || (newCurrencyConversions != null && newCurrencyConversions.getTimestamp() > currencyConversions.getTimestamp())) { currencyConversions = newCurrencyConversions; } diff --git a/app/src/main/java/org/thoughtcrime/securesms/service/webrtc/SignalCallManager.java b/app/src/main/java/org/thoughtcrime/securesms/service/webrtc/SignalCallManager.java index 063f491f95..5e7d790e2f 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/service/webrtc/SignalCallManager.java +++ b/app/src/main/java/org/thoughtcrime/securesms/service/webrtc/SignalCallManager.java @@ -53,6 +53,7 @@ import org.thoughtcrime.securesms.jobs.GroupCallUpdateSendJob; import org.thoughtcrime.securesms.jobs.RetrieveProfileJob; import org.thoughtcrime.securesms.keyvalue.SignalStore; import org.thoughtcrime.securesms.messages.GroupSendUtil; +import org.thoughtcrime.securesms.net.SignalNetwork; import org.thoughtcrime.securesms.notifications.v2.ConversationId; import org.thoughtcrime.securesms.ratelimit.ProofRequiredExceptionHandler; import org.thoughtcrime.securesms.recipients.Recipient; @@ -74,6 +75,8 @@ import org.thoughtcrime.securesms.webrtc.CallNotificationBuilder; import org.thoughtcrime.securesms.webrtc.audio.SignalAudioManager; import org.thoughtcrime.securesms.webrtc.locks.LockManager; import org.webrtc.PeerConnection; +import org.whispersystems.signalservice.api.NetworkResult; +import org.whispersystems.signalservice.api.NetworkResultUtil; import org.whispersystems.signalservice.api.crypto.SealedSenderAccess; import org.whispersystems.signalservice.api.crypto.UntrustedIdentityException; import org.whispersystems.signalservice.api.messages.SendMessageResult; @@ -876,9 +879,10 @@ public final class SignalCallManager implements CallManager.Observer, GroupCall. headerPairs = Collections.emptyList(); } - CallingResponse response = AppDependencies.getSignalServiceMessageSender() - .makeCallingRequest(requestId, url, httpMethod.name(), headerPairs, body); + NetworkResult result = SignalNetwork.calling() + .makeCallingRequest(requestId, url, httpMethod.name(), headerPairs, body); + CallingResponse response = ((NetworkResult.Success) result).getResult(); try { if (response instanceof CallingResponse.Success) { CallingResponse.Success success = (CallingResponse.Success) response; @@ -1029,7 +1033,7 @@ public final class SignalCallManager implements CallManager.Observer, GroupCall. public void retrieveTurnServers(@NonNull RemotePeer remotePeer) { networkExecutor.execute(() -> { try { - List turnServerInfos = AppDependencies.getSignalServiceAccountManager().getTurnServerInfo(); + List turnServerInfos = NetworkResultUtil.toBasicLegacy(SignalNetwork.calling().getTurnServerInfo()); List iceServers = mapToIceServers(turnServerInfos); process((s, p) -> { RemotePeer activePeer = s.getCallInfoState().getActivePeer(); diff --git a/app/src/main/java/org/thoughtcrime/securesms/service/webrtc/links/SignalCallLinkManager.kt b/app/src/main/java/org/thoughtcrime/securesms/service/webrtc/links/SignalCallLinkManager.kt index 50b94539be..2f15e387d9 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/service/webrtc/links/SignalCallLinkManager.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/service/webrtc/links/SignalCallLinkManager.kt @@ -6,9 +6,7 @@ package org.thoughtcrime.securesms.service.webrtc.links import io.reactivex.rxjava3.core.Single -import org.signal.core.util.isAbsent import org.signal.core.util.logging.Log -import org.signal.core.util.or import org.signal.libsignal.zkgroup.GenericServerPublicParams import org.signal.libsignal.zkgroup.calllinks.CallLinkAuthCredentialPresentation import org.signal.libsignal.zkgroup.calllinks.CallLinkSecretParams @@ -22,8 +20,9 @@ import org.signal.ringrtc.CallLinkState.Restrictions import org.signal.ringrtc.CallManager import org.thoughtcrime.securesms.dependencies.AppDependencies import org.thoughtcrime.securesms.keyvalue.SignalStore +import org.thoughtcrime.securesms.net.SignalNetwork import org.thoughtcrime.securesms.recipients.Recipient -import org.whispersystems.signalservice.internal.ServiceResponse +import org.whispersystems.signalservice.api.NetworkResult import java.io.IOException /** @@ -51,27 +50,28 @@ class SignalCallLinkManager( Log.d(TAG, "Requesting call link credential response.") - val serviceResponse: ServiceResponse = AppDependencies.callLinksService.getCreateCallLinkAuthCredential(request) - if (serviceResponse.result.isAbsent()) { - throw IOException("Failed to create credential response", serviceResponse.applicationError.or(serviceResponse.executionError).get()) + when (val result: NetworkResult = SignalNetwork.calling.createCallLinkCredential(request)) { + is NetworkResult.Success -> { + Log.d(TAG, "Requesting call link credential.") + + val createCallLinkCredential: CreateCallLinkCredential = requestContext.receiveResponse( + result.result, + userAci.libSignalAci, + genericServerPublicParams + ) + + Log.d(TAG, "Requesting and returning call link presentation.") + + return createCallLinkCredential.present( + roomId, + userAci.libSignalAci, + genericServerPublicParams, + CallLinkSecretParams.deriveFromRootKey(linkRootKey) + ) + } + + else -> throw IOException("Failed to create credential response", result.getCause()) } - - Log.d(TAG, "Requesting call link credential.") - - val createCallLinkCredential: CreateCallLinkCredential = requestContext.receiveResponse( - serviceResponse.result.get(), - userAci.libSignalAci, - genericServerPublicParams - ) - - Log.d(TAG, "Requesting and returning call link presentation.") - - return createCallLinkCredential.present( - roomId, - userAci.libSignalAci, - genericServerPublicParams, - CallLinkSecretParams.deriveFromRootKey(linkRootKey) - ) } private fun requestCallLinkAuthCredentialPresentation( diff --git a/app/src/test/java/org/thoughtcrime/securesms/dependencies/MockApplicationDependencyProvider.kt b/app/src/test/java/org/thoughtcrime/securesms/dependencies/MockApplicationDependencyProvider.kt index 9463cb3fac..75f920a4fc 100644 --- a/app/src/test/java/org/thoughtcrime/securesms/dependencies/MockApplicationDependencyProvider.kt +++ b/app/src/test/java/org/thoughtcrime/securesms/dependencies/MockApplicationDependencyProvider.kt @@ -39,11 +39,12 @@ import org.whispersystems.signalservice.api.SignalServiceMessageSender import org.whispersystems.signalservice.api.account.AccountApi 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.groupsv2.GroupsV2Operations import org.whispersystems.signalservice.api.keys.KeysApi import org.whispersystems.signalservice.api.link.LinkDeviceApi +import org.whispersystems.signalservice.api.payments.PaymentsApi import org.whispersystems.signalservice.api.registration.RegistrationApi -import org.whispersystems.signalservice.api.services.CallLinksService import org.whispersystems.signalservice.api.services.DonationsService import org.whispersystems.signalservice.api.services.ProfileService import org.whispersystems.signalservice.api.storage.StorageServiceApi @@ -143,7 +144,7 @@ class MockApplicationDependencyProvider : AppDependencies.Provider { return mockk(relaxed = true) } - override fun providePayments(signalServiceAccountManager: SignalServiceAccountManager): Payments { + override fun providePayments(paymentsApi: PaymentsApi): Payments { return mockk(relaxed = true) } @@ -183,10 +184,6 @@ class MockApplicationDependencyProvider : AppDependencies.Provider { return mockk(relaxed = true) } - override fun provideCallLinksService(pushServiceSocket: PushServiceSocket): CallLinksService { - return mockk(relaxed = true) - } - override fun provideProfileService( profileOperations: ClientZkProfileOperations, signalServiceMessageReceiver: SignalServiceMessageReceiver, @@ -255,4 +252,12 @@ class MockApplicationDependencyProvider : AppDependencies.Provider { override fun provideUsernameApi(unauthWebSocket: SignalWebSocket.UnauthenticatedWebSocket): UsernameApi { return mockk(relaxed = true) } + + override fun provideCallingApi(authWebSocket: SignalWebSocket.AuthenticatedWebSocket, pushServiceSocket: PushServiceSocket): CallingApi { + return mockk(relaxed = true) + } + + override fun providePaymentsApi(authWebSocket: SignalWebSocket.AuthenticatedWebSocket): PaymentsApi { + return mockk(relaxed = true) + } } diff --git a/libsignal-service/src/main/java/org/whispersystems/signalservice/api/SignalServiceAccountManager.java b/libsignal-service/src/main/java/org/whispersystems/signalservice/api/SignalServiceAccountManager.java index 7853644b53..99fd6dbf1e 100644 --- a/libsignal-service/src/main/java/org/whispersystems/signalservice/api/SignalServiceAccountManager.java +++ b/libsignal-service/src/main/java/org/whispersystems/signalservice/api/SignalServiceAccountManager.java @@ -230,19 +230,10 @@ public class SignalServiceAccountManager { return new RemoteConfigResult(out, response.getServerEpochTime()); } - public List getTurnServerInfo() throws IOException { - List relays = this.pushServiceSocket.getCallingRelays().getRelays(); - return relays != null ? relays : Collections.emptyList(); - } - public void checkNetworkConnection() throws IOException { this.pushServiceSocket.pingStorageService(); } - public CurrencyConversions getCurrencyConversions() throws IOException { - return this.pushServiceSocket.getCurrencyConversions(); - } - public void reportSpam(ServiceId serviceId, String serverGuid, String reportingToken) throws IOException { this.pushServiceSocket.reportSpam(serviceId, serverGuid, reportingToken); } @@ -333,9 +324,4 @@ public class SignalServiceAccountManager { public RegistrationApi getRegistrationApi() { return new RegistrationApi(pushServiceSocket); } - - public AuthCredentials getPaymentsAuthorization() throws IOException { - return pushServiceSocket.getPaymentsAuthorization(); - } - } diff --git a/libsignal-service/src/main/java/org/whispersystems/signalservice/api/SignalServiceMessageSender.java b/libsignal-service/src/main/java/org/whispersystems/signalservice/api/SignalServiceMessageSender.java index 30c1596569..e450153cbc 100644 --- a/libsignal-service/src/main/java/org/whispersystems/signalservice/api/SignalServiceMessageSender.java +++ b/libsignal-service/src/main/java/org/whispersystems/signalservice/api/SignalServiceMessageSender.java @@ -398,20 +398,6 @@ public class SignalServiceMessageSender { return results; } - /** - * Send an http request on behalf of the calling infrastructure. - * - * @param requestId Request identifier - * @param url Fully qualified URL to request - * @param httpMethod Http method to use (e.g., "GET", "POST") - * @param headers Optional list of headers to send with request - * @param body Optional body to send with request - * @return - */ - public CallingResponse makeCallingRequest(long requestId, String url, String httpMethod, List> headers, byte[] body) { - return socket.makeCallingRequest(requestId, url, httpMethod, headers, body); - } - /** * Send a message to a single recipient. * diff --git a/libsignal-service/src/main/java/org/whispersystems/signalservice/api/calling/CallingApi.kt b/libsignal-service/src/main/java/org/whispersystems/signalservice/api/calling/CallingApi.kt new file mode 100644 index 0000000000..cf81277122 --- /dev/null +++ b/libsignal-service/src/main/java/org/whispersystems/signalservice/api/calling/CallingApi.kt @@ -0,0 +1,84 @@ +/* + * Copyright 2025 Signal Messenger, LLC + * SPDX-License-Identifier: AGPL-3.0-only + */ + +package org.whispersystems.signalservice.api.calling + +import org.signal.libsignal.zkgroup.calllinks.CreateCallLinkCredentialRequest +import org.signal.libsignal.zkgroup.calllinks.CreateCallLinkCredentialResponse +import org.whispersystems.signalservice.api.NetworkResult +import org.whispersystems.signalservice.api.messages.calls.CallingResponse +import org.whispersystems.signalservice.api.messages.calls.TurnServerInfo +import org.whispersystems.signalservice.api.websocket.SignalWebSocket +import org.whispersystems.signalservice.internal.get +import org.whispersystems.signalservice.internal.post +import org.whispersystems.signalservice.internal.push.CreateCallLinkAuthRequest +import org.whispersystems.signalservice.internal.push.CreateCallLinkAuthResponse +import org.whispersystems.signalservice.internal.push.GetCallingRelaysResponse +import org.whispersystems.signalservice.internal.push.PushServiceSocket +import org.whispersystems.signalservice.internal.websocket.WebSocketRequestMessage +import org.signal.libsignal.protocol.util.Pair as LibSignalPair + +/** + * Provide calling specific network apis. + */ +class CallingApi( + private val auth: SignalWebSocket.AuthenticatedWebSocket, + private val pushServiceSocket: PushServiceSocket +) { + + /** + * Get 1:1 relay addresses in IpV4, Ipv6, and URL formats. + * + * GET /v2/calling/relays + * - 200: Success + * - 400: Invalid request + * - 422: Invalid request format + * - 429: Rate limited + */ + fun getTurnServerInfo(): NetworkResult> { + val request = WebSocketRequestMessage.get("/v2/calling/relays") + return NetworkResult.fromWebSocketRequest(auth, request, GetCallingRelaysResponse::class) + .map { it.relays ?: emptyList() } + } + + /** + * Generate a call link credential. + * + * POST /v1/call-link/create-auth + * - 200: Success + * - 400: Invalid request + * - 422: Invalid request format + * - 429: Rate limited + */ + fun createCallLinkCredential(request: CreateCallLinkCredentialRequest): NetworkResult { + val request = WebSocketRequestMessage.post("/v1/call-link/create-auth", body = CreateCallLinkAuthRequest.create(request)) + return NetworkResult.fromWebSocketRequest(auth, request, CreateCallLinkAuthResponse::class) + .map { it.createCallLinkCredentialResponse } + } + + /** + * Send an http request on behalf of the calling infrastructure. Only returns [NetworkResult.Success] with the + * wrapped [CallingResponse] wrapping the error which in practice should never happen. + * + * @param requestId Request identifier + * @param url Fully qualified URL to request + * @param httpMethod Http method to use (e.g., "GET", "POST") + * @param headers Optional list of headers to send with request + * @param body Optional body to send with request + * @return + */ + fun makeCallingRequest( + requestId: Long, + url: String, + httpMethod: String, + headers: List>?, + body: ByteArray? + ): NetworkResult { + return when (val result = NetworkResult.fromFetch { pushServiceSocket.makeCallingRequest(requestId, url, httpMethod, headers, body) }) { + is NetworkResult.Success -> result + else -> NetworkResult.Success(CallingResponse.Error(requestId, result.getCause())) + } + } +} diff --git a/libsignal-service/src/main/java/org/whispersystems/signalservice/api/payments/PaymentsApi.kt b/libsignal-service/src/main/java/org/whispersystems/signalservice/api/payments/PaymentsApi.kt new file mode 100644 index 0000000000..6524fe765c --- /dev/null +++ b/libsignal-service/src/main/java/org/whispersystems/signalservice/api/payments/PaymentsApi.kt @@ -0,0 +1,36 @@ +/* + * Copyright 2025 Signal Messenger, LLC + * SPDX-License-Identifier: AGPL-3.0-only + */ + +package org.whispersystems.signalservice.api.payments + +import org.whispersystems.signalservice.api.NetworkResult +import org.whispersystems.signalservice.api.websocket.SignalWebSocket +import org.whispersystems.signalservice.internal.get +import org.whispersystems.signalservice.internal.push.AuthCredentials +import org.whispersystems.signalservice.internal.websocket.WebSocketRequestMessage + +/** + * Provide payments specific network apis. + */ +class PaymentsApi(private val authWebSocket: SignalWebSocket.AuthenticatedWebSocket) { + + /** + * GET /v1/payments/auth + * - 200: Success + */ + fun getAuthorization(): NetworkResult { + val request = WebSocketRequestMessage.get("/v1/payments/auth") + return NetworkResult.fromWebSocketRequest(authWebSocket, request, AuthCredentials::class) + } + + /** + * GET /v1/payments/conversions + * - 200: Success + */ + fun getCurrencyConversions(): NetworkResult { + val request = WebSocketRequestMessage.get("/v1/payments/conversions") + return NetworkResult.fromWebSocketRequest(authWebSocket, request, CurrencyConversions::class) + } +} diff --git a/libsignal-service/src/main/java/org/whispersystems/signalservice/api/services/CallLinksService.kt b/libsignal-service/src/main/java/org/whispersystems/signalservice/api/services/CallLinksService.kt deleted file mode 100644 index 897f2ce4fa..0000000000 --- a/libsignal-service/src/main/java/org/whispersystems/signalservice/api/services/CallLinksService.kt +++ /dev/null @@ -1,22 +0,0 @@ -/* - * Copyright 2023 Signal Messenger, LLC - * SPDX-License-Identifier: AGPL-3.0-only - */ -package org.whispersystems.signalservice.api.services - -import org.signal.libsignal.zkgroup.calllinks.CreateCallLinkCredentialRequest -import org.signal.libsignal.zkgroup.calllinks.CreateCallLinkCredentialResponse -import org.whispersystems.signalservice.internal.ServiceResponse -import org.whispersystems.signalservice.internal.push.PushServiceSocket -import java.io.IOException - -class CallLinksService(private val pushServiceSocket: PushServiceSocket) { - - fun getCreateCallLinkAuthCredential(request: CreateCallLinkCredentialRequest): ServiceResponse { - return try { - ServiceResponse.forResult(pushServiceSocket.getCallLinkAuthResponse(request), 200, "") - } catch (e: IOException) { - ServiceResponse.forUnknownError(e) - } - } -} diff --git a/libsignal-service/src/main/java/org/whispersystems/signalservice/internal/push/PushServiceSocket.java b/libsignal-service/src/main/java/org/whispersystems/signalservice/internal/push/PushServiceSocket.java index 1612bb0ba8..90a97ded3e 100644 --- a/libsignal-service/src/main/java/org/whispersystems/signalservice/internal/push/PushServiceSocket.java +++ b/libsignal-service/src/main/java/org/whispersystems/signalservice/internal/push/PushServiceSocket.java @@ -10,7 +10,6 @@ import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.core.JsonProcessingException; import com.squareup.wire.Message; -import org.jetbrains.annotations.NotNull; import org.signal.core.util.Base64; import org.signal.core.util.concurrent.FutureTransformers; import org.signal.core.util.concurrent.ListenableFuture; @@ -22,8 +21,6 @@ import org.signal.libsignal.protocol.logging.Log; import org.signal.libsignal.protocol.state.PreKeyBundle; import org.signal.libsignal.protocol.util.Pair; import org.signal.libsignal.zkgroup.VerificationFailedException; -import org.signal.libsignal.zkgroup.calllinks.CreateCallLinkCredentialRequest; -import org.signal.libsignal.zkgroup.calllinks.CreateCallLinkCredentialResponse; import org.signal.libsignal.zkgroup.profiles.ClientZkProfileOperations; import org.signal.libsignal.zkgroup.profiles.ExpiringProfileKeyCredential; import org.signal.libsignal.zkgroup.profiles.ProfileKey; @@ -45,13 +42,6 @@ import org.signal.storageservice.protos.groups.Member; import org.whispersystems.signalservice.api.account.AccountAttributes; import org.whispersystems.signalservice.api.account.PreKeyCollection; import org.whispersystems.signalservice.api.account.PreKeyUpload; -import org.whispersystems.signalservice.api.archive.ArchiveCredentialPresentation; -import org.whispersystems.signalservice.api.archive.ArchiveGetMediaItemsResponse; -import org.whispersystems.signalservice.api.archive.ArchiveMediaRequest; -import org.whispersystems.signalservice.api.archive.ArchiveMediaResponse; -import org.whispersystems.signalservice.api.archive.BatchArchiveMediaRequest; -import org.whispersystems.signalservice.api.archive.BatchArchiveMediaResponse; -import org.whispersystems.signalservice.api.archive.DeleteArchivedMediaRequest; import org.whispersystems.signalservice.api.crypto.SealedSenderAccess; import org.whispersystems.signalservice.api.groupsv2.CredentialResponse; import org.whispersystems.signalservice.api.groupsv2.GroupsV2AuthorizationString; @@ -159,7 +149,6 @@ import java.security.NoSuchAlgorithmException; import java.security.SecureRandom; import java.time.ZonedDateTime; import java.time.format.DateTimeFormatter; -import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; @@ -211,8 +200,6 @@ public class PushServiceSocket { private static final String PREKEY_DEVICE_PATH = "/v2/keys/%s/%s"; private static final String PREKEY_CHECK_PATH = "/v2/keys/check"; - private static final String CALLING_RELAYS = "/v2/calling/relays"; - private static final String PROVISIONING_MESSAGE_PATH = "/v1/provisioning/%s"; private static final String SET_RESTORE_METHOD_PATH = "/v1/devices/restore_account/%s"; private static final String WAIT_RESTORE_METHOD_PATH = "/v1/devices/restore_account/%s?timeout=%s"; @@ -223,9 +210,6 @@ public class PushServiceSocket { private static final String UUID_ACK_MESSAGE_PATH = "/v1/messages/uuid/%s"; private static final String ATTACHMENT_V4_PATH = "/v4/attachments/form/upload"; - private static final String PAYMENTS_AUTH_PATH = "/v1/payments/auth"; - private static final String PAYMENTS_CONVERSIONS = "/v1/payments/conversions"; - private static final String PROFILE_PATH = "/v1/profile/%s"; private static final String PROFILE_BATCH_CHECK_PATH = "/v1/profile/identity_check/batch"; @@ -286,8 +270,6 @@ public class PushServiceSocket { private static final String ARCHIVE_MEDIA_DOWNLOAD_PATH = "backups/%s/%s"; - private static final String CALL_LINK_CREATION_AUTH = "/v1/call-link/create-auth"; - private static final String SERVER_DELIVERED_TIMESTAMP_HEADER = "X-Signal-Timestamp"; private static final Map NO_HEADERS = Collections.emptyMap(); @@ -1137,32 +1119,6 @@ public class PushServiceSocket { } } - public CreateCallLinkCredentialResponse getCallLinkAuthResponse(CreateCallLinkCredentialRequest request) throws IOException { - String payload = JsonUtil.toJson(CreateCallLinkAuthRequest.create(request)); - String response = makeServiceRequest( - CALL_LINK_CREATION_AUTH, - "POST", - payload - ); - - return JsonUtil.fromJson(response, CreateCallLinkAuthResponse.class).getCreateCallLinkCredentialResponse(); - } - - private AuthCredentials getAuthCredentials(String authPath) throws IOException { - String response = makeServiceRequest(authPath, "GET", null); - AuthCredentials token = JsonUtil.fromJson(response, AuthCredentials.class); - return token; - } - - public AuthCredentials getPaymentsAuthorization() throws IOException { - return getAuthCredentials(PAYMENTS_AUTH_PATH); - } - - public GetCallingRelaysResponse getCallingRelays() throws IOException { - String response = makeServiceRequest(CALLING_RELAYS, "GET", null); - return JsonUtil.fromJson(response, GetCallingRelaysResponse.class); - } - public String getStorageAuth() throws IOException { String response = makeServiceRequest("/v1/storage/auth", "GET", null); StorageAuthResponse authResponse = JsonUtil.fromJson(response, StorageAuthResponse.class); @@ -1188,14 +1144,6 @@ public class PushServiceSocket { } } - public Optional writeStorageContacts(String authToken, WriteOperation writeOperation) throws IOException { - try (Response response = makeStorageRequest(authToken, "/v1/storage", "PUT", protobufRequestBody(writeOperation), NO_HANDLER)) { - return Optional.empty(); - } catch (ContactManifestMismatchException e) { - return Optional.of(StorageManifest.ADAPTER.decode(e.getResponseBody())); - } - } - public void writeStorageItems(String authToken, WriteOperation writeOperation) throws IOException { makeStorageRequest(authToken, "/v1/storage", "PUT", protobufRequestBody(writeOperation), UNOPINIONATED_BINARY_ERROR_HANDLER); } @@ -1211,10 +1159,6 @@ public class PushServiceSocket { return JsonUtil.fromJson(response, RemoteConfigResponse.class); } - public void setSoTimeoutMillis(long soTimeoutMillis) { - this.soTimeoutMillis = soTimeoutMillis; - } - public void cancelInFlightRequests() { synchronized (connections) { Log.w(TAG, "Canceling: " + connections.size()); @@ -2462,8 +2406,6 @@ public class PushServiceSocket { } } - public enum ClientSet { KeyBackup } - public CredentialResponse retrieveGroupsV2Credentials(long todaySeconds) throws IOException { @@ -2652,18 +2594,6 @@ public class PushServiceSocket { } } - public CurrencyConversions getCurrencyConversions() - throws NonSuccessfulResponseCodeException, PushNetworkException, MalformedResponseException - { - String response = makeServiceRequest(PAYMENTS_CONVERSIONS, "GET", null); - try { - return JsonUtil.fromJson(response, CurrencyConversions.class); - } catch (IOException e) { - Log.w(TAG, e); - throw new MalformedResponseException("Unable to parse entity", e); - } - } - public void reportSpam(ServiceId serviceId, String serverGuid, String reportingToken) throws NonSuccessfulResponseCodeException, MalformedResponseException, PushNetworkException {