Convert `PreKeyState` to a record
This commit is contained in:
parent
9ecfe15ac4
commit
f10f772e94
|
@ -138,15 +138,15 @@ public class KeysController {
|
||||||
|
|
||||||
final boolean usePhoneNumberIdentity = usePhoneNumberIdentity(identityType);
|
final boolean usePhoneNumberIdentity = usePhoneNumberIdentity(identityType);
|
||||||
|
|
||||||
if (preKeys.getSignedPreKey() != null &&
|
if (preKeys.signedPreKey() != null &&
|
||||||
!preKeys.getSignedPreKey().equals(usePhoneNumberIdentity ? device.getSignedPreKey(IdentityType.PNI)
|
!preKeys.signedPreKey().equals(usePhoneNumberIdentity ? device.getSignedPreKey(IdentityType.PNI)
|
||||||
: device.getSignedPreKey(IdentityType.ACI))) {
|
: device.getSignedPreKey(IdentityType.ACI))) {
|
||||||
updateAccount = true;
|
updateAccount = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
final IdentityKey oldIdentityKey =
|
final IdentityKey oldIdentityKey =
|
||||||
usePhoneNumberIdentity ? account.getIdentityKey(IdentityType.PNI) : account.getIdentityKey(IdentityType.ACI);
|
usePhoneNumberIdentity ? account.getIdentityKey(IdentityType.PNI) : account.getIdentityKey(IdentityType.ACI);
|
||||||
if (!Objects.equals(preKeys.getIdentityKey(), oldIdentityKey)) {
|
if (!Objects.equals(preKeys.identityKey(), oldIdentityKey)) {
|
||||||
updateAccount = true;
|
updateAccount = true;
|
||||||
|
|
||||||
final boolean hasIdentityKey = oldIdentityKey != null;
|
final boolean hasIdentityKey = oldIdentityKey != null;
|
||||||
|
@ -170,26 +170,26 @@ public class KeysController {
|
||||||
|
|
||||||
if (updateAccount) {
|
if (updateAccount) {
|
||||||
account = accounts.update(account, a -> {
|
account = accounts.update(account, a -> {
|
||||||
if (preKeys.getSignedPreKey() != null) {
|
if (preKeys.signedPreKey() != null) {
|
||||||
a.getDevice(device.getId()).ifPresent(d -> {
|
a.getDevice(device.getId()).ifPresent(d -> {
|
||||||
if (usePhoneNumberIdentity) {
|
if (usePhoneNumberIdentity) {
|
||||||
d.setPhoneNumberIdentitySignedPreKey(preKeys.getSignedPreKey());
|
d.setPhoneNumberIdentitySignedPreKey(preKeys.signedPreKey());
|
||||||
} else {
|
} else {
|
||||||
d.setSignedPreKey(preKeys.getSignedPreKey());
|
d.setSignedPreKey(preKeys.signedPreKey());
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
if (usePhoneNumberIdentity) {
|
if (usePhoneNumberIdentity) {
|
||||||
a.setPhoneNumberIdentityKey(preKeys.getIdentityKey());
|
a.setPhoneNumberIdentityKey(preKeys.identityKey());
|
||||||
} else {
|
} else {
|
||||||
a.setIdentityKey(preKeys.getIdentityKey());
|
a.setIdentityKey(preKeys.identityKey());
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
return keys.store(getIdentifier(account, identityType), device.getId(),
|
return keys.store(getIdentifier(account, identityType), device.getId(),
|
||||||
preKeys.getPreKeys(), preKeys.getPqPreKeys(), preKeys.getSignedPreKey(), preKeys.getPqLastResortPreKey())
|
preKeys.preKeys(), preKeys.pqPreKeys(), preKeys.signedPreKey(), preKeys.pqLastResortPreKey())
|
||||||
.thenApply(Util.ASYNC_EMPTY_RESPONSE);
|
.thenApply(Util.ASYNC_EMPTY_RESPONSE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -4,105 +4,59 @@
|
||||||
*/
|
*/
|
||||||
package org.whispersystems.textsecuregcm.entities;
|
package org.whispersystems.textsecuregcm.entities;
|
||||||
|
|
||||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
|
||||||
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 com.google.common.annotations.VisibleForTesting;
|
|
||||||
import io.swagger.v3.oas.annotations.media.Schema;
|
import io.swagger.v3.oas.annotations.media.Schema;
|
||||||
import org.signal.libsignal.protocol.IdentityKey;
|
import org.signal.libsignal.protocol.IdentityKey;
|
||||||
import org.whispersystems.textsecuregcm.util.IdentityKeyAdapter;
|
import org.whispersystems.textsecuregcm.util.IdentityKeyAdapter;
|
||||||
|
|
||||||
import javax.validation.Valid;
|
import javax.validation.Valid;
|
||||||
import javax.validation.constraints.AssertTrue;
|
import javax.validation.constraints.AssertTrue;
|
||||||
import javax.validation.constraints.NotNull;
|
import javax.validation.constraints.NotNull;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
public class PreKeyState {
|
public record PreKeyState(
|
||||||
|
@Valid
|
||||||
|
@Schema(description = """
|
||||||
|
A list of unsigned elliptic-curve prekeys to use for this device. If present and not empty, replaces all stored
|
||||||
|
unsigned EC prekeys for the device; if absent or empty, any stored unsigned EC prekeys for the device are not
|
||||||
|
deleted.
|
||||||
|
""")
|
||||||
|
List<@Valid ECPreKey> preKeys,
|
||||||
|
|
||||||
@JsonProperty
|
@Valid
|
||||||
@Valid
|
@Schema(description = """
|
||||||
@Schema(description = """
|
An optional signed elliptic-curve prekey to use for this device. If present, replaces the stored signed
|
||||||
A list of unsigned elliptic-curve prekeys to use for this device. If present and not empty, replaces all stored
|
elliptic-curve prekey for the device; if absent, the stored signed prekey is not deleted. If present, must have
|
||||||
unsigned EC prekeys for the device; if absent or empty, any stored unsigned EC prekeys for the device are not
|
a valid signature from the identity key in this request.
|
||||||
deleted.
|
""")
|
||||||
""")
|
ECSignedPreKey signedPreKey,
|
||||||
private List<@Valid ECPreKey> preKeys;
|
|
||||||
|
|
||||||
@JsonProperty
|
@Valid
|
||||||
@Valid
|
@Schema(description = """
|
||||||
@Schema(description = """
|
A list of signed post-quantum one-time prekeys to use for this device. Each key must have a valid signature from
|
||||||
An optional signed elliptic-curve prekey to use for this device. If present, replaces the stored signed
|
the identity key in this request. If present and not empty, replaces all stored unsigned PQ prekeys for the
|
||||||
elliptic-curve prekey for the device; if absent, the stored signed prekey is not deleted. If present, must have a
|
device; if absent or empty, any stored unsigned PQ prekeys for the device are not deleted.
|
||||||
valid signature from the identity key in this request.
|
""")
|
||||||
""")
|
List<@Valid KEMSignedPreKey> pqPreKeys,
|
||||||
private ECSignedPreKey signedPreKey;
|
|
||||||
|
|
||||||
@JsonProperty
|
@Valid
|
||||||
@Valid
|
@Schema(description = """
|
||||||
@Schema(description = """
|
An optional signed last-resort post-quantum prekey to use for this device. If present, replaces the stored
|
||||||
A list of signed post-quantum one-time prekeys to use for this device. Each key must have a valid signature from
|
signed post-quantum last-resort prekey for the device; if absent, a stored last-resort prekey will *not* be
|
||||||
the identity key in this request. If present and not empty, replaces all stored unsigned PQ prekeys for the
|
deleted. If present, must have a valid signature from the identity key in this request.
|
||||||
device; if absent or empty, any stored unsigned PQ prekeys for the device are not deleted.
|
""")
|
||||||
""")
|
KEMSignedPreKey pqLastResortPreKey,
|
||||||
private List<@Valid KEMSignedPreKey> pqPreKeys;
|
|
||||||
|
|
||||||
@JsonProperty
|
@JsonSerialize(using = IdentityKeyAdapter.Serializer.class)
|
||||||
@Valid
|
@JsonDeserialize(using = IdentityKeyAdapter.Deserializer.class)
|
||||||
@Schema(description = """
|
@NotNull
|
||||||
An optional signed last-resort post-quantum prekey to use for this device. If present, replaces the stored signed
|
@Schema(description = """
|
||||||
post-quantum last-resort prekey for the device; if absent, a stored last-resort prekey will *not* be deleted. If
|
Required. The public identity key for this identity (account or phone-number identity). If this device is not
|
||||||
present, must have a valid signature from the identity key in this request.
|
the primary device for the account, must match the existing stored identity key for this identity.
|
||||||
""")
|
""")
|
||||||
private KEMSignedPreKey pqLastResortPreKey;
|
IdentityKey identityKey
|
||||||
|
) {
|
||||||
@JsonProperty
|
|
||||||
@JsonSerialize(using = IdentityKeyAdapter.Serializer.class)
|
|
||||||
@JsonDeserialize(using = IdentityKeyAdapter.Deserializer.class)
|
|
||||||
@NotNull
|
|
||||||
@Schema(description = """
|
|
||||||
Required. The public identity key for this identity (account or phone-number identity). If this device is not the
|
|
||||||
primary device for the account, must match the existing stored identity key for this identity.
|
|
||||||
""")
|
|
||||||
private IdentityKey identityKey;
|
|
||||||
|
|
||||||
public PreKeyState() {
|
|
||||||
}
|
|
||||||
|
|
||||||
@VisibleForTesting
|
|
||||||
public PreKeyState(IdentityKey identityKey, ECSignedPreKey signedPreKey, List<ECPreKey> keys) {
|
|
||||||
this(identityKey, signedPreKey, keys, null, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
@VisibleForTesting
|
|
||||||
public PreKeyState(IdentityKey identityKey, ECSignedPreKey signedPreKey, List<ECPreKey> keys,
|
|
||||||
List<KEMSignedPreKey> pqKeys, KEMSignedPreKey pqLastResortKey) {
|
|
||||||
this.identityKey = identityKey;
|
|
||||||
this.signedPreKey = signedPreKey;
|
|
||||||
this.preKeys = keys;
|
|
||||||
this.pqPreKeys = pqKeys;
|
|
||||||
this.pqLastResortPreKey = pqLastResortKey;
|
|
||||||
}
|
|
||||||
|
|
||||||
public List<ECPreKey> getPreKeys() {
|
|
||||||
return preKeys;
|
|
||||||
}
|
|
||||||
|
|
||||||
public ECSignedPreKey getSignedPreKey() {
|
|
||||||
return signedPreKey;
|
|
||||||
}
|
|
||||||
|
|
||||||
public List<KEMSignedPreKey> getPqPreKeys() {
|
|
||||||
return pqPreKeys;
|
|
||||||
}
|
|
||||||
|
|
||||||
public KEMSignedPreKey getPqLastResortPreKey() {
|
|
||||||
return pqLastResortPreKey;
|
|
||||||
}
|
|
||||||
|
|
||||||
public IdentityKey getIdentityKey() {
|
|
||||||
return identityKey;
|
|
||||||
}
|
|
||||||
|
|
||||||
@AssertTrue
|
@AssertTrue
|
||||||
public boolean isSignatureValidOnEachSignedKey() {
|
public boolean isSignatureValidOnEachSignedKey() {
|
||||||
|
|
|
@ -732,7 +732,7 @@ class KeysControllerTest {
|
||||||
final ECSignedPreKey signedPreKey = KeysHelper.signedECPreKey(31338, identityKeyPair);
|
final ECSignedPreKey signedPreKey = KeysHelper.signedECPreKey(31338, identityKeyPair);
|
||||||
final IdentityKey identityKey = new IdentityKey(identityKeyPair.getPublicKey());
|
final IdentityKey identityKey = new IdentityKey(identityKeyPair.getPublicKey());
|
||||||
|
|
||||||
PreKeyState preKeyState = new PreKeyState(identityKey, signedPreKey, List.of(preKey));
|
final PreKeyState preKeyState = new PreKeyState(List.of(preKey), signedPreKey, null, null, identityKey);
|
||||||
|
|
||||||
Response response =
|
Response response =
|
||||||
resources.getJerseyTest()
|
resources.getJerseyTest()
|
||||||
|
@ -763,7 +763,8 @@ class KeysControllerTest {
|
||||||
final KEMSignedPreKey pqLastResortPreKey = KeysHelper.signedKEMPreKey(31340, identityKeyPair);
|
final KEMSignedPreKey pqLastResortPreKey = KeysHelper.signedKEMPreKey(31340, identityKeyPair);
|
||||||
final IdentityKey identityKey = new IdentityKey(identityKeyPair.getPublicKey());
|
final IdentityKey identityKey = new IdentityKey(identityKeyPair.getPublicKey());
|
||||||
|
|
||||||
PreKeyState preKeyState = new PreKeyState(identityKey, signedPreKey, List.of(preKey), List.of(pqPreKey), pqLastResortPreKey);
|
final PreKeyState preKeyState =
|
||||||
|
new PreKeyState(List.of(preKey), signedPreKey, List.of(pqPreKey), pqLastResortPreKey, identityKey);
|
||||||
|
|
||||||
Response response =
|
Response response =
|
||||||
resources.getJerseyTest()
|
resources.getJerseyTest()
|
||||||
|
@ -866,7 +867,7 @@ class KeysControllerTest {
|
||||||
final ECSignedPreKey signedPreKey = KeysHelper.signedECPreKey(31338, identityKeyPair);
|
final ECSignedPreKey signedPreKey = KeysHelper.signedECPreKey(31338, identityKeyPair);
|
||||||
final IdentityKey identityKey = new IdentityKey(identityKeyPair.getPublicKey());
|
final IdentityKey identityKey = new IdentityKey(identityKeyPair.getPublicKey());
|
||||||
|
|
||||||
PreKeyState preKeyState = new PreKeyState(identityKey, signedPreKey, List.of(preKey));
|
final PreKeyState preKeyState = new PreKeyState(List.of(preKey), signedPreKey, null, null, identityKey);
|
||||||
|
|
||||||
Response response =
|
Response response =
|
||||||
resources.getJerseyTest()
|
resources.getJerseyTest()
|
||||||
|
@ -898,7 +899,8 @@ class KeysControllerTest {
|
||||||
final KEMSignedPreKey pqLastResortPreKey = KeysHelper.signedKEMPreKey(31340, identityKeyPair);
|
final KEMSignedPreKey pqLastResortPreKey = KeysHelper.signedKEMPreKey(31340, identityKeyPair);
|
||||||
final IdentityKey identityKey = new IdentityKey(identityKeyPair.getPublicKey());
|
final IdentityKey identityKey = new IdentityKey(identityKeyPair.getPublicKey());
|
||||||
|
|
||||||
PreKeyState preKeyState = new PreKeyState(identityKey, signedPreKey, List.of(preKey), List.of(pqPreKey), pqLastResortPreKey);
|
final PreKeyState preKeyState =
|
||||||
|
new PreKeyState(List.of(preKey), signedPreKey, List.of(pqPreKey), pqLastResortPreKey, identityKey);
|
||||||
|
|
||||||
Response response =
|
Response response =
|
||||||
resources.getJerseyTest()
|
resources.getJerseyTest()
|
||||||
|
@ -926,7 +928,7 @@ class KeysControllerTest {
|
||||||
@Test
|
@Test
|
||||||
void putPrekeyWithInvalidSignature() {
|
void putPrekeyWithInvalidSignature() {
|
||||||
final ECSignedPreKey badSignedPreKey = KeysHelper.signedECPreKey(1, Curve.generateKeyPair());
|
final ECSignedPreKey badSignedPreKey = KeysHelper.signedECPreKey(1, Curve.generateKeyPair());
|
||||||
PreKeyState preKeyState = new PreKeyState(IDENTITY_KEY, badSignedPreKey, List.of());
|
final PreKeyState preKeyState = new PreKeyState(List.of(), badSignedPreKey, null, null, IDENTITY_KEY);
|
||||||
Response response =
|
Response response =
|
||||||
resources.getJerseyTest()
|
resources.getJerseyTest()
|
||||||
.target("/v2/keys")
|
.target("/v2/keys")
|
||||||
|
@ -945,7 +947,7 @@ class KeysControllerTest {
|
||||||
final ECSignedPreKey signedPreKey = KeysHelper.signedECPreKey(31338, identityKeyPair);
|
final ECSignedPreKey signedPreKey = KeysHelper.signedECPreKey(31338, identityKeyPair);
|
||||||
final IdentityKey identityKey = new IdentityKey(identityKeyPair.getPublicKey());
|
final IdentityKey identityKey = new IdentityKey(identityKeyPair.getPublicKey());
|
||||||
|
|
||||||
PreKeyState preKeyState = new PreKeyState(identityKey, signedPreKey, List.of(preKey));
|
final PreKeyState preKeyState = new PreKeyState(List.of(preKey), signedPreKey, null, null, identityKey);
|
||||||
|
|
||||||
Response response =
|
Response response =
|
||||||
resources.getJerseyTest()
|
resources.getJerseyTest()
|
||||||
|
@ -975,9 +977,9 @@ class KeysControllerTest {
|
||||||
final ECPreKey preKey = KeysHelper.ecPreKey(31337);
|
final ECPreKey preKey = KeysHelper.ecPreKey(31337);
|
||||||
final ECSignedPreKey signedPreKey = KeysHelper.signedECPreKey(31338, IDENTITY_KEY_PAIR);
|
final ECSignedPreKey signedPreKey = KeysHelper.signedECPreKey(31338, IDENTITY_KEY_PAIR);
|
||||||
|
|
||||||
List<ECPreKey> preKeys = List.of(preKey);
|
final List<ECPreKey> preKeys = List.of(preKey);
|
||||||
|
|
||||||
PreKeyState preKeyState = new PreKeyState(IDENTITY_KEY, signedPreKey, preKeys);
|
final PreKeyState preKeyState = new PreKeyState(preKeys, signedPreKey, null, null, IDENTITY_KEY);
|
||||||
|
|
||||||
Response response =
|
Response response =
|
||||||
resources.getJerseyTest()
|
resources.getJerseyTest()
|
||||||
|
|
Loading…
Reference in New Issue