diff --git a/service/config/sample-secrets-bundle.yml b/service/config/sample-secrets-bundle.yml
index 772bed93c..81dd83749 100644
--- a/service/config/sample-secrets-bundle.yml
+++ b/service/config/sample-secrets-bundle.yml
@@ -94,7 +94,6 @@ currentReportingKey.salt: AAAAAAAAAAA=
registrationService.collationKeySalt: AAAAAAAAAAA=
-turn.secret: AAAAAAAAAAA=
turn.cloudflare.apiToken: ABCDEFGHIJKLM
linkDevice.secret: AAAAAAAAAAA=
diff --git a/service/config/sample.yml b/service/config/sample.yml
index 08e44939b..43e3c6444 100644
--- a/service/config/sample.yml
+++ b/service/config/sample.yml
@@ -473,7 +473,6 @@ keyTransparencyService:
clientPrivateKey: secret://keyTransparencyService.clientPrivateKey
turn:
- secret: secret://turn.secret
cloudflare:
apiToken: secret://turn.cloudflare.apiToken
endpoint: https://rtc.live.cloudflare.com/v1/turn/keys/LMNOP/credentials/generate
@@ -490,30 +489,6 @@ turn:
linkDevice:
secret: secret://linkDevice.secret
-maxmindCityDatabase:
- s3Region: a-region
- s3Bucket: a-bucket
- objectKey: an-object.tar.gz
- maxSize: 32777216
-
-callingTurnDnsRecords:
- s3Region: a-region
- s3Bucket: a-bucket
- objectKey: an-object.tar.gz
- maxSize: 32777216
-
-callingTurnPerformanceTable:
- s3Region: a-region
- s3Bucket: a-bucket
- objectKey: an-object.tar.gz
- maxSize: 32777216
-
-callingTurnManualTable:
- s3Region: a-region
- s3Bucket: a-bucket
- objectKey: an-object.tar.gz
- maxSize: 32777216
-
noiseTunnel:
port: 8443
tlsKeyStoreFile: /path/to/file.p12
diff --git a/service/pom.xml b/service/pom.xml
index debda1675..72d30e03c 100644
--- a/service/pom.xml
+++ b/service/pom.xml
@@ -232,12 +232,6 @@
1.27.1
-
- com.maxmind.geoip2
- geoip2
- 4.2.1
-
-
com.google.cloud
google-cloud-pubsub
diff --git a/service/src/main/java/org/whispersystems/textsecuregcm/WhisperServerConfiguration.java b/service/src/main/java/org/whispersystems/textsecuregcm/WhisperServerConfiguration.java
index f79e2ce46..8e8702b76 100644
--- a/service/src/main/java/org/whispersystems/textsecuregcm/WhisperServerConfiguration.java
+++ b/service/src/main/java/org/whispersystems/textsecuregcm/WhisperServerConfiguration.java
@@ -301,27 +301,6 @@ public class WhisperServerConfiguration extends Configuration {
@JsonProperty
private VirtualThreadConfiguration virtualThread = new VirtualThreadConfiguration(Duration.ofMillis(1));
-
- @Valid
- @NotNull
- @JsonProperty
- private S3ObjectMonitorFactory maxmindCityDatabase;
-
- @Valid
- @NotNull
- @JsonProperty
- private S3ObjectMonitorFactory callingTurnDnsRecords;
-
- @Valid
- @NotNull
- @JsonProperty
- private S3ObjectMonitorFactory callingTurnPerformanceTable;
-
- @Valid
- @NotNull
- @JsonProperty
- private S3ObjectMonitorFactory callingTurnManualTable;
-
@Valid
@NotNull
@JsonProperty
@@ -539,22 +518,6 @@ public class WhisperServerConfiguration extends Configuration {
return virtualThread;
}
- public S3ObjectMonitorFactory getMaxmindCityDatabase() {
- return maxmindCityDatabase;
- }
-
- public S3ObjectMonitorFactory getCallingTurnDnsRecords() {
- return callingTurnDnsRecords;
- }
-
- public S3ObjectMonitorFactory getCallingTurnPerformanceTable() {
- return callingTurnPerformanceTable;
- }
-
- public S3ObjectMonitorFactory getCallingTurnManualTable() {
- return callingTurnManualTable;
- }
-
public NoiseWebSocketTunnelConfiguration getNoiseWebSocketTunnelConfiguration() {
return noiseTunnel;
}
diff --git a/service/src/main/java/org/whispersystems/textsecuregcm/WhisperServerService.java b/service/src/main/java/org/whispersystems/textsecuregcm/WhisperServerService.java
index a616b82f3..ef03ac3a6 100644
--- a/service/src/main/java/org/whispersystems/textsecuregcm/WhisperServerService.java
+++ b/service/src/main/java/org/whispersystems/textsecuregcm/WhisperServerService.java
@@ -85,7 +85,6 @@ import org.whispersystems.textsecuregcm.auth.ExternalServiceCredentialsGenerator
import org.whispersystems.textsecuregcm.auth.IdlePrimaryDeviceAuthenticatedWebSocketUpgradeFilter;
import org.whispersystems.textsecuregcm.auth.PhoneVerificationTokenManager;
import org.whispersystems.textsecuregcm.auth.RegistrationLockVerificationManager;
-import org.whispersystems.textsecuregcm.auth.TurnTokenGenerator;
import org.whispersystems.textsecuregcm.auth.WebsocketRefreshApplicationEventListener;
import org.whispersystems.textsecuregcm.auth.grpc.ProhibitAuthenticationInterceptor;
import org.whispersystems.textsecuregcm.auth.grpc.RequireAuthenticationInterceptor;
@@ -667,7 +666,6 @@ public class WhisperServerService extends Application> urlsWithIps,
- Optional> urlsWithHostname
- ) {
- try {
- final Mac mac = Mac.getInstance(ALGORITHM);
- final long validUntilSeconds = Instant.now().plus(Duration.ofDays(1)).getEpochSecond();
- final long user = Util.ensureNonNegativeInt(new SecureRandom().nextInt());
- final String userTime = validUntilSeconds + ":" + user;
- final String protocol = urlsWithIps.isEmpty() || urlsWithIps.get().isEmpty()
- ? WithUrlsProtocol
- : WithIpsProtocol;
- final String protocolUserTime = userTime + "#" + protocol;
-
- mac.init(new SecretKeySpec(turnSecret, ALGORITHM));
- final String password = Base64.getEncoder().encodeToString(mac.doFinal(protocolUserTime.getBytes()));
-
- return from(
- protocolUserTime,
- password,
- urlsWithHostname,
- urlsWithIps,
- hostname
- );
- } catch (final NoSuchAlgorithmException | InvalidKeyException e) {
- throw new AssertionError(e);
- }
- }
-
- @SuppressWarnings("OptionalUsedAsFieldOrParameterType")
- public static TurnToken from(
- String username,
- String password,
- Optional> urls,
- Optional> urlsWithIps,
- String hostname
- ) {
- return new TurnToken(
- username,
- password,
- urls.orElse(Collections.emptyList()),
- urlsWithIps.orElse(Collections.emptyList()),
- hostname
- );
- }
-}
diff --git a/service/src/main/java/org/whispersystems/textsecuregcm/calls/routing/DynamicConfigTurnRouter.java b/service/src/main/java/org/whispersystems/textsecuregcm/calls/routing/DynamicConfigTurnRouter.java
deleted file mode 100644
index d579ae486..000000000
--- a/service/src/main/java/org/whispersystems/textsecuregcm/calls/routing/DynamicConfigTurnRouter.java
+++ /dev/null
@@ -1,74 +0,0 @@
-/*
- * Copyright 2024 Signal Messenger, LLC
- * SPDX-License-Identifier: AGPL-3.0-only
- */
-
-package org.whispersystems.textsecuregcm.calls.routing;
-
-import org.whispersystems.textsecuregcm.configuration.TurnUriConfiguration;
-import org.whispersystems.textsecuregcm.configuration.dynamic.DynamicConfiguration;
-import org.whispersystems.textsecuregcm.configuration.dynamic.DynamicTurnConfiguration;
-import org.whispersystems.textsecuregcm.storage.DynamicConfigurationManager;
-import org.whispersystems.textsecuregcm.util.Pair;
-import org.whispersystems.textsecuregcm.util.WeightedRandomSelect;
-import java.util.Collections;
-import java.util.List;
-import java.util.Optional;
-import java.util.Random;
-import java.util.UUID;
-
-/** Uses DynamicConfig to help route a turn request */
-public class DynamicConfigTurnRouter {
-
- private static final Random rng = new Random();
-
- public static final long RANDOMIZE_RATE_BASIS = 100_000;
-
- private final DynamicConfigurationManager dynamicConfigurationManager;
-
- public DynamicConfigTurnRouter(final DynamicConfigurationManager dynamicConfigurationManager) {
- this.dynamicConfigurationManager = dynamicConfigurationManager;
- }
-
- public List targetedUrls(final UUID aci) {
- final DynamicTurnConfiguration turnConfig = dynamicConfigurationManager.getConfiguration().getTurnConfiguration();
-
- final Optional enrolled = turnConfig.getUriConfigs().stream()
- .filter(config -> config.getEnrolledAcis().contains(aci))
- .findFirst();
-
- return enrolled
- .map(turnUriConfiguration -> turnUriConfiguration.getUris().stream().toList())
- .orElse(Collections.emptyList());
- }
-
- public List randomUrls() {
- final DynamicTurnConfiguration turnConfig = dynamicConfigurationManager.getConfiguration().getTurnConfiguration();
-
- // select from turn server sets by weighted choice
- return WeightedRandomSelect.select(turnConfig
- .getUriConfigs()
- .stream()
- .map(c -> new Pair<>(c.getUris(), c.getWeight())).toList());
- }
-
- public String getHostname() {
- final DynamicTurnConfiguration turnConfig = dynamicConfigurationManager.getConfiguration().getTurnConfiguration();
- return turnConfig.getHostname();
- }
-
- public long getRandomizeRate() {
- final DynamicTurnConfiguration turnConfig = dynamicConfigurationManager.getConfiguration().getTurnConfiguration();
- return turnConfig.getRandomizeRate();
- }
-
- public int getDefaultInstanceIpCount() {
- final DynamicTurnConfiguration turnConfig = dynamicConfigurationManager.getConfiguration().getTurnConfiguration();
- return turnConfig.getDefaultInstanceIpCount();
- }
-
- public boolean shouldRandomize() {
- long rate = getRandomizeRate();
- return rate >= RANDOMIZE_RATE_BASIS || rng.nextLong(0, DynamicConfigTurnRouter.RANDOMIZE_RATE_BASIS) < rate;
- }
-}
diff --git a/service/src/main/java/org/whispersystems/textsecuregcm/calls/routing/TurnCallRouter.java b/service/src/main/java/org/whispersystems/textsecuregcm/calls/routing/TurnCallRouter.java
deleted file mode 100644
index 4367d755c..000000000
--- a/service/src/main/java/org/whispersystems/textsecuregcm/calls/routing/TurnCallRouter.java
+++ /dev/null
@@ -1,190 +0,0 @@
-/*
- * Copyright 2023 Signal Messenger, LLC
- * SPDX-License-Identifier: AGPL-3.0-only
- */
-
-package org.whispersystems.textsecuregcm.calls.routing;
-
-import com.maxmind.geoip2.DatabaseReader;
-import com.maxmind.geoip2.exception.GeoIp2Exception;
-import com.maxmind.geoip2.model.CityResponse;
-import org.apache.commons.lang3.tuple.Triple;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.whispersystems.textsecuregcm.util.Util;
-import javax.annotation.Nonnull;
-import java.io.IOException;
-import java.net.InetAddress;
-import java.util.*;
-import java.util.function.Supplier;
-import java.util.stream.IntStream;
-import java.util.stream.Stream;
-
-/**
- * Returns routes based on performance tables, manually routing tables, and target routing. Falls back to a random Turn
- * instance that the server knows about.
- */
-public class TurnCallRouter {
-
- private final Logger logger = LoggerFactory.getLogger(TurnCallRouter.class);
-
- private final Supplier callDnsRecords;
- private final Supplier performanceRouting;
- private final Supplier manualRouting;
- private final DynamicConfigTurnRouter configTurnRouter;
- private final Supplier geoIp;
- // controls whether instance IPs are shuffled. using if & boolean is ~5x faster than a function pointer
- private final boolean stableSelect;
-
- public TurnCallRouter(
- @Nonnull Supplier callDnsRecords,
- @Nonnull Supplier performanceRouting,
- @Nonnull Supplier manualRouting,
- @Nonnull DynamicConfigTurnRouter configTurnRouter,
- @Nonnull Supplier geoIp,
- boolean stableSelect
- ) {
- this.performanceRouting = performanceRouting;
- this.callDnsRecords = callDnsRecords;
- this.manualRouting = manualRouting;
- this.configTurnRouter = configTurnRouter;
- this.geoIp = geoIp;
- this.stableSelect = stableSelect;
- }
-
- public TurnServerOptions getRoutingFor(
- @Nonnull final UUID aci,
- @Nonnull final Optional clientAddress
- ) {
- return getRoutingFor(aci, clientAddress, this.configTurnRouter.getDefaultInstanceIpCount());
- }
-
- /**
- * Gets Turn Instance addresses. Returns both the IPv4 and IPv6 addresses. Prefers to match the IP protocol of the
- * client address in datacenter selection. Returns 2 instance options of the preferred protocol for every one instance
- * of the other.
- * @param aci aci of client
- * @param clientAddress IP address to base routing on
- * @param instanceLimit max instances to return options for
- * @return Up to two * instanceLimit options, half in ipv4, half in ipv6
- */
- public TurnServerOptions getRoutingFor(
- @Nonnull final UUID aci,
- @Nonnull final Optional clientAddress,
- final int instanceLimit
- ) {
- try {
- return getRoutingForInner(aci, clientAddress, instanceLimit);
- } catch(Exception e) {
- logger.error("Failed to perform routing", e);
- return new TurnServerOptions(this.configTurnRouter.getHostname(), null, Optional.of(this.configTurnRouter.randomUrls()));
- }
- }
-
- TurnServerOptions getRoutingForInner(
- @Nonnull final UUID aci,
- @Nonnull final Optional clientAddress,
- final int instanceLimit
- ) {
- String hostname = this.configTurnRouter.getHostname();
-
- List targetedUrls = this.configTurnRouter.targetedUrls(aci);
- if(!targetedUrls.isEmpty()) {
- return new TurnServerOptions(hostname, Optional.empty(), Optional.ofNullable(targetedUrls));
- }
-
- if(clientAddress.isEmpty() || this.configTurnRouter.shouldRandomize() || instanceLimit < 1) {
- return new TurnServerOptions(hostname, Optional.empty(), Optional.ofNullable(this.configTurnRouter.randomUrls()));
- }
-
- CityResponse geoInfo;
- try {
- geoInfo = geoIp.get().city(clientAddress.get());
- } catch (IOException | GeoIp2Exception e) {
- throw new RuntimeException(e);
- }
- Optional subdivision = !geoInfo.getSubdivisions().isEmpty()
- ? Optional.of(geoInfo.getSubdivisions().getFirst().getIsoCode())
- : Optional.empty();
-
- List datacenters = this.manualRouting.get().getDatacentersFor(
- clientAddress.get(),
- geoInfo.getContinent().getCode(),
- geoInfo.getCountry().getIsoCode(),
- subdivision
- );
-
- if (datacenters.isEmpty()){
- datacenters = this.performanceRouting.get().getDatacentersFor(
- clientAddress.get(),
- geoInfo.getContinent().getCode(),
- geoInfo.getCountry().getIsoCode(),
- subdivision
- );
- }
-
- List urlsWithIps = getUrlsForInstances(
- selectInstances(
- datacenters,
- instanceLimit
- ));
- return new TurnServerOptions(hostname, Optional.of(urlsWithIps), Optional.of(minimalRandomUrls()));
- }
-
- // Includes only the udp options in the randomUrls
- private List minimalRandomUrls(){
- return this.configTurnRouter.randomUrls().stream()
- .filter(s -> s.startsWith("turn:") && !s.endsWith("transport=tcp"))
- .toList();
- }
-
- // returns balanced number of instances across provided datacenters, prioritizing the datacenters earlier in the list
- private List selectInstances(List datacenters, int instanceLimit) {
- if(datacenters.isEmpty() || instanceLimit == 0) {
- return Collections.emptyList();
- }
-
- CallDnsRecords dnsRecords = this.callDnsRecords.get();
- List> ipv4Options = datacenters.stream()
- .map(dc -> randomNOf(dnsRecords.aByRegion().get(dc), instanceLimit, stableSelect))
- .toList();
- List> ipv6Options = datacenters.stream()
- .map(dc -> randomNOf(dnsRecords.aaaaByRegion().get(dc), instanceLimit, stableSelect))
- .toList();
-
- List ipv4Selection = selectFromOptions(ipv4Options, instanceLimit);
- List ipv6Selection = selectFromOptions(ipv6Options, instanceLimit);
-
- return Stream.concat(
- ipv4Selection.stream().map(InetAddress::getHostAddress),
- // map ipv6 to RFC3986 format i.e. surrounded by brackets
- ipv6Selection.stream().map(i -> String.format("[%s]", i.getHostAddress()))
- ).toList();
- }
-
- private static List selectFromOptions(List> recordsByDc, int instanceLimit) {
- return IntStream.range(0, recordsByDc.size())
- .mapToObj(dcIndex -> IntStream.range(0, recordsByDc.get(dcIndex).size())
- .mapToObj(addressIndex -> Triple.of(addressIndex, dcIndex, recordsByDc.get(dcIndex).get(addressIndex))))
- .flatMap(i -> i)
- .sorted(Comparator.comparingInt((Triple t) -> t.getLeft())
- .thenComparingInt(Triple::getMiddle))
- .limit(instanceLimit)
- .sorted(Comparator.comparingInt(Triple::getMiddle))
- .map(Triple::getRight)
- .toList();
- }
-
- private static List randomNOf(List values, int n, boolean stableSelect) {
- return stableSelect ? Util.randomNOfStable(values, n) : Util.randomNOfShuffled(values, n);
- }
-
- private static List getUrlsForInstances(List instanceIps) {
- return instanceIps.stream().flatMap(ip -> Stream.of(
- String.format("turn:%s", ip),
- String.format("turn:%s:80?transport=tcp", ip),
- String.format("turns:%s:443?transport=tcp", ip)
- )
- ).toList();
- }
-}
diff --git a/service/src/main/java/org/whispersystems/textsecuregcm/configuration/CloudflareTurnConfiguration.java b/service/src/main/java/org/whispersystems/textsecuregcm/configuration/CloudflareTurnConfiguration.java
index 52df5f84b..d7fd73e0e 100644
--- a/service/src/main/java/org/whispersystems/textsecuregcm/configuration/CloudflareTurnConfiguration.java
+++ b/service/src/main/java/org/whispersystems/textsecuregcm/configuration/CloudflareTurnConfiguration.java
@@ -7,6 +7,7 @@ package org.whispersystems.textsecuregcm.configuration;
import jakarta.validation.Valid;
import jakarta.validation.constraints.NotBlank;
+import jakarta.validation.constraints.NotEmpty;
import jakarta.validation.constraints.NotNull;
import java.util.List;
import jakarta.validation.constraints.Positive;
@@ -15,8 +16,8 @@ import org.whispersystems.textsecuregcm.configuration.secrets.SecretString;
public record CloudflareTurnConfiguration(@NotNull SecretString apiToken,
@NotBlank String endpoint,
@NotBlank long ttl,
- @NotBlank List urls,
- @NotBlank List urlsWithIps,
+ @NotNull @NotEmpty @Valid List<@NotBlank String> urls,
+ @NotNull @NotEmpty @Valid List<@NotBlank String> urlsWithIps,
@NotNull @Valid CircuitBreakerConfiguration circuitBreaker,
@NotNull @Valid RetryConfiguration retry,
@NotBlank String hostname,
diff --git a/service/src/main/java/org/whispersystems/textsecuregcm/configuration/TurnConfiguration.java b/service/src/main/java/org/whispersystems/textsecuregcm/configuration/TurnConfiguration.java
index 6637503b5..6e69794d6 100644
--- a/service/src/main/java/org/whispersystems/textsecuregcm/configuration/TurnConfiguration.java
+++ b/service/src/main/java/org/whispersystems/textsecuregcm/configuration/TurnConfiguration.java
@@ -5,7 +5,5 @@
package org.whispersystems.textsecuregcm.configuration;
-import org.whispersystems.textsecuregcm.configuration.secrets.SecretBytes;
-
-public record TurnConfiguration(SecretBytes secret, CloudflareTurnConfiguration cloudflare) {
+public record TurnConfiguration(CloudflareTurnConfiguration cloudflare) {
}
diff --git a/service/src/main/java/org/whispersystems/textsecuregcm/configuration/dynamic/DynamicConfiguration.java b/service/src/main/java/org/whispersystems/textsecuregcm/configuration/dynamic/DynamicConfiguration.java
index 25f4e1411..092cb7679 100644
--- a/service/src/main/java/org/whispersystems/textsecuregcm/configuration/dynamic/DynamicConfiguration.java
+++ b/service/src/main/java/org/whispersystems/textsecuregcm/configuration/dynamic/DynamicConfiguration.java
@@ -42,10 +42,6 @@ public class DynamicConfiguration {
@Valid
private DynamicCaptchaConfiguration captcha = new DynamicCaptchaConfiguration();
- @JsonProperty
- @Valid
- private DynamicTurnConfiguration turn = new DynamicTurnConfiguration();
-
@JsonProperty
@Valid
DynamicMessagePersisterConfiguration messagePersister = new DynamicMessagePersisterConfiguration();
@@ -104,10 +100,6 @@ public class DynamicConfiguration {
return captcha;
}
- public DynamicTurnConfiguration getTurnConfiguration() {
- return turn;
- }
-
public DynamicMessagePersisterConfiguration getMessagePersisterConfiguration() {
return messagePersister;
}
diff --git a/service/src/main/java/org/whispersystems/textsecuregcm/configuration/dynamic/DynamicTurnConfiguration.java b/service/src/main/java/org/whispersystems/textsecuregcm/configuration/dynamic/DynamicTurnConfiguration.java
deleted file mode 100644
index 678883ab4..000000000
--- a/service/src/main/java/org/whispersystems/textsecuregcm/configuration/dynamic/DynamicTurnConfiguration.java
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- * Copyright 2013-2020 Signal Messenger, LLC
- * SPDX-License-Identifier: AGPL-3.0-only
- */
-
-package org.whispersystems.textsecuregcm.configuration.dynamic;
-
-import com.fasterxml.jackson.annotation.JsonProperty;
-import jakarta.validation.Valid;
-import java.util.Collections;
-import java.util.List;
-import org.whispersystems.textsecuregcm.configuration.TurnUriConfiguration;
-
-public class DynamicTurnConfiguration {
-
- @JsonProperty
- private String hostname;
-
- /**
- * Rate at which to prioritize a random turn URL to exercise all endpoints.
- * Based on a 100,000 basis, where 100,000 == 100%.
- */
- @JsonProperty
- private long randomizeRate = 5_000;
-
- /**
- * Number of instance ips to return in TURN routing request
- */
- @JsonProperty
- private int defaultInstanceIpCount = 0;
-
- @JsonProperty
- private List<@Valid TurnUriConfiguration> uriConfigs = Collections.emptyList();
-
- public List getUriConfigs() {
- return uriConfigs;
- }
-
- public long getRandomizeRate() {
- return randomizeRate;
- }
-
- public int getDefaultInstanceIpCount() {
- return defaultInstanceIpCount;
- }
-
- public String getHostname() {
- return hostname;
- }
-}
diff --git a/service/src/main/java/org/whispersystems/textsecuregcm/geo/MaxMindDatabaseManager.java b/service/src/main/java/org/whispersystems/textsecuregcm/geo/MaxMindDatabaseManager.java
deleted file mode 100644
index a58ba3b21..000000000
--- a/service/src/main/java/org/whispersystems/textsecuregcm/geo/MaxMindDatabaseManager.java
+++ /dev/null
@@ -1,102 +0,0 @@
-/*
- * Copyright 2023 Signal Messenger, LLC
- * SPDX-License-Identifier: AGPL-3.0-only
- */
-
-package org.whispersystems.textsecuregcm.geo;
-
-import com.maxmind.db.CHMCache;
-import com.maxmind.geoip2.DatabaseReader;
-import io.dropwizard.lifecycle.Managed;
-import io.micrometer.core.instrument.Metrics;
-import io.micrometer.core.instrument.Timer;
-import java.io.BufferedInputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.util.concurrent.ScheduledExecutorService;
-import java.util.concurrent.atomic.AtomicReference;
-import java.util.function.Supplier;
-import org.apache.commons.compress.archivers.ArchiveEntry;
-import org.apache.commons.compress.archivers.tar.TarArchiveInputStream;
-import org.apache.commons.compress.compressors.gzip.GzipCompressorInputStream;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.whispersystems.textsecuregcm.configuration.S3ObjectMonitorFactory;
-import org.whispersystems.textsecuregcm.metrics.MetricsUtil;
-import org.whispersystems.textsecuregcm.s3.S3ObjectMonitor;
-import software.amazon.awssdk.auth.credentials.AwsCredentialsProvider;
-
-public class MaxMindDatabaseManager implements Supplier, Managed {
-
- private final S3ObjectMonitor databaseMonitor;
-
- private final AtomicReference databaseReader = new AtomicReference<>();
-
- private final String databaseTag;
-
- private final Timer refreshTimer;
-
- private static final Logger log = LoggerFactory.getLogger(MaxMindDatabaseManager.class);
-
- public MaxMindDatabaseManager(final ScheduledExecutorService executorService,
- final AwsCredentialsProvider awsCredentialsProvider, final S3ObjectMonitorFactory configuration,
- final String databaseTag) {
-
- this.databaseMonitor = configuration.build(awsCredentialsProvider, executorService);
- this.databaseTag = databaseTag;
- this.refreshTimer = Metrics.timer(MetricsUtil.name(MaxMindDatabaseManager.class, "refresh"), "db", databaseTag);
- }
-
- private void handleDatabaseChanged(final InputStream inputStream) {
- refreshTimer.record(() -> {
- boolean foundDatabaseEntry = false;
-
- try (final InputStream bufferedInputStream = new BufferedInputStream(inputStream);
- final GzipCompressorInputStream gzipInputStream = new GzipCompressorInputStream(bufferedInputStream);
- final TarArchiveInputStream tarInputStream = new TarArchiveInputStream(gzipInputStream)) {
-
- ArchiveEntry nextEntry;
-
- while ((nextEntry = tarInputStream.getNextEntry()) != null) {
- if (nextEntry.getName().toLowerCase().endsWith(".mmdb")) {
- foundDatabaseEntry = true;
-
- final DatabaseReader oldReader = databaseReader.getAndSet(
- new DatabaseReader.Builder(tarInputStream).withCache(new CHMCache()).build()
- );
- if (oldReader != null) {
- oldReader.close();
- }
- break;
- }
- }
- } catch (final IOException e) {
- log.error(String.format("Failed to load MaxMind database, tag %s", databaseTag));
- }
-
- if (!foundDatabaseEntry) {
- log.warn(String.format("No .mmdb entry loaded from input stream, tag %s", databaseTag));
- }
- });
- }
-
- @Override
- public void start() throws Exception {
- databaseMonitor.start(this::handleDatabaseChanged);
- }
-
- @Override
- public void stop() throws Exception {
- databaseMonitor.stop();
-
- final DatabaseReader reader = databaseReader.getAndSet(null);
- if (reader != null) {
- reader.close();
- }
- }
-
- @Override
- public DatabaseReader get() {
- return this.databaseReader.get();
- }
-}
diff --git a/service/src/test/java/org/whispersystems/textsecuregcm/calls/routing/CallDnsRecordsManagerTest.java b/service/src/test/java/org/whispersystems/textsecuregcm/calls/routing/CallDnsRecordsManagerTest.java
deleted file mode 100644
index 24fb6075d..000000000
--- a/service/src/test/java/org/whispersystems/textsecuregcm/calls/routing/CallDnsRecordsManagerTest.java
+++ /dev/null
@@ -1,101 +0,0 @@
-/*
- * Copyright 2024 Signal Messenger, LLC
- * SPDX-License-Identifier: AGPL-3.0-only
- */
-
-package org.whispersystems.textsecuregcm.calls.routing;
-
-import org.junit.jupiter.api.Test;
-import java.io.ByteArrayInputStream;
-import java.io.IOException;
-import java.net.InetAddress;
-import java.net.UnknownHostException;
-import java.nio.charset.StandardCharsets;
-import java.util.Map;
-import java.util.stream.Stream;
-
-import static org.assertj.core.api.AssertionsForClassTypes.assertThat;
-
-public class CallDnsRecordsManagerTest {
-
- @Test
- public void testParseDnsRecords() throws IOException {
- var input = """
- {
- "aByRegion": {
- "datacenter-1": [
- "127.0.0.1"
- ],
- "datacenter-2": [
- "127.0.0.2",
- "127.0.0.3"
- ],
- "datacenter-3": [
- "127.0.0.4",
- "127.0.0.5"
- ],
- "datacenter-4": [
- "127.0.0.6",
- "127.0.0.7"
- ]
- },
- "aaaaByRegion": {
- "datacenter-1": [
- "2600:1111:2222:3333:0:20:0:0",
- "2600:1111:2222:3333:0:21:0:0",
- "2600:1111:2222:3333:0:22:0:0"
- ],
- "datacenter-2": [
- "2600:1111:2222:3333:0:23:0:0",
- "2600:1111:2222:3333:0:24:0:0"
- ],
- "datacenter-3": [
- "2600:1111:2222:3333:0:25:0:0",
- "2600:1111:2222:3333:0:26:0:0"
- ],
- "datacenter-4": [
- "2600:1111:2222:3333:0:27:0:0"
- ]
- }
- }
- """;
-
- var actual = CallDnsRecordsManager.parseRecords(new ByteArrayInputStream(input.getBytes(StandardCharsets.UTF_8)));
- var expected = new CallDnsRecords(
- Map.of(
- "datacenter-1", Stream.of("127.0.0.1").map(this::getAddressByName).toList(),
- "datacenter-2", Stream.of("127.0.0.2", "127.0.0.3").map(this::getAddressByName).toList(),
- "datacenter-3", Stream.of("127.0.0.4", "127.0.0.5").map(this::getAddressByName).toList(),
- "datacenter-4", Stream.of("127.0.0.6", "127.0.0.7").map(this::getAddressByName).toList()
- ),
- Map.of(
- "datacenter-1", Stream.of(
- "2600:1111:2222:3333:0:20:0:0",
- "2600:1111:2222:3333:0:21:0:0",
- "2600:1111:2222:3333:0:22:0:0"
- ).map(this::getAddressByName).toList(),
- "datacenter-2", Stream.of(
- "2600:1111:2222:3333:0:23:0:0",
- "2600:1111:2222:3333:0:24:0:0")
- .map(this::getAddressByName).toList(),
- "datacenter-3", Stream.of(
- "2600:1111:2222:3333:0:25:0:0",
- "2600:1111:2222:3333:0:26:0:0")
- .map(this::getAddressByName).toList(),
- "datacenter-4", Stream.of(
- "2600:1111:2222:3333:0:27:0:0"
- ).map(this::getAddressByName).toList()
- )
- );
-
- assertThat(actual).isEqualTo(expected);
- }
-
- InetAddress getAddressByName(String ip) {
- try {
- return InetAddress.getByName(ip) ;
- } catch (UnknownHostException e) {
- throw new RuntimeException(e);
- }
- }
-}
diff --git a/service/src/test/java/org/whispersystems/textsecuregcm/calls/routing/CallRoutingTableParserTest.java b/service/src/test/java/org/whispersystems/textsecuregcm/calls/routing/CallRoutingTableParserTest.java
deleted file mode 100644
index a0427a59a..000000000
--- a/service/src/test/java/org/whispersystems/textsecuregcm/calls/routing/CallRoutingTableParserTest.java
+++ /dev/null
@@ -1,245 +0,0 @@
-/*
- * Copyright 2024 Signal Messenger, LLC
- * SPDX-License-Identifier: AGPL-3.0-only
- */
-
-package org.whispersystems.textsecuregcm.calls.routing;
-
-import org.junit.jupiter.api.Test;
-import static org.assertj.core.api.Assertions.assertThat;
-
-import java.io.IOException;
-import java.io.StringReader;
-import java.util.List;
-import java.util.Map;
-import java.util.Optional;
-
-public class CallRoutingTableParserTest {
-
- @Test
- public void testParserSuccess() throws IOException {
- var input =
- """
- 192.1.12.0/24 datacenter-1 datacenter-2 datacenter-3
- 193.123.123.0/24 datacenter-1 datacenter-2
- 1.123.123.0/24 datacenter-1
-
- 2001:db8:b0aa::/48 datacenter-1
- 2001:db8:b0ab::/48 datacenter-3 datacenter-1 datacenter-2
- 2001:db8:b0ac::/48 datacenter-2 datacenter-1
-
- SA-SR-v4 datacenter-3
- SA-UY-v4 datacenter-3 datacenter-1 datacenter-2
- NA-US-VA-v6 datacenter-2 datacenter-1
- """;
- var actual = CallRoutingTableParser.fromTsv(new StringReader(input));
- var expected = new CallRoutingTable(
- Map.of(
- (CidrBlock.IpV4CidrBlock) CidrBlock.parseCidrBlock("192.1.12.0/24"), List.of("datacenter-1", "datacenter-2", "datacenter-3"),
- (CidrBlock.IpV4CidrBlock) CidrBlock.parseCidrBlock("193.123.123.0/24"), List.of("datacenter-1", "datacenter-2"),
- (CidrBlock.IpV4CidrBlock) CidrBlock.parseCidrBlock("1.123.123.0/24"), List.of("datacenter-1")
- ),
- Map.of(
- (CidrBlock.IpV6CidrBlock) CidrBlock.parseCidrBlock("2001:db8:b0aa::/48"), List.of("datacenter-1"),
- (CidrBlock.IpV6CidrBlock) CidrBlock.parseCidrBlock("2001:db8:b0ab::/48"), List.of("datacenter-3", "datacenter-1", "datacenter-2"),
- (CidrBlock.IpV6CidrBlock) CidrBlock.parseCidrBlock("2001:db8:b0ac::/48"), List.of("datacenter-2", "datacenter-1")
- ),
- Map.of(
- new CallRoutingTable.GeoKey("SA", "SR", Optional.empty(), CallRoutingTable.Protocol.v4), List.of("datacenter-3"),
- new CallRoutingTable.GeoKey("SA", "UY", Optional.empty(), CallRoutingTable.Protocol.v4), List.of("datacenter-3", "datacenter-1", "datacenter-2"),
- new CallRoutingTable.GeoKey("NA", "US", Optional.of("VA"), CallRoutingTable.Protocol.v6), List.of("datacenter-2", "datacenter-1")
- )
- );
-
- assertThat(actual).isEqualTo(expected);
- }
-
- @Test
- public void testParserVariousWhitespaceSuccess() throws IOException {
- var input =
- """
-
- 192.1.12.0/24\t \tdatacenter-1\t\t datacenter-2 datacenter-3
- \t193.123.123.0/24\tdatacenter-1\tdatacenter-2
-
-
- 1.123.123.0/24\t datacenter-1
- 2001:db8:b0aa::/48\t \tdatacenter-1
- 2001:db8:b0ab::/48 \tdatacenter-3\tdatacenter-1 datacenter-2
- 2001:db8:b0ac::/48\tdatacenter-2\tdatacenter-1
-
-
-
-
-
-
- SA-SR-v4 datacenter-3
-
-
-
-
- SA-UY-v4\tdatacenter-3\tdatacenter-1\tdatacenter-2
- NA-US-VA-v6 datacenter-2 \tdatacenter-1
- """;
- var actual = CallRoutingTableParser.fromTsv(new StringReader(input));
- var expected = new CallRoutingTable(
- Map.of(
- (CidrBlock.IpV4CidrBlock) CidrBlock.parseCidrBlock("192.1.12.0/24"), List.of("datacenter-1", "datacenter-2", "datacenter-3"),
- (CidrBlock.IpV4CidrBlock) CidrBlock.parseCidrBlock("193.123.123.0/24"), List.of("datacenter-1", "datacenter-2"),
- (CidrBlock.IpV4CidrBlock) CidrBlock.parseCidrBlock("1.123.123.0/24"), List.of("datacenter-1")
- ),
- Map.of(
- (CidrBlock.IpV6CidrBlock) CidrBlock.parseCidrBlock("2001:db8:b0aa::/48"), List.of("datacenter-1"),
- (CidrBlock.IpV6CidrBlock) CidrBlock.parseCidrBlock("2001:db8:b0ab::/48"), List.of("datacenter-3", "datacenter-1", "datacenter-2"),
- (CidrBlock.IpV6CidrBlock) CidrBlock.parseCidrBlock("2001:db8:b0ac::/48"), List.of("datacenter-2", "datacenter-1")
- ),
- Map.of(
- new CallRoutingTable.GeoKey("SA", "SR", Optional.empty(), CallRoutingTable.Protocol.v4), List.of("datacenter-3"),
- new CallRoutingTable.GeoKey("SA", "UY", Optional.empty(), CallRoutingTable.Protocol.v4), List.of("datacenter-3", "datacenter-1", "datacenter-2"),
- new CallRoutingTable.GeoKey("NA", "US", Optional.of("VA"), CallRoutingTable.Protocol.v6), List.of("datacenter-2", "datacenter-1")
- )
- );
-
- assertThat(actual).isEqualTo(expected);
- }
-
- @Test
- public void testParserMissingSection() throws IOException {
- var input =
- """
- 192.1.12.0/24\t \tdatacenter-1\t\t datacenter-2 datacenter-3
- 193.123.123.0/24\tdatacenter-1\tdatacenter-2
- 1.123.123.0/24\t datacenter-1
-
- SA-SR-v4 datacenter-3
- SA-UY-v4\tdatacenter-3\tdatacenter-1\tdatacenter-2
- NA-US-VA-v6 datacenter-2 \tdatacenter-1
- """;
- var actual = CallRoutingTableParser.fromTsv(new StringReader(input));
- var expected = new CallRoutingTable(
- Map.of(
- (CidrBlock.IpV4CidrBlock) CidrBlock.parseCidrBlock("192.1.12.0/24"), List.of("datacenter-1", "datacenter-2", "datacenter-3"),
- (CidrBlock.IpV4CidrBlock) CidrBlock.parseCidrBlock("193.123.123.0/24"), List.of("datacenter-1", "datacenter-2"),
- (CidrBlock.IpV4CidrBlock) CidrBlock.parseCidrBlock("1.123.123.0/24"), List.of("datacenter-1")
- ),
- Map.of(),
- Map.of(
- new CallRoutingTable.GeoKey("SA", "SR", Optional.empty(), CallRoutingTable.Protocol.v4), List.of("datacenter-3"),
- new CallRoutingTable.GeoKey("SA", "UY", Optional.empty(), CallRoutingTable.Protocol.v4), List.of("datacenter-3", "datacenter-1", "datacenter-2"),
- new CallRoutingTable.GeoKey("NA", "US", Optional.of("VA"), CallRoutingTable.Protocol.v6), List.of("datacenter-2", "datacenter-1")
- )
- );
-
- assertThat(actual).isEqualTo(expected);
- }
-
-
- @Test
- public void testParserMixedSections() throws IOException {
- var input =
- """
-
-
- 1.123.123.0/24\t datacenter-1
- 2001:db8:b0aa::/48\t \tdatacenter-1
- 2001:db8:b0ab::/48 \tdatacenter-3\tdatacenter-1 datacenter-2
- 2001:db8:b0ac::/48\tdatacenter-2\tdatacenter-1
-
-
-
- 192.1.12.0/24\t \tdatacenter-1\t\t datacenter-2 datacenter-3
- 193.123.123.0/24\tdatacenter-1\tdatacenter-2
-
-
-
- SA-SR-v4 datacenter-3
-
-
-
-
- SA-UY-v4\tdatacenter-3\tdatacenter-1\tdatacenter-2
- NA-US-VA-v6 datacenter-2 \tdatacenter-1
- """;
- var actual = CallRoutingTableParser.fromTsv(new StringReader(input));
- var expected = new CallRoutingTable(
- Map.of(
- (CidrBlock.IpV4CidrBlock) CidrBlock.parseCidrBlock("1.123.123.0/24"), List.of("datacenter-1"),
- (CidrBlock.IpV4CidrBlock) CidrBlock.parseCidrBlock("192.1.12.0/24"), List.of("datacenter-1", "datacenter-2", "datacenter-3"),
- (CidrBlock.IpV4CidrBlock) CidrBlock.parseCidrBlock("193.123.123.0/24"), List.of("datacenter-1", "datacenter-2")
- ),
- Map.of(
- (CidrBlock.IpV6CidrBlock) CidrBlock.parseCidrBlock("2001:db8:b0aa::/48"), List.of("datacenter-1"),
- (CidrBlock.IpV6CidrBlock) CidrBlock.parseCidrBlock("2001:db8:b0ab::/48"), List.of("datacenter-3", "datacenter-1", "datacenter-2"),
- (CidrBlock.IpV6CidrBlock) CidrBlock.parseCidrBlock("2001:db8:b0ac::/48"), List.of("datacenter-2", "datacenter-1")
- ),
- Map.of(
- new CallRoutingTable.GeoKey("SA", "SR", Optional.empty(), CallRoutingTable.Protocol.v4), List.of("datacenter-3"),
- new CallRoutingTable.GeoKey("SA", "UY", Optional.empty(), CallRoutingTable.Protocol.v4), List.of("datacenter-3", "datacenter-1", "datacenter-2"),
- new CallRoutingTable.GeoKey("NA", "US", Optional.of("VA"), CallRoutingTable.Protocol.v6), List.of("datacenter-2", "datacenter-1")
- )
- );
-
- assertThat(actual).isEqualTo(expected);
- }
-
- @Test
- public void testJsonParserSuccess() throws IOException {
- var input =
- """
- {
- "ipv4GeoToDataCenters": {
- "SA-SR": ["datacenter-3"],
- "SA-UY": ["datacenter-3", "datacenter-1", "datacenter-2"]
- },
- "ipv6GeoToDataCenters": {
- "NA-US-VA": ["datacenter-2", "datacenter-1"]
- },
- "ipv4SubnetsToDatacenters": {
- "192.1.12.0": ["datacenter-1", "datacenter-2", "datacenter-3"],
- "193.123.123.0": ["datacenter-1", "datacenter-2"],
- "1.123.123.0": ["datacenter-1"]
- },
- "ipv6SubnetsToDatacenters": {
- "2001:db8:b0aa::": ["datacenter-1"],
- "2001:db8:b0ab::": ["datacenter-3", "datacenter-1", "datacenter-2"],
- "2001:db8:b0ac::": ["datacenter-2", "datacenter-1"]
- }
- }
- """;
- var actual = CallRoutingTableParser.fromJson(new StringReader(input));
- var expected = new CallRoutingTable(
- Map.of(
- (CidrBlock.IpV4CidrBlock) CidrBlock.parseCidrBlock("192.1.12.0/24"), List.of("datacenter-1", "datacenter-2", "datacenter-3"),
- (CidrBlock.IpV4CidrBlock) CidrBlock.parseCidrBlock("193.123.123.0/24"), List.of("datacenter-1", "datacenter-2"),
- (CidrBlock.IpV4CidrBlock) CidrBlock.parseCidrBlock("1.123.123.0/24"), List.of("datacenter-1")
- ),
- Map.of(
- (CidrBlock.IpV6CidrBlock) CidrBlock.parseCidrBlock("2001:db8:b0aa::/48"), List.of("datacenter-1"),
- (CidrBlock.IpV6CidrBlock) CidrBlock.parseCidrBlock("2001:db8:b0ab::/48"), List.of("datacenter-3", "datacenter-1", "datacenter-2"),
- (CidrBlock.IpV6CidrBlock) CidrBlock.parseCidrBlock("2001:db8:b0ac::/48"), List.of("datacenter-2", "datacenter-1")
- ),
- Map.of(
- new CallRoutingTable.GeoKey("SA", "SR", Optional.empty(), CallRoutingTable.Protocol.v4), List.of("datacenter-3"),
- new CallRoutingTable.GeoKey("SA", "UY", Optional.empty(), CallRoutingTable.Protocol.v4), List.of("datacenter-3", "datacenter-1", "datacenter-2"),
- new CallRoutingTable.GeoKey("NA", "US", Optional.of("VA"), CallRoutingTable.Protocol.v6), List.of("datacenter-2", "datacenter-1")
- )
- );
-
- assertThat(actual).isEqualTo(expected);
- }
-
- @Test
- public void testParseVariousEdgeCases() throws IOException {
- var input =
- """
- {
- "ipv4GeoToDataCenters": {},
- "ipv6GeoToDataCenters": {},
- "ipv4SubnetsToDatacenters": {},
- "ipv6SubnetsToDatacenters": {}
- }
- """;
- assertThat(CallRoutingTableParser.fromJson(new StringReader(input))).isEqualTo(CallRoutingTable.empty());
- assertThat(CallRoutingTableParser.fromJson(new StringReader("{}"))).isEqualTo(CallRoutingTable.empty());
- }
-}
diff --git a/service/src/test/java/org/whispersystems/textsecuregcm/calls/routing/CallRoutingTableTest.java b/service/src/test/java/org/whispersystems/textsecuregcm/calls/routing/CallRoutingTableTest.java
deleted file mode 100644
index 0f601f7f0..000000000
--- a/service/src/test/java/org/whispersystems/textsecuregcm/calls/routing/CallRoutingTableTest.java
+++ /dev/null
@@ -1,139 +0,0 @@
-/*
- * Copyright 2024 Signal Messenger, LLC
- * SPDX-License-Identifier: AGPL-3.0-only
- */
-
-package org.whispersystems.textsecuregcm.calls.routing;
-
-import static org.assertj.core.api.AssertionsForClassTypes.assertThat;
-
-import java.net.Inet4Address;
-import java.net.Inet6Address;
-import java.net.UnknownHostException;
-import java.util.List;
-import java.util.Map;
-import java.util.Optional;
-import org.junit.jupiter.api.Test;
-
-public class CallRoutingTableTest {
-
- static final CallRoutingTable basicTable = new CallRoutingTable(
- Map.of(
- (CidrBlock.IpV4CidrBlock) CidrBlock.parseCidrBlock("192.1.12.0/24"), List.of("datacenter-1", "datacenter-2", "datacenter-3"),
- (CidrBlock.IpV4CidrBlock) CidrBlock.parseCidrBlock("193.123.123.0/24"), List.of("datacenter-1", "datacenter-2"),
- (CidrBlock.IpV4CidrBlock) CidrBlock.parseCidrBlock("1.123.123.0/24"), List.of("datacenter-4")
- ),
- Map.of(
- (CidrBlock.IpV6CidrBlock) CidrBlock.parseCidrBlock("2001:db8:b0aa::/48"), List.of("datacenter-1"),
- (CidrBlock.IpV6CidrBlock) CidrBlock.parseCidrBlock("2001:db8:b0ab::/48"), List.of("datacenter-3", "datacenter-1", "datacenter-2"),
- (CidrBlock.IpV6CidrBlock) CidrBlock.parseCidrBlock("2001:db8:b0ac::/48"), List.of("datacenter-2", "datacenter-1")
- ),
- Map.of(
- new CallRoutingTable.GeoKey("SA", "SR", Optional.empty(), CallRoutingTable.Protocol.v4), List.of("datacenter-3"),
- new CallRoutingTable.GeoKey("SA", "UY", Optional.empty(), CallRoutingTable.Protocol.v4), List.of("datacenter-3", "datacenter-1", "datacenter-2"),
- new CallRoutingTable.GeoKey("NA", "US", Optional.of("VA"), CallRoutingTable.Protocol.v6), List.of("datacenter-2", "datacenter-1"),
- new CallRoutingTable.GeoKey("NA", "US", Optional.empty(), CallRoutingTable.Protocol.v6), List.of("datacenter-3", "datacenter-4")
- )
- );
-
- // has overlapping subnets
- static final CallRoutingTable overlappingTable = new CallRoutingTable(
- Map.of(
- (CidrBlock.IpV4CidrBlock) CidrBlock.parseCidrBlock("192.1.12.0/24"), List.of("datacenter-1", "datacenter-2", "datacenter-3"),
- (CidrBlock.IpV4CidrBlock) CidrBlock.parseCidrBlock("1.123.123.0/24"), List.of("datacenter-4"),
- (CidrBlock.IpV4CidrBlock) CidrBlock.parseCidrBlock("1.123.0.0/16"), List.of("datacenter-1")
- ),
- Map.of(
- (CidrBlock.IpV6CidrBlock) CidrBlock.parseCidrBlock("2001:db8:b0aa::/48"), List.of("datacenter-1"),
- (CidrBlock.IpV6CidrBlock) CidrBlock.parseCidrBlock("2001:db8:b0ac::/48"), List.of("datacenter-3", "datacenter-1", "datacenter-2"),
- (CidrBlock.IpV6CidrBlock) CidrBlock.parseCidrBlock("2001:db8:b0a0::/44"), List.of("datacenter-2", "datacenter-1")
- ),
- Map.of(
- new CallRoutingTable.GeoKey("SA", "SR", Optional.empty(), CallRoutingTable.Protocol.v4), List.of("datacenter-3"),
- new CallRoutingTable.GeoKey("SA", "UY", Optional.empty(), CallRoutingTable.Protocol.v4), List.of("datacenter-3", "datacenter-1", "datacenter-2"),
- new CallRoutingTable.GeoKey("NA", "US", Optional.of("VA"), CallRoutingTable.Protocol.v6), List.of("datacenter-2", "datacenter-1")
- )
- );
-
- @Test
- void testGetFastestDataCentersBySubnet() throws UnknownHostException {
- var v4address = Inet4Address.getByName("1.123.123.1");
- var actualV4 = basicTable.getDatacentersBySubnet(v4address);
- assertThat(actualV4).isEqualTo(List.of("datacenter-4"));
-
- var v6address = Inet6Address.getByName("2001:db8:b0ac:aaaa:aaaa:aaaa:aaaa:0001");
- var actualV6 = basicTable.getDatacentersBySubnet(v6address);
- assertThat(actualV6).isEqualTo(List.of("datacenter-2", "datacenter-1"));
- }
-
- @Test
- void testGetFastestDataCentersBySubnetOverlappingTable() throws UnknownHostException {
- var v4address = Inet4Address.getByName("1.123.123.1");
- var actualV4 = overlappingTable.getDatacentersBySubnet(v4address);
- assertThat(actualV4).isEqualTo(List.of("datacenter-4"));
-
- var v6address = Inet6Address.getByName("2001:db8:b0ac:aaaa:aaaa:aaaa:aaaa:0001");
- var actualV6 = overlappingTable.getDatacentersBySubnet(v6address);
- assertThat(actualV6).isEqualTo(List.of("datacenter-3", "datacenter-1", "datacenter-2"));
- }
-
- @Test
- void testGetFastestDataCentersByGeo() {
- var actual = basicTable.getDatacentersByGeo("SA", "SR", Optional.empty());
- assertThat(actual).isEqualTo(List.of("datacenter-3"));
-
- var actualWithSubdvision = basicTable.getDatacentersByGeo("NA", "US", Optional.of("VA"));
- assertThat(actualWithSubdvision).isEqualTo(List.of("datacenter-2", "datacenter-1"));
- }
-
- @Test
- void testGetFastestDataCentersByGeoFallback() {
- var actualExactMatch = basicTable.getDatacentersByGeo("NA", "US", Optional.of("VA"));
- assertThat(actualExactMatch).isEqualTo(List.of("datacenter-2", "datacenter-1"));
-
- var actualApproximateMatch = basicTable.getDatacentersByGeo("NA", "US", Optional.of("MD"));
- assertThat(actualApproximateMatch).isEqualTo(List.of("datacenter-3", "datacenter-4"));
- }
-
- @Test
- void testGetFastestDatacentersPrioritizesSubnet() throws UnknownHostException {
- var v4address = Inet4Address.getByName("1.123.123.1");
- var actual = basicTable.getDatacentersFor(v4address, "NA", "US", Optional.of("VA"));
- assertThat(actual).isEqualTo(List.of("datacenter-4", "datacenter-2", "datacenter-1"));
- }
-
- @Test
- void testGetFastestDatacentersEmptySubnet() throws UnknownHostException {
- var v4address = Inet4Address.getByName("200.200.123.1");
- var actual = basicTable.getDatacentersFor(v4address, "NA", "US", Optional.of("VA"));
- assertThat(actual).isEqualTo(List.of("datacenter-2", "datacenter-1"));
- }
-
- @Test
- void testGetFastestDatacentersEmptySubnetTakesExtraFromGeo() throws UnknownHostException {
- var v4address = Inet4Address.getByName("200.200.123.1");
- var actual = basicTable.getDatacentersFor(v4address, "SA", "UY", Optional.empty());
- assertThat(actual).isEqualTo(List.of("datacenter-3", "datacenter-1", "datacenter-2"));
- }
-
- @Test
- void testGetFastestDatacentersEmptyGeoResults() throws UnknownHostException {
- var v4address = Inet4Address.getByName("1.123.123.1");
- var actual = basicTable.getDatacentersFor(v4address, "ZZ", "AA", Optional.empty());
- assertThat(actual).isEqualTo(List.of("datacenter-4"));
- }
-
- @Test
- void testGetFastestDatacentersEmptyGeoTakesFromSubnet() throws UnknownHostException {
- var v4address = Inet4Address.getByName("192.1.12.1");
- var actual = basicTable.getDatacentersFor(v4address, "ZZ", "AA", Optional.empty());
- assertThat(actual).isEqualTo(List.of("datacenter-1", "datacenter-2", "datacenter-3"));
- }
-
- @Test
- void testGetFastestDatacentersDistinct() throws UnknownHostException {
- var v6address = Inet6Address.getByName("2001:db8:b0ac:aaaa:aaaa:aaaa:aaaa:0001");
- var actual = basicTable.getDatacentersFor(v6address, "NA", "US", Optional.of("VA"));
- assertThat(actual).isEqualTo(List.of("datacenter-2", "datacenter-1"));
- }
-}
diff --git a/service/src/test/java/org/whispersystems/textsecuregcm/calls/routing/CidrBlockTest.java b/service/src/test/java/org/whispersystems/textsecuregcm/calls/routing/CidrBlockTest.java
deleted file mode 100644
index 74aa2d6d1..000000000
--- a/service/src/test/java/org/whispersystems/textsecuregcm/calls/routing/CidrBlockTest.java
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- * Copyright 2024 Signal Messenger, LLC
- * SPDX-License-Identifier: AGPL-3.0-only
- */
-
-package org.whispersystems.textsecuregcm.calls.routing;
-
-import org.junit.jupiter.api.Test;
-
-import java.math.BigInteger;
-import java.net.InetAddress;
-import java.net.UnknownHostException;
-import java.util.HexFormat;
-
-import static org.assertj.core.api.Assertions.assertThat;
-
-public class CidrBlockTest {
-
- private HexFormat hex = HexFormat.ofDelimiter(":").withLowerCase();
-
- @Test
- public void testIPv4CidrBlockParseSuccess() {
- var actual = CidrBlock.parseCidrBlock("255.32.15.0/24");
- var expected = new CidrBlock.IpV4CidrBlock(0xFF_20_0F_00, 0xFFFFFF00, 24);
-
- assertThat(actual).isInstanceOf(CidrBlock.IpV4CidrBlock.class);
- assertThat(actual).isEqualTo(expected);
- }
-
- @Test
- public void testIPv6CidrBlockParseSuccess() {
- var actual = CidrBlock.parseCidrBlock("2001:db8:b0aa::/48");
- var expected = new CidrBlock.IpV6CidrBlock(
- new BigInteger(hex.parseHex("20:01:0d:b8:b0:aa:00:00:00:00:00:00:00:00:00:00")),
- new BigInteger(hex.parseHex("FF:FF:FF:FF:FF:FF:00:00:00:00:00:00:00:00:00:00")),
- 48
- );
-
- assertThat(actual).isInstanceOf(CidrBlock.IpV6CidrBlock.class);
- assertThat(actual).isEqualTo(expected);
- }
-
- @Test
- public void testIPv4InBlock() throws UnknownHostException {
- var block = CidrBlock.parseCidrBlock("255.32.15.0/24");
-
- assertThat(block.ipInBlock(InetAddress.getByName("255.32.15.123"))).isTrue();
- assertThat(block.ipInBlock(InetAddress.getByName("255.32.15.0"))).isTrue();
- assertThat(block.ipInBlock(InetAddress.getByName("255.32.16.0"))).isFalse();
- assertThat(block.ipInBlock(InetAddress.getByName("255.33.15.0"))).isFalse();
- assertThat(block.ipInBlock(InetAddress.getByName("254.33.15.0"))).isFalse();
- }
-
- @Test
- public void testIPv6InBlock() throws UnknownHostException {
- var block = CidrBlock.parseCidrBlock("2001:db8:b0aa::/48");
-
- assertThat(block.ipInBlock(InetAddress.getByName("2001:db8:b0aa:1:1::"))).isTrue();
- assertThat(block.ipInBlock(InetAddress.getByName("2001:db8:b0aa:0:0::"))).isTrue();
- assertThat(block.ipInBlock(InetAddress.getByName("2001:db8:b0ab:1:1::"))).isFalse();
- assertThat(block.ipInBlock(InetAddress.getByName("2001:da8:b0aa:1:1::"))).isFalse();
- }
-}
diff --git a/service/src/test/java/org/whispersystems/textsecuregcm/calls/routing/DynamicConfigTurnRouterTest.java b/service/src/test/java/org/whispersystems/textsecuregcm/calls/routing/DynamicConfigTurnRouterTest.java
deleted file mode 100644
index 9465637d6..000000000
--- a/service/src/test/java/org/whispersystems/textsecuregcm/calls/routing/DynamicConfigTurnRouterTest.java
+++ /dev/null
@@ -1,137 +0,0 @@
-/*
- * Copyright 2024 Signal Messenger, LLC
- * SPDX-License-Identifier: AGPL-3.0-only
- */
-
-package org.whispersystems.textsecuregcm.calls.routing;
-
-import com.fasterxml.jackson.core.JsonProcessingException;
-import org.junit.jupiter.api.Test;
-import org.whispersystems.textsecuregcm.configuration.dynamic.DynamicConfiguration;
-import org.whispersystems.textsecuregcm.storage.DynamicConfigurationManager;
-import java.util.Collection;
-import java.util.List;
-import java.util.Map;
-import java.util.UUID;
-import java.util.stream.Collectors;
-import java.util.stream.Stream;
-
-import static org.assertj.core.api.Assertions.assertThat;
-import static org.junit.jupiter.api.Assertions.assertTrue;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.when;
-
-public class DynamicConfigTurnRouterTest {
- @Test
- public void testAlwaysSelectFirst() throws JsonProcessingException {
- final String configString = """
- captcha:
- scoreFloor: 1.0
- turn:
- uriConfigs:
- - uris:
- - always1.org
- - always2.org
- - uris:
- - never.org
- weight: 0
- """;
- DynamicConfiguration config = DynamicConfigurationManager
- .parseConfiguration(configString, DynamicConfiguration.class)
- .orElseThrow();
-
- @SuppressWarnings("unchecked")
- DynamicConfigurationManager mockDynamicConfigManager = mock(
- DynamicConfigurationManager.class);
-
- when(mockDynamicConfigManager.getConfiguration()).thenReturn(config);
-
- final DynamicConfigTurnRouter configTurnRouter = new DynamicConfigTurnRouter(mockDynamicConfigManager);
-
- final long COUNT = 1000;
-
- final Map urlCounts = Stream
- .generate(configTurnRouter::randomUrls)
- .limit(COUNT)
- .flatMap(Collection::stream)
- .collect(Collectors.groupingBy(i -> i, Collectors.counting()));
-
- assertThat(urlCounts.get("always1.org")).isEqualTo(COUNT);
- assertThat(urlCounts.get("always2.org")).isEqualTo(COUNT);
- assertThat(urlCounts).doesNotContainKey("never.org");
- }
-
- @Test
- public void testProbabilisticUrls() throws JsonProcessingException {
- final String configString = """
- captcha:
- scoreFloor: 1.0
- turn:
- uriConfigs:
- - uris:
- - always.org
- - sometimes1.org
- weight: 5
- - uris:
- - always.org
- - sometimes2.org
- weight: 5
- """;
- DynamicConfiguration config = DynamicConfigurationManager
- .parseConfiguration(configString, DynamicConfiguration.class)
- .orElseThrow();
-
- @SuppressWarnings("unchecked")
- DynamicConfigurationManager mockDynamicConfigManager = mock(
- DynamicConfigurationManager.class);
-
- when(mockDynamicConfigManager.getConfiguration()).thenReturn(config);
- final DynamicConfigTurnRouter configTurnRouter = new DynamicConfigTurnRouter(mockDynamicConfigManager);
-
- final long COUNT = 1000;
-
- final Map urlCounts = Stream
- .generate(configTurnRouter::randomUrls)
- .limit(COUNT)
- .flatMap(Collection::stream)
- .collect(Collectors.groupingBy(i -> i, Collectors.counting()));
-
- assertThat(urlCounts.get("always.org")).isEqualTo(COUNT);
- assertThat(urlCounts.get("sometimes1.org")).isGreaterThan(0);
- assertThat(urlCounts.get("sometimes2.org")).isGreaterThan(0);
- }
-
- @Test
- public void testExplicitEnrollment() throws JsonProcessingException {
- final String configString = """
- captcha:
- scoreFloor: 1.0
- turn:
- secret: bloop
- uriConfigs:
- - uris:
- - enrolled.org
- weight: 0
- enrolledAcis:
- - 732506d7-d04f-43a4-b1d7-8a3a91ebe8a6
- - uris:
- - unenrolled.org
- weight: 1
- """;
- DynamicConfiguration config = DynamicConfigurationManager
- .parseConfiguration(configString, DynamicConfiguration.class)
- .orElseThrow();
-
- @SuppressWarnings("unchecked")
- DynamicConfigurationManager mockDynamicConfigManager = mock(
- DynamicConfigurationManager.class);
-
- when(mockDynamicConfigManager.getConfiguration()).thenReturn(config);
- final DynamicConfigTurnRouter configTurnRouter = new DynamicConfigTurnRouter(mockDynamicConfigManager);
-
- List urls = configTurnRouter.targetedUrls(UUID.fromString("732506d7-d04f-43a4-b1d7-8a3a91ebe8a6"));
- assertThat(urls.getFirst()).isEqualTo("enrolled.org");
- urls = configTurnRouter.targetedUrls(UUID.randomUUID());
- assertTrue(urls.isEmpty());
- }
-}
diff --git a/service/src/test/java/org/whispersystems/textsecuregcm/calls/routing/TurnCallRouterTest.java b/service/src/test/java/org/whispersystems/textsecuregcm/calls/routing/TurnCallRouterTest.java
deleted file mode 100644
index 0d4687347..000000000
--- a/service/src/test/java/org/whispersystems/textsecuregcm/calls/routing/TurnCallRouterTest.java
+++ /dev/null
@@ -1,335 +0,0 @@
-/*
- * Copyright 2024 Signal Messenger, LLC
- * SPDX-License-Identifier: AGPL-3.0-only
- */
-
-package org.whispersystems.textsecuregcm.calls.routing;
-
-import com.maxmind.geoip2.DatabaseReader;
-import com.maxmind.geoip2.exception.GeoIp2Exception;
-import com.maxmind.geoip2.model.CityResponse;
-import com.maxmind.geoip2.record.Continent;
-import com.maxmind.geoip2.record.Country;
-import com.maxmind.geoip2.record.Subdivision;
-import org.junit.jupiter.api.BeforeEach;
-import org.junit.jupiter.api.Test;
-
-import java.io.IOException;
-import java.net.InetAddress;
-import java.net.UnknownHostException;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.List;
-import java.util.Map;
-import java.util.Optional;
-import java.util.UUID;
-
-import static org.assertj.core.api.AssertionsForClassTypes.assertThat;
-import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.when;
-
-public class TurnCallRouterTest {
-
- private final static String TEST_HOSTNAME = "subdomain.example.org";
- private final static List TEST_URLS_WITH_HOSTS = List.of(
- "stun:one.example.com",
- "turn:two.example.com",
- "turn:three.example.com?transport=tcp"
- );
- private final static List EXPECTED_TEST_URLS_WITH_HOSTS = List.of(
- "turn:two.example.com"
- );
-
- private CallRoutingTable performanceTable;
- private CallRoutingTable manualTable;
- private DynamicConfigTurnRouter configTurnRouter;
- private DatabaseReader geoIp;
- private Country country;
- private Continent continent;
- private CallDnsRecords callDnsRecords;
- private Subdivision subdivision;
- private UUID aci = UUID.randomUUID();
-
- @BeforeEach
- void setup() throws IOException, GeoIp2Exception {
- performanceTable = mock(CallRoutingTable.class);
- manualTable = mock(CallRoutingTable.class);
- configTurnRouter = mock(DynamicConfigTurnRouter.class);
- geoIp = mock(DatabaseReader.class);
- continent = mock(Continent.class);
- country = mock(Country.class);
- subdivision = mock(Subdivision.class);
- ArrayList subdivisions = new ArrayList<>();
- subdivisions.add(subdivision);
-
- when(geoIp.city(any())).thenReturn(new CityResponse(null, continent, country, null, null, null, null, null, subdivisions, null));
- setupDefault();
- }
-
- void setupDefault() {
- when(configTurnRouter.targetedUrls(any())).thenReturn(Collections.emptyList());
- when(configTurnRouter.randomUrls()).thenReturn(TEST_URLS_WITH_HOSTS);
- when(configTurnRouter.getHostname()).thenReturn(TEST_HOSTNAME);
- when(configTurnRouter.shouldRandomize()).thenReturn(false);
- when(manualTable.getDatacentersFor(any(), any(), any(), any())).thenReturn(Collections.emptyList());
- when(continent.getCode()).thenReturn("NA");
- when(country.getIsoCode()).thenReturn("US");
- when(subdivision.getIsoCode()).thenReturn("VA");
- try {
- callDnsRecords = new CallDnsRecords(
- Map.of(
- "dc-manual", List.of(InetAddress.getByName("1.1.1.1")),
- "dc-performance1", List.of(
- InetAddress.getByName("9.9.9.1"),
- InetAddress.getByName("9.9.9.2")
- ),
- "dc-performance2", List.of(InetAddress.getByName("9.9.9.3")),
- "dc-performance3", List.of(InetAddress.getByName("9.9.9.4")),
- "dc-performance4", List.of(
- InetAddress.getByName("9.9.9.5"),
- InetAddress.getByName("9.9.9.6"),
- InetAddress.getByName("9.9.9.7")
- )
- ),
- Map.of(
- "dc-manual", List.of(InetAddress.getByName("2222:1111:0:dead::")),
- "dc-performance1", List.of(
- InetAddress.getByName("2222:1111:0:abc0::"),
- InetAddress.getByName("2222:1111:0:abc1::")
- ),
- "dc-performance2", List.of(InetAddress.getByName("2222:1111:0:abc2::")),
- "dc-performance3", List.of(InetAddress.getByName("2222:1111:0:abc3::")),
- "dc-performance4", List.of(
- InetAddress.getByName("2222:1111:0:abc4::"),
- InetAddress.getByName("2222:1111:0:abc5::"),
- InetAddress.getByName("2222:1111:0:abc6::")
- )
- )
- );
- } catch (UnknownHostException e) {
- throw new RuntimeException(e);
- }
- }
-
- private TurnCallRouter router() {
- return new TurnCallRouter(
- () -> callDnsRecords,
- () -> performanceTable,
- () -> manualTable,
- configTurnRouter,
- () -> geoIp,
- // set to true so the return values are predictable
- true
- );
- }
-
- TurnServerOptions optionsWithUrls(List urls) {
- return new TurnServerOptions(
- TEST_HOSTNAME,
- Optional.of(urls),
- Optional.of(EXPECTED_TEST_URLS_WITH_HOSTS)
- );
- }
-
- @Test
- public void testPrioritizesTargetedUrls() throws UnknownHostException {
- List targetedUrls = List.of(
- "targeted1.example.com",
- "targeted.example.com"
- );
- when(configTurnRouter.targetedUrls(any()))
- .thenReturn(targetedUrls);
-
- assertThat(router().getRoutingFor(aci, Optional.of(InetAddress.getByName("0.0.0.1")), 10))
- .isEqualTo(new TurnServerOptions(
- TEST_HOSTNAME,
- Optional.empty(),
- Optional.of(targetedUrls)
- ));
- }
-
- @Test
- public void testRandomizes() throws UnknownHostException {
- when(configTurnRouter.shouldRandomize())
- .thenReturn(true);
-
- assertThat(router().getRoutingFor(aci, Optional.of(InetAddress.getByName("0.0.0.1")), 10))
- .isEqualTo(new TurnServerOptions(
- TEST_HOSTNAME,
- Optional.empty(),
- Optional.of(TEST_URLS_WITH_HOSTS)
- ));
- }
-
- @Test
- public void testUrlsOnlyNoInstanceIps() throws UnknownHostException {
- when(performanceTable.getDatacentersFor(any(), any(), any(), any()))
- .thenReturn(List.of("dc-performance2", "dc-performance1"));
- when(configTurnRouter.shouldRandomize())
- .thenReturn(false);
-
- assertThat(router().getRoutingFor(aci, Optional.of(InetAddress.getByName("0.0.0.1")), 0))
- .isEqualTo(new TurnServerOptions(
- TEST_HOSTNAME,
- Optional.empty(),
- Optional.of(TEST_URLS_WITH_HOSTS)
- ));
- }
-
- @Test
- public void testOrderedByPerformance() throws UnknownHostException {
- when(performanceTable.getDatacentersFor(any(), any(), any(), any()))
- .thenReturn(List.of("dc-performance2", "dc-performance1"));
-
- assertThat(router().getRoutingFor(aci, Optional.of(InetAddress.getByName("0.0.0.1")), 10))
- .isEqualTo(optionsWithUrls(List.of(
- "turn:9.9.9.3",
- "turn:9.9.9.3:80?transport=tcp",
- "turns:9.9.9.3:443?transport=tcp",
-
- "turn:9.9.9.1",
- "turn:9.9.9.1:80?transport=tcp",
- "turns:9.9.9.1:443?transport=tcp",
-
- "turn:9.9.9.2",
- "turn:9.9.9.2:80?transport=tcp",
- "turns:9.9.9.2:443?transport=tcp",
-
- "turn:[2222:1111:0:abc2:0:0:0:0]",
- "turn:[2222:1111:0:abc2:0:0:0:0]:80?transport=tcp",
- "turns:[2222:1111:0:abc2:0:0:0:0]:443?transport=tcp",
-
- "turn:[2222:1111:0:abc0:0:0:0:0]",
- "turn:[2222:1111:0:abc0:0:0:0:0]:80?transport=tcp",
- "turns:[2222:1111:0:abc0:0:0:0:0]:443?transport=tcp",
-
- "turn:[2222:1111:0:abc1:0:0:0:0]",
- "turn:[2222:1111:0:abc1:0:0:0:0]:80?transport=tcp",
- "turns:[2222:1111:0:abc1:0:0:0:0]:443?transport=tcp"
- )));
- }
-
- @Test
- public void testPrioritizesManualRecords() throws UnknownHostException {
- when(performanceTable.getDatacentersFor(any(), any(), any(), any()))
- .thenReturn(List.of("dc-performance1"));
- when(manualTable.getDatacentersFor(any(), any(), any(), any()))
- .thenReturn(List.of("dc-manual"));
-
- assertThat(router().getRoutingFor(aci, Optional.of(InetAddress.getByName("0.0.0.1")), 10))
- .isEqualTo(optionsWithUrls(List.of(
- "turn:1.1.1.1",
- "turn:1.1.1.1:80?transport=tcp",
- "turns:1.1.1.1:443?transport=tcp",
-
- "turn:[2222:1111:0:dead:0:0:0:0]",
- "turn:[2222:1111:0:dead:0:0:0:0]:80?transport=tcp",
- "turns:[2222:1111:0:dead:0:0:0:0]:443?transport=tcp"
- )));
- }
-
- @Test
- public void testLimitPrioritizesBestDataCenters() throws UnknownHostException {
- when(performanceTable.getDatacentersFor(any(), any(), any(), any()))
- .thenReturn(List.of("dc-performance3", "dc-performance2", "dc-performance3"));
-
- // gets one instance from best two datacenters
- assertThat(router().getRoutingFor(aci, Optional.of(InetAddress.getByName("0.0.0.1")), 2))
- .isEqualTo(optionsWithUrls(List.of(
- "turn:9.9.9.4",
- "turn:9.9.9.4:80?transport=tcp",
- "turns:9.9.9.4:443?transport=tcp",
-
- "turn:9.9.9.3",
- "turn:9.9.9.3:80?transport=tcp",
- "turns:9.9.9.3:443?transport=tcp",
-
- "turn:[2222:1111:0:abc3:0:0:0:0]",
- "turn:[2222:1111:0:abc3:0:0:0:0]:80?transport=tcp",
- "turns:[2222:1111:0:abc3:0:0:0:0]:443?transport=tcp",
-
- "turn:[2222:1111:0:abc2:0:0:0:0]",
- "turn:[2222:1111:0:abc2:0:0:0:0]:80?transport=tcp",
- "turns:[2222:1111:0:abc2:0:0:0:0]:443?transport=tcp"
- )));
-
- assertThat(router().getRoutingFor(aci, Optional.of(InetAddress.getByName("2222:1111:0:abc2:0:0:0:1")), 1))
- .isEqualTo(optionsWithUrls(List.of(
- "turn:9.9.9.4",
- "turn:9.9.9.4:80?transport=tcp",
- "turns:9.9.9.4:443?transport=tcp",
-
- "turn:[2222:1111:0:abc3:0:0:0:0]",
- "turn:[2222:1111:0:abc3:0:0:0:0]:80?transport=tcp",
- "turns:[2222:1111:0:abc3:0:0:0:0]:443?transport=tcp"
- )));
- }
-
- @Test
- public void testBackFillsUpToLimit() throws UnknownHostException {
- when(performanceTable.getDatacentersFor(any(), any(), any(), any()))
- .thenReturn(List.of("dc-performance4", "dc-performance2", "dc-performance3"));
-
- assertThat(router().getRoutingFor(aci, Optional.of(InetAddress.getByName("0.0.0.1")), 5))
- .isEqualTo(optionsWithUrls(List.of(
- "turn:9.9.9.5",
- "turn:9.9.9.5:80?transport=tcp",
- "turns:9.9.9.5:443?transport=tcp",
-
- "turn:9.9.9.6",
- "turn:9.9.9.6:80?transport=tcp",
- "turns:9.9.9.6:443?transport=tcp",
-
- "turn:9.9.9.7",
- "turn:9.9.9.7:80?transport=tcp",
- "turns:9.9.9.7:443?transport=tcp",
-
- "turn:9.9.9.3",
- "turn:9.9.9.3:80?transport=tcp",
- "turns:9.9.9.3:443?transport=tcp",
-
- "turn:9.9.9.4",
- "turn:9.9.9.4:80?transport=tcp",
- "turns:9.9.9.4:443?transport=tcp",
-
- "turn:[2222:1111:0:abc4:0:0:0:0]",
- "turn:[2222:1111:0:abc4:0:0:0:0]:80?transport=tcp",
- "turns:[2222:1111:0:abc4:0:0:0:0]:443?transport=tcp",
-
- "turn:[2222:1111:0:abc5:0:0:0:0]",
- "turn:[2222:1111:0:abc5:0:0:0:0]:80?transport=tcp",
- "turns:[2222:1111:0:abc5:0:0:0:0]:443?transport=tcp",
-
- "turn:[2222:1111:0:abc6:0:0:0:0]",
- "turn:[2222:1111:0:abc6:0:0:0:0]:80?transport=tcp",
- "turns:[2222:1111:0:abc6:0:0:0:0]:443?transport=tcp",
-
- "turn:[2222:1111:0:abc2:0:0:0:0]",
- "turn:[2222:1111:0:abc2:0:0:0:0]:80?transport=tcp",
- "turns:[2222:1111:0:abc2:0:0:0:0]:443?transport=tcp",
-
- "turn:[2222:1111:0:abc3:0:0:0:0]",
- "turn:[2222:1111:0:abc3:0:0:0:0]:80?transport=tcp",
- "turns:[2222:1111:0:abc3:0:0:0:0]:443?transport=tcp"
- )));
- }
-
- @Test
- public void testNoDatacentersMatched() throws UnknownHostException {
- when(performanceTable.getDatacentersFor(any(), any(), any(), any()))
- .thenReturn(List.of());
-
- assertThat(router().getRoutingFor(aci, Optional.of(InetAddress.getByName("0.0.0.1")), 10))
- .isEqualTo(optionsWithUrls(List.of()));
- }
-
- @Test
- public void testHandlesDatacenterNotInDnsRecords() throws UnknownHostException {
- when(performanceTable.getDatacentersFor(any(), any(), any(), any()))
- .thenReturn(List.of("unsynced-datacenter"));
-
- assertThat(router().getRoutingFor(aci, Optional.of(InetAddress.getByName("0.0.0.1")), 10))
- .isEqualTo(optionsWithUrls(List.of()));
- }
-}
diff --git a/service/src/test/java/org/whispersystems/textsecuregcm/configuration/dynamic/DynamicConfigurationTest.java b/service/src/test/java/org/whispersystems/textsecuregcm/configuration/dynamic/DynamicConfigurationTest.java
index ac7b7eb70..f6b445978 100644
--- a/service/src/test/java/org/whispersystems/textsecuregcm/configuration/dynamic/DynamicConfigurationTest.java
+++ b/service/src/test/java/org/whispersystems/textsecuregcm/configuration/dynamic/DynamicConfigurationTest.java
@@ -335,67 +335,6 @@ class DynamicConfigurationTest {
assertThat(resetRateLimiterConfig.permitRegenerationDuration()).isEqualTo(Duration.ofNanos(4_000));
}
- @Test
- void testParseTurnConfig() throws JsonProcessingException {
- {
- final String config = REQUIRED_CONFIG.concat("""
- turn:
- secret: bloop
- uriConfigs:
- - uris:
- - turn:test.org
- weight: -1
- """);
- assertThat(DynamicConfigurationManager.parseConfiguration(config, DynamicConfiguration.class)).isEmpty();
- }
- {
- final String config = REQUIRED_CONFIG.concat("""
- turn:
- uriConfigs:
- - uris:
- - turn:test0.org
- - turn:test1.org
- - uris:
- - turn:test2.org
- weight: 2
- enrolledAcis:
- - 732506d7-d04f-43a4-b1d7-8a3a91ebe8a6
- randomizeRate: 100_000
- hostname: test.domain.org
- """);
- DynamicTurnConfiguration turnConfiguration = DynamicConfigurationManager
- .parseConfiguration(config, DynamicConfiguration.class)
- .orElseThrow()
- .getTurnConfiguration();
- assertThat(turnConfiguration.getUriConfigs().get(0).getUris()).hasSize(2);
- assertThat(turnConfiguration.getUriConfigs().get(1).getUris()).hasSize(1);
- assertThat(turnConfiguration.getUriConfigs().get(0).getWeight()).isEqualTo(1);
- assertThat(turnConfiguration.getUriConfigs().get(1).getWeight()).isEqualTo(2);
- assertThat(turnConfiguration.getUriConfigs().get(1).getEnrolledAcis())
- .containsExactly(UUID.fromString("732506d7-d04f-43a4-b1d7-8a3a91ebe8a6"));
-
- assertThat(turnConfiguration.getHostname()).isEqualTo("test.domain.org");
- assertThat(turnConfiguration.getRandomizeRate()).isEqualTo(100_000L);
- assertThat(turnConfiguration.getDefaultInstanceIpCount()).isEqualTo(0);
- }
-
- {
- final String config = REQUIRED_CONFIG.concat("""
- turn:
- uriConfigs:
- - uris:
- - turn:test0.org
- - turn:test1.org
- defaultInstanceIpCount: 5
- """);
- DynamicTurnConfiguration turnConfiguration = DynamicConfigurationManager
- .parseConfiguration(config, DynamicConfiguration.class)
- .orElseThrow()
- .getTurnConfiguration();
- assertThat(turnConfiguration.getDefaultInstanceIpCount()).isEqualTo(5);
- }
- }
-
@Test
void testMessagePersister() throws JsonProcessingException {
{
diff --git a/service/src/test/java/org/whispersystems/textsecuregcm/controllers/AccountControllerTest.java b/service/src/test/java/org/whispersystems/textsecuregcm/controllers/AccountControllerTest.java
index 6ffe5a8a3..fb34b0d57 100644
--- a/service/src/test/java/org/whispersystems/textsecuregcm/controllers/AccountControllerTest.java
+++ b/service/src/test/java/org/whispersystems/textsecuregcm/controllers/AccountControllerTest.java
@@ -59,7 +59,6 @@ import org.signal.libsignal.usernames.BaseUsernameException;
import org.whispersystems.textsecuregcm.auth.AuthenticatedDevice;
import org.whispersystems.textsecuregcm.auth.SaltedTokenHash;
import org.whispersystems.textsecuregcm.auth.StoredRegistrationLock;
-import org.whispersystems.textsecuregcm.auth.TurnTokenGenerator;
import org.whispersystems.textsecuregcm.entities.AccountAttributes;
import org.whispersystems.textsecuregcm.entities.AccountIdentifierResponse;
import org.whispersystems.textsecuregcm.entities.AccountIdentityResponse;
@@ -130,7 +129,6 @@ class AccountControllerTest {
private static final RateLimiter usernameReserveLimiter = mock(RateLimiter.class);
private static final RateLimiter usernameLookupLimiter = mock(RateLimiter.class);
private static final RateLimiter checkAccountExistence = mock(RateLimiter.class);
- private static final TurnTokenGenerator turnTokenGenerator = mock(TurnTokenGenerator.class);
private static final Account senderPinAccount = mock(Account.class);
private static final Account senderRegLockAccount = mock(Account.class);
private static final Account senderHasStorage = mock(Account.class);
@@ -234,7 +232,6 @@ class AccountControllerTest {
usernameSetLimiter,
usernameReserveLimiter,
usernameLookupLimiter,
- turnTokenGenerator,
senderPinAccount,
senderRegLockAccount,
senderHasStorage,
diff --git a/service/src/test/resources/config/test-secrets-bundle.yml b/service/src/test/resources/config/test-secrets-bundle.yml
index 96600b455..dc2d640c6 100644
--- a/service/src/test/resources/config/test-secrets-bundle.yml
+++ b/service/src/test/resources/config/test-secrets-bundle.yml
@@ -164,7 +164,6 @@ currentReportingKey.salt: AAAAAAAAAAA=
registrationService.collationKeySalt: AAAAAAAAAAA=
-turn.secret: AAAAAAAAAAA=
turn.cloudflare.apiToken: ABCDEFGHIJKLM
linkDevice.secret: AAAAAAAAAAA=
diff --git a/service/src/test/resources/config/test.yml b/service/src/test/resources/config/test.yml
index ba26d7de1..208959b1e 100644
--- a/service/src/test/resources/config/test.yml
+++ b/service/src/test/resources/config/test.yml
@@ -467,7 +467,6 @@ keyTransparencyService:
clientPrivateKey: secret://keyTransparencyService.clientPrivateKey
turn:
- secret: secret://turn.secret
cloudflare:
apiToken: secret://turn.cloudflare.apiToken
endpoint: https://rtc.live.cloudflare.com/v1/turn/keys/LMNOP/credentials/generate
@@ -484,18 +483,6 @@ turn:
linkDevice:
secret: secret://linkDevice.secret
-maxmindCityDatabase:
- type: static
-
-callingTurnDnsRecords:
- type: static
-
-callingTurnPerformanceTable:
- type: static
-
-callingTurnManualTable:
- type: static
-
noiseTunnel:
port: 8443
noiseStaticPrivateKey: secret://noiseTunnel.noiseStaticPrivateKey