Return empty lists instead of null in GetCallingRelaysV2
This commit is contained in:
parent
7e616a4056
commit
ae1e7fbaa0
|
@ -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
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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) {
|
||||
}
|
||||
|
|
|
@ -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
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
) {
|
||||
}
|
||||
|
|
|
@ -127,8 +127,8 @@ public class TurnCallRouterTest {
|
|||
TurnServerOptions optionsWithUrls(List<String> urls) {
|
||||
return new TurnServerOptions(
|
||||
TEST_HOSTNAME,
|
||||
urls,
|
||||
EXPECTED_TEST_URLS_WITH_HOSTS
|
||||
Optional.of(urls),
|
||||
Optional.of(EXPECTED_TEST_URLS_WITH_HOSTS)
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -144,8 +144,8 @@ public class TurnCallRouterTest {
|
|||
assertThat(router().getRoutingFor(aci, Optional.of(InetAddress.getByName("0.0.0.1")), 10))
|
||||
.isEqualTo(new TurnServerOptions(
|
||||
TEST_HOSTNAME,
|
||||
null,
|
||||
targetedUrls
|
||||
Optional.empty(),
|
||||
Optional.of(targetedUrls)
|
||||
));
|
||||
}
|
||||
|
||||
|
@ -157,8 +157,8 @@ public class TurnCallRouterTest {
|
|||
assertThat(router().getRoutingFor(aci, Optional.of(InetAddress.getByName("0.0.0.1")), 10))
|
||||
.isEqualTo(new TurnServerOptions(
|
||||
TEST_HOSTNAME,
|
||||
null,
|
||||
TEST_URLS_WITH_HOSTS
|
||||
Optional.empty(),
|
||||
Optional.of(TEST_URLS_WITH_HOSTS)
|
||||
));
|
||||
}
|
||||
|
||||
|
@ -172,8 +172,8 @@ public class TurnCallRouterTest {
|
|||
assertThat(router().getRoutingFor(aci, Optional.of(InetAddress.getByName("0.0.0.1")), 0))
|
||||
.isEqualTo(new TurnServerOptions(
|
||||
TEST_HOSTNAME,
|
||||
null,
|
||||
TEST_URLS_WITH_HOSTS
|
||||
Optional.empty(),
|
||||
Optional.of(TEST_URLS_WITH_HOSTS)
|
||||
));
|
||||
}
|
||||
|
||||
|
|
|
@ -21,6 +21,7 @@ import java.io.IOException;
|
|||
import java.net.InetAddress;
|
||||
import java.net.UnknownHostException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import org.glassfish.jersey.test.grizzly.GrizzlyWebTestContainerFactory;
|
||||
|
@ -84,8 +85,8 @@ class CallRoutingControllerTest {
|
|||
void testGetTurnEndpointsSuccess() throws UnknownHostException {
|
||||
TurnServerOptions options = new TurnServerOptions(
|
||||
"example.domain.org",
|
||||
List.of("stun:12.34.56.78"),
|
||||
List.of("stun:example.domain.org")
|
||||
Optional.of(List.of("stun:12.34.56.78")),
|
||||
Optional.of(List.of("stun:example.domain.org"))
|
||||
);
|
||||
|
||||
when(turnCallRouter.getRoutingFor(
|
||||
|
@ -104,8 +105,8 @@ class CallRoutingControllerTest {
|
|||
assertThat(token.username()).isNotEmpty();
|
||||
assertThat(token.password()).isNotEmpty();
|
||||
assertThat(token.hostname()).isEqualTo(options.hostname());
|
||||
assertThat(token.urlsWithIps()).isEqualTo(options.urlsWithIps());
|
||||
assertThat(token.urls()).isEqualTo(options.urlsWithHostname());
|
||||
assertThat(token.urlsWithIps()).isEqualTo(options.urlsWithIps().get());
|
||||
assertThat(token.urls()).isEqualTo(options.urlsWithHostname().get());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -115,7 +116,7 @@ class CallRoutingControllerTest {
|
|||
.thenReturn(true);
|
||||
|
||||
when(cloudflareTurnCredentialsManager.retrieveFromCloudflare()).thenReturn(new TurnToken("ABC", "XYZ",
|
||||
List.of("turn:cloudflare.example.com:3478?transport=udp"), null,
|
||||
List.of("turn:cloudflare.example.com:3478?transport=udp"), Collections.emptyList(),
|
||||
"cf.example.com"));
|
||||
|
||||
try (Response response = resources.getJerseyTest()
|
||||
|
@ -129,7 +130,7 @@ class CallRoutingControllerTest {
|
|||
assertThat(token.username()).isEqualTo("ABC");
|
||||
assertThat(token.password()).isEqualTo("XYZ");
|
||||
assertThat(token.hostname()).isEqualTo("cf.example.com");
|
||||
assertThat(token.urlsWithIps()).isNull();
|
||||
assertThat(token.urlsWithIps()).isEmpty();
|
||||
assertThat(token.urls()).isEqualTo(List.of("turn:cloudflare.example.com:3478?transport=udp"));
|
||||
}
|
||||
}
|
||||
|
@ -138,8 +139,8 @@ class CallRoutingControllerTest {
|
|||
void testGetTurnEndpointsInvalidIpSuccess() throws UnknownHostException {
|
||||
TurnServerOptions options = new TurnServerOptions(
|
||||
"example.domain.org",
|
||||
List.of(),
|
||||
List.of("stun:example.domain.org")
|
||||
Optional.of(List.of()),
|
||||
Optional.of(List.of("stun:example.domain.org"))
|
||||
);
|
||||
|
||||
when(turnCallRouter.getRoutingFor(
|
||||
|
@ -158,8 +159,8 @@ class CallRoutingControllerTest {
|
|||
assertThat(token.username()).isNotEmpty();
|
||||
assertThat(token.password()).isNotEmpty();
|
||||
assertThat(token.hostname()).isEqualTo(options.hostname());
|
||||
assertThat(token.urlsWithIps()).isEqualTo(options.urlsWithIps());
|
||||
assertThat(token.urls()).isEqualTo(options.urlsWithHostname());
|
||||
assertThat(token.urlsWithIps()).isEqualTo(options.urlsWithIps().get());
|
||||
assertThat(token.urls()).isEqualTo(options.urlsWithHostname().get());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -49,8 +49,8 @@ class CallRoutingControllerV2Test {
|
|||
private static final String REMOTE_ADDRESS = "123.123.123.1";
|
||||
private static final TurnServerOptions TURN_SERVER_OPTIONS = new TurnServerOptions(
|
||||
"example.domain.org",
|
||||
List.of("stun:12.34.56.78"),
|
||||
List.of("stun:example.domain.org")
|
||||
Optional.of(List.of("stun:12.34.56.78")),
|
||||
Optional.of(List.of("stun:example.domain.org"))
|
||||
);
|
||||
private static final TurnToken CLOUDFLARE_TURN_TOKEN = new TurnToken(
|
||||
"ABC",
|
||||
|
@ -129,8 +129,8 @@ class CallRoutingControllerV2Test {
|
|||
assertThat(relays.getFirst().username()).isNotEmpty();
|
||||
assertThat(relays.getFirst().password()).isNotEmpty();
|
||||
assertThat(relays.getFirst().hostname()).isEqualTo(options.hostname());
|
||||
assertThat(relays.getFirst().urlsWithIps()).isEqualTo(options.urlsWithIps());
|
||||
assertThat(relays.getFirst().urls()).isEqualTo(options.urlsWithHostname());
|
||||
assertThat(relays.getFirst().urlsWithIps()).isEqualTo(options.urlsWithIps().get());
|
||||
assertThat(relays.getFirst().urls()).isEqualTo(options.urlsWithHostname().get());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -159,8 +159,8 @@ class CallRoutingControllerV2Test {
|
|||
assertThat(token.username()).isNotEmpty();
|
||||
assertThat(token.password()).isNotEmpty();
|
||||
assertThat(token.hostname()).isEqualTo(options.hostname());
|
||||
assertThat(token.urlsWithIps()).isEqualTo(options.urlsWithIps());
|
||||
assertThat(token.urls()).isEqualTo(options.urlsWithHostname());
|
||||
assertThat(token.urlsWithIps()).isEqualTo(options.urlsWithIps().get());
|
||||
assertThat(token.urls()).isEqualTo(options.urlsWithHostname().get());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -168,8 +168,8 @@ class CallRoutingControllerV2Test {
|
|||
void testGetRelaysInvalidIpSuccess() throws UnknownHostException {
|
||||
TurnServerOptions options = new TurnServerOptions(
|
||||
"example.domain.org",
|
||||
List.of(),
|
||||
List.of("stun:example.domain.org")
|
||||
Optional.of(List.of()),
|
||||
Optional.of(List.of("stun:example.domain.org"))
|
||||
);
|
||||
|
||||
when(turnCallRouter.getRoutingFor(
|
||||
|
@ -192,8 +192,8 @@ class CallRoutingControllerV2Test {
|
|||
assertThat(token.username()).isNotEmpty();
|
||||
assertThat(token.password()).isNotEmpty();
|
||||
assertThat(token.hostname()).isEqualTo(options.hostname());
|
||||
assertThat(token.urlsWithIps()).isEqualTo(options.urlsWithIps());
|
||||
assertThat(token.urls()).isEqualTo(options.urlsWithHostname());
|
||||
assertThat(token.urlsWithIps()).isEqualTo(options.urlsWithIps().get());
|
||||
assertThat(token.urls()).isEqualTo(options.urlsWithHostname().get());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue