Allow signup captchas to target CLDR two-letter region codes
This commit is contained in:
parent
d23e89fb9c
commit
b280c768a4
|
@ -21,6 +21,14 @@ public class DynamicCaptchaConfiguration {
|
||||||
@NotNull
|
@NotNull
|
||||||
private Set<String> signupCountryCodes = Collections.emptySet();
|
private Set<String> signupCountryCodes = Collections.emptySet();
|
||||||
|
|
||||||
|
@JsonProperty
|
||||||
|
@NotNull
|
||||||
|
private Set<String> signupRegions = Collections.emptySet();
|
||||||
|
|
||||||
|
public BigDecimal getScoreFloor() {
|
||||||
|
return scoreFloor;
|
||||||
|
}
|
||||||
|
|
||||||
public Set<String> getSignupCountryCodes() {
|
public Set<String> getSignupCountryCodes() {
|
||||||
return signupCountryCodes;
|
return signupCountryCodes;
|
||||||
}
|
}
|
||||||
|
@ -30,7 +38,12 @@ public class DynamicCaptchaConfiguration {
|
||||||
this.signupCountryCodes = numbers;
|
this.signupCountryCodes = numbers;
|
||||||
}
|
}
|
||||||
|
|
||||||
public BigDecimal getScoreFloor() {
|
@VisibleForTesting
|
||||||
return scoreFloor;
|
public void setSignupRegions(final Set<String> signupRegions) {
|
||||||
|
this.signupRegions = signupRegions;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Set<String> getSignupRegions() {
|
||||||
|
return signupRegions;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -776,6 +776,8 @@ public class AccountController {
|
||||||
}
|
}
|
||||||
|
|
||||||
final String countryCode = Util.getCountryCode(number);
|
final String countryCode = Util.getCountryCode(number);
|
||||||
|
final String region = Util.getRegion(number);
|
||||||
|
|
||||||
if (captchaToken.isPresent()) {
|
if (captchaToken.isPresent()) {
|
||||||
boolean validToken = recaptchaClient.verify(captchaToken.get(), sourceHost);
|
boolean validToken = recaptchaClient.verify(captchaToken.get(), sourceHost);
|
||||||
|
|
||||||
|
@ -822,7 +824,9 @@ public class AccountController {
|
||||||
|
|
||||||
DynamicCaptchaConfiguration captchaConfig = dynamicConfigurationManager.getConfiguration()
|
DynamicCaptchaConfiguration captchaConfig = dynamicConfigurationManager.getConfiguration()
|
||||||
.getCaptchaConfiguration();
|
.getCaptchaConfiguration();
|
||||||
boolean countryFiltered = captchaConfig.getSignupCountryCodes().contains(countryCode);
|
|
||||||
|
boolean countryFiltered = captchaConfig.getSignupCountryCodes().contains(countryCode) ||
|
||||||
|
captchaConfig.getSignupRegions().contains(region);
|
||||||
|
|
||||||
if (abusiveHostRules.isBlocked(sourceHost)) {
|
if (abusiveHostRules.isBlocked(sourceHost)) {
|
||||||
blockedHostMeter.mark();
|
blockedHostMeter.mark();
|
||||||
|
|
|
@ -79,6 +79,15 @@ public class Util {
|
||||||
else return "0";
|
else return "0";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static String getRegion(final String number) {
|
||||||
|
try {
|
||||||
|
final PhoneNumber phoneNumber = PHONE_NUMBER_UTIL.parse(number, null);
|
||||||
|
return PHONE_NUMBER_UTIL.getRegionCodeForNumber(phoneNumber);
|
||||||
|
} catch (final NumberParseException e) {
|
||||||
|
return "ZZ";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public static String getNumberPrefix(String number) {
|
public static String getNumberPrefix(String number) {
|
||||||
String countryCode = getCountryCode(number);
|
String countryCode = getCountryCode(number);
|
||||||
int remaining = number.length() - (1 + countryCode.length());
|
int remaining = number.length() - (1 + countryCode.length());
|
||||||
|
|
|
@ -52,6 +52,7 @@ import org.junit.jupiter.api.Test;
|
||||||
import org.junit.jupiter.api.extension.ExtendWith;
|
import org.junit.jupiter.api.extension.ExtendWith;
|
||||||
import org.junit.jupiter.params.ParameterizedTest;
|
import org.junit.jupiter.params.ParameterizedTest;
|
||||||
import org.junit.jupiter.params.provider.Arguments;
|
import org.junit.jupiter.params.provider.Arguments;
|
||||||
|
import org.junit.jupiter.params.provider.CsvSource;
|
||||||
import org.junit.jupiter.params.provider.MethodSource;
|
import org.junit.jupiter.params.provider.MethodSource;
|
||||||
import org.junit.jupiter.params.provider.ValueSource;
|
import org.junit.jupiter.params.provider.ValueSource;
|
||||||
import org.mockito.ArgumentCaptor;
|
import org.mockito.ArgumentCaptor;
|
||||||
|
@ -984,7 +985,8 @@ class AccountControllerTest {
|
||||||
.thenReturn(enrolledInVerifyExperiment);
|
.thenReturn(enrolledInVerifyExperiment);
|
||||||
|
|
||||||
final String challenge = "challenge";
|
final String challenge = "challenge";
|
||||||
when(pendingAccountsManager.getCodeForNumber(RESTRICTED_NUMBER)).thenReturn(Optional.of(new StoredVerificationCode("123456", System.currentTimeMillis(), challenge, null)));
|
when(pendingAccountsManager.getCodeForNumber(RESTRICTED_NUMBER))
|
||||||
|
.thenReturn(Optional.of(new StoredVerificationCode("123456", System.currentTimeMillis(), challenge, null)));
|
||||||
|
|
||||||
Response response =
|
Response response =
|
||||||
resources.getJerseyTest()
|
resources.getJerseyTest()
|
||||||
|
@ -1000,6 +1002,54 @@ class AccountControllerTest {
|
||||||
verifyNoMoreInteractions(smsSender);
|
verifyNoMoreInteractions(smsSender);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ParameterizedTest
|
||||||
|
@CsvSource({
|
||||||
|
"+12025550123, true, true",
|
||||||
|
"+12025550123, false, true",
|
||||||
|
"+12505550199, true, false",
|
||||||
|
"+12505550199, false, false",
|
||||||
|
})
|
||||||
|
void testRestrictedRegion(final String number, final boolean enrolledInVerifyExperiment, final boolean expectSendCode) {
|
||||||
|
final DynamicConfiguration dynamicConfiguration = mock(DynamicConfiguration.class);
|
||||||
|
when(dynamicConfigurationManager.getConfiguration()).thenReturn(dynamicConfiguration);
|
||||||
|
|
||||||
|
final DynamicCaptchaConfiguration signupCaptchaConfig = new DynamicCaptchaConfiguration();
|
||||||
|
signupCaptchaConfig.setSignupRegions(Set.of("CA"));
|
||||||
|
|
||||||
|
when(dynamicConfiguration.getCaptchaConfiguration()).thenReturn(signupCaptchaConfig);
|
||||||
|
|
||||||
|
when(verifyExperimentEnrollmentManager.isEnrolled(any(), anyString(), anyList(), anyString()))
|
||||||
|
.thenReturn(enrolledInVerifyExperiment);
|
||||||
|
|
||||||
|
final String challenge = "challenge";
|
||||||
|
when(pendingAccountsManager.getCodeForNumber(number))
|
||||||
|
.thenReturn(Optional.of(new StoredVerificationCode("123456", System.currentTimeMillis(), challenge, null)));
|
||||||
|
|
||||||
|
when(smsSender.deliverSmsVerificationWithTwilioVerify(any(), any(), any(), any()))
|
||||||
|
.thenReturn(CompletableFuture.completedFuture(Optional.empty()));
|
||||||
|
|
||||||
|
Response response =
|
||||||
|
resources.getJerseyTest()
|
||||||
|
.target(String.format("/v1/accounts/sms/code/%s", number))
|
||||||
|
.queryParam("challenge", challenge)
|
||||||
|
.request()
|
||||||
|
.header("X-Forwarded-For", NICE_HOST)
|
||||||
|
.get();
|
||||||
|
|
||||||
|
if (expectSendCode) {
|
||||||
|
assertThat(response.getStatus()).isEqualTo(200);
|
||||||
|
|
||||||
|
if (enrolledInVerifyExperiment) {
|
||||||
|
verify(smsSender).deliverSmsVerificationWithTwilioVerify(eq(number), any(), any(), any());
|
||||||
|
} else {
|
||||||
|
verify(smsSender).deliverSmsVerification(eq(number), any(), any());
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
assertThat(response.getStatus()).isEqualTo(402);
|
||||||
|
verifyNoMoreInteractions(smsSender);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@ParameterizedTest
|
@ParameterizedTest
|
||||||
@ValueSource(booleans = {false, true})
|
@ValueSource(booleans = {false, true})
|
||||||
void testSendRestrictedIn(final boolean enrolledInVerifyExperiment) throws Exception {
|
void testSendRestrictedIn(final boolean enrolledInVerifyExperiment) throws Exception {
|
||||||
|
|
Loading…
Reference in New Issue