Validate registration IDs

This commit is contained in:
Katherine
2023-11-28 15:43:35 -08:00
committed by GitHub
parent 8b95bb0c03
commit f46842c6c9
10 changed files with 123 additions and 31 deletions

View File

@@ -265,6 +265,36 @@ class AccountControllerV2Test {
}
}
@ParameterizedTest
@MethodSource
void invalidRegistrationId(final Integer pniRegistrationId, final int expectedStatusCode) {
when(registrationServiceClient.getSession(any(), any()))
.thenReturn(CompletableFuture.completedFuture(
Optional.of(new RegistrationServiceSession(new byte[16], NEW_NUMBER, true, null, null, null,
SESSION_EXPIRATION_SECONDS))));
final ChangeNumberRequest changeNumberRequest = new ChangeNumberRequest(encodeSessionId("session"),
null, NEW_NUMBER, "123", new IdentityKey(Curve.generateKeyPair().getPublicKey()),
Collections.emptyList(), Collections.emptyMap(), null, Map.of((byte) 1, pniRegistrationId));
final Response response = resources.getJerseyTest()
.target("/v2/accounts/number")
.request()
.header(HttpHeaders.AUTHORIZATION,
AuthHelper.getAuthHeader(AuthHelper.VALID_UUID, AuthHelper.VALID_PASSWORD))
.put(Entity.entity(changeNumberRequest, MediaType.APPLICATION_JSON_TYPE));
assertEquals(expectedStatusCode, response.getStatus());
}
private static Stream<Arguments> invalidRegistrationId() {
return Stream.of(
Arguments.of(0x3FFF, 200),
Arguments.of(0, 422),
Arguments.of(-1, 422),
Arguments.of(0x3FFF + 1, 422),
Arguments.of(Integer.MAX_VALUE, 422)
);
}
@Test
void rateLimitedNumber() throws Exception {
doThrow(new RateLimitExceededException(null, true))
@@ -398,13 +428,20 @@ class AccountControllerV2Test {
* Valid request JSON with the given Recovery Password
*/
private static String requestJsonRecoveryPassword(final byte[] recoveryPassword, final String newNumber) {
return requestJson("", recoveryPassword, newNumber);
return requestJson("", recoveryPassword, newNumber, 123);
}
/**
* Valid request JSON with the given pniRegistrationId
*/
private static String requestJsonRegistrationIds(final Integer pniRegistrationId) {
return requestJson("", new byte[0], "+18005551234", pniRegistrationId);
}
/**
* Valid request JSON with the give session ID and recovery password
*/
private static String requestJson(final String sessionId, final byte[] recoveryPassword, final String newNumber) {
private static String requestJson(final String sessionId, final byte[] recoveryPassword, final String newNumber, final Integer pniRegistrationId) {
return String.format("""
{
"sessionId": "%s",
@@ -414,16 +451,16 @@ class AccountControllerV2Test {
"pniIdentityKey": "%s",
"deviceMessages": [],
"devicePniSignedPrekeys": {},
"pniRegistrationIds": {}
"pniRegistrationIds": {"1": %d}
}
""", encodeSessionId(sessionId), encodeRecoveryPassword(recoveryPassword), newNumber, Base64.getEncoder().encodeToString(IDENTITY_KEY.serialize()));
""", encodeSessionId(sessionId), encodeRecoveryPassword(recoveryPassword), newNumber, Base64.getEncoder().encodeToString(IDENTITY_KEY.serialize()), pniRegistrationId);
}
/**
* Valid request JSON with the give session ID
*/
private static String requestJson(final String sessionId, final String newNumber) {
return requestJson(sessionId, new byte[0], newNumber);
return requestJson(sessionId, new byte[0], newNumber, 123);
}
/**

View File

@@ -576,6 +576,56 @@ class DeviceControllerTest {
);
}
@ParameterizedTest
@MethodSource
void linkDeviceRegistrationId(final int registrationId, final int expectedStatusCode) {
final Device existingDevice = mock(Device.class);
when(existingDevice.getId()).thenReturn(Device.PRIMARY_ID);
when(AuthHelper.VALID_ACCOUNT.getDevices()).thenReturn(List.of(existingDevice));
VerificationCode deviceCode = resources.getJerseyTest()
.target("/v1/devices/provisioning/code")
.request()
.header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_UUID, AuthHelper.VALID_PASSWORD))
.get(VerificationCode.class);
final ECKeyPair aciIdentityKeyPair = Curve.generateKeyPair();
final ECKeyPair pniIdentityKeyPair = Curve.generateKeyPair();
final ECSignedPreKey aciSignedPreKey = KeysHelper.signedECPreKey(1, aciIdentityKeyPair);
final ECSignedPreKey pniSignedPreKey = KeysHelper.signedECPreKey(2, pniIdentityKeyPair);
final KEMSignedPreKey aciPqLastResortPreKey = KeysHelper.signedKEMPreKey(3, aciIdentityKeyPair);
final KEMSignedPreKey pniPqLastResortPreKey = KeysHelper.signedKEMPreKey(4, pniIdentityKeyPair);
when(account.getIdentityKey(IdentityType.ACI)).thenReturn(new IdentityKey(aciIdentityKeyPair.getPublicKey()));
when(account.getIdentityKey(IdentityType.PNI)).thenReturn(new IdentityKey(pniIdentityKeyPair.getPublicKey()));
when(keysManager.storeEcSignedPreKeys(any(), any())).thenReturn(CompletableFuture.completedFuture(null));
when(keysManager.storePqLastResort(any(), any())).thenReturn(CompletableFuture.completedFuture(null));
final LinkDeviceRequest request = new LinkDeviceRequest(deviceCode.verificationCode(),
new AccountAttributes(false, registrationId, null, null, true, null),
new DeviceActivationRequest(aciSignedPreKey, pniSignedPreKey, aciPqLastResortPreKey, pniPqLastResortPreKey, Optional.of(new ApnRegistrationId("apn", null)), Optional.empty()));
try (final Response response = resources.getJerseyTest()
.target("/v1/devices/link")
.request()
.header("Authorization", AuthHelper.getProvisioningAuthHeader(AuthHelper.VALID_NUMBER, "password1"))
.put(Entity.entity(request, MediaType.APPLICATION_JSON_TYPE))) {
assertEquals(expectedStatusCode, response.getStatus());
}
}
private static Stream<Arguments> linkDeviceRegistrationId() {
return Stream.of(
Arguments.of(0x3FFF, 200),
Arguments.of(0, 422),
Arguments.of(-1, 422),
Arguments.of(0x3FFF + 1, 422),
Arguments.of(Integer.MAX_VALUE, 422)
);
}
private static ECSignedPreKey ecSignedPreKeyWithBadSignature(final ECSignedPreKey signedPreKey) {
return new ECSignedPreKey(signedPreKey.keyId(),
signedPreKey.publicKey(),