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