From: AsamK Date: Sun, 3 Oct 2021 14:17:58 +0000 (+0200) Subject: Retrieve self profile from storage X-Git-Tag: v0.9.1~28 X-Git-Url: https://git.nmode.ca/signal-cli/commitdiff_plain/26594dd0eed44225d7d4a17571597a81e4e3b58a Retrieve self profile from storage --- diff --git a/lib/src/main/java/org/asamk/signal/manager/ManagerImpl.java b/lib/src/main/java/org/asamk/signal/manager/ManagerImpl.java index 6a039c69..0fd1eb33 100644 --- a/lib/src/main/java/org/asamk/signal/manager/ManagerImpl.java +++ b/lib/src/main/java/org/asamk/signal/manager/ManagerImpl.java @@ -209,7 +209,7 @@ public class ManagerImpl implements Manager { avatarStore, this::resolveSignalServiceAddress, account.getRecipientStore()); - this.storageHelper = new StorageHelper(account, dependencies, groupHelper); + this.storageHelper = new StorageHelper(account, dependencies, groupHelper, profileHelper); this.contactHelper = new ContactHelper(account); this.syncHelper = new SyncHelper(account, attachmentHelper, diff --git a/lib/src/main/java/org/asamk/signal/manager/RegistrationManager.java b/lib/src/main/java/org/asamk/signal/manager/RegistrationManager.java index ff94c19b..c42782f7 100644 --- a/lib/src/main/java/org/asamk/signal/manager/RegistrationManager.java +++ b/lib/src/main/java/org/asamk/signal/manager/RegistrationManager.java @@ -183,15 +183,15 @@ public class RegistrationManager implements Closeable { account = null; m.refreshPreKeys(); + if (response.isStorageCapable()) { + m.retrieveRemoteStorage(); + } // Set an initial empty profile so user can be added to groups try { m.setProfile(null, null, null, null, null); } catch (NoClassDefFoundError e) { logger.warn("Failed to set default profile: {}", e.getMessage()); } - if (response.isStorageCapable()) { - m.retrieveRemoteStorage(); - } final var result = m; m = null; diff --git a/lib/src/main/java/org/asamk/signal/manager/helper/ProfileHelper.java b/lib/src/main/java/org/asamk/signal/manager/helper/ProfileHelper.java index 46c83e9d..e24d41fa 100644 --- a/lib/src/main/java/org/asamk/signal/manager/helper/ProfileHelper.java +++ b/lib/src/main/java/org/asamk/signal/manager/helper/ProfileHelper.java @@ -33,6 +33,7 @@ import java.util.Base64; import java.util.Date; import java.util.HashSet; import java.util.List; +import java.util.Objects; import java.util.Set; import io.reactivex.rxjava3.core.Single; @@ -110,6 +111,17 @@ public final class ProfileHelper { */ public void setProfile( String givenName, final String familyName, String about, String aboutEmoji, Optional avatar + ) throws IOException { + setProfile(true, givenName, familyName, about, aboutEmoji, avatar); + } + + public void setProfile( + boolean uploadProfile, + String givenName, + final String familyName, + String about, + String aboutEmoji, + Optional avatar ) throws IOException { var profile = getRecipientProfile(account.getSelfRecipientId()); var builder = profile == null ? Profile.newBuilder() : Profile.newBuilder(profile); @@ -127,18 +139,22 @@ public final class ProfileHelper { } var newProfile = builder.build(); - try (final var streamDetails = avatar == null - ? avatarStore.retrieveProfileAvatar(account.getSelfAddress()) - : avatar.isPresent() ? Utils.createStreamDetailsFromFile(avatar.get()) : null) { - dependencies.getAccountManager() - .setVersionedProfile(account.getUuid(), - account.getProfileKey(), - newProfile.getInternalServiceName(), - newProfile.getAbout() == null ? "" : newProfile.getAbout(), - newProfile.getAboutEmoji() == null ? "" : newProfile.getAboutEmoji(), - Optional.absent(), - streamDetails, - List.of(/* TODO */)); + if (uploadProfile) { + try (final var streamDetails = avatar == null + ? avatarStore.retrieveProfileAvatar(account.getSelfAddress()) + : avatar.isPresent() ? Utils.createStreamDetailsFromFile(avatar.get()) : null) { + final var avatarPath = dependencies.getAccountManager() + .setVersionedProfile(account.getUuid(), + account.getProfileKey(), + newProfile.getInternalServiceName(), + newProfile.getAbout() == null ? "" : newProfile.getAbout(), + newProfile.getAboutEmoji() == null ? "" : newProfile.getAboutEmoji(), + Optional.absent(), + streamDetails, + List.of(/* TODO */)); + builder.withAvatarUrlPath(avatarPath.orNull()); + newProfile = builder.build(); + } } if (avatar != null) { @@ -197,6 +213,7 @@ public final class ProfileHelper { null, null, null, + null, ProfileUtils.getUnidentifiedAccessMode(encryptedProfile, null), ProfileUtils.getCapabilities(encryptedProfile)); } @@ -242,15 +259,23 @@ public final class ProfileHelper { private Profile decryptProfileAndDownloadAvatar( final RecipientId recipientId, final ProfileKey profileKey, final SignalServiceProfile encryptedProfile ) { - if (encryptedProfile.getAvatar() != null) { - downloadProfileAvatar(addressResolver.resolveSignalServiceAddress(recipientId), - encryptedProfile.getAvatar(), - profileKey); - } + final var avatarPath = encryptedProfile.getAvatar(); + downloadProfileAvatar(recipientId, avatarPath, profileKey); return ProfileUtils.decryptProfile(profileKey, encryptedProfile); } + public void downloadProfileAvatar( + final RecipientId recipientId, final String avatarPath, final ProfileKey profileKey + ) { + var profile = account.getProfileStore().getProfile(recipientId); + if (profile == null || !Objects.equals(avatarPath, profile.getAvatarUrlPath())) { + downloadProfileAvatar(addressResolver.resolveSignalServiceAddress(recipientId), avatarPath, profileKey); + var builder = profile == null ? Profile.newBuilder() : Profile.newBuilder(profile); + account.getProfileStore().storeProfile(recipientId, builder.withAvatarUrlPath(avatarPath).build()); + } + } + private ProfileAndCredential retrieveProfileSync( RecipientId recipientId, SignalServiceProfile.RequestType requestType ) throws IOException { @@ -310,6 +335,15 @@ public final class ProfileHelper { private void downloadProfileAvatar( SignalServiceAddress address, String avatarPath, ProfileKey profileKey ) { + if (avatarPath == null) { + try { + avatarStore.deleteProfileAvatar(address); + } catch (IOException e) { + logger.warn("Failed to delete local profile avatar, ignoring: {}", e.getMessage()); + } + return; + } + try { avatarStore.storeProfileAvatar(address, outputStream -> retrieveProfileAvatar(avatarPath, profileKey, outputStream)); diff --git a/lib/src/main/java/org/asamk/signal/manager/helper/StorageHelper.java b/lib/src/main/java/org/asamk/signal/manager/helper/StorageHelper.java index f76c95fb..b68e65b4 100644 --- a/lib/src/main/java/org/asamk/signal/manager/helper/StorageHelper.java +++ b/lib/src/main/java/org/asamk/signal/manager/helper/StorageHelper.java @@ -32,13 +32,18 @@ public class StorageHelper { private final SignalAccount account; private final SignalDependencies dependencies; private final GroupHelper groupHelper; + private final ProfileHelper profileHelper; public StorageHelper( - final SignalAccount account, final SignalDependencies dependencies, final GroupHelper groupHelper + final SignalAccount account, + final SignalDependencies dependencies, + final GroupHelper groupHelper, + final ProfileHelper profileHelper ) { this.account = account; this.dependencies = dependencies; this.groupHelper = groupHelper; + this.profileHelper = profileHelper; } public void readDataFromStorage() throws IOException { @@ -199,12 +204,26 @@ public class StorageHelper { account.getConfigurationStore().setLinkPreviews(accountRecord.isLinkPreviewsEnabled()); if (accountRecord.getProfileKey().isPresent()) { + ProfileKey profileKey; try { - account.setProfileKey(new ProfileKey(accountRecord.getProfileKey().get())); + profileKey = new ProfileKey(accountRecord.getProfileKey().get()); } catch (InvalidInputException e) { logger.warn("Received invalid profile key from storage"); + profileKey = null; + } + if (profileKey != null) { + account.setProfileKey(profileKey); + final var avatarPath = accountRecord.getAvatarUrlPath().orNull(); + profileHelper.downloadProfileAvatar(account.getSelfRecipientId(), avatarPath, profileKey); } } + + profileHelper.setProfile(false, + accountRecord.getGivenName().orNull(), + accountRecord.getFamilyName().orNull(), + null, + null, + null); } private SignalStorageRecord getSignalStorageRecord(final StorageId accountId) throws IOException { diff --git a/lib/src/main/java/org/asamk/signal/manager/storage/SignalAccount.java b/lib/src/main/java/org/asamk/signal/manager/storage/SignalAccount.java index 9c51017c..5bb9fdeb 100644 --- a/lib/src/main/java/org/asamk/signal/manager/storage/SignalAccount.java +++ b/lib/src/main/java/org/asamk/signal/manager/storage/SignalAccount.java @@ -631,6 +631,7 @@ public class SignalAccount implements Closeable { profile.getFamilyName(), profile.getAbout(), profile.getAboutEmoji(), + null, profile.isUnrestrictedUnidentifiedAccess() ? Profile.UnidentifiedAccessMode.UNRESTRICTED : profile.getUnidentifiedAccess() != null diff --git a/lib/src/main/java/org/asamk/signal/manager/storage/recipients/Profile.java b/lib/src/main/java/org/asamk/signal/manager/storage/recipients/Profile.java index d61a81b5..c6ba5c92 100644 --- a/lib/src/main/java/org/asamk/signal/manager/storage/recipients/Profile.java +++ b/lib/src/main/java/org/asamk/signal/manager/storage/recipients/Profile.java @@ -17,6 +17,8 @@ public class Profile { private final String aboutEmoji; + private final String avatarUrlPath; + private final UnidentifiedAccessMode unidentifiedAccessMode; private final Set capabilities; @@ -27,6 +29,7 @@ public class Profile { final String familyName, final String about, final String aboutEmoji, + final String avatarUrlPath, final UnidentifiedAccessMode unidentifiedAccessMode, final Set capabilities ) { @@ -35,6 +38,7 @@ public class Profile { this.familyName = familyName; this.about = about; this.aboutEmoji = aboutEmoji; + this.avatarUrlPath = avatarUrlPath; this.unidentifiedAccessMode = unidentifiedAccessMode; this.capabilities = capabilities; } @@ -45,6 +49,7 @@ public class Profile { familyName = builder.familyName; about = builder.about; aboutEmoji = builder.aboutEmoji; + avatarUrlPath = builder.avatarUrlPath; unidentifiedAccessMode = builder.unidentifiedAccessMode; capabilities = builder.capabilities; } @@ -60,6 +65,7 @@ public class Profile { builder.familyName = copy.getFamilyName(); builder.about = copy.getAbout(); builder.aboutEmoji = copy.getAboutEmoji(); + builder.avatarUrlPath = copy.getAvatarUrlPath(); builder.unidentifiedAccessMode = copy.getUnidentifiedAccessMode(); builder.capabilities = copy.getCapabilities(); return builder; @@ -107,6 +113,10 @@ public class Profile { return aboutEmoji; } + public String getAvatarUrlPath() { + return avatarUrlPath; + } + public UnidentifiedAccessMode getUnidentifiedAccessMode() { return unidentifiedAccessMode; } @@ -152,6 +162,7 @@ public class Profile { private String familyName; private String about; private String aboutEmoji; + private String avatarUrlPath; private UnidentifiedAccessMode unidentifiedAccessMode = UnidentifiedAccessMode.UNKNOWN; private Set capabilities = Collections.emptySet(); private long lastUpdateTimestamp = 0; @@ -179,6 +190,11 @@ public class Profile { return this; } + public Builder withAvatarUrlPath(final String val) { + avatarUrlPath = val; + return this; + } + public Builder withUnidentifiedAccessMode(final UnidentifiedAccessMode val) { unidentifiedAccessMode = val; return this; diff --git a/lib/src/main/java/org/asamk/signal/manager/storage/recipients/RecipientStore.java b/lib/src/main/java/org/asamk/signal/manager/storage/recipients/RecipientStore.java index bace6a6b..16302692 100644 --- a/lib/src/main/java/org/asamk/signal/manager/storage/recipients/RecipientStore.java +++ b/lib/src/main/java/org/asamk/signal/manager/storage/recipients/RecipientStore.java @@ -89,6 +89,7 @@ public class RecipientStore implements RecipientResolver, ContactsStore, Profile r.profile.familyName, r.profile.about, r.profile.aboutEmoji, + r.profile.avatarUrlPath, Profile.UnidentifiedAccessMode.valueOfOrUnknown(r.profile.unidentifiedAccessMode), r.profile.capabilities.stream() .map(Profile.Capability::valueOfOrNull) @@ -445,6 +446,7 @@ public class RecipientStore implements RecipientResolver, ContactsStore, Profile recipient.getProfile().getFamilyName(), recipient.getProfile().getAbout(), recipient.getProfile().getAboutEmoji(), + recipient.getProfile().getAvatarUrlPath(), recipient.getProfile().getUnidentifiedAccessMode().name(), recipient.getProfile() .getCapabilities() @@ -558,6 +560,7 @@ public class RecipientStore implements RecipientResolver, ContactsStore, Profile public String familyName; public String about; public String aboutEmoji; + public String avatarUrlPath; public String unidentifiedAccessMode; public Set capabilities; @@ -571,6 +574,7 @@ public class RecipientStore implements RecipientResolver, ContactsStore, Profile final String familyName, final String about, final String aboutEmoji, + final String avatarUrlPath, final String unidentifiedAccessMode, final Set capabilities ) { @@ -579,6 +583,7 @@ public class RecipientStore implements RecipientResolver, ContactsStore, Profile this.familyName = familyName; this.about = about; this.aboutEmoji = aboutEmoji; + this.avatarUrlPath = avatarUrlPath; this.unidentifiedAccessMode = unidentifiedAccessMode; this.capabilities = capabilities; } diff --git a/lib/src/main/java/org/asamk/signal/manager/util/ProfileUtils.java b/lib/src/main/java/org/asamk/signal/manager/util/ProfileUtils.java index 7ceb07f6..c1b1183c 100644 --- a/lib/src/main/java/org/asamk/signal/manager/util/ProfileUtils.java +++ b/lib/src/main/java/org/asamk/signal/manager/util/ProfileUtils.java @@ -27,6 +27,7 @@ public class ProfileUtils { nameParts.second(), about, aboutEmoji, + encryptedProfile.getAvatar(), getUnidentifiedAccessMode(encryptedProfile, profileCipher), getCapabilities(encryptedProfile)); } catch (InvalidCiphertextException e) {