Use V2 key transparency query RPCs
This commit is contained in:
parent
0c3c390a0b
commit
1b09529ece
@ -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);
|
||||
}
|
||||
|
||||
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -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) {
|
||||
|
||||
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@ -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));
|
||||
|
||||
@ -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);
|
||||
}
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user