From d018efe2a5b03e29c0cf9235b0393305df7723f6 Mon Sep 17 00:00:00 2001 From: Jon Chambers <63609320+jon-signal@users.noreply.github.com> Date: Mon, 26 Feb 2024 10:30:52 -0500 Subject: [PATCH] Require non-null proofs in "confirm username hash" requests --- .../entities/ConfirmUsernameHashRequest.java | 2 ++ .../controllers/AccountControllerTest.java | 25 +++++++++++++++++++ 2 files changed, 27 insertions(+) diff --git a/service/src/main/java/org/whispersystems/textsecuregcm/entities/ConfirmUsernameHashRequest.java b/service/src/main/java/org/whispersystems/textsecuregcm/entities/ConfirmUsernameHashRequest.java index 96a442c63..449e78041 100644 --- a/service/src/main/java/org/whispersystems/textsecuregcm/entities/ConfirmUsernameHashRequest.java +++ b/service/src/main/java/org/whispersystems/textsecuregcm/entities/ConfirmUsernameHashRequest.java @@ -7,6 +7,7 @@ package org.whispersystems.textsecuregcm.entities; import javax.annotation.Nullable; import javax.validation.Valid; +import javax.validation.constraints.NotNull; import javax.validation.constraints.Size; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; @@ -25,6 +26,7 @@ public record ConfirmUsernameHashRequest( @JsonSerialize(using = ByteArrayBase64UrlAdapter.Serializing.class) @JsonDeserialize(using = ByteArrayBase64UrlAdapter.Deserializing.class) + @NotNull byte[] zkProof, @Schema(type = "string", description = "The url-safe base64-encoded encrypted username to be stored for username links") diff --git a/service/src/test/java/org/whispersystems/textsecuregcm/controllers/AccountControllerTest.java b/service/src/test/java/org/whispersystems/textsecuregcm/controllers/AccountControllerTest.java index 23170f988..1ccc74ed0 100644 --- a/service/src/test/java/org/whispersystems/textsecuregcm/controllers/AccountControllerTest.java +++ b/service/src/test/java/org/whispersystems/textsecuregcm/controllers/AccountControllerTest.java @@ -13,6 +13,7 @@ import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyByte; import static org.mockito.ArgumentMatchers.anyList; import static org.mockito.Mockito.clearInvocations; +import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.doThrow; import static org.mockito.Mockito.eq; @@ -208,6 +209,17 @@ class AccountControllerTest { when(accountsManager.getByE164(eq(SENDER_PREAUTH))).thenReturn(Optional.empty()); when(accountsManager.getByE164(eq(SENDER_HAS_STORAGE))).thenReturn(Optional.of(senderHasStorage)); when(accountsManager.getByE164(eq(SENDER_TRANSFER))).thenReturn(Optional.of(senderTransfer)); + + doAnswer(invocation -> { + final byte[] proof = invocation.getArgument(0); + final byte[] hash = invocation.getArgument(1); + + if (proof == null || hash == null) { + throw new NullPointerException(); + } + + return null; + }).when(usernameZkProofVerifier).verifyProof(any(), any()); } @AfterEach @@ -595,6 +607,19 @@ class AccountControllerTest { verify(usernameZkProofVerifier).verifyProof(ZK_PROOF, USERNAME_HASH_1); } + @Test + void testConfirmUsernameHashNullProof() { + try (final Response response = + resources.getJerseyTest() + .target("/v1/accounts/username_hash/confirm") + .request() + .header(HttpHeaders.AUTHORIZATION, AuthHelper.getAuthHeader(AuthHelper.VALID_UUID, AuthHelper.VALID_PASSWORD)) + .put(Entity.json(new ConfirmUsernameHashRequest(USERNAME_HASH_1, null, ENCRYPTED_USERNAME_1)))) { + + assertThat(response.getStatus()).isEqualTo(422); + } + } + @Test void testConfirmUsernameHashOld() throws BaseUsernameException { Account account = mock(Account.class);