From e627d4e2c496bb0a33be7867b32e51d6d9f34e7d Mon Sep 17 00:00:00 2001 From: Katherine Date: Thu, 31 Oct 2024 10:54:55 -0400 Subject: [PATCH] Require some tree head sizes in key transparency search and monitor requests --- .../KeyTransparencyMonitorRequest.java | 6 +- .../KeyTransparencySearchRequest.java | 3 +- .../KeyTransparencyServiceClient.java | 18 ++-- .../KeyTransparencyControllerTest.java | 96 +++++++++---------- 4 files changed, 61 insertions(+), 62 deletions(-) diff --git a/service/src/main/java/org/whispersystems/textsecuregcm/entities/KeyTransparencyMonitorRequest.java b/service/src/main/java/org/whispersystems/textsecuregcm/entities/KeyTransparencyMonitorRequest.java index ba7bcb91b..19c1b6a1a 100644 --- a/service/src/main/java/org/whispersystems/textsecuregcm/entities/KeyTransparencyMonitorRequest.java +++ b/service/src/main/java/org/whispersystems/textsecuregcm/entities/KeyTransparencyMonitorRequest.java @@ -36,12 +36,10 @@ public record KeyTransparencyMonitorRequest( Optional<@Valid UsernameHashMonitor> usernameHash, @Schema(description = "The tree head size to prove consistency against.") - @NotNull - Optional<@Positive Long> lastNonDistinguishedTreeHeadSize, + @Positive long lastNonDistinguishedTreeHeadSize, @Schema(description = "The distinguished tree head size to prove consistency against.") - @NotNull - Optional<@Positive Long> lastDistinguishedTreeHeadSize + @Positive long lastDistinguishedTreeHeadSize ) { public record AciMonitor( diff --git a/service/src/main/java/org/whispersystems/textsecuregcm/entities/KeyTransparencySearchRequest.java b/service/src/main/java/org/whispersystems/textsecuregcm/entities/KeyTransparencySearchRequest.java index 1bff881b9..3142a7c3c 100644 --- a/service/src/main/java/org/whispersystems/textsecuregcm/entities/KeyTransparencySearchRequest.java +++ b/service/src/main/java/org/whispersystems/textsecuregcm/entities/KeyTransparencySearchRequest.java @@ -51,8 +51,9 @@ public record KeyTransparencySearchRequest( @Schema(description = "The non-distinguished tree head size to prove consistency against.") Optional<@Positive Long> lastTreeHeadSize, + @NotNull @Schema(description = "The distinguished tree head size to prove consistency against.") - Optional<@Positive Long> distinguishedTreeHeadSize + @Positive long distinguishedTreeHeadSize ) { @AssertTrue public boolean isUnidentifiedAccessKeyProvidedWithE164() { diff --git a/service/src/main/java/org/whispersystems/textsecuregcm/keytransparency/KeyTransparencyServiceClient.java b/service/src/main/java/org/whispersystems/textsecuregcm/keytransparency/KeyTransparencyServiceClient.java index 2f21ba9b3..95583a566 100644 --- a/service/src/main/java/org/whispersystems/textsecuregcm/keytransparency/KeyTransparencyServiceClient.java +++ b/service/src/main/java/org/whispersystems/textsecuregcm/keytransparency/KeyTransparencyServiceClient.java @@ -119,7 +119,7 @@ public class KeyTransparencyServiceClient implements Managed { final Optional usernameHash, final Optional e164SearchRequest, final Optional lastTreeHeadSize, - final Optional distinguishedTreeHeadSize, + final long distinguishedTreeHeadSize, final Duration timeout) { final SearchRequest.Builder searchKeysRequestBuilder = SearchRequest.newBuilder() .setAci(aci) @@ -128,9 +128,9 @@ public class KeyTransparencyServiceClient implements Managed { usernameHash.ifPresent(searchKeysRequestBuilder::setUsernameHash); e164SearchRequest.ifPresent(searchKeysRequestBuilder::setE164SearchRequest); - final ConsistencyParameters.Builder consistency = ConsistencyParameters.newBuilder(); + final ConsistencyParameters.Builder consistency = ConsistencyParameters.newBuilder() + .setDistinguished(distinguishedTreeHeadSize); lastTreeHeadSize.ifPresent(consistency::setLast); - distinguishedTreeHeadSize.ifPresent(consistency::setDistinguished); searchKeysRequestBuilder.setConsistency(consistency.build()); @@ -138,17 +138,17 @@ public class KeyTransparencyServiceClient implements Managed { .search(searchKeysRequestBuilder.build()), callbackExecutor); } - @SuppressWarnings("OptionalUsedAsFieldOrParameterType") public CompletableFuture monitor(final List monitorKeys, - final Optional lastTreeHeadSize, - final Optional distinguishedTreeHeadSize, + final long lastTreeHeadSize, + final long distinguishedTreeHeadSize, final Duration timeout) { final MonitorRequest.Builder monitorRequestBuilder = MonitorRequest.newBuilder() .addAllContactKeys(monitorKeys); - final ConsistencyParameters.Builder consistency = ConsistencyParameters.newBuilder(); - lastTreeHeadSize.ifPresent(consistency::setLast); - distinguishedTreeHeadSize.ifPresent(consistency::setDistinguished); + final ConsistencyParameters consistency = ConsistencyParameters.newBuilder() + .setLast(lastTreeHeadSize) + .setDistinguished(distinguishedTreeHeadSize) + .build(); monitorRequestBuilder.setConsistency(consistency); diff --git a/service/src/test/java/org/whispersystems/textsecuregcm/controllers/KeyTransparencyControllerTest.java b/service/src/test/java/org/whispersystems/textsecuregcm/controllers/KeyTransparencyControllerTest.java index ed6014a17..d5559bb20 100644 --- a/service/src/test/java/org/whispersystems/textsecuregcm/controllers/KeyTransparencyControllerTest.java +++ b/service/src/test/java/org/whispersystems/textsecuregcm/controllers/KeyTransparencyControllerTest.java @@ -10,6 +10,7 @@ import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertTrue; import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyLong; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.reset; @@ -154,7 +155,7 @@ public class KeyTransparencyControllerTest { e164.ifPresent(ignored -> searchResponseBuilder.setE164(TreeSearchResponse.getDefaultInstance())); usernameHash.ifPresent(ignored -> searchResponseBuilder.setUsernameHash(TreeSearchResponse.getDefaultInstance())); - when(keyTransparencyServiceClient.search(any(), any(), any(), any(), any(), any(), any())) + when(keyTransparencyServiceClient.search(any(), any(), any(), any(), any(), anyLong(), any())) .thenReturn(CompletableFuture.completedFuture(searchResponseBuilder.build())); final Invocation.Builder request = resources.getJerseyTest() @@ -164,7 +165,7 @@ public class KeyTransparencyControllerTest { final Optional unidentifiedAccessKey = e164.isPresent() ? Optional.of(UNIDENTIFIED_ACCESS_KEY) : Optional.empty(); final String searchJson = createRequestJson( new KeyTransparencySearchRequest(ACI, e164, usernameHash, ACI_IDENTITY_KEY, - unidentifiedAccessKey, Optional.of(3L), Optional.of(4L))); + unidentifiedAccessKey, Optional.of(3L), 4L)); try (Response response = request.post(Entity.json(searchJson))) { assertEquals(200, response.getStatus()); @@ -180,7 +181,7 @@ public class KeyTransparencyControllerTest { ArgumentCaptor> e164Argument = ArgumentCaptor.forClass(Optional.class); verify(keyTransparencyServiceClient).search(aciArgument.capture(), aciIdentityKeyArgument.capture(), - usernameHashArgument.capture(), e164Argument.capture(), eq(Optional.of(3L)), eq(Optional.of(4L)), + usernameHashArgument.capture(), e164Argument.capture(), eq(Optional.of(3L)), eq(4L), eq(KeyTransparencyController.KEY_TRANSPARENCY_RPC_TIMEOUT)); assertArrayEquals(ACI.toCompactByteArray(), aciArgument.getValue().toByteArray()); @@ -222,7 +223,7 @@ public class KeyTransparencyControllerTest { .header(HttpHeaders.AUTHORIZATION, AuthHelper.getAuthHeader(AuthHelper.VALID_UUID, AuthHelper.VALID_PASSWORD)); try (Response response = request.post( Entity.json(createRequestJson(new KeyTransparencySearchRequest(ACI, Optional.empty(), Optional.empty(), - ACI_IDENTITY_KEY, Optional.empty(), Optional.empty(), Optional.empty()))))) { + ACI_IDENTITY_KEY, Optional.empty(), Optional.empty(), 4L))))) { assertEquals(400, response.getStatus()); } verifyNoInteractions(keyTransparencyServiceClient); @@ -231,7 +232,7 @@ public class KeyTransparencyControllerTest { @ParameterizedTest @MethodSource void searchGrpcErrors(final Status grpcStatus, final int httpStatus) { - when(keyTransparencyServiceClient.search(any(), any(), any(), any(), any(), any(), any())) + when(keyTransparencyServiceClient.search(any(), any(), any(), any(), any(), anyLong(), any())) .thenReturn(CompletableFuture.failedFuture(new CompletionException(new StatusRuntimeException(grpcStatus)))); final Invocation.Builder request = resources.getJerseyTest() @@ -239,9 +240,9 @@ public class KeyTransparencyControllerTest { .request(); try (Response response = request.post( Entity.json(createRequestJson(new KeyTransparencySearchRequest(ACI, Optional.empty(), Optional.empty(), - ACI_IDENTITY_KEY, Optional.empty(), Optional.empty(), Optional.empty()))))) { + ACI_IDENTITY_KEY, Optional.empty(), Optional.empty(), 4L))))) { assertEquals(httpStatus, response.getStatus()); - verify(keyTransparencyServiceClient, times(1)).search(any(), any(), any(), any(), any(), any(), any()); + verify(keyTransparencyServiceClient, times(1)).search(any(), any(), any(), any(), any(), anyLong(), any()); } } @@ -262,7 +263,7 @@ public class KeyTransparencyControllerTest { final Optional e164, final Optional unidentifiedAccessKey, final Optional lastTreeHeadSize, - final Optional distinguishedTreeHeadSize) { + final long distinguishedTreeHeadSize) { final Invocation.Builder request = resources.getJerseyTest() .target("/v1/key-transparency/search") .request(); @@ -277,17 +278,17 @@ public class KeyTransparencyControllerTest { private static Stream searchInvalidRequest() { return Stream.of( // ACI can't be null - Arguments.of(null, ACI_IDENTITY_KEY, Optional.empty(), Optional.empty(), Optional.empty(), Optional.empty()), + Arguments.of(null, ACI_IDENTITY_KEY, Optional.empty(), Optional.empty(), Optional.empty(), 4L), // ACI identity key can't be null - Arguments.of(ACI, null, Optional.empty(), Optional.empty(), Optional.empty(), Optional.empty()), + Arguments.of(ACI, null, Optional.empty(), Optional.empty(), Optional.empty(), 4L), // lastNonDistinguishedTreeHeadSize must be positive - Arguments.of(ACI, ACI_IDENTITY_KEY, Optional.empty(), Optional.empty(), Optional.of(0L), Optional.empty()), + Arguments.of(ACI, ACI_IDENTITY_KEY, Optional.empty(), Optional.empty(), Optional.of(0L), 4L), // lastDistinguishedTreeHeadSize must be positive - Arguments.of(ACI, ACI_IDENTITY_KEY, Optional.empty(), Optional.empty(), Optional.empty(), Optional.of(0L)), + Arguments.of(ACI, ACI_IDENTITY_KEY, Optional.empty(), Optional.empty(), Optional.empty(), 0L), // E164 can't be provided without an unidentified access key - Arguments.of(ACI, ACI_IDENTITY_KEY, Optional.of(NUMBER), Optional.empty(), Optional.empty(), Optional.empty()), + Arguments.of(ACI, ACI_IDENTITY_KEY, Optional.of(NUMBER), Optional.empty(), Optional.empty(), 4L), // ...and an unidentified access key can't be provided without an E164 - Arguments.of(ACI, ACI_IDENTITY_KEY, Optional.empty(), Optional.of(UNIDENTIFIED_ACCESS_KEY), Optional.empty(), Optional.empty()) + Arguments.of(ACI, ACI_IDENTITY_KEY, Optional.empty(), Optional.of(UNIDENTIFIED_ACCESS_KEY), Optional.empty(), 4L) ); } @@ -300,7 +301,7 @@ public class KeyTransparencyControllerTest { .request(); try (Response response = request.post( Entity.json(createRequestJson(new KeyTransparencySearchRequest(ACI, Optional.empty(), Optional.empty(), - ACI_IDENTITY_KEY, Optional.empty(), Optional.empty(), Optional.empty()))))) { + ACI_IDENTITY_KEY, Optional.empty(), Optional.empty(), 4L))))) { assertEquals(429, response.getStatus()); verifyNoInteractions(keyTransparencyServiceClient); } @@ -308,7 +309,7 @@ public class KeyTransparencyControllerTest { @Test void monitorSuccess() { - when(keyTransparencyServiceClient.monitor(any(), any(), any(), any())) + when(keyTransparencyServiceClient.monitor(any(), anyLong(), anyLong(), any())) .thenReturn(CompletableFuture.completedFuture(TestRandomUtil.nextBytes(16))); final Invocation.Builder request = resources.getJerseyTest() @@ -319,7 +320,7 @@ public class KeyTransparencyControllerTest { createRequestJson( new KeyTransparencyMonitorRequest( new KeyTransparencyMonitorRequest.AciMonitor(ACI, List.of(3L), COMMITMENT_INDEX), - Optional.empty(), Optional.empty(), Optional.of(3L), Optional.of(4L)))))) { + Optional.empty(), Optional.empty(), 3L, 4L))))) { assertEquals(200, response.getStatus()); final KeyTransparencyMonitorResponse keyTransparencyMonitorResponse = response.readEntity( @@ -327,7 +328,7 @@ public class KeyTransparencyControllerTest { assertNotNull(keyTransparencyMonitorResponse.monitorResponse()); verify(keyTransparencyServiceClient, times(1)).monitor( - any(), eq(Optional.of(3L)), eq(Optional.of(4L)), eq(KeyTransparencyController.KEY_TRANSPARENCY_RPC_TIMEOUT)); + any(), eq(3L), eq(4L), eq(KeyTransparencyController.KEY_TRANSPARENCY_RPC_TIMEOUT)); } } @@ -341,7 +342,7 @@ public class KeyTransparencyControllerTest { Entity.json(createRequestJson( new KeyTransparencyMonitorRequest( new KeyTransparencyMonitorRequest.AciMonitor(ACI, List.of(3L), COMMITMENT_INDEX), - Optional.empty(), Optional.empty(), Optional.empty(), Optional.empty()))))) { + Optional.empty(), Optional.empty(), 3L, 4L))))) { assertEquals(400, response.getStatus()); verifyNoInteractions(keyTransparencyServiceClient); } @@ -350,7 +351,7 @@ public class KeyTransparencyControllerTest { @ParameterizedTest @MethodSource void monitorGrpcErrors(final Status grpcStatus, final int httpStatus) { - when(keyTransparencyServiceClient.monitor(any(), any(), any(), any())) + when(keyTransparencyServiceClient.monitor(any(), anyLong(), anyLong(), any())) .thenReturn(CompletableFuture.failedFuture(new CompletionException(new StatusRuntimeException(grpcStatus)))); final Invocation.Builder request = resources.getJerseyTest() @@ -360,9 +361,9 @@ public class KeyTransparencyControllerTest { Entity.json(createRequestJson( new KeyTransparencyMonitorRequest( new KeyTransparencyMonitorRequest.AciMonitor(ACI, List.of(3L), COMMITMENT_INDEX), - Optional.empty(), Optional.empty(), Optional.empty(), Optional.empty()))))) { + Optional.empty(), Optional.empty(), 3L, 4L))))) { assertEquals(httpStatus, response.getStatus()); - verify(keyTransparencyServiceClient, times(1)).monitor(any(), any(), any(), any()); + verify(keyTransparencyServiceClient, times(1)).monitor(any(), anyLong(), anyLong(), any()); } } @@ -391,120 +392,119 @@ public class KeyTransparencyControllerTest { return Stream.of( // aci monitor cannot be null Arguments.of(createRequestJson( - new KeyTransparencyMonitorRequest(null, Optional.empty(), Optional.empty(), Optional.empty(), - Optional.empty()))), + new KeyTransparencyMonitorRequest(null, Optional.empty(), Optional.empty(), 3L, 4L))), // aci monitor fields can't be null Arguments.of(createRequestJson( new KeyTransparencyMonitorRequest(new KeyTransparencyMonitorRequest.AciMonitor(null, null, null), - Optional.empty(), Optional.empty(), Optional.empty(), Optional.empty()))), + Optional.empty(), Optional.empty(), 3L, 4L))), Arguments.of(createRequestJson( new KeyTransparencyMonitorRequest( new KeyTransparencyMonitorRequest.AciMonitor(null, List.of(4L), COMMITMENT_INDEX), - Optional.empty(), Optional.empty(), Optional.empty(), Optional.empty()))), + Optional.empty(), Optional.empty(), 3L, 4L))), Arguments.of(createRequestJson( new KeyTransparencyMonitorRequest(new KeyTransparencyMonitorRequest.AciMonitor(ACI, null, COMMITMENT_INDEX), - Optional.empty(), Optional.empty(), Optional.empty(), Optional.empty()))), + Optional.empty(), Optional.empty(), 3L, 4L))), Arguments.of(createRequestJson( new KeyTransparencyMonitorRequest(new KeyTransparencyMonitorRequest.AciMonitor(ACI, List.of(4L), null), - Optional.empty(), Optional.empty(), Optional.empty(), Optional.empty()))), + Optional.empty(), Optional.empty(), 3L, 4L))), // aciPositions list can't be empty Arguments.of(createRequestJson(new KeyTransparencyMonitorRequest( new KeyTransparencyMonitorRequest.AciMonitor(ACI, Collections.emptyList(), COMMITMENT_INDEX), - Optional.empty(), Optional.empty(), Optional.empty(), Optional.empty()))), + Optional.empty(), Optional.empty(), 3L, 4L))), // aci commitment index must be the correct size Arguments.of(createRequestJson(new KeyTransparencyMonitorRequest( new KeyTransparencyMonitorRequest.AciMonitor(ACI, List.of(4L), new byte[0]), - Optional.empty(), Optional.empty(), Optional.empty(), Optional.empty()))), + Optional.empty(), Optional.empty(), 3L, 4L))), Arguments.of(createRequestJson(new KeyTransparencyMonitorRequest( new KeyTransparencyMonitorRequest.AciMonitor(ACI, Collections.emptyList(), new byte[33]), - Optional.empty(), Optional.empty(), Optional.empty(), Optional.empty()))), + Optional.empty(), Optional.empty(), 3L, 4L))), // username monitor fields cannot be null Arguments.of(createRequestJson( new KeyTransparencyMonitorRequest( new KeyTransparencyMonitorRequest.AciMonitor(ACI, List.of(4L), COMMITMENT_INDEX), Optional.empty(), Optional.of(new KeyTransparencyMonitorRequest.UsernameHashMonitor(null, null, null)), - Optional.empty(), Optional.empty()))), + 3L, 4L))), Arguments.of(createRequestJson( new KeyTransparencyMonitorRequest( new KeyTransparencyMonitorRequest.AciMonitor(ACI, List.of(4L), COMMITMENT_INDEX), Optional.empty(), Optional.of(new KeyTransparencyMonitorRequest.UsernameHashMonitor(null, List.of(5L), COMMITMENT_INDEX)), - Optional.empty(), Optional.empty()))), + 3L, 4L))), Arguments.of(createRequestJson( new KeyTransparencyMonitorRequest( new KeyTransparencyMonitorRequest.AciMonitor(ACI, List.of(4L), COMMITMENT_INDEX), Optional.empty(), Optional.of( new KeyTransparencyMonitorRequest.UsernameHashMonitor(USERNAME_HASH, null, COMMITMENT_INDEX)), - Optional.empty(), Optional.empty()))), + 3L, 4L))), Arguments.of(createRequestJson( new KeyTransparencyMonitorRequest( new KeyTransparencyMonitorRequest.AciMonitor(ACI, List.of(4L), COMMITMENT_INDEX), Optional.empty(), Optional.of(new KeyTransparencyMonitorRequest.UsernameHashMonitor(USERNAME_HASH, List.of(5L), null)), - Optional.empty(), Optional.empty()))), + 3L, 4L))), // usernameHashPositions list cannot be empty Arguments.of(createRequestJson( new KeyTransparencyMonitorRequest( new KeyTransparencyMonitorRequest.AciMonitor(ACI, List.of(4L), COMMITMENT_INDEX), Optional.empty(), Optional.of(new KeyTransparencyMonitorRequest.UsernameHashMonitor(USERNAME_HASH, - Collections.emptyList(), COMMITMENT_INDEX)), Optional.empty(), Optional.empty()))), + Collections.emptyList(), COMMITMENT_INDEX)), 3L, 4L))), // username commitment index must be the correct size Arguments.of(createRequestJson( new KeyTransparencyMonitorRequest( new KeyTransparencyMonitorRequest.AciMonitor(ACI, List.of(4L), new byte[0]), Optional.empty(), Optional.of(new KeyTransparencyMonitorRequest.UsernameHashMonitor(USERNAME_HASH, - List.of(5L), new byte[0])), Optional.empty(), Optional.empty()))), + List.of(5L), new byte[0])), 3L, 4L))), Arguments.of(createRequestJson( new KeyTransparencyMonitorRequest(new KeyTransparencyMonitorRequest.AciMonitor(ACI, List.of(4L), null), Optional.empty(), Optional.of(new KeyTransparencyMonitorRequest.UsernameHashMonitor(USERNAME_HASH, - List.of(5L), new byte[33])), Optional.empty(), Optional.empty()))), + List.of(5L), new byte[33])), 3L, 4L))), // e164 fields cannot be null Arguments.of( createRequestJson(new KeyTransparencyMonitorRequest( new KeyTransparencyMonitorRequest.AciMonitor(ACI, List.of(4L), COMMITMENT_INDEX), Optional.of(new KeyTransparencyMonitorRequest.E164Monitor(null, null, null)), - Optional.empty(), Optional.empty(), Optional.empty()))), + Optional.empty(), 3L, 4L))), Arguments.of( createRequestJson(new KeyTransparencyMonitorRequest( new KeyTransparencyMonitorRequest.AciMonitor(ACI, List.of(4L), COMMITMENT_INDEX), Optional.of(new KeyTransparencyMonitorRequest.E164Monitor(null, List.of(5L), COMMITMENT_INDEX)), - Optional.empty(), Optional.empty(), Optional.empty()))), + Optional.empty(), 3L, 4L))), Arguments.of( createRequestJson(new KeyTransparencyMonitorRequest( new KeyTransparencyMonitorRequest.AciMonitor(ACI, List.of(4L), COMMITMENT_INDEX), Optional.of(new KeyTransparencyMonitorRequest.E164Monitor(NUMBER, null, COMMITMENT_INDEX)), - Optional.empty(), Optional.empty(), Optional.empty()))), + Optional.empty(), 3L, 4L))), Arguments.of( createRequestJson(new KeyTransparencyMonitorRequest( new KeyTransparencyMonitorRequest.AciMonitor(ACI, List.of(4L), COMMITMENT_INDEX), Optional.of(new KeyTransparencyMonitorRequest.E164Monitor(NUMBER, List.of(5L), null)), - Optional.empty(), Optional.empty(), Optional.empty()))), + Optional.empty(), 3L, 4L))), // e164Positions list cannot empty Arguments.of(createRequestJson(new KeyTransparencyMonitorRequest( new KeyTransparencyMonitorRequest.AciMonitor(ACI, List.of(4L), COMMITMENT_INDEX), Optional.of( new KeyTransparencyMonitorRequest.E164Monitor(NUMBER, Collections.emptyList(), COMMITMENT_INDEX)), - Optional.empty(), Optional.empty(), Optional.empty()))), + Optional.empty(), 3L, 4L))), // e164 commitment index must be the correct size Arguments.of(createRequestJson(new KeyTransparencyMonitorRequest( new KeyTransparencyMonitorRequest.AciMonitor(ACI, List.of(4L), COMMITMENT_INDEX), Optional.of( new KeyTransparencyMonitorRequest.E164Monitor(NUMBER, List.of(5L), new byte[0])), - Optional.empty(), Optional.empty(), Optional.empty()))), + Optional.empty(), 3L, 4L))), Arguments.of(createRequestJson(new KeyTransparencyMonitorRequest( new KeyTransparencyMonitorRequest.AciMonitor(ACI, List.of(4L), COMMITMENT_INDEX), Optional.of( new KeyTransparencyMonitorRequest.E164Monitor(NUMBER, List.of(5L), new byte[33])), - Optional.empty(), Optional.empty(), Optional.empty()))), + Optional.empty(), 3L, 4L))), // lastNonDistinguishedTreeHeadSize must be positive Arguments.of(createRequestJson(new KeyTransparencyMonitorRequest( new KeyTransparencyMonitorRequest.AciMonitor(ACI, List.of(4L), COMMITMENT_INDEX), Optional.empty(), - Optional.empty(), Optional.of(0L), Optional.empty()))), + Optional.empty(), 0L, 4L))), // lastDistinguishedTreeHeadSize must be positive Arguments.of(createRequestJson(new KeyTransparencyMonitorRequest( new KeyTransparencyMonitorRequest.AciMonitor(ACI, List.of(4L), COMMITMENT_INDEX), Optional.empty(), - Optional.empty(), Optional.empty(), Optional.of(-1L)))) + Optional.empty(), 3L, 0L))) ); } @@ -519,7 +519,7 @@ public class KeyTransparencyControllerTest { Entity.json(createRequestJson( new KeyTransparencyMonitorRequest(new KeyTransparencyMonitorRequest.AciMonitor(ACI, List.of(3L), null), Optional.empty(), Optional.empty(), - Optional.empty(), Optional.empty()))))) { + 3L, 4L))))) { assertEquals(429, response.getStatus()); verifyNoInteractions(keyTransparencyServiceClient); }