Remove obsolete dynamic configuration

This commit is contained in:
Chris Eager 2023-05-02 09:48:46 -05:00 committed by Chris Eager
parent 3ee5ac4514
commit 57b6c10dd1
9 changed files with 13 additions and 213 deletions

View File

@ -510,9 +510,12 @@ public class WhisperServerService extends Application<WhisperServerConfiguration
RemoteConfigsManager remoteConfigsManager = new RemoteConfigsManager(remoteConfigs); RemoteConfigsManager remoteConfigsManager = new RemoteConfigsManager(remoteConfigs);
APNSender apnSender = new APNSender(apnSenderExecutor, config.getApnConfiguration()); APNSender apnSender = new APNSender(apnSenderExecutor, config.getApnConfiguration());
FcmSender fcmSender = new FcmSender(fcmSenderExecutor, config.getFcmConfiguration().credentials()); FcmSender fcmSender = new FcmSender(fcmSenderExecutor, config.getFcmConfiguration().credentials());
ApnPushNotificationScheduler apnPushNotificationScheduler = new ApnPushNotificationScheduler(pushSchedulerCluster, apnSender, accountsManager); ApnPushNotificationScheduler apnPushNotificationScheduler = new ApnPushNotificationScheduler(pushSchedulerCluster,
PushNotificationManager pushNotificationManager = new PushNotificationManager(accountsManager, apnSender, fcmSender, apnPushNotificationScheduler, pushLatencyManager, dynamicConfigurationManager); apnSender, accountsManager);
RateLimiters rateLimiters = RateLimiters.createAndValidate(config.getLimitsConfiguration(), dynamicConfigurationManager, rateLimitersCluster); PushNotificationManager pushNotificationManager = new PushNotificationManager(accountsManager, apnSender, fcmSender,
apnPushNotificationScheduler, pushLatencyManager);
RateLimiters rateLimiters = RateLimiters.createAndValidate(config.getLimitsConfiguration(),
dynamicConfigurationManager, rateLimitersCluster);
ProvisioningManager provisioningManager = new ProvisioningManager(config.getPubsubCacheConfiguration().getUri(), redisClientResources, config.getPubsubCacheConfiguration().getTimeout(), config.getPubsubCacheConfiguration().getCircuitBreakerConfiguration()); ProvisioningManager provisioningManager = new ProvisioningManager(config.getPubsubCacheConfiguration().getUri(), redisClientResources, config.getPubsubCacheConfiguration().getTimeout(), config.getPubsubCacheConfiguration().getCircuitBreakerConfiguration());
IssuedReceiptsManager issuedReceiptsManager = new IssuedReceiptsManager( IssuedReceiptsManager issuedReceiptsManager = new IssuedReceiptsManager(
config.getDynamoDbTables().getIssuedReceipts().getTableName(), config.getDynamoDbTables().getIssuedReceipts().getTableName(),

View File

@ -39,10 +39,6 @@ public class DynamicConfiguration {
@Valid @Valid
private DynamicCaptchaConfiguration captcha = new DynamicCaptchaConfiguration(); private DynamicCaptchaConfiguration captcha = new DynamicCaptchaConfiguration();
@JsonProperty
@Valid
private DynamicRateLimitChallengeConfiguration rateLimitChallenge = new DynamicRateLimitChallengeConfiguration();
@JsonProperty @JsonProperty
@Valid @Valid
private DynamicPushLatencyConfiguration pushLatency = new DynamicPushLatencyConfiguration(Collections.emptyMap()); private DynamicPushLatencyConfiguration pushLatency = new DynamicPushLatencyConfiguration(Collections.emptyMap());
@ -55,10 +51,6 @@ public class DynamicConfiguration {
@Valid @Valid
DynamicMessagePersisterConfiguration messagePersister = new DynamicMessagePersisterConfiguration(); DynamicMessagePersisterConfiguration messagePersister = new DynamicMessagePersisterConfiguration();
@JsonProperty
@Valid
DynamicPushNotificationConfiguration pushNotifications = new DynamicPushNotificationConfiguration();
@JsonProperty @JsonProperty
@Valid @Valid
@ -90,10 +82,6 @@ public class DynamicConfiguration {
return captcha; return captcha;
} }
public DynamicRateLimitChallengeConfiguration getRateLimitChallengeConfiguration() {
return rateLimitChallenge;
}
public DynamicPushLatencyConfiguration getPushLatencyConfiguration() { public DynamicPushLatencyConfiguration getPushLatencyConfiguration() {
return pushLatency; return pushLatency;
} }
@ -106,10 +94,6 @@ public class DynamicConfiguration {
return messagePersister; return messagePersister;
} }
public DynamicPushNotificationConfiguration getPushNotificationConfiguration() {
return pushNotifications;
}
public DynamicRateLimitPolicy getRateLimitPolicy() { public DynamicRateLimitPolicy getRateLimitPolicy() {
return rateLimitPolicy; return rateLimitPolicy;
} }

View File

@ -1,18 +0,0 @@
/*
* Copyright 2013-2022 Signal Messenger, LLC
* SPDX-License-Identifier: AGPL-3.0-only
*/
package org.whispersystems.textsecuregcm.configuration.dynamic;
import com.fasterxml.jackson.annotation.JsonProperty;
public class DynamicPushNotificationConfiguration {
@JsonProperty
private boolean lowUrgencyEnabled = false;
public boolean isLowUrgencyEnabled() {
return lowUrgencyEnabled;
}
}

View File

@ -1,26 +0,0 @@
package org.whispersystems.textsecuregcm.configuration.dynamic;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.google.common.annotations.VisibleForTesting;
import com.vdurmont.semver4j.Semver;
import java.util.Collections;
import java.util.Map;
import java.util.Optional;
import org.whispersystems.textsecuregcm.util.ua.ClientPlatform;
import javax.validation.constraints.NotNull;
public class DynamicRateLimitChallengeConfiguration {
@JsonProperty
@NotNull
private Map<ClientPlatform, Semver> clientSupportedVersions = Collections.emptyMap();
@VisibleForTesting
Map<ClientPlatform, Semver> getClientSupportedVersions() {
return clientSupportedVersions;
}
public Optional<Semver> getMinimumSupportedVersion(final ClientPlatform platform) {
return Optional.ofNullable(clientSupportedVersions.get(platform));
}
}

View File

@ -5,44 +5,19 @@
package org.whispersystems.textsecuregcm.limits; package org.whispersystems.textsecuregcm.limits;
import com.vdurmont.semver4j.Semver;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Optional;
import org.whispersystems.textsecuregcm.configuration.dynamic.DynamicConfiguration;
import org.whispersystems.textsecuregcm.storage.Account; import org.whispersystems.textsecuregcm.storage.Account;
import org.whispersystems.textsecuregcm.storage.DynamicConfigurationManager;
import org.whispersystems.textsecuregcm.util.ua.UnrecognizedUserAgentException;
import org.whispersystems.textsecuregcm.util.ua.UserAgent;
import org.whispersystems.textsecuregcm.util.ua.UserAgentUtil;
public class RateLimitChallengeOptionManager { public class RateLimitChallengeOptionManager {
private final RateLimiters rateLimiters; private final RateLimiters rateLimiters;
private final DynamicConfigurationManager<DynamicConfiguration> dynamicConfigurationManager;
public static final String OPTION_RECAPTCHA = "recaptcha"; public static final String OPTION_RECAPTCHA = "recaptcha";
public static final String OPTION_PUSH_CHALLENGE = "pushChallenge"; public static final String OPTION_PUSH_CHALLENGE = "pushChallenge";
public RateLimitChallengeOptionManager(final RateLimiters rateLimiters, public RateLimitChallengeOptionManager(final RateLimiters rateLimiters) {
final DynamicConfigurationManager<DynamicConfiguration> dynamicConfigurationManager) {
this.rateLimiters = rateLimiters; this.rateLimiters = rateLimiters;
this.dynamicConfigurationManager = dynamicConfigurationManager;
}
public boolean isClientBelowMinimumVersion(final String userAgent) {
try {
final UserAgent client = UserAgentUtil.parseUserAgentString(userAgent);
final Optional<Semver> minimumClientVersion = dynamicConfigurationManager.getConfiguration()
.getRateLimitChallengeConfiguration()
.getMinimumSupportedVersion(client.getPlatform());
return minimumClientVersion.map(version -> version.isGreaterThan(client.getVersion()))
.orElse(true);
} catch (final UnrecognizedUserAgentException ignored) {
return false;
}
} }
public List<String> getChallengeOptions(final Account account) { public List<String> getChallengeOptions(final Account account) {

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2013-2022 Signal Messenger, LLC * Copyright 2013 Signal Messenger, LLC
* SPDX-License-Identifier: AGPL-3.0-only * SPDX-License-Identifier: AGPL-3.0-only
*/ */
@ -14,12 +14,10 @@ import java.util.function.BiConsumer;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import org.whispersystems.textsecuregcm.configuration.dynamic.DynamicConfiguration;
import org.whispersystems.textsecuregcm.redis.RedisOperation; import org.whispersystems.textsecuregcm.redis.RedisOperation;
import org.whispersystems.textsecuregcm.storage.Account; import org.whispersystems.textsecuregcm.storage.Account;
import org.whispersystems.textsecuregcm.storage.AccountsManager; import org.whispersystems.textsecuregcm.storage.AccountsManager;
import org.whispersystems.textsecuregcm.storage.Device; import org.whispersystems.textsecuregcm.storage.Device;
import org.whispersystems.textsecuregcm.storage.DynamicConfigurationManager;
import org.whispersystems.textsecuregcm.util.Pair; import org.whispersystems.textsecuregcm.util.Pair;
import org.whispersystems.textsecuregcm.util.Util; import org.whispersystems.textsecuregcm.util.Util;
@ -30,7 +28,6 @@ public class PushNotificationManager {
private final FcmSender fcmSender; private final FcmSender fcmSender;
private final ApnPushNotificationScheduler apnPushNotificationScheduler; private final ApnPushNotificationScheduler apnPushNotificationScheduler;
private final PushLatencyManager pushLatencyManager; private final PushLatencyManager pushLatencyManager;
private final DynamicConfigurationManager<DynamicConfiguration> dynamicConfigurationManager;
private static final String SENT_NOTIFICATION_COUNTER_NAME = name(PushNotificationManager.class, "sentPushNotification"); private static final String SENT_NOTIFICATION_COUNTER_NAME = name(PushNotificationManager.class, "sentPushNotification");
private static final String FAILED_NOTIFICATION_COUNTER_NAME = name(PushNotificationManager.class, "failedPushNotification"); private static final String FAILED_NOTIFICATION_COUNTER_NAME = name(PushNotificationManager.class, "failedPushNotification");
@ -41,27 +38,21 @@ public class PushNotificationManager {
final APNSender apnSender, final APNSender apnSender,
final FcmSender fcmSender, final FcmSender fcmSender,
final ApnPushNotificationScheduler apnPushNotificationScheduler, final ApnPushNotificationScheduler apnPushNotificationScheduler,
final PushLatencyManager pushLatencyManager, final PushLatencyManager pushLatencyManager) {
final DynamicConfigurationManager<DynamicConfiguration> dynamicConfigurationManager) {
this.accountsManager = accountsManager; this.accountsManager = accountsManager;
this.apnSender = apnSender; this.apnSender = apnSender;
this.fcmSender = fcmSender; this.fcmSender = fcmSender;
this.apnPushNotificationScheduler = apnPushNotificationScheduler; this.apnPushNotificationScheduler = apnPushNotificationScheduler;
this.pushLatencyManager = pushLatencyManager; this.pushLatencyManager = pushLatencyManager;
this.dynamicConfigurationManager = dynamicConfigurationManager;
} }
public void sendNewMessageNotification(final Account destination, final long destinationDeviceId, final boolean urgent) throws NotPushRegisteredException { public void sendNewMessageNotification(final Account destination, final long destinationDeviceId, final boolean urgent) throws NotPushRegisteredException {
final Device device = destination.getDevice(destinationDeviceId).orElseThrow(NotPushRegisteredException::new); final Device device = destination.getDevice(destinationDeviceId).orElseThrow(NotPushRegisteredException::new);
final Pair<String, PushNotification.TokenType> tokenAndType = getToken(device); final Pair<String, PushNotification.TokenType> tokenAndType = getToken(device);
final boolean effectiveUrgent =
dynamicConfigurationManager.getConfiguration().getPushNotificationConfiguration().isLowUrgencyEnabled() ?
urgent : true;
sendNotification(new PushNotification(tokenAndType.first(), tokenAndType.second(), sendNotification(new PushNotification(tokenAndType.first(), tokenAndType.second(),
PushNotification.NotificationType.NOTIFICATION, null, destination, device, effectiveUrgent)); PushNotification.NotificationType.NOTIFICATION, null, destination, device, urgent));
} }
public void sendRegistrationChallengeNotification(final String deviceToken, final PushNotification.TokenType tokenType, final String challengeToken) { public void sendRegistrationChallengeNotification(final String deviceToken, final PushNotification.TokenType tokenType, final String challengeToken) {

View File

@ -312,37 +312,6 @@ class DynamicConfigurationTest {
assertThat(resetRateLimiterConfig.leakRatePerMinute()).isEqualTo(44); assertThat(resetRateLimiterConfig.leakRatePerMinute()).isEqualTo(44);
} }
@Test
void testParseRateLimitReset() throws JsonProcessingException {
{
final String emptyConfigYaml = REQUIRED_CONFIG.concat("test: true");
final DynamicConfiguration emptyConfig =
DynamicConfigurationManager.parseConfiguration(emptyConfigYaml, DynamicConfiguration.class).orElseThrow();
assertThat(emptyConfig.getRateLimitChallengeConfiguration().getClientSupportedVersions()).isEmpty();
}
{
final String rateLimitChallengeConfig = REQUIRED_CONFIG.concat("""
rateLimitChallenge:
clientSupportedVersions:
IOS: 5.1.0
ANDROID: 5.2.0
DESKTOP: 5.0.0
""");
DynamicRateLimitChallengeConfiguration rateLimitChallengeConfiguration =
DynamicConfigurationManager.parseConfiguration(rateLimitChallengeConfig, DynamicConfiguration.class).orElseThrow()
.getRateLimitChallengeConfiguration();
final Map<ClientPlatform, Semver> clientSupportedVersions = rateLimitChallengeConfiguration.getClientSupportedVersions();
assertThat(clientSupportedVersions.get(ClientPlatform.IOS)).isEqualTo(new Semver("5.1.0"));
assertThat(clientSupportedVersions.get(ClientPlatform.ANDROID)).isEqualTo(new Semver("5.2.0"));
assertThat(clientSupportedVersions.get(ClientPlatform.DESKTOP)).isEqualTo(new Semver("5.0.0"));
}
}
@Test @Test
void testParseTurnConfig() throws JsonProcessingException { void testParseTurnConfig() throws JsonProcessingException {
{ {

View File

@ -12,24 +12,17 @@ import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.Mockito.mock; import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when; import static org.mockito.Mockito.when;
import com.vdurmont.semver4j.Semver;
import java.util.List; import java.util.List;
import java.util.Optional;
import java.util.UUID; import java.util.UUID;
import java.util.stream.Stream; import java.util.stream.Stream;
import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.Arguments; import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.MethodSource; import org.junit.jupiter.params.provider.MethodSource;
import org.whispersystems.textsecuregcm.configuration.dynamic.DynamicConfiguration;
import org.whispersystems.textsecuregcm.configuration.dynamic.DynamicRateLimitChallengeConfiguration;
import org.whispersystems.textsecuregcm.storage.Account; import org.whispersystems.textsecuregcm.storage.Account;
import org.whispersystems.textsecuregcm.storage.DynamicConfigurationManager;
import org.whispersystems.textsecuregcm.util.ua.ClientPlatform;
class RateLimitChallengeOptionManagerTest { class RateLimitChallengeOptionManagerTest {
private DynamicRateLimitChallengeConfiguration rateLimitChallengeConfiguration;
private RateLimiters rateLimiters; private RateLimiters rateLimiters;
private RateLimitChallengeOptionManager rateLimitChallengeOptionManager; private RateLimitChallengeOptionManager rateLimitChallengeOptionManager;
@ -37,42 +30,7 @@ class RateLimitChallengeOptionManagerTest {
@BeforeEach @BeforeEach
void setUp() { void setUp() {
rateLimiters = mock(RateLimiters.class); rateLimiters = mock(RateLimiters.class);
rateLimitChallengeOptionManager = new RateLimitChallengeOptionManager(rateLimiters);
final DynamicConfigurationManager<DynamicConfiguration> dynamicConfigurationManager =
mock(DynamicConfigurationManager.class);
final DynamicConfiguration dynamicConfiguration = mock(DynamicConfiguration.class);
rateLimitChallengeConfiguration = mock(DynamicRateLimitChallengeConfiguration.class);
when(dynamicConfigurationManager.getConfiguration()).thenReturn(dynamicConfiguration);
when(dynamicConfiguration.getRateLimitChallengeConfiguration()).thenReturn(rateLimitChallengeConfiguration);
rateLimitChallengeOptionManager = new RateLimitChallengeOptionManager(rateLimiters, dynamicConfigurationManager);
}
@ParameterizedTest
@MethodSource
void isClientBelowMinimumVersion(final String userAgent, final boolean expectBelowMinimumVersion) {
when(rateLimitChallengeConfiguration.getMinimumSupportedVersion(any())).thenReturn(Optional.empty());
when(rateLimitChallengeConfiguration.getMinimumSupportedVersion(ClientPlatform.ANDROID))
.thenReturn(Optional.of(new Semver("5.6.0")));
when(rateLimitChallengeConfiguration.getMinimumSupportedVersion(ClientPlatform.DESKTOP))
.thenReturn(Optional.of(new Semver("5.0.0-beta.2")));
assertEquals(expectBelowMinimumVersion, rateLimitChallengeOptionManager.isClientBelowMinimumVersion(userAgent));
}
private static Stream<Arguments> isClientBelowMinimumVersion() {
return Stream.of(
Arguments.of("Signal-Android/5.1.2 Android/30", true),
Arguments.of("Signal-Android/5.6.0 Android/30", false),
Arguments.of("Signal-Android/5.11.1 Android/30", false),
Arguments.of("Signal-Desktop/5.0.0-beta.3 macOS/11", false),
Arguments.of("Signal-Desktop/5.0.0-beta.1 Windows/3.1", true),
Arguments.of("Signal-Desktop/5.2.0 Debian/11", false),
Arguments.of("Signal-iOS/5.1.2 iOS/12.2", true),
Arguments.of("anything-else", false)
);
} }
@ParameterizedTest @ParameterizedTest

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2013-2022 Signal Messenger, LLC * Copyright 2013 Signal Messenger, LLC
* SPDX-License-Identifier: AGPL-3.0-only * SPDX-License-Identifier: AGPL-3.0-only
*/ */
@ -22,12 +22,9 @@ import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.ValueSource; import org.junit.jupiter.params.provider.ValueSource;
import org.whispersystems.textsecuregcm.configuration.dynamic.DynamicConfiguration;
import org.whispersystems.textsecuregcm.configuration.dynamic.DynamicPushNotificationConfiguration;
import org.whispersystems.textsecuregcm.storage.Account; import org.whispersystems.textsecuregcm.storage.Account;
import org.whispersystems.textsecuregcm.storage.AccountsManager; import org.whispersystems.textsecuregcm.storage.AccountsManager;
import org.whispersystems.textsecuregcm.storage.Device; import org.whispersystems.textsecuregcm.storage.Device;
import org.whispersystems.textsecuregcm.storage.DynamicConfigurationManager;
import org.whispersystems.textsecuregcm.tests.util.AccountsHelper; import org.whispersystems.textsecuregcm.tests.util.AccountsHelper;
import org.whispersystems.textsecuregcm.util.Util; import org.whispersystems.textsecuregcm.util.Util;
@ -38,7 +35,6 @@ class PushNotificationManagerTest {
private FcmSender fcmSender; private FcmSender fcmSender;
private ApnPushNotificationScheduler apnPushNotificationScheduler; private ApnPushNotificationScheduler apnPushNotificationScheduler;
private PushLatencyManager pushLatencyManager; private PushLatencyManager pushLatencyManager;
private DynamicPushNotificationConfiguration pushNotificationConfiguration;
private PushNotificationManager pushNotificationManager; private PushNotificationManager pushNotificationManager;
@ -49,21 +45,11 @@ class PushNotificationManagerTest {
fcmSender = mock(FcmSender.class); fcmSender = mock(FcmSender.class);
apnPushNotificationScheduler = mock(ApnPushNotificationScheduler.class); apnPushNotificationScheduler = mock(ApnPushNotificationScheduler.class);
pushLatencyManager = mock(PushLatencyManager.class); pushLatencyManager = mock(PushLatencyManager.class);
pushNotificationConfiguration = mock(DynamicPushNotificationConfiguration.class);
@SuppressWarnings("unchecked") final DynamicConfigurationManager<DynamicConfiguration> dynamicConfigurationManager =
mock(DynamicConfigurationManager.class);
final DynamicConfiguration dynamicConfiguration = mock(DynamicConfiguration.class);
when(dynamicConfigurationManager.getConfiguration()).thenReturn(dynamicConfiguration);
when(dynamicConfiguration.getPushNotificationConfiguration()).thenReturn(pushNotificationConfiguration);
when(pushNotificationConfiguration.isLowUrgencyEnabled()).thenReturn(true);
AccountsHelper.setupMockUpdate(accountsManager); AccountsHelper.setupMockUpdate(accountsManager);
pushNotificationManager = new PushNotificationManager(accountsManager, apnSender, fcmSender, pushNotificationManager = new PushNotificationManager(accountsManager, apnSender, fcmSender,
apnPushNotificationScheduler, pushLatencyManager, dynamicConfigurationManager); apnPushNotificationScheduler, pushLatencyManager);
} }
@ParameterizedTest @ParameterizedTest
@ -85,28 +71,6 @@ class PushNotificationManagerTest {
verify(fcmSender).sendNotification(new PushNotification(deviceToken, PushNotification.TokenType.FCM, PushNotification.NotificationType.NOTIFICATION, null, account, device, urgent)); verify(fcmSender).sendNotification(new PushNotification(deviceToken, PushNotification.TokenType.FCM, PushNotification.NotificationType.NOTIFICATION, null, account, device, urgent));
} }
@ParameterizedTest
@ValueSource(booleans = {true, false})
void sendNewMessageNotificationLowUrgencyDisabled(final boolean urgent) throws NotPushRegisteredException {
final Account account = mock(Account.class);
final Device device = mock(Device.class);
final String deviceToken = "token";
when(device.getId()).thenReturn(Device.MASTER_ID);
when(device.getApnId()).thenReturn(deviceToken);
when(account.getDevice(Device.MASTER_ID)).thenReturn(Optional.of(device));
when(pushNotificationConfiguration.isLowUrgencyEnabled()).thenReturn(false);
when(apnSender.sendNotification(any()))
.thenReturn(CompletableFuture.completedFuture(new SendPushNotificationResult(true, null, false)));
pushNotificationManager.sendNewMessageNotification(account, Device.MASTER_ID, urgent);
verify(apnSender).sendNotification(new PushNotification(deviceToken, PushNotification.TokenType.APN, PushNotification.NotificationType.NOTIFICATION, null, account, device, true));
}
@Test @Test
void sendRegistrationChallengeNotification() { void sendRegistrationChallengeNotification() {
final String deviceToken = "token"; final String deviceToken = "token";