Control enforcement of unsealed sender rate limits via dynamic configuration.
This commit is contained in:
parent
6332552346
commit
5f49772ca6
|
@ -392,7 +392,7 @@ public class WhisperServerService extends Application<WhisperServerConfiguration
|
|||
AttachmentControllerV2 attachmentControllerV2 = new AttachmentControllerV2(rateLimiters, config.getAwsAttachmentsConfiguration().getAccessKey(), config.getAwsAttachmentsConfiguration().getAccessSecret(), config.getAwsAttachmentsConfiguration().getRegion(), config.getAwsAttachmentsConfiguration().getBucket());
|
||||
AttachmentControllerV3 attachmentControllerV3 = new AttachmentControllerV3(rateLimiters, config.getGcpAttachmentsConfiguration().getDomain(), config.getGcpAttachmentsConfiguration().getEmail(), config.getGcpAttachmentsConfiguration().getMaxSizeInBytes(), config.getGcpAttachmentsConfiguration().getPathPrefix(), config.getGcpAttachmentsConfiguration().getRsaSigningKey());
|
||||
KeysController keysController = new KeysController(rateLimiters, keysDynamoDb, accountsManager, directoryQueue);
|
||||
MessageController messageController = new MessageController(rateLimiters, messageSender, receiptSender, accountsManager, messagesManager, apnFallbackManager);
|
||||
MessageController messageController = new MessageController(rateLimiters, messageSender, receiptSender, accountsManager, messagesManager, apnFallbackManager, dynamicConfigurationManager);
|
||||
ProfileController profileController = new ProfileController(rateLimiters, accountsManager, profilesManager, usernamesManager, cdnS3Client, profileCdnPolicyGenerator, profileCdnPolicySigner, config.getCdnConfiguration().getBucket(), zkProfileOperations, isZkEnabled);
|
||||
StickerController stickerController = new StickerController(rateLimiters, config.getCdnConfiguration().getAccessKey(), config.getCdnConfiguration().getAccessSecret(), config.getCdnConfiguration().getRegion(), config.getCdnConfiguration().getBucket());
|
||||
RemoteConfigController remoteConfigController = new RemoteConfigController(remoteConfigsManager, config.getRemoteConfigConfiguration().getAuthorizedTokens(), config.getRemoteConfigConfiguration().getGlobalConfig());
|
||||
|
|
|
@ -22,6 +22,10 @@ public class DynamicConfiguration {
|
|||
@Valid
|
||||
private DynamicRemoteDeprecationConfiguration remoteDeprecation = new DynamicRemoteDeprecationConfiguration();
|
||||
|
||||
@JsonProperty
|
||||
@Valid
|
||||
private DynamicMessageRateConfiguration messageRate = new DynamicMessageRateConfiguration();
|
||||
|
||||
@JsonProperty
|
||||
private Set<String> featureFlags = Collections.emptySet();
|
||||
|
||||
|
@ -37,6 +41,10 @@ public class DynamicConfiguration {
|
|||
return remoteDeprecation;
|
||||
}
|
||||
|
||||
public DynamicMessageRateConfiguration getMessageRateConfiguration() {
|
||||
return messageRate;
|
||||
}
|
||||
|
||||
public Set<String> getActiveFeatureFlags() {
|
||||
return featureFlags;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,18 @@
|
|||
/*
|
||||
* Copyright 2021 Signal Messenger, LLC
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
|
||||
package org.whispersystems.textsecuregcm.configuration.dynamic;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
|
||||
public class DynamicMessageRateConfiguration {
|
||||
|
||||
@JsonProperty
|
||||
private boolean enforceUnsealedSenderRateLimit = false;
|
||||
|
||||
public boolean isEnforceUnsealedSenderRateLimit() {
|
||||
return enforceUnsealedSenderRateLimit;
|
||||
}
|
||||
}
|
|
@ -59,6 +59,7 @@ import org.whispersystems.textsecuregcm.redis.RedisOperation;
|
|||
import org.whispersystems.textsecuregcm.storage.Account;
|
||||
import org.whispersystems.textsecuregcm.storage.AccountsManager;
|
||||
import org.whispersystems.textsecuregcm.storage.Device;
|
||||
import org.whispersystems.textsecuregcm.storage.DynamicConfigurationManager;
|
||||
import org.whispersystems.textsecuregcm.storage.MessagesManager;
|
||||
import org.whispersystems.textsecuregcm.util.Base64;
|
||||
import org.whispersystems.textsecuregcm.util.Constants;
|
||||
|
@ -79,12 +80,13 @@ public class MessageController {
|
|||
private final Timer sendMessageInternalTimer = metricRegistry.timer(name(getClass(), "sendMessageInternal"));
|
||||
private final Histogram outgoingMessageListSizeHistogram = metricRegistry.histogram(name(getClass(), "outgoingMessageListSize"));
|
||||
|
||||
private final RateLimiters rateLimiters;
|
||||
private final MessageSender messageSender;
|
||||
private final ReceiptSender receiptSender;
|
||||
private final AccountsManager accountsManager;
|
||||
private final MessagesManager messagesManager;
|
||||
private final ApnFallbackManager apnFallbackManager;
|
||||
private final RateLimiters rateLimiters;
|
||||
private final MessageSender messageSender;
|
||||
private final ReceiptSender receiptSender;
|
||||
private final AccountsManager accountsManager;
|
||||
private final MessagesManager messagesManager;
|
||||
private final ApnFallbackManager apnFallbackManager;
|
||||
private final DynamicConfigurationManager dynamicConfigurationManager;
|
||||
|
||||
private static final String SENT_MESSAGE_COUNTER_NAME = name(MessageController.class, "sentMessages");
|
||||
private static final String REJECT_UNSEALED_SENDER_COUNTER_NAME = name(MessageController.class, "rejectUnsealedSenderLimit");
|
||||
|
@ -102,14 +104,16 @@ public class MessageController {
|
|||
ReceiptSender receiptSender,
|
||||
AccountsManager accountsManager,
|
||||
MessagesManager messagesManager,
|
||||
ApnFallbackManager apnFallbackManager)
|
||||
ApnFallbackManager apnFallbackManager,
|
||||
DynamicConfigurationManager dynamicConfigurationManager)
|
||||
{
|
||||
this.rateLimiters = rateLimiters;
|
||||
this.messageSender = messageSender;
|
||||
this.receiptSender = receiptSender;
|
||||
this.accountsManager = accountsManager;
|
||||
this.messagesManager = messagesManager;
|
||||
this.apnFallbackManager = apnFallbackManager;
|
||||
this.rateLimiters = rateLimiters;
|
||||
this.messageSender = messageSender;
|
||||
this.receiptSender = receiptSender;
|
||||
this.accountsManager = accountsManager;
|
||||
this.messagesManager = messagesManager;
|
||||
this.apnFallbackManager = apnFallbackManager;
|
||||
this.dynamicConfigurationManager = dynamicConfigurationManager;
|
||||
}
|
||||
|
||||
@Timed
|
||||
|
@ -134,6 +138,10 @@ public class MessageController {
|
|||
} catch (RateLimitExceededException e) {
|
||||
Metrics.counter(REJECT_UNSEALED_SENDER_COUNTER_NAME, SENDER_COUNTRY_TAG_NAME, Util.getCountryCode(source.get().getNumber())).increment();
|
||||
logger.debug("Rejected unsealed sender limit from: {}", source.get().getNumber());
|
||||
|
||||
if (dynamicConfigurationManager.getConfiguration().getMessageRateConfiguration().isEnforceUnsealedSenderRateLimit()) {
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -107,6 +107,28 @@ public class DynamicConfigurationTest {
|
|||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testParseMessageRateConfiguration() throws JsonProcessingException {
|
||||
{
|
||||
final String emptyConfigYaml = "test: true";
|
||||
final DynamicConfiguration emptyConfig = DynamicConfigurationManager.OBJECT_MAPPER
|
||||
.readValue(emptyConfigYaml, DynamicConfiguration.class);
|
||||
|
||||
assertFalse(emptyConfig.getMessageRateConfiguration().isEnforceUnsealedSenderRateLimit());
|
||||
}
|
||||
|
||||
{
|
||||
final String messageRateConfigYaml =
|
||||
"messageRate:\n" +
|
||||
" enforceUnsealedSenderRateLimit: true";
|
||||
|
||||
final DynamicConfiguration emptyConfig = DynamicConfigurationManager.OBJECT_MAPPER
|
||||
.readValue(messageRateConfigYaml, DynamicConfiguration.class);
|
||||
|
||||
assertTrue(emptyConfig.getMessageRateConfiguration().isEnforceUnsealedSenderRateLimit());
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testParseFeatureFlags() throws JsonProcessingException {
|
||||
{
|
||||
|
|
|
@ -66,6 +66,7 @@ import org.whispersystems.textsecuregcm.push.ReceiptSender;
|
|||
import org.whispersystems.textsecuregcm.storage.Account;
|
||||
import org.whispersystems.textsecuregcm.storage.AccountsManager;
|
||||
import org.whispersystems.textsecuregcm.storage.Device;
|
||||
import org.whispersystems.textsecuregcm.storage.DynamicConfigurationManager;
|
||||
import org.whispersystems.textsecuregcm.storage.MessagesManager;
|
||||
import org.whispersystems.textsecuregcm.tests.util.AuthHelper;
|
||||
import org.whispersystems.textsecuregcm.util.Base64;
|
||||
|
@ -78,16 +79,17 @@ public class MessageControllerTest {
|
|||
private static final String MULTI_DEVICE_RECIPIENT = "+14152222222";
|
||||
private static final UUID MULTI_DEVICE_UUID = UUID.randomUUID();
|
||||
|
||||
private final MessageSender messageSender = mock(MessageSender.class);
|
||||
private final ReceiptSender receiptSender = mock(ReceiptSender.class);
|
||||
private final AccountsManager accountsManager = mock(AccountsManager.class);
|
||||
private final MessagesManager messagesManager = mock(MessagesManager.class);
|
||||
private final RateLimiters rateLimiters = mock(RateLimiters.class);
|
||||
private final RateLimiter rateLimiter = mock(RateLimiter.class);
|
||||
private final CardinalityRateLimiter unsealedSenderLimiter = mock(CardinalityRateLimiter.class);
|
||||
private final ApnFallbackManager apnFallbackManager = mock(ApnFallbackManager.class);
|
||||
private final MessageSender messageSender = mock(MessageSender.class);
|
||||
private final ReceiptSender receiptSender = mock(ReceiptSender.class);
|
||||
private final AccountsManager accountsManager = mock(AccountsManager.class);
|
||||
private final MessagesManager messagesManager = mock(MessagesManager.class);
|
||||
private final RateLimiters rateLimiters = mock(RateLimiters.class);
|
||||
private final RateLimiter rateLimiter = mock(RateLimiter.class);
|
||||
private final CardinalityRateLimiter unsealedSenderLimiter = mock(CardinalityRateLimiter.class);
|
||||
private final ApnFallbackManager apnFallbackManager = mock(ApnFallbackManager.class);
|
||||
private final DynamicConfigurationManager dynamicConfigurationManager = mock(DynamicConfigurationManager.class);
|
||||
|
||||
private final ObjectMapper mapper = new ObjectMapper();
|
||||
private final ObjectMapper mapper = new ObjectMapper();
|
||||
|
||||
@Rule
|
||||
public final ResourceTestRule resources = ResourceTestRule.builder()
|
||||
|
@ -95,7 +97,7 @@ public class MessageControllerTest {
|
|||
.addProvider(new PolymorphicAuthValueFactoryProvider.Binder<>(ImmutableSet.of(Account.class, DisabledPermittedAccount.class)))
|
||||
.setTestContainerFactory(new GrizzlyWebTestContainerFactory())
|
||||
.addResource(new MessageController(rateLimiters, messageSender, receiptSender, accountsManager,
|
||||
messagesManager, apnFallbackManager))
|
||||
messagesManager, apnFallbackManager, dynamicConfigurationManager))
|
||||
.build();
|
||||
|
||||
|
||||
|
|
Loading…
Reference in New Issue