Remove deprecated `aci` field from batch identity check elements

This commit is contained in:
Jon Chambers 2024-10-17 15:00:11 -04:00 committed by Chris Eager
parent adf5795dff
commit 1447819198
4 changed files with 23 additions and 65 deletions

View File

@ -23,7 +23,6 @@ import java.util.Collections;
import java.util.HexFormat; import java.util.HexFormat;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Objects;
import java.util.Optional; import java.util.Optional;
import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletableFuture;
import java.util.concurrent.Executor; import java.util.concurrent.Executor;
@ -351,7 +350,7 @@ public class ProfileController {
private void checkFingerprintAndAdd(BatchIdentityCheckRequest.Element element, private void checkFingerprintAndAdd(BatchIdentityCheckRequest.Element element,
Collection<BatchIdentityCheckResponse.Element> responseElements, MessageDigest md) { Collection<BatchIdentityCheckResponse.Element> responseElements, MessageDigest md) {
final ServiceIdentifier identifier = Objects.requireNonNullElse(element.uuid(), element.aci()); final ServiceIdentifier identifier = element.uuid();
final Optional<Account> maybeAccount = accountsManager.getByServiceIdentifier(identifier); final Optional<Account> maybeAccount = accountsManager.getByServiceIdentifier(identifier);
maybeAccount.ifPresent(account -> { maybeAccount.ifPresent(account -> {
@ -365,7 +364,7 @@ public class ProfileController {
byte[] fingerprint = Util.truncate(digest, 4); byte[] fingerprint = Util.truncate(digest, 4);
if (!Arrays.equals(fingerprint, element.fingerprint())) { if (!Arrays.equals(fingerprint, element.fingerprint())) {
responseElements.add(new BatchIdentityCheckResponse.Element(element.uuid(), element.aci(), identityKey)); responseElements.add(new BatchIdentityCheckResponse.Element(element.uuid(), identityKey));
} }
}); });
} }

View File

@ -12,7 +12,6 @@ import javax.annotation.Nullable;
import javax.validation.Valid; import javax.validation.Valid;
import javax.validation.constraints.NotNull; import javax.validation.constraints.NotNull;
import javax.validation.constraints.Size; import javax.validation.constraints.Size;
import org.whispersystems.textsecuregcm.identity.AciServiceIdentifier;
import org.whispersystems.textsecuregcm.identity.ServiceIdentifier; import org.whispersystems.textsecuregcm.identity.ServiceIdentifier;
import org.whispersystems.textsecuregcm.util.ExactlySize; import org.whispersystems.textsecuregcm.util.ExactlySize;
import org.whispersystems.textsecuregcm.util.ServiceIdentifierAdapter; import org.whispersystems.textsecuregcm.util.ServiceIdentifierAdapter;
@ -24,30 +23,13 @@ public record BatchIdentityCheckRequest(@Valid @NotNull @Size(max = 1000) List<E
* @param fingerprint most significant 4 bytes of SHA-256 of the 33-byte identity key field (32-byte curve25519 public * @param fingerprint most significant 4 bytes of SHA-256 of the 33-byte identity key field (32-byte curve25519 public
* key prefixed with 0x05) * key prefixed with 0x05)
*/ */
public record Element(@Nullable public record Element(@NotNull
@JsonSerialize(using = ServiceIdentifierAdapter.ServiceIdentifierSerializer.class) @JsonSerialize(using = ServiceIdentifierAdapter.ServiceIdentifierSerializer.class)
@JsonDeserialize(using = ServiceIdentifierAdapter.ServiceIdentifierDeserializer.class) @JsonDeserialize(using = ServiceIdentifierAdapter.ServiceIdentifierDeserializer.class)
ServiceIdentifier uuid, ServiceIdentifier uuid,
@Nullable
@Deprecated // remove after 2023-11-01
@JsonSerialize(using = ServiceIdentifierAdapter.ServiceIdentifierSerializer.class)
@JsonDeserialize(using = ServiceIdentifierAdapter.AciServiceIdentifierDeserializer.class)
AciServiceIdentifier aci,
@NotNull @NotNull
@ExactlySize(4) @ExactlySize(4)
byte[] fingerprint) { byte[] fingerprint) {
public Element {
if (aci == null && uuid == null) {
throw new IllegalArgumentException("aci and uuid cannot both be null");
} }
if (aci != null && uuid != null) {
throw new IllegalArgumentException("aci and uuid cannot both be non-null");
}
}
}
} }

View File

@ -9,7 +9,6 @@ import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import com.fasterxml.jackson.databind.annotation.JsonSerialize; import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import java.util.List; import java.util.List;
import javax.annotation.Nullable;
import javax.validation.Valid; import javax.validation.Valid;
import javax.validation.constraints.NotNull; import javax.validation.constraints.NotNull;
import org.signal.libsignal.protocol.IdentityKey; import org.signal.libsignal.protocol.IdentityKey;
@ -22,29 +21,12 @@ public record BatchIdentityCheckResponse(@Valid List<Element> elements) {
public record Element(@JsonInclude(JsonInclude.Include.NON_EMPTY) public record Element(@JsonInclude(JsonInclude.Include.NON_EMPTY)
@JsonSerialize(using = ServiceIdentifierAdapter.ServiceIdentifierSerializer.class) @JsonSerialize(using = ServiceIdentifierAdapter.ServiceIdentifierSerializer.class)
@JsonDeserialize(using = ServiceIdentifierAdapter.ServiceIdentifierDeserializer.class) @JsonDeserialize(using = ServiceIdentifierAdapter.ServiceIdentifierDeserializer.class)
@Nullable @NotNull
ServiceIdentifier uuid, ServiceIdentifier uuid,
@JsonInclude(JsonInclude.Include.NON_EMPTY)
@JsonSerialize(using = ServiceIdentifierAdapter.ServiceIdentifierSerializer.class)
@JsonDeserialize(using = ServiceIdentifierAdapter.AciServiceIdentifierDeserializer.class)
@Nullable
@Deprecated // remove after 2023-11-01
ServiceIdentifier aci,
@NotNull @NotNull
@JsonSerialize(using = IdentityKeyAdapter.Serializer.class) @JsonSerialize(using = IdentityKeyAdapter.Serializer.class)
@JsonDeserialize(using = IdentityKeyAdapter.Deserializer.class) @JsonDeserialize(using = IdentityKeyAdapter.Deserializer.class)
IdentityKey identityKey) { IdentityKey identityKey) {
public Element {
if (aci == null && uuid == null) {
throw new IllegalArgumentException("aci and uuid cannot both be null");
}
if (aci != null && uuid != null) {
throw new IllegalArgumentException("aci and uuid cannot both be non-null");
}
}
} }
} }

View File

@ -36,7 +36,6 @@ import java.util.Collections;
import java.util.HexFormat; import java.util.HexFormat;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Objects;
import java.util.Optional; import java.util.Optional;
import java.util.UUID; import java.util.UUID;
import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletableFuture;
@ -1299,13 +1298,11 @@ class ProfileControllerTest {
void testBatchIdentityCheck() { void testBatchIdentityCheck() {
try (final Response response = resources.getJerseyTest().target("/v1/profile/identity_check/batch").request() try (final Response response = resources.getJerseyTest().target("/v1/profile/identity_check/batch").request()
.post(Entity.json(new BatchIdentityCheckRequest(List.of( .post(Entity.json(new BatchIdentityCheckRequest(List.of(
new BatchIdentityCheckRequest.Element(new AciServiceIdentifier(AuthHelper.VALID_UUID), null, new BatchIdentityCheckRequest.Element(new AciServiceIdentifier(AuthHelper.VALID_UUID),
convertKeyToFingerprint(ACCOUNT_IDENTITY_KEY)), convertKeyToFingerprint(ACCOUNT_IDENTITY_KEY)),
new BatchIdentityCheckRequest.Element(new PniServiceIdentifier(AuthHelper.VALID_PNI_TWO), null, new BatchIdentityCheckRequest.Element(new PniServiceIdentifier(AuthHelper.VALID_PNI_TWO),
convertKeyToFingerprint(ACCOUNT_TWO_PHONE_NUMBER_IDENTITY_KEY)), convertKeyToFingerprint(ACCOUNT_TWO_PHONE_NUMBER_IDENTITY_KEY)),
new BatchIdentityCheckRequest.Element(null, new AciServiceIdentifier(AuthHelper.VALID_UUID_TWO), new BatchIdentityCheckRequest.Element(new AciServiceIdentifier(AuthHelper.INVALID_UUID),
convertKeyToFingerprint(ACCOUNT_TWO_IDENTITY_KEY)),
new BatchIdentityCheckRequest.Element(new AciServiceIdentifier(AuthHelper.INVALID_UUID), null,
convertKeyToFingerprint(ACCOUNT_TWO_PHONE_NUMBER_IDENTITY_KEY)) convertKeyToFingerprint(ACCOUNT_TWO_PHONE_NUMBER_IDENTITY_KEY))
))))) { ))))) {
assertThat(response).isNotNull(); assertThat(response).isNotNull();
@ -1322,46 +1319,42 @@ class ProfileControllerTest {
final Condition<BatchIdentityCheckResponse.Element> isAnExpectedUuid = final Condition<BatchIdentityCheckResponse.Element> isAnExpectedUuid =
new Condition<>(element -> element.identityKey() new Condition<>(element -> element.identityKey()
.equals(expectedIdentityKeys.get(Objects.requireNonNullElse(element.uuid(), element.aci()))), .equals(expectedIdentityKeys.get(element.uuid())),
"is an expected UUID with the correct identity key"); "is an expected UUID with the correct identity key");
final IdentityKey validAciIdentityKey = new IdentityKey(Curve.generateKeyPair().getPublicKey()); final IdentityKey validAciIdentityKey = new IdentityKey(Curve.generateKeyPair().getPublicKey());
final IdentityKey secondValidPniIdentityKey = new IdentityKey(Curve.generateKeyPair().getPublicKey()); final IdentityKey secondValidPniIdentityKey = new IdentityKey(Curve.generateKeyPair().getPublicKey());
final IdentityKey secondValidAciIdentityKey = new IdentityKey(Curve.generateKeyPair().getPublicKey());
final IdentityKey invalidAciIdentityKey = new IdentityKey(Curve.generateKeyPair().getPublicKey()); final IdentityKey invalidAciIdentityKey = new IdentityKey(Curve.generateKeyPair().getPublicKey());
try (final Response response = resources.getJerseyTest().target("/v1/profile/identity_check/batch").request() try (final Response response = resources.getJerseyTest().target("/v1/profile/identity_check/batch").request()
.post(Entity.json(new BatchIdentityCheckRequest(List.of( .post(Entity.json(new BatchIdentityCheckRequest(List.of(
new BatchIdentityCheckRequest.Element(new AciServiceIdentifier(AuthHelper.VALID_UUID), null, new BatchIdentityCheckRequest.Element(new AciServiceIdentifier(AuthHelper.VALID_UUID),
convertKeyToFingerprint(validAciIdentityKey)), convertKeyToFingerprint(validAciIdentityKey)),
new BatchIdentityCheckRequest.Element(new PniServiceIdentifier(AuthHelper.VALID_PNI_TWO), null, new BatchIdentityCheckRequest.Element(new PniServiceIdentifier(AuthHelper.VALID_PNI_TWO),
convertKeyToFingerprint(secondValidPniIdentityKey)), convertKeyToFingerprint(secondValidPniIdentityKey)),
new BatchIdentityCheckRequest.Element(null, new AciServiceIdentifier(AuthHelper.VALID_UUID_TWO), new BatchIdentityCheckRequest.Element(new AciServiceIdentifier(AuthHelper.INVALID_UUID),
convertKeyToFingerprint(secondValidAciIdentityKey)),
new BatchIdentityCheckRequest.Element(new AciServiceIdentifier(AuthHelper.INVALID_UUID), null,
convertKeyToFingerprint(invalidAciIdentityKey)) convertKeyToFingerprint(invalidAciIdentityKey))
))))) { ))))) {
assertThat(response).isNotNull(); assertThat(response).isNotNull();
assertThat(response.getStatus()).isEqualTo(200); assertThat(response.getStatus()).isEqualTo(200);
BatchIdentityCheckResponse identityCheckResponse = response.readEntity(BatchIdentityCheckResponse.class); BatchIdentityCheckResponse identityCheckResponse = response.readEntity(BatchIdentityCheckResponse.class);
assertThat(identityCheckResponse).isNotNull(); assertThat(identityCheckResponse).isNotNull();
assertThat(identityCheckResponse.elements()).isNotNull().hasSize(3); assertThat(identityCheckResponse.elements()).isNotNull().hasSize(2);
assertThat(identityCheckResponse.elements()).element(0).isNotNull().is(isAnExpectedUuid); assertThat(identityCheckResponse.elements()).element(0).isNotNull().is(isAnExpectedUuid);
assertThat(identityCheckResponse.elements()).element(1).isNotNull().is(isAnExpectedUuid); assertThat(identityCheckResponse.elements()).element(1).isNotNull().is(isAnExpectedUuid);
assertThat(identityCheckResponse.elements()).element(2).isNotNull().is(isAnExpectedUuid);
} }
final List<BatchIdentityCheckRequest.Element> largeElementList = new ArrayList<>(List.of( final List<BatchIdentityCheckRequest.Element> largeElementList = new ArrayList<>(List.of(
new BatchIdentityCheckRequest.Element(new AciServiceIdentifier(AuthHelper.VALID_UUID), null, new BatchIdentityCheckRequest.Element(new AciServiceIdentifier(AuthHelper.VALID_UUID),
convertKeyToFingerprint(validAciIdentityKey)), convertKeyToFingerprint(validAciIdentityKey)),
new BatchIdentityCheckRequest.Element(new PniServiceIdentifier(AuthHelper.VALID_PNI_TWO), null, new BatchIdentityCheckRequest.Element(new PniServiceIdentifier(AuthHelper.VALID_PNI_TWO),
convertKeyToFingerprint(secondValidPniIdentityKey)), convertKeyToFingerprint(secondValidPniIdentityKey)),
new BatchIdentityCheckRequest.Element(new AciServiceIdentifier(AuthHelper.INVALID_UUID), null, new BatchIdentityCheckRequest.Element(new AciServiceIdentifier(AuthHelper.INVALID_UUID),
convertKeyToFingerprint(invalidAciIdentityKey)))); convertKeyToFingerprint(invalidAciIdentityKey))));
for (int i = 0; i < 900; i++) { for (int i = 0; i < 900; i++) {
largeElementList.add( largeElementList.add(
new BatchIdentityCheckRequest.Element(new AciServiceIdentifier(UUID.randomUUID()), null, new BatchIdentityCheckRequest.Element(new AciServiceIdentifier(UUID.randomUUID()),
convertKeyToFingerprint(new IdentityKey(Curve.generateKeyPair().getPublicKey())))); convertKeyToFingerprint(new IdentityKey(Curve.generateKeyPair().getPublicKey()))));
} }
@ -1437,15 +1430,17 @@ class ProfileControllerTest {
new ServiceId.Aci(AuthHelper.VALID_UUID)); new ServiceId.Aci(AuthHelper.VALID_UUID));
final byte[] name = TestRandomUtil.nextBytes(81); final byte[] name = TestRandomUtil.nextBytes(81);
final Response response = resources.getJerseyTest() try (final Response response = resources.getJerseyTest()
.target("/v1/profile/") .target("/v1/profile/")
.request() .request()
.header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_UUID, AuthHelper.VALID_PASSWORD)) .header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_UUID, AuthHelper.VALID_PASSWORD))
.put(Entity.entity(new CreateProfileRequest(commitment, version, .put(Entity.entity(new CreateProfileRequest(commitment, version,
name, null, null, name, null, null,
null, true, false, Optional.of(List.of()), null), MediaType.APPLICATION_JSON_TYPE)); null, true, false, Optional.of(List.of()), null), MediaType.APPLICATION_JSON_TYPE))) {
assertThat(response.getStatus()).isEqualTo(422); assertThat(response.getStatus()).isEqualTo(422);
} }
}
static Stream<Arguments> testBatchIdentityCheckDeserializationBadRequest() { static Stream<Arguments> testBatchIdentityCheckDeserializationBadRequest() {
return Stream.of( return Stream.of(
@ -1457,7 +1452,7 @@ class ProfileControllerTest {
] ]
} }
""", Base64.getEncoder().encodeToString(convertKeyToFingerprint(new IdentityKey(Curve.generateKeyPair().getPublicKey())))), """, Base64.getEncoder().encodeToString(convertKeyToFingerprint(new IdentityKey(Curve.generateKeyPair().getPublicKey())))),
400), 422),
Arguments.of( // a blank string is invalid Arguments.of( // a blank string is invalid
String.format(""" String.format("""
{ {