]> nmode's Git Repositories - signal-cli/commitdiff
Store retrieved storage manifest locally
authorAsamK <asamk@gmx.de>
Tue, 24 May 2022 19:07:40 +0000 (21:07 +0200)
committerAsamK <asamk@gmx.de>
Tue, 24 May 2022 19:09:06 +0000 (21:09 +0200)
lib/src/main/java/org/asamk/signal/manager/helper/StorageHelper.java
lib/src/main/java/org/asamk/signal/manager/storage/SignalAccount.java

index 426806ff365d81cc4e78456a72b48a6f9c510de5..281901c1315ec95cfaca22ca1aac9bfe69e071fc 100644 (file)
@@ -21,10 +21,13 @@ import org.whispersystems.signalservice.internal.storage.protos.AccountRecord;
 import org.whispersystems.signalservice.internal.storage.protos.ManifestRecord;
 
 import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Collection;
 import java.util.Collections;
 import java.util.Date;
 import java.util.List;
 import java.util.Optional;
+import java.util.stream.Collectors;
 
 public class StorageHelper {
 
@@ -56,11 +59,19 @@ public class StorageHelper {
             return;
         }
 
-        account.setStorageManifestVersion(manifest.get().getVersion());
+        logger.trace("Remote storage manifest has {} records", manifest.get().getStorageIds().size());
+        final var storageIds = manifest.get()
+                .getStorageIds()
+                .stream()
+                .filter(id -> !id.isUnknown())
+                .collect(Collectors.toSet());
 
-        final var storageIds = manifest.get().getStorageIds().stream().filter(id -> !id.isUnknown()).toList();
+        Optional<SignalStorageManifest> localManifest = account.getStorageManifest();
+        localManifest.ifPresent(m -> m.getStorageIds().forEach(storageIds::remove));
 
+        logger.trace("Reading {} new records", manifest.get().getStorageIds().size());
         for (final var record : getSignalStorageRecords(storageIds)) {
+            logger.debug("Reading record of type {}", record.getType());
             if (record.getType() == ManifestRecord.Identifier.Type.ACCOUNT_VALUE) {
                 readAccountRecord(record);
             } else if (record.getType() == ManifestRecord.Identifier.Type.GROUPV2_VALUE) {
@@ -71,6 +82,8 @@ public class StorageHelper {
                 readContactRecord(record);
             }
         }
+        account.setStorageManifestVersion(manifest.get().getVersion());
+        account.setStorageManifest(manifest.get());
         logger.debug("Done reading data from remote storage");
     }
 
@@ -86,10 +99,12 @@ public class StorageHelper {
         final var contact = account.getContactStore().getContact(recipientId);
         final var blocked = contact != null && contact.isBlocked();
         final var profileShared = contact != null && contact.isProfileSharingEnabled();
-        if (contactRecord.getGivenName().isPresent()
-                || contactRecord.getFamilyName().isPresent()
-                || blocked != contactRecord.isBlocked()
-                || profileShared != contactRecord.isProfileSharingEnabled()) {
+        final var givenName = contact == null ? null : contact.getGivenName();
+        final var familyName = contact == null ? null : contact.getFamilyName();
+        if ((contactRecord.getGivenName().isPresent() && !contactRecord.getGivenName().get().equals(givenName)) || (
+                contactRecord.getFamilyName().isPresent() && !contactRecord.getFamilyName().get().equals(familyName)
+        ) || blocked != contactRecord.isBlocked() || profileShared != contactRecord.isProfileSharingEnabled()) {
+            logger.debug("Storing new or updated contact {}", recipientId);
             final var contactBuilder = contact == null ? Contact.newBuilder() : Contact.newBuilder(contact);
             final var newContact = contactBuilder.withBlocked(contactRecord.isBlocked())
                     .withGivenName(contactRecord.getGivenName().orElse(null))
@@ -101,6 +116,7 @@ public class StorageHelper {
 
         if (contactRecord.getProfileKey().isPresent()) {
             try {
+                logger.trace("Storing profile key {}", recipientId);
                 final var profileKey = new ProfileKey(contactRecord.getProfileKey().get());
                 account.getProfileStore().storeProfileKey(recipientId, profileKey);
             } catch (InvalidInputException e) {
@@ -109,6 +125,7 @@ public class StorageHelper {
         }
         if (contactRecord.getIdentityKey().isPresent()) {
             try {
+                logger.trace("Storing identity key {}", recipientId);
                 final var identityKey = new IdentityKey(contactRecord.getIdentityKey().get());
                 account.getIdentityKeyStore().saveIdentity(recipientId, identityKey, new Date());
 
@@ -239,10 +256,11 @@ public class StorageHelper {
         return records.size() > 0 ? records.get(0) : null;
     }
 
-    private List<SignalStorageRecord> getSignalStorageRecords(final List<StorageId> storageIds) throws IOException {
+    private List<SignalStorageRecord> getSignalStorageRecords(final Collection<StorageId> storageIds) throws IOException {
         List<SignalStorageRecord> records;
         try {
-            records = dependencies.getAccountManager().readStorageRecords(account.getStorageKey(), storageIds);
+            records = dependencies.getAccountManager()
+                    .readStorageRecords(account.getStorageKey(), new ArrayList<>(storageIds));
         } catch (InvalidKeyException e) {
             logger.warn("Failed to read storage records, ignoring.");
             return List.of();
index 6d6bb12feb9a661f3c2391ead19a6e40c66c183f..f66d3e4a9db01a7f59f525aab37cee109a5c8059 100644 (file)
@@ -59,6 +59,7 @@ import org.whispersystems.signalservice.api.push.PNI;
 import org.whispersystems.signalservice.api.push.ServiceId;
 import org.whispersystems.signalservice.api.push.ServiceIdType;
 import org.whispersystems.signalservice.api.push.SignalServiceAddress;
+import org.whispersystems.signalservice.api.storage.SignalStorageManifest;
 import org.whispersystems.signalservice.api.storage.StorageKey;
 import org.whispersystems.signalservice.api.util.CredentialsProvider;
 import org.whispersystems.signalservice.api.util.UuidUtil;
@@ -67,6 +68,8 @@ import java.io.ByteArrayInputStream;
 import java.io.ByteArrayOutputStream;
 import java.io.Closeable;
 import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
 import java.io.IOException;
 import java.io.RandomAccessFile;
 import java.nio.channels.Channels;
@@ -81,6 +84,7 @@ import java.util.Comparator;
 import java.util.Date;
 import java.util.HashSet;
 import java.util.List;
+import java.util.Optional;
 import java.util.function.Supplier;
 
 public class SignalAccount implements Closeable {
@@ -467,6 +471,10 @@ public class SignalAccount implements Closeable {
         return new File(getUserPath(dataPath, account), "recipients-store");
     }
 
+    private static File getStorageManifestFile(File dataPath, String account) {
+        return new File(getUserPath(dataPath, account), "storage-manifest");
+    }
+
     private static File getDatabaseFile(File dataPath, String account) {
         return new File(getUserPath(dataPath, account), "account.db");
     }
@@ -1274,6 +1282,30 @@ public class SignalAccount implements Closeable {
         save();
     }
 
+    public Optional<SignalStorageManifest> getStorageManifest() {
+        final var storageManifestFile = getStorageManifestFile(dataPath, accountPath);
+        if (!storageManifestFile.exists()) {
+            return Optional.empty();
+        }
+        try (var inputStream = new FileInputStream(storageManifestFile)) {
+            return Optional.of(SignalStorageManifest.deserialize(inputStream.readAllBytes()));
+        } catch (IOException e) {
+            logger.warn("Failed to read local storage manifest.", e);
+            return Optional.empty();
+        }
+    }
+
+    public void setStorageManifest(SignalStorageManifest manifest) {
+        final var manifestBytes = manifest.serialize();
+
+        final var storageManifestFile = getStorageManifestFile(dataPath, accountPath);
+        try (var outputStream = new FileOutputStream(storageManifestFile)) {
+            outputStream.write(manifestBytes);
+        } catch (IOException e) {
+            logger.error("Failed to store local storage manifest.", e);
+        }
+    }
+
     public ProfileKey getProfileKey() {
         return profileKey;
     }