Use V2 key transparency query RPCs

This commit is contained in:
Katherine 2026-06-24 15:02:34 -07:00 committed by GitHub
parent 0c3c390a0b
commit 1b09529ece
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 118 additions and 122 deletions

View File

@ -33,6 +33,8 @@ import org.glassfish.jersey.server.ManagedAsync;
import org.signal.keytransparency.client.AciMonitorRequest;
import org.signal.keytransparency.client.E164MonitorRequest;
import org.signal.keytransparency.client.E164SearchRequest;
import org.signal.keytransparency.client.MonitorResponseV2;
import org.signal.keytransparency.client.SearchResponseV2;
import org.signal.keytransparency.client.UsernameHashMonitorRequest;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ -101,15 +103,23 @@ public class KeyTransparencyController {
.build()
));
return new KeyTransparencySearchResponse(
keyTransparencyServiceClient.search(
ByteString.copyFrom(request.aci().toCompactByteArray()),
ByteString.copyFrom(request.aciIdentityKey().serialize()),
request.usernameHash().map(ByteString::copyFrom),
maybeE164SearchRequest,
request.lastTreeHeadSize(),
request.distinguishedTreeHeadSize())
.toByteArray());
final SearchResponseV2 searchResponse = keyTransparencyServiceClient.search(
ByteString.copyFrom(request.aci().toCompactByteArray()),
ByteString.copyFrom(request.aciIdentityKey().serialize()),
request.usernameHash().map(ByteString::copyFrom),
maybeE164SearchRequest,
request.lastTreeHeadSize(),
request.distinguishedTreeHeadSize());
if (searchResponse.hasPermissionDenied()) {
throw new StatusRuntimeException(Status.PERMISSION_DENIED);
}
if (!searchResponse.hasSearchResponse()) {
throw new StatusRuntimeException(Status.UNAVAILABLE.withDescription("Missing search response"));
}
return new KeyTransparencySearchResponse(searchResponse.getSearchResponse().toByteArray());
} catch (final StatusRuntimeException exception) {
handleKeyTransparencyServiceError(exception);
}
@ -163,13 +173,22 @@ public class KeyTransparencyController {
.setCommitmentIndex(ByteString.copyFrom(e164.commitmentIndex()))
.build());
return new KeyTransparencyMonitorResponse(keyTransparencyServiceClient.monitor(
final MonitorResponseV2 monitorResponse = keyTransparencyServiceClient.monitor(
aciMonitorRequest,
usernameHashMonitorRequest,
e164MonitorRequest,
request.lastNonDistinguishedTreeHeadSize(),
request.lastDistinguishedTreeHeadSize())
.toByteArray());
request.lastDistinguishedTreeHeadSize());
if (monitorResponse.hasPermissionDenied()) {
throw new StatusRuntimeException(Status.PERMISSION_DENIED);
}
if (!monitorResponse.hasMonitorResponse()) {
throw new StatusRuntimeException(Status.UNAVAILABLE.withDescription("Missing monitor response"));
}
return new KeyTransparencyMonitorResponse(monitorResponse.getMonitorResponse().toByteArray());
} catch (final StatusRuntimeException exception) {
handleKeyTransparencyServiceError(exception);
}

View File

@ -15,8 +15,10 @@ import org.signal.keytransparency.client.E164MonitorRequest;
import org.signal.keytransparency.client.E164SearchRequest;
import org.signal.keytransparency.client.MonitorRequest;
import org.signal.keytransparency.client.MonitorResponse;
import org.signal.keytransparency.client.MonitorResponseV2;
import org.signal.keytransparency.client.SearchRequest;
import org.signal.keytransparency.client.SearchResponse;
import org.signal.keytransparency.client.SearchResponseV2;
import org.signal.keytransparency.client.SimpleKeyTransparencyQueryServiceGrpc;
import org.signal.keytransparency.client.UsernameHashMonitorRequest;
import org.whispersystems.textsecuregcm.controllers.AccountController;
@ -39,102 +41,51 @@ public class KeyTransparencyGrpcService extends
}
@Override
public SearchResponse search(final SearchRequest request) throws RateLimitExceededException {
public SearchResponseV2 searchV2(final SearchRequest request) throws RateLimitExceededException {
rateLimiters.getKeyTransparencySearchLimiter().validate(RequestAttributesUtil.getRemoteAddress().getHostAddress());
return client.search(validateSearchRequest(request));
}
@Override
public MonitorResponse monitor(final MonitorRequest request) throws RateLimitExceededException {
public MonitorResponseV2 monitorV2(final MonitorRequest request) throws RateLimitExceededException {
rateLimiters.getKeyTransparencyMonitorLimiter().validate(RequestAttributesUtil.getRemoteAddress().getHostAddress());
return client.monitor(validateMonitorRequest(request));
}
@Override
public DistinguishedResponse distinguished(final DistinguishedRequest request) throws RateLimitExceededException {
public DistinguishedResponse distinguishedV2(final DistinguishedRequest request) throws RateLimitExceededException {
rateLimiters.getKeyTransparencyDistinguishedLimiter().validate(RequestAttributesUtil.getRemoteAddress().getHostAddress());
// A client's very first distinguished request will not have a "last" parameter
if (request.hasLast() && request.getLast() <= 0) {
throw Status.INVALID_ARGUMENT.withDescription("Last tree head size must be positive").asRuntimeException();
}
return client.distinguished(request);
}
private SearchRequest validateSearchRequest(final SearchRequest request) {
validateAci(request.getAci().toByteArray());
if (request.hasE164SearchRequest()) {
final E164SearchRequest e164SearchRequest = request.getE164SearchRequest();
if (e164SearchRequest.getUnidentifiedAccessKey().isEmpty() != e164SearchRequest.getE164().isEmpty()) {
throw Status.INVALID_ARGUMENT.withDescription("Unidentified access key and E164 must be provided together or not at all").asRuntimeException();
throw GrpcExceptions.fieldViolation("e164_search_request", "Unidentified access key and E164 must be provided together or not at all");
}
}
if (!request.getConsistency().hasDistinguished()) {
throw Status.INVALID_ARGUMENT.withDescription("Must provide distinguished tree head size").asRuntimeException();
}
validateConsistencyParameters(request.getConsistency());
return request;
}
private void validateAci(final byte[] aci) {
try {
AciServiceIdentifier.fromBytes(aci);
} catch (IllegalArgumentException e) {
throw GrpcExceptions.fieldViolation("aci", "Invalid ACI");
}
}
private MonitorRequest validateMonitorRequest(final MonitorRequest request) {
final AciMonitorRequest aciMonitorRequest = request.getAci();
validateAci(request.getAci().getAci().toByteArray());
try {
AciServiceIdentifier.fromBytes(aciMonitorRequest.getAci().toByteArray());
} catch (IllegalArgumentException e) {
throw Status.INVALID_ARGUMENT.withDescription("Invalid ACI").asRuntimeException();
}
if (aciMonitorRequest.getEntryPosition() <= 0) {
throw Status.INVALID_ARGUMENT.withDescription("Aci entry position must be positive").asRuntimeException();
}
if (aciMonitorRequest.getCommitmentIndex().size() != COMMITMENT_INDEX_LENGTH) {
throw Status.INVALID_ARGUMENT.withDescription("Aci commitment index must be 32 bytes").asRuntimeException();
if (!request.getConsistency().hasLast()) {
throw GrpcExceptions.fieldViolation("consistency_last", "Must provide distinguished and last tree head sizes");
}
if (request.hasUsernameHash()) {
final UsernameHashMonitorRequest usernameHashMonitorRequest = request.getUsernameHash();
if (usernameHashMonitorRequest.getUsernameHash().isEmpty()) {
throw Status.INVALID_ARGUMENT.withDescription("Username hash cannot be empty").asRuntimeException();
}
if (usernameHashMonitorRequest.getUsernameHash().size() != AccountController.USERNAME_HASH_LENGTH) {
throw Status.INVALID_ARGUMENT.withDescription("Invalid username hash length").asRuntimeException();
}
if (usernameHashMonitorRequest.getEntryPosition() <= 0) {
throw Status.INVALID_ARGUMENT.withDescription("Username hash entry position must be positive").asRuntimeException();
}
if (usernameHashMonitorRequest.getCommitmentIndex().size() != COMMITMENT_INDEX_LENGTH) {
throw Status.INVALID_ARGUMENT.withDescription("Username hash commitment index must be 32 bytes").asRuntimeException();
}
}
if (request.hasE164()) {
final E164MonitorRequest e164MonitorRequest = request.getE164();
if (e164MonitorRequest.getE164().isEmpty()) {
throw Status.INVALID_ARGUMENT.withDescription("E164 cannot be empty").asRuntimeException();
}
if (e164MonitorRequest.getEntryPosition() <= 0) {
throw Status.INVALID_ARGUMENT.withDescription("E164 entry position must be positive").asRuntimeException();
}
if (e164MonitorRequest.getCommitmentIndex().size() != COMMITMENT_INDEX_LENGTH) {
throw Status.INVALID_ARGUMENT.withDescription("E164 commitment index must be 32 bytes").asRuntimeException();
}
}
if (!request.getConsistency().hasDistinguished() || !request.getConsistency().hasLast()) {
throw Status.INVALID_ARGUMENT.withDescription("Must provide distinguished and last tree head sizes").asRuntimeException();
}
validateConsistencyParameters(request.getConsistency());
return request;
}
private static void validateConsistencyParameters(final ConsistencyParameters consistency) {
if (consistency.getDistinguished() <= 0) {
throw Status.INVALID_ARGUMENT.withDescription("Distinguished tree head size must be positive").asRuntimeException();
}
if (consistency.hasLast() && consistency.getLast() <= 0) {
throw Status.INVALID_ARGUMENT.withDescription("Last tree head size must be positive").asRuntimeException();
}
}
}

View File

@ -29,8 +29,10 @@ import org.signal.keytransparency.client.E164SearchRequest;
import org.signal.keytransparency.client.KeyTransparencyQueryServiceGrpc;
import org.signal.keytransparency.client.MonitorRequest;
import org.signal.keytransparency.client.MonitorResponse;
import org.signal.keytransparency.client.MonitorResponseV2;
import org.signal.keytransparency.client.SearchRequest;
import org.signal.keytransparency.client.SearchResponse;
import org.signal.keytransparency.client.SearchResponseV2;
import org.signal.keytransparency.client.UsernameHashMonitorRequest;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ -110,7 +112,7 @@ public class KeyTransparencyServiceClient implements Managed {
}
@SuppressWarnings("OptionalUsedAsFieldOrParameterType")
public SearchResponse search(
public SearchResponseV2 search(
final ByteString aci,
final ByteString aciIdentityKey,
final Optional<ByteString> usernameHash,
@ -132,13 +134,13 @@ public class KeyTransparencyServiceClient implements Managed {
return search(searchRequestBuilder.build());
}
public SearchResponse search(final SearchRequest request) {
public SearchResponseV2 search(final SearchRequest request) {
return stub.withDeadline(toDeadline(KEY_TRANSPARENCY_RPC_TIMEOUT))
.search(request);
.searchV2(request);
}
@SuppressWarnings("OptionalUsedAsFieldOrParameterType")
public MonitorResponse monitor(final AciMonitorRequest aciMonitorRequest,
public MonitorResponseV2 monitor(final AciMonitorRequest aciMonitorRequest,
final Optional<UsernameHashMonitorRequest> usernameHashMonitorRequest,
final Optional<E164MonitorRequest> e164MonitorRequest,
final long lastTreeHeadSize,
@ -155,12 +157,11 @@ public class KeyTransparencyServiceClient implements Managed {
return monitor(monitorRequestBuilder.build());
}
public MonitorResponse monitor(final MonitorRequest request) {
public MonitorResponseV2 monitor(final MonitorRequest request) {
return stub.withDeadline(toDeadline(KEY_TRANSPARENCY_RPC_TIMEOUT))
.monitor(request);
.monitorV2(request);
}
@SuppressWarnings("OptionalUsedAsFieldOrParameterType")
public DistinguishedResponse getDistinguishedKey(final Optional<Long> lastTreeHeadSize) {
final DistinguishedRequest request = lastTreeHeadSize.map(
@ -171,7 +172,7 @@ public class KeyTransparencyServiceClient implements Managed {
public DistinguishedResponse distinguished(final DistinguishedRequest request) {
return stub.withDeadline(toDeadline(KEY_TRANSPARENCY_RPC_TIMEOUT))
.distinguished(request);
.distinguishedV2(request);
}
private static Deadline toDeadline(final Duration timeout) {

View File

@ -34,17 +34,17 @@ service KeyTransparencyQueryService {
* subsequent Search and Monitor requests. It should be the first key
* transparency RPC a client calls.
*/
rpc Distinguished(DistinguishedRequest) returns (DistinguishedResponse) {}
rpc DistinguishedV2(DistinguishedRequest) returns (DistinguishedResponse) {}
/**
* An endpoint used by clients to search for one or more identifiers in the transparency log.
* The server returns proof that the identifier(s) exist in the log.
*/
rpc Search(SearchRequest) returns (SearchResponse) {}
rpc SearchV2(SearchRequest) returns (SearchResponseV2) {}
/**
* An endpoint that allows users to monitor a group of identifiers by returning proof that the log continues to be
* constructed correctly in later entries for those identifiers.
*/
rpc Monitor(MonitorRequest) returns (MonitorResponse) {}
rpc MonitorV2(MonitorRequest) returns (MonitorResponseV2) {}
}
message SearchRequest {
@ -112,6 +112,19 @@ message SearchResponse {
optional CondensedTreeSearchResponse username_hash = 4;
}
/**
* Indicates that the client is not authorized to make the request because
* it did not provide the correct set of data.
*/
message PermissionDenied {}
message SearchResponseV2 {
oneof response {
SearchResponse search_response = 1;
PermissionDenied permission_denied = 2;
}
}
/**
* The tree head size(s) to prove consistency against. A client's very first
* key transparency request should be looking up the "distinguished" key;
@ -124,13 +137,11 @@ message ConsistencyParameters {
* This field may be omitted if the client is looking up an identifier
* for the first time.
*/
optional uint64 last = 1;
optional uint64 last = 1 [(org.signal.chat.require.range) = {min: 1}];
/**
* The distinguished tree head size to prove consistency against.
* This field may be omitted when the client is looking up the
* "distinguished" key for the very first time.
*/
optional uint64 distinguished = 2;
uint64 distinguished = 2 [(org.signal.chat.require.range) = {min: 1}];
}
/**
@ -143,7 +154,7 @@ message DistinguishedRequest {
* exception of a client's very first request, this field should always be
* set.
*/
optional uint64 last = 1;
optional uint64 last = 1 [(org.signal.chat.require.range) = {min: 1}];
}
/**
@ -343,20 +354,20 @@ message MonitorRequest {
message AciMonitorRequest {
bytes aci = 1 [(org.signal.chat.require.exactlySize) = 16];
uint64 entry_position = 2;
uint64 entry_position = 2 [(org.signal.chat.require.range) = {min: 1}];
bytes commitment_index = 3 [(org.signal.chat.require.exactlySize) = 32];
}
message UsernameHashMonitorRequest {
bytes username_hash = 1 [(org.signal.chat.require.exactlySize) = 0, (org.signal.chat.require.exactlySize) = 32];
uint64 entry_position = 2;
bytes commitment_index = 3 [(org.signal.chat.require.exactlySize) = 0, (org.signal.chat.require.exactlySize) = 32];
bytes username_hash = 1 [(org.signal.chat.require.exactlySize) = 32];
uint64 entry_position = 2 [(org.signal.chat.require.range) = {min: 1}];
bytes commitment_index = 3 [(org.signal.chat.require.exactlySize) = 32];
}
message E164MonitorRequest {
optional string e164 = 1 [(org.signal.chat.require.e164) = true];
uint64 entry_position = 2;
bytes commitment_index = 3 [(org.signal.chat.require.exactlySize) = 0, (org.signal.chat.require.exactlySize) = 32];
string e164 = 1 [(org.signal.chat.require.e164) = true];
uint64 entry_position = 2 [(org.signal.chat.require.range) = {min: 1}];
bytes commitment_index = 3 [(org.signal.chat.require.exactlySize) = 32];
}
message MonitorProof {
@ -397,3 +408,10 @@ message MonitorResponse {
*/
repeated bytes inclusion = 5;
}
message MonitorResponseV2 {
oneof response {
MonitorResponse monitor_response = 1;
PermissionDenied permission_denied = 2;
}
}

View File

@ -54,8 +54,10 @@ import org.signal.keytransparency.client.DistinguishedResponse;
import org.signal.keytransparency.client.E164SearchRequest;
import org.signal.keytransparency.client.FullTreeHead;
import org.signal.keytransparency.client.MonitorResponse;
import org.signal.keytransparency.client.MonitorResponseV2;
import org.signal.keytransparency.client.SearchProof;
import org.signal.keytransparency.client.SearchResponse;
import org.signal.keytransparency.client.SearchResponseV2;
import org.signal.keytransparency.client.UpdateValue;
import org.signal.libsignal.protocol.IdentityKey;
import org.signal.libsignal.protocol.ecc.ECKeyPair;
@ -143,7 +145,10 @@ public class KeyTransparencyControllerTest {
usernameHash.ifPresent(ignored -> searchResponseBuilder.setUsernameHash(CondensedTreeSearchResponse.getDefaultInstance()));
when(keyTransparencyServiceClient.search(any(), any(), any(), any(), any(), anyLong()))
.thenReturn(searchResponseBuilder.build());
.thenReturn(SearchResponseV2.newBuilder()
.setSearchResponse(searchResponseBuilder.build())
.build()
);
final Invocation.Builder request = resources.getJerseyTest()
.target("/v1/key-transparency/search")
@ -291,7 +296,9 @@ public class KeyTransparencyControllerTest {
@Test
void monitorSuccess() {
when(keyTransparencyServiceClient.monitor(any(), any(), any(), anyLong(), anyLong()))
.thenReturn(MonitorResponse.getDefaultInstance());
.thenReturn(MonitorResponseV2.newBuilder()
.setMonitorResponse(MonitorResponse.getDefaultInstance())
.build());
final Invocation.Builder request = resources.getJerseyTest()
.target("/v1/key-transparency/monitor")
@ -306,7 +313,7 @@ public class KeyTransparencyControllerTest {
final KeyTransparencyMonitorResponse keyTransparencyMonitorResponse = response.readEntity(
KeyTransparencyMonitorResponse.class);
assertNotNull(keyTransparencyMonitorResponse.serializedResponse());
assertArrayEquals(MonitorResponse.getDefaultInstance().toByteArray(), keyTransparencyMonitorResponse.serializedResponse());
verify(keyTransparencyServiceClient, times(1)).monitor(
any(), any(), any(), eq(3L), eq(4L));

View File

@ -23,9 +23,9 @@ import org.signal.keytransparency.client.E164MonitorRequest;
import org.signal.keytransparency.client.E164SearchRequest;
import org.signal.keytransparency.client.KeyTransparencyQueryServiceGrpc;
import org.signal.keytransparency.client.MonitorRequest;
import org.signal.keytransparency.client.MonitorResponse;
import org.signal.keytransparency.client.MonitorResponseV2;
import org.signal.keytransparency.client.SearchRequest;
import org.signal.keytransparency.client.SearchResponse;
import org.signal.keytransparency.client.SearchResponseV2;
import org.signal.keytransparency.client.UsernameHashMonitorRequest;
import org.signal.libsignal.protocol.IdentityKey;
import org.whispersystems.textsecuregcm.controllers.RateLimitExceededException;
@ -56,7 +56,7 @@ import static org.whispersystems.textsecuregcm.grpc.GrpcTestUtils.assertRateLimi
import static org.whispersystems.textsecuregcm.grpc.GrpcTestUtils.assertStatusException;
import static org.whispersystems.textsecuregcm.grpc.KeyTransparencyGrpcService.COMMITMENT_INDEX_LENGTH;
@SuppressWarnings("OptionalUsedAsFieldOrParameterType")
@SuppressWarnings({"OptionalUsedAsFieldOrParameterType", "ThrowableNotThrown", "ResultOfMethodCallIgnored"})
public class KeyTransparencyGrpcServiceTest extends SimpleBaseGrpcTest<KeyTransparencyGrpcService, KeyTransparencyQueryServiceGrpc.KeyTransparencyQueryServiceBlockingStub>{
@Mock
private KeyTransparencyServiceClient keyTransparencyServiceClient;
@ -80,7 +80,7 @@ public class KeyTransparencyGrpcServiceTest extends SimpleBaseGrpcTest<KeyTransp
@Test
void searchSuccess() throws RateLimitExceededException {
when(keyTransparencyServiceClient.search(any())).thenReturn(SearchResponse.getDefaultInstance());
when(keyTransparencyServiceClient.search(any())).thenReturn(SearchResponseV2.getDefaultInstance());
Mockito.doNothing().when(rateLimiter).validate(any(String.class));
final SearchRequest request = SearchRequest.newBuilder()
.setAci(ByteString.copyFrom(ACI.toCompactByteArray()))
@ -90,7 +90,7 @@ public class KeyTransparencyGrpcServiceTest extends SimpleBaseGrpcTest<KeyTransp
.build())
.build();
assertDoesNotThrow(() -> unauthenticatedServiceStub().search(request));
assertDoesNotThrow(() -> unauthenticatedServiceStub().searchV2(request));
verify(keyTransparencyServiceClient, times(1)).search(eq(request));
}
@ -121,7 +121,7 @@ public class KeyTransparencyGrpcServiceTest extends SimpleBaseGrpcTest<KeyTransp
lastTreeHeadSize.ifPresent(consistencyBuilder::setLast);
requestBuilder.setConsistency(consistencyBuilder.build());
assertStatusException(Status.INVALID_ARGUMENT, () -> unauthenticatedServiceStub().search(requestBuilder.build()));
assertStatusException(Status.INVALID_ARGUMENT, () -> unauthenticatedServiceStub().searchV2(requestBuilder.build()));
verifyNoInteractions(keyTransparencyServiceClient);
}
@ -152,13 +152,13 @@ public class KeyTransparencyGrpcServiceTest extends SimpleBaseGrpcTest<KeyTransp
.setDistinguished(10)
.build())
.build();
assertRateLimitExceeded(retryAfterDuration, () -> unauthenticatedServiceStub().search(request));
assertRateLimitExceeded(retryAfterDuration, () -> unauthenticatedServiceStub().searchV2(request));
verifyNoInteractions(keyTransparencyServiceClient);
}
@Test
void monitorSuccess() {
when(keyTransparencyServiceClient.monitor(any())).thenReturn(MonitorResponse.getDefaultInstance());
when(keyTransparencyServiceClient.monitor(any())).thenReturn(MonitorResponseV2.getDefaultInstance());
when(rateLimiter.validateReactive(any(String.class)))
.thenReturn(Mono.empty());
final AciMonitorRequest aciMonitorRequest = AciMonitorRequest.newBuilder()
@ -175,7 +175,7 @@ public class KeyTransparencyGrpcServiceTest extends SimpleBaseGrpcTest<KeyTransp
.build())
.build();
assertDoesNotThrow(() -> unauthenticatedServiceStub().monitor(request));
assertDoesNotThrow(() -> unauthenticatedServiceStub().monitorV2(request));
verify(keyTransparencyServiceClient, times(1)).monitor(eq(request));
}
@ -199,7 +199,7 @@ public class KeyTransparencyGrpcServiceTest extends SimpleBaseGrpcTest<KeyTransp
requestBuilder.setConsistency(consistencyBuilder.build());
assertStatusException(Status.INVALID_ARGUMENT, () -> unauthenticatedServiceStub().monitor(requestBuilder.build()));
assertStatusException(Status.INVALID_ARGUMENT, () -> unauthenticatedServiceStub().monitorV2(requestBuilder.build()));
}
private static Stream<Arguments> monitorInvalidRequest() {
@ -218,9 +218,9 @@ public class KeyTransparencyGrpcServiceTest extends SimpleBaseGrpcTest<KeyTransp
Arguments.argumentSet("Invalid username hash length", validAciMonitorRequest, Optional.empty(), Optional.of(constructUsernameHashMonitorRequest(new byte[31], new byte[32], 10)), Optional.of(4L), Optional.of(4L)),
Arguments.argumentSet("Invalid commitment index on username hash monitor request", validAciMonitorRequest, Optional.empty(), Optional.of(constructUsernameHashMonitorRequest(USERNAME_HASH, new byte[31], 10)), Optional.of(4L), Optional.of(4L)),
Arguments.argumentSet("Invalid entry position on username hash monitor request", validAciMonitorRequest, Optional.empty(), Optional.of(constructUsernameHashMonitorRequest(USERNAME_HASH, new byte[32], 0)), Optional.of(4L), Optional.of(4L)),
Arguments.argumentSet("consistency.last must be provided", validAciMonitorRequest, Optional.empty(), Optional.empty(), Optional.empty(), Optional.of(4L),
Arguments.argumentSet("consistency.last must be provided", validAciMonitorRequest, Optional.empty(), Optional.empty(), Optional.empty(), Optional.of(4L)),
Arguments.argumentSet("consistency.last must be positive", validAciMonitorRequest, Optional.empty(), Optional.empty(), Optional.of(0L), Optional.of(4L)),
Arguments.argumentSet("consistency.distinguished must be provided", validAciMonitorRequest, Optional.empty(), Optional.empty(), Optional.of(4L)), Optional.empty()),
Arguments.argumentSet("consistency.distinguished must be provided", validAciMonitorRequest, Optional.empty(), Optional.empty(), Optional.of(4L), Optional.empty()),
Arguments.argumentSet("consistency.distinguished must be positive", validAciMonitorRequest, Optional.empty(), Optional.empty(), Optional.of(4L), Optional.of(0L))
);
}
@ -243,7 +243,7 @@ public class KeyTransparencyGrpcServiceTest extends SimpleBaseGrpcTest<KeyTransp
.setLast(10)
.build())
.build();
assertRateLimitExceeded(retryAfterDuration, () -> unauthenticatedServiceStub().monitor(request));
assertRateLimitExceeded(retryAfterDuration, () -> unauthenticatedServiceStub().monitorV2(request));
verifyNoInteractions(keyTransparencyServiceClient);
}
@ -254,7 +254,7 @@ public class KeyTransparencyGrpcServiceTest extends SimpleBaseGrpcTest<KeyTransp
.thenReturn(Mono.empty());
final DistinguishedRequest request = DistinguishedRequest.newBuilder().build();
assertDoesNotThrow(() -> unauthenticatedServiceStub().distinguished(request));
assertDoesNotThrow(() -> unauthenticatedServiceStub().distinguishedV2(request));
verify(keyTransparencyServiceClient, times(1)).distinguished(eq(request));
}
@ -264,7 +264,7 @@ public class KeyTransparencyGrpcServiceTest extends SimpleBaseGrpcTest<KeyTransp
.setLast(0)
.build();
assertStatusException(Status.INVALID_ARGUMENT, () -> unauthenticatedServiceStub().distinguished(request));
assertStatusException(Status.INVALID_ARGUMENT, () -> unauthenticatedServiceStub().distinguishedV2(request));
verifyNoInteractions(keyTransparencyServiceClient);
}
@ -277,7 +277,7 @@ public class KeyTransparencyGrpcServiceTest extends SimpleBaseGrpcTest<KeyTransp
.setLast(10)
.build();
assertRateLimitExceeded(retryAfterDuration, () -> unauthenticatedServiceStub().distinguished(request));
assertRateLimitExceeded(retryAfterDuration, () -> unauthenticatedServiceStub().distinguishedV2(request));
verifyNoInteractions(keyTransparencyServiceClient);
}