Move turn secret to static configuration
This commit is contained in:
parent
13456bad3a
commit
9cfd88a23f
|
@ -84,3 +84,5 @@ artService.userAuthenticationTokenUserIdSecret: AAAAAAAAAAA= # base64-encoded se
|
||||||
|
|
||||||
currentReportingKey.secret: AAAAAAAAAAA=
|
currentReportingKey.secret: AAAAAAAAAAA=
|
||||||
currentReportingKey.salt: AAAAAAAAAAA=
|
currentReportingKey.salt: AAAAAAAAAAA=
|
||||||
|
|
||||||
|
turn.secret: AAAAAAAAAAA=
|
||||||
|
|
|
@ -419,3 +419,6 @@ registrationService:
|
||||||
ABCDEFGHIJKLMNOPQRSTUVWXYZ/0123456789+abcdefghijklmnopqrstuvwxyz
|
ABCDEFGHIJKLMNOPQRSTUVWXYZ/0123456789+abcdefghijklmnopqrstuvwxyz
|
||||||
AAAAAAAAAAAAAAAAAAAA
|
AAAAAAAAAAAAAAAAAAAA
|
||||||
-----END CERTIFICATE-----
|
-----END CERTIFICATE-----
|
||||||
|
|
||||||
|
turn:
|
||||||
|
secret: secret://turn.secret
|
||||||
|
|
|
@ -47,6 +47,7 @@ import org.whispersystems.textsecuregcm.configuration.SecureValueRecovery2Config
|
||||||
import org.whispersystems.textsecuregcm.configuration.SpamFilterConfiguration;
|
import org.whispersystems.textsecuregcm.configuration.SpamFilterConfiguration;
|
||||||
import org.whispersystems.textsecuregcm.configuration.StripeConfiguration;
|
import org.whispersystems.textsecuregcm.configuration.StripeConfiguration;
|
||||||
import org.whispersystems.textsecuregcm.configuration.SubscriptionConfiguration;
|
import org.whispersystems.textsecuregcm.configuration.SubscriptionConfiguration;
|
||||||
|
import org.whispersystems.textsecuregcm.configuration.TurnSecretConfiguration;
|
||||||
import org.whispersystems.textsecuregcm.configuration.UnidentifiedDeliveryConfiguration;
|
import org.whispersystems.textsecuregcm.configuration.UnidentifiedDeliveryConfiguration;
|
||||||
import org.whispersystems.textsecuregcm.configuration.ZkConfig;
|
import org.whispersystems.textsecuregcm.configuration.ZkConfig;
|
||||||
import org.whispersystems.textsecuregcm.limits.RateLimiterConfig;
|
import org.whispersystems.textsecuregcm.limits.RateLimiterConfig;
|
||||||
|
@ -264,6 +265,11 @@ public class WhisperServerConfiguration extends Configuration {
|
||||||
@JsonProperty
|
@JsonProperty
|
||||||
private RegistrationServiceConfiguration registrationService;
|
private RegistrationServiceConfiguration registrationService;
|
||||||
|
|
||||||
|
@Valid
|
||||||
|
@NotNull
|
||||||
|
@JsonProperty
|
||||||
|
private TurnSecretConfiguration turn;
|
||||||
|
|
||||||
public AdminEventLoggingConfiguration getAdminEventLoggingConfiguration() {
|
public AdminEventLoggingConfiguration getAdminEventLoggingConfiguration() {
|
||||||
return adminEventLoggingConfiguration;
|
return adminEventLoggingConfiguration;
|
||||||
}
|
}
|
||||||
|
@ -438,4 +444,8 @@ public class WhisperServerConfiguration extends Configuration {
|
||||||
public RegistrationServiceConfiguration getRegistrationServiceConfiguration() {
|
public RegistrationServiceConfiguration getRegistrationServiceConfiguration() {
|
||||||
return registrationService;
|
return registrationService;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public TurnSecretConfiguration getTurnSecretConfiguration() {
|
||||||
|
return turn;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -554,7 +554,8 @@ public class WhisperServerService extends Application<WhisperServerConfiguration
|
||||||
pushNotificationManager,
|
pushNotificationManager,
|
||||||
pushLatencyManager);
|
pushLatencyManager);
|
||||||
final ReceiptSender receiptSender = new ReceiptSender(accountsManager, messageSender, receiptSenderExecutor);
|
final ReceiptSender receiptSender = new ReceiptSender(accountsManager, messageSender, receiptSenderExecutor);
|
||||||
final TurnTokenGenerator turnTokenGenerator = new TurnTokenGenerator(dynamicConfigurationManager);
|
final TurnTokenGenerator turnTokenGenerator = new TurnTokenGenerator(dynamicConfigurationManager,
|
||||||
|
config.getTurnSecretConfiguration().secret().value());
|
||||||
|
|
||||||
RecaptchaClient recaptchaClient = new RecaptchaClient(
|
RecaptchaClient recaptchaClient = new RecaptchaClient(
|
||||||
config.getRecaptchaConfiguration().projectPath(),
|
config.getRecaptchaConfiguration().projectPath(),
|
||||||
|
|
|
@ -26,39 +26,44 @@ import java.util.Optional;
|
||||||
|
|
||||||
public class TurnTokenGenerator {
|
public class TurnTokenGenerator {
|
||||||
|
|
||||||
private final DynamicConfigurationManager<DynamicConfiguration> dynamicConfiguration;
|
private final DynamicConfigurationManager<DynamicConfiguration> dynamicConfigurationManager;
|
||||||
|
|
||||||
|
private final byte[] turnSecret;
|
||||||
|
|
||||||
private static final String ALGORITHM = "HmacSHA1";
|
private static final String ALGORITHM = "HmacSHA1";
|
||||||
|
|
||||||
public TurnTokenGenerator(final DynamicConfigurationManager<DynamicConfiguration> config) {
|
public TurnTokenGenerator(final DynamicConfigurationManager<DynamicConfiguration> dynamicConfigurationManager,
|
||||||
this.dynamicConfiguration = config;
|
final byte[] turnSecret) {
|
||||||
|
|
||||||
|
this.dynamicConfigurationManager = dynamicConfigurationManager;
|
||||||
|
this.turnSecret = turnSecret;
|
||||||
}
|
}
|
||||||
|
|
||||||
public TurnToken generate(final String e164) {
|
public TurnToken generate(final String e164) {
|
||||||
try {
|
try {
|
||||||
final byte[] key = dynamicConfiguration.getConfiguration().getTurnConfiguration().getSecret().getBytes();
|
|
||||||
final List<String> urls = urls(e164);
|
final List<String> urls = urls(e164);
|
||||||
final Mac mac = Mac.getInstance(ALGORITHM);
|
final Mac mac = Mac.getInstance(ALGORITHM);
|
||||||
final long validUntilSeconds = Instant.now().plus(Duration.ofDays(1)).getEpochSecond();
|
final long validUntilSeconds = Instant.now().plus(Duration.ofDays(1)).getEpochSecond();
|
||||||
final long user = Util.ensureNonNegativeInt(new SecureRandom().nextInt());
|
final long user = Util.ensureNonNegativeInt(new SecureRandom().nextInt());
|
||||||
final String userTime = validUntilSeconds + ":" + user;
|
final String userTime = validUntilSeconds + ":" + user;
|
||||||
|
|
||||||
mac.init(new SecretKeySpec(key, ALGORITHM));
|
mac.init(new SecretKeySpec(turnSecret, ALGORITHM));
|
||||||
final String password = Base64.getEncoder().encodeToString(mac.doFinal(userTime.getBytes()));
|
final String password = Base64.getEncoder().encodeToString(mac.doFinal(userTime.getBytes()));
|
||||||
|
|
||||||
return new TurnToken(userTime, password, urls);
|
return new TurnToken(userTime, password, urls);
|
||||||
} catch (NoSuchAlgorithmException | InvalidKeyException e) {
|
} catch (final NoSuchAlgorithmException | InvalidKeyException e) {
|
||||||
throw new AssertionError(e);
|
throw new AssertionError(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<String> urls(final String e164) {
|
private List<String> urls(final String e164) {
|
||||||
final DynamicTurnConfiguration turnConfig = dynamicConfiguration.getConfiguration().getTurnConfiguration();
|
final DynamicTurnConfiguration turnConfig = dynamicConfigurationManager.getConfiguration().getTurnConfiguration();
|
||||||
|
|
||||||
// Check if number is enrolled to test out specific turn servers
|
// Check if number is enrolled to test out specific turn servers
|
||||||
final Optional<TurnUriConfiguration> enrolled = turnConfig.getUriConfigs().stream()
|
final Optional<TurnUriConfiguration> enrolled = turnConfig.getUriConfigs().stream()
|
||||||
.filter(config -> config.getEnrolledNumbers().contains(e164))
|
.filter(config -> config.getEnrolledNumbers().contains(e164))
|
||||||
.findFirst();
|
.findFirst();
|
||||||
|
|
||||||
if (enrolled.isPresent()) {
|
if (enrolled.isPresent()) {
|
||||||
return enrolled.get().getUris();
|
return enrolled.get().getUris();
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,11 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2023 Signal Messenger, LLC
|
||||||
|
* SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.whispersystems.textsecuregcm.configuration;
|
||||||
|
|
||||||
|
import org.whispersystems.textsecuregcm.configuration.secrets.SecretBytes;
|
||||||
|
|
||||||
|
public record TurnSecretConfiguration(SecretBytes secret) {
|
||||||
|
}
|
|
@ -13,17 +13,10 @@ import org.whispersystems.textsecuregcm.configuration.TurnUriConfiguration;
|
||||||
|
|
||||||
public class DynamicTurnConfiguration {
|
public class DynamicTurnConfiguration {
|
||||||
|
|
||||||
@JsonProperty
|
|
||||||
private String secret;
|
|
||||||
|
|
||||||
@JsonProperty
|
@JsonProperty
|
||||||
private List<@Valid TurnUriConfiguration> uriConfigs = Collections.emptyList();
|
private List<@Valid TurnUriConfiguration> uriConfigs = Collections.emptyList();
|
||||||
|
|
||||||
public List<TurnUriConfiguration> getUriConfigs() {
|
public List<TurnUriConfiguration> getUriConfigs() {
|
||||||
return uriConfigs;
|
return uriConfigs;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getSecret() {
|
|
||||||
return secret;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,6 +5,7 @@ import org.junit.jupiter.api.Test;
|
||||||
import org.whispersystems.textsecuregcm.configuration.dynamic.DynamicConfiguration;
|
import org.whispersystems.textsecuregcm.configuration.dynamic.DynamicConfiguration;
|
||||||
import org.whispersystems.textsecuregcm.storage.DynamicConfigurationManager;
|
import org.whispersystems.textsecuregcm.storage.DynamicConfigurationManager;
|
||||||
|
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
import java.util.stream.Stream;
|
import java.util.stream.Stream;
|
||||||
|
@ -21,7 +22,6 @@ public class TurnTokenGeneratorTest {
|
||||||
captcha:
|
captcha:
|
||||||
scoreFloor: 1.0
|
scoreFloor: 1.0
|
||||||
turn:
|
turn:
|
||||||
secret: bloop
|
|
||||||
uriConfigs:
|
uriConfigs:
|
||||||
- uris:
|
- uris:
|
||||||
- always1.org
|
- always1.org
|
||||||
|
@ -39,7 +39,9 @@ public class TurnTokenGeneratorTest {
|
||||||
DynamicConfigurationManager.class);
|
DynamicConfigurationManager.class);
|
||||||
|
|
||||||
when(mockDynamicConfigManager.getConfiguration()).thenReturn(config);
|
when(mockDynamicConfigManager.getConfiguration()).thenReturn(config);
|
||||||
final TurnTokenGenerator turnTokenGenerator = new TurnTokenGenerator(mockDynamicConfigManager);
|
|
||||||
|
final TurnTokenGenerator turnTokenGenerator =
|
||||||
|
new TurnTokenGenerator(mockDynamicConfigManager, "bloop".getBytes(StandardCharsets.UTF_8));
|
||||||
|
|
||||||
final long COUNT = 1000;
|
final long COUNT = 1000;
|
||||||
|
|
||||||
|
@ -60,7 +62,6 @@ public class TurnTokenGeneratorTest {
|
||||||
captcha:
|
captcha:
|
||||||
scoreFloor: 1.0
|
scoreFloor: 1.0
|
||||||
turn:
|
turn:
|
||||||
secret: bloop
|
|
||||||
uriConfigs:
|
uriConfigs:
|
||||||
- uris:
|
- uris:
|
||||||
- always.org
|
- always.org
|
||||||
|
@ -80,7 +81,8 @@ public class TurnTokenGeneratorTest {
|
||||||
DynamicConfigurationManager.class);
|
DynamicConfigurationManager.class);
|
||||||
|
|
||||||
when(mockDynamicConfigManager.getConfiguration()).thenReturn(config);
|
when(mockDynamicConfigManager.getConfiguration()).thenReturn(config);
|
||||||
final TurnTokenGenerator turnTokenGenerator = new TurnTokenGenerator(mockDynamicConfigManager);
|
final TurnTokenGenerator turnTokenGenerator =
|
||||||
|
new TurnTokenGenerator(mockDynamicConfigManager, "bloop".getBytes(StandardCharsets.UTF_8));
|
||||||
|
|
||||||
final long COUNT = 1000;
|
final long COUNT = 1000;
|
||||||
|
|
||||||
|
@ -122,7 +124,9 @@ public class TurnTokenGeneratorTest {
|
||||||
|
|
||||||
when(mockDynamicConfigManager.getConfiguration()).thenReturn(config);
|
when(mockDynamicConfigManager.getConfiguration()).thenReturn(config);
|
||||||
|
|
||||||
final TurnTokenGenerator turnTokenGenerator = new TurnTokenGenerator(mockDynamicConfigManager);
|
final TurnTokenGenerator turnTokenGenerator =
|
||||||
|
new TurnTokenGenerator(mockDynamicConfigManager, "bloop".getBytes(StandardCharsets.UTF_8));
|
||||||
|
|
||||||
TurnToken token = turnTokenGenerator.generate("+15555555555");
|
TurnToken token = turnTokenGenerator.generate("+15555555555");
|
||||||
assertThat(token.getUrls().get(0)).isEqualTo("enrolled.org");
|
assertThat(token.getUrls().get(0)).isEqualTo("enrolled.org");
|
||||||
token = turnTokenGenerator.generate("+15555555556");
|
token = turnTokenGenerator.generate("+15555555556");
|
||||||
|
|
|
@ -329,7 +329,6 @@ class DynamicConfigurationTest {
|
||||||
{
|
{
|
||||||
final String config = REQUIRED_CONFIG.concat("""
|
final String config = REQUIRED_CONFIG.concat("""
|
||||||
turn:
|
turn:
|
||||||
secret: bloop
|
|
||||||
uriConfigs:
|
uriConfigs:
|
||||||
- uris:
|
- uris:
|
||||||
- turn:test0.org
|
- turn:test0.org
|
||||||
|
@ -344,7 +343,6 @@ class DynamicConfigurationTest {
|
||||||
.parseConfiguration(config, DynamicConfiguration.class)
|
.parseConfiguration(config, DynamicConfiguration.class)
|
||||||
.orElseThrow()
|
.orElseThrow()
|
||||||
.getTurnConfiguration();
|
.getTurnConfiguration();
|
||||||
assertThat(turnConfiguration.getSecret()).isEqualTo("bloop");
|
|
||||||
assertThat(turnConfiguration.getUriConfigs().get(0).getUris()).hasSize(2);
|
assertThat(turnConfiguration.getUriConfigs().get(0).getUris()).hasSize(2);
|
||||||
assertThat(turnConfiguration.getUriConfigs().get(1).getUris()).hasSize(1);
|
assertThat(turnConfiguration.getUriConfigs().get(1).getUris()).hasSize(1);
|
||||||
assertThat(turnConfiguration.getUriConfigs().get(0).getWeight()).isEqualTo(1);
|
assertThat(turnConfiguration.getUriConfigs().get(0).getWeight()).isEqualTo(1);
|
||||||
|
|
Loading…
Reference in New Issue