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

@@ -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();
}