From 142376f36012b68141f6077cce42fa80a1dc8005 Mon Sep 17 00:00:00 2001 From: Ehren Kret Date: Fri, 12 Feb 2021 17:33:26 -0600 Subject: [PATCH] Add payment address to the versioned profile --- .../controllers/ProfileController.java | 61 +++++++++------- .../entities/CreateProfileRequest.java | 21 ++++-- .../textsecuregcm/entities/Profile.java | 45 +++++++----- .../textsecuregcm/storage/Profiles.java | 62 ++++++++++------ .../storage/VersionedProfile.java | 20 +++-- .../mappers/VersionedProfileMapper.java | 19 ++--- service/src/main/resources/accountsdb.xml | 8 ++ .../controllers/ProfileControllerTest.java | 73 +++++++++++++++---- .../tests/storage/ProfilesManagerTest.java | 6 +- .../tests/storage/ProfilesTest.java | 26 ++++--- 10 files changed, 229 insertions(+), 112 deletions(-) diff --git a/service/src/main/java/org/whispersystems/textsecuregcm/controllers/ProfileController.java b/service/src/main/java/org/whispersystems/textsecuregcm/controllers/ProfileController.java index 1183a6994..371e826fb 100644 --- a/service/src/main/java/org/whispersystems/textsecuregcm/controllers/ProfileController.java +++ b/service/src/main/java/org/whispersystems/textsecuregcm/controllers/ProfileController.java @@ -8,6 +8,24 @@ package org.whispersystems.textsecuregcm.controllers; import com.amazonaws.services.s3.AmazonS3; import com.codahale.metrics.annotation.Timed; import io.dropwizard.auth.Auth; +import java.security.SecureRandom; +import java.time.ZoneOffset; +import java.time.ZonedDateTime; +import java.util.Optional; +import java.util.UUID; +import javax.validation.Valid; +import javax.validation.valueextraction.Unwrapping; +import javax.ws.rs.Consumes; +import javax.ws.rs.GET; +import javax.ws.rs.HeaderParam; +import javax.ws.rs.PUT; +import javax.ws.rs.Path; +import javax.ws.rs.PathParam; +import javax.ws.rs.Produces; +import javax.ws.rs.QueryParam; +import javax.ws.rs.WebApplicationException; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; import org.apache.commons.codec.DecoderException; import org.apache.commons.codec.binary.Base64; import org.apache.commons.codec.binary.Hex; @@ -38,25 +56,6 @@ import org.whispersystems.textsecuregcm.storage.VersionedProfile; import org.whispersystems.textsecuregcm.util.ExactlySize; import org.whispersystems.textsecuregcm.util.Pair; -import javax.validation.Valid; -import javax.validation.valueextraction.Unwrapping; -import javax.ws.rs.Consumes; -import javax.ws.rs.GET; -import javax.ws.rs.HeaderParam; -import javax.ws.rs.PUT; -import javax.ws.rs.Path; -import javax.ws.rs.PathParam; -import javax.ws.rs.Produces; -import javax.ws.rs.QueryParam; -import javax.ws.rs.WebApplicationException; -import javax.ws.rs.core.MediaType; -import javax.ws.rs.core.Response; -import java.security.SecureRandom; -import java.time.ZoneOffset; -import java.time.ZonedDateTime; -import java.util.Optional; -import java.util.UUID; - @SuppressWarnings("OptionalUsedAsFieldOrParameterType") @Path("/v1/profile") public class ProfileController { @@ -110,7 +109,15 @@ public class ProfileController { String avatar = request.isAvatar() ? generateAvatarObjectName() : null; Optional response = Optional.empty(); - profilesManager.set(account.getUuid(), new VersionedProfile(request.getVersion(), request.getName(), avatar, request.getAboutEmoji(), request.getAbout(), request.getCommitment().serialize())); + profilesManager.set(account.getUuid(), + new VersionedProfile( + request.getVersion(), + request.getName(), + avatar, + request.getAboutEmoji(), + request.getAbout(), + request.getPaymentAddress(), + request.getCommitment().serialize())); if (request.isAvatar()) { Optional currentAvatar = Optional.empty(); @@ -191,17 +198,19 @@ public class ProfileController { Optional username = usernamesManager.get(accountProfile.get().getUuid()); Optional profile = profilesManager.get(uuid, version); - String name = profile.map(VersionedProfile::getName).orElse(accountProfile.get().getProfileName()); - String about = profile.map(VersionedProfile::getAbout).orElse(null); - String aboutEmoji = profile.map(VersionedProfile::getAboutEmoji).orElse(null); - String avatar = profile.map(VersionedProfile::getAvatar).orElse(accountProfile.get().getAvatar()); - + String name = profile.map(VersionedProfile::getName).orElse(accountProfile.get().getProfileName()); + String about = profile.map(VersionedProfile::getAbout).orElse(null); + String aboutEmoji = profile.map(VersionedProfile::getAboutEmoji).orElse(null); + String avatar = profile.map(VersionedProfile::getAvatar).orElse(accountProfile.get().getAvatar()); + String paymentAddress = profile.map(VersionedProfile::getPaymentAddress).orElse(null); + Optional credential = getProfileCredential(credentialRequest, profile, uuid); return Optional.of(new Profile(name, about, aboutEmoji, avatar, + paymentAddress, accountProfile.get().getIdentityKey(), UnidentifiedAccessChecksum.generateFor(accountProfile.get().getUnidentifiedAccessKey()), accountProfile.get().isUnrestrictedUnidentifiedAccess(), @@ -242,6 +251,7 @@ public class ProfileController { null, null, accountProfile.get().getAvatar(), + null, accountProfile.get().getIdentityKey(), UnidentifiedAccessChecksum.generateFor(accountProfile.get().getUnidentifiedAccessKey()), accountProfile.get().isUnrestrictedUnidentifiedAccess(), @@ -317,6 +327,7 @@ public class ProfileController { null, null, accountProfile.get().getAvatar(), + null, accountProfile.get().getIdentityKey(), UnidentifiedAccessChecksum.generateFor(accountProfile.get().getUnidentifiedAccessKey()), accountProfile.get().isUnrestrictedUnidentifiedAccess(), diff --git a/service/src/main/java/org/whispersystems/textsecuregcm/entities/CreateProfileRequest.java b/service/src/main/java/org/whispersystems/textsecuregcm/entities/CreateProfileRequest.java index 538c0b1fe..17ace4dee 100644 --- a/service/src/main/java/org/whispersystems/textsecuregcm/entities/CreateProfileRequest.java +++ b/service/src/main/java/org/whispersystems/textsecuregcm/entities/CreateProfileRequest.java @@ -35,6 +35,10 @@ public class CreateProfileRequest { @ExactlySize({0, 208, 376, 720}) private String about; + @JsonProperty + @ExactlySize({0, 684}) + private String paymentAddress; + @JsonProperty @NotNull @JsonDeserialize(using = ProfileKeyCommitmentAdapter.Deserializing.class) @@ -43,13 +47,16 @@ public class CreateProfileRequest { public CreateProfileRequest() {} - public CreateProfileRequest(ProfileKeyCommitment commitment, String version, String name, String aboutEmoji, String about, boolean wantsAvatar) { + public CreateProfileRequest( + ProfileKeyCommitment commitment, String version, String name, String aboutEmoji, String about, + String paymentAddress, boolean wantsAvatar) { this.commitment = commitment; - this.version = version; - this.name = name; + this.version = version; + this.name = name; this.aboutEmoji = aboutEmoji; - this.about = about; - this.avatar = wantsAvatar; + this.about = about; + this.paymentAddress = paymentAddress; + this.avatar = wantsAvatar; } public ProfileKeyCommitment getCommitment() { @@ -75,4 +82,8 @@ public class CreateProfileRequest { public String getAbout() { return StringUtils.stripToNull(about); } + + public String getPaymentAddress() { + return paymentAddress; + } } diff --git a/service/src/main/java/org/whispersystems/textsecuregcm/entities/Profile.java b/service/src/main/java/org/whispersystems/textsecuregcm/entities/Profile.java index 437e609dd..5c9c1f355 100644 --- a/service/src/main/java/org/whispersystems/textsecuregcm/entities/Profile.java +++ b/service/src/main/java/org/whispersystems/textsecuregcm/entities/Profile.java @@ -9,12 +9,10 @@ import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.fasterxml.jackson.databind.annotation.JsonSerialize; import com.google.common.annotations.VisibleForTesting; - -import org.signal.zkgroup.profiles.ProfileKeyCredentialResponse; -import org.whispersystems.textsecuregcm.storage.PaymentAddress; - import java.util.List; import java.util.UUID; +import org.signal.zkgroup.profiles.ProfileKeyCredentialResponse; +import org.whispersystems.textsecuregcm.storage.PaymentAddress; public class Profile { @@ -33,6 +31,9 @@ public class Profile { @JsonProperty private String avatar; + @JsonProperty + private String paymentAddress; + @JsonProperty private String unidentifiedAccess; @@ -58,24 +59,24 @@ public class Profile { public Profile() {} - public Profile(String name, String about, String aboutEmoji, String avatar, String identityKey, - String unidentifiedAccess, boolean unrestrictedUnidentifiedAccess, - UserCapabilities capabilities, String username, UUID uuid, - ProfileKeyCredentialResponse credential, - List payments) + public Profile( + String name, String about, String aboutEmoji, String avatar, String paymentAddress, String identityKey, + String unidentifiedAccess, boolean unrestrictedUnidentifiedAccess, UserCapabilities capabilities, String username, + UUID uuid, ProfileKeyCredentialResponse credential, List payments) { - this.name = name; - this.about = about; - this.aboutEmoji = aboutEmoji; - this.avatar = avatar; - this.identityKey = identityKey; - this.unidentifiedAccess = unidentifiedAccess; + this.name = name; + this.about = about; + this.aboutEmoji = aboutEmoji; + this.avatar = avatar; + this.paymentAddress = paymentAddress; + this.identityKey = identityKey; + this.unidentifiedAccess = unidentifiedAccess; this.unrestrictedUnidentifiedAccess = unrestrictedUnidentifiedAccess; - this.capabilities = capabilities; - this.username = username; - this.uuid = uuid; - this.payments = payments; - this.credential = credential; + this.capabilities = capabilities; + this.username = username; + this.uuid = uuid; + this.payments = payments; + this.credential = credential; } @VisibleForTesting @@ -101,6 +102,10 @@ public class Profile { return avatar; } + public String getPaymentAddress() { + return paymentAddress; + } + @VisibleForTesting public String getUnidentifiedAccess() { return unidentifiedAccess; diff --git a/service/src/main/java/org/whispersystems/textsecuregcm/storage/Profiles.java b/service/src/main/java/org/whispersystems/textsecuregcm/storage/Profiles.java index d23df863e..9947d40a4 100644 --- a/service/src/main/java/org/whispersystems/textsecuregcm/storage/Profiles.java +++ b/service/src/main/java/org/whispersystems/textsecuregcm/storage/Profiles.java @@ -5,27 +5,27 @@ package org.whispersystems.textsecuregcm.storage; +import static com.codahale.metrics.MetricRegistry.name; + import com.codahale.metrics.MetricRegistry; import com.codahale.metrics.SharedMetricRegistries; import com.codahale.metrics.Timer; +import java.util.Optional; +import java.util.UUID; import org.whispersystems.textsecuregcm.storage.mappers.VersionedProfileMapper; import org.whispersystems.textsecuregcm.util.Constants; -import java.util.Optional; -import java.util.UUID; - -import static com.codahale.metrics.MetricRegistry.name; - public class Profiles { - public static final String ID = "id"; - public static final String UID = "uuid"; - public static final String VERSION = "version"; - public static final String NAME = "name"; - public static final String AVATAR = "avatar"; - public static final String ABOUT_EMOJI = "about_emoji"; - public static final String ABOUT = "about"; - public static final String COMMITMENT = "commitment"; + public static final String ID = "id"; + public static final String UID = "uuid"; + public static final String VERSION = "version"; + public static final String NAME = "name"; + public static final String AVATAR = "avatar"; + public static final String ABOUT_EMOJI = "about_emoji"; + public static final String ABOUT = "about"; + public static final String PAYMENT_ADDRESS = "payment_address"; + public static final String COMMITMENT = "commitment"; private final MetricRegistry metricRegistry = SharedMetricRegistries.getOrCreate(Constants.METRICS_NAME); @@ -43,15 +43,33 @@ public class Profiles { public void set(UUID uuid, VersionedProfile profile) { database.use(jdbi -> jdbi.useHandle(handle -> { try (Timer.Context ignored = setTimer.time()) { - handle.createUpdate("INSERT INTO profiles (" + UID + ", " + VERSION + ", " + NAME + ", " + AVATAR + ", " + ABOUT_EMOJI + ", " + ABOUT + ", " + COMMITMENT + ") VALUES (:uuid, :version, :name, :avatar, :about_emoji, :about, :commitment) ON CONFLICT (" + UID + ", " + VERSION + ") DO UPDATE SET " + NAME + " = EXCLUDED." + NAME + ", " + AVATAR + " = EXCLUDED." + AVATAR + ", " + ABOUT + " = EXCLUDED." + ABOUT + ", " + ABOUT_EMOJI + " = EXCLUDED." + ABOUT_EMOJI) - .bind("uuid", uuid) - .bind("version", profile.getVersion()) - .bind("name", profile.getName()) - .bind("avatar", profile.getAvatar()) - .bind("about_emoji", profile.getAboutEmoji()) - .bind("about", profile.getAbout()) - .bind("commitment", profile.getCommitment()) - .execute(); + handle.createUpdate( + "INSERT INTO profiles (" + + UID + ", " + + VERSION + ", " + + NAME + ", " + + AVATAR + ", " + + ABOUT_EMOJI + ", " + + ABOUT + ", " + + PAYMENT_ADDRESS + ", " + + COMMITMENT + ") " + + "VALUES (:uuid, :version, :name, :avatar, :about_emoji, :about, :payment_address, :commitment) " + + "ON CONFLICT (" + UID + ", " + VERSION + ") " + + "DO UPDATE SET " + + NAME + " = EXCLUDED." + NAME + ", " + + AVATAR + " = EXCLUDED." + AVATAR + ", " + + ABOUT + " = EXCLUDED." + ABOUT + ", " + + ABOUT_EMOJI + " = EXCLUDED." + ABOUT_EMOJI + ", " + + PAYMENT_ADDRESS + " = EXCLUDED." + PAYMENT_ADDRESS) + .bind("uuid", uuid) + .bind("version", profile.getVersion()) + .bind("name", profile.getName()) + .bind("avatar", profile.getAvatar()) + .bind("about_emoji", profile.getAboutEmoji()) + .bind("about", profile.getAbout()) + .bind("payment_address", profile.getPaymentAddress()) + .bind("commitment", profile.getCommitment()) + .execute(); } })); } diff --git a/service/src/main/java/org/whispersystems/textsecuregcm/storage/VersionedProfile.java b/service/src/main/java/org/whispersystems/textsecuregcm/storage/VersionedProfile.java index 45ea02c70..368104e07 100644 --- a/service/src/main/java/org/whispersystems/textsecuregcm/storage/VersionedProfile.java +++ b/service/src/main/java/org/whispersystems/textsecuregcm/storage/VersionedProfile.java @@ -27,6 +27,9 @@ public class VersionedProfile { @JsonProperty private String about; + @JsonProperty + private String paymentAddress; + @JsonProperty @JsonSerialize(using = ByteArrayAdapter.Serializing.class) @JsonDeserialize(using = ByteArrayAdapter.Deserializing.class) @@ -34,12 +37,15 @@ public class VersionedProfile { public VersionedProfile() {} - public VersionedProfile(String version, String name, String avatar, String aboutEmoji, String about, byte[] commitment) { - this.version = version; - this.name = name; - this.avatar = avatar; + public VersionedProfile( + String version, String name, String avatar, String aboutEmoji, String about, String paymentAddress, + byte[] commitment) { + this.version = version; + this.name = name; + this.avatar = avatar; this.aboutEmoji = aboutEmoji; - this.about = about; + this.about = about; + this.paymentAddress = paymentAddress; this.commitment = commitment; } @@ -63,6 +69,10 @@ public class VersionedProfile { return about; } + public String getPaymentAddress() { + return paymentAddress; + } + public byte[] getCommitment() { return commitment; } diff --git a/service/src/main/java/org/whispersystems/textsecuregcm/storage/mappers/VersionedProfileMapper.java b/service/src/main/java/org/whispersystems/textsecuregcm/storage/mappers/VersionedProfileMapper.java index c7ca2b92a..53f740b96 100644 --- a/service/src/main/java/org/whispersystems/textsecuregcm/storage/mappers/VersionedProfileMapper.java +++ b/service/src/main/java/org/whispersystems/textsecuregcm/storage/mappers/VersionedProfileMapper.java @@ -5,23 +5,24 @@ package org.whispersystems.textsecuregcm.storage.mappers; +import java.sql.ResultSet; +import java.sql.SQLException; import org.jdbi.v3.core.mapper.RowMapper; import org.jdbi.v3.core.statement.StatementContext; import org.whispersystems.textsecuregcm.storage.Profiles; import org.whispersystems.textsecuregcm.storage.VersionedProfile; -import java.sql.ResultSet; -import java.sql.SQLException; - public class VersionedProfileMapper implements RowMapper { @Override public VersionedProfile map(ResultSet resultSet, StatementContext ctx) throws SQLException { - return new VersionedProfile(resultSet.getString(Profiles.VERSION), - resultSet.getString(Profiles.NAME), - resultSet.getString(Profiles.AVATAR), - resultSet.getString(Profiles.ABOUT_EMOJI), - resultSet.getString(Profiles.ABOUT), - resultSet.getBytes(Profiles.COMMITMENT)); + return new VersionedProfile( + resultSet.getString(Profiles.VERSION), + resultSet.getString(Profiles.NAME), + resultSet.getString(Profiles.AVATAR), + resultSet.getString(Profiles.ABOUT_EMOJI), + resultSet.getString(Profiles.ABOUT), + resultSet.getString(Profiles.PAYMENT_ADDRESS), + resultSet.getBytes(Profiles.COMMITMENT)); } } diff --git a/service/src/main/resources/accountsdb.xml b/service/src/main/resources/accountsdb.xml index f12dc151d..ccb76d5ae 100644 --- a/service/src/main/resources/accountsdb.xml +++ b/service/src/main/resources/accountsdb.xml @@ -359,4 +359,12 @@ + + + + + + + + diff --git a/service/src/test/java/org/whispersystems/textsecuregcm/tests/controllers/ProfileControllerTest.java b/service/src/test/java/org/whispersystems/textsecuregcm/tests/controllers/ProfileControllerTest.java index 7d9330958..cb6ff2220 100644 --- a/service/src/test/java/org/whispersystems/textsecuregcm/tests/controllers/ProfileControllerTest.java +++ b/service/src/test/java/org/whispersystems/textsecuregcm/tests/controllers/ProfileControllerTest.java @@ -128,7 +128,8 @@ public class ProfileControllerTest { when(accountsManager.get(argThat((ArgumentMatcher) identifier -> identifier != null && identifier.hasNumber() && identifier.getNumber().equals(AuthHelper.VALID_NUMBER)))).thenReturn(Optional.of(capabilitiesAccount)); when(profilesManager.get(eq(AuthHelper.VALID_UUID), eq("someversion"))).thenReturn(Optional.empty()); - when(profilesManager.get(eq(AuthHelper.VALID_UUID_TWO), eq("validversion"))).thenReturn(Optional.of(new VersionedProfile("validversion", "validname", "profiles/validavatar", "emoji", "about", "validcommitmnet".getBytes()))); + when(profilesManager.get(eq(AuthHelper.VALID_UUID_TWO), eq("validversion"))).thenReturn(Optional.of(new VersionedProfile("validversion", "validname", "profiles/validavatar", "emoji", "about", + null, "validcommitmnet".getBytes()))); clearInvocations(rateLimiter); clearInvocations(accountsManager); @@ -305,7 +306,8 @@ public class ProfileControllerTest { .target("/v1/profile/") .request() .header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_NUMBER, AuthHelper.VALID_PASSWORD)) - .put(Entity.entity(new CreateProfileRequest(commitment, "someversion", "123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678", null, null, true), MediaType.APPLICATION_JSON_TYPE), ProfileAvatarUploadAttributes.class); + .put(Entity.entity(new CreateProfileRequest(commitment, "someversion", "123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678", null, null, + null, true), MediaType.APPLICATION_JSON_TYPE), ProfileAvatarUploadAttributes.class); ArgumentCaptor profileArgumentCaptor = ArgumentCaptor.forClass(VersionedProfile.class); @@ -329,7 +331,8 @@ public class ProfileControllerTest { .target("/v1/profile/") .request() .header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_NUMBER, AuthHelper.VALID_PASSWORD)) - .put(Entity.entity(new CreateProfileRequest(commitment, "someversion", "1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890", null, null, true), MediaType.APPLICATION_JSON_TYPE)); + .put(Entity.entity(new CreateProfileRequest(commitment, "someversion", "1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890", null, null, + null, true), MediaType.APPLICATION_JSON_TYPE)); assertThat(response.getStatus()).isEqualTo(422); } @@ -344,7 +347,8 @@ public class ProfileControllerTest { .target("/v1/profile/") .request() .header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_NUMBER_TWO, AuthHelper.VALID_PASSWORD_TWO)) - .put(Entity.entity(new CreateProfileRequest(commitment, "anotherversion", "123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678", null, null, false), MediaType.APPLICATION_JSON_TYPE)); + .put(Entity.entity(new CreateProfileRequest(commitment, "anotherversion", "123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678", null, null, + null, false), MediaType.APPLICATION_JSON_TYPE)); assertThat(response.getStatus()).isEqualTo(200); assertThat(response.hasEntity()).isFalse(); @@ -374,7 +378,8 @@ public class ProfileControllerTest { .target("/v1/profile/") .request() .header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_NUMBER_TWO, AuthHelper.VALID_PASSWORD_TWO)) - .put(Entity.entity(new CreateProfileRequest(commitment, "validversion", "123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678", null, null, true), MediaType.APPLICATION_JSON_TYPE), ProfileAvatarUploadAttributes.class); + .put(Entity.entity(new CreateProfileRequest(commitment, "validversion", "123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678", null, null, + null, true), MediaType.APPLICATION_JSON_TYPE), ProfileAvatarUploadAttributes.class); ArgumentCaptor profileArgumentCaptor = ArgumentCaptor.forClass(VersionedProfile.class); @@ -399,7 +404,7 @@ public class ProfileControllerTest { .target("/v1/profile/") .request() .header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_NUMBER_TWO, AuthHelper.VALID_PASSWORD_TWO)) - .put(Entity.entity(new CreateProfileRequest(commitment, "validversion", name, null, null, true), MediaType.APPLICATION_JSON_TYPE), ProfileAvatarUploadAttributes.class); + .put(Entity.entity(new CreateProfileRequest(commitment, "validversion", name, null, null, null, true), MediaType.APPLICATION_JSON_TYPE), ProfileAvatarUploadAttributes.class); ArgumentCaptor profileArgumentCaptor = ArgumentCaptor.forClass(VersionedProfile.class); @@ -429,7 +434,7 @@ public class ProfileControllerTest { .target("/v1/profile/") .request() .header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_NUMBER_TWO, AuthHelper.VALID_PASSWORD_TWO)) - .put(Entity.entity(new CreateProfileRequest(commitment, "anotherversion", name, emoji, text, false), MediaType.APPLICATION_JSON_TYPE)); + .put(Entity.entity(new CreateProfileRequest(commitment, "anotherversion", name, emoji, text, null, false), MediaType.APPLICATION_JSON_TYPE)); assertThat(response.getStatus()).isEqualTo(200); assertThat(response.hasEntity()).isFalse(); @@ -444,12 +449,52 @@ public class ProfileControllerTest { verifyNoMoreInteractions(s3client); - assertThat(profileArgumentCaptor.getValue().getCommitment()).isEqualTo(commitment.serialize()); - assertThat(profileArgumentCaptor.getValue().getAvatar()).isNull(); - assertThat(profileArgumentCaptor.getValue().getVersion()).isEqualTo("anotherversion"); - assertThat(profileArgumentCaptor.getValue().getName()).isEqualTo(name); - assertThat(profileArgumentCaptor.getValue().getAboutEmoji()).isEqualTo(emoji); - assertThat(profileArgumentCaptor.getValue().getAbout()).isEqualTo(text); + final VersionedProfile profile = profileArgumentCaptor.getValue(); + assertThat(profile.getCommitment()).isEqualTo(commitment.serialize()); + assertThat(profile.getAvatar()).isNull(); + assertThat(profile.getVersion()).isEqualTo("anotherversion"); + assertThat(profile.getName()).isEqualTo(name); + assertThat(profile.getAboutEmoji()).isEqualTo(emoji); + assertThat(profile.getAbout()).isEqualTo(text); + assertThat(profile.getPaymentAddress()).isNull(); + } + + @Test + public void testSetProfilePaymentAddress() throws InvalidInputException { + ProfileKeyCommitment commitment = new ProfileKey(new byte[32]).getCommitment(AuthHelper.VALID_UUID); + + clearInvocations(AuthHelper.VALID_ACCOUNT_TWO); + + final String name = RandomStringUtils.randomAlphabetic(380); + final String paymentAddress = RandomStringUtils.randomAlphanumeric(684); + + Response response = resources.getJerseyTest() + .target("/v1/profile") + .request() + .header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_NUMBER_TWO, AuthHelper.VALID_PASSWORD_TWO)) + .put(Entity.entity(new CreateProfileRequest(commitment, "yetanotherversion", name, null, null, paymentAddress, false), MediaType.APPLICATION_JSON_TYPE)); + + assertThat(response.getStatus()).isEqualTo(200); + assertThat(response.hasEntity()).isFalse(); + + ArgumentCaptor profileArgumentCaptor = ArgumentCaptor.forClass(VersionedProfile.class); + + verify(profilesManager).get(eq(AuthHelper.VALID_UUID_TWO), eq("yetanotherversion")); + verify(profilesManager).set(eq(AuthHelper.VALID_UUID_TWO), profileArgumentCaptor.capture()); + + verify(AuthHelper.VALID_ACCOUNT_TWO).setProfileName(eq(name)); + verify(AuthHelper.VALID_ACCOUNT_TWO).setAvatar(null); + + verifyNoMoreInteractions(s3client); + + final VersionedProfile profile = profileArgumentCaptor.getValue(); + assertThat(profile.getCommitment()).isEqualTo(commitment.serialize()); + assertThat(profile.getAvatar()).isNull(); + assertThat(profile.getVersion()).isEqualTo("yetanotherversion"); + assertThat(profile.getName()).isEqualTo(name); + assertThat(profile.getAboutEmoji()).isNull(); + assertThat(profile.getAbout()).isNull(); + assertThat(profile.getPaymentAddress()).isEqualTo(paymentAddress); } @Test @@ -476,6 +521,4 @@ public class ProfileControllerTest { verify(rateLimiter, times(1)).validate(eq(AuthHelper.VALID_NUMBER)); } - - } diff --git a/service/src/test/java/org/whispersystems/textsecuregcm/tests/storage/ProfilesManagerTest.java b/service/src/test/java/org/whispersystems/textsecuregcm/tests/storage/ProfilesManagerTest.java index 25f8eef65..689662686 100644 --- a/service/src/test/java/org/whispersystems/textsecuregcm/tests/storage/ProfilesManagerTest.java +++ b/service/src/test/java/org/whispersystems/textsecuregcm/tests/storage/ProfilesManagerTest.java @@ -61,7 +61,8 @@ public class ProfilesManagerTest { Profiles profiles = mock(Profiles.class); UUID uuid = UUID.randomUUID(); - VersionedProfile profile = new VersionedProfile("someversion", "somename", "someavatar", null, null, "somecommitment".getBytes()); + VersionedProfile profile = new VersionedProfile("someversion", "somename", "someavatar", null, null, + null, "somecommitment".getBytes()); when(commands.hget(eq("profiles::" + uuid.toString()), eq("someversion"))).thenReturn(null); when(profiles.get(eq(uuid), eq("someversion"))).thenReturn(Optional.of(profile)); @@ -87,7 +88,8 @@ public class ProfilesManagerTest { Profiles profiles = mock(Profiles.class); UUID uuid = UUID.randomUUID(); - VersionedProfile profile = new VersionedProfile("someversion", "somename", "someavatar", null, null, "somecommitment".getBytes()); + VersionedProfile profile = new VersionedProfile("someversion", "somename", "someavatar", null, null, + null, "somecommitment".getBytes()); when(commands.hget(eq("profiles::" + uuid.toString()), eq("someversion"))).thenThrow(new RedisException("Connection lost")); when(profiles.get(eq(uuid), eq("someversion"))).thenReturn(Optional.of(profile)); diff --git a/service/src/test/java/org/whispersystems/textsecuregcm/tests/storage/ProfilesTest.java b/service/src/test/java/org/whispersystems/textsecuregcm/tests/storage/ProfilesTest.java index aab5dee63..c86f85510 100644 --- a/service/src/test/java/org/whispersystems/textsecuregcm/tests/storage/ProfilesTest.java +++ b/service/src/test/java/org/whispersystems/textsecuregcm/tests/storage/ProfilesTest.java @@ -41,7 +41,8 @@ public class ProfilesTest { @Test public void testSetGet() { UUID uuid = UUID.randomUUID(); - VersionedProfile profile = new VersionedProfile("123", "foo", "avatarLocation", "emoji", "the very model of a modern major general", "acommitment".getBytes()); + VersionedProfile profile = new VersionedProfile("123", "foo", "avatarLocation", "emoji", "the very model of a modern major general", + null, "acommitment".getBytes()); profiles.set(uuid, profile); Optional retrieved = profiles.get(uuid, "123"); @@ -57,7 +58,8 @@ public class ProfilesTest { @Test public void testSetGetNullOptionalFields() { UUID uuid = UUID.randomUUID(); - VersionedProfile profile = new VersionedProfile("123", "foo", null, null, null, "acommitment".getBytes()); + VersionedProfile profile = new VersionedProfile("123", "foo", null, null, null, null, + "acommitment".getBytes()); profiles.set(uuid, profile); Optional retrieved = profiles.get(uuid, "123"); @@ -73,7 +75,8 @@ public class ProfilesTest { @Test public void testSetReplace() { UUID uuid = UUID.randomUUID(); - VersionedProfile profile = new VersionedProfile("123", "foo", "avatarLocation", null, null, "acommitment".getBytes()); + VersionedProfile profile = new VersionedProfile("123", "foo", "avatarLocation", null, null, + null, "acommitment".getBytes()); profiles.set(uuid, profile); Optional retrieved = profiles.get(uuid, "123"); @@ -85,7 +88,8 @@ public class ProfilesTest { assertThat(retrieved.get().getAbout()).isNull(); assertThat(retrieved.get().getAboutEmoji()).isNull(); - VersionedProfile updated = new VersionedProfile("123", "bar", "baz", "emoji", "bio", "boof".getBytes()); + VersionedProfile updated = new VersionedProfile("123", "bar", "baz", "emoji", "bio", null, + "boof".getBytes()); profiles.set(uuid, updated); retrieved = profiles.get(uuid, "123"); @@ -103,8 +107,10 @@ public class ProfilesTest { @Test public void testMultipleVersions() { UUID uuid = UUID.randomUUID(); - VersionedProfile profileOne = new VersionedProfile("123", "foo", "avatarLocation", null, null, "acommitmnet".getBytes()); - VersionedProfile profileTwo = new VersionedProfile("345", "bar", "baz", "emoji", "i keep typing emoju for some reason", "boof".getBytes()); + VersionedProfile profileOne = new VersionedProfile("123", "foo", "avatarLocation", null, null, + null, "acommitmnet".getBytes()); + VersionedProfile profileTwo = new VersionedProfile("345", "bar", "baz", "emoji", "i keep typing emoju for some reason", + null, "boof".getBytes()); profiles.set(uuid, profileOne); profiles.set(uuid, profileTwo); @@ -131,7 +137,8 @@ public class ProfilesTest { @Test public void testMissing() { UUID uuid = UUID.randomUUID(); - VersionedProfile profile = new VersionedProfile("123", "foo", "avatarLocation", null, null, "aDigest".getBytes()); + VersionedProfile profile = new VersionedProfile("123", "foo", "avatarLocation", null, null, + null, "aDigest".getBytes()); profiles.set(uuid, profile); Optional retrieved = profiles.get(uuid, "888"); @@ -142,8 +149,9 @@ public class ProfilesTest { @Test public void testDelete() { UUID uuid = UUID.randomUUID(); - VersionedProfile profileOne = new VersionedProfile("123", "foo", "avatarLocation", null, null, "aDigest".getBytes()); - VersionedProfile profileTwo = new VersionedProfile("345", "bar", "baz", null, null, "boof".getBytes()); + VersionedProfile profileOne = new VersionedProfile("123", "foo", "avatarLocation", null, null, + null, "aDigest".getBytes()); + VersionedProfile profileTwo = new VersionedProfile("345", "bar", "baz", null, null, null, "boof".getBytes()); profiles.set(uuid, profileOne); profiles.set(uuid, profileTwo);