Update batch check entities from two optional fields to a single field

This commit is contained in:
Chris Eager 2022-09-09 13:52:36 -05:00 committed by Chris Eager
parent 320c5eac53
commit 8b65c11e1e
4 changed files with 51 additions and 32 deletions

View File

@ -394,8 +394,15 @@ public class ProfileController {
maybeAccount = accountsManager.getByAccountIdentifier(element.aci());
usePhoneNumberIdentity = false;
} else {
maybeAccount = accountsManager.getByPhoneNumberIdentifier(element.pni());
usePhoneNumberIdentity = true;
final Optional<Account> maybeAciAccount = accountsManager.getByAccountIdentifier(element.uuid());
if (maybeAciAccount.isEmpty()) {
maybeAccount = accountsManager.getByPhoneNumberIdentifier(element.uuid());
usePhoneNumberIdentity = true;
} else {
maybeAccount = maybeAciAccount;
usePhoneNumberIdentity = false;
}
}
maybeAccount.ifPresent(account -> {
@ -414,7 +421,7 @@ public class ProfileController {
byte[] fingerprint = Util.truncate(digest, 4);
if (!Arrays.equals(fingerprint, element.fingerprint())) {
responseElements.add(new BatchIdentityCheckResponse.Element(element.aci(), element.pni(), identityKeyBytes));
responseElements.add(new BatchIdentityCheckResponse.Element(element.aci(), element.uuid(), identityKeyBytes));
}
});
}

View File

@ -16,22 +16,21 @@ import org.whispersystems.textsecuregcm.util.ExactlySize;
public record BatchIdentityCheckRequest(@Valid @NotNull @Size(max = 1000) List<Element> elements) {
/**
* Exactly one of {@code aci} and {@code pni} must be non-null
*
* @param aci account id
* @param pni phone number id
* @param uuid account id or phone number id
* @param fingerprint most significant 4 bytes of SHA-256 of the 33-byte identity key field (32-byte curve25519 public
* key prefixed with 0x05)
*/
public record Element(@Nullable UUID aci, @Nullable UUID pni, @NotNull @ExactlySize(4) byte[] fingerprint) {
public record Element(@Deprecated @Nullable UUID aci,
@Nullable UUID uuid,
@NotNull @ExactlySize(4) byte[] fingerprint) {
public Element {
if (aci == null && pni == null) {
throw new IllegalArgumentException("aci and pni cannot both be null");
if (aci == null && uuid == null) {
throw new IllegalArgumentException("aci and uuid cannot both be null");
}
if (aci != null && pni != null) {
throw new IllegalArgumentException("aci and pni cannot both be non-null");
if (aci != null && uuid != null) {
throw new IllegalArgumentException("aci and uuid cannot both be non-null");
}
}
}

View File

@ -5,6 +5,7 @@
package org.whispersystems.textsecuregcm.entities;
import com.fasterxml.jackson.annotation.JsonInclude;
import java.util.List;
import java.util.UUID;
import javax.annotation.Nullable;
@ -14,18 +15,17 @@ import org.whispersystems.textsecuregcm.util.ExactlySize;
public record BatchIdentityCheckResponse(@Valid List<Element> elements) {
/**
* Exactly one of {@code aci} and {@code pni} must be non-null
*/
public record Element(@Nullable UUID aci, @Nullable UUID pni, @NotNull @ExactlySize(33) byte[] identityKey) {
public record Element(@Deprecated @JsonInclude(JsonInclude.Include.NON_EMPTY) @Nullable UUID aci,
@JsonInclude(JsonInclude.Include.NON_EMPTY) @Nullable UUID uuid,
@NotNull @ExactlySize(33) byte[] identityKey) {
public Element {
if (aci == null && pni == null) {
throw new IllegalArgumentException("aci and pni cannot both be null");
if (aci == null && uuid == null) {
throw new IllegalArgumentException("aci and uuid cannot both be null");
}
if (aci != null && pni != null) {
throw new IllegalArgumentException("aci and pni cannot both be non-null");
if (aci != null && uuid != null) {
throw new IllegalArgumentException("aci and uuid cannot both be non-null");
}
}
}

View File

@ -1237,6 +1237,8 @@ class ProfileControllerTest {
convertStringToFingerprint(ACCOUNT_IDENTITY_KEY)),
new BatchIdentityCheckRequest.Element(null, AuthHelper.VALID_PNI_TWO,
convertStringToFingerprint(ACCOUNT_TWO_PHONE_NUMBER_IDENTITY_KEY)),
new BatchIdentityCheckRequest.Element(null, AuthHelper.VALID_UUID_TWO,
convertStringToFingerprint(ACCOUNT_TWO_IDENTITY_KEY)),
new BatchIdentityCheckRequest.Element(AuthHelper.INVALID_UUID, null,
convertStringToFingerprint(ACCOUNT_TWO_PHONE_NUMBER_IDENTITY_KEY))
))))) {
@ -1250,8 +1252,10 @@ class ProfileControllerTest {
Condition<BatchIdentityCheckResponse.Element> isAnExpectedUuid = new Condition<>(element -> {
if (AuthHelper.VALID_UUID.equals(element.aci())) {
return Arrays.equals(Base64.getDecoder().decode(ACCOUNT_IDENTITY_KEY), element.identityKey());
} else if (AuthHelper.VALID_PNI_TWO.equals(element.pni())) {
} else if (AuthHelper.VALID_PNI_TWO.equals(element.uuid())) {
return Arrays.equals(Base64.getDecoder().decode(ACCOUNT_TWO_PHONE_NUMBER_IDENTITY_KEY), element.identityKey());
} else if (AuthHelper.VALID_UUID_TWO.equals(element.uuid())) {
return Arrays.equals(Base64.getDecoder().decode(ACCOUNT_TWO_IDENTITY_KEY), element.identityKey());
} else {
return false;
}
@ -1262,15 +1266,18 @@ class ProfileControllerTest {
new BatchIdentityCheckRequest.Element(AuthHelper.VALID_UUID, null, convertStringToFingerprint("else1234")),
new BatchIdentityCheckRequest.Element(null, AuthHelper.VALID_PNI_TWO,
convertStringToFingerprint("another1")),
new BatchIdentityCheckRequest.Element(null, AuthHelper.VALID_UUID_TWO,
convertStringToFingerprint("another2")),
new BatchIdentityCheckRequest.Element(AuthHelper.INVALID_UUID, null, convertStringToFingerprint("456"))
))))) {
assertThat(response).isNotNull();
assertThat(response.getStatus()).isEqualTo(200);
BatchIdentityCheckResponse identityCheckResponse = response.readEntity(BatchIdentityCheckResponse.class);
assertThat(identityCheckResponse).isNotNull();
assertThat(identityCheckResponse.elements()).isNotNull().hasSize(2);
assertThat(identityCheckResponse.elements()).isNotNull().hasSize(3);
assertThat(identityCheckResponse.elements()).element(0).isNotNull().is(isAnExpectedUuid);
assertThat(identityCheckResponse.elements()).element(1).isNotNull().is(isAnExpectedUuid);
assertThat(identityCheckResponse.elements()).element(2).isNotNull().is(isAnExpectedUuid);
}
List<BatchIdentityCheckRequest.Element> largeElementList = new ArrayList<>(List.of(
@ -1294,12 +1301,12 @@ class ProfileControllerTest {
}
@Test
void testBatchIdentityCheckDeserialization() {
void testBatchIdentityCheckDeserialization() throws Exception {
Condition<BatchIdentityCheckResponse.Element> isAnExpectedUuid = new Condition<>(element -> {
if (AuthHelper.VALID_UUID.equals(element.aci())) {
return Arrays.equals(Base64.getDecoder().decode(ACCOUNT_IDENTITY_KEY), element.identityKey());
} else if (AuthHelper.VALID_PNI_TWO.equals(element.pni())) {
} else if (AuthHelper.VALID_PNI_TWO.equals(element.uuid())) {
return Arrays.equals(Base64.getDecoder().decode(ACCOUNT_TWO_PHONE_NUMBER_IDENTITY_KEY), element.identityKey());
} else {
return false;
@ -1311,7 +1318,7 @@ class ProfileControllerTest {
{
"elements": [
{ "aci": "%s", "fingerprint": "%s" },
{ "pni": "%s", "fingerprint": "%s" },
{ "uuid": "%s", "fingerprint": "%s" },
{ "aci": "%s", "fingerprint": "%s" }
]
}
@ -1322,7 +1329,13 @@ class ProfileControllerTest {
.post(Entity.entity(json, "application/json"))) {
assertThat(response).isNotNull();
assertThat(response.getStatus()).isEqualTo(200);
BatchIdentityCheckResponse identityCheckResponse = response.readEntity(BatchIdentityCheckResponse.class);
String responseJson = response.readEntity(String.class);
// `null` properties should be omitted from the response
assertThat(responseJson).doesNotContain("null");
BatchIdentityCheckResponse identityCheckResponse = SystemMapper.getMapper()
.readValue(responseJson, BatchIdentityCheckResponse.class);
assertThat(identityCheckResponse).isNotNull();
assertThat(identityCheckResponse.elements()).isNotNull().hasSize(2);
assertThat(identityCheckResponse.elements()).element(0).isNotNull().is(isAnExpectedUuid);
@ -1342,11 +1355,11 @@ class ProfileControllerTest {
static Stream<Arguments> testBatchIdentityCheckDeserializationBadRequest() {
return Stream.of(
Arguments.of( // aci and pni cannot both be null
Arguments.of( // aci and uuid cannot both be null
"""
{
"elements": [
{ "aci": null, "pni": null, "fingerprint": "%s" }
{ "aci": null, "uuid": null, "fingerprint": "%s" }
]
}
"""),
@ -1354,7 +1367,7 @@ class ProfileControllerTest {
"""
{
"elements": [
{ "aci": "", "pni": null, "fingerprint": "%s" }
{ "aci": "", "uuid": null, "fingerprint": "%s" }
]
}
"""
@ -1363,15 +1376,15 @@ class ProfileControllerTest {
"""
{
"elements": [
{ "aci": null, "pni": " ", "fingerprint": "%s" }
{ "aci": null, "uuid": " ", "fingerprint": "%s" }
]
}
"""),
Arguments.of( // aci and pni cannot both be non-null
Arguments.of( // aci and uuid cannot both be non-null
String.format("""
{
"elements": [
{ "aci": "%s", "pni": "%s", "fingerprint": "%s" }
{ "aci": "%s", "uuid": "%s", "fingerprint": "%s" }
]
}
""", AuthHelper.VALID_UUID, AuthHelper.VALID_PNI,