Convert CDSI auth to WebSocket and service to NetworkResult.

This commit is contained in:
Cody Henthorne
2025-03-11 15:14:34 -04:00
committed by Greyson Parrelli
parent 92e590aa3b
commit 6aca7c9194
10 changed files with 198 additions and 217 deletions

View File

@@ -11,13 +11,15 @@ import org.thoughtcrime.securesms.database.RecipientTable.CdsV2Result
import org.thoughtcrime.securesms.database.SignalDatabase
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.thoughtcrime.securesms.recipients.RecipientId
import org.thoughtcrime.securesms.util.RemoteConfig
import org.thoughtcrime.securesms.util.SignalE164Util
import org.whispersystems.signalservice.api.NetworkResult
import org.whispersystems.signalservice.api.cds.CdsiV2Service
import org.whispersystems.signalservice.api.push.exceptions.CdsiInvalidTokenException
import org.whispersystems.signalservice.api.push.exceptions.CdsiResourceExhaustedException
import org.whispersystems.signalservice.api.services.CdsiV2Service
import java.io.IOException
import java.util.Optional
import kotlin.math.roundToInt
@@ -89,25 +91,39 @@ object ContactDiscoveryRefreshV2 {
@WorkerThread
@Synchronized
fun lookupE164(e164: String): ContactDiscovery.LookupResult? {
val response: CdsiV2Service.Response = try {
AppDependencies.signalServiceAccountManager.getRegisteredUsersWithCdsi(
emptySet(),
setOf(e164),
SignalDatabase.recipients.getAllServiceIdProfileKeyPairs(),
Optional.empty(),
10_000,
AppDependencies.libsignalNetwork,
RemoteConfig.libsignalRouteBasedCDSILookup
) {
Log.i(TAG, "Ignoring token for one-off lookup.")
val result = SignalNetwork.cdsApi.getRegisteredUsers(
previousE164s = emptySet(),
newE164s = setOf(e164),
serviceIds = SignalDatabase.recipients.getAllServiceIdProfileKeyPairs(),
token = Optional.empty(),
timeoutMs = 10_000,
libsignalNetwork = AppDependencies.libsignalNetwork,
useLibsignalRouteBasedCDSIConnectionLogic = RemoteConfig.libsignalRouteBasedCDSILookup
) {
Log.i(TAG, "Ignoring token for one-off lookup.")
}
val response = when (result) {
is NetworkResult.Success -> result.result
is NetworkResult.StatusCodeError -> {
when (val e = result.exception) {
is CdsiResourceExhaustedException -> {
Log.w(TAG, "CDS resource exhausted! Can try again in ${e.retryAfterSeconds} seconds.")
SignalStore.misc.cdsBlockedUtil = System.currentTimeMillis() + e.retryAfterSeconds.seconds.inWholeMilliseconds
throw e
}
is CdsiInvalidTokenException -> {
Log.w(TAG, "We did not provide a token, but still got a token error! Unexpected, but ignoring.")
throw e
}
else -> throw e
}
}
} catch (e: CdsiResourceExhaustedException) {
Log.w(TAG, "CDS resource exhausted! Can try again in ${e.retryAfterSeconds} seconds.")
SignalStore.misc.cdsBlockedUtil = System.currentTimeMillis() + e.retryAfterSeconds.seconds.inWholeMilliseconds
throw e
} catch (e: CdsiInvalidTokenException) {
Log.w(TAG, "We did not provide a token, but still got a token error! Unexpected, but ignoring.")
throw e
is NetworkResult.NetworkError -> throw result.exception
is NetworkResult.ApplicationError -> throw RuntimeException("Unexpected exception", result.throwable)
}
return response.results[e164]?.let { item ->
@@ -154,36 +170,50 @@ object ContactDiscoveryRefreshV2 {
stopwatch.split("preamble")
val response: CdsiV2Service.Response = try {
AppDependencies.signalServiceAccountManager.getRegisteredUsersWithCdsi(
previousE164s,
newE164s,
SignalDatabase.recipients.getAllServiceIdProfileKeyPairs(),
Optional.ofNullable(token),
timeoutMs,
AppDependencies.libsignalNetwork,
RemoteConfig.libsignalRouteBasedCDSILookup
) { tokenToSave ->
stopwatch.split("network-pre-token")
if (!isPartialRefresh) {
SignalStore.misc.cdsToken = tokenToSave
SignalDatabase.cds.updateAfterFullCdsQuery(previousE164s + newE164s, allE164s + newE164s)
Log.d(TAG, "Token saved!")
} else {
SignalDatabase.cds.updateAfterPartialCdsQuery(newE164s)
Log.d(TAG, "Ignoring token.")
}
stopwatch.split("cds-db")
val result = SignalNetwork.cdsApi.getRegisteredUsers(
previousE164s = previousE164s,
newE164s = newE164s,
serviceIds = SignalDatabase.recipients.getAllServiceIdProfileKeyPairs(),
token = Optional.ofNullable(token),
timeoutMs = timeoutMs,
libsignalNetwork = AppDependencies.libsignalNetwork,
useLibsignalRouteBasedCDSIConnectionLogic = RemoteConfig.libsignalRouteBasedCDSILookup
) { tokenToSave ->
stopwatch.split("network-pre-token")
if (!isPartialRefresh) {
SignalStore.misc.cdsToken = tokenToSave
SignalDatabase.cds.updateAfterFullCdsQuery(previousE164s + newE164s, allE164s + newE164s)
Log.d(TAG, "Token saved!")
} else {
SignalDatabase.cds.updateAfterPartialCdsQuery(newE164s)
Log.d(TAG, "Ignoring token.")
}
} catch (e: CdsiResourceExhaustedException) {
Log.w(TAG, "CDS resource exhausted! Can try again in ${e.retryAfterSeconds} seconds.")
SignalStore.misc.cdsBlockedUtil = System.currentTimeMillis() + e.retryAfterSeconds.seconds.inWholeMilliseconds
throw e
} catch (e: CdsiInvalidTokenException) {
Log.w(TAG, "Our token was invalid! Only thing we can do now is clear our local state :(")
SignalStore.misc.cdsToken = null
SignalDatabase.cds.clearAll()
throw e
stopwatch.split("cds-db")
}
val response: CdsiV2Service.Response = when (result) {
is NetworkResult.Success -> result.result
is NetworkResult.StatusCodeError -> {
when (val e = result.exception) {
is CdsiResourceExhaustedException -> {
Log.w(TAG, "CDS resource exhausted! Can try again in ${e.retryAfterSeconds} seconds.")
SignalStore.misc.cdsBlockedUtil = System.currentTimeMillis() + e.retryAfterSeconds.seconds.inWholeMilliseconds
throw e
}
is CdsiInvalidTokenException -> {
Log.w(TAG, "Our token was invalid! Only thing we can do now is clear our local state :(")
SignalStore.misc.cdsToken = null
SignalDatabase.cds.clearAll()
throw e
}
else -> throw e
}
}
is NetworkResult.NetworkError -> throw result.exception
is NetworkResult.ApplicationError -> throw RuntimeException("Unexpected exception", result.throwable)
}
if (!isPartialRefresh && SignalStore.misc.isCdsBlocked) {

View File

@@ -46,6 +46,7 @@ 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.cds.CdsApi
import org.whispersystems.signalservice.api.groupsv2.GroupsV2Operations
import org.whispersystems.signalservice.api.keys.KeysApi
import org.whispersystems.signalservice.api.link.LinkDeviceApi
@@ -322,6 +323,9 @@ object AppDependencies {
val paymentsApi: PaymentsApi
get() = networkModule.paymentsApi
val cdsApi: CdsApi
get() = networkModule.cdsApi
@JvmStatic
val okHttpClient: OkHttpClient
get() = networkModule.okHttpClient
@@ -396,5 +400,6 @@ object AppDependencies {
fun provideUsernameApi(unauthWebSocket: SignalWebSocket.UnauthenticatedWebSocket): UsernameApi
fun provideCallingApi(authWebSocket: SignalWebSocket.AuthenticatedWebSocket, pushServiceSocket: PushServiceSocket): CallingApi
fun providePaymentsApi(authWebSocket: SignalWebSocket.AuthenticatedWebSocket): PaymentsApi
fun provideCdsApi(authWebSocket: SignalWebSocket.AuthenticatedWebSocket): CdsApi
}
}

View File

@@ -84,6 +84,7 @@ 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.cds.CdsApi;
import org.whispersystems.signalservice.api.groupsv2.ClientZkOperations;
import org.whispersystems.signalservice.api.groupsv2.GroupsV2Operations;
import org.whispersystems.signalservice.api.keys.KeysApi;
@@ -510,6 +511,11 @@ public class ApplicationDependencyProvider implements AppDependencies.Provider {
return new PaymentsApi(authWebSocket);
}
@Override
public @NonNull CdsApi provideCdsApi(@NonNull SignalWebSocket.AuthenticatedWebSocket authWebSocket) {
return new CdsApi(authWebSocket);
}
@VisibleForTesting
static class DynamicCredentialsProvider implements CredentialsProvider {

View File

@@ -30,6 +30,7 @@ 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.cds.CdsApi
import org.whispersystems.signalservice.api.groupsv2.GroupsV2Operations
import org.whispersystems.signalservice.api.keys.KeysApi
import org.whispersystems.signalservice.api.link.LinkDeviceApi
@@ -172,6 +173,10 @@ class NetworkDependenciesModule(
provider.providePaymentsApi(authWebSocket)
}
val cdsApi: CdsApi by lazy {
provider.provideCdsApi(authWebSocket)
}
val okHttpClient: OkHttpClient by lazy {
OkHttpClient.Builder()
.addInterceptor(StandardUserAgentInterceptor())

View File

@@ -10,6 +10,7 @@ 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.cds.CdsApi
import org.whispersystems.signalservice.api.keys.KeysApi
import org.whispersystems.signalservice.api.link.LinkDeviceApi
import org.whispersystems.signalservice.api.payments.PaymentsApi
@@ -36,6 +37,9 @@ object SignalNetwork {
val calling: CallingApi
get() = AppDependencies.callingApi
val cdsApi: CdsApi
get() = AppDependencies.cdsApi
val keys: KeysApi
get() = AppDependencies.keysApi