Add support for about and aboutEmoji for profiles

This commit is contained in:
AsamK 2021-01-24 00:02:07 +01:00
parent 7d802fb8c5
commit a811d1a05a
4 changed files with 79 additions and 22 deletions

View file

@ -362,22 +362,33 @@ public class Manager implements Closeable {
} }
/** /**
* @param avatar if avatar is null the image from the local avatar store is used (if present), * @param name if null, the previous name will be kept
* if it's Optional.absent(), the avatar will be removed * @param about if null, the previous about text will be kept
* @param aboutEmoji if null, the previous about emoji will be kept
* @param avatar if avatar is null the image from the local avatar store is used (if present),
* if it's Optional.absent(), the avatar will be removed
*/ */
public void setProfile(String name, Optional<File> avatar) throws IOException { public void setProfile(String name, String about, String aboutEmoji, Optional<File> avatar) throws IOException {
// TODO SignalProfileEntry profileEntry = account.getProfileStore().getProfileEntry(getSelfAddress());
String about = null; SignalProfile profile = profileEntry == null ? null : profileEntry.getProfile();
String aboutEmoji = null; SignalProfile newProfile = new SignalProfile(profile == null ? null : profile.getIdentityKey(),
name != null ? name : profile == null || profile.getName() == null ? "" : profile.getName(),
about != null ? about : profile == null || profile.getAbout() == null ? "" : profile.getAbout(),
aboutEmoji != null
? aboutEmoji
: profile == null || profile.getAboutEmoji() == null ? "" : profile.getAboutEmoji(),
profile == null ? null : profile.getUnidentifiedAccess(),
account.isUnrestrictedUnidentifiedAccess(),
profile == null ? null : profile.getCapabilities());
try (final StreamDetails streamDetails = avatar == null try (final StreamDetails streamDetails = avatar == null
? avatarStore.retrieveProfileAvatar(getSelfAddress()) ? avatarStore.retrieveProfileAvatar(getSelfAddress())
: avatar.isPresent() ? Utils.createStreamDetailsFromFile(avatar.get()) : null) { : avatar.isPresent() ? Utils.createStreamDetailsFromFile(avatar.get()) : null) {
accountManager.setVersionedProfile(account.getUuid(), accountManager.setVersionedProfile(account.getUuid(),
account.getProfileKey(), account.getProfileKey(),
name, newProfile.getName(),
about, newProfile.getAbout(),
aboutEmoji, newProfile.getAboutEmoji(),
streamDetails); streamDetails);
} }
@ -389,6 +400,12 @@ public class Manager implements Closeable {
avatarStore.deleteProfileAvatar(getSelfAddress()); avatarStore.deleteProfileAvatar(getSelfAddress());
} }
} }
account.getProfileStore()
.updateProfile(getSelfAddress(),
account.getProfileKey(),
System.currentTimeMillis(),
newProfile,
profileEntry == null ? null : profileEntry.getProfileKeyCredential());
try { try {
sendSyncMessage(SignalServiceSyncMessage.forFetchLatest(SignalServiceSyncMessage.FetchType.LOCAL_PROFILE)); sendSyncMessage(SignalServiceSyncMessage.forFetchLatest(SignalServiceSyncMessage.FetchType.LOCAL_PROFILE));

View file

@ -13,6 +13,12 @@ public class SignalProfile {
@JsonProperty @JsonProperty
private final String name; private final String name;
@JsonProperty
private final String about;
@JsonProperty
private final String aboutEmoji;
@JsonProperty @JsonProperty
private final String unidentifiedAccess; private final String unidentifiedAccess;
@ -25,12 +31,16 @@ public class SignalProfile {
public SignalProfile( public SignalProfile(
final String identityKey, final String identityKey,
final String name, final String name,
final String about,
final String aboutEmoji,
final String unidentifiedAccess, final String unidentifiedAccess,
final boolean unrestrictedUnidentifiedAccess, final boolean unrestrictedUnidentifiedAccess,
final SignalServiceProfile.Capabilities capabilities final SignalServiceProfile.Capabilities capabilities
) { ) {
this.identityKey = identityKey; this.identityKey = identityKey;
this.name = name; this.name = name;
this.about = about;
this.aboutEmoji = aboutEmoji;
this.unidentifiedAccess = unidentifiedAccess; this.unidentifiedAccess = unidentifiedAccess;
this.unrestrictedUnidentifiedAccess = unrestrictedUnidentifiedAccess; this.unrestrictedUnidentifiedAccess = unrestrictedUnidentifiedAccess;
this.capabilities = new Capabilities(); this.capabilities = new Capabilities();
@ -42,12 +52,16 @@ public class SignalProfile {
public SignalProfile( public SignalProfile(
@JsonProperty("identityKey") final String identityKey, @JsonProperty("identityKey") final String identityKey,
@JsonProperty("name") final String name, @JsonProperty("name") final String name,
@JsonProperty("about") final String about,
@JsonProperty("aboutEmoji") final String aboutEmoji,
@JsonProperty("unidentifiedAccess") final String unidentifiedAccess, @JsonProperty("unidentifiedAccess") final String unidentifiedAccess,
@JsonProperty("unrestrictedUnidentifiedAccess") final boolean unrestrictedUnidentifiedAccess, @JsonProperty("unrestrictedUnidentifiedAccess") final boolean unrestrictedUnidentifiedAccess,
@JsonProperty("capabilities") final Capabilities capabilities @JsonProperty("capabilities") final Capabilities capabilities
) { ) {
this.identityKey = identityKey; this.identityKey = identityKey;
this.name = name; this.name = name;
this.about = about;
this.aboutEmoji = aboutEmoji;
this.unidentifiedAccess = unidentifiedAccess; this.unidentifiedAccess = unidentifiedAccess;
this.unrestrictedUnidentifiedAccess = unrestrictedUnidentifiedAccess; this.unrestrictedUnidentifiedAccess = unrestrictedUnidentifiedAccess;
this.capabilities = capabilities; this.capabilities = capabilities;
@ -61,6 +75,14 @@ public class SignalProfile {
return name; return name;
} }
public String getAbout() {
return about;
}
public String getAboutEmoji() {
return aboutEmoji;
}
public String getUnidentifiedAccess() { public String getUnidentifiedAccess() {
return unidentifiedAccess; return unidentifiedAccess;
} }
@ -82,7 +104,12 @@ public class SignalProfile {
+ ", name='" + ", name='"
+ name + name
+ '\'' + '\''
+ ", avatarFile=" + ", about='"
+ about
+ '\''
+ ", aboutEmoji='"
+ aboutEmoji
+ '\''
+ ", unidentifiedAccess='" + ", unidentifiedAccess='"
+ unidentifiedAccess + unidentifiedAccess
+ '\'' + '\''

View file

@ -15,14 +15,9 @@ public class ProfileUtils {
) { ) {
ProfileCipher profileCipher = new ProfileCipher(profileKey); ProfileCipher profileCipher = new ProfileCipher(profileKey);
try { try {
String name; String name = decryptName(encryptedProfile.getName(), profileCipher);
try { String about = decryptName(encryptedProfile.getAbout(), profileCipher);
name = encryptedProfile.getName() == null String aboutEmoji = decryptName(encryptedProfile.getAboutEmoji(), profileCipher);
? null
: new String(profileCipher.decryptName(Base64.getDecoder().decode(encryptedProfile.getName())));
} catch (IllegalArgumentException e) {
name = null;
}
String unidentifiedAccess; String unidentifiedAccess;
try { try {
unidentifiedAccess = encryptedProfile.getUnidentifiedAccess() == null unidentifiedAccess = encryptedProfile.getUnidentifiedAccess() == null
@ -35,6 +30,8 @@ public class ProfileUtils {
} }
return new SignalProfile(encryptedProfile.getIdentityKey(), return new SignalProfile(encryptedProfile.getIdentityKey(),
name, name,
about,
aboutEmoji,
unidentifiedAccess, unidentifiedAccess,
encryptedProfile.isUnrestrictedUnidentifiedAccess(), encryptedProfile.isUnrestrictedUnidentifiedAccess(),
encryptedProfile.getCapabilities()); encryptedProfile.getCapabilities());
@ -42,4 +39,16 @@ public class ProfileUtils {
return null; return null;
} }
} }
private static String decryptName(
final String encryptedName, final ProfileCipher profileCipher
) throws InvalidCiphertextException {
try {
return encryptedName == null
? null
: new String(profileCipher.decryptName(Base64.getDecoder().decode(encryptedName)));
} catch (IllegalArgumentException e) {
return null;
}
}
} }

View file

@ -15,18 +15,22 @@ public class UpdateProfileCommand implements LocalCommand {
@Override @Override
public void attachToSubparser(final Subparser subparser) { public void attachToSubparser(final Subparser subparser) {
subparser.addArgument("--name").help("New profile name");
subparser.addArgument("--about").help("New profile about text");
subparser.addArgument("--about-emoji").help("New profile about emoji");
final MutuallyExclusiveGroup avatarOptions = subparser.addMutuallyExclusiveGroup(); final MutuallyExclusiveGroup avatarOptions = subparser.addMutuallyExclusiveGroup();
avatarOptions.addArgument("--avatar").help("Path to new profile avatar"); avatarOptions.addArgument("--avatar").help("Path to new profile avatar");
avatarOptions.addArgument("--remove-avatar").action(Arguments.storeTrue()); avatarOptions.addArgument("--remove-avatar").action(Arguments.storeTrue());
subparser.addArgument("--name").required(true).help("New profile name"); subparser.help("Set a name, about and avatar image for the user profile");
subparser.help("Set a name and avatar image for the user profile");
} }
@Override @Override
public int handleCommand(final Namespace ns, final Manager m) { public int handleCommand(final Namespace ns, final Manager m) {
String name = ns.getString("name"); String name = ns.getString("name");
String about = ns.getString("about");
String aboutEmoji = ns.getString("about_emoji");
String avatarPath = ns.getString("avatar"); String avatarPath = ns.getString("avatar");
boolean removeAvatar = ns.getBoolean("remove_avatar"); boolean removeAvatar = ns.getBoolean("remove_avatar");
@ -34,7 +38,7 @@ public class UpdateProfileCommand implements LocalCommand {
Optional<File> avatarFile = removeAvatar Optional<File> avatarFile = removeAvatar
? Optional.absent() ? Optional.absent()
: avatarPath == null ? null : Optional.of(new File(avatarPath)); : avatarPath == null ? null : Optional.of(new File(avatarPath));
m.setProfile(name, avatarFile); m.setProfile(name, about, aboutEmoji, avatarFile);
} catch (IOException e) { } catch (IOException e) {
System.err.println("UpdateAccount error: " + e.getMessage()); System.err.println("UpdateAccount error: " + e.getMessage());
return 3; return 3;