]> nmode's Git Repositories - signal-cli/commitdiff
Improve behavior of changed recipient id
authorAsamK <asamk@gmx.de>
Mon, 6 Dec 2021 23:02:24 +0000 (00:02 +0100)
committerAsamK <asamk@gmx.de>
Mon, 6 Dec 2021 23:02:24 +0000 (00:02 +0100)
lib/src/main/java/org/asamk/signal/manager/storage/groups/GroupStore.java
lib/src/main/java/org/asamk/signal/manager/storage/identities/IdentityKeyStore.java
lib/src/main/java/org/asamk/signal/manager/storage/recipients/RecipientId.java
lib/src/main/java/org/asamk/signal/manager/storage/recipients/RecipientResolver.java
lib/src/main/java/org/asamk/signal/manager/storage/recipients/RecipientStore.java
lib/src/main/java/org/asamk/signal/manager/storage/senderKeys/SenderKeyRecordStore.java
lib/src/main/java/org/asamk/signal/manager/storage/senderKeys/SenderKeySharedStore.java
lib/src/main/java/org/asamk/signal/manager/storage/sessions/SessionStore.java

index cfa39bc9aaf4921477b3f351cb34671b7c17f42c..5d8bf2c1b9be6102c6a79e24658bfe81a6cebdb3 100644 (file)
@@ -36,6 +36,7 @@ import java.util.Base64;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
+import java.util.Objects;
 import java.util.stream.Collectors;
 
 public class GroupStore {
@@ -82,8 +83,8 @@ public class GroupStore {
                                 m.number));
                     }
 
-                    return RecipientId.of(m.recipientId);
-                }).collect(Collectors.toSet());
+                    return recipientResolver.resolveRecipient(m.recipientId);
+                }).filter(Objects::nonNull).collect(Collectors.toSet());
 
                 return new GroupInfoV1(GroupIdV1.fromBase64(g1.groupId),
                         g1.expectedV2Id == null ? null : GroupIdV2.fromBase64(g1.expectedV2Id),
index 9e89861ac82de89f8856f0cbca5736806818b82b..fef06c5bf067973920e0205ed1d3bf1619292bf9 100644 (file)
@@ -26,6 +26,7 @@ import java.util.Date;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
+import java.util.Objects;
 import java.util.regex.Pattern;
 import java.util.stream.Collectors;
 
@@ -161,7 +162,8 @@ public class IdentityKeyStore implements org.whispersystems.libsignal.state.Iden
         }
         return Arrays.stream(files)
                 .filter(f -> identityFileNamePattern.matcher(f.getName()).matches())
-                .map(f -> RecipientId.of(Integer.parseInt(f.getName())))
+                .map(f -> resolver.resolveRecipient(Long.parseLong(f.getName())))
+                .filter(Objects::nonNull)
                 .map(this::loadIdentityLocked)
                 .collect(Collectors.toList());
     }
index d7aa373dc6df0da85d450eb111e63a502697dddb..cea637ec08519fd6907fba4d601f0a86bce81e57 100644 (file)
@@ -1,8 +1,42 @@
 package org.asamk.signal.manager.storage.recipients;
 
-public record RecipientId(long id) {
+import java.util.Objects;
 
-    public static RecipientId of(long id) {
-        return new RecipientId(id);
+public final class RecipientId {
+
+    private long id;
+    private final RecipientStore recipientStore;
+
+    RecipientId(long id, final RecipientStore recipientStore) {
+        this.id = id;
+        this.recipientStore = recipientStore;
+    }
+
+    public long id() {
+        if (recipientStore != null) {
+            final var actualRecipientId = recipientStore.getActualRecipientId(this.id);
+            if (actualRecipientId != this.id) {
+                this.id = actualRecipientId;
+            }
+        }
+        return this.id;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (obj == this) return true;
+        if (obj == null || obj.getClass() != this.getClass()) return false;
+        var that = (RecipientId) obj;
+        return this.id() == that.id();
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(id());
+    }
+
+    @Override
+    public String toString() {
+        return "RecipientId[" + "id=" + id() + ']';
     }
 }
index 06747684f81e2f412b1d3ec247068a2418c7aca1..487001a0d01a12efd1aaac4996e9521d635c4ddb 100644 (file)
@@ -12,4 +12,6 @@ public interface RecipientResolver {
     RecipientId resolveRecipient(SignalServiceAddress address);
 
     RecipientId resolveRecipient(ACI aci);
+
+    RecipientId resolveRecipient(long recipientId);
 }
index 24f36b258e3c2196af6f38edb69ee48b9a370f28..706110db43cac7febbe67bad33d953ca5b7fe087 100644 (file)
@@ -44,7 +44,7 @@ public class RecipientStore implements RecipientResolver, ContactsStore, Profile
     private final RecipientMergeHandler recipientMergeHandler;
 
     private final Map<RecipientId, Recipient> recipients;
-    private final Map<RecipientId, RecipientId> recipientsMerged = new HashMap<>();
+    private final Map<Long, Long> recipientsMerged = new HashMap<>();
 
     private long lastId;
 
@@ -52,8 +52,14 @@ public class RecipientStore implements RecipientResolver, ContactsStore, Profile
         final var objectMapper = Utils.createStorageObjectMapper();
         try (var inputStream = new FileInputStream(file)) {
             final var storage = objectMapper.readValue(inputStream, Storage.class);
+
+            final var recipientStore = new RecipientStore(objectMapper,
+                    file,
+                    recipientMergeHandler,
+                    new HashMap<>(),
+                    storage.lastId);
             final var recipients = storage.recipients.stream().map(r -> {
-                final var recipientId = new RecipientId(r.id);
+                final var recipientId = new RecipientId(r.id, recipientStore);
                 final var address = new RecipientAddress(Optional.ofNullable(r.uuid).map(UuidUtil::parseOrThrow),
                         Optional.ofNullable(r.number));
 
@@ -101,7 +107,9 @@ public class RecipientStore implements RecipientResolver, ContactsStore, Profile
                 return new Recipient(recipientId, address, contact, profileKey, profileKeyCredential, profile);
             }).collect(Collectors.toMap(Recipient::getRecipientId, r -> r));
 
-            return new RecipientStore(objectMapper, file, recipientMergeHandler, recipients, storage.lastId);
+            recipientStore.addRecipients(recipients);
+
+            return recipientStore;
         } catch (FileNotFoundException e) {
             logger.debug("Creating new recipient store.");
             return new RecipientStore(objectMapper, file, recipientMergeHandler, new HashMap<>(), 0);
@@ -130,7 +138,6 @@ public class RecipientStore implements RecipientResolver, ContactsStore, Profile
 
     public Recipient getRecipient(RecipientId recipientId) {
         synchronized (recipients) {
-            recipientId = getActualRecipientId(recipientId);
             return recipients.get(recipientId);
         }
     }
@@ -140,6 +147,12 @@ public class RecipientStore implements RecipientResolver, ContactsStore, Profile
         return resolveRecipient(new RecipientAddress(aci == null ? null : aci.uuid()), false);
     }
 
+    @Override
+    public RecipientId resolveRecipient(final long recipientId) {
+        final var recipient = getRecipient(new RecipientId(recipientId, this));
+        return recipient == null ? null : recipient.getRecipientId();
+    }
+
     @Override
     public RecipientId resolveRecipient(final String identifier) {
         return resolveRecipient(Utils.getRecipientAddressFromIdentifier(identifier), false);
@@ -201,7 +214,6 @@ public class RecipientStore implements RecipientResolver, ContactsStore, Profile
     @Override
     public void storeContact(RecipientId recipientId, final Contact contact) {
         synchronized (recipients) {
-            recipientId = getActualRecipientId(recipientId);
             final var recipient = recipients.get(recipientId);
             storeRecipientLocked(recipientId, Recipient.newBuilder(recipient).withContact(contact).build());
         }
@@ -225,7 +237,6 @@ public class RecipientStore implements RecipientResolver, ContactsStore, Profile
     @Override
     public void deleteContact(RecipientId recipientId) {
         synchronized (recipients) {
-            recipientId = getActualRecipientId(recipientId);
             final var recipient = recipients.get(recipientId);
             storeRecipientLocked(recipientId, Recipient.newBuilder(recipient).withContact(null).build());
         }
@@ -233,7 +244,6 @@ public class RecipientStore implements RecipientResolver, ContactsStore, Profile
 
     public void deleteRecipientData(RecipientId recipientId) {
         synchronized (recipients) {
-            recipientId = getActualRecipientId(recipientId);
             logger.debug("Deleting recipient data for {}", recipientId);
             final var recipient = recipients.get(recipientId);
             storeRecipientLocked(recipientId,
@@ -265,7 +275,6 @@ public class RecipientStore implements RecipientResolver, ContactsStore, Profile
     @Override
     public void storeProfile(RecipientId recipientId, final Profile profile) {
         synchronized (recipients) {
-            recipientId = getActualRecipientId(recipientId);
             final var recipient = recipients.get(recipientId);
             storeRecipientLocked(recipientId, Recipient.newBuilder(recipient).withProfile(profile).build());
         }
@@ -274,7 +283,6 @@ public class RecipientStore implements RecipientResolver, ContactsStore, Profile
     @Override
     public void storeProfileKey(RecipientId recipientId, final ProfileKey profileKey) {
         synchronized (recipients) {
-            recipientId = getActualRecipientId(recipientId);
             final var recipient = recipients.get(recipientId);
             if (profileKey != null && profileKey.equals(recipient.getProfileKey())) {
                 return;
@@ -294,7 +302,6 @@ public class RecipientStore implements RecipientResolver, ContactsStore, Profile
     @Override
     public void storeProfileKeyCredential(RecipientId recipientId, final ProfileKeyCredential profileKeyCredential) {
         synchronized (recipients) {
-            recipientId = getActualRecipientId(recipientId);
             final var recipient = recipients.get(recipientId);
             storeRecipientLocked(recipientId,
                     Recipient.newBuilder(recipient).withProfileKeyCredential(profileKeyCredential).build());
@@ -307,6 +314,10 @@ public class RecipientStore implements RecipientResolver, ContactsStore, Profile
         }
     }
 
+    private void addRecipients(final Map<RecipientId, Recipient> recipients) {
+        this.recipients.putAll(recipients);
+    }
+
     /**
      * @param isHighTrust true, if the number/uuid connection was obtained from a trusted source.
      *                    Has no effect, if the address contains only a number or a uuid.
@@ -391,8 +402,10 @@ public class RecipientStore implements RecipientResolver, ContactsStore, Profile
                 byNumberRecipient.getRecipientId(),
                 byUuidRecipient.getRecipientId());
         updateRecipientAddressLocked(byUuidRecipient.getRecipientId(), address);
-        mergeRecipientsLocked(byUuidRecipient.getRecipientId(), byNumberRecipient.getRecipientId());
-        return new Pair<>(byUuidRecipient.getRecipientId(), byNumber.map(Recipient::getRecipientId));
+        // Create a fixed RecipientId that won't update its id after merge
+        final var toBeMergedRecipientId = new RecipientId(byNumberRecipient.getRecipientId().id(), null);
+        mergeRecipientsLocked(byUuidRecipient.getRecipientId(), toBeMergedRecipientId);
+        return new Pair<>(byUuidRecipient.getRecipientId(), Optional.of(toBeMergedRecipientId));
     }
 
     private RecipientId addNewRecipientLocked(final RecipientAddress address) {
@@ -403,12 +416,11 @@ public class RecipientStore implements RecipientResolver, ContactsStore, Profile
     }
 
     private void updateRecipientAddressLocked(RecipientId recipientId, final RecipientAddress address) {
-        recipientId = getActualRecipientId(recipientId);
         final var recipient = recipients.get(recipientId);
         storeRecipientLocked(recipientId, Recipient.newBuilder(recipient).withAddress(address).build());
     }
 
-    private RecipientId getActualRecipientId(RecipientId recipientId) {
+    long getActualRecipientId(long recipientId) {
         while (recipientsMerged.containsKey(recipientId)) {
             final var newRecipientId = recipientsMerged.get(recipientId);
             logger.debug("Using {} instead of {}, because recipients have been merged", newRecipientId, recipientId);
@@ -440,7 +452,7 @@ public class RecipientStore implements RecipientResolver, ContactsStore, Profile
                                 : toBeMergedRecipient.getProfileKeyCredential(),
                         recipient.getProfile() != null ? recipient.getProfile() : toBeMergedRecipient.getProfile()));
         recipients.remove(toBeMergedRecipientId);
-        recipientsMerged.put(toBeMergedRecipientId, recipientId);
+        recipientsMerged.put(toBeMergedRecipientId.id(), recipientId.id());
         saveLocked();
     }
 
@@ -467,7 +479,7 @@ public class RecipientStore implements RecipientResolver, ContactsStore, Profile
     }
 
     private RecipientId nextIdLocked() {
-        return new RecipientId(++this.lastId);
+        return new RecipientId(++this.lastId, this);
     }
 
     private void saveLocked() {
index fb26fa007f532d7f0e199bbb903afd1fb2175129..caddebcc62528e07b05fa226b3b9eaad1d970ef3 100644 (file)
@@ -17,6 +17,7 @@ import java.util.Arrays;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
+import java.util.Objects;
 import java.util.UUID;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
@@ -139,9 +140,14 @@ public class SenderKeyRecordStore implements org.whispersystems.libsignal.groups
         return Arrays.stream(files)
                 .map(f -> senderKeyFileNamePattern.matcher(f.getName()))
                 .filter(Matcher::matches)
-                .map(matcher -> new Key(RecipientId.of(Long.parseLong(matcher.group(1))),
-                        Integer.parseInt(matcher.group(2)),
-                        UUID.fromString(matcher.group(3))))
+                .map(matcher -> {
+                    final var recipientId = resolver.resolveRecipient(Long.parseLong(matcher.group(1)));
+                    if (recipientId == null) {
+                        return null;
+                    }
+                    return new Key(recipientId, Integer.parseInt(matcher.group(2)), UUID.fromString(matcher.group(3)));
+                })
+                .filter(Objects::nonNull)
                 .collect(Collectors.toList());
     }
 
index 08197aec1e51f02d453289f31a9e373a1150f55f..ba85233816954f27ea647d481cde81eb688bf007 100644 (file)
@@ -47,7 +47,11 @@ public class SenderKeySharedStore {
             final var storage = objectMapper.readValue(inputStream, Storage.class);
             final var sharedSenderKeys = new HashMap<DistributionId, Set<SenderKeySharedEntry>>();
             for (final var senderKey : storage.sharedSenderKeys) {
-                final var entry = new SenderKeySharedEntry(RecipientId.of(senderKey.recipientId), senderKey.deviceId);
+                final var recipientId = resolver.resolveRecipient(senderKey.recipientId);
+                if (recipientId == null) {
+                    continue;
+                }
+                final var entry = new SenderKeySharedEntry(recipientId, senderKey.deviceId);
                 final var uuid = UuidUtil.parseOrNull(senderKey.distributionId);
                 if (uuid == null) {
                     logger.warn("Read invalid distribution id from storage {}, ignoring", senderKey.distributionId);
index 627ef45ec270656a35545f409b92854a8bbf62e6..8011a69d5ce4e1e9c4d3aa3361cdbc3c5ace9a1f 100644 (file)
@@ -238,8 +238,14 @@ public class SessionStore implements SignalServiceSessionStore {
         return Arrays.stream(files)
                 .map(f -> sessionFileNamePattern.matcher(f.getName()))
                 .filter(Matcher::matches)
-                .map(matcher -> new Key(RecipientId.of(Long.parseLong(matcher.group(1))),
-                        Integer.parseInt(matcher.group(2))))
+                .map(matcher -> {
+                    final var recipientId = resolver.resolveRecipient(Long.parseLong(matcher.group(1)));
+                    if (recipientId == null) {
+                        return null;
+                    }
+                    return new Key(recipientId, Integer.parseInt(matcher.group(2)));
+                })
+                .filter(Objects::nonNull)
                 .collect(Collectors.toList());
     }