Add payment address to the versioned profile

This commit is contained in:
Ehren Kret 2021-02-12 17:33:26 -06:00
parent ae329e735f
commit 142376f360
10 changed files with 229 additions and 112 deletions

View File

@ -8,6 +8,24 @@ package org.whispersystems.textsecuregcm.controllers;
import com.amazonaws.services.s3.AmazonS3; import com.amazonaws.services.s3.AmazonS3;
import com.codahale.metrics.annotation.Timed; import com.codahale.metrics.annotation.Timed;
import io.dropwizard.auth.Auth; 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.DecoderException;
import org.apache.commons.codec.binary.Base64; import org.apache.commons.codec.binary.Base64;
import org.apache.commons.codec.binary.Hex; 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.ExactlySize;
import org.whispersystems.textsecuregcm.util.Pair; 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") @SuppressWarnings("OptionalUsedAsFieldOrParameterType")
@Path("/v1/profile") @Path("/v1/profile")
public class ProfileController { public class ProfileController {
@ -110,7 +109,15 @@ public class ProfileController {
String avatar = request.isAvatar() ? generateAvatarObjectName() : null; String avatar = request.isAvatar() ? generateAvatarObjectName() : null;
Optional<ProfileAvatarUploadAttributes> response = Optional.empty(); Optional<ProfileAvatarUploadAttributes> 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()) { if (request.isAvatar()) {
Optional<String> currentAvatar = Optional.empty(); Optional<String> currentAvatar = Optional.empty();
@ -195,6 +202,7 @@ public class ProfileController {
String about = profile.map(VersionedProfile::getAbout).orElse(null); String about = profile.map(VersionedProfile::getAbout).orElse(null);
String aboutEmoji = profile.map(VersionedProfile::getAboutEmoji).orElse(null); String aboutEmoji = profile.map(VersionedProfile::getAboutEmoji).orElse(null);
String avatar = profile.map(VersionedProfile::getAvatar).orElse(accountProfile.get().getAvatar()); String avatar = profile.map(VersionedProfile::getAvatar).orElse(accountProfile.get().getAvatar());
String paymentAddress = profile.map(VersionedProfile::getPaymentAddress).orElse(null);
Optional<ProfileKeyCredentialResponse> credential = getProfileCredential(credentialRequest, profile, uuid); Optional<ProfileKeyCredentialResponse> credential = getProfileCredential(credentialRequest, profile, uuid);
@ -202,6 +210,7 @@ public class ProfileController {
about, about,
aboutEmoji, aboutEmoji,
avatar, avatar,
paymentAddress,
accountProfile.get().getIdentityKey(), accountProfile.get().getIdentityKey(),
UnidentifiedAccessChecksum.generateFor(accountProfile.get().getUnidentifiedAccessKey()), UnidentifiedAccessChecksum.generateFor(accountProfile.get().getUnidentifiedAccessKey()),
accountProfile.get().isUnrestrictedUnidentifiedAccess(), accountProfile.get().isUnrestrictedUnidentifiedAccess(),
@ -242,6 +251,7 @@ public class ProfileController {
null, null,
null, null,
accountProfile.get().getAvatar(), accountProfile.get().getAvatar(),
null,
accountProfile.get().getIdentityKey(), accountProfile.get().getIdentityKey(),
UnidentifiedAccessChecksum.generateFor(accountProfile.get().getUnidentifiedAccessKey()), UnidentifiedAccessChecksum.generateFor(accountProfile.get().getUnidentifiedAccessKey()),
accountProfile.get().isUnrestrictedUnidentifiedAccess(), accountProfile.get().isUnrestrictedUnidentifiedAccess(),
@ -317,6 +327,7 @@ public class ProfileController {
null, null,
null, null,
accountProfile.get().getAvatar(), accountProfile.get().getAvatar(),
null,
accountProfile.get().getIdentityKey(), accountProfile.get().getIdentityKey(),
UnidentifiedAccessChecksum.generateFor(accountProfile.get().getUnidentifiedAccessKey()), UnidentifiedAccessChecksum.generateFor(accountProfile.get().getUnidentifiedAccessKey()),
accountProfile.get().isUnrestrictedUnidentifiedAccess(), accountProfile.get().isUnrestrictedUnidentifiedAccess(),

View File

@ -35,6 +35,10 @@ public class CreateProfileRequest {
@ExactlySize({0, 208, 376, 720}) @ExactlySize({0, 208, 376, 720})
private String about; private String about;
@JsonProperty
@ExactlySize({0, 684})
private String paymentAddress;
@JsonProperty @JsonProperty
@NotNull @NotNull
@JsonDeserialize(using = ProfileKeyCommitmentAdapter.Deserializing.class) @JsonDeserialize(using = ProfileKeyCommitmentAdapter.Deserializing.class)
@ -43,12 +47,15 @@ public class CreateProfileRequest {
public 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.commitment = commitment;
this.version = version; this.version = version;
this.name = name; this.name = name;
this.aboutEmoji = aboutEmoji; this.aboutEmoji = aboutEmoji;
this.about = about; this.about = about;
this.paymentAddress = paymentAddress;
this.avatar = wantsAvatar; this.avatar = wantsAvatar;
} }
@ -75,4 +82,8 @@ public class CreateProfileRequest {
public String getAbout() { public String getAbout() {
return StringUtils.stripToNull(about); return StringUtils.stripToNull(about);
} }
public String getPaymentAddress() {
return paymentAddress;
}
} }

View File

@ -9,12 +9,10 @@ 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 com.google.common.annotations.VisibleForTesting;
import org.signal.zkgroup.profiles.ProfileKeyCredentialResponse;
import org.whispersystems.textsecuregcm.storage.PaymentAddress;
import java.util.List; import java.util.List;
import java.util.UUID; import java.util.UUID;
import org.signal.zkgroup.profiles.ProfileKeyCredentialResponse;
import org.whispersystems.textsecuregcm.storage.PaymentAddress;
public class Profile { public class Profile {
@ -33,6 +31,9 @@ public class Profile {
@JsonProperty @JsonProperty
private String avatar; private String avatar;
@JsonProperty
private String paymentAddress;
@JsonProperty @JsonProperty
private String unidentifiedAccess; private String unidentifiedAccess;
@ -58,16 +59,16 @@ public class Profile {
public Profile() {} public Profile() {}
public Profile(String name, String about, String aboutEmoji, String avatar, String identityKey, public Profile(
String unidentifiedAccess, boolean unrestrictedUnidentifiedAccess, String name, String about, String aboutEmoji, String avatar, String paymentAddress, String identityKey,
UserCapabilities capabilities, String username, UUID uuid, String unidentifiedAccess, boolean unrestrictedUnidentifiedAccess, UserCapabilities capabilities, String username,
ProfileKeyCredentialResponse credential, UUID uuid, ProfileKeyCredentialResponse credential, List<PaymentAddress> payments)
List<PaymentAddress> payments)
{ {
this.name = name; this.name = name;
this.about = about; this.about = about;
this.aboutEmoji = aboutEmoji; this.aboutEmoji = aboutEmoji;
this.avatar = avatar; this.avatar = avatar;
this.paymentAddress = paymentAddress;
this.identityKey = identityKey; this.identityKey = identityKey;
this.unidentifiedAccess = unidentifiedAccess; this.unidentifiedAccess = unidentifiedAccess;
this.unrestrictedUnidentifiedAccess = unrestrictedUnidentifiedAccess; this.unrestrictedUnidentifiedAccess = unrestrictedUnidentifiedAccess;
@ -101,6 +102,10 @@ public class Profile {
return avatar; return avatar;
} }
public String getPaymentAddress() {
return paymentAddress;
}
@VisibleForTesting @VisibleForTesting
public String getUnidentifiedAccess() { public String getUnidentifiedAccess() {
return unidentifiedAccess; return unidentifiedAccess;

View File

@ -5,16 +5,15 @@
package org.whispersystems.textsecuregcm.storage; package org.whispersystems.textsecuregcm.storage;
import static com.codahale.metrics.MetricRegistry.name;
import com.codahale.metrics.MetricRegistry; import com.codahale.metrics.MetricRegistry;
import com.codahale.metrics.SharedMetricRegistries; import com.codahale.metrics.SharedMetricRegistries;
import com.codahale.metrics.Timer; import com.codahale.metrics.Timer;
import org.whispersystems.textsecuregcm.storage.mappers.VersionedProfileMapper;
import org.whispersystems.textsecuregcm.util.Constants;
import java.util.Optional; import java.util.Optional;
import java.util.UUID; import java.util.UUID;
import org.whispersystems.textsecuregcm.storage.mappers.VersionedProfileMapper;
import static com.codahale.metrics.MetricRegistry.name; import org.whispersystems.textsecuregcm.util.Constants;
public class Profiles { public class Profiles {
@ -25,6 +24,7 @@ public class Profiles {
public static final String AVATAR = "avatar"; public static final String AVATAR = "avatar";
public static final String ABOUT_EMOJI = "about_emoji"; public static final String ABOUT_EMOJI = "about_emoji";
public static final String ABOUT = "about"; public static final String ABOUT = "about";
public static final String PAYMENT_ADDRESS = "payment_address";
public static final String COMMITMENT = "commitment"; public static final String COMMITMENT = "commitment";
private final MetricRegistry metricRegistry = SharedMetricRegistries.getOrCreate(Constants.METRICS_NAME); private final MetricRegistry metricRegistry = SharedMetricRegistries.getOrCreate(Constants.METRICS_NAME);
@ -43,13 +43,31 @@ public class Profiles {
public void set(UUID uuid, VersionedProfile profile) { public void set(UUID uuid, VersionedProfile profile) {
database.use(jdbi -> jdbi.useHandle(handle -> { database.use(jdbi -> jdbi.useHandle(handle -> {
try (Timer.Context ignored = setTimer.time()) { 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) 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("uuid", uuid)
.bind("version", profile.getVersion()) .bind("version", profile.getVersion())
.bind("name", profile.getName()) .bind("name", profile.getName())
.bind("avatar", profile.getAvatar()) .bind("avatar", profile.getAvatar())
.bind("about_emoji", profile.getAboutEmoji()) .bind("about_emoji", profile.getAboutEmoji())
.bind("about", profile.getAbout()) .bind("about", profile.getAbout())
.bind("payment_address", profile.getPaymentAddress())
.bind("commitment", profile.getCommitment()) .bind("commitment", profile.getCommitment())
.execute(); .execute();
} }

View File

@ -27,6 +27,9 @@ public class VersionedProfile {
@JsonProperty @JsonProperty
private String about; private String about;
@JsonProperty
private String paymentAddress;
@JsonProperty @JsonProperty
@JsonSerialize(using = ByteArrayAdapter.Serializing.class) @JsonSerialize(using = ByteArrayAdapter.Serializing.class)
@JsonDeserialize(using = ByteArrayAdapter.Deserializing.class) @JsonDeserialize(using = ByteArrayAdapter.Deserializing.class)
@ -34,12 +37,15 @@ public class VersionedProfile {
public VersionedProfile() {} public VersionedProfile() {}
public VersionedProfile(String version, String name, String avatar, String aboutEmoji, String about, byte[] commitment) { public VersionedProfile(
String version, String name, String avatar, String aboutEmoji, String about, String paymentAddress,
byte[] commitment) {
this.version = version; this.version = version;
this.name = name; this.name = name;
this.avatar = avatar; this.avatar = avatar;
this.aboutEmoji = aboutEmoji; this.aboutEmoji = aboutEmoji;
this.about = about; this.about = about;
this.paymentAddress = paymentAddress;
this.commitment = commitment; this.commitment = commitment;
} }
@ -63,6 +69,10 @@ public class VersionedProfile {
return about; return about;
} }
public String getPaymentAddress() {
return paymentAddress;
}
public byte[] getCommitment() { public byte[] getCommitment() {
return commitment; return commitment;
} }

View File

@ -5,23 +5,24 @@
package org.whispersystems.textsecuregcm.storage.mappers; 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.mapper.RowMapper;
import org.jdbi.v3.core.statement.StatementContext; import org.jdbi.v3.core.statement.StatementContext;
import org.whispersystems.textsecuregcm.storage.Profiles; import org.whispersystems.textsecuregcm.storage.Profiles;
import org.whispersystems.textsecuregcm.storage.VersionedProfile; import org.whispersystems.textsecuregcm.storage.VersionedProfile;
import java.sql.ResultSet;
import java.sql.SQLException;
public class VersionedProfileMapper implements RowMapper<VersionedProfile> { public class VersionedProfileMapper implements RowMapper<VersionedProfile> {
@Override @Override
public VersionedProfile map(ResultSet resultSet, StatementContext ctx) throws SQLException { public VersionedProfile map(ResultSet resultSet, StatementContext ctx) throws SQLException {
return new VersionedProfile(resultSet.getString(Profiles.VERSION), return new VersionedProfile(
resultSet.getString(Profiles.VERSION),
resultSet.getString(Profiles.NAME), resultSet.getString(Profiles.NAME),
resultSet.getString(Profiles.AVATAR), resultSet.getString(Profiles.AVATAR),
resultSet.getString(Profiles.ABOUT_EMOJI), resultSet.getString(Profiles.ABOUT_EMOJI),
resultSet.getString(Profiles.ABOUT), resultSet.getString(Profiles.ABOUT),
resultSet.getString(Profiles.PAYMENT_ADDRESS),
resultSet.getBytes(Profiles.COMMITMENT)); resultSet.getBytes(Profiles.COMMITMENT));
} }
} }

View File

@ -359,4 +359,12 @@
<dropTable tableName="feature_flags" /> <dropTable tableName="feature_flags" />
</changeSet> </changeSet>
<changeSet id="23" author="ehren">
<addColumn tableName="profiles">
<column name="payment_address" type="text">
<constraints nullable="true"/>
</column>
</addColumn>
</changeSet>
</databaseChangeLog> </databaseChangeLog>

View File

@ -128,7 +128,8 @@ public class ProfileControllerTest {
when(accountsManager.get(argThat((ArgumentMatcher<AmbiguousIdentifier>) identifier -> identifier != null && identifier.hasNumber() && identifier.getNumber().equals(AuthHelper.VALID_NUMBER)))).thenReturn(Optional.of(capabilitiesAccount)); when(accountsManager.get(argThat((ArgumentMatcher<AmbiguousIdentifier>) 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), 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(rateLimiter);
clearInvocations(accountsManager); clearInvocations(accountsManager);
@ -305,7 +306,8 @@ public class ProfileControllerTest {
.target("/v1/profile/") .target("/v1/profile/")
.request() .request()
.header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_NUMBER, AuthHelper.VALID_PASSWORD)) .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<VersionedProfile> profileArgumentCaptor = ArgumentCaptor.forClass(VersionedProfile.class); ArgumentCaptor<VersionedProfile> profileArgumentCaptor = ArgumentCaptor.forClass(VersionedProfile.class);
@ -329,7 +331,8 @@ public class ProfileControllerTest {
.target("/v1/profile/") .target("/v1/profile/")
.request() .request()
.header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_NUMBER, AuthHelper.VALID_PASSWORD)) .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); assertThat(response.getStatus()).isEqualTo(422);
} }
@ -344,7 +347,8 @@ public class ProfileControllerTest {
.target("/v1/profile/") .target("/v1/profile/")
.request() .request()
.header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_NUMBER_TWO, AuthHelper.VALID_PASSWORD_TWO)) .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.getStatus()).isEqualTo(200);
assertThat(response.hasEntity()).isFalse(); assertThat(response.hasEntity()).isFalse();
@ -374,7 +378,8 @@ public class ProfileControllerTest {
.target("/v1/profile/") .target("/v1/profile/")
.request() .request()
.header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_NUMBER_TWO, AuthHelper.VALID_PASSWORD_TWO)) .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<VersionedProfile> profileArgumentCaptor = ArgumentCaptor.forClass(VersionedProfile.class); ArgumentCaptor<VersionedProfile> profileArgumentCaptor = ArgumentCaptor.forClass(VersionedProfile.class);
@ -399,7 +404,7 @@ public class ProfileControllerTest {
.target("/v1/profile/") .target("/v1/profile/")
.request() .request()
.header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_NUMBER_TWO, AuthHelper.VALID_PASSWORD_TWO)) .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<VersionedProfile> profileArgumentCaptor = ArgumentCaptor.forClass(VersionedProfile.class); ArgumentCaptor<VersionedProfile> profileArgumentCaptor = ArgumentCaptor.forClass(VersionedProfile.class);
@ -429,7 +434,7 @@ public class ProfileControllerTest {
.target("/v1/profile/") .target("/v1/profile/")
.request() .request()
.header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_NUMBER_TWO, AuthHelper.VALID_PASSWORD_TWO)) .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.getStatus()).isEqualTo(200);
assertThat(response.hasEntity()).isFalse(); assertThat(response.hasEntity()).isFalse();
@ -444,12 +449,52 @@ public class ProfileControllerTest {
verifyNoMoreInteractions(s3client); verifyNoMoreInteractions(s3client);
assertThat(profileArgumentCaptor.getValue().getCommitment()).isEqualTo(commitment.serialize()); final VersionedProfile profile = profileArgumentCaptor.getValue();
assertThat(profileArgumentCaptor.getValue().getAvatar()).isNull(); assertThat(profile.getCommitment()).isEqualTo(commitment.serialize());
assertThat(profileArgumentCaptor.getValue().getVersion()).isEqualTo("anotherversion"); assertThat(profile.getAvatar()).isNull();
assertThat(profileArgumentCaptor.getValue().getName()).isEqualTo(name); assertThat(profile.getVersion()).isEqualTo("anotherversion");
assertThat(profileArgumentCaptor.getValue().getAboutEmoji()).isEqualTo(emoji); assertThat(profile.getName()).isEqualTo(name);
assertThat(profileArgumentCaptor.getValue().getAbout()).isEqualTo(text); 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<VersionedProfile> 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 @Test
@ -476,6 +521,4 @@ public class ProfileControllerTest {
verify(rateLimiter, times(1)).validate(eq(AuthHelper.VALID_NUMBER)); verify(rateLimiter, times(1)).validate(eq(AuthHelper.VALID_NUMBER));
} }
} }

View File

@ -61,7 +61,8 @@ public class ProfilesManagerTest {
Profiles profiles = mock(Profiles.class); Profiles profiles = mock(Profiles.class);
UUID uuid = UUID.randomUUID(); 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(commands.hget(eq("profiles::" + uuid.toString()), eq("someversion"))).thenReturn(null);
when(profiles.get(eq(uuid), eq("someversion"))).thenReturn(Optional.of(profile)); when(profiles.get(eq(uuid), eq("someversion"))).thenReturn(Optional.of(profile));
@ -87,7 +88,8 @@ public class ProfilesManagerTest {
Profiles profiles = mock(Profiles.class); Profiles profiles = mock(Profiles.class);
UUID uuid = UUID.randomUUID(); 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(commands.hget(eq("profiles::" + uuid.toString()), eq("someversion"))).thenThrow(new RedisException("Connection lost"));
when(profiles.get(eq(uuid), eq("someversion"))).thenReturn(Optional.of(profile)); when(profiles.get(eq(uuid), eq("someversion"))).thenReturn(Optional.of(profile));

View File

@ -41,7 +41,8 @@ public class ProfilesTest {
@Test @Test
public void testSetGet() { public void testSetGet() {
UUID uuid = UUID.randomUUID(); 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); profiles.set(uuid, profile);
Optional<VersionedProfile> retrieved = profiles.get(uuid, "123"); Optional<VersionedProfile> retrieved = profiles.get(uuid, "123");
@ -57,7 +58,8 @@ public class ProfilesTest {
@Test @Test
public void testSetGetNullOptionalFields() { public void testSetGetNullOptionalFields() {
UUID uuid = UUID.randomUUID(); 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); profiles.set(uuid, profile);
Optional<VersionedProfile> retrieved = profiles.get(uuid, "123"); Optional<VersionedProfile> retrieved = profiles.get(uuid, "123");
@ -73,7 +75,8 @@ public class ProfilesTest {
@Test @Test
public void testSetReplace() { public void testSetReplace() {
UUID uuid = UUID.randomUUID(); 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); profiles.set(uuid, profile);
Optional<VersionedProfile> retrieved = profiles.get(uuid, "123"); Optional<VersionedProfile> retrieved = profiles.get(uuid, "123");
@ -85,7 +88,8 @@ public class ProfilesTest {
assertThat(retrieved.get().getAbout()).isNull(); assertThat(retrieved.get().getAbout()).isNull();
assertThat(retrieved.get().getAboutEmoji()).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); profiles.set(uuid, updated);
retrieved = profiles.get(uuid, "123"); retrieved = profiles.get(uuid, "123");
@ -103,8 +107,10 @@ public class ProfilesTest {
@Test @Test
public void testMultipleVersions() { public void testMultipleVersions() {
UUID uuid = UUID.randomUUID(); UUID uuid = UUID.randomUUID();
VersionedProfile profileOne = new VersionedProfile("123", "foo", "avatarLocation", null, null, "acommitmnet".getBytes()); VersionedProfile profileOne = new VersionedProfile("123", "foo", "avatarLocation", null, null,
VersionedProfile profileTwo = new VersionedProfile("345", "bar", "baz", "emoji", "i keep typing emoju for some reason", "boof".getBytes()); 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, profileOne);
profiles.set(uuid, profileTwo); profiles.set(uuid, profileTwo);
@ -131,7 +137,8 @@ public class ProfilesTest {
@Test @Test
public void testMissing() { public void testMissing() {
UUID uuid = UUID.randomUUID(); 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); profiles.set(uuid, profile);
Optional<VersionedProfile> retrieved = profiles.get(uuid, "888"); Optional<VersionedProfile> retrieved = profiles.get(uuid, "888");
@ -142,8 +149,9 @@ public class ProfilesTest {
@Test @Test
public void testDelete() { public void testDelete() {
UUID uuid = UUID.randomUUID(); UUID uuid = UUID.randomUUID();
VersionedProfile profileOne = new VersionedProfile("123", "foo", "avatarLocation", null, null, "aDigest".getBytes()); VersionedProfile profileOne = new VersionedProfile("123", "foo", "avatarLocation", null, null,
VersionedProfile profileTwo = new VersionedProfile("345", "bar", "baz", null, null, "boof".getBytes()); null, "aDigest".getBytes());
VersionedProfile profileTwo = new VersionedProfile("345", "bar", "baz", null, null, null, "boof".getBytes());
profiles.set(uuid, profileOne); profiles.set(uuid, profileOne);
profiles.set(uuid, profileTwo); profiles.set(uuid, profileTwo);