]> nmode's Git Repositories - signal-cli/commitdiff
Update libsignal-service-java
authorAsamK <asamk@gmx.de>
Thu, 26 Aug 2021 19:23:30 +0000 (21:23 +0200)
committerAsamK <asamk@gmx.de>
Sun, 29 Aug 2021 11:37:24 +0000 (13:37 +0200)
52 files changed:
lib/build.gradle.kts
lib/src/main/java/org/asamk/signal/manager/AvatarStore.java
lib/src/main/java/org/asamk/signal/manager/Manager.java
lib/src/main/java/org/asamk/signal/manager/UntrustedIdentityException.java [new file with mode: 0644]
lib/src/main/java/org/asamk/signal/manager/api/RecipientIdentifier.java
lib/src/main/java/org/asamk/signal/manager/helper/GroupV2Helper.java
lib/src/main/java/org/asamk/signal/manager/helper/IncomingMessageHandler.java
lib/src/main/java/org/asamk/signal/manager/helper/ProfileHelper.java
lib/src/main/java/org/asamk/signal/manager/helper/SendHelper.java
lib/src/main/java/org/asamk/signal/manager/helper/SyncHelper.java
lib/src/main/java/org/asamk/signal/manager/storage/SignalAccount.java
lib/src/main/java/org/asamk/signal/manager/storage/Utils.java
lib/src/main/java/org/asamk/signal/manager/storage/contacts/LegacyContactInfo.java
lib/src/main/java/org/asamk/signal/manager/storage/groups/GroupInfoV2.java
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/profiles/LegacyProfileStore.java
lib/src/main/java/org/asamk/signal/manager/storage/profiles/LegacySignalProfileEntry.java
lib/src/main/java/org/asamk/signal/manager/storage/protocol/LegacyIdentityInfo.java
lib/src/main/java/org/asamk/signal/manager/storage/protocol/LegacyJsonIdentityKeyStore.java
lib/src/main/java/org/asamk/signal/manager/storage/protocol/LegacyJsonSessionStore.java
lib/src/main/java/org/asamk/signal/manager/storage/protocol/LegacySessionInfo.java
lib/src/main/java/org/asamk/signal/manager/storage/protocol/SignalProtocolStore.java
lib/src/main/java/org/asamk/signal/manager/storage/recipients/LegacyRecipientStore.java
lib/src/main/java/org/asamk/signal/manager/storage/recipients/Recipient.java
lib/src/main/java/org/asamk/signal/manager/storage/recipients/RecipientAddress.java [new file with mode: 0644]
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/sessions/SessionStore.java
lib/src/main/java/org/asamk/signal/manager/util/Utils.java
run_tests.sh
src/main/java/org/asamk/signal/JsonDbusReceiveMessageHandler.java
src/main/java/org/asamk/signal/ReceiveMessageHandler.java
src/main/java/org/asamk/signal/commands/JoinGroupCommand.java
src/main/java/org/asamk/signal/commands/ListContactsCommand.java
src/main/java/org/asamk/signal/commands/ListGroupsCommand.java
src/main/java/org/asamk/signal/commands/ListIdentitiesCommand.java
src/main/java/org/asamk/signal/commands/QuitGroupCommand.java
src/main/java/org/asamk/signal/commands/RemoteDeleteCommand.java
src/main/java/org/asamk/signal/commands/SendCommand.java
src/main/java/org/asamk/signal/commands/SendReactionCommand.java
src/main/java/org/asamk/signal/commands/SendReceiptCommand.java
src/main/java/org/asamk/signal/commands/SendTypingCommand.java
src/main/java/org/asamk/signal/commands/UpdateGroupCommand.java
src/main/java/org/asamk/signal/dbus/DbusSignalImpl.java
src/main/java/org/asamk/signal/json/JsonMention.java
src/main/java/org/asamk/signal/json/JsonMessageEnvelope.java
src/main/java/org/asamk/signal/json/JsonQuote.java
src/main/java/org/asamk/signal/json/JsonReaction.java
src/main/java/org/asamk/signal/json/JsonSyncDataMessage.java
src/main/java/org/asamk/signal/json/JsonSyncReadMessage.java
src/main/java/org/asamk/signal/util/Util.java

index dcb99cee9e9a4dbb3c849e5660e4ec71d1327bcb..316ce564e0093484e4cf17c40d1c02c32ab60a3b 100644 (file)
@@ -14,7 +14,7 @@ repositories {
 }
 
 dependencies {
-    api("com.github.turasa:signal-service-java:2.15.3_unofficial_25")
+    api("com.github.turasa:signal-service-java:2.15.3_unofficial_26")
     implementation("com.google.protobuf:protobuf-javalite:3.10.0")
     implementation("org.bouncycastle:bcprov-jdk15on:1.69")
     implementation("org.slf4j:slf4j-api:1.7.30")
index 8a1e61729872e9befc26f7f488f569c57382a30e..12a6525e4de68aff21482e9761f8fb9fa9d23074 100644 (file)
@@ -82,7 +82,7 @@ public class AvatarStore {
     }
 
     private String getLegacyIdentifier(final SignalServiceAddress address) {
-        return address.getNumber().or(() -> address.getUuid().get().toString());
+        return address.getNumber().or(() -> address.getUuid().toString());
     }
 
     private File getProfileAvatarFile(SignalServiceAddress address) {
index bbdfa9e5ed817dac407586114b715193677aa91a..9e38853bfa4cbc97614c390bc4df1f30124386d1 100644 (file)
@@ -73,7 +73,6 @@ import org.whispersystems.libsignal.state.SignedPreKeyRecord;
 import org.whispersystems.libsignal.util.Pair;
 import org.whispersystems.libsignal.util.guava.Optional;
 import org.whispersystems.signalservice.api.SignalSessionLock;
-import org.whispersystems.signalservice.api.crypto.UntrustedIdentityException;
 import org.whispersystems.signalservice.api.groupsv2.GroupLinkNotActiveException;
 import org.whispersystems.signalservice.api.messages.SendMessageResult;
 import org.whispersystems.signalservice.api.messages.SignalServiceAttachmentRemoteId;
@@ -83,6 +82,7 @@ import org.whispersystems.signalservice.api.messages.SignalServiceEnvelope;
 import org.whispersystems.signalservice.api.messages.SignalServiceReceiptMessage;
 import org.whispersystems.signalservice.api.messages.SignalServiceTypingMessage;
 import org.whispersystems.signalservice.api.push.SignalServiceAddress;
+import org.whispersystems.signalservice.api.push.exceptions.UnregisteredUserException;
 import org.whispersystems.signalservice.api.util.DeviceNameUtil;
 import org.whispersystems.signalservice.api.util.InvalidNumberException;
 import org.whispersystems.signalservice.api.util.PhoneNumberFormatter;
@@ -200,7 +200,7 @@ public class Manager implements Closeable {
                 dependencies,
                 unidentifiedAccessHelper,
                 this::resolveSignalServiceAddress,
-                this::resolveRecipient,
+                account.getRecipientStore(),
                 this::handleIdentityFailure,
                 this::getGroup,
                 this::refreshRegisteredUser);
@@ -211,15 +211,14 @@ public class Manager implements Closeable {
                 groupV2Helper,
                 avatarStore,
                 this::resolveSignalServiceAddress,
-                this::resolveRecipient);
+                account.getRecipientStore());
         this.contactHelper = new ContactHelper(account);
         this.syncHelper = new SyncHelper(account,
                 attachmentHelper,
                 sendHelper,
                 groupHelper,
                 avatarStore,
-                this::resolveSignalServiceAddress,
-                this::resolveRecipient);
+                this::resolveSignalServiceAddress);
 
         this.context = new Context(account,
                 dependencies.getAccountManager(),
@@ -233,7 +232,8 @@ public class Manager implements Closeable {
 
         this.incomingMessageHandler = new IncomingMessageHandler(account,
                 dependencies,
-                this::resolveRecipient,
+                account.getRecipientStore(),
+                this::resolveSignalServiceAddress,
                 groupHelper,
                 contactHelper,
                 attachmentHelper,
@@ -328,7 +328,7 @@ public class Manager implements Closeable {
     public Map<String, Pair<String, UUID>> areUsersRegistered(Set<String> numbers) throws IOException {
         Map<String, String> canonicalizedNumbers = numbers.stream().collect(Collectors.toMap(n -> n, n -> {
             try {
-                return canonicalizePhoneNumber(n);
+                return PhoneNumberFormatter.formatNumber(n, account.getUsername());
             } catch (InvalidNumberException e) {
                 return "";
             }
@@ -490,7 +490,7 @@ public class Manager implements Closeable {
     public SendGroupMessageResults quitGroup(
             GroupId groupId, Set<RecipientIdentifier.Single> groupAdmins
     ) throws GroupNotFoundException, IOException, NotAGroupMemberException, LastGroupAdminException {
-        final var newAdmins = getRecipientIds(groupAdmins);
+        final var newAdmins = resolveRecipients(groupAdmins);
         return groupHelper.quitGroup(groupId, newAdmins);
     }
 
@@ -501,7 +501,7 @@ public class Manager implements Closeable {
     public Pair<GroupId, SendGroupMessageResults> createGroup(
             String name, Set<RecipientIdentifier.Single> members, File avatarFile
     ) throws IOException, AttachmentInvalidException {
-        return groupHelper.createGroup(name, members == null ? null : getRecipientIds(members), avatarFile);
+        return groupHelper.createGroup(name, members == null ? null : resolveRecipients(members), avatarFile);
     }
 
     public SendGroupMessageResults updateGroup(
@@ -523,10 +523,10 @@ public class Manager implements Closeable {
         return groupHelper.updateGroup(groupId,
                 name,
                 description,
-                members == null ? null : getRecipientIds(members),
-                removeMembers == null ? null : getRecipientIds(removeMembers),
-                admins == null ? null : getRecipientIds(admins),
-                removeAdmins == null ? null : getRecipientIds(removeAdmins),
+                members == null ? null : resolveRecipients(members),
+                removeMembers == null ? null : resolveRecipients(removeMembers),
+                admins == null ? null : resolveRecipients(admins),
+                removeAdmins == null ? null : resolveRecipients(removeAdmins),
                 resetGroupLink,
                 groupLinkState,
                 addMemberPermission,
@@ -662,7 +662,7 @@ public class Manager implements Closeable {
 
     public void setContactName(
             RecipientIdentifier.Single recipient, String name
-    ) throws NotMasterDeviceException {
+    ) throws NotMasterDeviceException, UnregisteredUserException {
         if (!account.isMasterDevice()) {
             throw new NotMasterDeviceException();
         }
@@ -755,53 +755,28 @@ public class Manager implements Closeable {
         return certificate;
     }
 
-    private Set<RecipientId> getRecipientIds(Collection<RecipientIdentifier.Single> recipients) {
-        final var signalServiceAddresses = new HashSet<SignalServiceAddress>(recipients.size());
-        final var addressesMissingUuid = new HashSet<SignalServiceAddress>();
-
-        for (var number : recipients) {
-            final var resolvedAddress = resolveSignalServiceAddress(resolveRecipient(number));
-            if (resolvedAddress.getUuid().isPresent()) {
-                signalServiceAddresses.add(resolvedAddress);
-            } else {
-                addressesMissingUuid.add(resolvedAddress);
-            }
-        }
-
-        final var numbersMissingUuid = addressesMissingUuid.stream()
-                .map(a -> a.getNumber().get())
-                .collect(Collectors.toSet());
-        Map<String, UUID> registeredUsers;
-        try {
-            registeredUsers = getRegisteredUsers(numbersMissingUuid);
-        } catch (IOException e) {
-            logger.warn("Failed to resolve uuids from server, ignoring: {}", e.getMessage());
-            registeredUsers = Map.of();
-        }
-
-        for (var address : addressesMissingUuid) {
-            final var number = address.getNumber().get();
-            if (registeredUsers.containsKey(number)) {
-                final var newAddress = resolveSignalServiceAddress(resolveRecipientTrusted(new SignalServiceAddress(
-                        registeredUsers.get(number),
-                        number)));
-                signalServiceAddresses.add(newAddress);
-            } else {
-                signalServiceAddresses.add(address);
-            }
-        }
-
-        return signalServiceAddresses.stream().map(this::resolveRecipient).collect(Collectors.toSet());
-    }
-
     private RecipientId refreshRegisteredUser(RecipientId recipientId) throws IOException {
         final var address = resolveSignalServiceAddress(recipientId);
         if (!address.getNumber().isPresent()) {
             return recipientId;
         }
         final var number = address.getNumber().get();
-        final var uuidMap = getRegisteredUsers(Set.of(number));
-        return resolveRecipientTrusted(new SignalServiceAddress(uuidMap.getOrDefault(number, null), number));
+        final var uuid = getRegisteredUser(number);
+        return resolveRecipientTrusted(new SignalServiceAddress(uuid, number));
+    }
+
+    private UUID getRegisteredUser(final String number) throws IOException {
+        final Map<String, UUID> uuidMap;
+        try {
+            uuidMap = getRegisteredUsers(Set.of(number));
+        } catch (NumberFormatException e) {
+            throw new UnregisteredUserException(number, e);
+        }
+        final var uuid = uuidMap.get(number);
+        if (uuid == null) {
+            throw new UnregisteredUserException(number, null);
+        }
+        return uuid;
     }
 
     private Map<String, UUID> getRegisteredUsers(final Set<String> numbers) throws IOException {
@@ -856,9 +831,9 @@ public class Manager implements Closeable {
                     cachedMessage.delete();
                     return null;
                 }
-                if (!envelope.hasSource()) {
+                if (!envelope.hasSourceUuid()) {
                     final var identifier = e.getSender();
-                    final var recipientId = resolveRecipient(identifier);
+                    final var recipientId = account.getRecipientStore().resolveRecipient(identifier);
                     try {
                         account.getMessageCache().replaceSender(cachedMessage, recipientId);
                     } catch (IOException ioException) {
@@ -901,8 +876,8 @@ public class Manager implements Closeable {
             logger.debug("Checking for new message from server");
             try {
                 var result = signalWebSocket.readOrEmpty(unit.toMillis(timeout), envelope1 -> {
-                    final var recipientId = envelope1.hasSource()
-                            ? resolveRecipient(envelope1.getSourceIdentifier())
+                    final var recipientId = envelope1.hasSourceUuid()
+                            ? resolveRecipient(envelope1.getSourceAddress())
                             : null;
                     // store message on disk, before acknowledging receipt to the server
                     cachedMessage[0] = account.getMessageCache().cacheMessage(envelope1, recipientId);
@@ -944,10 +919,10 @@ public class Manager implements Closeable {
                 handleQueuedActions(queuedActions);
             }
             if (cachedMessage[0] != null) {
-                if (exception instanceof ProtocolUntrustedIdentityException) {
-                    final var identifier = ((ProtocolUntrustedIdentityException) exception).getSender();
-                    final var recipientId = resolveRecipient(identifier);
-                    if (!envelope.hasSource()) {
+                if (exception instanceof UntrustedIdentityException) {
+                    final var address = ((UntrustedIdentityException) exception).getSender();
+                    final var recipientId = resolveRecipient(address);
+                    if (!envelope.hasSourceUuid()) {
                         try {
                             cachedMessage[0] = account.getMessageCache().replaceSender(cachedMessage[0], recipientId);
                         } catch (IOException ioException) {
@@ -977,7 +952,12 @@ public class Manager implements Closeable {
     }
 
     public boolean isContactBlocked(final RecipientIdentifier.Single recipient) {
-        final var recipientId = resolveRecipient(recipient);
+        final RecipientId recipientId;
+        try {
+            recipientId = resolveRecipient(recipient);
+        } catch (UnregisteredUserException e) {
+            return false;
+        }
         return contactHelper.isContactBlocked(recipientId);
     }
 
@@ -994,7 +974,12 @@ public class Manager implements Closeable {
     }
 
     public String getContactOrProfileName(RecipientIdentifier.Single recipientIdentifier) {
-        final var recipientId = resolveRecipient(recipientIdentifier);
+        final RecipientId recipientId;
+        try {
+            recipientId = resolveRecipient(recipientIdentifier);
+        } catch (UnregisteredUserException e) {
+            return null;
+        }
 
         final var contact = account.getContactStore().getContact(recipientId);
         if (contact != null && !Util.isEmpty(contact.getName())) {
@@ -1018,7 +1003,12 @@ public class Manager implements Closeable {
     }
 
     public List<IdentityInfo> getIdentities(RecipientIdentifier.Single recipient) {
-        final var identity = account.getIdentityKeyStore().getIdentity(resolveRecipient(recipient));
+        IdentityInfo identity;
+        try {
+            identity = account.getIdentityKeyStore().getIdentity(resolveRecipient(recipient));
+        } catch (UnregisteredUserException e) {
+            identity = null;
+        }
         return identity == null ? List.of() : List.of(identity);
     }
 
@@ -1029,7 +1019,12 @@ public class Manager implements Closeable {
      * @param fingerprint Fingerprint
      */
     public boolean trustIdentityVerified(RecipientIdentifier.Single recipient, byte[] fingerprint) {
-        var recipientId = resolveRecipient(recipient);
+        RecipientId recipientId;
+        try {
+            recipientId = resolveRecipient(recipient);
+        } catch (UnregisteredUserException e) {
+            return false;
+        }
         return trustIdentity(recipientId,
                 identityKey -> Arrays.equals(identityKey.serialize(), fingerprint),
                 TrustLevel.TRUSTED_VERIFIED);
@@ -1042,8 +1037,13 @@ public class Manager implements Closeable {
      * @param safetyNumber Safety number
      */
     public boolean trustIdentityVerifiedSafetyNumber(RecipientIdentifier.Single recipient, String safetyNumber) {
-        var recipientId = resolveRecipient(recipient);
-        var address = account.getRecipientStore().resolveServiceAddress(recipientId);
+        RecipientId recipientId;
+        try {
+            recipientId = resolveRecipient(recipient);
+        } catch (UnregisteredUserException e) {
+            return false;
+        }
+        var address = resolveSignalServiceAddress(recipientId);
         return trustIdentity(recipientId,
                 identityKey -> safetyNumber.equals(computeSafetyNumber(address, identityKey)),
                 TrustLevel.TRUSTED_VERIFIED);
@@ -1056,8 +1056,13 @@ public class Manager implements Closeable {
      * @param safetyNumber Scannable safety number
      */
     public boolean trustIdentityVerifiedSafetyNumber(RecipientIdentifier.Single recipient, byte[] safetyNumber) {
-        var recipientId = resolveRecipient(recipient);
-        var address = account.getRecipientStore().resolveServiceAddress(recipientId);
+        RecipientId recipientId;
+        try {
+            recipientId = resolveRecipient(recipient);
+        } catch (UnregisteredUserException e) {
+            return false;
+        }
+        var address = resolveSignalServiceAddress(recipientId);
         return trustIdentity(recipientId, identityKey -> {
             final var fingerprint = computeSafetyNumberFingerprint(address, identityKey);
             try {
@@ -1074,7 +1079,12 @@ public class Manager implements Closeable {
      * @param recipient username of the identity
      */
     public boolean trustIdentityAllKeys(RecipientIdentifier.Single recipient) {
-        var recipientId = resolveRecipient(recipient);
+        RecipientId recipientId;
+        try {
+            recipientId = resolveRecipient(recipient);
+        } catch (UnregisteredUserException e) {
+            return false;
+        }
         return trustIdentity(recipientId, identityKey -> true, TrustLevel.TRUSTED_UNVERIFIED);
     }
 
@@ -1092,7 +1102,7 @@ public class Manager implements Closeable {
 
         account.getIdentityKeyStore().setIdentityTrustLevel(recipientId, identity.getIdentityKey(), trustLevel);
         try {
-            var address = account.getRecipientStore().resolveServiceAddress(recipientId);
+            var address = resolveSignalServiceAddress(recipientId);
             syncHelper.sendVerifiedMessage(address, identity.getIdentityKey(), trustLevel);
         } catch (IOException e) {
             logger.warn("Failed to send verification sync message: {}", e.getMessage());
@@ -1136,48 +1146,61 @@ public class Manager implements Closeable {
                 theirIdentityKey);
     }
 
-    @Deprecated
-    public SignalServiceAddress resolveSignalServiceAddress(String identifier) {
-        var address = Utils.getSignalServiceAddressFromIdentifier(identifier);
-
-        return resolveSignalServiceAddress(address);
-    }
-
-    @Deprecated
     public SignalServiceAddress resolveSignalServiceAddress(SignalServiceAddress address) {
         if (address.matches(account.getSelfAddress())) {
             return account.getSelfAddress();
         }
 
-        return account.getRecipientStore().resolveServiceAddress(address);
+        return resolveSignalServiceAddress(resolveRecipient(address));
     }
 
-    public SignalServiceAddress resolveSignalServiceAddress(RecipientId recipientId) {
-        return account.getRecipientStore().resolveServiceAddress(recipientId);
+    public SignalServiceAddress resolveSignalServiceAddress(UUID uuid) {
+        return resolveSignalServiceAddress(account.getRecipientStore().resolveRecipient(uuid));
     }
 
-    private String canonicalizePhoneNumber(final String number) throws InvalidNumberException {
-        return PhoneNumberFormatter.formatNumber(number, account.getUsername());
-    }
+    public SignalServiceAddress resolveSignalServiceAddress(RecipientId recipientId) {
+        final var address = account.getRecipientStore().resolveRecipientAddress(recipientId);
+        if (address.getUuid().isPresent()) {
+            return address.toSignalServiceAddress();
+        }
 
-    private RecipientId resolveRecipient(final String identifier) {
-        var address = Utils.getSignalServiceAddressFromIdentifier(identifier);
+        // Address in recipient store doesn't have a uuid, this shouldn't happen
+        // Try to retrieve the uuid from the server
+        final var number = address.getNumber().get();
+        try {
+            return resolveSignalServiceAddress(getRegisteredUser(number));
+        } catch (IOException e) {
+            logger.warn("Failed to get uuid for e164 number: {}", number, e);
+            // Return SignalServiceAddress with unknown UUID
+            return address.toSignalServiceAddress();
+        }
+    }
 
-        return resolveRecipient(address);
+    private Set<RecipientId> resolveRecipients(Collection<RecipientIdentifier.Single> recipients) throws UnregisteredUserException {
+        final var recipientIds = new HashSet<RecipientId>(recipients.size());
+        for (var number : recipients) {
+            final var recipientId = resolveRecipient(number);
+            recipientIds.add(recipientId);
+        }
+        return recipientIds;
     }
 
-    private RecipientId resolveRecipient(final RecipientIdentifier.Single recipient) {
-        final SignalServiceAddress address;
+    private RecipientId resolveRecipient(final RecipientIdentifier.Single recipient) throws UnregisteredUserException {
         if (recipient instanceof RecipientIdentifier.Uuid) {
-            address = new SignalServiceAddress(((RecipientIdentifier.Uuid) recipient).uuid, null);
+            return account.getRecipientStore().resolveRecipient(((RecipientIdentifier.Uuid) recipient).uuid);
         } else {
-            address = new SignalServiceAddress(null, ((RecipientIdentifier.Number) recipient).number);
+            final var number = ((RecipientIdentifier.Number) recipient).number;
+            return account.getRecipientStore().resolveRecipient(number, () -> {
+                try {
+                    return getRegisteredUser(number);
+                } catch (IOException e) {
+                    return null;
+                }
+            });
         }
-
-        return resolveRecipient(address);
     }
 
-    public RecipientId resolveRecipient(SignalServiceAddress address) {
+    private RecipientId resolveRecipient(SignalServiceAddress address) {
         return account.getRecipientStore().resolveRecipient(address);
     }
 
diff --git a/lib/src/main/java/org/asamk/signal/manager/UntrustedIdentityException.java b/lib/src/main/java/org/asamk/signal/manager/UntrustedIdentityException.java
new file mode 100644 (file)
index 0000000..3b90b9e
--- /dev/null
@@ -0,0 +1,27 @@
+package org.asamk.signal.manager;
+
+import org.whispersystems.signalservice.api.push.SignalServiceAddress;
+
+public class UntrustedIdentityException extends Exception {
+
+    private final SignalServiceAddress sender;
+    private final Integer senderDevice;
+
+    public UntrustedIdentityException(final SignalServiceAddress sender) {
+        this(sender, null);
+    }
+
+    public UntrustedIdentityException(final SignalServiceAddress sender, final Integer senderDevice) {
+        super("Untrusted identity: " + sender.getIdentifier());
+        this.sender = sender;
+        this.senderDevice = senderDevice;
+    }
+
+    public SignalServiceAddress getSender() {
+        return sender;
+    }
+
+    public Integer getSenderDevice() {
+        return senderDevice;
+    }
+}
index cbcf17242c58736c9c83379f5f683d891faed8c2..4a66cbb37173ce2e9dce1db900ff75a6bc9267c3 100644 (file)
@@ -32,9 +32,7 @@ public abstract class RecipientIdentifier {
         }
 
         public static Single fromAddress(SignalServiceAddress address) {
-            return address.getUuid().isPresent()
-                    ? new Uuid(address.getUuid().get())
-                    : new Number(address.getNumber().get());
+            return new Uuid(address.getUuid());
         }
     }
 
index 19240cefc3178e0ea8b2592b55055e0ce363ebb0..3187fca1877c0a934bc324ff2a8a0c272ab0d120 100644 (file)
@@ -150,11 +150,9 @@ public class GroupV2Helper {
 
         if (!areMembersValid(members)) return null;
 
-        var self = new GroupCandidate(addressResolver.resolveSignalServiceAddress(selfRecipientIdProvider.getSelfRecipientId())
-                .getUuid()
-                .orNull(), Optional.fromNullable(profileKeyCredential));
+        var self = new GroupCandidate(getSelfUuid(), Optional.fromNullable(profileKeyCredential));
         var candidates = members.stream()
-                .map(member -> new GroupCandidate(addressResolver.resolveSignalServiceAddress(member).getUuid().get(),
+                .map(member -> new GroupCandidate(addressResolver.resolveSignalServiceAddress(member).getUuid(),
                         Optional.fromNullable(profileKeyCredentialProvider.getProfileKeyCredential(member))))
                 .collect(Collectors.toSet());
 
@@ -169,18 +167,6 @@ public class GroupV2Helper {
     }
 
     private boolean areMembersValid(final Set<RecipientId> members) {
-        final var noUuidCapability = members.stream()
-                .map(addressResolver::resolveSignalServiceAddress)
-                .filter(address -> !address.getUuid().isPresent())
-                .map(SignalServiceAddress::getNumber)
-                .map(Optional::get)
-                .collect(Collectors.toSet());
-        if (noUuidCapability.size() > 0) {
-            logger.warn("Cannot create a V2 group as some members don't have a UUID: {}",
-                    String.join(", ", noUuidCapability));
-            return false;
-        }
-
         final var noGv2Capability = members.stream()
                 .map(profileProvider::getProfile)
                 .filter(profile -> profile != null && !profile.getCapabilities().contains(Profile.Capability.gv2))
@@ -214,11 +200,8 @@ public class GroupV2Helper {
             change.setModifyAvatar(GroupChange.Actions.ModifyAvatarAction.newBuilder().setAvatar(avatarCdnKey));
         }
 
-        final var uuid = addressResolver.resolveSignalServiceAddress(this.selfRecipientIdProvider.getSelfRecipientId())
-                .getUuid();
-        if (uuid.isPresent()) {
-            change.setSourceUuid(UuidUtil.toByteString(uuid.get()));
-        }
+        final var uuid = getSelfUuid();
+        change.setSourceUuid(UuidUtil.toByteString(uuid));
 
         return commitChange(groupInfoV2, change);
     }
@@ -233,13 +216,11 @@ public class GroupV2Helper {
         }
 
         var candidates = newMembers.stream()
-                .map(member -> new GroupCandidate(addressResolver.resolveSignalServiceAddress(member).getUuid().get(),
+                .map(member -> new GroupCandidate(addressResolver.resolveSignalServiceAddress(member).getUuid(),
                         Optional.fromNullable(profileKeyCredentialProvider.getProfileKeyCredential(member))))
                 .collect(Collectors.toSet());
 
-        final var uuid = addressResolver.resolveSignalServiceAddress(selfRecipientIdProvider.getSelfRecipientId())
-                .getUuid()
-                .get();
+        final var uuid = getSelfUuid();
         final var change = groupOperations.createModifyGroupMembershipChange(candidates, uuid);
 
         change.setSourceUuid(UuidUtil.toByteString(uuid));
@@ -251,9 +232,7 @@ public class GroupV2Helper {
             GroupInfoV2 groupInfoV2, Set<RecipientId> membersToMakeAdmin
     ) throws IOException {
         var pendingMembersList = groupInfoV2.getGroup().getPendingMembersList();
-        final var selfUuid = addressResolver.resolveSignalServiceAddress(selfRecipientIdProvider.getSelfRecipientId())
-                .getUuid()
-                .get();
+        final var selfUuid = getSelfUuid();
         var selfPendingMember = DecryptedGroupUtil.findPendingByUuid(pendingMembersList, selfUuid);
 
         if (selfPendingMember.isPresent()) {
@@ -263,7 +242,6 @@ public class GroupV2Helper {
         final var adminUuids = membersToMakeAdmin.stream()
                 .map(addressResolver::resolveSignalServiceAddress)
                 .map(SignalServiceAddress::getUuid)
-                .map(Optional::get)
                 .collect(Collectors.toList());
         final GroupsV2Operations.GroupOperations groupOperations = getGroupOperations(groupInfoV2);
         return commitChange(groupInfoV2, groupOperations.createLeaveAndPromoteMembersToAdmin(selfUuid, adminUuids));
@@ -275,8 +253,6 @@ public class GroupV2Helper {
         final var memberUuids = members.stream()
                 .map(addressResolver::resolveSignalServiceAddress)
                 .map(SignalServiceAddress::getUuid)
-                .filter(Optional::isPresent)
-                .map(Optional::get)
                 .collect(Collectors.toSet());
         return ejectMembers(groupInfoV2, memberUuids);
     }
@@ -288,8 +264,6 @@ public class GroupV2Helper {
         final var memberUuids = members.stream()
                 .map(addressResolver::resolveSignalServiceAddress)
                 .map(SignalServiceAddress::getUuid)
-                .filter(Optional::isPresent)
-                .map(Optional::get)
                 .map(uuid -> DecryptedGroupUtil.findPendingByUuid(pendingMembersList, uuid))
                 .filter(Optional::isPresent)
                 .map(Optional::get)
@@ -360,8 +334,7 @@ public class GroupV2Helper {
                 : groupOperations.createGroupJoinDirect(profileKeyCredential);
 
         change.setSourceUuid(UuidUtil.toByteString(addressResolver.resolveSignalServiceAddress(selfRecipientId)
-                .getUuid()
-                .get()));
+                .getUuid()));
 
         return commitChange(groupSecretParams, decryptedGroupJoinInfo.getRevision(), change, groupLinkPassword);
     }
@@ -378,9 +351,7 @@ public class GroupV2Helper {
         final var change = groupOperations.createAcceptInviteChange(profileKeyCredential);
 
         final var uuid = addressResolver.resolveSignalServiceAddress(selfRecipientId).getUuid();
-        if (uuid.isPresent()) {
-            change.setSourceUuid(UuidUtil.toByteString(uuid.get()));
-        }
+        change.setSourceUuid(UuidUtil.toByteString(uuid));
 
         return commitChange(groupInfoV2, change);
     }
@@ -391,7 +362,7 @@ public class GroupV2Helper {
         final GroupsV2Operations.GroupOperations groupOperations = getGroupOperations(groupInfoV2);
         final var address = addressResolver.resolveSignalServiceAddress(recipientId);
         final var newRole = admin ? Member.Role.ADMINISTRATOR : Member.Role.DEFAULT;
-        final var change = groupOperations.createChangeMemberRole(address.getUuid().get(), newRole);
+        final var change = groupOperations.createChangeMemberRole(address.getUuid(), newRole);
         return commitChange(groupInfoV2, change);
     }
 
@@ -473,10 +444,7 @@ public class GroupV2Helper {
         final DecryptedGroup decryptedGroupState;
 
         try {
-            decryptedChange = groupOperations.decryptChange(changeActions,
-                    addressResolver.resolveSignalServiceAddress(selfRecipientIdProvider.getSelfRecipientId())
-                            .getUuid()
-                            .get());
+            decryptedChange = groupOperations.decryptChange(changeActions, getSelfUuid());
             decryptedGroupState = DecryptedGroupUtil.apply(previousGroupState, decryptedChange);
         } catch (VerificationFailedException | InvalidGroupStateException | NotAbleToApplyGroupV2ChangeException e) {
             throw new IOException(e);
@@ -543,13 +511,15 @@ public class GroupV2Helper {
         final var credentials = groupsV2Api.getCredentials(today);
         // TODO cache credentials until they expire
         var authCredentialResponse = credentials.get(today);
-        final var uuid = addressResolver.resolveSignalServiceAddress(this.selfRecipientIdProvider.getSelfRecipientId())
-                .getUuid()
-                .get();
+        final var uuid = getSelfUuid();
         try {
             return groupsV2Api.getGroupsV2AuthorizationString(uuid, today, groupSecretParams, authCredentialResponse);
         } catch (VerificationFailedException e) {
             throw new IOException(e);
         }
     }
+
+    private UUID getSelfUuid() {
+        return addressResolver.resolveSignalServiceAddress(this.selfRecipientIdProvider.getSelfRecipientId()).getUuid();
+    }
 }
index b0b42545676e68c178e17b7a8c9a8ce672caf6a9..f28b3638eb1f65ac90b6c62bd4a0489c1423a4e6 100644 (file)
@@ -4,6 +4,7 @@ import org.asamk.signal.manager.JobExecutor;
 import org.asamk.signal.manager.Manager;
 import org.asamk.signal.manager.SignalDependencies;
 import org.asamk.signal.manager.TrustLevel;
+import org.asamk.signal.manager.UntrustedIdentityException;
 import org.asamk.signal.manager.actions.HandleAction;
 import org.asamk.signal.manager.actions.RenewSessionAction;
 import org.asamk.signal.manager.actions.RetrieveProfileAction;
@@ -34,6 +35,7 @@ import org.whispersystems.signalservice.api.messages.SignalServiceContent;
 import org.whispersystems.signalservice.api.messages.SignalServiceDataMessage;
 import org.whispersystems.signalservice.api.messages.SignalServiceEnvelope;
 import org.whispersystems.signalservice.api.messages.SignalServiceGroup;
+import org.whispersystems.signalservice.api.messages.multidevice.SignalServiceSyncMessage;
 import org.whispersystems.signalservice.api.messages.multidevice.StickerPackOperationMessage;
 import org.whispersystems.signalservice.api.push.SignalServiceAddress;
 
@@ -48,6 +50,7 @@ public final class IncomingMessageHandler {
     private final SignalAccount account;
     private final SignalDependencies dependencies;
     private final RecipientResolver recipientResolver;
+    private final SignalServiceAddressResolver addressResolver;
     private final GroupHelper groupHelper;
     private final ContactHelper contactHelper;
     private final AttachmentHelper attachmentHelper;
@@ -58,6 +61,7 @@ public final class IncomingMessageHandler {
             final SignalAccount account,
             final SignalDependencies dependencies,
             final RecipientResolver recipientResolver,
+            final SignalServiceAddressResolver addressResolver,
             final GroupHelper groupHelper,
             final ContactHelper contactHelper,
             final AttachmentHelper attachmentHelper,
@@ -67,6 +71,7 @@ public final class IncomingMessageHandler {
         this.account = account;
         this.dependencies = dependencies;
         this.recipientResolver = recipientResolver;
+        this.addressResolver = addressResolver;
         this.groupHelper = groupHelper;
         this.contactHelper = contactHelper;
         this.attachmentHelper = attachmentHelper;
@@ -80,7 +85,7 @@ public final class IncomingMessageHandler {
             final Manager.ReceiveMessageHandler handler
     ) {
         final var actions = new ArrayList<HandleAction>();
-        if (envelope.hasSource()) {
+        if (envelope.hasSourceUuid()) {
             // Store uuid if we don't have it already
             // address/uuid in envelope is sent by server
             account.getRecipientStore().resolveRecipientTrusted(envelope.getSourceAddress());
@@ -93,6 +98,8 @@ public final class IncomingMessageHandler {
             } catch (ProtocolUntrustedIdentityException e) {
                 final var recipientId = account.getRecipientStore().resolveRecipient(e.getSender());
                 actions.add(new RetrieveProfileAction(recipientId));
+                exception = new UntrustedIdentityException(addressResolver.resolveSignalServiceAddress(recipientId),
+                        e.getSenderDevice());
             } catch (ProtocolInvalidMessageException e) {
                 final var sender = account.getRecipientStore().resolveRecipient(e.getSender());
                 logger.debug("Received invalid message, queuing renew session action.");
@@ -102,7 +109,7 @@ public final class IncomingMessageHandler {
                 exception = e;
             }
 
-            if (!envelope.hasSource() && content != null) {
+            if (!envelope.hasSourceUuid() && content != null) {
                 // Store uuid if we don't have it already
                 // address/uuid is validated by unidentified sender certificate
                 account.getRecipientStore().resolveRecipientTrusted(content.getSender());
@@ -113,7 +120,7 @@ public final class IncomingMessageHandler {
             logger.info("Ignoring a message from blocked user/group: {}", envelope.getTimestamp());
         } else if (isNotAllowedToSendToGroup(envelope, content)) {
             logger.info("Ignoring a group message from an unauthorized sender (no member or admin): {} {}",
-                    (envelope.hasSource() ? envelope.getSourceAddress() : content.getSender()).getIdentifier(),
+                    (envelope.hasSourceUuid() ? envelope.getSourceAddress() : content.getSender()).getIdentifier(),
                     envelope.getTimestamp());
         } else {
             actions.addAll(handleMessage(envelope, content, ignoreAttachments));
@@ -126,146 +133,153 @@ public final class IncomingMessageHandler {
             SignalServiceEnvelope envelope, SignalServiceContent content, boolean ignoreAttachments
     ) {
         var actions = new ArrayList<HandleAction>();
-        if (content != null) {
-            final RecipientId sender;
-            if (!envelope.isUnidentifiedSender() && envelope.hasSource()) {
-                sender = recipientResolver.resolveRecipient(envelope.getSourceAddress());
-            } else {
-                sender = recipientResolver.resolveRecipient(content.getSender());
+        if (content == null) {
+            return actions;
+        }
+
+        final RecipientId sender;
+        if (!envelope.isUnidentifiedSender() && envelope.hasSourceUuid()) {
+            sender = recipientResolver.resolveRecipient(envelope.getSourceAddress());
+        } else {
+            sender = recipientResolver.resolveRecipient(content.getSender());
+        }
+
+        if (content.getDataMessage().isPresent()) {
+            var message = content.getDataMessage().get();
+
+            if (content.isNeedsReceipt()) {
+                actions.add(new SendReceiptAction(sender, message.getTimestamp()));
             }
 
-            if (content.getDataMessage().isPresent()) {
-                var message = content.getDataMessage().get();
+            actions.addAll(handleSignalServiceDataMessage(message,
+                    false,
+                    sender,
+                    account.getSelfRecipientId(),
+                    ignoreAttachments));
+        }
 
-                if (content.isNeedsReceipt()) {
-                    actions.add(new SendReceiptAction(sender, message.getTimestamp()));
-                }
+        if (content.getSyncMessage().isPresent()) {
+            var syncMessage = content.getSyncMessage().get();
+            actions.addAll(handleSyncMessage(syncMessage, sender, ignoreAttachments));
+        }
 
-                actions.addAll(handleSignalServiceDataMessage(message,
-                        false,
-                        sender,
-                        account.getSelfRecipientId(),
-                        ignoreAttachments));
+        return actions;
+    }
+
+    private List<HandleAction> handleSyncMessage(
+            final SignalServiceSyncMessage syncMessage, final RecipientId sender, final boolean ignoreAttachments
+    ) {
+        var actions = new ArrayList<HandleAction>();
+        account.setMultiDevice(true);
+        if (syncMessage.getSent().isPresent()) {
+            var message = syncMessage.getSent().get();
+            final var destination = message.getDestination().orNull();
+            actions.addAll(handleSignalServiceDataMessage(message.getMessage(),
+                    true,
+                    sender,
+                    destination == null ? null : recipientResolver.resolveRecipient(destination),
+                    ignoreAttachments));
+        }
+        if (syncMessage.getRequest().isPresent() && account.isMasterDevice()) {
+            var rm = syncMessage.getRequest().get();
+            if (rm.isContactsRequest()) {
+                actions.add(SendSyncContactsAction.create());
             }
-            if (content.getSyncMessage().isPresent()) {
-                account.setMultiDevice(true);
-                var syncMessage = content.getSyncMessage().get();
-                if (syncMessage.getSent().isPresent()) {
-                    var message = syncMessage.getSent().get();
-                    final var destination = message.getDestination().orNull();
-                    actions.addAll(handleSignalServiceDataMessage(message.getMessage(),
-                            true,
-                            sender,
-                            destination == null ? null : recipientResolver.resolveRecipient(destination),
-                            ignoreAttachments));
-                }
-                if (syncMessage.getRequest().isPresent() && account.isMasterDevice()) {
-                    var rm = syncMessage.getRequest().get();
-                    if (rm.isContactsRequest()) {
-                        actions.add(SendSyncContactsAction.create());
-                    }
-                    if (rm.isGroupsRequest()) {
-                        actions.add(SendSyncGroupsAction.create());
-                    }
-                    if (rm.isBlockedListRequest()) {
-                        actions.add(SendSyncBlockedListAction.create());
-                    }
-                    // TODO Handle rm.isConfigurationRequest(); rm.isKeysRequest();
+            if (rm.isGroupsRequest()) {
+                actions.add(SendSyncGroupsAction.create());
+            }
+            if (rm.isBlockedListRequest()) {
+                actions.add(SendSyncBlockedListAction.create());
+            }
+            // TODO Handle rm.isConfigurationRequest(); rm.isKeysRequest();
+        }
+        if (syncMessage.getGroups().isPresent()) {
+            logger.warn("Received a group v1 sync message, that can't be handled anymore, ignoring.");
+        }
+        if (syncMessage.getBlockedList().isPresent()) {
+            final var blockedListMessage = syncMessage.getBlockedList().get();
+            for (var address : blockedListMessage.getAddresses()) {
+                contactHelper.setContactBlocked(recipientResolver.resolveRecipient(address), true);
+            }
+            for (var groupId : blockedListMessage.getGroupIds()
+                    .stream()
+                    .map(GroupId::unknownVersion)
+                    .collect(Collectors.toSet())) {
+                try {
+                    groupHelper.setGroupBlocked(groupId, true);
+                } catch (GroupNotFoundException e) {
+                    logger.warn("BlockedListMessage contained groupID that was not found in GroupStore: {}",
+                            groupId.toBase64());
                 }
-                if (syncMessage.getGroups().isPresent()) {
-                    try {
-                        final var groupsMessage = syncMessage.getGroups().get();
-                        attachmentHelper.retrieveAttachment(groupsMessage, syncHelper::handleSyncDeviceGroups);
-                    } catch (Exception e) {
-                        logger.warn("Failed to handle received sync groups, ignoring: {}", e.getMessage());
-                    }
+            }
+        }
+        if (syncMessage.getContacts().isPresent()) {
+            try {
+                final var contactsMessage = syncMessage.getContacts().get();
+                attachmentHelper.retrieveAttachment(contactsMessage.getContactsStream(),
+                        syncHelper::handleSyncDeviceContacts);
+            } catch (Exception e) {
+                logger.warn("Failed to handle received sync contacts, ignoring: {}", e.getMessage());
+            }
+        }
+        if (syncMessage.getVerified().isPresent()) {
+            final var verifiedMessage = syncMessage.getVerified().get();
+            account.getIdentityKeyStore()
+                    .setIdentityTrustLevel(account.getRecipientStore()
+                                    .resolveRecipientTrusted(verifiedMessage.getDestination()),
+                            verifiedMessage.getIdentityKey(),
+                            TrustLevel.fromVerifiedState(verifiedMessage.getVerified()));
+        }
+        if (syncMessage.getStickerPackOperations().isPresent()) {
+            final var stickerPackOperationMessages = syncMessage.getStickerPackOperations().get();
+            for (var m : stickerPackOperationMessages) {
+                if (!m.getPackId().isPresent()) {
+                    continue;
                 }
-                if (syncMessage.getBlockedList().isPresent()) {
-                    final var blockedListMessage = syncMessage.getBlockedList().get();
-                    for (var address : blockedListMessage.getAddresses()) {
-                        contactHelper.setContactBlocked(recipientResolver.resolveRecipient(address), true);
+                final var stickerPackId = StickerPackId.deserialize(m.getPackId().get());
+                final var installed = !m.getType().isPresent()
+                        || m.getType().get() == StickerPackOperationMessage.Type.INSTALL;
+
+                var sticker = account.getStickerStore().getSticker(stickerPackId);
+                if (m.getPackKey().isPresent()) {
+                    if (sticker == null) {
+                        sticker = new Sticker(stickerPackId, m.getPackKey().get());
                     }
-                    for (var groupId : blockedListMessage.getGroupIds()
-                            .stream()
-                            .map(GroupId::unknownVersion)
-                            .collect(Collectors.toSet())) {
-                        try {
-                            groupHelper.setGroupBlocked(groupId, true);
-                        } catch (GroupNotFoundException e) {
-                            logger.warn("BlockedListMessage contained groupID that was not found in GroupStore: {}",
-                                    groupId.toBase64());
-                        }
+                    if (installed) {
+                        jobExecutor.enqueueJob(new RetrieveStickerPackJob(stickerPackId, m.getPackKey().get()));
                     }
                 }
-                if (syncMessage.getContacts().isPresent()) {
-                    try {
-                        final var contactsMessage = syncMessage.getContacts().get();
-                        attachmentHelper.retrieveAttachment(contactsMessage.getContactsStream(),
-                                syncHelper::handleSyncDeviceContacts);
-                    } catch (Exception e) {
-                        logger.warn("Failed to handle received sync contacts, ignoring: {}", e.getMessage());
-                    }
-                }
-                if (syncMessage.getVerified().isPresent()) {
-                    final var verifiedMessage = syncMessage.getVerified().get();
-                    account.getIdentityKeyStore()
-                            .setIdentityTrustLevel(account.getRecipientStore()
-                                            .resolveRecipientTrusted(verifiedMessage.getDestination()),
-                                    verifiedMessage.getIdentityKey(),
-                                    TrustLevel.fromVerifiedState(verifiedMessage.getVerified()));
-                }
-                if (syncMessage.getStickerPackOperations().isPresent()) {
-                    final var stickerPackOperationMessages = syncMessage.getStickerPackOperations().get();
-                    for (var m : stickerPackOperationMessages) {
-                        if (!m.getPackId().isPresent()) {
-                            continue;
-                        }
-                        final var stickerPackId = StickerPackId.deserialize(m.getPackId().get());
-                        final var installed = !m.getType().isPresent()
-                                || m.getType().get() == StickerPackOperationMessage.Type.INSTALL;
-
-                        var sticker = account.getStickerStore().getSticker(stickerPackId);
-                        if (m.getPackKey().isPresent()) {
-                            if (sticker == null) {
-                                sticker = new Sticker(stickerPackId, m.getPackKey().get());
-                            }
-                            if (installed) {
-                                jobExecutor.enqueueJob(new RetrieveStickerPackJob(stickerPackId, m.getPackKey().get()));
-                            }
-                        }
 
-                        if (sticker != null) {
-                            sticker.setInstalled(installed);
-                            account.getStickerStore().updateSticker(sticker);
-                        }
-                    }
-                }
-                if (syncMessage.getFetchType().isPresent()) {
-                    switch (syncMessage.getFetchType().get()) {
-                        case LOCAL_PROFILE:
-                            actions.add(new RetrieveProfileAction(account.getSelfRecipientId()));
-                        case STORAGE_MANIFEST:
-                            // TODO
-                    }
-                }
-                if (syncMessage.getKeys().isPresent()) {
-                    final var keysMessage = syncMessage.getKeys().get();
-                    if (keysMessage.getStorageService().isPresent()) {
-                        final var storageKey = keysMessage.getStorageService().get();
-                        account.setStorageKey(storageKey);
-                    }
+                if (sticker != null) {
+                    sticker.setInstalled(installed);
+                    account.getStickerStore().updateSticker(sticker);
                 }
-                if (syncMessage.getConfiguration().isPresent()) {
+            }
+        }
+        if (syncMessage.getFetchType().isPresent()) {
+            switch (syncMessage.getFetchType().get()) {
+                case LOCAL_PROFILE:
+                    actions.add(new RetrieveProfileAction(account.getSelfRecipientId()));
+                case STORAGE_MANIFEST:
                     // TODO
-                }
             }
         }
+        if (syncMessage.getKeys().isPresent()) {
+            final var keysMessage = syncMessage.getKeys().get();
+            if (keysMessage.getStorageService().isPresent()) {
+                final var storageKey = keysMessage.getStorageService().get();
+                account.setStorageKey(storageKey);
+            }
+        }
+        if (syncMessage.getConfiguration().isPresent()) {
+            // TODO
+        }
         return actions;
     }
 
     private boolean isMessageBlocked(SignalServiceEnvelope envelope, SignalServiceContent content) {
         SignalServiceAddress source;
-        if (!envelope.isUnidentifiedSender() && envelope.hasSource()) {
+        if (!envelope.isUnidentifiedSender() && envelope.hasSourceUuid()) {
             source = envelope.getSourceAddress();
         } else if (content != null) {
             source = content.getSender();
@@ -290,7 +304,7 @@ public final class IncomingMessageHandler {
 
     private boolean isNotAllowedToSendToGroup(SignalServiceEnvelope envelope, SignalServiceContent content) {
         SignalServiceAddress source;
-        if (!envelope.isUnidentifiedSender() && envelope.hasSource()) {
+        if (!envelope.isUnidentifiedSender() && envelope.hasSourceUuid()) {
             source = envelope.getSourceAddress();
         } else if (content != null) {
             source = content.getSender();
index ac75a5730d5272f31b5653d0bbb66cca9af2f83e..52154798ab85dc358f39bcd575a908807af4eebd 100644 (file)
@@ -273,7 +273,7 @@ public final class ProfileHelper {
 
     private Single<ProfileAndCredential> retrieveProfile(
             RecipientId recipientId, SignalServiceProfile.RequestType requestType
-    ) throws IOException {
+    ) {
         var unidentifiedAccess = getUnidentifiedAccess(recipientId);
         var profileKey = Optional.fromNullable(profileKeyProvider.getProfileKey(recipientId));
 
@@ -286,7 +286,7 @@ public final class ProfileHelper {
             Optional<ProfileKey> profileKey,
             Optional<UnidentifiedAccess> unidentifiedAccess,
             SignalServiceProfile.RequestType requestType
-    ) throws IOException {
+    ) {
         var profileService = profileServiceProvider.getProfileService();
 
         Single<ServiceResponse<ProfileAndCredential>> responseSingle;
@@ -294,11 +294,7 @@ public final class ProfileHelper {
             responseSingle = profileService.getProfile(address, profileKey, unidentifiedAccess, requestType);
         } catch (NoClassDefFoundError e) {
             // Native zkgroup lib not available for ProfileKey
-            if (!address.getNumber().isPresent()) {
-                throw new NotFoundException("Can't request profile without number");
-            }
-            var addressWithoutUuid = new SignalServiceAddress(Optional.absent(), address.getNumber());
-            responseSingle = profileService.getProfile(addressWithoutUuid, profileKey, unidentifiedAccess, requestType);
+            responseSingle = profileService.getProfile(address, Optional.absent(), unidentifiedAccess, requestType);
         }
 
         return responseSingle.map(pair -> {
index 058a04f2d255309576541a66e96c6b8cc64fe27d..da901a3d88428d0f8c28672093169e11b55ce7d4 100644 (file)
@@ -1,6 +1,7 @@
 package org.asamk.signal.manager.helper;
 
 import org.asamk.signal.manager.SignalDependencies;
+import org.asamk.signal.manager.UntrustedIdentityException;
 import org.asamk.signal.manager.groups.GroupId;
 import org.asamk.signal.manager.groups.GroupNotFoundException;
 import org.asamk.signal.manager.groups.GroupSendingNotAllowedException;
@@ -13,8 +14,8 @@ import org.asamk.signal.manager.storage.recipients.RecipientResolver;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.whispersystems.libsignal.util.guava.Optional;
+import org.whispersystems.signalservice.api.SignalServiceMessageSender;
 import org.whispersystems.signalservice.api.crypto.ContentHint;
-import org.whispersystems.signalservice.api.crypto.UntrustedIdentityException;
 import org.whispersystems.signalservice.api.messages.SendMessageResult;
 import org.whispersystems.signalservice.api.messages.SignalServiceDataMessage;
 import org.whispersystems.signalservice.api.messages.SignalServiceReceiptMessage;
@@ -43,6 +44,20 @@ public class SendHelper {
     private final GroupProvider groupProvider;
     private final RecipientRegistrationRefresher recipientRegistrationRefresher;
 
+    private final SignalServiceMessageSender.IndividualSendEvents sendEvents = new SignalServiceMessageSender.IndividualSendEvents() {
+        @Override
+        public void onMessageEncrypted() {
+        }
+
+        @Override
+        public void onMessageSent() {
+        }
+
+        @Override
+        public void onSyncMessageSent() {
+        }
+    };
+
     public SendHelper(
             final SignalAccount account,
             final SignalDependencies dependencies,
@@ -145,9 +160,12 @@ public class SendHelper {
             final SignalServiceReceiptMessage receiptMessage, final RecipientId recipientId
     ) throws IOException, UntrustedIdentityException {
         final var messageSender = dependencies.getMessageSender();
-        messageSender.sendReceipt(addressResolver.resolveSignalServiceAddress(recipientId),
-                unidentifiedAccessHelper.getAccessFor(recipientId),
-                receiptMessage);
+        final var address = addressResolver.resolveSignalServiceAddress(recipientId);
+        try {
+            messageSender.sendReceipt(address, unidentifiedAccessHelper.getAccessFor(recipientId), receiptMessage);
+        } catch (org.whispersystems.signalservice.api.crypto.UntrustedIdentityException e) {
+            throw new UntrustedIdentityException(address);
+        }
     }
 
     public SendMessageResult sendNullMessage(RecipientId recipientId) throws IOException {
@@ -162,7 +180,7 @@ public class SendHelper {
                 final var newAddress = addressResolver.resolveSignalServiceAddress(newRecipientId);
                 return messageSender.sendNullMessage(newAddress, unidentifiedAccessHelper.getAccessFor(newRecipientId));
             }
-        } catch (UntrustedIdentityException e) {
+        } catch (org.whispersystems.signalservice.api.crypto.UntrustedIdentityException e) {
             return SendMessageResult.identityFailure(address, e.getIdentityKey());
         }
     }
@@ -183,7 +201,7 @@ public class SendHelper {
         var messageSender = dependencies.getMessageSender();
         try {
             return messageSender.sendSyncMessage(message, unidentifiedAccessHelper.getAccessForSync());
-        } catch (UntrustedIdentityException e) {
+        } catch (org.whispersystems.signalservice.api.crypto.UntrustedIdentityException e) {
             var address = addressResolver.resolveSignalServiceAddress(account.getSelfRecipientId());
             return SendMessageResult.identityFailure(address, e.getIdentityKey());
         }
@@ -195,11 +213,15 @@ public class SendHelper {
         var messageSender = dependencies.getMessageSender();
         final var address = addressResolver.resolveSignalServiceAddress(recipientId);
         try {
-            messageSender.sendTyping(address, unidentifiedAccessHelper.getAccessFor(recipientId), message);
-        } catch (UnregisteredUserException e) {
-            final var newRecipientId = recipientRegistrationRefresher.refreshRecipientRegistration(recipientId);
-            final var newAddress = addressResolver.resolveSignalServiceAddress(newRecipientId);
-            messageSender.sendTyping(newAddress, unidentifiedAccessHelper.getAccessFor(newRecipientId), message);
+            try {
+                messageSender.sendTyping(address, unidentifiedAccessHelper.getAccessFor(recipientId), message);
+            } catch (UnregisteredUserException e) {
+                final var newRecipientId = recipientRegistrationRefresher.refreshRecipientRegistration(recipientId);
+                final var newAddress = addressResolver.resolveSignalServiceAddress(newRecipientId);
+                messageSender.sendTyping(newAddress, unidentifiedAccessHelper.getAccessFor(newRecipientId), message);
+            }
+        } catch (org.whispersystems.signalservice.api.crypto.UntrustedIdentityException e) {
+            throw new UntrustedIdentityException(address);
         }
     }
 
@@ -247,7 +269,7 @@ public class SendHelper {
                     message,
                     sendResult -> logger.trace("Partial message send result: {}", sendResult.isSuccess()),
                     () -> false);
-        } catch (UntrustedIdentityException e) {
+        } catch (org.whispersystems.signalservice.api.crypto.UntrustedIdentityException e) {
             return List.of();
         }
     }
@@ -263,15 +285,17 @@ public class SendHelper {
                 return messageSender.sendDataMessage(address,
                         unidentifiedAccessHelper.getAccessFor(recipientId),
                         ContentHint.DEFAULT,
-                        message);
+                        message,
+                        sendEvents);
             } catch (UnregisteredUserException e) {
                 final var newRecipientId = recipientRegistrationRefresher.refreshRecipientRegistration(recipientId);
                 return messageSender.sendDataMessage(addressResolver.resolveSignalServiceAddress(newRecipientId),
                         unidentifiedAccessHelper.getAccessFor(newRecipientId),
                         ContentHint.DEFAULT,
-                        message);
+                        message,
+                        sendEvents);
             }
-        } catch (UntrustedIdentityException e) {
+        } catch (org.whispersystems.signalservice.api.crypto.UntrustedIdentityException e) {
             return SendMessageResult.identityFailure(address, e.getIdentityKey());
         }
     }
index 48dc206e234e723653a72d12725d60edf03ee88c..461706f012ee2fcfe5e5e2b9b482e70e4d39b0db 100644 (file)
@@ -2,11 +2,9 @@ package org.asamk.signal.manager.helper;
 
 import org.asamk.signal.manager.AvatarStore;
 import org.asamk.signal.manager.TrustLevel;
-import org.asamk.signal.manager.groups.GroupId;
 import org.asamk.signal.manager.storage.SignalAccount;
 import org.asamk.signal.manager.storage.groups.GroupInfoV1;
 import org.asamk.signal.manager.storage.recipients.Contact;
-import org.asamk.signal.manager.storage.recipients.RecipientResolver;
 import org.asamk.signal.manager.util.AttachmentUtils;
 import org.asamk.signal.manager.util.IOUtils;
 import org.slf4j.Logger;
@@ -21,7 +19,6 @@ import org.whispersystems.signalservice.api.messages.multidevice.DeviceContact;
 import org.whispersystems.signalservice.api.messages.multidevice.DeviceContactsInputStream;
 import org.whispersystems.signalservice.api.messages.multidevice.DeviceContactsOutputStream;
 import org.whispersystems.signalservice.api.messages.multidevice.DeviceGroup;
-import org.whispersystems.signalservice.api.messages.multidevice.DeviceGroupsInputStream;
 import org.whispersystems.signalservice.api.messages.multidevice.DeviceGroupsOutputStream;
 import org.whispersystems.signalservice.api.messages.multidevice.RequestMessage;
 import org.whispersystems.signalservice.api.messages.multidevice.SignalServiceSyncMessage;
@@ -36,7 +33,6 @@ import java.io.InputStream;
 import java.io.OutputStream;
 import java.nio.file.Files;
 import java.util.ArrayList;
-import java.util.List;
 import java.util.stream.Collectors;
 
 public class SyncHelper {
@@ -49,7 +45,6 @@ public class SyncHelper {
     private final GroupHelper groupHelper;
     private final AvatarStore avatarStore;
     private final SignalServiceAddressResolver addressResolver;
-    private final RecipientResolver recipientResolver;
 
     public SyncHelper(
             final SignalAccount account,
@@ -57,8 +52,7 @@ public class SyncHelper {
             final SendHelper sendHelper,
             final GroupHelper groupHelper,
             final AvatarStore avatarStore,
-            final SignalServiceAddressResolver addressResolver,
-            final RecipientResolver recipientResolver
+            final SignalServiceAddressResolver addressResolver
     ) {
         this.account = account;
         this.attachmentHelper = attachmentHelper;
@@ -66,7 +60,6 @@ public class SyncHelper {
         this.groupHelper = groupHelper;
         this.avatarStore = avatarStore;
         this.addressResolver = addressResolver;
-        this.recipientResolver = recipientResolver;
     }
 
     public void requestAllSyncData() throws IOException {
@@ -222,48 +215,6 @@ public class SyncHelper {
         sendHelper.sendSyncMessage(SignalServiceSyncMessage.forVerified(verifiedMessage));
     }
 
-    public void handleSyncDeviceGroups(final InputStream input) {
-        final var s = new DeviceGroupsInputStream(input);
-        DeviceGroup g;
-        while (true) {
-            try {
-                g = s.read();
-            } catch (IOException e) {
-                logger.warn("Sync groups contained invalid group, ignoring: {}", e.getMessage());
-                continue;
-            }
-            if (g == null) {
-                break;
-            }
-            var syncGroup = account.getGroupStore().getOrCreateGroupV1(GroupId.v1(g.getId()));
-            if (syncGroup != null) {
-                if (g.getName().isPresent()) {
-                    syncGroup.name = g.getName().get();
-                }
-                syncGroup.addMembers(g.getMembers()
-                        .stream()
-                        .map(recipientResolver::resolveRecipient)
-                        .collect(Collectors.toSet()));
-                if (!g.isActive()) {
-                    syncGroup.removeMember(account.getSelfRecipientId());
-                } else {
-                    // Add ourself to the member set as it's marked as active
-                    syncGroup.addMembers(List.of(account.getSelfRecipientId()));
-                }
-                syncGroup.blocked = g.isBlocked();
-                if (g.getColor().isPresent()) {
-                    syncGroup.color = g.getColor().get();
-                }
-
-                if (g.getAvatar().isPresent()) {
-                    groupHelper.downloadGroupAvatar(syncGroup.getGroupId(), g.getAvatar().get());
-                }
-                syncGroup.archived = g.isArchived();
-                account.getGroupStore().updateGroup(syncGroup);
-            }
-        }
-    }
-
     public void handleSyncDeviceContacts(final InputStream input) {
         final var s = new DeviceContactsInputStream(input);
         DeviceContact c;
index 477e02dc0262a657ea4ff12705293b06160267f5..c972c2c7a809458c103355c40f18b751dc40331d 100644 (file)
@@ -152,7 +152,7 @@ public class SignalAccount implements Closeable {
 
         account.initStores(dataPath, identityKey, registrationId, trustNewIdentity);
         account.groupStore = new GroupStore(getGroupCachePath(dataPath, username),
-                account.recipientStore::resolveRecipient,
+                account.recipientStore,
                 account::saveGroupStore);
         account.stickerStore = new StickerStore(account::saveStickerStore);
 
@@ -174,9 +174,9 @@ public class SignalAccount implements Closeable {
 
         preKeyStore = new PreKeyStore(getPreKeysPath(dataPath, username));
         signedPreKeyStore = new SignedPreKeyStore(getSignedPreKeysPath(dataPath, username));
-        sessionStore = new SessionStore(getSessionsPath(dataPath, username), recipientStore::resolveRecipient);
+        sessionStore = new SessionStore(getSessionsPath(dataPath, username), recipientStore);
         identityKeyStore = new IdentityKeyStore(getIdentitiesPath(dataPath, username),
-                recipientStore::resolveRecipient,
+                recipientStore,
                 identityKey,
                 registrationId,
                 trustNewIdentity);
@@ -254,7 +254,7 @@ public class SignalAccount implements Closeable {
 
         account.initStores(dataPath, identityKey, registrationId, trustNewIdentity);
         account.groupStore = new GroupStore(getGroupCachePath(dataPath, username),
-                account.recipientStore::resolveRecipient,
+                account.recipientStore,
                 account::saveGroupStore);
         account.stickerStore = new StickerStore(account::saveStickerStore);
 
@@ -453,12 +453,10 @@ public class SignalAccount implements Closeable {
             groupStoreStorage = jsonProcessor.convertValue(rootNode.get("groupStore"), GroupStore.Storage.class);
             groupStore = GroupStore.fromStorage(groupStoreStorage,
                     getGroupCachePath(dataPath, username),
-                    recipientStore::resolveRecipient,
+                    recipientStore,
                     this::saveGroupStore);
         } else {
-            groupStore = new GroupStore(getGroupCachePath(dataPath, username),
-                    recipientStore::resolveRecipient,
-                    this::saveGroupStore);
+            groupStore = new GroupStore(getGroupCachePath(dataPath, username), recipientStore, this::saveGroupStore);
         }
 
         if (rootNode.hasNonNull("stickerStore")) {
@@ -572,7 +570,7 @@ public class SignalAccount implements Closeable {
             var profileStoreNode = rootNode.get("profileStore");
             final var legacyProfileStore = jsonProcessor.convertValue(profileStoreNode, LegacyProfileStore.class);
             for (var profileEntry : legacyProfileStore.getProfileEntries()) {
-                var recipientId = recipientStore.resolveRecipient(profileEntry.getServiceAddress());
+                var recipientId = recipientStore.resolveRecipient(profileEntry.getAddress());
                 recipientStore.storeProfileKeyCredential(recipientId, profileEntry.getProfileKeyCredential());
                 recipientStore.storeProfileKey(recipientId, profileEntry.getProfileKey());
                 final var profile = profileEntry.getProfile();
index e542f4e33e949df98900bb30b7f1a7bb25bdc978..e4b639a2910b657d82ba187e7dc7e1f4c882442d 100644 (file)
@@ -9,7 +9,11 @@ import com.fasterxml.jackson.databind.JsonNode;
 import com.fasterxml.jackson.databind.ObjectMapper;
 import com.fasterxml.jackson.databind.SerializationFeature;
 
+import org.asamk.signal.manager.storage.recipients.RecipientAddress;
+import org.whispersystems.signalservice.api.util.UuidUtil;
+
 import java.io.InvalidObjectException;
+import java.util.Optional;
 
 public class Utils {
 
@@ -37,4 +41,12 @@ public class Utils {
 
         return node;
     }
+
+    public static RecipientAddress getRecipientAddressFromIdentifier(final String identifier) {
+        if (UuidUtil.isUuid(identifier)) {
+            return new RecipientAddress(UuidUtil.parseOrThrow(identifier));
+        } else {
+            return new RecipientAddress(Optional.empty(), Optional.of(identifier));
+        }
+    }
 }
index a90f87e0fbc1ce5a12084ba6f8eb6e1bcfb0a37d..6c6bd7eae4311cde301d496d5aa29a98028b5a66 100644 (file)
@@ -3,7 +3,7 @@ package org.asamk.signal.manager.storage.contacts;
 import com.fasterxml.jackson.annotation.JsonIgnore;
 import com.fasterxml.jackson.annotation.JsonProperty;
 
-import org.whispersystems.signalservice.api.push.SignalServiceAddress;
+import org.asamk.signal.manager.storage.recipients.RecipientAddress;
 
 import java.util.UUID;
 
@@ -42,7 +42,7 @@ public class LegacyContactInfo {
     }
 
     @JsonIgnore
-    public SignalServiceAddress getAddress() {
-        return new SignalServiceAddress(uuid, number);
+    public RecipientAddress getAddress() {
+        return new RecipientAddress(uuid, number);
     }
 }
index 59cfedb542ffed0d99fb94ac6e7fd0a6351d02e4..f86dcb047234570ffc62859067bfdadaad469e67 100644 (file)
@@ -9,7 +9,6 @@ import org.signal.storageservice.protos.groups.Member;
 import org.signal.storageservice.protos.groups.local.DecryptedGroup;
 import org.signal.storageservice.protos.groups.local.EnabledState;
 import org.signal.zkgroup.groups.GroupMasterKey;
-import org.whispersystems.signalservice.api.push.SignalServiceAddress;
 import org.whispersystems.signalservice.api.util.UuidUtil;
 
 import java.util.Set;
@@ -89,7 +88,7 @@ public class GroupInfoV2 extends GroupInfo {
         }
         return group.getMembersList()
                 .stream()
-                .map(m -> new SignalServiceAddress(UuidUtil.parseOrThrow(m.getUuid().toByteArray()), null))
+                .map(m -> UuidUtil.parseOrThrow(m.getUuid().toByteArray()))
                 .map(recipientResolver::resolveRecipient)
                 .collect(Collectors.toSet());
     }
@@ -101,7 +100,7 @@ public class GroupInfoV2 extends GroupInfo {
         }
         return group.getPendingMembersList()
                 .stream()
-                .map(m -> new SignalServiceAddress(UuidUtil.parseOrThrow(m.getUuid().toByteArray()), null))
+                .map(m -> UuidUtil.parseOrThrow(m.getUuid().toByteArray()))
                 .map(recipientResolver::resolveRecipient)
                 .collect(Collectors.toSet());
     }
@@ -113,7 +112,7 @@ public class GroupInfoV2 extends GroupInfo {
         }
         return group.getRequestingMembersList()
                 .stream()
-                .map(m -> new SignalServiceAddress(UuidUtil.parseOrThrow(m.getUuid().toByteArray()), null))
+                .map(m -> UuidUtil.parseOrThrow(m.getUuid().toByteArray()))
                 .map(recipientResolver::resolveRecipient)
                 .collect(Collectors.toSet());
     }
@@ -126,7 +125,7 @@ public class GroupInfoV2 extends GroupInfo {
         return group.getMembersList()
                 .stream()
                 .filter(m -> m.getRole() == Member.Role.ADMINISTRATOR)
-                .map(m -> new SignalServiceAddress(UuidUtil.parseOrThrow(m.getUuid().toByteArray()), null))
+                .map(m -> UuidUtil.parseOrThrow(m.getUuid().toByteArray()))
                 .map(recipientResolver::resolveRecipient)
                 .collect(Collectors.toSet());
     }
index 86459c2abd47db5f58f35ddb495dd7463cab309c..4adc413ad07a32fbb0b4bf9d4daeccb6eedbd580 100644 (file)
@@ -14,6 +14,7 @@ import org.asamk.signal.manager.groups.GroupId;
 import org.asamk.signal.manager.groups.GroupIdV1;
 import org.asamk.signal.manager.groups.GroupIdV2;
 import org.asamk.signal.manager.groups.GroupUtils;
+import org.asamk.signal.manager.storage.recipients.RecipientAddress;
 import org.asamk.signal.manager.storage.recipients.RecipientId;
 import org.asamk.signal.manager.storage.recipients.RecipientResolver;
 import org.asamk.signal.manager.util.IOUtils;
@@ -22,7 +23,6 @@ import org.signal.zkgroup.InvalidInputException;
 import org.signal.zkgroup.groups.GroupMasterKey;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
-import org.whispersystems.signalservice.api.push.SignalServiceAddress;
 import org.whispersystems.signalservice.api.util.UuidUtil;
 import org.whispersystems.signalservice.internal.util.Hex;
 
@@ -78,7 +78,7 @@ public class GroupStore {
                 final var g1 = (Storage.GroupV1) g;
                 final var members = g1.members.stream().map(m -> {
                     if (m.recipientId == null) {
-                        return recipientResolver.resolveRecipient(new SignalServiceAddress(UuidUtil.parseOrNull(m.uuid),
+                        return recipientResolver.resolveRecipient(new RecipientAddress(UuidUtil.parseOrNull(m.uuid),
                                 m.number));
                     }
 
@@ -343,17 +343,17 @@ public class GroupStore {
                 }
             }
 
-            private static final class JsonSignalServiceAddress {
+            private static final class JsonRecipientAddress {
 
                 public String uuid;
 
                 public String number;
 
                 // For deserialization
-                public JsonSignalServiceAddress() {
+                public JsonRecipientAddress() {
                 }
 
-                JsonSignalServiceAddress(final String uuid, final String number) {
+                JsonRecipientAddress(final String uuid, final String number) {
                     this.uuid = uuid;
                     this.number = number;
                 }
@@ -370,7 +370,7 @@ public class GroupStore {
                         if (address.recipientId != null) {
                             jgen.writeNumber(address.recipientId);
                         } else if (address.uuid != null) {
-                            jgen.writeObject(new JsonSignalServiceAddress(address.uuid, address.number));
+                            jgen.writeObject(new JsonRecipientAddress(address.uuid, address.number));
                         } else {
                             jgen.writeString(address.number);
                         }
@@ -393,7 +393,7 @@ public class GroupStore {
                         } else if (n.isNumber()) {
                             addresses.add(new Member(n.numberValue().longValue(), null, null));
                         } else {
-                            var address = jsonParser.getCodec().treeToValue(n, JsonSignalServiceAddress.class);
+                            var address = jsonParser.getCodec().treeToValue(n, JsonRecipientAddress.class);
                             addresses.add(new Member(null, address.uuid, address.number));
                         }
                     }
index 0cbdf347e218ae952ef7452c9bf205b640ec4f48..f24e77b1ef2293ba61cbc3b25d0095a4be6e5d90 100644 (file)
@@ -6,7 +6,6 @@ import org.asamk.signal.manager.TrustLevel;
 import org.asamk.signal.manager.storage.recipients.RecipientId;
 import org.asamk.signal.manager.storage.recipients.RecipientResolver;
 import org.asamk.signal.manager.util.IOUtils;
-import org.asamk.signal.manager.util.Utils;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.whispersystems.libsignal.IdentityKey;
@@ -177,7 +176,7 @@ public class IdentityKeyStore implements org.whispersystems.libsignal.state.Iden
      * @param identifier can be either a serialized uuid or a e164 phone number
      */
     private RecipientId resolveRecipient(String identifier) {
-        return resolver.resolveRecipient(Utils.getSignalServiceAddressFromIdentifier(identifier));
+        return resolver.resolveRecipient(identifier);
     }
 
     private File getIdentityFile(final RecipientId recipientId) {
index 8e1d5c88c60419ea2ff5e43ef136528f471c7113..1c6369f077d91f22d24df91515193fc861568042 100644 (file)
@@ -8,10 +8,10 @@ import com.fasterxml.jackson.databind.JsonNode;
 import com.fasterxml.jackson.databind.ObjectMapper;
 import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
 
+import org.asamk.signal.manager.storage.recipients.RecipientAddress;
 import org.signal.zkgroup.InvalidInputException;
 import org.signal.zkgroup.profiles.ProfileKey;
 import org.signal.zkgroup.profiles.ProfileKeyCredential;
-import org.whispersystems.signalservice.api.push.SignalServiceAddress;
 import org.whispersystems.signalservice.api.util.UuidUtil;
 
 import java.io.IOException;
@@ -45,7 +45,7 @@ public class LegacyProfileStore {
                 for (var entry : node) {
                     var name = entry.hasNonNull("name") ? entry.get("name").asText() : null;
                     var uuid = entry.hasNonNull("uuid") ? UuidUtil.parseOrNull(entry.get("uuid").asText()) : null;
-                    final var serviceAddress = new SignalServiceAddress(uuid, name);
+                    final var address = new RecipientAddress(uuid, name);
                     ProfileKey profileKey = null;
                     try {
                         profileKey = new ProfileKey(Base64.getDecoder().decode(entry.get("profileKey").asText()));
@@ -61,7 +61,7 @@ public class LegacyProfileStore {
                     }
                     var lastUpdateTimestamp = entry.get("lastUpdateTimestamp").asLong();
                     var profile = jsonProcessor.treeToValue(entry.get("profile"), SignalProfile.class);
-                    profileEntries.add(new LegacySignalProfileEntry(serviceAddress,
+                    profileEntries.add(new LegacySignalProfileEntry(address,
                             profileKey,
                             lastUpdateTimestamp,
                             profile,
index 1e2f7ec84e3640b9415c17ab6674003a727faa6d..03b11bcbbb20093ae7dd37230354f9316fb78685 100644 (file)
@@ -1,12 +1,12 @@
 package org.asamk.signal.manager.storage.profiles;
 
+import org.asamk.signal.manager.storage.recipients.RecipientAddress;
 import org.signal.zkgroup.profiles.ProfileKey;
 import org.signal.zkgroup.profiles.ProfileKeyCredential;
-import org.whispersystems.signalservice.api.push.SignalServiceAddress;
 
 public class LegacySignalProfileEntry {
 
-    private final SignalServiceAddress serviceAddress;
+    private final RecipientAddress address;
 
     private final ProfileKey profileKey;
 
@@ -17,21 +17,21 @@ public class LegacySignalProfileEntry {
     private final ProfileKeyCredential profileKeyCredential;
 
     public LegacySignalProfileEntry(
-            final SignalServiceAddress serviceAddress,
+            final RecipientAddress address,
             final ProfileKey profileKey,
             final long lastUpdateTimestamp,
             final SignalProfile profile,
             final ProfileKeyCredential profileKeyCredential
     ) {
-        this.serviceAddress = serviceAddress;
+        this.address = address;
         this.profileKey = profileKey;
         this.lastUpdateTimestamp = lastUpdateTimestamp;
         this.profile = profile;
         this.profileKeyCredential = profileKeyCredential;
     }
 
-    public SignalServiceAddress getServiceAddress() {
-        return serviceAddress;
+    public RecipientAddress getAddress() {
+        return address;
     }
 
     public ProfileKey getProfileKey() {
index eb66b3e5cfad2c87b9c4c99bfa760504d14807f7..2fa19f428056f9ac74aabd3815ac00d49f1aa9f7 100644 (file)
@@ -1,30 +1,30 @@
 package org.asamk.signal.manager.storage.protocol;
 
 import org.asamk.signal.manager.TrustLevel;
+import org.asamk.signal.manager.storage.recipients.RecipientAddress;
 import org.whispersystems.libsignal.IdentityKey;
-import org.whispersystems.signalservice.api.push.SignalServiceAddress;
 
 import java.util.Date;
 
 public class LegacyIdentityInfo {
 
-    SignalServiceAddress address;
+    RecipientAddress address;
     IdentityKey identityKey;
     TrustLevel trustLevel;
     Date added;
 
-    LegacyIdentityInfo(SignalServiceAddress address, IdentityKey identityKey, TrustLevel trustLevel, Date added) {
+    LegacyIdentityInfo(RecipientAddress address, IdentityKey identityKey, TrustLevel trustLevel, Date added) {
         this.address = address;
         this.identityKey = identityKey;
         this.trustLevel = trustLevel;
         this.added = added;
     }
 
-    public SignalServiceAddress getAddress() {
+    public RecipientAddress getAddress() {
         return address;
     }
 
-    public void setAddress(final SignalServiceAddress address) {
+    public void setAddress(final RecipientAddress address) {
         this.address = address;
     }
 
index 781b6f96aeff94e2fa890a00d628d18deadab07b..5e11ab7af5b201147395059e55dd4015da925b31 100644 (file)
@@ -6,13 +6,13 @@ import com.fasterxml.jackson.databind.JsonDeserializer;
 import com.fasterxml.jackson.databind.JsonNode;
 
 import org.asamk.signal.manager.TrustLevel;
-import org.asamk.signal.manager.util.Utils;
+import org.asamk.signal.manager.storage.Utils;
+import org.asamk.signal.manager.storage.recipients.RecipientAddress;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.whispersystems.libsignal.IdentityKey;
 import org.whispersystems.libsignal.IdentityKeyPair;
 import org.whispersystems.libsignal.InvalidKeyException;
-import org.whispersystems.signalservice.api.push.SignalServiceAddress;
 import org.whispersystems.signalservice.api.util.UuidUtil;
 
 import java.io.IOException;
@@ -55,11 +55,11 @@ public class LegacyJsonIdentityKeyStore {
         return localRegistrationId;
     }
 
-    private LegacyIdentityInfo getIdentity(SignalServiceAddress serviceAddress) {
+    private LegacyIdentityInfo getIdentity(RecipientAddress address) {
         long maxDate = 0;
         LegacyIdentityInfo maxIdentity = null;
         for (var id : this.identities) {
-            if (!id.address.matches(serviceAddress)) {
+            if (!id.getAddress().matches(address)) {
                 continue;
             }
 
@@ -98,16 +98,16 @@ public class LegacyJsonIdentityKeyStore {
                     var uuid = trustedKey.hasNonNull("uuid")
                             ? UuidUtil.parseOrNull(trustedKey.get("uuid").asText())
                             : null;
-                    final var serviceAddress = uuid == null
-                            ? Utils.getSignalServiceAddressFromIdentifier(trustedKeyName)
-                            : new SignalServiceAddress(uuid, trustedKeyName);
+                    final var address = uuid == null
+                            ? Utils.getRecipientAddressFromIdentifier(trustedKeyName)
+                            : new RecipientAddress(uuid, trustedKeyName);
                     try {
                         var id = new IdentityKey(Base64.getDecoder().decode(trustedKey.get("identityKey").asText()), 0);
                         var trustLevel = trustedKey.hasNonNull("trustLevel") ? TrustLevel.fromInt(trustedKey.get(
                                 "trustLevel").asInt()) : TrustLevel.TRUSTED_UNVERIFIED;
                         var added = trustedKey.hasNonNull("addedTimestamp") ? new Date(trustedKey.get("addedTimestamp")
                                 .asLong()) : new Date();
-                        identities.add(new LegacyIdentityInfo(serviceAddress, id, trustLevel, added));
+                        identities.add(new LegacyIdentityInfo(address, id, trustLevel, added));
                     } catch (InvalidKeyException e) {
                         logger.warn("Error while decoding key for {}: {}", trustedKeyName, e.getMessage());
                     }
index 5f301aebaee00301d72903a064e08c82cbd415fe..9ee0cf8714c5362c4ea27c390f23900711741941 100644 (file)
@@ -5,8 +5,8 @@ import com.fasterxml.jackson.databind.DeserializationContext;
 import com.fasterxml.jackson.databind.JsonDeserializer;
 import com.fasterxml.jackson.databind.JsonNode;
 
-import org.asamk.signal.manager.util.Utils;
-import org.whispersystems.signalservice.api.push.SignalServiceAddress;
+import org.asamk.signal.manager.storage.Utils;
+import org.asamk.signal.manager.storage.recipients.RecipientAddress;
 import org.whispersystems.signalservice.api.util.UuidUtil;
 
 import java.io.IOException;
@@ -45,12 +45,12 @@ public class LegacyJsonSessionStore {
                     }
 
                     var uuid = session.hasNonNull("uuid") ? UuidUtil.parseOrNull(session.get("uuid").asText()) : null;
-                    final var serviceAddress = uuid == null
-                            ? Utils.getSignalServiceAddressFromIdentifier(sessionName)
-                            : new SignalServiceAddress(uuid, sessionName);
+                    final var address = uuid == null
+                            ? Utils.getRecipientAddressFromIdentifier(sessionName)
+                            : new RecipientAddress(uuid, sessionName);
                     final var deviceId = session.get("deviceId").asInt();
                     final var record = Base64.getDecoder().decode(session.get("record").asText());
-                    var sessionInfo = new LegacySessionInfo(serviceAddress, deviceId, record);
+                    var sessionInfo = new LegacySessionInfo(address, deviceId, record);
                     sessions.add(sessionInfo);
                 }
             }
index a19bbd8643fa7b90eb37eb0da9f5fa231e01793f..2cb984fb643c91814e01766f9c4e7baff13bd89d 100644 (file)
@@ -1,16 +1,16 @@
 package org.asamk.signal.manager.storage.protocol;
 
-import org.whispersystems.signalservice.api.push.SignalServiceAddress;
+import org.asamk.signal.manager.storage.recipients.RecipientAddress;
 
 public class LegacySessionInfo {
 
-    public SignalServiceAddress address;
+    public RecipientAddress address;
 
     public int deviceId;
 
     public byte[] sessionRecord;
 
-    LegacySessionInfo(final SignalServiceAddress address, final int deviceId, final byte[] sessionRecord) {
+    LegacySessionInfo(final RecipientAddress address, final int deviceId, final byte[] sessionRecord) {
         this.address = address;
         this.deviceId = deviceId;
         this.sessionRecord = sessionRecord;
index 849234232ef2181d4082af13bc3a1aeb9732dc5d..77eb764a4ab2e4c405a1d3ce96c057a8150020ad 100644 (file)
@@ -129,6 +129,11 @@ public class SignalProtocolStore implements SignalServiceDataStore {
         sessionStore.archiveSession(address);
     }
 
+    @Override
+    public Set<SignalProtocolAddress> getAllAddressesWithActiveSessions(final List<String> addressNames) {
+        return sessionStore.getAllAddressesWithActiveSessions(addressNames);
+    }
+
     @Override
     public SignedPreKeyRecord loadSignedPreKey(int signedPreKeyId) throws InvalidKeyIdException {
         return signedPreKeyStore.loadSignedPreKey(signedPreKeyId);
@@ -189,4 +194,11 @@ public class SignalProtocolStore implements SignalServiceDataStore {
     public boolean isMultiDevice() {
         return isMultiDevice.get();
     }
+
+    @Override
+    public Transaction beginTransaction() {
+        return () -> {
+            // No-op transaction should be safe, as it's only a performance improvement
+        };
+    }
 }
index 493171575ae4b0c39e8fb15f1cd795950804f88e..2aeb349f4645ad6ca5294425fffb4d4a22d67c7c 100644 (file)
@@ -7,7 +7,6 @@ import com.fasterxml.jackson.databind.JsonDeserializer;
 import com.fasterxml.jackson.databind.JsonNode;
 import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
 
-import org.whispersystems.signalservice.api.push.SignalServiceAddress;
 import org.whispersystems.signalservice.api.util.UuidUtil;
 
 import java.io.IOException;
@@ -18,28 +17,27 @@ public class LegacyRecipientStore {
 
     @JsonProperty("recipientStore")
     @JsonDeserialize(using = RecipientStoreDeserializer.class)
-    private final List<SignalServiceAddress> addresses = new ArrayList<>();
+    private final List<RecipientAddress> addresses = new ArrayList<>();
 
-    public List<SignalServiceAddress> getAddresses() {
+    public List<RecipientAddress> getAddresses() {
         return addresses;
     }
 
-    public static class RecipientStoreDeserializer extends JsonDeserializer<List<SignalServiceAddress>> {
+    public static class RecipientStoreDeserializer extends JsonDeserializer<List<RecipientAddress>> {
 
         @Override
-        public List<SignalServiceAddress> deserialize(
+        public List<RecipientAddress> deserialize(
                 JsonParser jsonParser, DeserializationContext deserializationContext
         ) throws IOException {
             JsonNode node = jsonParser.getCodec().readTree(jsonParser);
 
-            var addresses = new ArrayList<SignalServiceAddress>();
+            var addresses = new ArrayList<RecipientAddress>();
 
             if (node.isArray()) {
                 for (var recipient : node) {
                     var recipientName = recipient.get("name").asText();
                     var uuid = UuidUtil.parseOrThrow(recipient.get("uuid").asText());
-                    final var serviceAddress = new SignalServiceAddress(uuid, recipientName);
-                    addresses.add(serviceAddress);
+                    addresses.add(new RecipientAddress(uuid, recipientName));
                 }
             }
 
index 3ccf8210242276bebb308262284516c35f2b4c51..2d2950dc0539f52e4ddd103ddb1e21e8ba116d87 100644 (file)
@@ -2,13 +2,12 @@ package org.asamk.signal.manager.storage.recipients;
 
 import org.signal.zkgroup.profiles.ProfileKey;
 import org.signal.zkgroup.profiles.ProfileKeyCredential;
-import org.whispersystems.signalservice.api.push.SignalServiceAddress;
 
 public class Recipient {
 
     private final RecipientId recipientId;
 
-    private final SignalServiceAddress address;
+    private final RecipientAddress address;
 
     private final Contact contact;
 
@@ -20,7 +19,7 @@ public class Recipient {
 
     public Recipient(
             final RecipientId recipientId,
-            final SignalServiceAddress address,
+            final RecipientAddress address,
             final Contact contact,
             final ProfileKey profileKey,
             final ProfileKeyCredential profileKeyCredential,
@@ -62,7 +61,7 @@ public class Recipient {
         return recipientId;
     }
 
-    public SignalServiceAddress getAddress() {
+    public RecipientAddress getAddress() {
         return address;
     }
 
@@ -85,7 +84,7 @@ public class Recipient {
     public static final class Builder {
 
         private RecipientId recipientId;
-        private SignalServiceAddress address;
+        private RecipientAddress address;
         private Contact contact;
         private ProfileKey profileKey;
         private ProfileKeyCredential profileKeyCredential;
@@ -99,7 +98,7 @@ public class Recipient {
             return this;
         }
 
-        public Builder withAddress(final SignalServiceAddress val) {
+        public Builder withAddress(final RecipientAddress val) {
             address = val;
             return this;
         }
diff --git a/lib/src/main/java/org/asamk/signal/manager/storage/recipients/RecipientAddress.java b/lib/src/main/java/org/asamk/signal/manager/storage/recipients/RecipientAddress.java
new file mode 100644 (file)
index 0000000..29e964b
--- /dev/null
@@ -0,0 +1,89 @@
+package org.asamk.signal.manager.storage.recipients;
+
+import org.whispersystems.signalservice.api.push.SignalServiceAddress;
+import org.whispersystems.signalservice.api.util.UuidUtil;
+
+import java.util.Optional;
+import java.util.UUID;
+
+public class RecipientAddress {
+
+    private final Optional<UUID> uuid;
+    private final Optional<String> e164;
+
+    /**
+     * Construct a RecipientAddress.
+     *
+     * @param uuid The UUID of the user, if available.
+     * @param e164 The phone number of the user, if available.
+     */
+    public RecipientAddress(Optional<UUID> uuid, Optional<String> e164) {
+        if (!uuid.isPresent() && !e164.isPresent()) {
+            throw new AssertionError("Must have either a UUID or E164 number!");
+        }
+
+        this.uuid = uuid;
+        this.e164 = e164;
+    }
+
+    public RecipientAddress(UUID uuid, String e164) {
+        this(Optional.ofNullable(uuid), Optional.ofNullable(e164));
+    }
+
+    public RecipientAddress(SignalServiceAddress address) {
+        this.uuid = Optional.of(address.getUuid());
+        this.e164 = Optional.ofNullable(address.getNumber().orNull());
+    }
+
+    public RecipientAddress(UUID uuid) {
+        this.uuid = Optional.of(uuid);
+        this.e164 = Optional.empty();
+    }
+
+    public Optional<String> getNumber() {
+        return e164;
+    }
+
+    public Optional<UUID> getUuid() {
+        return uuid;
+    }
+
+    public String getIdentifier() {
+        if (uuid.isPresent()) {
+            return uuid.get().toString();
+        } else if (e164.isPresent()) {
+            return e164.get();
+        } else {
+            throw new AssertionError("Given the checks in the constructor, this should not be possible.");
+        }
+    }
+
+    public boolean matches(RecipientAddress other) {
+        return (uuid.isPresent() && other.uuid.isPresent() && uuid.get().equals(other.uuid.get())) || (
+                e164.isPresent() && other.e164.isPresent() && e164.get().equals(other.e164.get())
+        );
+    }
+
+    public SignalServiceAddress toSignalServiceAddress() {
+        return new SignalServiceAddress(uuid.orElse(UuidUtil.UNKNOWN_UUID),
+                org.whispersystems.libsignal.util.guava.Optional.fromNullable(e164.orElse(null)));
+    }
+
+    @Override
+    public boolean equals(final Object o) {
+        if (this == o) return true;
+        if (o == null || getClass() != o.getClass()) return false;
+
+        final RecipientAddress that = (RecipientAddress) o;
+
+        if (!uuid.equals(that.uuid)) return false;
+        return e164.equals(that.e164);
+    }
+
+    @Override
+    public int hashCode() {
+        int result = uuid.hashCode();
+        result = 31 * result + e164.hashCode();
+        return result;
+    }
+}
index c6d06d2303661efc117d353267d76137e0fd4ccf..a76e5b50dd385a682e5f0941b417234ee1ef520c 100644 (file)
@@ -2,7 +2,15 @@ package org.asamk.signal.manager.storage.recipients;
 
 import org.whispersystems.signalservice.api.push.SignalServiceAddress;
 
+import java.util.UUID;
+
 public interface RecipientResolver {
 
+    RecipientId resolveRecipient(String identifier);
+
+    RecipientId resolveRecipient(RecipientAddress address);
+
     RecipientId resolveRecipient(SignalServiceAddress address);
+
+    RecipientId resolveRecipient(UUID uuid);
 }
index c8a1134005792155b7f85f00cd6fd43bc046e55f..86164d5878cf3aa90425cfe842b2b6c804dcb90d 100644 (file)
@@ -12,6 +12,7 @@ import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.whispersystems.libsignal.util.Pair;
 import org.whispersystems.signalservice.api.push.SignalServiceAddress;
+import org.whispersystems.signalservice.api.push.exceptions.UnregisteredUserException;
 import org.whispersystems.signalservice.api.util.UuidUtil;
 
 import java.io.ByteArrayInputStream;
@@ -30,9 +31,10 @@ import java.util.Objects;
 import java.util.Optional;
 import java.util.Set;
 import java.util.UUID;
+import java.util.function.Supplier;
 import java.util.stream.Collectors;
 
-public class RecipientStore implements ContactsStore, ProfileStore {
+public class RecipientStore implements RecipientResolver, ContactsStore, ProfileStore {
 
     private final static Logger logger = LoggerFactory.getLogger(RecipientStore.class);
 
@@ -51,9 +53,8 @@ public class RecipientStore implements ContactsStore, ProfileStore {
             final var storage = objectMapper.readValue(inputStream, Storage.class);
             final var recipients = storage.recipients.stream().map(r -> {
                 final var recipientId = new RecipientId(r.id);
-                final var address = new SignalServiceAddress(org.whispersystems.libsignal.util.guava.Optional.fromNullable(
-                        r.uuid).transform(UuidUtil::parseOrThrow),
-                        org.whispersystems.libsignal.util.guava.Optional.fromNullable(r.number));
+                final var address = new RecipientAddress(Optional.ofNullable(r.uuid).map(UuidUtil::parseOrThrow),
+                        Optional.ofNullable(r.number));
 
                 Contact contact = null;
                 if (r.contact != null) {
@@ -119,7 +120,7 @@ public class RecipientStore implements ContactsStore, ProfileStore {
         this.lastId = lastId;
     }
 
-    public SignalServiceAddress resolveServiceAddress(RecipientId recipientId) {
+    public RecipientAddress resolveRecipientAddress(RecipientId recipientId) {
         synchronized (recipients) {
             return getRecipient(recipientId).getAddress();
         }
@@ -134,24 +135,52 @@ public class RecipientStore implements ContactsStore, ProfileStore {
         }
     }
 
-    @Deprecated
-    public SignalServiceAddress resolveServiceAddress(SignalServiceAddress address) {
-        return resolveServiceAddress(resolveRecipient(address, false));
+    @Override
+    public RecipientId resolveRecipient(UUID uuid) {
+        return resolveRecipient(new RecipientAddress(uuid), false);
     }
 
-    public RecipientId resolveRecipient(UUID uuid) {
-        return resolveRecipient(new SignalServiceAddress(uuid, null), false);
+    @Override
+    public RecipientId resolveRecipient(final String identifier) {
+        return resolveRecipient(Utils.getRecipientAddressFromIdentifier(identifier), false);
     }
 
-    public RecipientId resolveRecipient(String number) {
-        return resolveRecipient(new SignalServiceAddress(null, number), false);
+    public RecipientId resolveRecipient(
+            final String number, Supplier<UUID> uuidSupplier
+    ) throws UnregisteredUserException {
+        final Optional<Recipient> byNumber;
+        synchronized (recipients) {
+            byNumber = findByNumberLocked(number);
+        }
+        if (byNumber.isEmpty() || byNumber.get().getAddress().getUuid().isEmpty()) {
+            final var uuid = uuidSupplier.get();
+            if (uuid == null) {
+                throw new UnregisteredUserException(number, null);
+            }
+
+            return resolveRecipient(new RecipientAddress(uuid, number), false);
+        }
+        return byNumber.get().getRecipientId();
     }
 
-    public RecipientId resolveRecipientTrusted(SignalServiceAddress address) {
+    public RecipientId resolveRecipient(RecipientAddress address) {
+        return resolveRecipient(address, false);
+    }
+
+    @Override
+    public RecipientId resolveRecipient(final SignalServiceAddress address) {
+        return resolveRecipient(new RecipientAddress(address), false);
+    }
+
+    public RecipientId resolveRecipientTrusted(RecipientAddress address) {
         return resolveRecipient(address, true);
     }
 
-    public List<RecipientId> resolveRecipientsTrusted(List<SignalServiceAddress> addresses) {
+    public RecipientId resolveRecipientTrusted(SignalServiceAddress address) {
+        return resolveRecipient(new RecipientAddress(address), true);
+    }
+
+    public List<RecipientId> resolveRecipientsTrusted(List<RecipientAddress> addresses) {
         final List<RecipientId> recipientIds;
         final List<Pair<RecipientId, RecipientId>> toBeMerged = new ArrayList<>();
         synchronized (recipients) {
@@ -169,10 +198,6 @@ public class RecipientStore implements ContactsStore, ProfileStore {
         return recipientIds;
     }
 
-    public RecipientId resolveRecipient(SignalServiceAddress address) {
-        return resolveRecipient(address, false);
-    }
-
     @Override
     public void storeContact(final RecipientId recipientId, final Contact contact) {
         synchronized (recipients) {
@@ -262,7 +287,7 @@ public class RecipientStore implements ContactsStore, ProfileStore {
      * @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.
      */
-    private RecipientId resolveRecipient(SignalServiceAddress address, boolean isHighTrust) {
+    private RecipientId resolveRecipient(RecipientAddress address, boolean isHighTrust) {
         final Pair<RecipientId, Optional<RecipientId>> pair;
         synchronized (recipients) {
             pair = resolveRecipientLocked(address, isHighTrust);
@@ -278,30 +303,26 @@ public class RecipientStore implements ContactsStore, ProfileStore {
     }
 
     private Pair<RecipientId, Optional<RecipientId>> resolveRecipientLocked(
-            SignalServiceAddress address, boolean isHighTrust
+            RecipientAddress address, boolean isHighTrust
     ) {
-        final var byNumber = !address.getNumber().isPresent()
+        final var byNumber = address.getNumber().isEmpty()
                 ? Optional.<Recipient>empty()
-                : findByNameLocked(address.getNumber().get());
-        final var byUuid = !address.getUuid().isPresent()
+                : findByNumberLocked(address.getNumber().get());
+        final var byUuid = address.getUuid().isEmpty() || address.getUuid().get().equals(UuidUtil.UNKNOWN_UUID)
                 ? Optional.<Recipient>empty()
                 : findByUuidLocked(address.getUuid().get());
 
         if (byNumber.isEmpty() && byUuid.isEmpty()) {
             logger.debug("Got new recipient, both uuid and number are unknown");
 
-            if (isHighTrust || !address.getUuid().isPresent() || !address.getNumber().isPresent()) {
+            if (isHighTrust || address.getUuid().isEmpty() || address.getNumber().isEmpty()) {
                 return new Pair<>(addNewRecipientLocked(address), Optional.empty());
             }
 
-            return new Pair<>(addNewRecipientLocked(new SignalServiceAddress(address.getUuid().get(), null)),
-                    Optional.empty());
+            return new Pair<>(addNewRecipientLocked(new RecipientAddress(address.getUuid().get())), Optional.empty());
         }
 
-        if (!isHighTrust
-                || !address.getUuid().isPresent()
-                || !address.getNumber().isPresent()
-                || byNumber.equals(byUuid)) {
+        if (!isHighTrust || address.getUuid().isEmpty() || address.getNumber().isEmpty() || byNumber.equals(byUuid)) {
             return new Pair<>(byUuid.or(() -> byNumber).map(Recipient::getRecipientId).get(), Optional.empty());
         }
 
@@ -317,7 +338,7 @@ public class RecipientStore implements ContactsStore, ProfileStore {
                         "Got recipient existing with number, but different uuid, so stripping its number and adding new recipient");
 
                 updateRecipientAddressLocked(byNumber.get().getRecipientId(),
-                        new SignalServiceAddress(byNumber.get().getAddress().getUuid().get(), null));
+                        new RecipientAddress(byNumber.get().getAddress().getUuid().get()));
                 return new Pair<>(addNewRecipientLocked(address), Optional.empty());
             }
 
@@ -331,7 +352,7 @@ public class RecipientStore implements ContactsStore, ProfileStore {
                     "Got separate recipients for high trust number and uuid, recipient for number has different uuid, so stripping its number");
 
             updateRecipientAddressLocked(byNumber.get().getRecipientId(),
-                    new SignalServiceAddress(byNumber.get().getAddress().getUuid().get(), null));
+                    new RecipientAddress(byNumber.get().getAddress().getUuid().get()));
             updateRecipientAddressLocked(byUuid.get().getRecipientId(), address);
             return new Pair<>(byUuid.get().getRecipientId(), Optional.empty());
         }
@@ -342,14 +363,14 @@ public class RecipientStore implements ContactsStore, ProfileStore {
         return new Pair<>(byUuid.get().getRecipientId(), byNumber.map(Recipient::getRecipientId));
     }
 
-    private RecipientId addNewRecipientLocked(final SignalServiceAddress serviceAddress) {
+    private RecipientId addNewRecipientLocked(final RecipientAddress address) {
         final var nextRecipientId = nextIdLocked();
-        storeRecipientLocked(nextRecipientId, new Recipient(nextRecipientId, serviceAddress, null, null, null, null));
+        storeRecipientLocked(nextRecipientId, new Recipient(nextRecipientId, address, null, null, null, null));
         return nextRecipientId;
     }
 
     private void updateRecipientAddressLocked(
-            final RecipientId recipientId, final SignalServiceAddress address
+            final RecipientId recipientId, final RecipientAddress address
     ) {
         final var recipient = recipients.get(recipientId);
         storeRecipientLocked(recipientId, Recipient.newBuilder(recipient).withAddress(address).build());
@@ -380,7 +401,7 @@ public class RecipientStore implements ContactsStore, ProfileStore {
         saveLocked();
     }
 
-    private Optional<Recipient> findByNameLocked(final String number) {
+    private Optional<Recipient> findByNumberLocked(final String number) {
         return recipients.entrySet()
                 .stream()
                 .filter(entry -> entry.getValue().getAddress().getNumber().isPresent() && number.equals(entry.getValue()
@@ -431,8 +452,8 @@ public class RecipientStore implements ContactsStore, ProfileStore {
                                     .map(Enum::name)
                                     .collect(Collectors.toSet()));
             return new Storage.Recipient(pair.getKey().getId(),
-                    recipient.getAddress().getNumber().orNull(),
-                    recipient.getAddress().getUuid().transform(UUID::toString).orNull(),
+                    recipient.getAddress().getNumber().orElse(null),
+                    recipient.getAddress().getUuid().map(UUID::toString).orElse(null),
                     recipient.getProfileKey() == null
                             ? null
                             : base64.encodeToString(recipient.getProfileKey().serialize()),
index ef0a055bfe4f0a46c4af79777696fd2614c10d06..5738408d6826f9861e14dbb7df9b7d2d13128ed4 100644 (file)
@@ -3,7 +3,6 @@ package org.asamk.signal.manager.storage.sessions;
 import org.asamk.signal.manager.storage.recipients.RecipientId;
 import org.asamk.signal.manager.storage.recipients.RecipientResolver;
 import org.asamk.signal.manager.util.IOUtils;
-import org.asamk.signal.manager.util.Utils;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.whispersystems.libsignal.NoSessionException;
@@ -23,6 +22,7 @@ import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 import java.util.Objects;
+import java.util.Set;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 import java.util.stream.Collectors;
@@ -150,6 +150,19 @@ public class SessionStore implements SignalServiceSessionStore {
         }
     }
 
+    @Override
+    public Set<SignalProtocolAddress> getAllAddressesWithActiveSessions(final List<String> addressNames) {
+        final var recipientIdToNameMap = addressNames.stream()
+                .collect(Collectors.toMap(this::resolveRecipient, name -> name));
+        synchronized (cachedSessions) {
+            return recipientIdToNameMap.keySet()
+                    .stream()
+                    .flatMap(recipientId -> getKeysLocked(recipientId).stream())
+                    .map(key -> new SignalProtocolAddress(recipientIdToNameMap.get(key.recipientId), key.getDeviceId()))
+                    .collect(Collectors.toSet());
+        }
+    }
+
     public void archiveAllSessions() {
         synchronized (cachedSessions) {
             final var keys = getKeysLocked();
@@ -198,7 +211,7 @@ public class SessionStore implements SignalServiceSessionStore {
      * @param identifier can be either a serialized uuid or a e164 phone number
      */
     private RecipientId resolveRecipient(String identifier) {
-        return resolver.resolveRecipient(Utils.getSignalServiceAddressFromIdentifier(identifier));
+        return resolver.resolveRecipient(identifier);
     }
 
     private Key getKey(final SignalProtocolAddress address) {
index a2466311680f3580c70394c8ef5b6eea9032b38a..3530d6ad7818d1cd51454f056541d55ba8eaa98a 100644 (file)
@@ -48,11 +48,11 @@ public class Utils {
         byte[] ownId;
         byte[] theirId;
 
-        if (isUuidCapable && ownAddress.getUuid().isPresent() && theirAddress.getUuid().isPresent()) {
+        if (isUuidCapable) {
             // Version 2: UUID user
             version = 2;
-            ownId = UuidUtil.toByteArray(ownAddress.getUuid().get());
-            theirId = UuidUtil.toByteArray(theirAddress.getUuid().get());
+            ownId = UuidUtil.toByteArray(ownAddress.getUuid());
+            theirId = UuidUtil.toByteArray(theirAddress.getUuid());
         } else {
             // Version 1: E164 user
             version = 1;
@@ -69,12 +69,4 @@ public class Utils {
                 theirId,
                 theirIdentityKey);
     }
-
-    public static SignalServiceAddress getSignalServiceAddressFromIdentifier(final String identifier) {
-        if (UuidUtil.isUuid(identifier)) {
-            return new SignalServiceAddress(UuidUtil.parseOrNull(identifier), null);
-        } else {
-            return new SignalServiceAddress(null, identifier);
-        }
-    }
 }
index 4ee468455ef7b5820e5434fdff83692ef8e8253f..5978eed975da0bff1efaa5e10f0ecf8ac06dc9f0 100755 (executable)
@@ -136,8 +136,8 @@ run_main -u "$NUMBER_2" listGroups -d
 run_main -u "$NUMBER_2" --output=json listGroups -d
 run_main -u "$NUMBER_1" receive
 run_main -u "$NUMBER_1" updateGroup -g "$GROUP_ID" -m "$NUMBER_2"
-run_main -u "$NUMBER_1" block "$GROUP_ID"
-run_main -u "$NUMBER_1" unblock "$GROUP_ID"
+run_main -u "$NUMBER_1" --verbose block -g "$GROUP_ID"
+run_main -u "$NUMBER_1" --verbose unblock -g "$GROUP_ID"
 
 ## Identities
 run_main -u "$NUMBER_1" listIdentities
index 5ed6af00f7e616ccb1026758e8f20bd8d07b4e50..9433d20914bf479e3f7487c3ee1348e8299bd32b 100644 (file)
@@ -45,7 +45,7 @@ public class JsonDbusReceiveMessageHandler extends JsonReceiveMessageHandler {
                 e.printStackTrace();
             }
         } else if (content != null) {
-            final var sender = !envelope.isUnidentifiedSender() && envelope.hasSource()
+            final var sender = !envelope.isUnidentifiedSender() && envelope.hasSourceUuid()
                     ? envelope.getSourceAddress()
                     : content.getSender();
             if (content.getReceiptMessage().isPresent()) {
index 0d8f312f8d43591f0969aa8425dd43ef411f1019..96603b76bf1bff245b459c2019f7ce9b7bfb9806 100644 (file)
@@ -1,12 +1,12 @@
 package org.asamk.signal;
 
 import org.asamk.signal.manager.Manager;
+import org.asamk.signal.manager.UntrustedIdentityException;
 import org.asamk.signal.manager.api.RecipientIdentifier;
 import org.asamk.signal.manager.groups.GroupId;
 import org.asamk.signal.manager.groups.GroupUtils;
 import org.asamk.signal.util.DateUtils;
 import org.asamk.signal.util.Util;
-import org.signal.libsignal.metadata.ProtocolUntrustedIdentityException;
 import org.slf4j.helpers.MessageFormatter;
 import org.whispersystems.signalservice.api.messages.SignalServiceAttachment;
 import org.whispersystems.signalservice.api.messages.SignalServiceContent;
@@ -38,12 +38,9 @@ public class ReceiveMessageHandler implements Manager.ReceiveMessageHandler {
 
     @Override
     public void handleMessage(SignalServiceEnvelope envelope, SignalServiceContent content, Throwable exception) {
-        if (envelope.hasSource()) {
+        if (envelope.hasSourceUuid()) {
             var source = envelope.getSourceAddress();
             writer.println("Envelope from: {} (device: {})", formatContact(source), envelope.getSourceDevice());
-            if (source.getRelay().isPresent()) {
-                writer.println("Relayed by: {}", source.getRelay().get());
-            }
         } else {
             writer.println("Envelope from: unknown source");
         }
@@ -56,8 +53,8 @@ public class ReceiveMessageHandler implements Manager.ReceiveMessageHandler {
             writer.println("Got receipt.");
         } else if (envelope.isSignalMessage() || envelope.isPreKeySignalMessage() || envelope.isUnidentifiedSender()) {
             if (exception != null) {
-                if (exception instanceof ProtocolUntrustedIdentityException) {
-                    var e = (ProtocolUntrustedIdentityException) exception;
+                if (exception instanceof UntrustedIdentityException) {
+                    var e = (UntrustedIdentityException) exception;
                     writer.println(
                             "The user’s key is untrusted, either the user has reinstalled Signal or a third party sent this message.");
                     final var recipientName = getLegacyIdentifier(m.resolveSignalServiceAddress(e.getSender()));
@@ -630,7 +627,7 @@ public class ReceiveMessageHandler implements Manager.ReceiveMessageHandler {
     private void printMention(
             PlainTextWriter writer, SignalServiceDataMessage.Mention mention
     ) {
-        final var address = m.resolveSignalServiceAddress(new SignalServiceAddress(mention.getUuid(), null));
+        final var address = m.resolveSignalServiceAddress(mention.getUuid());
         writer.println("- {}: {} (length: {})", formatContact(address), mention.getStart(), mention.getLength());
     }
 
index 8d651592ee57782426b3500fea0a0c0977849ff9..8c1b9fb25764c96f54dafe6b1450e78f498a43fe 100644 (file)
@@ -74,9 +74,14 @@ public class JoinGroupCommand implements JsonRpcLocalCommand {
         } catch (GroupPatchNotAcceptedException e) {
             throw new UserErrorException("Failed to join group, maybe already a member");
         } catch (IOException e) {
-            throw new IOErrorException("Failed to send message: " + e.getMessage());
+            throw new IOErrorException("Failed to send message: "
+                    + e.getMessage()
+                    + " ("
+                    + e.getClass().getSimpleName()
+                    + ")");
         } catch (DBusExecutionException e) {
-            throw new UnexpectedErrorException("Failed to send message: " + e.getMessage());
+            throw new UnexpectedErrorException("Failed to send message: " + e.getMessage() + " (" + e.getClass()
+                    .getSimpleName() + ")");
         } catch (GroupLinkNotActiveException e) {
             throw new UserErrorException("Group link is not valid: " + e.getMessage());
         }
index b39f9ec901d21c4941fc8379e3478a5103b997bf..5e609a48e45afd54f2159eee962614e612d648d9 100644 (file)
@@ -8,7 +8,6 @@ import org.asamk.signal.OutputWriter;
 import org.asamk.signal.PlainTextWriter;
 import org.asamk.signal.manager.Manager;
 
-import java.util.UUID;
 import java.util.stream.Collectors;
 
 import static org.asamk.signal.util.Util.getLegacyIdentifier;
@@ -47,7 +46,7 @@ public class ListContactsCommand implements JsonRpcLocalCommand {
                 final var address = m.resolveSignalServiceAddress(contactPair.first());
                 final var contact = contactPair.second();
                 return new JsonContact(address.getNumber().orNull(),
-                        address.getUuid().transform(UUID::toString).orNull(),
+                        address.getUuid().toString(),
                         contact.getName(),
                         contact.isBlocked(),
                         contact.getMessageExpirationTime());
index a6a9a2f1a4daa964983870d2daf76bb1dbade095..b53577be0a754e2d19676d46bfa98ebe00122a39 100644 (file)
@@ -16,7 +16,6 @@ import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 import java.util.Set;
-import java.util.UUID;
 import java.util.stream.Collectors;
 
 public class ListGroupsCommand implements JsonRpcLocalCommand {
@@ -46,8 +45,7 @@ public class ListGroupsCommand implements JsonRpcLocalCommand {
     private static Set<JsonGroupMember> resolveJsonMembers(Manager m, Set<RecipientId> addresses) {
         return addresses.stream()
                 .map(m::resolveSignalServiceAddress)
-                .map(address -> new JsonGroupMember(address.getNumber().orNull(),
-                        address.getUuid().transform(UUID::toString).orNull()))
+                .map(address -> new JsonGroupMember(address.getNumber().orNull(), address.getUuid().toString()))
                 .collect(Collectors.toSet());
     }
 
index c859996ee27f15e8419c60c00b3909340c261f54..02cd1d9fe9b9b5f8e415c409c0907ac17ccbbd89 100644 (file)
@@ -18,7 +18,6 @@ import org.whispersystems.signalservice.api.push.SignalServiceAddress;
 
 import java.util.Base64;
 import java.util.List;
-import java.util.UUID;
 import java.util.stream.Collectors;
 
 public class ListIdentitiesCommand implements JsonRpcLocalCommand {
@@ -72,7 +71,7 @@ public class ListIdentitiesCommand implements JsonRpcLocalCommand {
                 var safetyNumber = Util.formatSafetyNumber(m.computeSafetyNumber(address, id.getIdentityKey()));
                 var scannableSafetyNumber = m.computeSafetyNumberForScanning(address, id.getIdentityKey());
                 return new JsonIdentity(address.getNumber().orNull(),
-                        address.getUuid().transform(UUID::toString).orNull(),
+                        address.getUuid().toString(),
                         Hex.toString(id.getFingerprint()),
                         safetyNumber,
                         scannableSafetyNumber == null
index 03bf232ba66aba3266554391b0dfe1e6fa892b88..c64d19cc2a95dd2d04d78185fb24a839b74ad4f9 100644 (file)
@@ -66,7 +66,11 @@ public class QuitGroupCommand implements JsonRpcLocalCommand {
                 m.deleteGroup(groupId);
             }
         } catch (IOException e) {
-            throw new IOErrorException("Failed to send message: " + e.getMessage());
+            throw new IOErrorException("Failed to send message: "
+                    + e.getMessage()
+                    + " ("
+                    + e.getClass().getSimpleName()
+                    + ")");
         } catch (GroupNotFoundException e) {
             throw new UserErrorException("Failed to send to group: " + e.getMessage());
         } catch (LastGroupAdminException e) {
index e482dd583c5ff6736cc6b19178721d0fecc67351..6e1e92f7b2058af5041f47b478c5d7e695e49023 100644 (file)
@@ -64,7 +64,8 @@ public class RemoteDeleteCommand implements DbusCommand, JsonRpcLocalCommand {
         } catch (GroupNotFoundException | NotAGroupMemberException | GroupSendingNotAllowedException e) {
             throw new UserErrorException(e.getMessage());
         } catch (IOException e) {
-            throw new UnexpectedErrorException("Failed to send message: " + e.getMessage());
+            throw new UnexpectedErrorException("Failed to send message: " + e.getMessage() + " (" + e.getClass()
+                    .getSimpleName() + ")");
         }
     }
 
@@ -104,7 +105,8 @@ public class RemoteDeleteCommand implements DbusCommand, JsonRpcLocalCommand {
         } catch (Signal.Error.GroupNotFound e) {
             throw new UserErrorException("Failed to send to group: " + e.getMessage());
         } catch (DBusExecutionException e) {
-            throw new UnexpectedErrorException("Failed to send message: " + e.getMessage());
+            throw new UnexpectedErrorException("Failed to send message: " + e.getMessage() + " (" + e.getClass()
+                    .getSimpleName() + ")");
         }
     }
 
index c29d02681d183ba63503a5597ee0867ebd859265..7ab445fc378bb914843095ae94f0d106a5b138f2 100644 (file)
@@ -85,7 +85,8 @@ public class SendCommand implements DbusCommand, JsonRpcLocalCommand {
                 m.sendEndSessionMessage(singleRecipients);
                 return;
             } catch (IOException e) {
-                throw new UnexpectedErrorException("Failed to send message: " + e.getMessage());
+                throw new UnexpectedErrorException("Failed to send message: " + e.getMessage() + " (" + e.getClass()
+                        .getSimpleName() + ")");
             }
         }
 
@@ -108,7 +109,8 @@ public class SendCommand implements DbusCommand, JsonRpcLocalCommand {
             outputResult(outputWriter, results.getTimestamp());
             ErrorUtils.handleSendMessageResults(results.getResults());
         } catch (AttachmentInvalidException | IOException e) {
-            throw new UnexpectedErrorException("Failed to send message: " + e.getMessage());
+            throw new UnexpectedErrorException("Failed to send message: " + e.getMessage() + " (" + e.getClass()
+                    .getSimpleName() + ")");
         } catch (GroupNotFoundException | NotAGroupMemberException | GroupSendingNotAllowedException e) {
             throw new UserErrorException(e.getMessage());
         }
@@ -141,9 +143,11 @@ public class SendCommand implements DbusCommand, JsonRpcLocalCommand {
                 signal.sendEndSessionMessage(recipients);
                 return;
             } catch (Signal.Error.UntrustedIdentity e) {
-                throw new UntrustedKeyErrorException("Failed to send message: " + e.getMessage());
+                throw new UntrustedKeyErrorException("Failed to send message: " + e.getMessage() + " (" + e.getClass()
+                        .getSimpleName() + ")");
             } catch (DBusExecutionException e) {
-                throw new UnexpectedErrorException("Failed to send message: " + e.getMessage());
+                throw new UnexpectedErrorException("Failed to send message: " + e.getMessage() + " (" + e.getClass()
+                        .getSimpleName() + ")");
             }
         }
 
@@ -182,7 +186,8 @@ public class SendCommand implements DbusCommand, JsonRpcLocalCommand {
                 outputResult(outputWriter, timestamp);
                 return;
             } catch (Signal.Error.UntrustedIdentity e) {
-                throw new UntrustedKeyErrorException("Failed to send message: " + e.getMessage());
+                throw new UntrustedKeyErrorException("Failed to send message: " + e.getMessage() + " (" + e.getClass()
+                        .getSimpleName() + ")");
             } catch (DBusExecutionException e) {
                 throw new UnexpectedErrorException("Failed to send note to self message: " + e.getMessage());
             }
@@ -194,9 +199,11 @@ public class SendCommand implements DbusCommand, JsonRpcLocalCommand {
         } catch (UnknownObject e) {
             throw new UserErrorException("Failed to find dbus object, maybe missing the -u flag: " + e.getMessage());
         } catch (Signal.Error.UntrustedIdentity e) {
-            throw new UntrustedKeyErrorException("Failed to send message: " + e.getMessage());
+            throw new UntrustedKeyErrorException("Failed to send message: " + e.getMessage() + " (" + e.getClass()
+                    .getSimpleName() + ")");
         } catch (DBusExecutionException e) {
-            throw new UnexpectedErrorException("Failed to send message: " + e.getMessage());
+            throw new UnexpectedErrorException("Failed to send message: " + e.getMessage() + " (" + e.getClass()
+                    .getSimpleName() + ")");
         }
     }
 
index 98e5f5ec6d416541e63333f5db52d56a86884fce..11a16b2e8a3c0aa04c43704faecad09c3fdd45ab 100644 (file)
@@ -80,7 +80,8 @@ public class SendReactionCommand implements DbusCommand, JsonRpcLocalCommand {
         } catch (GroupNotFoundException | NotAGroupMemberException | GroupSendingNotAllowedException e) {
             throw new UserErrorException(e.getMessage());
         } catch (IOException e) {
-            throw new UnexpectedErrorException("Failed to send message: " + e.getMessage());
+            throw new UnexpectedErrorException("Failed to send message: " + e.getMessage() + " (" + e.getClass()
+                    .getSimpleName() + ")");
         }
     }
 
@@ -127,7 +128,8 @@ public class SendReactionCommand implements DbusCommand, JsonRpcLocalCommand {
         } catch (Signal.Error.GroupNotFound e) {
             throw new UserErrorException("Failed to send to group: " + e.getMessage());
         } catch (DBusExecutionException e) {
-            throw new UnexpectedErrorException("Failed to send message: " + e.getMessage());
+            throw new UnexpectedErrorException("Failed to send message: " + e.getMessage() + " (" + e.getClass()
+                    .getSimpleName() + ")");
         }
     }
 
index 70e2f015adc5f4fa8dd798815ada7081c8be5782..0d5772ecc81723c747cbfd0ec37132a00c5cbc11 100644 (file)
@@ -7,8 +7,8 @@ import org.asamk.signal.OutputWriter;
 import org.asamk.signal.commands.exceptions.CommandException;
 import org.asamk.signal.commands.exceptions.UserErrorException;
 import org.asamk.signal.manager.Manager;
+import org.asamk.signal.manager.UntrustedIdentityException;
 import org.asamk.signal.util.CommandUtil;
-import org.whispersystems.signalservice.api.crypto.UntrustedIdentityException;
 
 import java.io.IOException;
 
@@ -51,7 +51,8 @@ public class SendReceiptCommand implements JsonRpcLocalCommand {
                 throw new UserErrorException("Unknown receipt type: " + type);
             }
         } catch (IOException | UntrustedIdentityException e) {
-            throw new UserErrorException("Failed to send message: " + e.getMessage());
+            throw new UserErrorException("Failed to send message: " + e.getMessage() + " (" + e.getClass()
+                    .getSimpleName() + ")");
         }
     }
 }
index ace4da8529a57e057b724b4a7418e9d302e8cacf..3a965e4751caf1b1f59315b02ed393c27158b829 100644 (file)
@@ -8,13 +8,13 @@ import org.asamk.signal.OutputWriter;
 import org.asamk.signal.commands.exceptions.CommandException;
 import org.asamk.signal.commands.exceptions.UserErrorException;
 import org.asamk.signal.manager.Manager;
+import org.asamk.signal.manager.UntrustedIdentityException;
 import org.asamk.signal.manager.api.RecipientIdentifier;
 import org.asamk.signal.manager.api.TypingAction;
 import org.asamk.signal.manager.groups.GroupNotFoundException;
 import org.asamk.signal.manager.groups.GroupSendingNotAllowedException;
 import org.asamk.signal.manager.groups.NotAGroupMemberException;
 import org.asamk.signal.util.CommandUtil;
-import org.whispersystems.signalservice.api.crypto.UntrustedIdentityException;
 
 import java.io.IOException;
 import java.util.HashSet;
@@ -59,7 +59,8 @@ public class SendTypingCommand implements JsonRpcLocalCommand {
         try {
             m.sendTypingMessage(action, recipientIdentifiers);
         } catch (IOException | UntrustedIdentityException e) {
-            throw new UserErrorException("Failed to send message: " + e.getMessage());
+            throw new UserErrorException("Failed to send message: " + e.getMessage() + " (" + e.getClass()
+                    .getSimpleName() + ")");
         } catch (GroupNotFoundException | NotAGroupMemberException | GroupSendingNotAllowedException e) {
             throw new UserErrorException("Failed to send to group: " + e.getMessage());
         }
index a8d556f3495db8733b4eee9e995ee4c1ce2f5446..6df70ac2e3416104bfc9a1b805ada8a3ca898c12 100644 (file)
@@ -174,7 +174,8 @@ public class UpdateGroupCommand implements DbusCommand, JsonRpcLocalCommand {
         } catch (GroupNotFoundException | NotAGroupMemberException | GroupSendingNotAllowedException e) {
             throw new UserErrorException(e.getMessage());
         } catch (IOException e) {
-            throw new UnexpectedErrorException("Failed to send message: " + e.getMessage());
+            throw new UnexpectedErrorException("Failed to send message: " + e.getMessage() + " (" + e.getClass()
+                    .getSimpleName() + ")");
         }
     }
 
@@ -210,7 +211,8 @@ public class UpdateGroupCommand implements DbusCommand, JsonRpcLocalCommand {
         } catch (Signal.Error.AttachmentInvalid e) {
             throw new UserErrorException("Failed to add avatar attachment for group\": " + e.getMessage());
         } catch (DBusExecutionException e) {
-            throw new UnexpectedErrorException("Failed to send message: " + e.getMessage());
+            throw new UnexpectedErrorException("Failed to send message: " + e.getMessage() + " (" + e.getClass()
+                    .getSimpleName() + ")");
         }
     }
 
index 6a7cc7649808e656dd37a510914bff401d7c79bf..0bb0c43534c33cab1b1101322da8b7dc8e4af2a1 100644 (file)
@@ -21,6 +21,7 @@ import org.whispersystems.libsignal.util.Pair;
 import org.whispersystems.libsignal.util.guava.Optional;
 import org.whispersystems.signalservice.api.groupsv2.GroupLinkNotActiveException;
 import org.whispersystems.signalservice.api.messages.SendMessageResult;
+import org.whispersystems.signalservice.api.push.exceptions.UnregisteredUserException;
 import org.whispersystems.signalservice.api.util.InvalidNumberException;
 
 import java.io.File;
@@ -244,6 +245,8 @@ public class DbusSignalImpl implements Signal {
             m.setContactName(getSingleRecipientIdentifier(number, m.getUsername()), name);
         } catch (NotMasterDeviceException e) {
             throw new Error.Failure("This command doesn't work on linked devices.");
+        } catch (UnregisteredUserException e) {
+            throw new Error.Failure("Contact is not registered.");
         }
     }
 
index f0c66d00867c3df9b3cb945aab446dabe5127364..b24768b7c38bb1a74dcfc53e6b7d525ffd4124a5 100644 (file)
@@ -4,9 +4,6 @@ import com.fasterxml.jackson.annotation.JsonProperty;
 
 import org.asamk.signal.manager.Manager;
 import org.whispersystems.signalservice.api.messages.SignalServiceDataMessage;
-import org.whispersystems.signalservice.api.push.SignalServiceAddress;
-
-import java.util.UUID;
 
 import static org.asamk.signal.util.Util.getLegacyIdentifier;
 
@@ -29,10 +26,10 @@ public class JsonMention {
     final int length;
 
     JsonMention(SignalServiceDataMessage.Mention mention, Manager m) {
-        final var address = m.resolveSignalServiceAddress(new SignalServiceAddress(mention.getUuid(), null));
+        final var address = m.resolveSignalServiceAddress(mention.getUuid());
         this.name = getLegacyIdentifier(address);
         this.number = address.getNumber().orNull();
-        this.uuid = address.getUuid().transform(UUID::toString).orNull();
+        this.uuid = address.getUuid().toString();
         this.start = mention.getStart();
         this.length = mention.getLength();
     }
index 814952aaee61c34ad302bad72914b2fd6b965d93..7b884b0e3887588013854933ab7013c0356b35d8 100644 (file)
@@ -5,14 +5,13 @@ import com.fasterxml.jackson.annotation.JsonProperty;
 
 import org.asamk.Signal;
 import org.asamk.signal.manager.Manager;
+import org.asamk.signal.manager.UntrustedIdentityException;
 import org.asamk.signal.manager.api.RecipientIdentifier;
-import org.signal.libsignal.metadata.ProtocolUntrustedIdentityException;
 import org.whispersystems.signalservice.api.messages.SignalServiceContent;
 import org.whispersystems.signalservice.api.messages.SignalServiceEnvelope;
 import org.whispersystems.signalservice.api.util.InvalidNumberException;
 
 import java.util.List;
-import java.util.UUID;
 
 import static org.asamk.signal.util.Util.getLegacyIdentifier;
 
@@ -34,10 +33,6 @@ public class JsonMessageEnvelope {
     @JsonProperty
     final Integer sourceDevice;
 
-    @JsonProperty
-    @JsonInclude(JsonInclude.Include.NON_NULL)
-    final String relay;
-
     @JsonProperty
     final long timestamp;
 
@@ -64,34 +59,30 @@ public class JsonMessageEnvelope {
     public JsonMessageEnvelope(
             SignalServiceEnvelope envelope, SignalServiceContent content, Throwable exception, Manager m
     ) {
-        if (!envelope.isUnidentifiedSender() && envelope.hasSource()) {
-            var source = envelope.getSourceAddress();
+        if (!envelope.isUnidentifiedSender() && envelope.hasSourceUuid()) {
+            var source = m.resolveSignalServiceAddress(envelope.getSourceAddress());
             this.source = getLegacyIdentifier(source);
             this.sourceNumber = source.getNumber().orNull();
-            this.sourceUuid = source.getUuid().transform(UUID::toString).orNull();
+            this.sourceUuid = source.getUuid().toString();
             this.sourceDevice = envelope.getSourceDevice();
-            this.relay = source.getRelay().orNull();
         } else if (envelope.isUnidentifiedSender() && content != null) {
-            final var source = content.getSender();
+            final var source = m.resolveSignalServiceAddress(content.getSender());
             this.source = getLegacyIdentifier(source);
             this.sourceNumber = source.getNumber().orNull();
-            this.sourceUuid = source.getUuid().transform(UUID::toString).orNull();
+            this.sourceUuid = source.getUuid().toString();
             this.sourceDevice = content.getSenderDevice();
-            this.relay = null;
-        } else if (exception instanceof ProtocolUntrustedIdentityException) {
-            var e = (ProtocolUntrustedIdentityException) exception;
+        } else if (exception instanceof UntrustedIdentityException) {
+            var e = (UntrustedIdentityException) exception;
             final var source = m.resolveSignalServiceAddress(e.getSender());
             this.source = getLegacyIdentifier(source);
             this.sourceNumber = source.getNumber().orNull();
-            this.sourceUuid = source.getUuid().transform(UUID::toString).orNull();
+            this.sourceUuid = source.getUuid().toString();
             this.sourceDevice = e.getSenderDevice();
-            this.relay = null;
         } else {
             this.source = null;
             this.sourceNumber = null;
             this.sourceUuid = null;
             this.sourceDevice = null;
-            this.relay = null;
         }
         String name;
         try {
@@ -129,7 +120,6 @@ public class JsonMessageEnvelope {
         sourceUuid = null;
         sourceName = null;
         sourceDevice = null;
-        relay = null;
         timestamp = messageReceived.getTimestamp();
         receiptMessage = null;
         dataMessage = new JsonDataMessage(messageReceived);
@@ -144,7 +134,6 @@ public class JsonMessageEnvelope {
         sourceUuid = null;
         sourceName = null;
         sourceDevice = null;
-        relay = null;
         timestamp = receiptReceived.getTimestamp();
         receiptMessage = JsonReceiptMessage.deliveryReceipt(timestamp, List.of(timestamp));
         dataMessage = null;
@@ -159,7 +148,6 @@ public class JsonMessageEnvelope {
         sourceUuid = null;
         sourceName = null;
         sourceDevice = null;
-        relay = null;
         timestamp = messageReceived.getTimestamp();
         receiptMessage = null;
         dataMessage = null;
index ecd31c1af183a419ca0fde0dd2adeeee52d83d6c..73af895ae3c60c2050ee6ce9f080a1701f292d8e 100644 (file)
@@ -8,7 +8,6 @@ import org.whispersystems.signalservice.api.messages.SignalServiceDataMessage;
 
 import java.util.ArrayList;
 import java.util.List;
-import java.util.UUID;
 import java.util.stream.Collectors;
 
 import static org.asamk.signal.util.Util.getLegacyIdentifier;
@@ -43,7 +42,7 @@ public class JsonQuote {
         final var address = m.resolveSignalServiceAddress(quote.getAuthor());
         this.author = getLegacyIdentifier(address);
         this.authorNumber = address.getNumber().orNull();
-        this.authorUuid = address.getUuid().transform(UUID::toString).orNull();
+        this.authorUuid = address.getUuid().toString();
         this.text = quote.getText();
 
         if (quote.getMentions() != null && quote.getMentions().size() > 0) {
index ecea15fe1ef71fa8f1ee09a88e1f89651c6172cb..cc80ee84eb3ac89dde1c459fb69371a325a079fc 100644 (file)
@@ -5,8 +5,6 @@ import com.fasterxml.jackson.annotation.JsonProperty;
 import org.asamk.signal.manager.Manager;
 import org.whispersystems.signalservice.api.messages.SignalServiceDataMessage.Reaction;
 
-import java.util.UUID;
-
 import static org.asamk.signal.util.Util.getLegacyIdentifier;
 
 public class JsonReaction {
@@ -35,7 +33,7 @@ public class JsonReaction {
         final var address = m.resolveSignalServiceAddress(reaction.getTargetAuthor());
         this.targetAuthor = getLegacyIdentifier(address);
         this.targetAuthorNumber = address.getNumber().orNull();
-        this.targetAuthorUuid = address.getUuid().transform(UUID::toString).orNull();
+        this.targetAuthorUuid = address.getUuid().toString();
         this.targetSentTimestamp = reaction.getTargetSentTimestamp();
         this.isRemove = reaction.isRemove();
     }
index 28c9d9369403a41fdd95d87bea0a082e21e2594f..e2c92bac2e8a2a4c17d7ddcf3b8fb95a980f42e4 100644 (file)
@@ -6,8 +6,6 @@ import org.asamk.Signal;
 import org.asamk.signal.manager.Manager;
 import org.whispersystems.signalservice.api.messages.multidevice.SentTranscriptMessage;
 
-import java.util.UUID;
-
 import static org.asamk.signal.util.Util.getLegacyIdentifier;
 
 class JsonSyncDataMessage extends JsonDataMessage {
@@ -29,7 +27,7 @@ class JsonSyncDataMessage extends JsonDataMessage {
             final var address = transcriptMessage.getDestination().get();
             this.destination = getLegacyIdentifier(address);
             this.destinationNumber = address.getNumber().orNull();
-            this.destinationUuid = address.getUuid().transform(UUID::toString).orNull();
+            this.destinationUuid = address.getUuid().toString();
         } else {
             this.destination = null;
             this.destinationNumber = null;
index df307b45cbb10f0a9abcc5ff382254e788913b7e..042ed7e4e18b3851e1598bc8ff3069bdf39041e5 100644 (file)
@@ -4,8 +4,6 @@ import com.fasterxml.jackson.annotation.JsonProperty;
 
 import org.whispersystems.signalservice.api.messages.multidevice.ReadMessage;
 
-import java.util.UUID;
-
 import static org.asamk.signal.util.Util.getLegacyIdentifier;
 
 class JsonSyncReadMessage {
@@ -27,7 +25,7 @@ class JsonSyncReadMessage {
         final var sender = readMessage.getSender();
         this.sender = getLegacyIdentifier(sender);
         this.senderNumber = sender.getNumber().orNull();
-        this.senderUuid = sender.getUuid().transform(UUID::toString).orNull();
+        this.senderUuid = sender.getUuid().toString();
         this.timestamp = readMessage.getTimestamp();
     }
 }
index 01a79dd10b52fc7811b6b9819715d33850c5ef59..b4954bf3226d6075b907d9696f0df157d1b855bf 100644 (file)
@@ -60,7 +60,7 @@ public class Util {
     }
 
     public static String getLegacyIdentifier(final SignalServiceAddress address) {
-        return address.getNumber().or(() -> address.getUuid().get().toString());
+        return address.getNumber().or(() -> address.getUuid().toString());
     }
 
     public static ObjectMapper createJsonObjectMapper() {