Enforce one entry position per identifier in monitor request

This commit is contained in:
Katherine Yen 2025-01-09 10:58:28 -05:00 committed by Jon Chambers
parent 0628b3e41c
commit d3d68c2a60
4 changed files with 54 additions and 73 deletions

View File

@ -151,21 +151,21 @@ public class KeyTransparencyController {
try { try {
final AciMonitorRequest aciMonitorRequest = AciMonitorRequest.newBuilder() final AciMonitorRequest aciMonitorRequest = AciMonitorRequest.newBuilder()
.setAci(ByteString.copyFrom(request.aci().value().toCompactByteArray())) .setAci(ByteString.copyFrom(request.aci().value().toCompactByteArray()))
.addAllEntries(request.aci().positions()) .setEntryPosition(request.aci().entry_position())
.setCommitmentIndex(ByteString.copyFrom(request.aci().commitmentIndex())) .setCommitmentIndex(ByteString.copyFrom(request.aci().commitmentIndex()))
.build(); .build();
final Optional<UsernameHashMonitorRequest> usernameHashMonitorRequest = request.usernameHash().map(usernameHash -> final Optional<UsernameHashMonitorRequest> usernameHashMonitorRequest = request.usernameHash().map(usernameHash ->
UsernameHashMonitorRequest.newBuilder() UsernameHashMonitorRequest.newBuilder()
.setUsernameHash(ByteString.copyFrom(usernameHash.value())) .setUsernameHash(ByteString.copyFrom(usernameHash.value()))
.addAllEntries(usernameHash.positions()) .setEntryPosition(usernameHash.entry_position())
.setCommitmentIndex(ByteString.copyFrom(usernameHash.commitmentIndex())) .setCommitmentIndex(ByteString.copyFrom(usernameHash.commitmentIndex()))
.build()); .build());
final Optional<E164MonitorRequest> e164MonitorRequest = request.e164().map(e164 -> final Optional<E164MonitorRequest> e164MonitorRequest = request.e164().map(e164 ->
E164MonitorRequest.newBuilder() E164MonitorRequest.newBuilder()
.setE164(e164.value()) .setE164(e164.value())
.addAllEntries(e164.positions()) .setEntryPosition(e164.entry_position())
.setCommitmentIndex(ByteString.copyFrom(e164.commitmentIndex())) .setCommitmentIndex(ByteString.copyFrom(e164.commitmentIndex()))
.build()); .build());

View File

@ -49,11 +49,9 @@ public record KeyTransparencyMonitorRequest(
@Schema(description = "The aci identifier to monitor") @Schema(description = "The aci identifier to monitor")
AciServiceIdentifier value, AciServiceIdentifier value,
@Schema(description = "A list of log tree positions maintained by the client for the aci search key.") @Schema(description = "A log tree position maintained by the client for the aci.")
@Valid @Positive
@NotNull long entry_position,
@NotEmpty
List<@Positive Long> positions,
@Schema(description = "The commitment index derived from a previous search request, encoded in standard unpadded base64") @Schema(description = "The commitment index derived from a previous search request, encoded in standard unpadded base64")
@JsonSerialize(using = ByteArrayAdapter.Serializing.class) @JsonSerialize(using = ByteArrayAdapter.Serializing.class)
@ -68,11 +66,9 @@ public record KeyTransparencyMonitorRequest(
@NotBlank @NotBlank
String value, String value,
@Schema(description = "A list of log tree positions maintained by the client for the e164 search key.") @Schema(description = "A log tree position maintained by the client for the e164.")
@NotNull @Positive
@NotEmpty long entry_position,
@Valid
List<@Positive Long> positions,
@Schema(description = "The commitment index derived from a previous search request, encoded in standard unpadded base64") @Schema(description = "The commitment index derived from a previous search request, encoded in standard unpadded base64")
@JsonSerialize(using = ByteArrayAdapter.Serializing.class) @JsonSerialize(using = ByteArrayAdapter.Serializing.class)
@ -91,10 +87,9 @@ public record KeyTransparencyMonitorRequest(
@NotEmpty @NotEmpty
byte[] value, byte[] value,
@Schema(description = "A list of log tree positions maintained by the client for the username hash search key.") @Schema(description = "A log tree position maintained by the client for the username hash.")
@NotNull @Positive
@NotEmpty long entry_position,
@Valid List<@Positive Long> positions,
@Schema(description = "The commitment index derived from a previous search request, encoded in standard unpadded base64") @Schema(description = "The commitment index derived from a previous search request, encoded in standard unpadded base64")
@JsonSerialize(using = ByteArrayAdapter.Serializing.class) @JsonSerialize(using = ByteArrayAdapter.Serializing.class)

View File

@ -295,19 +295,19 @@ message MonitorRequest {
message AciMonitorRequest { message AciMonitorRequest {
bytes aci = 1; bytes aci = 1;
repeated uint64 entries = 2; uint64 entry_position = 2;
bytes commitment_index = 3; bytes commitment_index = 3;
} }
message UsernameHashMonitorRequest { message UsernameHashMonitorRequest {
bytes username_hash = 1; bytes username_hash = 1;
repeated uint64 entries = 2; uint64 entry_position = 2;
bytes commitment_index = 3; bytes commitment_index = 3;
} }
message E164MonitorRequest { message E164MonitorRequest {
string e164 = 1; string e164 = 1;
repeated uint64 entries = 2; uint64 entry_position = 2;
bytes commitment_index = 3; bytes commitment_index = 3;
} }

View File

@ -305,7 +305,7 @@ public class KeyTransparencyControllerTest {
try (Response response = request.post(Entity.json( try (Response response = request.post(Entity.json(
createRequestJson( createRequestJson(
new KeyTransparencyMonitorRequest( new KeyTransparencyMonitorRequest(
new KeyTransparencyMonitorRequest.AciMonitor(ACI, List.of(3L), COMMITMENT_INDEX), new KeyTransparencyMonitorRequest.AciMonitor(ACI,3, COMMITMENT_INDEX),
Optional.empty(), Optional.empty(), 3L, 4L))))) { Optional.empty(), Optional.empty(), 3L, 4L))))) {
assertEquals(200, response.getStatus()); assertEquals(200, response.getStatus());
@ -327,7 +327,7 @@ public class KeyTransparencyControllerTest {
try (Response response = request.post( try (Response response = request.post(
Entity.json(createRequestJson( Entity.json(createRequestJson(
new KeyTransparencyMonitorRequest( new KeyTransparencyMonitorRequest(
new KeyTransparencyMonitorRequest.AciMonitor(ACI, List.of(3L), COMMITMENT_INDEX), new KeyTransparencyMonitorRequest.AciMonitor(ACI, 3, COMMITMENT_INDEX),
Optional.empty(), Optional.empty(), 3L, 4L))))) { Optional.empty(), Optional.empty(), 3L, 4L))))) {
assertEquals(400, response.getStatus()); assertEquals(400, response.getStatus());
verifyNoInteractions(keyTransparencyServiceClient); verifyNoInteractions(keyTransparencyServiceClient);
@ -346,7 +346,7 @@ public class KeyTransparencyControllerTest {
try (Response response = request.post( try (Response response = request.post(
Entity.json(createRequestJson( Entity.json(createRequestJson(
new KeyTransparencyMonitorRequest( new KeyTransparencyMonitorRequest(
new KeyTransparencyMonitorRequest.AciMonitor(ACI, List.of(3L), COMMITMENT_INDEX), new KeyTransparencyMonitorRequest.AciMonitor(ACI, 3, COMMITMENT_INDEX),
Optional.empty(), Optional.empty(), 3L, 4L))))) { Optional.empty(), Optional.empty(), 3L, 4L))))) {
assertEquals(httpStatus, response.getStatus()); assertEquals(httpStatus, response.getStatus());
verify(keyTransparencyServiceClient, times(1)).monitor(any(), any(), any(), anyLong(), anyLong(), any()); verify(keyTransparencyServiceClient, times(1)).monitor(any(), any(), any(), anyLong(), anyLong(), any());
@ -381,115 +381,101 @@ public class KeyTransparencyControllerTest {
new KeyTransparencyMonitorRequest(null, Optional.empty(), Optional.empty(), 3L, 4L))), new KeyTransparencyMonitorRequest(null, Optional.empty(), Optional.empty(), 3L, 4L))),
// aci monitor fields can't be null // aci monitor fields can't be null
Arguments.of(createRequestJson( Arguments.of(createRequestJson(
new KeyTransparencyMonitorRequest(new KeyTransparencyMonitorRequest.AciMonitor(null, null, null), new KeyTransparencyMonitorRequest(new KeyTransparencyMonitorRequest.AciMonitor(null, 4, null),
Optional.empty(), Optional.empty(), 3L, 4L))), Optional.empty(), Optional.empty(), 3L, 4L))),
Arguments.of(createRequestJson( Arguments.of(createRequestJson(
new KeyTransparencyMonitorRequest( new KeyTransparencyMonitorRequest(
new KeyTransparencyMonitorRequest.AciMonitor(null, List.of(4L), COMMITMENT_INDEX), new KeyTransparencyMonitorRequest.AciMonitor(null, 4, COMMITMENT_INDEX),
Optional.empty(), Optional.empty(), 3L, 4L))), Optional.empty(), Optional.empty(), 3L, 4L))),
Arguments.of(createRequestJson( Arguments.of(createRequestJson(
new KeyTransparencyMonitorRequest(new KeyTransparencyMonitorRequest.AciMonitor(ACI, null, COMMITMENT_INDEX), new KeyTransparencyMonitorRequest(new KeyTransparencyMonitorRequest.AciMonitor(ACI, 4, null),
Optional.empty(), Optional.empty(), 3L, 4L))), Optional.empty(), Optional.empty(), 3L, 4L))),
Arguments.of(createRequestJson( // aciPosition must be positive
new KeyTransparencyMonitorRequest(new KeyTransparencyMonitorRequest.AciMonitor(ACI, List.of(4L), null),
Optional.empty(), Optional.empty(), 3L, 4L))),
// aciPositions list can't be empty
Arguments.of(createRequestJson(new KeyTransparencyMonitorRequest( Arguments.of(createRequestJson(new KeyTransparencyMonitorRequest(
new KeyTransparencyMonitorRequest.AciMonitor(ACI, Collections.emptyList(), COMMITMENT_INDEX), new KeyTransparencyMonitorRequest.AciMonitor(ACI, 0, COMMITMENT_INDEX),
Optional.empty(), Optional.empty(), 3L, 4L))), Optional.empty(), Optional.empty(), 3L, 4L))),
// aci commitment index must be the correct size // aci commitment index must be the correct size
Arguments.of(createRequestJson(new KeyTransparencyMonitorRequest( Arguments.of(createRequestJson(new KeyTransparencyMonitorRequest(
new KeyTransparencyMonitorRequest.AciMonitor(ACI, List.of(4L), new byte[0]), new KeyTransparencyMonitorRequest.AciMonitor(ACI, 4, new byte[0]),
Optional.empty(), Optional.empty(), 3L, 4L))), Optional.empty(), Optional.empty(), 3L, 4L))),
Arguments.of(createRequestJson(new KeyTransparencyMonitorRequest( Arguments.of(createRequestJson(new KeyTransparencyMonitorRequest(
new KeyTransparencyMonitorRequest.AciMonitor(ACI, Collections.emptyList(), new byte[33]), new KeyTransparencyMonitorRequest.AciMonitor(ACI, 0, new byte[33]),
Optional.empty(), Optional.empty(), 3L, 4L))), Optional.empty(), Optional.empty(), 3L, 4L))),
// username monitor fields cannot be null // username monitor fields cannot be null
Arguments.of(createRequestJson( Arguments.of(createRequestJson(
new KeyTransparencyMonitorRequest( new KeyTransparencyMonitorRequest(
new KeyTransparencyMonitorRequest.AciMonitor(ACI, List.of(4L), COMMITMENT_INDEX), Optional.empty(), new KeyTransparencyMonitorRequest.AciMonitor(ACI, 4, COMMITMENT_INDEX), Optional.empty(),
Optional.of(new KeyTransparencyMonitorRequest.UsernameHashMonitor(null, null, null)), Optional.of(new KeyTransparencyMonitorRequest.UsernameHashMonitor(null, 5, null)),
3L, 4L))), 3L, 4L))),
Arguments.of(createRequestJson( Arguments.of(createRequestJson(
new KeyTransparencyMonitorRequest( new KeyTransparencyMonitorRequest(
new KeyTransparencyMonitorRequest.AciMonitor(ACI, List.of(4L), COMMITMENT_INDEX), Optional.empty(), new KeyTransparencyMonitorRequest.AciMonitor(ACI, 4, COMMITMENT_INDEX), Optional.empty(),
Optional.of(new KeyTransparencyMonitorRequest.UsernameHashMonitor(null, List.of(5L), COMMITMENT_INDEX)), Optional.of(new KeyTransparencyMonitorRequest.UsernameHashMonitor(null, 5, COMMITMENT_INDEX)),
3L, 4L))), 3L, 4L))),
Arguments.of(createRequestJson( Arguments.of(createRequestJson(
new KeyTransparencyMonitorRequest( new KeyTransparencyMonitorRequest(
new KeyTransparencyMonitorRequest.AciMonitor(ACI, List.of(4L), COMMITMENT_INDEX), Optional.empty(), new KeyTransparencyMonitorRequest.AciMonitor(ACI, 4, COMMITMENT_INDEX), Optional.empty(),
Optional.of( Optional.of(new KeyTransparencyMonitorRequest.UsernameHashMonitor(USERNAME_HASH, 5, null)),
new KeyTransparencyMonitorRequest.UsernameHashMonitor(USERNAME_HASH, null, COMMITMENT_INDEX)),
3L, 4L))), 3L, 4L))),
// usernameHashPosition must be positive
Arguments.of(createRequestJson( Arguments.of(createRequestJson(
new KeyTransparencyMonitorRequest( new KeyTransparencyMonitorRequest(
new KeyTransparencyMonitorRequest.AciMonitor(ACI, List.of(4L), COMMITMENT_INDEX), Optional.empty(), new KeyTransparencyMonitorRequest.AciMonitor(ACI, 4, COMMITMENT_INDEX),
Optional.of(new KeyTransparencyMonitorRequest.UsernameHashMonitor(USERNAME_HASH, List.of(5L), null)),
3L, 4L))),
// usernameHashPositions list cannot be empty
Arguments.of(createRequestJson(
new KeyTransparencyMonitorRequest(
new KeyTransparencyMonitorRequest.AciMonitor(ACI, List.of(4L), COMMITMENT_INDEX),
Optional.empty(), Optional.empty(),
Optional.of(new KeyTransparencyMonitorRequest.UsernameHashMonitor(USERNAME_HASH, Optional.of(new KeyTransparencyMonitorRequest.UsernameHashMonitor(USERNAME_HASH,
Collections.emptyList(), COMMITMENT_INDEX)), 3L, 4L))), 0, COMMITMENT_INDEX)), 3L, 4L))),
// username commitment index must be the correct size // username commitment index must be the correct size
Arguments.of(createRequestJson( Arguments.of(createRequestJson(
new KeyTransparencyMonitorRequest( new KeyTransparencyMonitorRequest(
new KeyTransparencyMonitorRequest.AciMonitor(ACI, List.of(4L), new byte[0]), new KeyTransparencyMonitorRequest.AciMonitor(ACI, 4, new byte[0]),
Optional.empty(), Optional.empty(),
Optional.of(new KeyTransparencyMonitorRequest.UsernameHashMonitor(USERNAME_HASH, Optional.of(new KeyTransparencyMonitorRequest.UsernameHashMonitor(USERNAME_HASH,
List.of(5L), new byte[0])), 3L, 4L))), 5, new byte[0])), 3L, 4L))),
Arguments.of(createRequestJson( Arguments.of(createRequestJson(
new KeyTransparencyMonitorRequest(new KeyTransparencyMonitorRequest.AciMonitor(ACI, List.of(4L), null), new KeyTransparencyMonitorRequest(new KeyTransparencyMonitorRequest.AciMonitor(ACI, 4, null),
Optional.empty(), Optional.empty(),
Optional.of(new KeyTransparencyMonitorRequest.UsernameHashMonitor(USERNAME_HASH, Optional.of(new KeyTransparencyMonitorRequest.UsernameHashMonitor(USERNAME_HASH,
List.of(5L), new byte[33])), 3L, 4L))), 5, new byte[33])), 3L, 4L))),
// e164 fields cannot be null // e164 fields cannot be null
Arguments.of( Arguments.of(
createRequestJson(new KeyTransparencyMonitorRequest( createRequestJson(new KeyTransparencyMonitorRequest(
new KeyTransparencyMonitorRequest.AciMonitor(ACI, List.of(4L), COMMITMENT_INDEX), new KeyTransparencyMonitorRequest.AciMonitor(ACI, 4, COMMITMENT_INDEX),
Optional.of(new KeyTransparencyMonitorRequest.E164Monitor(null, null, null)), Optional.of(new KeyTransparencyMonitorRequest.E164Monitor(null, 5, null)),
Optional.empty(), 3L, 4L))), Optional.empty(), 3L, 4L))),
Arguments.of( Arguments.of(
createRequestJson(new KeyTransparencyMonitorRequest( createRequestJson(new KeyTransparencyMonitorRequest(
new KeyTransparencyMonitorRequest.AciMonitor(ACI, List.of(4L), COMMITMENT_INDEX), new KeyTransparencyMonitorRequest.AciMonitor(ACI, 4, COMMITMENT_INDEX),
Optional.of(new KeyTransparencyMonitorRequest.E164Monitor(null, List.of(5L), COMMITMENT_INDEX)), Optional.of(new KeyTransparencyMonitorRequest.E164Monitor(null, 5, COMMITMENT_INDEX)),
Optional.empty(), 3L, 4L))), Optional.empty(), 3L, 4L))),
Arguments.of( Arguments.of(
createRequestJson(new KeyTransparencyMonitorRequest( createRequestJson(new KeyTransparencyMonitorRequest(
new KeyTransparencyMonitorRequest.AciMonitor(ACI, List.of(4L), COMMITMENT_INDEX), new KeyTransparencyMonitorRequest.AciMonitor(ACI, 4, COMMITMENT_INDEX),
Optional.of(new KeyTransparencyMonitorRequest.E164Monitor(NUMBER, null, COMMITMENT_INDEX)), Optional.of(new KeyTransparencyMonitorRequest.E164Monitor(NUMBER, 5, null)),
Optional.empty(), 3L, 4L))), Optional.empty(), 3L, 4L))),
Arguments.of( // e164Position must be positive
createRequestJson(new KeyTransparencyMonitorRequest(
new KeyTransparencyMonitorRequest.AciMonitor(ACI, List.of(4L), COMMITMENT_INDEX),
Optional.of(new KeyTransparencyMonitorRequest.E164Monitor(NUMBER, List.of(5L), null)),
Optional.empty(), 3L, 4L))),
// e164Positions list cannot empty
Arguments.of(createRequestJson(new KeyTransparencyMonitorRequest( Arguments.of(createRequestJson(new KeyTransparencyMonitorRequest(
new KeyTransparencyMonitorRequest.AciMonitor(ACI, List.of(4L), COMMITMENT_INDEX), new KeyTransparencyMonitorRequest.AciMonitor(ACI, 4, COMMITMENT_INDEX),
Optional.of( Optional.of(
new KeyTransparencyMonitorRequest.E164Monitor(NUMBER, Collections.emptyList(), COMMITMENT_INDEX)), new KeyTransparencyMonitorRequest.E164Monitor(NUMBER, 0, COMMITMENT_INDEX)),
Optional.empty(), 3L, 4L))), Optional.empty(), 3L, 4L))),
// e164 commitment index must be the correct size // e164 commitment index must be the correct size
Arguments.of(createRequestJson(new KeyTransparencyMonitorRequest( Arguments.of(createRequestJson(new KeyTransparencyMonitorRequest(
new KeyTransparencyMonitorRequest.AciMonitor(ACI, List.of(4L), COMMITMENT_INDEX), new KeyTransparencyMonitorRequest.AciMonitor(ACI, 4, COMMITMENT_INDEX),
Optional.of( Optional.of(
new KeyTransparencyMonitorRequest.E164Monitor(NUMBER, List.of(5L), new byte[0])), new KeyTransparencyMonitorRequest.E164Monitor(NUMBER, 5, new byte[0])),
Optional.empty(), 3L, 4L))), Optional.empty(), 3L, 4L))),
Arguments.of(createRequestJson(new KeyTransparencyMonitorRequest( Arguments.of(createRequestJson(new KeyTransparencyMonitorRequest(
new KeyTransparencyMonitorRequest.AciMonitor(ACI, List.of(4L), COMMITMENT_INDEX), new KeyTransparencyMonitorRequest.AciMonitor(ACI, 4, COMMITMENT_INDEX),
Optional.of( Optional.of(
new KeyTransparencyMonitorRequest.E164Monitor(NUMBER, List.of(5L), new byte[33])), new KeyTransparencyMonitorRequest.E164Monitor(NUMBER, 5, new byte[33])),
Optional.empty(), 3L, 4L))), Optional.empty(), 3L, 4L))),
// lastNonDistinguishedTreeHeadSize must be positive // lastNonDistinguishedTreeHeadSize must be positive
Arguments.of(createRequestJson(new KeyTransparencyMonitorRequest( Arguments.of(createRequestJson(new KeyTransparencyMonitorRequest(
new KeyTransparencyMonitorRequest.AciMonitor(ACI, List.of(4L), COMMITMENT_INDEX), Optional.empty(), new KeyTransparencyMonitorRequest.AciMonitor(ACI, 4, COMMITMENT_INDEX), Optional.empty(),
Optional.empty(), 0L, 4L))), Optional.empty(), 0L, 4L))),
// lastDistinguishedTreeHeadSize must be positive // lastDistinguishedTreeHeadSize must be positive
Arguments.of(createRequestJson(new KeyTransparencyMonitorRequest( Arguments.of(createRequestJson(new KeyTransparencyMonitorRequest(
new KeyTransparencyMonitorRequest.AciMonitor(ACI, List.of(4L), COMMITMENT_INDEX), Optional.empty(), new KeyTransparencyMonitorRequest.AciMonitor(ACI, 4, COMMITMENT_INDEX), Optional.empty(),
Optional.empty(), 3L, 0L))) Optional.empty(), 3L, 0L)))
); );
} }
@ -503,7 +489,7 @@ public class KeyTransparencyControllerTest {
.request(); .request();
try (Response response = request.post( try (Response response = request.post(
Entity.json(createRequestJson( Entity.json(createRequestJson(
new KeyTransparencyMonitorRequest(new KeyTransparencyMonitorRequest.AciMonitor(ACI, List.of(3L), null), new KeyTransparencyMonitorRequest(new KeyTransparencyMonitorRequest.AciMonitor(ACI, 3, null),
Optional.empty(), Optional.empty(), Optional.empty(), Optional.empty(),
3L, 4L))))) { 3L, 4L))))) {
assertEquals(429, response.getStatus()); assertEquals(429, response.getStatus());