mirror of
https://github.com/signalapp/Signal-Server
synced 2026-04-21 07:18:05 +01:00
Add registration recovery checker
This commit is contained in:
@@ -80,6 +80,7 @@ import org.whispersystems.textsecuregcm.mappers.ImpossiblePhoneNumberExceptionMa
|
||||
import org.whispersystems.textsecuregcm.mappers.NonNormalizedPhoneNumberExceptionMapper;
|
||||
import org.whispersystems.textsecuregcm.mappers.RateLimitExceededExceptionMapper;
|
||||
import org.whispersystems.textsecuregcm.registration.RegistrationServiceClient;
|
||||
import org.whispersystems.textsecuregcm.spam.RegistrationRecoveryChecker;
|
||||
import org.whispersystems.textsecuregcm.storage.Account;
|
||||
import org.whispersystems.textsecuregcm.storage.AccountBadge;
|
||||
import org.whispersystems.textsecuregcm.storage.AccountsManager;
|
||||
@@ -111,6 +112,7 @@ class AccountControllerV2Test {
|
||||
RegistrationLockVerificationManager.class);
|
||||
private final RateLimiters rateLimiters = mock(RateLimiters.class);
|
||||
private final RateLimiter registrationLimiter = mock(RateLimiter.class);
|
||||
private final RegistrationRecoveryChecker registrationRecoveryChecker = mock(RegistrationRecoveryChecker.class);
|
||||
|
||||
private final ResourceExtension resources = ResourceExtension.builder()
|
||||
.addProperty(ServerProperties.UNWRAP_COMPLETION_STAGE_IN_WRITER_ENABLE, Boolean.TRUE)
|
||||
@@ -123,7 +125,8 @@ class AccountControllerV2Test {
|
||||
.setTestContainerFactory(new GrizzlyWebTestContainerFactory())
|
||||
.addResource(
|
||||
new AccountControllerV2(accountsManager, changeNumberManager,
|
||||
new PhoneVerificationTokenManager(registrationServiceClient, registrationRecoveryPasswordsManager),
|
||||
new PhoneVerificationTokenManager(registrationServiceClient, registrationRecoveryPasswordsManager,
|
||||
registrationRecoveryChecker),
|
||||
registrationLockVerificationManager, rateLimiters))
|
||||
.build();
|
||||
|
||||
@@ -382,6 +385,8 @@ class AccountControllerV2Test {
|
||||
void recoveryPasswordManagerVerificationTrue() throws Exception {
|
||||
when(registrationRecoveryPasswordsManager.verify(any(), any()))
|
||||
.thenReturn(CompletableFuture.completedFuture(true));
|
||||
when(registrationRecoveryChecker.checkRegistrationRecoveryAttempt(any(), any()))
|
||||
.thenReturn(true);
|
||||
|
||||
final Invocation.Builder request = resources.getJerseyTest()
|
||||
.target("/v2/accounts/number")
|
||||
@@ -418,6 +423,40 @@ class AccountControllerV2Test {
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void registrationRecoveryCheckerAllowsAttempt() {
|
||||
when(registrationRecoveryChecker.checkRegistrationRecoveryAttempt(any(), any())).thenReturn(true);
|
||||
when(registrationRecoveryPasswordsManager.verify(any(), any()))
|
||||
.thenReturn(CompletableFuture.completedFuture(true));
|
||||
|
||||
final Invocation.Builder request = resources.getJerseyTest()
|
||||
.target("/v2/accounts/number")
|
||||
.request()
|
||||
.header(HttpHeaders.AUTHORIZATION,
|
||||
AuthHelper.getAuthHeader(AuthHelper.VALID_UUID, AuthHelper.VALID_PASSWORD));
|
||||
final byte[] recoveryPassword = new byte[32];
|
||||
try (Response response = request.put(Entity.json(requestJsonRecoveryPassword(recoveryPassword, NEW_NUMBER)))) {
|
||||
assertEquals(200, response.getStatus());
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void registrationRecoveryCheckerDisallowsAttempt() {
|
||||
when(registrationRecoveryChecker.checkRegistrationRecoveryAttempt(any(), any())).thenReturn(false);
|
||||
when(registrationRecoveryPasswordsManager.verify(any(), any()))
|
||||
.thenReturn(CompletableFuture.completedFuture(true));
|
||||
|
||||
final Invocation.Builder request = resources.getJerseyTest()
|
||||
.target("/v2/accounts/number")
|
||||
.request()
|
||||
.header(HttpHeaders.AUTHORIZATION,
|
||||
AuthHelper.getAuthHeader(AuthHelper.VALID_UUID, AuthHelper.VALID_PASSWORD));
|
||||
final byte[] recoveryPassword = new byte[32];
|
||||
try (Response response = request.put(Entity.json(requestJsonRecoveryPassword(recoveryPassword, NEW_NUMBER)))) {
|
||||
assertEquals(403, response.getStatus());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Valid request JSON with the given Recovery Password
|
||||
*/
|
||||
|
||||
@@ -71,6 +71,7 @@ import org.whispersystems.textsecuregcm.mappers.ImpossiblePhoneNumberExceptionMa
|
||||
import org.whispersystems.textsecuregcm.mappers.NonNormalizedPhoneNumberExceptionMapper;
|
||||
import org.whispersystems.textsecuregcm.mappers.RateLimitExceededExceptionMapper;
|
||||
import org.whispersystems.textsecuregcm.registration.RegistrationServiceClient;
|
||||
import org.whispersystems.textsecuregcm.spam.RegistrationRecoveryChecker;
|
||||
import org.whispersystems.textsecuregcm.storage.Account;
|
||||
import org.whispersystems.textsecuregcm.storage.AccountsManager;
|
||||
import org.whispersystems.textsecuregcm.storage.DeviceSpec;
|
||||
@@ -97,6 +98,7 @@ class RegistrationControllerTest {
|
||||
RegistrationLockVerificationManager.class);
|
||||
private final RegistrationRecoveryPasswordsManager registrationRecoveryPasswordsManager = mock(
|
||||
RegistrationRecoveryPasswordsManager.class);
|
||||
private final RegistrationRecoveryChecker registrationRecoveryChecker = mock(RegistrationRecoveryChecker.class);
|
||||
private final RateLimiters rateLimiters = mock(RateLimiters.class);
|
||||
|
||||
private final RateLimiter registrationLimiter = mock(RateLimiter.class);
|
||||
@@ -110,7 +112,8 @@ class RegistrationControllerTest {
|
||||
.setTestContainerFactory(new GrizzlyWebTestContainerFactory())
|
||||
.addResource(
|
||||
new RegistrationController(accountsManager,
|
||||
new PhoneVerificationTokenManager(registrationServiceClient, registrationRecoveryPasswordsManager),
|
||||
new PhoneVerificationTokenManager(registrationServiceClient, registrationRecoveryPasswordsManager,
|
||||
registrationRecoveryChecker),
|
||||
registrationLockVerificationManager, rateLimiters))
|
||||
.build();
|
||||
|
||||
@@ -239,6 +242,7 @@ class RegistrationControllerTest {
|
||||
|
||||
@Test
|
||||
void recoveryPasswordManagerVerificationFailureOrTimeout() {
|
||||
when(registrationRecoveryChecker.checkRegistrationRecoveryAttempt(any(), any())).thenReturn(true);
|
||||
when(registrationRecoveryPasswordsManager.verify(any(), any()))
|
||||
.thenReturn(CompletableFuture.failedFuture(new RuntimeException()));
|
||||
|
||||
@@ -284,6 +288,7 @@ class RegistrationControllerTest {
|
||||
|
||||
@Test
|
||||
void recoveryPasswordManagerVerificationTrue() throws InterruptedException {
|
||||
when(registrationRecoveryChecker.checkRegistrationRecoveryAttempt(any(), any())).thenReturn(true);
|
||||
when(registrationRecoveryPasswordsManager.verify(any(), any()))
|
||||
.thenReturn(CompletableFuture.completedFuture(true));
|
||||
|
||||
@@ -317,6 +322,50 @@ class RegistrationControllerTest {
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void registrationRecoveryCheckerAllowsAttempt() throws InterruptedException {
|
||||
when(registrationRecoveryChecker.checkRegistrationRecoveryAttempt(any(), any())).thenReturn(true);
|
||||
when(registrationRecoveryPasswordsManager.verify(any(), any()))
|
||||
.thenReturn(CompletableFuture.completedFuture(true));
|
||||
|
||||
final Account account = mock(Account.class);
|
||||
when(account.getPrimaryDevice()).thenReturn(mock(Device.class));
|
||||
|
||||
when(accountsManager.create(any(), any(), any(), any(), any(), any()))
|
||||
.thenReturn(account);
|
||||
|
||||
final Invocation.Builder request = resources.getJerseyTest()
|
||||
.target("/v1/registration")
|
||||
.request()
|
||||
.header(HttpHeaders.AUTHORIZATION, AuthHelper.getProvisioningAuthHeader(NUMBER, PASSWORD));
|
||||
final byte[] recoveryPassword = new byte[32];
|
||||
try (Response response = request.post(Entity.json(requestJsonRecoveryPassword(recoveryPassword)))) {
|
||||
assertEquals(200, response.getStatus());
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void registrationRecoveryCheckerDisallowsAttempt() throws InterruptedException {
|
||||
when(registrationRecoveryChecker.checkRegistrationRecoveryAttempt(any(), any())).thenReturn(false);
|
||||
when(registrationRecoveryPasswordsManager.verify(any(), any()))
|
||||
.thenReturn(CompletableFuture.completedFuture(true));
|
||||
|
||||
final Account account = mock(Account.class);
|
||||
when(account.getPrimaryDevice()).thenReturn(mock(Device.class));
|
||||
|
||||
when(accountsManager.create(any(), any(), any(), any(), any(), any()))
|
||||
.thenReturn(account);
|
||||
|
||||
final Invocation.Builder request = resources.getJerseyTest()
|
||||
.target("/v1/registration")
|
||||
.request()
|
||||
.header(HttpHeaders.AUTHORIZATION, AuthHelper.getProvisioningAuthHeader(NUMBER, PASSWORD));
|
||||
final byte[] recoveryPassword = new byte[32];
|
||||
try (Response response = request.post(Entity.json(requestJsonRecoveryPassword(recoveryPassword)))) {
|
||||
assertEquals(403, response.getStatus());
|
||||
}
|
||||
}
|
||||
|
||||
@CartesianTest
|
||||
@CartesianTest.MethodFactory("registrationLockAndDeviceTransfer")
|
||||
void registrationLockAndDeviceTransfer(
|
||||
|
||||
Reference in New Issue
Block a user