Return empty lists instead of null in GetCallingRelaysV2

This commit is contained in:
adel-signal
2025-01-24 14:33:45 -08:00
committed by GitHub
parent 7e616a4056
commit ae1e7fbaa0
8 changed files with 87 additions and 49 deletions

View File

@@ -16,6 +16,7 @@ import java.net.URI;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.util.List;
import java.util.Optional;
import java.util.concurrent.CompletionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.ScheduledExecutorService;
@@ -126,8 +127,12 @@ public class CloudflareTurnCredentialsManager {
final CloudflareTurnResponse cloudflareTurnResponse = SystemMapper.jsonMapper()
.readValue(response.body(), CloudflareTurnResponse.class);
return new TurnToken(cloudflareTurnResponse.iceServers().username(),
return TurnTokenGenerator.from(
cloudflareTurnResponse.iceServers().username(),
cloudflareTurnResponse.iceServers().credential(),
cloudflareTurnUrls, cloudflareTurnComposedUrls, cloudflareTurnHostname);
Optional.ofNullable(cloudflareTurnUrls),
Optional.ofNullable(cloudflareTurnComposedUrls),
cloudflareTurnHostname
);
}
}

View File

@@ -5,9 +5,14 @@
package org.whispersystems.textsecuregcm.auth;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.util.List;
public record TurnToken(String username, String password, List<String> urls, @Nullable List<String> urlsWithIps,
@Nullable String hostname) {
public record TurnToken(
String username,
String password,
@Nonnull List<String> urls,
@Nonnull List<String> urlsWithIps,
@Nullable String hostname) {
}

View File

@@ -11,19 +11,13 @@ import java.security.SecureRandom;
import java.time.Duration;
import java.time.Instant;
import java.util.Base64;
import java.util.Collections;
import java.util.List;
import java.util.Optional;
import java.util.UUID;
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import org.whispersystems.textsecuregcm.calls.routing.TurnServerOptions;
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.Util;
import org.whispersystems.textsecuregcm.util.WeightedRandomSelect;
public class TurnTokenGenerator {
@@ -43,23 +37,51 @@ public class TurnTokenGenerator {
return generateToken(options.hostname(), options.urlsWithIps(), options.urlsWithHostname());
}
private TurnToken generateToken(String hostname, List<String> urlsWithIps, List<String> urlsWithHostname) {
@SuppressWarnings("OptionalUsedAsFieldOrParameterType")
private TurnToken generateToken(
String hostname,
Optional<List<String>> urlsWithIps,
Optional<List<String>> 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 != null && !urlsWithIps.isEmpty()
? WithIpsProtocol
: WithUrlsProtocol;
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 new TurnToken(protocolUserTime, password, urlsWithHostname, urlsWithIps, hostname);
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<List<String>> urls,
Optional<List<String>> urlsWithIps,
String hostname
) {
return new TurnToken(
username,
password,
urls.orElse(Collections.emptyList()),
urlsWithIps.orElse(Collections.emptyList()),
hostname
);
}
}

View File

@@ -77,7 +77,7 @@ public class TurnCallRouter {
return getRoutingForInner(aci, clientAddress, instanceLimit);
} catch(Exception e) {
logger.error("Failed to perform routing", e);
return new TurnServerOptions(this.configTurnRouter.getHostname(), null, this.configTurnRouter.randomUrls());
return new TurnServerOptions(this.configTurnRouter.getHostname(), null, Optional.of(this.configTurnRouter.randomUrls()));
}
}
@@ -90,11 +90,11 @@ public class TurnCallRouter {
List<String> targetedUrls = this.configTurnRouter.targetedUrls(aci);
if(!targetedUrls.isEmpty()) {
return new TurnServerOptions(hostname, null, targetedUrls);
return new TurnServerOptions(hostname, Optional.empty(), Optional.ofNullable(targetedUrls));
}
if(clientAddress.isEmpty() || this.configTurnRouter.shouldRandomize() || instanceLimit < 1) {
return new TurnServerOptions(hostname, null, this.configTurnRouter.randomUrls());
return new TurnServerOptions(hostname, Optional.empty(), Optional.ofNullable(this.configTurnRouter.randomUrls()));
}
CityResponse geoInfo;
@@ -128,7 +128,7 @@ public class TurnCallRouter {
datacenters,
instanceLimit
));
return new TurnServerOptions(hostname, urlsWithIps, minimalRandomUrls());
return new TurnServerOptions(hostname, Optional.of(urlsWithIps), Optional.of(minimalRandomUrls()));
}
// Includes only the udp options in the randomUrls

View File

@@ -6,6 +6,11 @@
package org.whispersystems.textsecuregcm.calls.routing;
import java.util.List;
import java.util.Optional;
public record TurnServerOptions(String hostname, List<String> urlsWithIps, List<String> urlsWithHostname) {
public record TurnServerOptions(
String hostname,
Optional<List<String>> urlsWithIps,
Optional<List<String>> urlsWithHostname
) {
}