Support for registration recaptcha
This commit is contained in:
parent
3de3fc00ce
commit
9999321400
|
@ -146,8 +146,16 @@ public class WhisperServerConfiguration extends Configuration {
|
||||||
@JsonProperty
|
@JsonProperty
|
||||||
private VoiceVerificationConfiguration voiceVerification;
|
private VoiceVerificationConfiguration voiceVerification;
|
||||||
|
|
||||||
|
@Valid
|
||||||
|
@NotNull
|
||||||
|
@JsonProperty
|
||||||
|
private RecaptchaConfiguration recaptcha;
|
||||||
|
|
||||||
private Map<String, String> transparentDataIndex = new HashMap<>();
|
private Map<String, String> transparentDataIndex = new HashMap<>();
|
||||||
|
|
||||||
|
public RecaptchaConfiguration getRecaptchaConfiguration() {
|
||||||
|
return recaptcha;
|
||||||
|
}
|
||||||
|
|
||||||
public VoiceVerificationConfiguration getVoiceVerificationConfiguration() {
|
public VoiceVerificationConfiguration getVoiceVerificationConfiguration() {
|
||||||
return voiceVerification;
|
return voiceVerification;
|
||||||
|
|
|
@ -59,6 +59,7 @@ import org.whispersystems.textsecuregcm.push.GCMSender;
|
||||||
import org.whispersystems.textsecuregcm.push.PushSender;
|
import org.whispersystems.textsecuregcm.push.PushSender;
|
||||||
import org.whispersystems.textsecuregcm.push.ReceiptSender;
|
import org.whispersystems.textsecuregcm.push.ReceiptSender;
|
||||||
import org.whispersystems.textsecuregcm.push.WebsocketSender;
|
import org.whispersystems.textsecuregcm.push.WebsocketSender;
|
||||||
|
import org.whispersystems.textsecuregcm.recaptcha.RecaptchaClient;
|
||||||
import org.whispersystems.textsecuregcm.redis.ReplicatedJedisPool;
|
import org.whispersystems.textsecuregcm.redis.ReplicatedJedisPool;
|
||||||
import org.whispersystems.textsecuregcm.s3.UrlSigner;
|
import org.whispersystems.textsecuregcm.s3.UrlSigner;
|
||||||
import org.whispersystems.textsecuregcm.sms.SmsSender;
|
import org.whispersystems.textsecuregcm.sms.SmsSender;
|
||||||
|
@ -192,6 +193,7 @@ public class WhisperServerService extends Application<WhisperServerConfiguration
|
||||||
PushSender pushSender = new PushSender(apnFallbackManager, gcmSender, apnSender, websocketSender, config.getPushConfiguration().getQueueSize());
|
PushSender pushSender = new PushSender(apnFallbackManager, gcmSender, apnSender, websocketSender, config.getPushConfiguration().getQueueSize());
|
||||||
ReceiptSender receiptSender = new ReceiptSender(accountsManager, pushSender);
|
ReceiptSender receiptSender = new ReceiptSender(accountsManager, pushSender);
|
||||||
TurnTokenGenerator turnTokenGenerator = new TurnTokenGenerator(config.getTurnConfiguration());
|
TurnTokenGenerator turnTokenGenerator = new TurnTokenGenerator(config.getTurnConfiguration());
|
||||||
|
RecaptchaClient recaptchaClient = new RecaptchaClient(config.getRecaptchaConfiguration().getSecret());
|
||||||
|
|
||||||
DirectoryCredentialsGenerator directoryCredentialsGenerator = new DirectoryCredentialsGenerator(config.getDirectoryConfiguration().getDirectoryClientConfiguration().getUserAuthenticationTokenSharedSecret(),
|
DirectoryCredentialsGenerator directoryCredentialsGenerator = new DirectoryCredentialsGenerator(config.getDirectoryConfiguration().getDirectoryClientConfiguration().getUserAuthenticationTokenSharedSecret(),
|
||||||
config.getDirectoryConfiguration().getDirectoryClientConfiguration().getUserAuthenticationTokenUserIdSecret());
|
config.getDirectoryConfiguration().getDirectoryClientConfiguration().getUserAuthenticationTokenUserIdSecret());
|
||||||
|
@ -223,7 +225,7 @@ public class WhisperServerService extends Application<WhisperServerConfiguration
|
||||||
.buildAuthFilter()));
|
.buildAuthFilter()));
|
||||||
environment.jersey().register(new AuthValueFactoryProvider.Binder<>(Account.class));
|
environment.jersey().register(new AuthValueFactoryProvider.Binder<>(Account.class));
|
||||||
|
|
||||||
environment.jersey().register(new AccountController(pendingAccountsManager, accountsManager, abusiveHostRules, rateLimiters, smsSender, directoryQueue, messagesManager, turnTokenGenerator, config.getTestDevices()));
|
environment.jersey().register(new AccountController(pendingAccountsManager, accountsManager, abusiveHostRules, rateLimiters, smsSender, directoryQueue, messagesManager, turnTokenGenerator, config.getTestDevices(), recaptchaClient));
|
||||||
environment.jersey().register(new DeviceController(pendingDevicesManager, accountsManager, messagesManager, directoryQueue, rateLimiters, config.getMaxDevices()));
|
environment.jersey().register(new DeviceController(pendingDevicesManager, accountsManager, messagesManager, directoryQueue, rateLimiters, config.getMaxDevices()));
|
||||||
environment.jersey().register(new DirectoryController(rateLimiters, directory, directoryCredentialsGenerator));
|
environment.jersey().register(new DirectoryController(rateLimiters, directory, directoryCredentialsGenerator));
|
||||||
environment.jersey().register(new ProvisioningController(rateLimiters, pushSender));
|
environment.jersey().register(new ProvisioningController(rateLimiters, pushSender));
|
||||||
|
|
|
@ -0,0 +1,16 @@
|
||||||
|
package org.whispersystems.textsecuregcm.configuration;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||||
|
import org.hibernate.validator.constraints.NotEmpty;
|
||||||
|
|
||||||
|
public class RecaptchaConfiguration {
|
||||||
|
|
||||||
|
@JsonProperty
|
||||||
|
@NotEmpty
|
||||||
|
private String secret;
|
||||||
|
|
||||||
|
public String getSecret() {
|
||||||
|
return secret;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -36,6 +36,7 @@ import org.whispersystems.textsecuregcm.entities.GcmRegistrationId;
|
||||||
import org.whispersystems.textsecuregcm.entities.RegistrationLock;
|
import org.whispersystems.textsecuregcm.entities.RegistrationLock;
|
||||||
import org.whispersystems.textsecuregcm.entities.RegistrationLockFailure;
|
import org.whispersystems.textsecuregcm.entities.RegistrationLockFailure;
|
||||||
import org.whispersystems.textsecuregcm.limits.RateLimiters;
|
import org.whispersystems.textsecuregcm.limits.RateLimiters;
|
||||||
|
import org.whispersystems.textsecuregcm.recaptcha.RecaptchaClient;
|
||||||
import org.whispersystems.textsecuregcm.sms.SmsSender;
|
import org.whispersystems.textsecuregcm.sms.SmsSender;
|
||||||
import org.whispersystems.textsecuregcm.sqs.DirectoryQueue;
|
import org.whispersystems.textsecuregcm.sqs.DirectoryQueue;
|
||||||
import org.whispersystems.textsecuregcm.storage.AbusiveHostRule;
|
import org.whispersystems.textsecuregcm.storage.AbusiveHostRule;
|
||||||
|
@ -84,6 +85,8 @@ public class AccountController {
|
||||||
private final Meter newUserMeter = metricRegistry.meter(name(AccountController.class, "brand_new_user" ));
|
private final Meter newUserMeter = metricRegistry.meter(name(AccountController.class, "brand_new_user" ));
|
||||||
private final Meter blockedHostMeter = metricRegistry.meter(name(AccountController.class, "blocked_host" ));
|
private final Meter blockedHostMeter = metricRegistry.meter(name(AccountController.class, "blocked_host" ));
|
||||||
private final Meter filteredHostMeter = metricRegistry.meter(name(AccountController.class, "filtered_host" ));
|
private final Meter filteredHostMeter = metricRegistry.meter(name(AccountController.class, "filtered_host" ));
|
||||||
|
private final Meter captchaSuccessMeter = metricRegistry.meter(name(AccountController.class, "captcha_success"));
|
||||||
|
private final Meter captchaFailureMeter = metricRegistry.meter(name(AccountController.class, "captcha_failure"));
|
||||||
|
|
||||||
private final PendingAccountsManager pendingAccounts;
|
private final PendingAccountsManager pendingAccounts;
|
||||||
private final AccountsManager accounts;
|
private final AccountsManager accounts;
|
||||||
|
@ -94,6 +97,7 @@ public class AccountController {
|
||||||
private final MessagesManager messagesManager;
|
private final MessagesManager messagesManager;
|
||||||
private final TurnTokenGenerator turnTokenGenerator;
|
private final TurnTokenGenerator turnTokenGenerator;
|
||||||
private final Map<String, Integer> testDevices;
|
private final Map<String, Integer> testDevices;
|
||||||
|
private final RecaptchaClient recaptchaClient;
|
||||||
|
|
||||||
public AccountController(PendingAccountsManager pendingAccounts,
|
public AccountController(PendingAccountsManager pendingAccounts,
|
||||||
AccountsManager accounts,
|
AccountsManager accounts,
|
||||||
|
@ -103,7 +107,8 @@ public class AccountController {
|
||||||
DirectoryQueue directoryQueue,
|
DirectoryQueue directoryQueue,
|
||||||
MessagesManager messagesManager,
|
MessagesManager messagesManager,
|
||||||
TurnTokenGenerator turnTokenGenerator,
|
TurnTokenGenerator turnTokenGenerator,
|
||||||
Map<String, Integer> testDevices)
|
Map<String, Integer> testDevices,
|
||||||
|
RecaptchaClient recaptchaClient)
|
||||||
{
|
{
|
||||||
this.pendingAccounts = pendingAccounts;
|
this.pendingAccounts = pendingAccounts;
|
||||||
this.accounts = accounts;
|
this.accounts = accounts;
|
||||||
|
@ -114,6 +119,7 @@ public class AccountController {
|
||||||
this.messagesManager = messagesManager;
|
this.messagesManager = messagesManager;
|
||||||
this.testDevices = testDevices;
|
this.testDevices = testDevices;
|
||||||
this.turnTokenGenerator = turnTokenGenerator;
|
this.turnTokenGenerator = turnTokenGenerator;
|
||||||
|
this.recaptchaClient = recaptchaClient;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Timed
|
@Timed
|
||||||
|
@ -123,7 +129,8 @@ public class AccountController {
|
||||||
@PathParam("number") String number,
|
@PathParam("number") String number,
|
||||||
@HeaderParam("X-Forwarded-For") String forwardedFor,
|
@HeaderParam("X-Forwarded-For") String forwardedFor,
|
||||||
@HeaderParam("Accept-Language") Optional<String> locale,
|
@HeaderParam("Accept-Language") Optional<String> locale,
|
||||||
@QueryParam("client") Optional<String> client)
|
@QueryParam("client") Optional<String> client,
|
||||||
|
@QueryParam("captcha") Optional<String> captcha)
|
||||||
throws IOException, RateLimitExceededException
|
throws IOException, RateLimitExceededException
|
||||||
{
|
{
|
||||||
if (!Util.isValidNumber(number)) {
|
if (!Util.isValidNumber(number)) {
|
||||||
|
@ -138,31 +145,8 @@ public class AccountController {
|
||||||
return Response.status(400).build();
|
return Response.status(400).build();
|
||||||
}
|
}
|
||||||
|
|
||||||
for (String requester : requesters) {
|
if (requiresCaptcha(number, transport, forwardedFor, requesters, captcha)) {
|
||||||
List<AbusiveHostRule> abuseRules = abusiveHostRules.getAbusiveHostRulesFor(requester);
|
return Response.status(402).build();
|
||||||
|
|
||||||
for (AbusiveHostRule abuseRule : abuseRules) {
|
|
||||||
if (abuseRule.isBlocked()) {
|
|
||||||
logger.info("Blocked host: " + transport + ", " + number + ", " + requester + " (" + forwardedFor + ")");
|
|
||||||
blockedHostMeter.mark();
|
|
||||||
return Response.ok().build();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!abuseRule.getRegions().isEmpty()) {
|
|
||||||
if (abuseRule.getRegions().stream().noneMatch(number::startsWith)) {
|
|
||||||
logger.info("Restricted host: " + transport + ", " + number + ", " + requester + " (" + forwardedFor + ")");
|
|
||||||
filteredHostMeter.mark();
|
|
||||||
return Response.ok().build();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
rateLimiters.getSmsVoiceIpLimiter().validate(requester);
|
|
||||||
} catch (RateLimitExceededException e) {
|
|
||||||
logger.info("Rate limited exceeded: " + transport + ", " + number + ", " + requester + " (" + forwardedFor + ")");
|
|
||||||
return Response.ok().build();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (transport) {
|
switch (transport) {
|
||||||
|
@ -398,6 +382,51 @@ public class AccountController {
|
||||||
accounts.update(account);
|
accounts.update(account);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private boolean requiresCaptcha(String number, String transport, String forwardedFor,
|
||||||
|
List<String> requesters, Optional<String> captchaToken)
|
||||||
|
{
|
||||||
|
if (captchaToken.isPresent()) {
|
||||||
|
boolean validToken = recaptchaClient.verify(captchaToken.get());
|
||||||
|
|
||||||
|
if (validToken) {
|
||||||
|
captchaSuccessMeter.mark();
|
||||||
|
return false;
|
||||||
|
} else {
|
||||||
|
captchaFailureMeter.mark();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (String requester : requesters) {
|
||||||
|
List<AbusiveHostRule> abuseRules = abusiveHostRules.getAbusiveHostRulesFor(requester);
|
||||||
|
|
||||||
|
for (AbusiveHostRule abuseRule : abuseRules) {
|
||||||
|
if (abuseRule.isBlocked()) {
|
||||||
|
logger.info("Blocked host: " + transport + ", " + number + ", " + requester + " (" + forwardedFor + ")");
|
||||||
|
blockedHostMeter.mark();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!abuseRule.getRegions().isEmpty()) {
|
||||||
|
if (abuseRule.getRegions().stream().noneMatch(number::startsWith)) {
|
||||||
|
logger.info("Restricted host: " + transport + ", " + number + ", " + requester + " (" + forwardedFor + ")");
|
||||||
|
filteredHostMeter.mark();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
rateLimiters.getSmsVoiceIpLimiter().validate(requester);
|
||||||
|
} catch (RateLimitExceededException e) {
|
||||||
|
logger.info("Rate limited exceeded: " + transport + ", " + number + ", " + requester + " (" + forwardedFor + ")");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
private void createAccount(String number, String password, String userAgent, AccountAttributes accountAttributes) {
|
private void createAccount(String number, String password, String userAgent, AccountAttributes accountAttributes) {
|
||||||
Device device = new Device();
|
Device device = new Device();
|
||||||
device.setId(Device.MASTER_ID);
|
device.setId(Device.MASTER_ID);
|
||||||
|
|
|
@ -0,0 +1,56 @@
|
||||||
|
package org.whispersystems.textsecuregcm.recaptcha;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||||
|
import com.fasterxml.jackson.databind.DeserializationFeature;
|
||||||
|
import com.fasterxml.jackson.jaxrs.json.JacksonJaxbJsonProvider;
|
||||||
|
import org.glassfish.jersey.client.ClientConfig;
|
||||||
|
|
||||||
|
import javax.ws.rs.client.Client;
|
||||||
|
import javax.ws.rs.client.ClientBuilder;
|
||||||
|
import javax.ws.rs.client.Entity;
|
||||||
|
import javax.ws.rs.core.MultivaluedHashMap;
|
||||||
|
import javax.ws.rs.core.MultivaluedMap;
|
||||||
|
|
||||||
|
public class RecaptchaClient {
|
||||||
|
|
||||||
|
private final Client client;
|
||||||
|
private final String recaptchaSecret;
|
||||||
|
|
||||||
|
public RecaptchaClient(String recaptchaSecret) {
|
||||||
|
this.client = ClientBuilder.newClient(new ClientConfig(new JacksonJaxbJsonProvider().configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false)));
|
||||||
|
this.recaptchaSecret = recaptchaSecret;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean verify(String captchaToken) {
|
||||||
|
MultivaluedMap<String, String> formData = new MultivaluedHashMap<>();
|
||||||
|
formData.add("secret", recaptchaSecret);
|
||||||
|
formData.add("response", captchaToken);
|
||||||
|
|
||||||
|
VerifyResponse response = client.target("https://www.google.com/recaptcha/api/siteverify")
|
||||||
|
.request()
|
||||||
|
.post(Entity.form(formData), VerifyResponse.class);
|
||||||
|
|
||||||
|
return response.success;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class VerifyResponse {
|
||||||
|
@JsonProperty
|
||||||
|
private boolean success;
|
||||||
|
|
||||||
|
@JsonProperty("error-codes")
|
||||||
|
private String[] errorCodes;
|
||||||
|
|
||||||
|
@JsonProperty
|
||||||
|
private String hostname;
|
||||||
|
|
||||||
|
@JsonProperty
|
||||||
|
private String challenge_ts;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "success: " + success + ", errorCodes: " + String.join(", ", errorCodes == null ? new String[0] : errorCodes) + ", hostname: " + hostname + ", challenge_ts: " + challenge_ts;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
|
@ -15,6 +15,7 @@ import org.whispersystems.textsecuregcm.limits.RateLimiter;
|
||||||
import org.whispersystems.textsecuregcm.limits.RateLimiters;
|
import org.whispersystems.textsecuregcm.limits.RateLimiters;
|
||||||
import org.whispersystems.textsecuregcm.mappers.RateLimitExceededExceptionMapper;
|
import org.whispersystems.textsecuregcm.mappers.RateLimitExceededExceptionMapper;
|
||||||
import org.whispersystems.textsecuregcm.providers.TimeProvider;
|
import org.whispersystems.textsecuregcm.providers.TimeProvider;
|
||||||
|
import org.whispersystems.textsecuregcm.recaptcha.RecaptchaClient;
|
||||||
import org.whispersystems.textsecuregcm.sms.SmsSender;
|
import org.whispersystems.textsecuregcm.sms.SmsSender;
|
||||||
import org.whispersystems.textsecuregcm.sqs.DirectoryQueue;
|
import org.whispersystems.textsecuregcm.sqs.DirectoryQueue;
|
||||||
import org.whispersystems.textsecuregcm.storage.AbusiveHostRule;
|
import org.whispersystems.textsecuregcm.storage.AbusiveHostRule;
|
||||||
|
@ -29,9 +30,9 @@ import org.whispersystems.textsecuregcm.util.SystemMapper;
|
||||||
import javax.ws.rs.client.Entity;
|
import javax.ws.rs.client.Entity;
|
||||||
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 java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
|
@ -52,6 +53,9 @@ public class AccountControllerTest {
|
||||||
private static final String RESTRICTED_HOST = "192.168.1.2";
|
private static final String RESTRICTED_HOST = "192.168.1.2";
|
||||||
private static final String NICE_HOST = "127.0.0.1";
|
private static final String NICE_HOST = "127.0.0.1";
|
||||||
|
|
||||||
|
private static final String VALID_CAPTCHA_TOKEN = "valid_token";
|
||||||
|
private static final String INVALID_CAPTCHA_TOKEN = "invalid_token";
|
||||||
|
|
||||||
private PendingAccountsManager pendingAccountsManager = mock(PendingAccountsManager.class);
|
private PendingAccountsManager pendingAccountsManager = mock(PendingAccountsManager.class);
|
||||||
private AccountsManager accountsManager = mock(AccountsManager.class );
|
private AccountsManager accountsManager = mock(AccountsManager.class );
|
||||||
private AbusiveHostRules abusiveHostRules = mock(AbusiveHostRules.class );
|
private AbusiveHostRules abusiveHostRules = mock(AbusiveHostRules.class );
|
||||||
|
@ -65,6 +69,7 @@ public class AccountControllerTest {
|
||||||
private TimeProvider timeProvider = mock(TimeProvider.class );
|
private TimeProvider timeProvider = mock(TimeProvider.class );
|
||||||
private TurnTokenGenerator turnTokenGenerator = mock(TurnTokenGenerator.class);
|
private TurnTokenGenerator turnTokenGenerator = mock(TurnTokenGenerator.class);
|
||||||
private Account senderPinAccount = mock(Account.class);
|
private Account senderPinAccount = mock(Account.class);
|
||||||
|
private RecaptchaClient recaptchaClient = mock(RecaptchaClient.class);
|
||||||
|
|
||||||
@Rule
|
@Rule
|
||||||
public final ResourceTestRule resources = ResourceTestRule.builder()
|
public final ResourceTestRule resources = ResourceTestRule.builder()
|
||||||
|
@ -81,7 +86,8 @@ public class AccountControllerTest {
|
||||||
directoryQueue,
|
directoryQueue,
|
||||||
storedMessages,
|
storedMessages,
|
||||||
turnTokenGenerator,
|
turnTokenGenerator,
|
||||||
new HashMap<>()))
|
new HashMap<>(),
|
||||||
|
recaptchaClient))
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
|
|
||||||
|
@ -112,6 +118,9 @@ public class AccountControllerTest {
|
||||||
when(abusiveHostRules.getAbusiveHostRulesFor(eq(RESTRICTED_HOST))).thenReturn(Collections.singletonList(new AbusiveHostRule(RESTRICTED_HOST, false, Collections.singletonList("+123"))));
|
when(abusiveHostRules.getAbusiveHostRulesFor(eq(RESTRICTED_HOST))).thenReturn(Collections.singletonList(new AbusiveHostRule(RESTRICTED_HOST, false, Collections.singletonList("+123"))));
|
||||||
when(abusiveHostRules.getAbusiveHostRulesFor(eq(NICE_HOST))).thenReturn(Collections.emptyList());
|
when(abusiveHostRules.getAbusiveHostRulesFor(eq(NICE_HOST))).thenReturn(Collections.emptyList());
|
||||||
|
|
||||||
|
when(recaptchaClient.verify(eq(INVALID_CAPTCHA_TOKEN))).thenReturn(false);
|
||||||
|
when(recaptchaClient.verify(eq(VALID_CAPTCHA_TOKEN))).thenReturn(true);
|
||||||
|
|
||||||
doThrow(new RateLimitExceededException(SENDER_OVER_PIN)).when(pinLimiter).validate(eq(SENDER_OVER_PIN));
|
doThrow(new RateLimitExceededException(SENDER_OVER_PIN)).when(pinLimiter).validate(eq(SENDER_OVER_PIN));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -169,12 +178,46 @@ public class AccountControllerTest {
|
||||||
.header("X-Forwarded-For", ABUSIVE_HOST)
|
.header("X-Forwarded-For", ABUSIVE_HOST)
|
||||||
.get();
|
.get();
|
||||||
|
|
||||||
assertThat(response.getStatus()).isEqualTo(200);
|
assertThat(response.getStatus()).isEqualTo(402);
|
||||||
|
|
||||||
verify(abusiveHostRules).getAbusiveHostRulesFor(eq(ABUSIVE_HOST));
|
verify(abusiveHostRules).getAbusiveHostRulesFor(eq(ABUSIVE_HOST));
|
||||||
verifyNoMoreInteractions(smsSender);
|
verifyNoMoreInteractions(smsSender);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testSendAbusiveHostWithValidCaptcha() throws IOException {
|
||||||
|
Response response =
|
||||||
|
resources.getJerseyTest()
|
||||||
|
.target(String.format("/v1/accounts/sms/code/%s", SENDER))
|
||||||
|
.queryParam("captcha", VALID_CAPTCHA_TOKEN)
|
||||||
|
.request()
|
||||||
|
.header("X-Forwarded-For", ABUSIVE_HOST)
|
||||||
|
.get();
|
||||||
|
|
||||||
|
assertThat(response.getStatus()).isEqualTo(200);
|
||||||
|
|
||||||
|
verifyNoMoreInteractions(abusiveHostRules);
|
||||||
|
verify(recaptchaClient).verify(eq(VALID_CAPTCHA_TOKEN));
|
||||||
|
verify(smsSender).deliverSmsVerification(eq(SENDER), eq(Optional.empty()), anyString());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testSendAbusiveHostWithInvalidCaptcha() {
|
||||||
|
Response response =
|
||||||
|
resources.getJerseyTest()
|
||||||
|
.target(String.format("/v1/accounts/sms/code/%s", SENDER))
|
||||||
|
.queryParam("captcha", INVALID_CAPTCHA_TOKEN)
|
||||||
|
.request()
|
||||||
|
.header("X-Forwarded-For", ABUSIVE_HOST)
|
||||||
|
.get();
|
||||||
|
|
||||||
|
assertThat(response.getStatus()).isEqualTo(402);
|
||||||
|
|
||||||
|
verifyNoMoreInteractions(abusiveHostRules);
|
||||||
|
verify(recaptchaClient).verify(eq(INVALID_CAPTCHA_TOKEN));
|
||||||
|
verifyNoMoreInteractions(smsSender);
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testSendMultipleHost() {
|
public void testSendMultipleHost() {
|
||||||
Response response =
|
Response response =
|
||||||
|
@ -184,7 +227,7 @@ public class AccountControllerTest {
|
||||||
.header("X-Forwarded-For", NICE_HOST + ", " + ABUSIVE_HOST)
|
.header("X-Forwarded-For", NICE_HOST + ", " + ABUSIVE_HOST)
|
||||||
.get();
|
.get();
|
||||||
|
|
||||||
assertThat(response.getStatus()).isEqualTo(200);
|
assertThat(response.getStatus()).isEqualTo(402);
|
||||||
|
|
||||||
verify(abusiveHostRules, times(1)).getAbusiveHostRulesFor(eq(ABUSIVE_HOST));
|
verify(abusiveHostRules, times(1)).getAbusiveHostRulesFor(eq(ABUSIVE_HOST));
|
||||||
verify(abusiveHostRules, times(1)).getAbusiveHostRulesFor(eq(NICE_HOST));
|
verify(abusiveHostRules, times(1)).getAbusiveHostRulesFor(eq(NICE_HOST));
|
||||||
|
@ -203,7 +246,7 @@ public class AccountControllerTest {
|
||||||
.header("X-Forwarded-For", RESTRICTED_HOST)
|
.header("X-Forwarded-For", RESTRICTED_HOST)
|
||||||
.get();
|
.get();
|
||||||
|
|
||||||
assertThat(response.getStatus()).isEqualTo(200);
|
assertThat(response.getStatus()).isEqualTo(402);
|
||||||
|
|
||||||
verify(abusiveHostRules).getAbusiveHostRulesFor(eq(RESTRICTED_HOST));
|
verify(abusiveHostRules).getAbusiveHostRulesFor(eq(RESTRICTED_HOST));
|
||||||
verifyNoMoreInteractions(smsSender);
|
verifyNoMoreInteractions(smsSender);
|
||||||
|
|
Loading…
Reference in New Issue