Use UUIDs as rate limiter keys.

This commit is contained in:
Jon Chambers 2021-06-30 16:31:21 -04:00 committed by Jon Chambers
parent becf6afbdd
commit a680639718
20 changed files with 98 additions and 89 deletions

View File

@ -567,7 +567,7 @@ public class WhisperServerService extends Application<WhisperServerConfiguration
smsSender, dynamicConfigurationManager, turnTokenGenerator, config.getTestDevices(),
transitionalRecaptchaClient, gcmSender, apnSender, backupCredentialsGenerator,
verifyExperimentEnrollmentManager));
environment.jersey().register(new KeysController(rateLimiters, keysDynamoDb, accountsManager, preKeyRateLimiter, dynamicConfigurationManager, rateLimitChallengeManager));
environment.jersey().register(new KeysController(rateLimiters, keysDynamoDb, accountsManager, preKeyRateLimiter, rateLimitChallengeManager));
final List<Object> commonControllers = List.of(
new AttachmentControllerV1(rateLimiters, config.getAwsAttachmentsConfiguration().getAccessKey(), config.getAwsAttachmentsConfiguration().getAccessSecret(), config.getAwsAttachmentsConfiguration().getBucket()),

View File

@ -207,17 +207,17 @@ public class AccountController {
throw new WebApplicationException(Response.status(400).build());
}
String requester = ForwardedIpUtil.getMostRecentProxy(forwardedFor).orElseThrow();
String sourceHost = ForwardedIpUtil.getMostRecentProxy(forwardedFor).orElseThrow();
Optional<StoredVerificationCode> storedChallenge = pendingAccounts.getCodeForNumber(number);
CaptchaRequirement requirement = requiresCaptcha(number, transport, forwardedFor, requester, captcha, storedChallenge, pushChallenge);
CaptchaRequirement requirement = requiresCaptcha(number, transport, forwardedFor, sourceHost, captcha, storedChallenge, pushChallenge);
if (requirement.isCaptchaRequired()) {
captchaRequiredMeter.mark();
if (requirement.isAutoBlock() && shouldAutoBlock(requester)) {
logger.info("Auto-block: " + requester);
abusiveHostRules.setBlockedHost(requester, "Auto-Block");
if (requirement.isAutoBlock() && shouldAutoBlock(sourceHost)) {
logger.info("Auto-block: {}", sourceHost);
abusiveHostRules.setBlockedHost(sourceHost, "Auto-Block");
}
return Response.status(402).build();
@ -405,7 +405,7 @@ public class AccountController {
@Path("/turn/")
@Produces(MediaType.APPLICATION_JSON)
public TurnToken getTurnToken(@Auth Account account) throws RateLimitExceededException {
rateLimiters.getTurnLimiter().validate(account.getNumber());
rateLimiters.getTurnLimiter().validate(account.getUuid());
return turnTokenGenerator.generate();
}
@ -568,7 +568,7 @@ public class AccountController {
@Path("/username/{username}")
@Produces(MediaType.APPLICATION_JSON)
public Response setUsername(@Auth Account account, @PathParam("username") String username) throws RateLimitExceededException {
rateLimiters.getUsernameSetLimiter().validate(account.getUuid().toString());
rateLimiters.getUsernameSetLimiter().validate(account.getUuid());
if (username == null || username.isEmpty()) {
return Response.status(Response.Status.BAD_REQUEST).build();
@ -588,14 +588,14 @@ public class AccountController {
}
private CaptchaRequirement requiresCaptcha(String number, String transport, String forwardedFor,
String requester,
String sourceHost,
Optional<String> captchaToken,
Optional<StoredVerificationCode> storedVerificationCode,
Optional<String> pushChallenge)
{
if (captchaToken.isPresent()) {
boolean validToken = recaptchaClient.verify(captchaToken.get(), requester);
boolean validToken = recaptchaClient.verify(captchaToken.get(), sourceHost);
if (validToken) {
captchaSuccessMeter.mark();
@ -633,18 +633,18 @@ public class AccountController {
}
}
List<AbusiveHostRule> abuseRules = abusiveHostRules.getAbusiveHostRulesFor(requester);
List<AbusiveHostRule> abuseRules = abusiveHostRules.getAbusiveHostRulesFor(sourceHost);
for (AbusiveHostRule abuseRule : abuseRules) {
if (abuseRule.isBlocked()) {
logger.info("Blocked host: " + transport + ", " + number + ", " + requester + " (" + forwardedFor + ")");
logger.info("Blocked host: {}, {}, {} ({})", transport, number, sourceHost, forwardedFor);
blockedHostMeter.mark();
return new CaptchaRequirement(true, false);
}
if (!abuseRule.getRegions().isEmpty()) {
if (abuseRule.getRegions().stream().noneMatch(number::startsWith)) {
logger.info("Restricted host: " + transport + ", " + number + ", " + requester + " (" + forwardedFor + ")");
logger.info("Restricted host: {}, {}, {} ({})", transport, number, sourceHost, forwardedFor);
filteredHostMeter.mark();
return new CaptchaRequirement(true, false);
}
@ -652,9 +652,9 @@ public class AccountController {
}
try {
rateLimiters.getSmsVoiceIpLimiter().validate(requester);
rateLimiters.getSmsVoiceIpLimiter().validate(sourceHost);
} catch (RateLimitExceededException e) {
logger.info("Rate limited exceeded: " + transport + ", " + number + ", " + requester + " (" + forwardedFor + ")");
logger.info("Rate limit exceeded: {}, {}, {} ({})", transport, number, sourceHost, forwardedFor);
rateLimitedHostMeter.mark();
return new CaptchaRequirement(true, true);
}
@ -662,7 +662,7 @@ public class AccountController {
try {
rateLimiters.getSmsVoicePrefixLimiter().validate(Util.getNumberPrefix(number));
} catch (RateLimitExceededException e) {
logger.info("Prefix rate limit exceeded: " + transport + ", " + number + ", (" + forwardedFor + ")");
logger.info("Prefix rate limit exceeded: {}, {}, {} ({})", transport, number, sourceHost, forwardedFor);
rateLimitedPrefixMeter.mark();
return new CaptchaRequirement(true, true);
}
@ -682,9 +682,9 @@ public class AccountController {
accounts.delete(account, AccountsManager.DeletionReason.USER_REQUEST);
}
private boolean shouldAutoBlock(String requester) {
private boolean shouldAutoBlock(String sourceHost) {
try {
rateLimiters.getAutoBlockLimiter().validate(requester);
rateLimiters.getAutoBlockLimiter().validate(sourceHost);
} catch (RateLimitExceededException e) {
return true;
}

View File

@ -49,7 +49,7 @@ public class AttachmentControllerV1 extends AttachmentControllerBase {
throws RateLimitExceededException
{
if (account.isRateLimited()) {
rateLimiters.getAttachmentLimiter().validate(account.getNumber());
rateLimiters.getAttachmentLimiter().validate(account.getUuid());
}
long attachmentId = generateAttachmentId();

View File

@ -41,7 +41,7 @@ public class AttachmentControllerV2 extends AttachmentControllerBase {
@Produces(MediaType.APPLICATION_JSON)
@Path("/form/upload")
public AttachmentDescriptorV2 getAttachmentUploadForm(@Auth Account account) throws RateLimitExceededException {
rateLimiter.validate(account.getNumber());
rateLimiter.validate(account.getUuid());
ZonedDateTime now = ZonedDateTime.now(ZoneOffset.UTC);
long attachmentId = generateAttachmentId();

View File

@ -58,7 +58,7 @@ public class AttachmentControllerV3 extends AttachmentControllerBase {
@Produces(MediaType.APPLICATION_JSON)
@Path("/form/upload")
public AttachmentDescriptorV3 getAttachmentUploadForm(@Auth Account account) throws RateLimitExceededException {
rateLimiter.validate(account.getNumber());
rateLimiter.validate(account.getUuid());
final ZonedDateTime now = ZonedDateTime.now(ZoneOffset.UTC);
final String key = generateAttachmentKey();

View File

@ -112,7 +112,7 @@ public class DeviceController {
public VerificationCode createDeviceToken(@Auth Account account)
throws RateLimitExceededException, DeviceLimitExceededException
{
rateLimiters.getAllocateDeviceLimiter().validate(account.getNumber());
rateLimiters.getAllocateDeviceLimiter().validate(account.getUuid());
int maxDeviceLimit = MAX_DEVICES;

View File

@ -40,11 +40,9 @@ import org.whispersystems.textsecuregcm.limits.PreKeyRateLimiter;
import org.whispersystems.textsecuregcm.limits.RateLimitChallengeException;
import org.whispersystems.textsecuregcm.limits.RateLimitChallengeManager;
import org.whispersystems.textsecuregcm.limits.RateLimiters;
import org.whispersystems.textsecuregcm.sqs.DirectoryQueue;
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.KeysDynamoDb;
import org.whispersystems.textsecuregcm.util.Util;
@ -57,7 +55,6 @@ public class KeysController {
private final AccountsManager accounts;
private final PreKeyRateLimiter preKeyRateLimiter;
private final DynamicConfigurationManager dynamicConfigurationManager;
private final RateLimitChallengeManager rateLimitChallengeManager;
private static final String PREKEY_REQUEST_COUNTER_NAME = name(KeysController.class, "preKeyGet");
@ -69,15 +66,12 @@ public class KeysController {
public KeysController(RateLimiters rateLimiters, KeysDynamoDb keysDynamoDb, AccountsManager accounts,
PreKeyRateLimiter preKeyRateLimiter,
DynamicConfigurationManager dynamicConfigurationManager,
RateLimitChallengeManager rateLimitChallengeManager) {
this.rateLimiters = rateLimiters;
this.keysDynamoDb = keysDynamoDb;
this.accounts = accounts;
this.preKeyRateLimiter = preKeyRateLimiter;
this.dynamicConfigurationManager = dynamicConfigurationManager;
this.rateLimitChallengeManager = rateLimitChallengeManager;
this.rateLimitChallengeManager = rateLimitChallengeManager;
}
@GET
@ -152,7 +146,7 @@ public class KeysController {
}
if (account.isPresent()) {
rateLimiters.getPreKeysLimiter().validate(account.get().getNumber() + "." + account.get().getAuthenticatedDevice().get().getId() + "__" + target.get().getNumber() + "." + deviceId);
rateLimiters.getPreKeysLimiter().validate(account.get().getUuid() + "." + account.get().getAuthenticatedDevice().get().getId() + "__" + target.get().getUuid() + "." + deviceId);
try {
preKeyRateLimiter.validate(account.get());

View File

@ -257,7 +257,7 @@ public class MessageController {
assert(destination.isPresent());
if (source.isPresent() && !source.get().isFor(destinationName)) {
rateLimiters.getMessagesLimiter().validate(source.get().getNumber() + "__" + destination.get().getUuid());
rateLimiters.getMessagesLimiter().validate(source.get().getUuid(), destination.get().getUuid());
final String senderCountryCode = Util.getCountryCode(source.get().getNumber());

View File

@ -210,7 +210,7 @@ public class ProfileController {
}
if (requestAccount.isPresent()) {
rateLimiters.getProfileLimiter().validate(requestAccount.get().getNumber());
rateLimiters.getProfileLimiter().validate(requestAccount.get().getUuid());
}
Optional<Account> accountProfile = accountsManager.get(uuid);
@ -260,7 +260,7 @@ public class ProfileController {
@Produces(MediaType.APPLICATION_JSON)
@Path("/username/{username}")
public Profile getProfileByUsername(@Auth Account account, @PathParam("username") String username) throws RateLimitExceededException {
rateLimiters.getUsernameLookupLimiter().validate(account.getUuid().toString());
rateLimiters.getUsernameLookupLimiter().validate(account.getUuid());
username = username.toLowerCase();
@ -341,7 +341,7 @@ public class ProfileController {
}
if (requestAccount.isPresent()) {
rateLimiters.getProfileLimiter().validate(requestAccount.get().getNumber());
rateLimiters.getProfileLimiter().validate(requestAccount.get().getUuid());
}
Optional<Account> accountProfile = accountsManager.get(identifier);

View File

@ -6,13 +6,8 @@
package org.whispersystems.textsecuregcm.controllers;
import com.codahale.metrics.annotation.Timed;
import org.whispersystems.textsecuregcm.entities.ProvisioningMessage;
import org.whispersystems.textsecuregcm.limits.RateLimiters;
import org.whispersystems.textsecuregcm.push.ProvisioningManager;
import org.whispersystems.textsecuregcm.storage.Account;
import org.whispersystems.textsecuregcm.websocket.InvalidWebsocketAddressException;
import org.whispersystems.textsecuregcm.websocket.ProvisioningAddress;
import io.dropwizard.auth.Auth;
import java.util.Base64;
import javax.validation.Valid;
import javax.ws.rs.Consumes;
import javax.ws.rs.PUT;
@ -22,10 +17,11 @@ import javax.ws.rs.Produces;
import javax.ws.rs.WebApplicationException;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import java.io.IOException;
import java.util.Base64;
import io.dropwizard.auth.Auth;
import org.whispersystems.textsecuregcm.entities.ProvisioningMessage;
import org.whispersystems.textsecuregcm.limits.RateLimiters;
import org.whispersystems.textsecuregcm.push.ProvisioningManager;
import org.whispersystems.textsecuregcm.storage.Account;
import org.whispersystems.textsecuregcm.websocket.ProvisioningAddress;
@Path("/v1/provisioning")
public class ProvisioningController {
@ -46,9 +42,9 @@ public class ProvisioningController {
public void sendProvisioningMessage(@Auth Account source,
@PathParam("destination") String destinationName,
@Valid ProvisioningMessage message)
throws RateLimitExceededException, InvalidWebsocketAddressException, IOException
{
rateLimiters.getMessagesLimiter().validate(source.getNumber());
throws RateLimitExceededException {
rateLimiters.getMessagesLimiter().validate(source.getUuid());
if (!provisioningManager.sendProvisioningMessage(new ProvisioningAddress(destinationName, 0),
Base64.getDecoder().decode(message.getBody())))

View File

@ -49,7 +49,7 @@ public class StickerController {
@PathParam("count") @Min(1) @Max(201) int stickerCount)
throws RateLimitExceededException
{
rateLimiters.getStickerPackLimiter().validate(account.getNumber());
rateLimiters.getStickerPackLimiter().validate(account.getUuid());
ZonedDateTime now = ZonedDateTime.now(ZoneOffset.UTC);
String packId = generatePackId();

View File

@ -49,7 +49,7 @@ public class PreKeyRateLimiter {
public void validate(final Account account) throws RateLimitExceededException {
try {
rateLimiters.getDailyPreKeysLimiter().validate(account.getNumber());
rateLimiters.getDailyPreKeysLimiter().validate(account.getUuid());
} catch (final RateLimitExceededException e) {
final boolean enforceLimit = dynamicConfigurationManager.getConfiguration()
@ -70,7 +70,7 @@ public class PreKeyRateLimiter {
public void handleRateLimitReset(final Account account) {
rateLimiters.getDailyPreKeysLimiter().clear(account.getNumber());
rateLimiters.getDailyPreKeysLimiter().clear(account.getUuid());
Metrics.counter(RATE_LIMIT_RESET_COUNTER_NAME, "countryCode", Util.getCountryCode(account.getNumber()))
.increment();

View File

@ -54,12 +54,12 @@ public class RateLimitChallengeManager {
}
public void answerPushChallenge(final Account account, final String challenge) throws RateLimitExceededException {
rateLimiters.getPushChallengeAttemptLimiter().validate(account.getNumber());
rateLimiters.getPushChallengeAttemptLimiter().validate(account.getUuid());
final boolean challengeSuccess = pushChallengeManager.answerChallenge(account, challenge);
if (challengeSuccess) {
rateLimiters.getPushChallengeSuccessLimiter().validate(account.getNumber());
rateLimiters.getPushChallengeSuccessLimiter().validate(account.getUuid());
resetRateLimits(account);
}
}
@ -67,7 +67,7 @@ public class RateLimitChallengeManager {
public void answerRecaptchaChallenge(final Account account, final String captcha, final String mostRecentProxyIp)
throws RateLimitExceededException {
rateLimiters.getRecaptchaChallengeAttemptLimiter().validate(account.getNumber());
rateLimiters.getRecaptchaChallengeAttemptLimiter().validate(account.getUuid());
final boolean challengeSuccess = recaptchaClient.verify(captcha, mostRecentProxyIp);
@ -76,14 +76,14 @@ public class RateLimitChallengeManager {
SUCCESS_TAG_NAME, String.valueOf(challengeSuccess)).increment();
if (challengeSuccess) {
rateLimiters.getRecaptchaChallengeSuccessLimiter().validate(account.getNumber());
rateLimiters.getRecaptchaChallengeSuccessLimiter().validate(account.getUuid());
resetRateLimits(account);
}
}
private void resetRateLimits(final Account account) throws RateLimitExceededException {
try {
rateLimiters.getRateLimitResetLimiter().validate(account.getNumber());
rateLimiters.getRateLimitResetLimiter().validate(account.getUuid());
} catch (final RateLimitExceededException e) {
Metrics.counter(RESET_RATE_LIMIT_EXCEEDED_COUNTER_NAME,
SOURCE_COUNTRY_TAG_NAME, Util.getCountryCode(account.getNumber())).increment();
@ -112,16 +112,14 @@ public class RateLimitChallengeManager {
public List<String> getChallengeOptions(final Account account) {
final List<String> options = new ArrayList<>(2);
final String key = account.getNumber();
if (rateLimiters.getRecaptchaChallengeAttemptLimiter().hasAvailablePermits(key, 1) &&
rateLimiters.getRecaptchaChallengeSuccessLimiter().hasAvailablePermits(key, 1)) {
if (rateLimiters.getRecaptchaChallengeAttemptLimiter().hasAvailablePermits(account.getUuid(), 1) &&
rateLimiters.getRecaptchaChallengeSuccessLimiter().hasAvailablePermits(account.getUuid(), 1)) {
options.add(OPTION_RECAPTCHA);
}
if (rateLimiters.getPushChallengeAttemptLimiter().hasAvailablePermits(key, 1) &&
rateLimiters.getPushChallengeSuccessLimiter().hasAvailablePermits(key, 1)) {
if (rateLimiters.getPushChallengeAttemptLimiter().hasAvailablePermits(account.getUuid(), 1) &&
rateLimiters.getPushChallengeSuccessLimiter().hasAvailablePermits(account.getUuid(), 1)) {
options.add(OPTION_PUSH_CHALLENGE);
}

View File

@ -14,6 +14,7 @@ import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import java.io.IOException;
import java.time.Duration;
import java.util.UUID;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.whispersystems.textsecuregcm.configuration.RateLimitsConfiguration.RateLimitConfiguration;
@ -61,14 +62,32 @@ public class RateLimiter {
}
}
public void validate(final UUID accountUuid) throws RateLimitExceededException {
validate(accountUuid.toString());
}
public void validate(final UUID sourceAccountUuid, final UUID destinationAccountUuid)
throws RateLimitExceededException {
validate(sourceAccountUuid.toString() + "__" + destinationAccountUuid.toString());
}
public void validate(String key) throws RateLimitExceededException {
validate(key, 1);
}
public boolean hasAvailablePermits(final UUID accountUuid, final int permits) {
return hasAvailablePermits(accountUuid.toString(), permits);
}
public boolean hasAvailablePermits(final String key, final int permits) {
return getBucket(key).getTimeUntilSpaceAvailable(permits).equals(Duration.ZERO);
}
public void clear(final UUID accountUuid) {
clear(accountUuid.toString());
}
public void clear(String key) {
cacheCluster.useCluster(connection -> connection.sync().del(getBucketName(key)));
}

View File

@ -65,7 +65,7 @@ public class UnsealedSenderRateLimiter {
try {
rateLimiters.getUnsealedSenderCardinalityLimiter()
.validate(sender.getNumber(), destination.getUuid().toString(), maxCardinality);
.validate(sender.getUuid().toString(), destination.getUuid().toString(), maxCardinality);
} catch (final RateLimitExceededException e) {
final boolean enforceLimit = dynamicConfigurationManager.getConfiguration()
@ -91,7 +91,7 @@ public class UnsealedSenderRateLimiter {
final long ttl;
{
final long remainingTtl = unsealedSenderCardinalityLimiter.getRemainingTtl(account.getNumber());
final long remainingTtl = unsealedSenderCardinalityLimiter.getRemainingTtl(account.getUuid().toString());
ttl = remainingTtl > 0 ? remainingTtl : unsealedSenderCardinalityLimiter.getInitialTtl().toSeconds();
}

View File

@ -49,7 +49,7 @@ class PreKeyRateLimiterTest {
void enforcementConfiguration() throws RateLimitExceededException {
doThrow(RateLimitExceededException.class)
.when(dailyPreKeyLimiter).validate(any());
.when(dailyPreKeyLimiter).validate(any(UUID.class));
when(rateLimitChallengeConfiguration.isPreKeyLimitEnforced()).thenReturn(false);

View File

@ -7,12 +7,13 @@ import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyZeroInteractions;
import static org.mockito.Mockito.verifyNoInteractions;
import static org.mockito.Mockito.when;
import com.vdurmont.semver4j.Semver;
import java.util.List;
import java.util.Optional;
import java.util.UUID;
import java.util.stream.Stream;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.params.ParameterizedTest;
@ -66,6 +67,8 @@ class RateLimitChallengeManagerTest {
@ValueSource(booleans = {true, false})
void answerPushChallenge(final boolean successfulChallenge) throws RateLimitExceededException {
final Account account = mock(Account.class);
when(account.getUuid()).thenReturn(UUID.randomUUID());
when(pushChallengeManager.answerChallenge(eq(account), any())).thenReturn(successfulChallenge);
when(rateLimiters.getPushChallengeAttemptLimiter()).thenReturn(mock(RateLimiter.class));
@ -78,8 +81,8 @@ class RateLimitChallengeManagerTest {
verify(preKeyRateLimiter).handleRateLimitReset(account);
verify(unsealedSenderRateLimiter).handleRateLimitReset(account);
} else {
verifyZeroInteractions(preKeyRateLimiter);
verifyZeroInteractions(unsealedSenderRateLimiter);
verifyNoInteractions(preKeyRateLimiter);
verifyNoInteractions(unsealedSenderRateLimiter);
}
}
@ -88,6 +91,7 @@ class RateLimitChallengeManagerTest {
void answerRecaptchaChallenge(final boolean successfulChallenge) throws RateLimitExceededException {
final Account account = mock(Account.class);
when(account.getNumber()).thenReturn("+18005551234");
when(account.getUuid()).thenReturn(UUID.randomUUID());
when(recaptchaClient.verify(any(), any())).thenReturn(successfulChallenge);
@ -101,8 +105,8 @@ class RateLimitChallengeManagerTest {
verify(preKeyRateLimiter).handleRateLimitReset(account);
verify(unsealedSenderRateLimiter).handleRateLimitReset(account);
} else {
verifyZeroInteractions(preKeyRateLimiter);
verifyZeroInteractions(unsealedSenderRateLimiter);
verifyNoInteractions(preKeyRateLimiter);
verifyNoInteractions(unsealedSenderRateLimiter);
}
}
@ -150,14 +154,17 @@ class RateLimitChallengeManagerTest {
when(rateLimiters.getPushChallengeAttemptLimiter()).thenReturn(pushChallengeAttemptLimiter);
when(rateLimiters.getPushChallengeSuccessLimiter()).thenReturn(pushChallengeSuccessLimiter);
when(recaptchaChallengeAttemptLimiter.hasAvailablePermits(any(), anyInt())).thenReturn(captchaAttemptPermitted);
when(recaptchaChallengeSuccessLimiter.hasAvailablePermits(any(), anyInt())).thenReturn(captchaSuccessPermitted);
when(pushChallengeAttemptLimiter.hasAvailablePermits(any(), anyInt())).thenReturn(pushAttemptPermitted);
when(pushChallengeSuccessLimiter.hasAvailablePermits(any(), anyInt())).thenReturn(pushSuccessPermitted);
when(recaptchaChallengeAttemptLimiter.hasAvailablePermits(any(UUID.class), anyInt())).thenReturn(captchaAttemptPermitted);
when(recaptchaChallengeSuccessLimiter.hasAvailablePermits(any(UUID.class), anyInt())).thenReturn(captchaSuccessPermitted);
when(pushChallengeAttemptLimiter.hasAvailablePermits(any(UUID.class), anyInt())).thenReturn(pushAttemptPermitted);
when(pushChallengeSuccessLimiter.hasAvailablePermits(any(UUID.class), anyInt())).thenReturn(pushSuccessPermitted);
final int expectedLength = (expectCaptcha ? 1 : 0) + (expectPushChallenge ? 1 : 0);
final List<String> options = rateLimitChallengeManager.getChallengeOptions(mock(Account.class));
final Account account = mock(Account.class);
when(account.getUuid()).thenReturn(UUID.randomUUID());
final List<String> options = rateLimitChallengeManager.getChallengeOptions(account);
assertEquals(expectedLength, options.size());
if (expectCaptcha) {

View File

@ -60,7 +60,6 @@ import org.whispersystems.textsecuregcm.mappers.RateLimitChallengeExceptionMappe
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.KeysDynamoDb;
import org.whispersystems.textsecuregcm.tests.util.AccountsHelper;
import org.whispersystems.textsecuregcm.tests.util.AuthHelper;
@ -95,8 +94,6 @@ class KeysControllerTest {
private final static RateLimitChallengeManager rateLimitChallengeManager = mock(RateLimitChallengeManager.class );
private final static Account existsAccount = mock(Account.class );
private final static DynamicConfigurationManager dynamicConfigurationManager = mock(DynamicConfigurationManager.class);
private static final RateLimiters rateLimiters = mock(RateLimiters.class);
private static final RateLimiter rateLimiter = mock(RateLimiter.class );
@ -105,7 +102,7 @@ class KeysControllerTest {
.addProvider(new PolymorphicAuthValueFactoryProvider.Binder<>(ImmutableSet.of(Account.class, DisabledPermittedAccount.class)))
.setTestContainerFactory(new GrizzlyWebTestContainerFactory())
.addResource(new RateLimitChallengeExceptionMapper(rateLimitChallengeManager))
.addResource(new KeysController(rateLimiters, keysDynamoDb, accounts, preKeyRateLimiter, dynamicConfigurationManager, rateLimitChallengeManager))
.addResource(new KeysController(rateLimiters, keysDynamoDb, accounts, preKeyRateLimiter, rateLimitChallengeManager))
.build();
@BeforeEach
@ -186,7 +183,6 @@ class KeysControllerTest {
existsAccount,
rateLimiters,
rateLimiter,
dynamicConfigurationManager,
rateLimitChallengeManager
);
}

View File

@ -185,7 +185,7 @@ class ProfileControllerTest {
verify(accountsManager, times(1)).get(argThat((ArgumentMatcher<AmbiguousIdentifier>) identifier -> identifier != null && identifier.hasUuid() && identifier.getUuid().equals(AuthHelper.VALID_UUID_TWO)));
verify(usernamesManager, times(1)).get(eq(AuthHelper.VALID_UUID_TWO));
verify(rateLimiter, times(1)).validate(eq(AuthHelper.VALID_NUMBER));
verify(rateLimiter, times(1)).validate(AuthHelper.VALID_UUID);
}
@Test
@ -206,7 +206,7 @@ class ProfileControllerTest {
verify(accountsManager, times(1)).get(argThat((ArgumentMatcher<AmbiguousIdentifier>) identifier -> identifier != null && identifier.hasNumber() && identifier.getNumber().equals(AuthHelper.VALID_NUMBER_TWO)));
verifyNoMoreInteractions(usernamesManager);
verify(rateLimiter, times(1)).validate(eq(AuthHelper.VALID_NUMBER));
verify(rateLimiter, times(1)).validate(AuthHelper.VALID_UUID);
}
@Test
@ -225,7 +225,7 @@ class ProfileControllerTest {
verify(accountsManager, times(1)).get(eq(AuthHelper.VALID_UUID_TWO));
verify(usernamesManager, times(1)).get(eq("n00bkiller"));
verify(usernameRateLimiter, times(1)).validate(eq(AuthHelper.VALID_UUID.toString()));
verify(usernameRateLimiter, times(1)).validate(eq(AuthHelper.VALID_UUID));
}
@Test
@ -260,7 +260,7 @@ class ProfileControllerTest {
assertThat(response.getStatus()).isEqualTo(404);
verify(usernamesManager, times(1)).get(eq("n00bkillerzzzzz"));
verify(usernameRateLimiter, times(1)).validate(eq(AuthHelper.VALID_UUID.toString()));
verify(usernameRateLimiter, times(1)).validate(eq(AuthHelper.VALID_UUID));
}
@ -587,7 +587,7 @@ class ProfileControllerTest {
verify(usernamesManager, times(1)).get(eq(AuthHelper.VALID_UUID_TWO));
verify(profilesManager, times(1)).get(eq(AuthHelper.VALID_UUID_TWO), eq("validversion"));
verify(rateLimiter, times(1)).validate(eq(AuthHelper.VALID_NUMBER));
verify(rateLimiter, times(1)).validate(AuthHelper.VALID_UUID);
}
@Test

View File

@ -6,7 +6,6 @@
package org.whispersystems.textsecuregcm.tests.controllers;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
@ -35,8 +34,8 @@ import org.whispersystems.textsecuregcm.util.SystemMapper;
@ExtendWith(DropwizardExtensionsSupport.class)
class StickerControllerTest {
private static RateLimiter rateLimiter = mock(RateLimiter.class );
private static RateLimiters rateLimiters = mock(RateLimiters.class);
private static final RateLimiter rateLimiter = mock(RateLimiter.class );
private static final RateLimiters rateLimiters = mock(RateLimiters.class);
private static final ResourceExtension resources = ResourceExtension.builder()
.addProvider(AuthHelper.getAuthFilter())
@ -86,7 +85,7 @@ class StickerControllerTest {
}
verify(rateLimiters, times(1)).getStickerPackLimiter();
verify(rateLimiter, times(1)).validate(eq(AuthHelper.VALID_NUMBER));
verify(rateLimiter, times(1)).validate(AuthHelper.VALID_UUID);
}
@Test