store account profile current version as byte array, not hex
This commit is contained in:
parent
022f2b874d
commit
06d96a04df
@ -216,7 +216,7 @@ public class ProfileController {
|
||||
.orElseGet(a::getBadges);
|
||||
|
||||
a.setBadges(clock, updatedBadges);
|
||||
a.setCurrentProfileVersion(request.version());
|
||||
a.setCurrentProfileVersion(HexFormat.of().parseHex(request.version()));
|
||||
});
|
||||
|
||||
if (request.getAvatarChange() == CreateProfileRequest.AvatarChange.UPDATE) {
|
||||
@ -436,7 +436,7 @@ public class ProfileController {
|
||||
|
||||
final ExpiringProfileKeyCredentialResponse expiringProfileKeyCredentialResponse;
|
||||
|
||||
if (account.getCurrentProfileVersion().map(version::equals).orElse(false)) {
|
||||
if (account.getCurrentProfileVersion().map(v -> HexFormat.of().formatHex(v).equals(version)).orElse(false)) {
|
||||
expiringProfileKeyCredentialResponse = profilesManager.getV1(account.getUuid(), version)
|
||||
.map(profile -> {
|
||||
final ExpiringProfileKeyCredentialResponse profileKeyCredentialResponse;
|
||||
@ -488,7 +488,7 @@ public class ProfileController {
|
||||
// Allow requests where either the version matches the latest version on Account or the latest version on Account
|
||||
// is empty to read the payment address.
|
||||
final byte[] paymentAddress = maybeProfile
|
||||
.filter(p -> account.getCurrentProfileVersion().map(v -> v.equals(p.version())).orElse(true))
|
||||
.filter(p -> account.getCurrentProfileVersion().map(v -> HexFormat.of().formatHex(v).equals(p.version())).orElse(true))
|
||||
.map(VersionedProfileV1::paymentAddress)
|
||||
.orElse(null);
|
||||
|
||||
|
||||
@ -95,7 +95,7 @@ public class ProfileGrpcHelper {
|
||||
|
||||
// Include payment address if the version matches the latest version on Account or the latest version on Account
|
||||
// is empty
|
||||
if (account.getCurrentProfileVersion().map(v -> v.equals(HexFormat.of().formatHex(requestVersion))).orElse(true)) {
|
||||
if (account.getCurrentProfileVersion().map(v -> Arrays.equals(v, requestVersion)).orElse(true)) {
|
||||
final Optional<byte []> paymentAddress = profile.map(VersionedProfile::paymentAddress).or(() -> v1Profile.map(VersionedProfileV1::paymentAddress));
|
||||
|
||||
if (paymentAddress.isPresent()) {
|
||||
|
||||
@ -8,6 +8,7 @@ package org.whispersystems.textsecuregcm.grpc;
|
||||
import com.google.protobuf.ByteString;
|
||||
import java.time.Clock;
|
||||
import java.time.ZonedDateTime;
|
||||
import java.util.Arrays;
|
||||
import java.util.HexFormat;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
@ -107,11 +108,8 @@ public class ProfileGrpcService extends SimpleProfileGrpc.ProfileImplBase {
|
||||
|
||||
validateRequest(request);
|
||||
|
||||
final String expectedCurrentVersionHex = HexFormat.of().formatHex(request.getExpectedCurrentVersion().toByteArray());
|
||||
|
||||
final boolean currentVersionMatchesExpected = account.getCurrentProfileVersion().isEmpty()
|
||||
? request.getExpectedCurrentVersion().isEmpty()
|
||||
: account.getCurrentProfileVersion().get().equals(expectedCurrentVersionHex);
|
||||
final byte[] expectedCurrentVersion = request.getExpectedCurrentVersion().toByteArray();
|
||||
final boolean currentVersionMatchesExpected = Arrays.equals(account.getCurrentProfileVersion().orElse(new byte[0]), expectedCurrentVersion);
|
||||
|
||||
if (!currentVersionMatchesExpected) {
|
||||
return SetProfileResponse.newBuilder().setExpectedVersionWriteConflict(FailedPrecondition.newBuilder()
|
||||
@ -177,7 +175,7 @@ public class ProfileGrpcService extends SimpleProfileGrpc.ProfileImplBase {
|
||||
}
|
||||
|
||||
try {
|
||||
accountsManager.updateCurrentProfileVersion(account.getIdentifier(IdentityType.ACI), version, expectedCurrentVersionHex, a -> {
|
||||
accountsManager.updateCurrentProfileVersion(account.getIdentifier(IdentityType.ACI), version, expectedCurrentVersion, a -> {
|
||||
|
||||
final List<AccountBadge> updatedBadges = Optional.of(request.getBadgeIdsList())
|
||||
.map(badges -> ProfileHelper.mergeBadgeIdsWithExistingAccountBadges(clock, badgeConfigurationMap, badges,
|
||||
|
||||
@ -8,12 +8,21 @@ package org.whispersystems.textsecuregcm.storage;
|
||||
import com.fasterxml.jackson.annotation.JsonFilter;
|
||||
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import com.fasterxml.jackson.core.JsonGenerator;
|
||||
import com.fasterxml.jackson.core.JsonParser;
|
||||
import com.fasterxml.jackson.databind.DeserializationContext;
|
||||
import com.fasterxml.jackson.databind.JsonDeserializer;
|
||||
import com.fasterxml.jackson.databind.JsonSerializer;
|
||||
import com.fasterxml.jackson.databind.SerializerProvider;
|
||||
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
|
||||
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
|
||||
import java.io.IOException;
|
||||
import java.time.Clock;
|
||||
import java.time.Instant;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Base64;
|
||||
import java.util.Collections;
|
||||
import java.util.HexFormat;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
@ -80,7 +89,9 @@ public class Account {
|
||||
private IdentityKey phoneNumberIdentityKey;
|
||||
|
||||
@JsonProperty("cpv")
|
||||
private String currentProfileVersion;
|
||||
@JsonSerialize(using = ProfileKeyAdapter.Serializing.class)
|
||||
@JsonDeserialize(using = ProfileKeyAdapter.Deserializing.class)
|
||||
private byte[] currentProfileVersion;
|
||||
|
||||
@JsonProperty
|
||||
private List<AccountBadge> badges = new ArrayList<>();
|
||||
@ -323,13 +334,13 @@ public class Account {
|
||||
.orElse(0L);
|
||||
}
|
||||
|
||||
public Optional<String> getCurrentProfileVersion() {
|
||||
public Optional<byte[]> getCurrentProfileVersion() {
|
||||
requireNotStale();
|
||||
|
||||
return Optional.ofNullable(currentProfileVersion);
|
||||
}
|
||||
|
||||
public void setCurrentProfileVersion(final String currentProfileVersion) {
|
||||
public void setCurrentProfileVersion(final byte[] currentProfileVersion) {
|
||||
requireNotStale();
|
||||
|
||||
this.currentProfileVersion = currentProfileVersion;
|
||||
@ -564,4 +575,26 @@ public class Account {
|
||||
logger.error("Accessor called on stale account", new RuntimeException());
|
||||
}
|
||||
}
|
||||
|
||||
private static class ProfileKeyAdapter {
|
||||
private static class Deserializing extends JsonDeserializer<byte[]> {
|
||||
@Override
|
||||
public byte[] deserialize(JsonParser jsonParser, DeserializationContext deserializationContext) throws IOException {
|
||||
final String val = jsonParser.getValueAsString();
|
||||
if (val.length() == 64) {
|
||||
return HexFormat.of().parseHex(val);
|
||||
} else {
|
||||
return Base64.getDecoder().decode(val);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// after deploying this once we can get rid of it in favor of the default base64
|
||||
private static class Serializing extends JsonSerializer<byte[]> {
|
||||
@Override
|
||||
public void serialize(byte[] bytes, JsonGenerator jsonGenerator, SerializerProvider serializaterProvider) throws IOException {
|
||||
jsonGenerator.writeString(HexFormat.of().formatHex(bytes));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -967,7 +967,7 @@ public class AccountsManager extends RedisPubSubAdapter<String, String> implemen
|
||||
///
|
||||
/// @throws WriteConflictException if the expected current version does not match the current version
|
||||
public Account updateCurrentProfileVersion(final UUID accountIdentifier, final byte[] newVersion,
|
||||
final String expectedCurrentVersion, final Consumer<Account> updater) throws WriteConflictException {
|
||||
final byte[] expectedCurrentVersion, final Consumer<Account> updater) throws WriteConflictException {
|
||||
|
||||
Objects.requireNonNull(expectedCurrentVersion, "expectedCurrentVersion");
|
||||
|
||||
@ -975,22 +975,20 @@ public class AccountsManager extends RedisPubSubAdapter<String, String> implemen
|
||||
final Account account = accounts.getByAccountIdentifier(accountIdentifier)
|
||||
.orElseThrow(() -> new IllegalArgumentException("Account not found: " + accountIdentifier));
|
||||
|
||||
final String newVersionHex = HexFormat.of().formatHex(newVersion);
|
||||
|
||||
return accountLockManager.withLock(Set.of(account.getPhoneNumberIdentifier()), () -> {
|
||||
final Account maybeUpdatedAccount = update(accountIdentifier, a -> {
|
||||
if (!a.getCurrentProfileVersion().orElse("").equals(expectedCurrentVersion)) {
|
||||
if (!a.getCurrentProfileVersion().orElse(new byte[0]).equals(expectedCurrentVersion)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
a.setCurrentProfileVersion(newVersionHex);
|
||||
a.setCurrentProfileVersion(newVersion);
|
||||
|
||||
updater.accept(a);
|
||||
|
||||
return true;
|
||||
});
|
||||
|
||||
if (!maybeUpdatedAccount.getCurrentProfileVersion().map(v -> v.equals(newVersionHex)).orElse(false)) {
|
||||
if (!maybeUpdatedAccount.getCurrentProfileVersion().map(v -> v.equals(newVersion)).orElse(false)) {
|
||||
throw new WriteConflictException();
|
||||
}
|
||||
|
||||
|
||||
@ -950,13 +950,14 @@ class ProfileControllerTest {
|
||||
final byte[] name = TestRandomUtil.nextBytes(81);
|
||||
final byte[] paymentAddress = TestRandomUtil.nextBytes(582);
|
||||
|
||||
final String version = versionHex("someversion");
|
||||
final byte[] version = version("someversion");
|
||||
final String versionHex = HexFormat.of().formatHex(version);
|
||||
try (final Response response = resources.getJerseyTest()
|
||||
.target("/v1/profile")
|
||||
.request()
|
||||
.header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_UUID_TWO, AuthHelper.VALID_PASSWORD_TWO))
|
||||
.put(Entity.entity(
|
||||
new CreateProfileRequest(commitment, version, name, null, null, paymentAddress, false, false,
|
||||
new CreateProfileRequest(commitment, versionHex, name, null, null, paymentAddress, false, false,
|
||||
Optional.of(List.of()), null), MediaType.APPLICATION_JSON_TYPE))) {
|
||||
|
||||
assertThat(response.getStatus()).isEqualTo(200);
|
||||
@ -969,13 +970,14 @@ class ProfileControllerTest {
|
||||
@Test
|
||||
void testGetProfileReturnsNoPaymentAddressIfCurrentVersionMismatch() {
|
||||
final byte[] paymentAddress = TestRandomUtil.nextBytes(582);
|
||||
final String version = versionHex("validversion");
|
||||
when(profilesManager.getV1(AuthHelper.VALID_UUID_TWO, version)).thenReturn(
|
||||
Optional.of(new VersionedProfileV1(version, null, null, null, null, paymentAddress, null, null)));
|
||||
final byte[] version = version("validversion");
|
||||
final String versionHex = HexFormat.of().formatHex(version);
|
||||
when(profilesManager.getV1(AuthHelper.VALID_UUID_TWO, versionHex)).thenReturn(
|
||||
Optional.of(new VersionedProfileV1(versionHex, null, null, null, null, paymentAddress, null, null)));
|
||||
|
||||
{
|
||||
final VersionedProfileResponse profile = resources.getJerseyTest()
|
||||
.target("/v1/profile/" + AuthHelper.VALID_UUID_TWO + "/" + version)
|
||||
.target("/v1/profile/" + AuthHelper.VALID_UUID_TWO + "/" + versionHex)
|
||||
.request()
|
||||
.header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_UUID, AuthHelper.VALID_PASSWORD))
|
||||
.get(VersionedProfileResponse.class);
|
||||
@ -987,7 +989,7 @@ class ProfileControllerTest {
|
||||
|
||||
{
|
||||
final VersionedProfileResponse profile = resources.getJerseyTest()
|
||||
.target("/v1/profile/" + AuthHelper.VALID_UUID_TWO + "/" + version)
|
||||
.target("/v1/profile/" + AuthHelper.VALID_UUID_TWO + "/" + versionHex)
|
||||
.request()
|
||||
.header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_UUID, AuthHelper.VALID_PASSWORD))
|
||||
.get(VersionedProfileResponse.class);
|
||||
@ -995,11 +997,11 @@ class ProfileControllerTest {
|
||||
assertThat(profile.paymentAddress()).containsExactly(paymentAddress);
|
||||
}
|
||||
|
||||
when(profileAccount.getCurrentProfileVersion()).thenReturn(Optional.of(versionHex("someotherversion")));
|
||||
when(profileAccount.getCurrentProfileVersion()).thenReturn(Optional.of(version("someotherversion")));
|
||||
|
||||
{
|
||||
final VersionedProfileResponse profile = resources.getJerseyTest()
|
||||
.target("/v1/profile/" + AuthHelper.VALID_UUID_TWO + "/" + version)
|
||||
.target("/v1/profile/" + AuthHelper.VALID_UUID_TWO + "/" + versionHex)
|
||||
.request()
|
||||
.header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_UUID, AuthHelper.VALID_PASSWORD))
|
||||
.get(VersionedProfileResponse.class);
|
||||
@ -1013,13 +1015,13 @@ class ProfileControllerTest {
|
||||
final Account account = mock(Account.class);
|
||||
when(account.getUuid()).thenReturn(AuthHelper.VALID_UUID);
|
||||
when(account.getIdentifier(IdentityType.ACI)).thenReturn(AuthHelper.VALID_UUID);
|
||||
when(account.getCurrentProfileVersion()).thenReturn(Optional.of(versionHex("version")));
|
||||
when(account.getCurrentProfileVersion()).thenReturn(Optional.of(version("version")));
|
||||
|
||||
when(accountsManager.getByAccountIdentifier(AuthHelper.VALID_UUID)).thenReturn(Optional.of(account));
|
||||
when(profilesManager.getV1(any(), any())).thenReturn(Optional.empty());
|
||||
|
||||
final ExpiringProfileKeyCredentialProfileResponse profile = resources.getJerseyTest()
|
||||
.target(String.format("/v1/profile/%s/%s/%s", AuthHelper.VALID_UUID, versionHex("version-that-does-not-exist"), "credential-request"))
|
||||
.target(String.format("/v1/profile/%s/%s/%s", AuthHelper.VALID_UUID, HexFormat.of().formatHex(version("version-that-does-not-exist")), "credential-request"))
|
||||
.queryParam("credentialType", "expiringProfileKey")
|
||||
.request()
|
||||
.header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_UUID, AuthHelper.VALID_PASSWORD))
|
||||
@ -1043,12 +1045,13 @@ class ProfileControllerTest {
|
||||
final byte[] emoji = TestRandomUtil.nextBytes(60);
|
||||
final byte[] about = TestRandomUtil.nextBytes(156);
|
||||
|
||||
final String version = versionHex("anotherversion");
|
||||
final byte[] version = version("anotherversion");
|
||||
final String versionHex = HexFormat.of().formatHex(version);
|
||||
try (final Response response = resources.getJerseyTest()
|
||||
.target("/v1/profile/")
|
||||
.request()
|
||||
.header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_UUID_TWO, AuthHelper.VALID_PASSWORD_TWO))
|
||||
.put(Entity.entity(new CreateProfileRequest(commitment, version, name, emoji, about, null, false, false,
|
||||
.put(Entity.entity(new CreateProfileRequest(commitment, versionHex, name, emoji, about, null, false, false,
|
||||
Optional.of(List.of("TEST2")), null), MediaType.APPLICATION_JSON_TYPE))) {
|
||||
|
||||
assertThat(response.getStatus()).isEqualTo(200);
|
||||
@ -1071,7 +1074,7 @@ class ProfileControllerTest {
|
||||
.target("/v1/profile/")
|
||||
.request()
|
||||
.header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_UUID_TWO, AuthHelper.VALID_PASSWORD_TWO))
|
||||
.put(Entity.entity(new CreateProfileRequest(commitment, version, name, emoji, about, null, false, false,
|
||||
.put(Entity.entity(new CreateProfileRequest(commitment, versionHex, name, emoji, about, null, false, false,
|
||||
Optional.of(List.of("TEST3", "TEST2")), null), MediaType.APPLICATION_JSON_TYPE))) {
|
||||
|
||||
assertThat(response.getStatus()).isEqualTo(200);
|
||||
@ -1097,7 +1100,7 @@ class ProfileControllerTest {
|
||||
.target("/v1/profile/")
|
||||
.request()
|
||||
.header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_UUID_TWO, AuthHelper.VALID_PASSWORD_TWO))
|
||||
.put(Entity.entity(new CreateProfileRequest(commitment, version, name, emoji, about, null, false, false,
|
||||
.put(Entity.entity(new CreateProfileRequest(commitment, versionHex, name, emoji, about, null, false, false,
|
||||
Optional.of(List.of("TEST2", "TEST3")), null), MediaType.APPLICATION_JSON_TYPE))) {
|
||||
|
||||
assertThat(response.getStatus()).isEqualTo(200);
|
||||
@ -1123,7 +1126,7 @@ class ProfileControllerTest {
|
||||
.target("/v1/profile/")
|
||||
.request()
|
||||
.header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_UUID_TWO, AuthHelper.VALID_PASSWORD_TWO))
|
||||
.put(Entity.entity(new CreateProfileRequest(commitment, version, name, emoji, about, null, false, false,
|
||||
.put(Entity.entity(new CreateProfileRequest(commitment, versionHex, name, emoji, about, null, false, false,
|
||||
Optional.of(List.of("TEST1")), null), MediaType.APPLICATION_JSON_TYPE))) {
|
||||
|
||||
assertThat(response.getStatus()).isEqualTo(200);
|
||||
@ -1150,7 +1153,8 @@ class ProfileControllerTest {
|
||||
final byte[] name = TestRandomUtil.nextBytes(81);
|
||||
final byte[] emoji = TestRandomUtil.nextBytes(60);
|
||||
final byte[] about = TestRandomUtil.nextBytes(156);
|
||||
final String version = versionHex("anotherversion");
|
||||
final byte[] version = version("anotherversion");
|
||||
final String versionHex = HexFormat.of().formatHex(version);
|
||||
|
||||
clearInvocations(AuthHelper.VALID_ACCOUNT_TWO);
|
||||
reset(accountsManager);
|
||||
@ -1173,7 +1177,7 @@ class ProfileControllerTest {
|
||||
.target("/v1/profile/")
|
||||
.request()
|
||||
.header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_UUID_TWO, AuthHelper.VALID_PASSWORD_TWO))
|
||||
.put(Entity.entity(new CreateProfileRequest(commitment, version, name, emoji, about, null, false, false,
|
||||
.put(Entity.entity(new CreateProfileRequest(commitment, versionHex, name, emoji, about, null, false, false,
|
||||
Optional.of(List.of("TEST1")), null), MediaType.APPLICATION_JSON_TYPE))) {
|
||||
|
||||
assertThat(response.getStatus()).isEqualTo(200);
|
||||
@ -1198,7 +1202,8 @@ class ProfileControllerTest {
|
||||
@MethodSource
|
||||
void testGetProfileWithExpiringProfileKeyCredential(final MultivaluedMap<String, Object> authHeaders)
|
||||
throws VerificationFailedException, InvalidInputException {
|
||||
final String version = versionHex("version");
|
||||
final byte[] version = version("version");
|
||||
final String versionHex = HexFormat.of().formatHex(version);
|
||||
|
||||
final ServerSecretParams serverSecretParams = ServerSecretParams.generate();
|
||||
final ServerPublicParams serverPublicParams = serverSecretParams.getPublicParams();
|
||||
@ -1233,12 +1238,12 @@ class ProfileControllerTest {
|
||||
serverZkProfile.issueExpiringProfileKeyCredential(credentialRequest, new ServiceId.Aci(AuthHelper.VALID_UUID), profileKeyCommitment, expiration);
|
||||
|
||||
when(accountsManager.getByServiceIdentifier(new AciServiceIdentifier(AuthHelper.VALID_UUID))).thenReturn(Optional.of(account));
|
||||
when(profilesManager.getV1(AuthHelper.VALID_UUID, version)).thenReturn(Optional.of(versionedProfile));
|
||||
when(profilesManager.getV1(AuthHelper.VALID_UUID, versionHex)).thenReturn(Optional.of(versionedProfile));
|
||||
when(zkProfileOperations.issueExpiringProfileKeyCredential(eq(credentialRequest), eq(new ServiceId.Aci(AuthHelper.VALID_UUID)), eq(profileKeyCommitment), any()))
|
||||
.thenReturn(credentialResponse);
|
||||
|
||||
final ExpiringProfileKeyCredentialProfileResponse profile = resources.getJerseyTest()
|
||||
.target(String.format("/v1/profile/%s/%s/%s", AuthHelper.VALID_UUID, version,
|
||||
.target(String.format("/v1/profile/%s/%s/%s", AuthHelper.VALID_UUID, versionHex,
|
||||
HexFormat.of().formatHex(credentialRequest.serialize())))
|
||||
.queryParam("credentialType", "expiringProfileKey")
|
||||
.request()
|
||||
@ -1267,7 +1272,8 @@ class ProfileControllerTest {
|
||||
@Test
|
||||
void testGetProfileWithExpiringProfileKeyCredentialBadRequest()
|
||||
throws VerificationFailedException, InvalidInputException {
|
||||
final String version = versionHex("version");
|
||||
final byte[] version = version("version");
|
||||
final String versionHex = HexFormat.of().formatHex(version);
|
||||
|
||||
final ServerSecretParams serverSecretParams = ServerSecretParams.generate();
|
||||
final ServerPublicParams serverPublicParams = serverSecretParams.getPublicParams();
|
||||
@ -1294,12 +1300,12 @@ class ProfileControllerTest {
|
||||
when(account.getCurrentProfileVersion()).thenReturn(Optional.of(version));
|
||||
|
||||
when(accountsManager.getByServiceIdentifier(new AciServiceIdentifier(AuthHelper.VALID_UUID))).thenReturn(Optional.of(account));
|
||||
when(profilesManager.getV1(AuthHelper.VALID_UUID, version)).thenReturn(Optional.of(versionedProfile));
|
||||
when(profilesManager.getV1(AuthHelper.VALID_UUID, versionHex)).thenReturn(Optional.of(versionedProfile));
|
||||
when(zkProfileOperations.issueExpiringProfileKeyCredential(any(), any(), any(), any()))
|
||||
.thenThrow(new VerificationFailedException());
|
||||
|
||||
final Response response = resources.getJerseyTest()
|
||||
.target(String.format("/v1/profile/%s/%s/%s", AuthHelper.VALID_UUID, version,
|
||||
.target(String.format("/v1/profile/%s/%s/%s", AuthHelper.VALID_UUID, versionHex,
|
||||
HexFormat.of().formatHex(credentialRequest.serialize())))
|
||||
.queryParam("credentialType", "expiringProfileKey")
|
||||
.request()
|
||||
@ -1312,7 +1318,8 @@ class ProfileControllerTest {
|
||||
@Test
|
||||
void testGetProfileWithExpiringProfileKeyCredentialNonCurrentVersion()
|
||||
throws VerificationFailedException, InvalidInputException {
|
||||
final String version = versionHex("version");
|
||||
final byte[] version = version("version");
|
||||
final String versionHex = HexFormat.of().formatHex(version);
|
||||
|
||||
final ServerSecretParams serverSecretParams = ServerSecretParams.generate();
|
||||
final ServerPublicParams serverPublicParams = serverSecretParams.getPublicParams();
|
||||
@ -1338,13 +1345,13 @@ class ProfileControllerTest {
|
||||
when(account.getUuid()).thenReturn(AuthHelper.VALID_UUID);
|
||||
when(account.getUnidentifiedAccessKey()).thenReturn(Optional.of(UNIDENTIFIED_ACCESS_KEY));
|
||||
when(account.isIdentifiedBy(new AciServiceIdentifier(AuthHelper.VALID_UUID))).thenReturn(true);
|
||||
when(account.getCurrentProfileVersion()).thenReturn(Optional.of(versionHex("the-current-version")));
|
||||
when(account.getCurrentProfileVersion()).thenReturn(Optional.of(version("the-current-version")));
|
||||
|
||||
when(accountsManager.getByServiceIdentifier(new AciServiceIdentifier(AuthHelper.VALID_UUID))).thenReturn(Optional.of(account));
|
||||
when(profilesManager.getV1(AuthHelper.VALID_UUID, version)).thenReturn(Optional.of(versionedProfile));
|
||||
when(profilesManager.getV1(AuthHelper.VALID_UUID, versionHex)).thenReturn(Optional.of(versionedProfile));
|
||||
|
||||
final Response response = resources.getJerseyTest()
|
||||
.target(String.format("/v1/profile/%s/%s/%s", AuthHelper.VALID_UUID, version,
|
||||
.target(String.format("/v1/profile/%s/%s/%s", AuthHelper.VALID_UUID, versionHex,
|
||||
HexFormat.of().formatHex(credentialRequest.serialize())))
|
||||
.queryParam("credentialType", "expiringProfileKey")
|
||||
.request()
|
||||
@ -1580,11 +1587,15 @@ class ProfileControllerTest {
|
||||
}
|
||||
}
|
||||
|
||||
private static String versionHex(final String versionString) {
|
||||
private static byte[] version(final String versionString) {
|
||||
try {
|
||||
return HexFormat.of().formatHex(MessageDigest.getInstance("SHA-256").digest(versionString.getBytes(StandardCharsets.UTF_8)));
|
||||
return MessageDigest.getInstance("SHA-256").digest(versionString.getBytes(StandardCharsets.UTF_8));
|
||||
} catch (NoSuchAlgorithmException e) {
|
||||
throw new AssertionError(e);
|
||||
}
|
||||
}
|
||||
|
||||
private static String versionHex(final String versionString) {
|
||||
return HexFormat.of().formatHex(version(versionString));
|
||||
}
|
||||
}
|
||||
|
||||
@ -372,7 +372,7 @@ public class ProfileAnonymousGrpcServiceTest extends SimpleBaseGrpcTest<ProfileA
|
||||
|
||||
final Optional<VersionedProfileV1> profile = Optional.of(new VersionedProfileV1(HexFormat.of().formatHex(requestVersion), name, avatar, emoji, about, paymentAddress, phoneNumberSharing, new byte[0]));
|
||||
|
||||
when(account.getCurrentProfileVersion()).thenReturn(Optional.ofNullable(accountVersion).map(v -> HexFormat.of().formatHex(v)));
|
||||
when(account.getCurrentProfileVersion()).thenReturn(Optional.ofNullable(accountVersion));
|
||||
when(account.isUnrestrictedUnidentifiedAccess()).thenReturn(false);
|
||||
when(account.getUnidentifiedAccessKey()).thenReturn(Optional.of(unidentifiedAccessKey));
|
||||
|
||||
@ -428,10 +428,9 @@ public class ProfileAnonymousGrpcServiceTest extends SimpleBaseGrpcTest<ProfileA
|
||||
final byte[] paymentAddress = TestRandomUtil.nextBytes(582);
|
||||
final byte[] commitment = TestRandomUtil.nextBytes(97);
|
||||
final byte[] version = TestRandomUtil.nextBytes(32);
|
||||
final String versionHex = HexFormat.of().formatHex(version);
|
||||
final VersionedProfile v2Profile = new VersionedProfile(version, data, paymentAddress, commitment);
|
||||
|
||||
when(account.getCurrentProfileVersion()).thenReturn(Optional.of(versionHex));
|
||||
when(account.getCurrentProfileVersion()).thenReturn(Optional.of(version));
|
||||
when(account.isUnrestrictedUnidentifiedAccess()).thenReturn(false);
|
||||
when(account.getUnidentifiedAccessKey()).thenReturn(Optional.of(unidentifiedAccessKey));
|
||||
when(account.hasCapability(DeviceCapability.PROFILES_V2)).thenReturn(true);
|
||||
@ -472,10 +471,9 @@ public class ProfileAnonymousGrpcServiceTest extends SimpleBaseGrpcTest<ProfileA
|
||||
final byte[] paymentAddress = TestRandomUtil.nextBytes(582);
|
||||
final byte[] commitment = TestRandomUtil.nextBytes(97);
|
||||
final byte[] version = TestRandomUtil.nextBytes(32);
|
||||
final String versionHex = HexFormat.of().formatHex(version);
|
||||
final VersionedProfile v2Profile = new VersionedProfile(version, data, paymentAddress, commitment);
|
||||
|
||||
when(account.getCurrentProfileVersion()).thenReturn(Optional.of(versionHex));
|
||||
when(account.getCurrentProfileVersion()).thenReturn(Optional.of(version));
|
||||
when(account.isUnrestrictedUnidentifiedAccess()).thenReturn(false);
|
||||
when(account.getUnidentifiedAccessKey()).thenReturn(Optional.of(unidentifiedAccessKey));
|
||||
when(account.hasCapability(DeviceCapability.PROFILES_V2)).thenReturn(true);
|
||||
|
||||
@ -304,7 +304,7 @@ public class ProfileGrpcServiceTest extends SimpleBaseGrpcTest<ProfileGrpcServic
|
||||
final byte[] validPhoneNumberSharing = new byte[29];
|
||||
|
||||
when(account.getCurrentProfileVersion()).thenReturn(
|
||||
Optional.of(HexFormat.of().formatHex(TestRandomUtil.nextBytes(32))));
|
||||
Optional.of(TestRandomUtil.nextBytes(32)));
|
||||
|
||||
final SetProfileRequest request = SetProfileRequest.newBuilder()
|
||||
.setVersion(ByteString.copyFrom(VERSION))
|
||||
@ -715,7 +715,7 @@ public class ProfileGrpcServiceTest extends SimpleBaseGrpcTest<ProfileGrpcServic
|
||||
.setVersion(ByteString.copyFrom(requestVersion))
|
||||
.build();
|
||||
|
||||
when(account.getCurrentProfileVersion()).thenReturn(Optional.ofNullable(accountVersion).map(v -> HexFormat.of().formatHex(v)));
|
||||
when(account.getCurrentProfileVersion()).thenReturn(Optional.ofNullable(accountVersion));
|
||||
when(accountsManager.getByServiceIdentifier(any())).thenReturn(Optional.of(account));
|
||||
when(profilesManager.getV1(any(), any())).thenReturn(profile);
|
||||
|
||||
@ -757,7 +757,6 @@ public class ProfileGrpcServiceTest extends SimpleBaseGrpcTest<ProfileGrpcServic
|
||||
final byte[] paymentAddress = TestRandomUtil.nextBytes(582);
|
||||
final byte[] commitment = TestRandomUtil.nextBytes(97);
|
||||
final byte[] version = TestRandomUtil.nextBytes(32);
|
||||
final String versionHex = HexFormat.of().formatHex(version);
|
||||
|
||||
final UUID targetAci = UUID.randomUUID();
|
||||
final VersionedProfile v2Profile = new VersionedProfile(version, data, paymentAddress, commitment);
|
||||
@ -766,7 +765,7 @@ public class ProfileGrpcServiceTest extends SimpleBaseGrpcTest<ProfileGrpcServic
|
||||
when(accountsManager.getByServiceIdentifier(new AciServiceIdentifier(targetAci)))
|
||||
.thenReturn(Optional.of(targetAccount));
|
||||
when(targetAccount.getUuid()).thenReturn(targetAci);
|
||||
when(targetAccount.getCurrentProfileVersion()).thenReturn(Optional.of(versionHex));
|
||||
when(targetAccount.getCurrentProfileVersion()).thenReturn(Optional.of(version));
|
||||
when(targetAccount.hasCapability(DeviceCapability.PROFILES_V2)).thenReturn(true);
|
||||
|
||||
when(profilesManager.get(eq(targetAci), aryEq(version))).thenReturn(Optional.of(v2Profile));
|
||||
@ -801,7 +800,6 @@ public class ProfileGrpcServiceTest extends SimpleBaseGrpcTest<ProfileGrpcServic
|
||||
final byte[] paymentAddress = TestRandomUtil.nextBytes(582);
|
||||
final byte[] commitment = TestRandomUtil.nextBytes(97);
|
||||
final byte[] version = TestRandomUtil.nextBytes(32);
|
||||
final String versionHex = HexFormat.of().formatHex(version);
|
||||
final VersionedProfile v2Profile = new VersionedProfile(version, data, paymentAddress, commitment);
|
||||
|
||||
final UUID targetAci = UUID.randomUUID();
|
||||
@ -810,7 +808,7 @@ public class ProfileGrpcServiceTest extends SimpleBaseGrpcTest<ProfileGrpcServic
|
||||
when(targetAccount.hasCapability(DeviceCapability.PROFILES_V2)).thenReturn(true);
|
||||
when(accountsManager.getByServiceIdentifier(new AciServiceIdentifier(targetAci))).thenReturn(Optional.of(targetAccount));
|
||||
|
||||
when(targetAccount.getCurrentProfileVersion()).thenReturn(Optional.of(versionHex));
|
||||
when(targetAccount.getCurrentProfileVersion()).thenReturn(Optional.of(version));
|
||||
when(profilesManager.get(targetAci, version)).thenReturn(Optional.of(v2Profile));
|
||||
when(profilesManager.getV1(any(), any())).thenReturn(Optional.empty());
|
||||
|
||||
|
||||
@ -171,7 +171,7 @@ class AccountsManagerConcurrentModificationIntegrationTest {
|
||||
}
|
||||
|
||||
final boolean discoverableByPhoneNumber = false;
|
||||
final String currentProfileVersion = "cpv";
|
||||
final byte[] currentProfileVersion = new byte[32];
|
||||
final IdentityKey identityKey = new IdentityKey(ECKeyPair.generate().getPublicKey());
|
||||
final byte[] unidentifiedAccessKey = new byte[]{1};
|
||||
final String pin = "1234";
|
||||
@ -214,11 +214,11 @@ class AccountsManagerConcurrentModificationIntegrationTest {
|
||||
return JsonHelpers.fromJson(redisSetArgumentCapture.getValue(), Account.class);
|
||||
}
|
||||
|
||||
private void verifyAccount(final String name, final Account account, final boolean discoverableByPhoneNumber, final String currentProfileVersion, final IdentityKey identityKey, final byte[] unidentifiedAccessKey, final String pin, final String clientRegistrationLock, final boolean unrestrictedUnidentifiedAccess, final long lastSeen) {
|
||||
private void verifyAccount(final String name, final Account account, final boolean discoverableByPhoneNumber, final byte[] currentProfileVersion, final IdentityKey identityKey, final byte[] unidentifiedAccessKey, final String pin, final String clientRegistrationLock, final boolean unrestrictedUnidentifiedAccess, final long lastSeen) {
|
||||
|
||||
assertAll(name,
|
||||
() -> assertEquals(discoverableByPhoneNumber, account.isDiscoverableByPhoneNumber()),
|
||||
() -> assertEquals(currentProfileVersion, account.getCurrentProfileVersion().orElseThrow()),
|
||||
() -> assertArrayEquals(currentProfileVersion, account.getCurrentProfileVersion().orElseThrow()),
|
||||
() -> assertEquals(identityKey, account.getIdentityKey(IdentityType.ACI)),
|
||||
() -> assertArrayEquals(unidentifiedAccessKey, account.getUnidentifiedAccessKey().orElseThrow()),
|
||||
() -> assertTrue(account.getRegistrationLock().verify(clientRegistrationLock)),
|
||||
|
||||
@ -1460,22 +1460,22 @@ class AccountsManagerTest {
|
||||
final UUID accountIdentifier = account.getIdentifier(IdentityType.ACI);
|
||||
addRetrievableAccount(account);
|
||||
|
||||
account.setCurrentProfileVersion(HexFormat.of().formatHex(currentVersion));
|
||||
account.setCurrentProfileVersion(currentVersion);
|
||||
|
||||
final AccountBadge badge = new AccountBadge("test", CLOCK.instant().plusSeconds(60), true);
|
||||
|
||||
assertTrue(account.getBadges().isEmpty());
|
||||
|
||||
if (expectException) {
|
||||
assertThrows(WriteConflictException.class, () -> accountsManager.updateCurrentProfileVersion(accountIdentifier, newVersion, HexFormat.of().formatHex(expectedVersion), _ -> {}));
|
||||
assertThrows(WriteConflictException.class, () -> accountsManager.updateCurrentProfileVersion(accountIdentifier, newVersion, expectedVersion, _ -> {}));
|
||||
} else {
|
||||
final Account updatedAccount = accountsManager.updateCurrentProfileVersion(accountIdentifier, newVersion,
|
||||
HexFormat.of().formatHex(expectedVersion), a -> {
|
||||
expectedVersion, a -> {
|
||||
|
||||
a.setBadges(CLOCK, new ArrayList<>(List.of(badge)));
|
||||
});
|
||||
|
||||
assertArrayEquals(newVersion, HexFormat.of().parseHex(updatedAccount.getCurrentProfileVersion().orElseThrow()));
|
||||
assertArrayEquals(newVersion, updatedAccount.getCurrentProfileVersion().orElseThrow());
|
||||
assertEquals(List.of(badge), updatedAccount.getBadges());
|
||||
}
|
||||
}
|
||||
|
||||
@ -1146,7 +1146,7 @@ class AccountsTest {
|
||||
final Account secondAccountInstance = accounts.getByAccountIdentifier(firstAccountInstance.getUuid()).orElseThrow();
|
||||
|
||||
// update via the first instance, which will update the version
|
||||
firstAccountInstance.setCurrentProfileVersion("1");
|
||||
firstAccountInstance.setCurrentProfileVersion(new byte[32]);
|
||||
accounts.update(firstAccountInstance);
|
||||
|
||||
assertThrows(ContestedOptimisticLockException.class,
|
||||
|
||||
Loading…
Reference in New Issue
Block a user