0
0
mirror of https://github.com/signalapp/Signal-Server.git synced 2024-09-20 12:02:18 +02:00

Add emojis/"about" text to profiles

This commit is contained in:
Jon Chambers 2021-01-20 15:42:47 -05:00 committed by GitHub
parent 6b850b9894
commit 225932b4c9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 163 additions and 29 deletions

View File

@ -110,7 +110,7 @@ public class ProfileController {
String avatar = request.isAvatar() ? generateAvatarObjectName() : null;
Optional<ProfileAvatarUploadAttributes> response = Optional.empty();
profilesManager.set(account.getUuid(), new VersionedProfile(request.getVersion(), request.getName(), avatar, request.getCommitment().serialize()));
profilesManager.set(account.getUuid(), new VersionedProfile(request.getVersion(), request.getName(), avatar, request.getAboutEmoji(), request.getAbout(), request.getCommitment().serialize()));
if (request.isAvatar()) {
Optional<String> currentAvatar = Optional.empty();
@ -193,11 +193,15 @@ public class ProfileController {
Optional<VersionedProfile> 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());
Optional<ProfileKeyCredentialResponse> credential = getProfileCredential(credentialRequest, profile, uuid);
return Optional.of(new Profile(name,
about,
aboutEmoji,
avatar,
accountProfile.get().getIdentityKey(),
UnidentifiedAccessChecksum.generateFor(accountProfile.get().getUnidentifiedAccessKey()),
@ -236,6 +240,8 @@ public class ProfileController {
}
return new Profile(accountProfile.get().getProfileName(),
null,
null,
accountProfile.get().getAvatar(),
accountProfile.get().getIdentityKey(),
UnidentifiedAccessChecksum.generateFor(accountProfile.get().getUnidentifiedAccessKey()),
@ -309,6 +315,8 @@ public class ProfileController {
}
return new Profile(accountProfile.get().getProfileName(),
null,
null,
accountProfile.get().getAvatar(),
accountProfile.get().getIdentityKey(),
UnidentifiedAccessChecksum.generateFor(accountProfile.get().getUnidentifiedAccessKey()),

View File

@ -8,6 +8,7 @@ package org.whispersystems.textsecuregcm.entities;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import org.apache.commons.lang3.StringUtils;
import org.hibernate.validator.constraints.NotEmpty;
import org.signal.zkgroup.profiles.ProfileKeyCommitment;
import org.whispersystems.textsecuregcm.util.ExactlySize;
@ -27,6 +28,14 @@ public class CreateProfileRequest {
@JsonProperty
private boolean avatar;
@JsonProperty
@ExactlySize({0, 80})
private String aboutEmoji;
@JsonProperty
@ExactlySize({0, 208, 376, 720})
private String about;
@JsonProperty
@NotNull
@JsonDeserialize(using = ProfileKeyCommitmentAdapter.Deserializing.class)
@ -35,10 +44,12 @@ public class CreateProfileRequest {
public CreateProfileRequest() {}
public CreateProfileRequest(ProfileKeyCommitment commitment, String version, String name, boolean wantsAvatar) {
public CreateProfileRequest(ProfileKeyCommitment commitment, String version, String name, String aboutEmoji, String about, boolean wantsAvatar) {
this.commitment = commitment;
this.version = version;
this.name = name;
this.aboutEmoji = aboutEmoji;
this.about = about;
this.avatar = wantsAvatar;
}
@ -57,4 +68,12 @@ public class CreateProfileRequest {
public boolean isAvatar() {
return avatar;
}
public String getAboutEmoji() {
return StringUtils.stripToNull(aboutEmoji);
}
public String getAbout() {
return StringUtils.stripToNull(about);
}
}

View File

@ -24,6 +24,12 @@ public class Profile {
@JsonProperty
private String name;
@JsonProperty
private String about;
@JsonProperty
private String aboutEmoji;
@JsonProperty
private String avatar;
@ -52,13 +58,15 @@ public class Profile {
public Profile() {}
public Profile(String name, String avatar, String identityKey,
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<PaymentAddress> payments)
{
this.name = name;
this.about = about;
this.aboutEmoji = aboutEmoji;
this.avatar = avatar;
this.identityKey = identityKey;
this.unidentifiedAccess = unidentifiedAccess;
@ -80,6 +88,14 @@ public class Profile {
return name;
}
public String getAbout() {
return about;
}
public String getAboutEmoji() {
return aboutEmoji;
}
@VisibleForTesting
public String getAvatar() {
return avatar;

View File

@ -23,6 +23,8 @@ public class Profiles {
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";
private final MetricRegistry metricRegistry = SharedMetricRegistries.getOrCreate(Constants.METRICS_NAME);
@ -46,6 +48,8 @@ public class Profiles {
.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();
}

View File

@ -8,7 +8,6 @@ package org.whispersystems.textsecuregcm.storage;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import org.whispersystems.textsecuregcm.entities.DeliveryCertificate;
import org.whispersystems.textsecuregcm.util.ByteArrayAdapter;
public class VersionedProfile {
@ -22,6 +21,12 @@ public class VersionedProfile {
@JsonProperty
private String avatar;
@JsonProperty
private String aboutEmoji;
@JsonProperty
private String about;
@JsonProperty
@JsonSerialize(using = ByteArrayAdapter.Serializing.class)
@JsonDeserialize(using = ByteArrayAdapter.Deserializing.class)
@ -29,10 +34,12 @@ public class VersionedProfile {
public VersionedProfile() {}
public VersionedProfile(String version, String name, String avatar, byte[] commitment) {
public VersionedProfile(String version, String name, String avatar, String aboutEmoji, String about, byte[] commitment) {
this.version = version;
this.name = name;
this.avatar = avatar;
this.aboutEmoji = aboutEmoji;
this.about = about;
this.commitment = commitment;
}
@ -48,6 +55,14 @@ public class VersionedProfile {
return avatar;
}
public String getAboutEmoji() {
return aboutEmoji;
}
public String getAbout() {
return about;
}
public byte[] getCommitment() {
return commitment;
}

View File

@ -20,6 +20,8 @@ public class VersionedProfileMapper implements RowMapper<VersionedProfile> {
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));
}
}

View File

@ -339,4 +339,16 @@
</createTable>
</changeSet>
<changeSet id="20" author="jon">
<addColumn tableName="profiles">
<column name="about" type="text">
<constraints nullable="true"/>
</column>
<column name="about_emoji" type="text">
<constraints nullable="true"/>
</column>
</addColumn>
</changeSet>
</databaseChangeLog>

View File

@ -129,7 +129,7 @@ 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(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", "validcommitmnet".getBytes())));
when(profilesManager.get(eq(AuthHelper.VALID_UUID_TWO), eq("validversion"))).thenReturn(Optional.of(new VersionedProfile("validversion", "validname", "profiles/validavatar", "emoji", "about", "validcommitmnet".getBytes())));
clearInvocations(rateLimiter);
clearInvocations(accountsManager);
@ -306,7 +306,7 @@ 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", true), MediaType.APPLICATION_JSON_TYPE), ProfileAvatarUploadAttributes.class);
.put(Entity.entity(new CreateProfileRequest(commitment, "someversion", "123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678", null, null, true), MediaType.APPLICATION_JSON_TYPE), ProfileAvatarUploadAttributes.class);
ArgumentCaptor<VersionedProfile> profileArgumentCaptor = ArgumentCaptor.forClass(VersionedProfile.class);
@ -319,7 +319,8 @@ public class ProfileControllerTest {
assertThat(profileArgumentCaptor.getValue().getAvatar()).isEqualTo(uploadAttributes.getKey());
assertThat(profileArgumentCaptor.getValue().getVersion()).isEqualTo("someversion");
assertThat(profileArgumentCaptor.getValue().getName()).isEqualTo("123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678");
}
assertThat(profileArgumentCaptor.getValue().getAboutEmoji()).isNull();
assertThat(profileArgumentCaptor.getValue().getAbout()).isNull(); }
@Test
public void testSetProfileWantAvatarUploadWithBadProfileSize() throws InvalidInputException {
@ -329,7 +330,7 @@ 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", true), MediaType.APPLICATION_JSON_TYPE));
.put(Entity.entity(new CreateProfileRequest(commitment, "someversion", "1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890", null, null, true), MediaType.APPLICATION_JSON_TYPE));
assertThat(response.getStatus()).isEqualTo(422);
}
@ -344,7 +345,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", "123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678", false), MediaType.APPLICATION_JSON_TYPE));
.put(Entity.entity(new CreateProfileRequest(commitment, "anotherversion", "123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678", null, null, false), MediaType.APPLICATION_JSON_TYPE));
assertThat(response.getStatus()).isEqualTo(200);
assertThat(response.hasEntity()).isFalse();
@ -363,17 +364,18 @@ public class ProfileControllerTest {
assertThat(profileArgumentCaptor.getValue().getAvatar()).isNull();
assertThat(profileArgumentCaptor.getValue().getVersion()).isEqualTo("anotherversion");
assertThat(profileArgumentCaptor.getValue().getName()).isEqualTo("123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678");
}
assertThat(profileArgumentCaptor.getValue().getAboutEmoji()).isNull();
assertThat(profileArgumentCaptor.getValue().getAbout()).isNull(); }
@Test
public void testSetProvfileWithAvatarUploadAndPreviousAvatar() throws InvalidInputException {
public void testSetProfileWithAvatarUploadAndPreviousAvatar() throws InvalidInputException {
ProfileKeyCommitment commitment = new ProfileKey(new byte[32]).getCommitment(AuthHelper.VALID_UUID_TWO);
ProfileAvatarUploadAttributes uploadAttributes= resources.getJerseyTest()
.target("/v1/profile/")
.request()
.header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_NUMBER_TWO, AuthHelper.VALID_PASSWORD_TWO))
.put(Entity.entity(new CreateProfileRequest(commitment, "validversion", "123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678", true), MediaType.APPLICATION_JSON_TYPE), ProfileAvatarUploadAttributes.class);
.put(Entity.entity(new CreateProfileRequest(commitment, "validversion", "123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678", null, null, true), MediaType.APPLICATION_JSON_TYPE), ProfileAvatarUploadAttributes.class);
ArgumentCaptor<VersionedProfile> profileArgumentCaptor = ArgumentCaptor.forClass(VersionedProfile.class);
@ -385,7 +387,8 @@ public class ProfileControllerTest {
assertThat(profileArgumentCaptor.getValue().getAvatar()).startsWith("profiles/");
assertThat(profileArgumentCaptor.getValue().getVersion()).isEqualTo("validversion");
assertThat(profileArgumentCaptor.getValue().getName()).isEqualTo("123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678");
}
assertThat(profileArgumentCaptor.getValue().getAboutEmoji()).isNull();
assertThat(profileArgumentCaptor.getValue().getAbout()).isNull(); }
@Test
public void testSetProfileExtendedName() throws InvalidInputException {
@ -397,7 +400,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, true), MediaType.APPLICATION_JSON_TYPE), ProfileAvatarUploadAttributes.class);
.put(Entity.entity(new CreateProfileRequest(commitment, "validversion", name, null, null, true), MediaType.APPLICATION_JSON_TYPE), ProfileAvatarUploadAttributes.class);
ArgumentCaptor<VersionedProfile> profileArgumentCaptor = ArgumentCaptor.forClass(VersionedProfile.class);
@ -409,6 +412,45 @@ public class ProfileControllerTest {
assertThat(profileArgumentCaptor.getValue().getAvatar()).startsWith("profiles/");
assertThat(profileArgumentCaptor.getValue().getVersion()).isEqualTo("validversion");
assertThat(profileArgumentCaptor.getValue().getName()).isEqualTo(name);
assertThat(profileArgumentCaptor.getValue().getAboutEmoji()).isNull();
assertThat(profileArgumentCaptor.getValue().getAbout()).isNull();
}
@Test
public void testSetProfileEmojiAndBioText() 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 emoji = RandomStringUtils.randomAlphanumeric(80);
final String text = RandomStringUtils.randomAlphanumeric(720);
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, "anotherversion", name, emoji, text, false), MediaType.APPLICATION_JSON_TYPE));
assertThat(response.getStatus()).isEqualTo(200);
assertThat(response.hasEntity()).isFalse();
ArgumentCaptor<VersionedProfile> profileArgumentCaptor = ArgumentCaptor.forClass(VersionedProfile.class);
verify(profilesManager, times(1)).get(eq(AuthHelper.VALID_UUID_TWO), eq("anotherversion"));
verify(profilesManager, times(1)).set(eq(AuthHelper.VALID_UUID_TWO), profileArgumentCaptor.capture());
verify(AuthHelper.VALID_ACCOUNT_TWO).setProfileName(name);
verify(AuthHelper.VALID_ACCOUNT_TWO).setAvatar(null);
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);
}
@Test
@ -421,6 +463,8 @@ public class ProfileControllerTest {
assertThat(profile.getIdentityKey()).isEqualTo("bar");
assertThat(profile.getName()).isEqualTo("validname");
assertThat(profile.getAbout()).isEqualTo("about");
assertThat(profile.getAboutEmoji()).isEqualTo("emoji");
assertThat(profile.getAvatar()).isEqualTo("profiles/validavatar");
assertThat(profile.getCapabilities().isGv2()).isFalse();
assertThat(profile.getCapabilities().isGv1Migration()).isFalse();

View File

@ -62,7 +62,7 @@ public class ProfilesManagerTest {
Profiles profiles = mock(Profiles.class);
UUID uuid = UUID.randomUUID();
VersionedProfile profile = new VersionedProfile("someversion", "somename", "someavatar", "somecommitment".getBytes());
VersionedProfile profile = new VersionedProfile("someversion", "somename", "someavatar", 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));
@ -88,7 +88,7 @@ public class ProfilesManagerTest {
Profiles profiles = mock(Profiles.class);
UUID uuid = UUID.randomUUID();
VersionedProfile profile = new VersionedProfile("someversion", "somename", "someavatar", "somecommitment".getBytes());
VersionedProfile profile = new VersionedProfile("someversion", "somename", "someavatar", 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));

View File

@ -41,7 +41,21 @@ public class ProfilesTest {
@Test
public void testSetGet() {
UUID uuid = UUID.randomUUID();
VersionedProfile profile = new VersionedProfile("123", "foo", "avatarLocation", "acommitment".getBytes());
VersionedProfile profile = new VersionedProfile("123", "foo", "avatarLocation", "emoji", "the very model of a modern major general", "acommitment".getBytes());
profiles.set(uuid, profile);
Optional<VersionedProfile> retrieved = profiles.get(uuid, "123");
assertThat(retrieved.isPresent()).isTrue();
assertThat(retrieved.get().getName()).isEqualTo(profile.getName());
assertThat(retrieved.get().getAvatar()).isEqualTo(profile.getAvatar());
assertThat(retrieved.get().getCommitment()).isEqualTo(profile.getCommitment());
}
@Test
public void testSetGetNullOptionalFields() {
UUID uuid = UUID.randomUUID();
VersionedProfile profile = new VersionedProfile("123", "foo", null, null, null, "acommitment".getBytes());
profiles.set(uuid, profile);
Optional<VersionedProfile> retrieved = profiles.get(uuid, "123");
@ -55,7 +69,7 @@ public class ProfilesTest {
@Test
public void testSetReplace() {
UUID uuid = UUID.randomUUID();
VersionedProfile profile = new VersionedProfile("123", "foo", "avatarLocation", "acommitment".getBytes());
VersionedProfile profile = new VersionedProfile("123", "foo", "avatarLocation", null, null, "acommitment".getBytes());
profiles.set(uuid, profile);
Optional<VersionedProfile> retrieved = profiles.get(uuid, "123");
@ -65,7 +79,7 @@ public class ProfilesTest {
assertThat(retrieved.get().getAvatar()).isEqualTo(profile.getAvatar());
assertThat(retrieved.get().getCommitment()).isEqualTo(profile.getCommitment());
VersionedProfile updated = new VersionedProfile("123", "bar", "baz", "boof".getBytes());
VersionedProfile updated = new VersionedProfile("123", "bar", "baz", "emoji", "bio", "boof".getBytes());
profiles.set(uuid, updated);
retrieved = profiles.get(uuid, "123");
@ -79,8 +93,8 @@ public class ProfilesTest {
@Test
public void testMultipleVersions() {
UUID uuid = UUID.randomUUID();
VersionedProfile profileOne = new VersionedProfile("123", "foo", "avatarLocation", "acommitmnet".getBytes());
VersionedProfile profileTwo = new VersionedProfile("345", "bar", "baz", "boof".getBytes());
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());
profiles.set(uuid, profileOne);
profiles.set(uuid, profileTwo);
@ -103,7 +117,7 @@ public class ProfilesTest {
@Test
public void testMissing() {
UUID uuid = UUID.randomUUID();
VersionedProfile profile = new VersionedProfile("123", "foo", "avatarLocation", "aDigest".getBytes());
VersionedProfile profile = new VersionedProfile("123", "foo", "avatarLocation", null, null, "aDigest".getBytes());
profiles.set(uuid, profile);
Optional<VersionedProfile> retrieved = profiles.get(uuid, "888");
@ -114,8 +128,8 @@ public class ProfilesTest {
@Test
public void testDelete() {
UUID uuid = UUID.randomUUID();
VersionedProfile profileOne = new VersionedProfile("123", "foo", "avatarLocation", "aDigest".getBytes());
VersionedProfile profileTwo = new VersionedProfile("345", "bar", "baz", "boof".getBytes());
VersionedProfile profileOne = new VersionedProfile("123", "foo", "avatarLocation", null, null, "aDigest".getBytes());
VersionedProfile profileTwo = new VersionedProfile("345", "bar", "baz", null, null, "boof".getBytes());
profiles.set(uuid, profileOne);
profiles.set(uuid, profileTwo);