Use UUIDs as rate limiter keys.
This commit is contained in:
parent
becf6afbdd
commit
a680639718
|
@ -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()),
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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());
|
||||
|
|
|
@ -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());
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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())))
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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)));
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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
|
||||
);
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue