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(),
|
smsSender, dynamicConfigurationManager, turnTokenGenerator, config.getTestDevices(),
|
||||||
transitionalRecaptchaClient, gcmSender, apnSender, backupCredentialsGenerator,
|
transitionalRecaptchaClient, gcmSender, apnSender, backupCredentialsGenerator,
|
||||||
verifyExperimentEnrollmentManager));
|
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(
|
final List<Object> commonControllers = List.of(
|
||||||
new AttachmentControllerV1(rateLimiters, config.getAwsAttachmentsConfiguration().getAccessKey(), config.getAwsAttachmentsConfiguration().getAccessSecret(), config.getAwsAttachmentsConfiguration().getBucket()),
|
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());
|
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);
|
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()) {
|
if (requirement.isCaptchaRequired()) {
|
||||||
captchaRequiredMeter.mark();
|
captchaRequiredMeter.mark();
|
||||||
|
|
||||||
if (requirement.isAutoBlock() && shouldAutoBlock(requester)) {
|
if (requirement.isAutoBlock() && shouldAutoBlock(sourceHost)) {
|
||||||
logger.info("Auto-block: " + requester);
|
logger.info("Auto-block: {}", sourceHost);
|
||||||
abusiveHostRules.setBlockedHost(requester, "Auto-Block");
|
abusiveHostRules.setBlockedHost(sourceHost, "Auto-Block");
|
||||||
}
|
}
|
||||||
|
|
||||||
return Response.status(402).build();
|
return Response.status(402).build();
|
||||||
|
@ -405,7 +405,7 @@ public class AccountController {
|
||||||
@Path("/turn/")
|
@Path("/turn/")
|
||||||
@Produces(MediaType.APPLICATION_JSON)
|
@Produces(MediaType.APPLICATION_JSON)
|
||||||
public TurnToken getTurnToken(@Auth Account account) throws RateLimitExceededException {
|
public TurnToken getTurnToken(@Auth Account account) throws RateLimitExceededException {
|
||||||
rateLimiters.getTurnLimiter().validate(account.getNumber());
|
rateLimiters.getTurnLimiter().validate(account.getUuid());
|
||||||
return turnTokenGenerator.generate();
|
return turnTokenGenerator.generate();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -568,7 +568,7 @@ public class AccountController {
|
||||||
@Path("/username/{username}")
|
@Path("/username/{username}")
|
||||||
@Produces(MediaType.APPLICATION_JSON)
|
@Produces(MediaType.APPLICATION_JSON)
|
||||||
public Response setUsername(@Auth Account account, @PathParam("username") String username) throws RateLimitExceededException {
|
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()) {
|
if (username == null || username.isEmpty()) {
|
||||||
return Response.status(Response.Status.BAD_REQUEST).build();
|
return Response.status(Response.Status.BAD_REQUEST).build();
|
||||||
|
@ -588,14 +588,14 @@ public class AccountController {
|
||||||
}
|
}
|
||||||
|
|
||||||
private CaptchaRequirement requiresCaptcha(String number, String transport, String forwardedFor,
|
private CaptchaRequirement requiresCaptcha(String number, String transport, String forwardedFor,
|
||||||
String requester,
|
String sourceHost,
|
||||||
Optional<String> captchaToken,
|
Optional<String> captchaToken,
|
||||||
Optional<StoredVerificationCode> storedVerificationCode,
|
Optional<StoredVerificationCode> storedVerificationCode,
|
||||||
Optional<String> pushChallenge)
|
Optional<String> pushChallenge)
|
||||||
{
|
{
|
||||||
|
|
||||||
if (captchaToken.isPresent()) {
|
if (captchaToken.isPresent()) {
|
||||||
boolean validToken = recaptchaClient.verify(captchaToken.get(), requester);
|
boolean validToken = recaptchaClient.verify(captchaToken.get(), sourceHost);
|
||||||
|
|
||||||
if (validToken) {
|
if (validToken) {
|
||||||
captchaSuccessMeter.mark();
|
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) {
|
for (AbusiveHostRule abuseRule : abuseRules) {
|
||||||
if (abuseRule.isBlocked()) {
|
if (abuseRule.isBlocked()) {
|
||||||
logger.info("Blocked host: " + transport + ", " + number + ", " + requester + " (" + forwardedFor + ")");
|
logger.info("Blocked host: {}, {}, {} ({})", transport, number, sourceHost, forwardedFor);
|
||||||
blockedHostMeter.mark();
|
blockedHostMeter.mark();
|
||||||
return new CaptchaRequirement(true, false);
|
return new CaptchaRequirement(true, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!abuseRule.getRegions().isEmpty()) {
|
if (!abuseRule.getRegions().isEmpty()) {
|
||||||
if (abuseRule.getRegions().stream().noneMatch(number::startsWith)) {
|
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();
|
filteredHostMeter.mark();
|
||||||
return new CaptchaRequirement(true, false);
|
return new CaptchaRequirement(true, false);
|
||||||
}
|
}
|
||||||
|
@ -652,9 +652,9 @@ public class AccountController {
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
rateLimiters.getSmsVoiceIpLimiter().validate(requester);
|
rateLimiters.getSmsVoiceIpLimiter().validate(sourceHost);
|
||||||
} catch (RateLimitExceededException e) {
|
} catch (RateLimitExceededException e) {
|
||||||
logger.info("Rate limited exceeded: " + transport + ", " + number + ", " + requester + " (" + forwardedFor + ")");
|
logger.info("Rate limit exceeded: {}, {}, {} ({})", transport, number, sourceHost, forwardedFor);
|
||||||
rateLimitedHostMeter.mark();
|
rateLimitedHostMeter.mark();
|
||||||
return new CaptchaRequirement(true, true);
|
return new CaptchaRequirement(true, true);
|
||||||
}
|
}
|
||||||
|
@ -662,7 +662,7 @@ public class AccountController {
|
||||||
try {
|
try {
|
||||||
rateLimiters.getSmsVoicePrefixLimiter().validate(Util.getNumberPrefix(number));
|
rateLimiters.getSmsVoicePrefixLimiter().validate(Util.getNumberPrefix(number));
|
||||||
} catch (RateLimitExceededException e) {
|
} catch (RateLimitExceededException e) {
|
||||||
logger.info("Prefix rate limit exceeded: " + transport + ", " + number + ", (" + forwardedFor + ")");
|
logger.info("Prefix rate limit exceeded: {}, {}, {} ({})", transport, number, sourceHost, forwardedFor);
|
||||||
rateLimitedPrefixMeter.mark();
|
rateLimitedPrefixMeter.mark();
|
||||||
return new CaptchaRequirement(true, true);
|
return new CaptchaRequirement(true, true);
|
||||||
}
|
}
|
||||||
|
@ -682,9 +682,9 @@ public class AccountController {
|
||||||
accounts.delete(account, AccountsManager.DeletionReason.USER_REQUEST);
|
accounts.delete(account, AccountsManager.DeletionReason.USER_REQUEST);
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean shouldAutoBlock(String requester) {
|
private boolean shouldAutoBlock(String sourceHost) {
|
||||||
try {
|
try {
|
||||||
rateLimiters.getAutoBlockLimiter().validate(requester);
|
rateLimiters.getAutoBlockLimiter().validate(sourceHost);
|
||||||
} catch (RateLimitExceededException e) {
|
} catch (RateLimitExceededException e) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -49,7 +49,7 @@ public class AttachmentControllerV1 extends AttachmentControllerBase {
|
||||||
throws RateLimitExceededException
|
throws RateLimitExceededException
|
||||||
{
|
{
|
||||||
if (account.isRateLimited()) {
|
if (account.isRateLimited()) {
|
||||||
rateLimiters.getAttachmentLimiter().validate(account.getNumber());
|
rateLimiters.getAttachmentLimiter().validate(account.getUuid());
|
||||||
}
|
}
|
||||||
|
|
||||||
long attachmentId = generateAttachmentId();
|
long attachmentId = generateAttachmentId();
|
||||||
|
|
|
@ -41,7 +41,7 @@ public class AttachmentControllerV2 extends AttachmentControllerBase {
|
||||||
@Produces(MediaType.APPLICATION_JSON)
|
@Produces(MediaType.APPLICATION_JSON)
|
||||||
@Path("/form/upload")
|
@Path("/form/upload")
|
||||||
public AttachmentDescriptorV2 getAttachmentUploadForm(@Auth Account account) throws RateLimitExceededException {
|
public AttachmentDescriptorV2 getAttachmentUploadForm(@Auth Account account) throws RateLimitExceededException {
|
||||||
rateLimiter.validate(account.getNumber());
|
rateLimiter.validate(account.getUuid());
|
||||||
|
|
||||||
ZonedDateTime now = ZonedDateTime.now(ZoneOffset.UTC);
|
ZonedDateTime now = ZonedDateTime.now(ZoneOffset.UTC);
|
||||||
long attachmentId = generateAttachmentId();
|
long attachmentId = generateAttachmentId();
|
||||||
|
|
|
@ -58,7 +58,7 @@ public class AttachmentControllerV3 extends AttachmentControllerBase {
|
||||||
@Produces(MediaType.APPLICATION_JSON)
|
@Produces(MediaType.APPLICATION_JSON)
|
||||||
@Path("/form/upload")
|
@Path("/form/upload")
|
||||||
public AttachmentDescriptorV3 getAttachmentUploadForm(@Auth Account account) throws RateLimitExceededException {
|
public AttachmentDescriptorV3 getAttachmentUploadForm(@Auth Account account) throws RateLimitExceededException {
|
||||||
rateLimiter.validate(account.getNumber());
|
rateLimiter.validate(account.getUuid());
|
||||||
|
|
||||||
final ZonedDateTime now = ZonedDateTime.now(ZoneOffset.UTC);
|
final ZonedDateTime now = ZonedDateTime.now(ZoneOffset.UTC);
|
||||||
final String key = generateAttachmentKey();
|
final String key = generateAttachmentKey();
|
||||||
|
|
|
@ -112,7 +112,7 @@ public class DeviceController {
|
||||||
public VerificationCode createDeviceToken(@Auth Account account)
|
public VerificationCode createDeviceToken(@Auth Account account)
|
||||||
throws RateLimitExceededException, DeviceLimitExceededException
|
throws RateLimitExceededException, DeviceLimitExceededException
|
||||||
{
|
{
|
||||||
rateLimiters.getAllocateDeviceLimiter().validate(account.getNumber());
|
rateLimiters.getAllocateDeviceLimiter().validate(account.getUuid());
|
||||||
|
|
||||||
int maxDeviceLimit = MAX_DEVICES;
|
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.RateLimitChallengeException;
|
||||||
import org.whispersystems.textsecuregcm.limits.RateLimitChallengeManager;
|
import org.whispersystems.textsecuregcm.limits.RateLimitChallengeManager;
|
||||||
import org.whispersystems.textsecuregcm.limits.RateLimiters;
|
import org.whispersystems.textsecuregcm.limits.RateLimiters;
|
||||||
import org.whispersystems.textsecuregcm.sqs.DirectoryQueue;
|
|
||||||
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.storage.KeysDynamoDb;
|
import org.whispersystems.textsecuregcm.storage.KeysDynamoDb;
|
||||||
import org.whispersystems.textsecuregcm.util.Util;
|
import org.whispersystems.textsecuregcm.util.Util;
|
||||||
|
|
||||||
|
@ -57,7 +55,6 @@ public class KeysController {
|
||||||
private final AccountsManager accounts;
|
private final AccountsManager accounts;
|
||||||
private final PreKeyRateLimiter preKeyRateLimiter;
|
private final PreKeyRateLimiter preKeyRateLimiter;
|
||||||
|
|
||||||
private final DynamicConfigurationManager dynamicConfigurationManager;
|
|
||||||
private final RateLimitChallengeManager rateLimitChallengeManager;
|
private final RateLimitChallengeManager rateLimitChallengeManager;
|
||||||
|
|
||||||
private static final String PREKEY_REQUEST_COUNTER_NAME = name(KeysController.class, "preKeyGet");
|
private static final String PREKEY_REQUEST_COUNTER_NAME = name(KeysController.class, "preKeyGet");
|
||||||
|
@ -69,14 +66,11 @@ public class KeysController {
|
||||||
|
|
||||||
public KeysController(RateLimiters rateLimiters, KeysDynamoDb keysDynamoDb, AccountsManager accounts,
|
public KeysController(RateLimiters rateLimiters, KeysDynamoDb keysDynamoDb, AccountsManager accounts,
|
||||||
PreKeyRateLimiter preKeyRateLimiter,
|
PreKeyRateLimiter preKeyRateLimiter,
|
||||||
DynamicConfigurationManager dynamicConfigurationManager,
|
|
||||||
RateLimitChallengeManager rateLimitChallengeManager) {
|
RateLimitChallengeManager rateLimitChallengeManager) {
|
||||||
this.rateLimiters = rateLimiters;
|
this.rateLimiters = rateLimiters;
|
||||||
this.keysDynamoDb = keysDynamoDb;
|
this.keysDynamoDb = keysDynamoDb;
|
||||||
this.accounts = accounts;
|
this.accounts = accounts;
|
||||||
this.preKeyRateLimiter = preKeyRateLimiter;
|
this.preKeyRateLimiter = preKeyRateLimiter;
|
||||||
|
|
||||||
this.dynamicConfigurationManager = dynamicConfigurationManager;
|
|
||||||
this.rateLimitChallengeManager = rateLimitChallengeManager;
|
this.rateLimitChallengeManager = rateLimitChallengeManager;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -152,7 +146,7 @@ public class KeysController {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (account.isPresent()) {
|
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 {
|
try {
|
||||||
preKeyRateLimiter.validate(account.get());
|
preKeyRateLimiter.validate(account.get());
|
||||||
|
|
|
@ -257,7 +257,7 @@ public class MessageController {
|
||||||
assert(destination.isPresent());
|
assert(destination.isPresent());
|
||||||
|
|
||||||
if (source.isPresent() && !source.get().isFor(destinationName)) {
|
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());
|
final String senderCountryCode = Util.getCountryCode(source.get().getNumber());
|
||||||
|
|
||||||
|
|
|
@ -210,7 +210,7 @@ public class ProfileController {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (requestAccount.isPresent()) {
|
if (requestAccount.isPresent()) {
|
||||||
rateLimiters.getProfileLimiter().validate(requestAccount.get().getNumber());
|
rateLimiters.getProfileLimiter().validate(requestAccount.get().getUuid());
|
||||||
}
|
}
|
||||||
|
|
||||||
Optional<Account> accountProfile = accountsManager.get(uuid);
|
Optional<Account> accountProfile = accountsManager.get(uuid);
|
||||||
|
@ -260,7 +260,7 @@ public class ProfileController {
|
||||||
@Produces(MediaType.APPLICATION_JSON)
|
@Produces(MediaType.APPLICATION_JSON)
|
||||||
@Path("/username/{username}")
|
@Path("/username/{username}")
|
||||||
public Profile getProfileByUsername(@Auth Account account, @PathParam("username") String username) throws RateLimitExceededException {
|
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();
|
username = username.toLowerCase();
|
||||||
|
|
||||||
|
@ -341,7 +341,7 @@ public class ProfileController {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (requestAccount.isPresent()) {
|
if (requestAccount.isPresent()) {
|
||||||
rateLimiters.getProfileLimiter().validate(requestAccount.get().getNumber());
|
rateLimiters.getProfileLimiter().validate(requestAccount.get().getUuid());
|
||||||
}
|
}
|
||||||
|
|
||||||
Optional<Account> accountProfile = accountsManager.get(identifier);
|
Optional<Account> accountProfile = accountsManager.get(identifier);
|
||||||
|
|
|
@ -6,13 +6,8 @@
|
||||||
package org.whispersystems.textsecuregcm.controllers;
|
package org.whispersystems.textsecuregcm.controllers;
|
||||||
|
|
||||||
import com.codahale.metrics.annotation.Timed;
|
import com.codahale.metrics.annotation.Timed;
|
||||||
import org.whispersystems.textsecuregcm.entities.ProvisioningMessage;
|
import io.dropwizard.auth.Auth;
|
||||||
import org.whispersystems.textsecuregcm.limits.RateLimiters;
|
import java.util.Base64;
|
||||||
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 javax.validation.Valid;
|
import javax.validation.Valid;
|
||||||
import javax.ws.rs.Consumes;
|
import javax.ws.rs.Consumes;
|
||||||
import javax.ws.rs.PUT;
|
import javax.ws.rs.PUT;
|
||||||
|
@ -22,10 +17,11 @@ import javax.ws.rs.Produces;
|
||||||
import javax.ws.rs.WebApplicationException;
|
import javax.ws.rs.WebApplicationException;
|
||||||
import javax.ws.rs.core.MediaType;
|
import javax.ws.rs.core.MediaType;
|
||||||
import javax.ws.rs.core.Response;
|
import javax.ws.rs.core.Response;
|
||||||
import java.io.IOException;
|
import org.whispersystems.textsecuregcm.entities.ProvisioningMessage;
|
||||||
import java.util.Base64;
|
import org.whispersystems.textsecuregcm.limits.RateLimiters;
|
||||||
|
import org.whispersystems.textsecuregcm.push.ProvisioningManager;
|
||||||
import io.dropwizard.auth.Auth;
|
import org.whispersystems.textsecuregcm.storage.Account;
|
||||||
|
import org.whispersystems.textsecuregcm.websocket.ProvisioningAddress;
|
||||||
|
|
||||||
@Path("/v1/provisioning")
|
@Path("/v1/provisioning")
|
||||||
public class ProvisioningController {
|
public class ProvisioningController {
|
||||||
|
@ -46,9 +42,9 @@ public class ProvisioningController {
|
||||||
public void sendProvisioningMessage(@Auth Account source,
|
public void sendProvisioningMessage(@Auth Account source,
|
||||||
@PathParam("destination") String destinationName,
|
@PathParam("destination") String destinationName,
|
||||||
@Valid ProvisioningMessage message)
|
@Valid ProvisioningMessage message)
|
||||||
throws RateLimitExceededException, InvalidWebsocketAddressException, IOException
|
throws RateLimitExceededException {
|
||||||
{
|
|
||||||
rateLimiters.getMessagesLimiter().validate(source.getNumber());
|
rateLimiters.getMessagesLimiter().validate(source.getUuid());
|
||||||
|
|
||||||
if (!provisioningManager.sendProvisioningMessage(new ProvisioningAddress(destinationName, 0),
|
if (!provisioningManager.sendProvisioningMessage(new ProvisioningAddress(destinationName, 0),
|
||||||
Base64.getDecoder().decode(message.getBody())))
|
Base64.getDecoder().decode(message.getBody())))
|
||||||
|
|
|
@ -49,7 +49,7 @@ public class StickerController {
|
||||||
@PathParam("count") @Min(1) @Max(201) int stickerCount)
|
@PathParam("count") @Min(1) @Max(201) int stickerCount)
|
||||||
throws RateLimitExceededException
|
throws RateLimitExceededException
|
||||||
{
|
{
|
||||||
rateLimiters.getStickerPackLimiter().validate(account.getNumber());
|
rateLimiters.getStickerPackLimiter().validate(account.getUuid());
|
||||||
|
|
||||||
ZonedDateTime now = ZonedDateTime.now(ZoneOffset.UTC);
|
ZonedDateTime now = ZonedDateTime.now(ZoneOffset.UTC);
|
||||||
String packId = generatePackId();
|
String packId = generatePackId();
|
||||||
|
|
|
@ -49,7 +49,7 @@ public class PreKeyRateLimiter {
|
||||||
public void validate(final Account account) throws RateLimitExceededException {
|
public void validate(final Account account) throws RateLimitExceededException {
|
||||||
|
|
||||||
try {
|
try {
|
||||||
rateLimiters.getDailyPreKeysLimiter().validate(account.getNumber());
|
rateLimiters.getDailyPreKeysLimiter().validate(account.getUuid());
|
||||||
} catch (final RateLimitExceededException e) {
|
} catch (final RateLimitExceededException e) {
|
||||||
|
|
||||||
final boolean enforceLimit = dynamicConfigurationManager.getConfiguration()
|
final boolean enforceLimit = dynamicConfigurationManager.getConfiguration()
|
||||||
|
@ -70,7 +70,7 @@ public class PreKeyRateLimiter {
|
||||||
|
|
||||||
public void handleRateLimitReset(final Account account) {
|
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()))
|
Metrics.counter(RATE_LIMIT_RESET_COUNTER_NAME, "countryCode", Util.getCountryCode(account.getNumber()))
|
||||||
.increment();
|
.increment();
|
||||||
|
|
|
@ -54,12 +54,12 @@ public class RateLimitChallengeManager {
|
||||||
}
|
}
|
||||||
|
|
||||||
public void answerPushChallenge(final Account account, final String challenge) throws RateLimitExceededException {
|
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);
|
final boolean challengeSuccess = pushChallengeManager.answerChallenge(account, challenge);
|
||||||
|
|
||||||
if (challengeSuccess) {
|
if (challengeSuccess) {
|
||||||
rateLimiters.getPushChallengeSuccessLimiter().validate(account.getNumber());
|
rateLimiters.getPushChallengeSuccessLimiter().validate(account.getUuid());
|
||||||
resetRateLimits(account);
|
resetRateLimits(account);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -67,7 +67,7 @@ public class RateLimitChallengeManager {
|
||||||
public void answerRecaptchaChallenge(final Account account, final String captcha, final String mostRecentProxyIp)
|
public void answerRecaptchaChallenge(final Account account, final String captcha, final String mostRecentProxyIp)
|
||||||
throws RateLimitExceededException {
|
throws RateLimitExceededException {
|
||||||
|
|
||||||
rateLimiters.getRecaptchaChallengeAttemptLimiter().validate(account.getNumber());
|
rateLimiters.getRecaptchaChallengeAttemptLimiter().validate(account.getUuid());
|
||||||
|
|
||||||
final boolean challengeSuccess = recaptchaClient.verify(captcha, mostRecentProxyIp);
|
final boolean challengeSuccess = recaptchaClient.verify(captcha, mostRecentProxyIp);
|
||||||
|
|
||||||
|
@ -76,14 +76,14 @@ public class RateLimitChallengeManager {
|
||||||
SUCCESS_TAG_NAME, String.valueOf(challengeSuccess)).increment();
|
SUCCESS_TAG_NAME, String.valueOf(challengeSuccess)).increment();
|
||||||
|
|
||||||
if (challengeSuccess) {
|
if (challengeSuccess) {
|
||||||
rateLimiters.getRecaptchaChallengeSuccessLimiter().validate(account.getNumber());
|
rateLimiters.getRecaptchaChallengeSuccessLimiter().validate(account.getUuid());
|
||||||
resetRateLimits(account);
|
resetRateLimits(account);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void resetRateLimits(final Account account) throws RateLimitExceededException {
|
private void resetRateLimits(final Account account) throws RateLimitExceededException {
|
||||||
try {
|
try {
|
||||||
rateLimiters.getRateLimitResetLimiter().validate(account.getNumber());
|
rateLimiters.getRateLimitResetLimiter().validate(account.getUuid());
|
||||||
} catch (final RateLimitExceededException e) {
|
} catch (final RateLimitExceededException e) {
|
||||||
Metrics.counter(RESET_RATE_LIMIT_EXCEEDED_COUNTER_NAME,
|
Metrics.counter(RESET_RATE_LIMIT_EXCEEDED_COUNTER_NAME,
|
||||||
SOURCE_COUNTRY_TAG_NAME, Util.getCountryCode(account.getNumber())).increment();
|
SOURCE_COUNTRY_TAG_NAME, Util.getCountryCode(account.getNumber())).increment();
|
||||||
|
@ -112,16 +112,14 @@ public class RateLimitChallengeManager {
|
||||||
public List<String> getChallengeOptions(final Account account) {
|
public List<String> getChallengeOptions(final Account account) {
|
||||||
final List<String> options = new ArrayList<>(2);
|
final List<String> options = new ArrayList<>(2);
|
||||||
|
|
||||||
final String key = account.getNumber();
|
if (rateLimiters.getRecaptchaChallengeAttemptLimiter().hasAvailablePermits(account.getUuid(), 1) &&
|
||||||
|
rateLimiters.getRecaptchaChallengeSuccessLimiter().hasAvailablePermits(account.getUuid(), 1)) {
|
||||||
if (rateLimiters.getRecaptchaChallengeAttemptLimiter().hasAvailablePermits(key, 1) &&
|
|
||||||
rateLimiters.getRecaptchaChallengeSuccessLimiter().hasAvailablePermits(key, 1)) {
|
|
||||||
|
|
||||||
options.add(OPTION_RECAPTCHA);
|
options.add(OPTION_RECAPTCHA);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (rateLimiters.getPushChallengeAttemptLimiter().hasAvailablePermits(key, 1) &&
|
if (rateLimiters.getPushChallengeAttemptLimiter().hasAvailablePermits(account.getUuid(), 1) &&
|
||||||
rateLimiters.getPushChallengeSuccessLimiter().hasAvailablePermits(key, 1)) {
|
rateLimiters.getPushChallengeSuccessLimiter().hasAvailablePermits(account.getUuid(), 1)) {
|
||||||
|
|
||||||
options.add(OPTION_PUSH_CHALLENGE);
|
options.add(OPTION_PUSH_CHALLENGE);
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,6 +14,7 @@ import com.fasterxml.jackson.core.JsonProcessingException;
|
||||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.time.Duration;
|
import java.time.Duration;
|
||||||
|
import java.util.UUID;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
import org.whispersystems.textsecuregcm.configuration.RateLimitsConfiguration.RateLimitConfiguration;
|
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 {
|
public void validate(String key) throws RateLimitExceededException {
|
||||||
validate(key, 1);
|
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) {
|
public boolean hasAvailablePermits(final String key, final int permits) {
|
||||||
return getBucket(key).getTimeUntilSpaceAvailable(permits).equals(Duration.ZERO);
|
return getBucket(key).getTimeUntilSpaceAvailable(permits).equals(Duration.ZERO);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void clear(final UUID accountUuid) {
|
||||||
|
clear(accountUuid.toString());
|
||||||
|
}
|
||||||
|
|
||||||
public void clear(String key) {
|
public void clear(String key) {
|
||||||
cacheCluster.useCluster(connection -> connection.sync().del(getBucketName(key)));
|
cacheCluster.useCluster(connection -> connection.sync().del(getBucketName(key)));
|
||||||
}
|
}
|
||||||
|
|
|
@ -65,7 +65,7 @@ public class UnsealedSenderRateLimiter {
|
||||||
|
|
||||||
try {
|
try {
|
||||||
rateLimiters.getUnsealedSenderCardinalityLimiter()
|
rateLimiters.getUnsealedSenderCardinalityLimiter()
|
||||||
.validate(sender.getNumber(), destination.getUuid().toString(), maxCardinality);
|
.validate(sender.getUuid().toString(), destination.getUuid().toString(), maxCardinality);
|
||||||
} catch (final RateLimitExceededException e) {
|
} catch (final RateLimitExceededException e) {
|
||||||
|
|
||||||
final boolean enforceLimit = dynamicConfigurationManager.getConfiguration()
|
final boolean enforceLimit = dynamicConfigurationManager.getConfiguration()
|
||||||
|
@ -91,7 +91,7 @@ public class UnsealedSenderRateLimiter {
|
||||||
|
|
||||||
final long ttl;
|
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();
|
ttl = remainingTtl > 0 ? remainingTtl : unsealedSenderCardinalityLimiter.getInitialTtl().toSeconds();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -49,7 +49,7 @@ class PreKeyRateLimiterTest {
|
||||||
void enforcementConfiguration() throws RateLimitExceededException {
|
void enforcementConfiguration() throws RateLimitExceededException {
|
||||||
|
|
||||||
doThrow(RateLimitExceededException.class)
|
doThrow(RateLimitExceededException.class)
|
||||||
.when(dailyPreKeyLimiter).validate(any());
|
.when(dailyPreKeyLimiter).validate(any(UUID.class));
|
||||||
|
|
||||||
when(rateLimitChallengeConfiguration.isPreKeyLimitEnforced()).thenReturn(false);
|
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.ArgumentMatchers.eq;
|
||||||
import static org.mockito.Mockito.mock;
|
import static org.mockito.Mockito.mock;
|
||||||
import static org.mockito.Mockito.verify;
|
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 static org.mockito.Mockito.when;
|
||||||
|
|
||||||
import com.vdurmont.semver4j.Semver;
|
import com.vdurmont.semver4j.Semver;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
|
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;
|
||||||
|
@ -66,6 +67,8 @@ class RateLimitChallengeManagerTest {
|
||||||
@ValueSource(booleans = {true, false})
|
@ValueSource(booleans = {true, false})
|
||||||
void answerPushChallenge(final boolean successfulChallenge) throws RateLimitExceededException {
|
void answerPushChallenge(final boolean successfulChallenge) throws RateLimitExceededException {
|
||||||
final Account account = mock(Account.class);
|
final Account account = mock(Account.class);
|
||||||
|
when(account.getUuid()).thenReturn(UUID.randomUUID());
|
||||||
|
|
||||||
when(pushChallengeManager.answerChallenge(eq(account), any())).thenReturn(successfulChallenge);
|
when(pushChallengeManager.answerChallenge(eq(account), any())).thenReturn(successfulChallenge);
|
||||||
|
|
||||||
when(rateLimiters.getPushChallengeAttemptLimiter()).thenReturn(mock(RateLimiter.class));
|
when(rateLimiters.getPushChallengeAttemptLimiter()).thenReturn(mock(RateLimiter.class));
|
||||||
|
@ -78,8 +81,8 @@ class RateLimitChallengeManagerTest {
|
||||||
verify(preKeyRateLimiter).handleRateLimitReset(account);
|
verify(preKeyRateLimiter).handleRateLimitReset(account);
|
||||||
verify(unsealedSenderRateLimiter).handleRateLimitReset(account);
|
verify(unsealedSenderRateLimiter).handleRateLimitReset(account);
|
||||||
} else {
|
} else {
|
||||||
verifyZeroInteractions(preKeyRateLimiter);
|
verifyNoInteractions(preKeyRateLimiter);
|
||||||
verifyZeroInteractions(unsealedSenderRateLimiter);
|
verifyNoInteractions(unsealedSenderRateLimiter);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -88,6 +91,7 @@ class RateLimitChallengeManagerTest {
|
||||||
void answerRecaptchaChallenge(final boolean successfulChallenge) throws RateLimitExceededException {
|
void answerRecaptchaChallenge(final boolean successfulChallenge) throws RateLimitExceededException {
|
||||||
final Account account = mock(Account.class);
|
final Account account = mock(Account.class);
|
||||||
when(account.getNumber()).thenReturn("+18005551234");
|
when(account.getNumber()).thenReturn("+18005551234");
|
||||||
|
when(account.getUuid()).thenReturn(UUID.randomUUID());
|
||||||
|
|
||||||
when(recaptchaClient.verify(any(), any())).thenReturn(successfulChallenge);
|
when(recaptchaClient.verify(any(), any())).thenReturn(successfulChallenge);
|
||||||
|
|
||||||
|
@ -101,8 +105,8 @@ class RateLimitChallengeManagerTest {
|
||||||
verify(preKeyRateLimiter).handleRateLimitReset(account);
|
verify(preKeyRateLimiter).handleRateLimitReset(account);
|
||||||
verify(unsealedSenderRateLimiter).handleRateLimitReset(account);
|
verify(unsealedSenderRateLimiter).handleRateLimitReset(account);
|
||||||
} else {
|
} else {
|
||||||
verifyZeroInteractions(preKeyRateLimiter);
|
verifyNoInteractions(preKeyRateLimiter);
|
||||||
verifyZeroInteractions(unsealedSenderRateLimiter);
|
verifyNoInteractions(unsealedSenderRateLimiter);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -150,14 +154,17 @@ class RateLimitChallengeManagerTest {
|
||||||
when(rateLimiters.getPushChallengeAttemptLimiter()).thenReturn(pushChallengeAttemptLimiter);
|
when(rateLimiters.getPushChallengeAttemptLimiter()).thenReturn(pushChallengeAttemptLimiter);
|
||||||
when(rateLimiters.getPushChallengeSuccessLimiter()).thenReturn(pushChallengeSuccessLimiter);
|
when(rateLimiters.getPushChallengeSuccessLimiter()).thenReturn(pushChallengeSuccessLimiter);
|
||||||
|
|
||||||
when(recaptchaChallengeAttemptLimiter.hasAvailablePermits(any(), anyInt())).thenReturn(captchaAttemptPermitted);
|
when(recaptchaChallengeAttemptLimiter.hasAvailablePermits(any(UUID.class), anyInt())).thenReturn(captchaAttemptPermitted);
|
||||||
when(recaptchaChallengeSuccessLimiter.hasAvailablePermits(any(), anyInt())).thenReturn(captchaSuccessPermitted);
|
when(recaptchaChallengeSuccessLimiter.hasAvailablePermits(any(UUID.class), anyInt())).thenReturn(captchaSuccessPermitted);
|
||||||
when(pushChallengeAttemptLimiter.hasAvailablePermits(any(), anyInt())).thenReturn(pushAttemptPermitted);
|
when(pushChallengeAttemptLimiter.hasAvailablePermits(any(UUID.class), anyInt())).thenReturn(pushAttemptPermitted);
|
||||||
when(pushChallengeSuccessLimiter.hasAvailablePermits(any(), anyInt())).thenReturn(pushSuccessPermitted);
|
when(pushChallengeSuccessLimiter.hasAvailablePermits(any(UUID.class), anyInt())).thenReturn(pushSuccessPermitted);
|
||||||
|
|
||||||
final int expectedLength = (expectCaptcha ? 1 : 0) + (expectPushChallenge ? 1 : 0);
|
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());
|
assertEquals(expectedLength, options.size());
|
||||||
|
|
||||||
if (expectCaptcha) {
|
if (expectCaptcha) {
|
||||||
|
|
|
@ -60,7 +60,6 @@ import org.whispersystems.textsecuregcm.mappers.RateLimitChallengeExceptionMappe
|
||||||
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.storage.KeysDynamoDb;
|
import org.whispersystems.textsecuregcm.storage.KeysDynamoDb;
|
||||||
import org.whispersystems.textsecuregcm.tests.util.AccountsHelper;
|
import org.whispersystems.textsecuregcm.tests.util.AccountsHelper;
|
||||||
import org.whispersystems.textsecuregcm.tests.util.AuthHelper;
|
import org.whispersystems.textsecuregcm.tests.util.AuthHelper;
|
||||||
|
@ -95,8 +94,6 @@ class KeysControllerTest {
|
||||||
private final static RateLimitChallengeManager rateLimitChallengeManager = mock(RateLimitChallengeManager.class );
|
private final static RateLimitChallengeManager rateLimitChallengeManager = mock(RateLimitChallengeManager.class );
|
||||||
private final static Account existsAccount = mock(Account.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 RateLimiters rateLimiters = mock(RateLimiters.class);
|
||||||
private static final RateLimiter rateLimiter = mock(RateLimiter.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)))
|
.addProvider(new PolymorphicAuthValueFactoryProvider.Binder<>(ImmutableSet.of(Account.class, DisabledPermittedAccount.class)))
|
||||||
.setTestContainerFactory(new GrizzlyWebTestContainerFactory())
|
.setTestContainerFactory(new GrizzlyWebTestContainerFactory())
|
||||||
.addResource(new RateLimitChallengeExceptionMapper(rateLimitChallengeManager))
|
.addResource(new RateLimitChallengeExceptionMapper(rateLimitChallengeManager))
|
||||||
.addResource(new KeysController(rateLimiters, keysDynamoDb, accounts, preKeyRateLimiter, dynamicConfigurationManager, rateLimitChallengeManager))
|
.addResource(new KeysController(rateLimiters, keysDynamoDb, accounts, preKeyRateLimiter, rateLimitChallengeManager))
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
@BeforeEach
|
@BeforeEach
|
||||||
|
@ -186,7 +183,6 @@ class KeysControllerTest {
|
||||||
existsAccount,
|
existsAccount,
|
||||||
rateLimiters,
|
rateLimiters,
|
||||||
rateLimiter,
|
rateLimiter,
|
||||||
dynamicConfigurationManager,
|
|
||||||
rateLimitChallengeManager
|
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(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(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
|
@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)));
|
verify(accountsManager, times(1)).get(argThat((ArgumentMatcher<AmbiguousIdentifier>) identifier -> identifier != null && identifier.hasNumber() && identifier.getNumber().equals(AuthHelper.VALID_NUMBER_TWO)));
|
||||||
verifyNoMoreInteractions(usernamesManager);
|
verifyNoMoreInteractions(usernamesManager);
|
||||||
verify(rateLimiter, times(1)).validate(eq(AuthHelper.VALID_NUMBER));
|
verify(rateLimiter, times(1)).validate(AuthHelper.VALID_UUID);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -225,7 +225,7 @@ class ProfileControllerTest {
|
||||||
|
|
||||||
verify(accountsManager, times(1)).get(eq(AuthHelper.VALID_UUID_TWO));
|
verify(accountsManager, times(1)).get(eq(AuthHelper.VALID_UUID_TWO));
|
||||||
verify(usernamesManager, times(1)).get(eq("n00bkiller"));
|
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
|
@Test
|
||||||
|
@ -260,7 +260,7 @@ class ProfileControllerTest {
|
||||||
assertThat(response.getStatus()).isEqualTo(404);
|
assertThat(response.getStatus()).isEqualTo(404);
|
||||||
|
|
||||||
verify(usernamesManager, times(1)).get(eq("n00bkillerzzzzz"));
|
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(usernamesManager, times(1)).get(eq(AuthHelper.VALID_UUID_TWO));
|
||||||
verify(profilesManager, times(1)).get(eq(AuthHelper.VALID_UUID_TWO), eq("validversion"));
|
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
|
@Test
|
||||||
|
|
|
@ -6,7 +6,6 @@
|
||||||
package org.whispersystems.textsecuregcm.tests.controllers;
|
package org.whispersystems.textsecuregcm.tests.controllers;
|
||||||
|
|
||||||
import static org.assertj.core.api.Assertions.assertThat;
|
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.mock;
|
||||||
import static org.mockito.Mockito.times;
|
import static org.mockito.Mockito.times;
|
||||||
import static org.mockito.Mockito.verify;
|
import static org.mockito.Mockito.verify;
|
||||||
|
@ -35,8 +34,8 @@ import org.whispersystems.textsecuregcm.util.SystemMapper;
|
||||||
@ExtendWith(DropwizardExtensionsSupport.class)
|
@ExtendWith(DropwizardExtensionsSupport.class)
|
||||||
class StickerControllerTest {
|
class StickerControllerTest {
|
||||||
|
|
||||||
private static RateLimiter rateLimiter = mock(RateLimiter.class );
|
private static final RateLimiter rateLimiter = mock(RateLimiter.class );
|
||||||
private static RateLimiters rateLimiters = mock(RateLimiters.class);
|
private static final RateLimiters rateLimiters = mock(RateLimiters.class);
|
||||||
|
|
||||||
private static final ResourceExtension resources = ResourceExtension.builder()
|
private static final ResourceExtension resources = ResourceExtension.builder()
|
||||||
.addProvider(AuthHelper.getAuthFilter())
|
.addProvider(AuthHelper.getAuthFilter())
|
||||||
|
@ -86,7 +85,7 @@ class StickerControllerTest {
|
||||||
}
|
}
|
||||||
|
|
||||||
verify(rateLimiters, times(1)).getStickerPackLimiter();
|
verify(rateLimiters, times(1)).getStickerPackLimiter();
|
||||||
verify(rateLimiter, times(1)).validate(eq(AuthHelper.VALID_NUMBER));
|
verify(rateLimiter, times(1)).validate(AuthHelper.VALID_UUID);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|
Loading…
Reference in New Issue