]> nmode's Git Repositories - signal-cli/commitdiff
Retrieve self profile from storage
authorAsamK <asamk@gmx.de>
Sun, 3 Oct 2021 14:17:58 +0000 (16:17 +0200)
committerAsamK <asamk@gmx.de>
Sun, 3 Oct 2021 14:17:58 +0000 (16:17 +0200)
lib/src/main/java/org/asamk/signal/manager/ManagerImpl.java
lib/src/main/java/org/asamk/signal/manager/RegistrationManager.java
lib/src/main/java/org/asamk/signal/manager/helper/ProfileHelper.java
lib/src/main/java/org/asamk/signal/manager/helper/StorageHelper.java
lib/src/main/java/org/asamk/signal/manager/storage/SignalAccount.java
lib/src/main/java/org/asamk/signal/manager/storage/recipients/Profile.java
lib/src/main/java/org/asamk/signal/manager/storage/recipients/RecipientStore.java
lib/src/main/java/org/asamk/signal/manager/util/ProfileUtils.java

index 6a039c69fba743227ee00744af8a0d9d31b6028c..0fd1eb33cf0d69a937f45ab6e52c4d0a91b2ccb8 100644 (file)
@@ -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,
index ff94c19b400ca36be81c4262f3b52ac18c6f1601..c42782f718d4b4a8f5d8cc4b825f25acde19f079 100644 (file)
@@ -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;
index 46c83e9d47ff62515c53d425f4b450810dd0d9fc..e24d41fad91464144f11f8e5ed67ad6e565c4ecc 100644 (file)
@@ -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<File> 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<File> 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));
index f76c95fb0f4f673f71b784a4d8830d0cad733a00..b68e65b481f62e29d7ebae24c63d09fff240ec89 100644 (file)
@@ -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 {
index 9c51017c4bcd3e64f8be7e36765570dd204fe809..5bb9fdeb5add3ba4ffb9674f064ab038bd3cfcaf 100644 (file)
@@ -631,6 +631,7 @@ public class SignalAccount implements Closeable {
                             profile.getFamilyName(),
                             profile.getAbout(),
                             profile.getAboutEmoji(),
+                            null,
                             profile.isUnrestrictedUnidentifiedAccess()
                                     ? Profile.UnidentifiedAccessMode.UNRESTRICTED
                                     : profile.getUnidentifiedAccess() != null
index d61a81b59938f9460ce27dbe70760f8e845e87bc..c6ba5c922bb63a38ddb28422676c428a64ab9a8d 100644 (file)
@@ -17,6 +17,8 @@ public class Profile {
 
     private final String aboutEmoji;
 
+    private final String avatarUrlPath;
+
     private final UnidentifiedAccessMode unidentifiedAccessMode;
 
     private final Set<Capability> 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<Capability> 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<Capability> 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;
index bace6a6b5952763bd0077e19842a6f9a7bdc820e..1630269270714e3672b7b3a829e3be520fa8a69c 100644 (file)
@@ -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<String> 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<String> 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;
                 }
index 7ceb07f6f2acaabecc116af3ae537ccd07522f41..c1b1183c31bc3454ce96b5f5b3f864717d632fb9 100644 (file)
@@ -27,6 +27,7 @@ public class ProfileUtils {
                     nameParts.second(),
                     about,
                     aboutEmoji,
+                    encryptedProfile.getAvatar(),
                     getUnidentifiedAccessMode(encryptedProfile, profileCipher),
                     getCapabilities(encryptedProfile));
         } catch (InvalidCiphertextException e) {