]> nmode's Git Repositories - signal-cli/commitdiff
Reduce use of unknown serviceIds
authorAsamK <asamk@gmx.de>
Wed, 5 Apr 2023 09:07:53 +0000 (11:07 +0200)
committerAsamK <asamk@gmx.de>
Wed, 5 Apr 2023 09:10:46 +0000 (11:10 +0200)
lib/src/main/java/org/asamk/signal/manager/ManagerImpl.java
lib/src/main/java/org/asamk/signal/manager/api/RecipientAddress.java
lib/src/main/java/org/asamk/signal/manager/helper/IdentityHelper.java
lib/src/main/java/org/asamk/signal/manager/helper/ReceiveHelper.java
lib/src/main/java/org/asamk/signal/manager/helper/RecipientHelper.java
lib/src/main/java/org/asamk/signal/manager/helper/SendHelper.java
lib/src/main/java/org/asamk/signal/manager/helper/StorageHelper.java
lib/src/main/java/org/asamk/signal/manager/storage/SignalAccount.java
lib/src/main/java/org/asamk/signal/manager/storage/identities/LegacyIdentityKeyStore.java
lib/src/main/java/org/asamk/signal/manager/storage/recipients/RecipientAddress.java
lib/src/main/java/org/asamk/signal/manager/util/Utils.java

index 1dbd9bc68087a4be2c1cf4e7a6c5748a58dc4a01..9696d956abe24b7dfb6df61b9c41bbebafcf4741 100644 (file)
@@ -676,14 +676,17 @@ class ManagerImpl implements Manager {
         var delete = new SignalServiceDataMessage.RemoteDelete(targetSentTimestamp);
         final var messageBuilder = SignalServiceDataMessage.newBuilder().withRemoteDelete(delete);
         for (final var recipient : recipients) {
-            if (recipient instanceof RecipientIdentifier.Single r) {
+            if (recipient instanceof RecipientIdentifier.Uuid u) {
+                account.getMessageSendLogStore()
+                        .deleteEntryForRecipientNonGroup(targetSentTimestamp, ServiceId.from(u.uuid()));
+            } else if (recipient instanceof RecipientIdentifier.Single r) {
                 try {
                     final var recipientId = context.getRecipientHelper().resolveRecipient(r);
-                    account.getMessageSendLogStore()
-                            .deleteEntryForRecipientNonGroup(targetSentTimestamp,
-                                    account.getRecipientAddressResolver()
-                                            .resolveRecipientAddress(recipientId)
-                                            .getServiceId());
+                    final var address = account.getRecipientAddressResolver().resolveRecipientAddress(recipientId);
+                    if (address.serviceId().isPresent()) {
+                        account.getMessageSendLogStore()
+                                .deleteEntryForRecipientNonGroup(targetSentTimestamp, address.serviceId().get());
+                    }
                 } catch (UnregisteredRecipientException ignored) {
                 }
             } else if (recipient instanceof RecipientIdentifier.Group r) {
@@ -749,8 +752,10 @@ class ManagerImpl implements Manager {
                 final var serviceId = context.getAccount()
                         .getRecipientAddressResolver()
                         .resolveRecipientAddress(recipientId)
-                        .getServiceId();
-                account.getAciSessionStore().deleteAllSessions(serviceId);
+                        .serviceId();
+                if (serviceId.isPresent()) {
+                    account.getAciSessionStore().deleteAllSessions(serviceId.get());
+                }
             }
         }
     }
@@ -1131,9 +1136,12 @@ class ManagerImpl implements Manager {
     public List<Identity> getIdentities(RecipientIdentifier.Single recipient) {
         ServiceId serviceId;
         try {
-            serviceId = account.getRecipientAddressResolver()
-                    .resolveRecipientAddress(context.getRecipientHelper().resolveRecipient(recipient))
-                    .getServiceId();
+            final var address = account.getRecipientAddressResolver()
+                    .resolveRecipientAddress(context.getRecipientHelper().resolveRecipient(recipient));
+            if (address.serviceId().isEmpty()) {
+                return List.of();
+            }
+            serviceId = address.serviceId().get();
         } catch (UnregisteredRecipientException e) {
             return List.of();
         }
index ee3bded9cb148f14cb912bc87427db4881936923..f500e3a93e60c2f5b8fdf07ee461eaf10d1279cb 100644 (file)
@@ -39,10 +39,6 @@ public record RecipientAddress(Optional<UUID> uuid, Optional<String> number, Opt
         this(Optional.of(uuid), Optional.empty(), Optional.empty());
     }
 
-    public ServiceId getServiceId() {
-        return ServiceId.from(uuid.orElse(UNKNOWN_UUID));
-    }
-
     public String getIdentifier() {
         if (uuid.isPresent()) {
             return uuid.get().toString();
index b908823ae8236a2587001ab770f69c0a469db66a..df762c91801610050d7a2c6c1097bd4e53c81396 100644 (file)
@@ -2,7 +2,6 @@ package org.asamk.signal.manager.helper;
 
 import org.asamk.signal.manager.api.TrustLevel;
 import org.asamk.signal.manager.storage.SignalAccount;
-import org.asamk.signal.manager.storage.recipients.RecipientAddress;
 import org.asamk.signal.manager.storage.recipients.RecipientId;
 import org.asamk.signal.manager.util.Utils;
 import org.signal.libsignal.protocol.IdentityKey;
@@ -17,7 +16,7 @@ import org.whispersystems.signalservice.api.push.ServiceId;
 
 import java.io.IOException;
 import java.util.Arrays;
-import java.util.function.Function;
+import java.util.function.BiFunction;
 
 import static org.asamk.signal.manager.config.ServiceConfig.capabilities;
 
@@ -34,22 +33,19 @@ public class IdentityHelper {
     }
 
     public boolean trustIdentityVerified(RecipientId recipientId, byte[] fingerprint) {
-        final var serviceId = account.getRecipientAddressResolver().resolveRecipientAddress(recipientId).getServiceId();
-        return trustIdentity(serviceId,
-                identityKey -> Arrays.equals(identityKey.serialize(), fingerprint),
+        return trustIdentity(recipientId,
+                (serviceId, identityKey) -> Arrays.equals(identityKey.serialize(), fingerprint),
                 TrustLevel.TRUSTED_VERIFIED);
     }
 
     public boolean trustIdentityVerifiedSafetyNumber(RecipientId recipientId, String safetyNumber) {
-        final var serviceId = account.getRecipientAddressResolver().resolveRecipientAddress(recipientId).getServiceId();
-        return trustIdentity(serviceId,
-                identityKey -> safetyNumber.equals(computeSafetyNumber(serviceId, identityKey)),
+        return trustIdentity(recipientId,
+                (serviceId, identityKey) -> safetyNumber.equals(computeSafetyNumber(serviceId, identityKey)),
                 TrustLevel.TRUSTED_VERIFIED);
     }
 
     public boolean trustIdentityVerifiedSafetyNumber(RecipientId recipientId, byte[] safetyNumber) {
-        final var serviceId = account.getRecipientAddressResolver().resolveRecipientAddress(recipientId).getServiceId();
-        return trustIdentity(serviceId, identityKey -> {
+        return trustIdentity(recipientId, (serviceId, identityKey) -> {
             final var fingerprint = computeSafetyNumberForScanning(serviceId, identityKey);
             try {
                 return fingerprint != null && fingerprint.compareTo(safetyNumber);
@@ -60,8 +56,7 @@ public class IdentityHelper {
     }
 
     public boolean trustIdentityAllKeys(RecipientId recipientId) {
-        final var serviceId = account.getRecipientAddressResolver().resolveRecipientAddress(recipientId).getServiceId();
-        return trustIdentity(serviceId, identityKey -> true, TrustLevel.TRUSTED_UNVERIFIED);
+        return trustIdentity(recipientId, (serviceId, identityKey) -> true, TrustLevel.TRUSTED_UNVERIFIED);
     }
 
     public String computeSafetyNumber(ServiceId serviceId, IdentityKey theirIdentityKey) {
@@ -77,35 +72,50 @@ public class IdentityHelper {
     private Fingerprint computeSafetyNumberFingerprint(
             final ServiceId serviceId, final IdentityKey theirIdentityKey
     ) {
-        final var address = account.getRecipientAddressResolver()
-                .resolveRecipientAddress(account.getRecipientResolver().resolveRecipient(serviceId));
+        final var recipientId = account.getRecipientResolver().resolveRecipient(serviceId);
+        final var address = account.getRecipientAddressResolver().resolveRecipientAddress(recipientId);
 
-        return Utils.computeSafetyNumber(capabilities.getUuid(),
-                account.getSelfRecipientAddress(),
+        if (capabilities.getUuid()) {
+            if (serviceId.isUnknown()) {
+                return null;
+            }
+            return Utils.computeSafetyNumberForUuid(account.getAci(),
+                    account.getAciIdentityKeyPair().getPublicKey(),
+                    serviceId,
+                    theirIdentityKey);
+        }
+        if (address.number().isEmpty()) {
+            return null;
+        }
+        return Utils.computeSafetyNumberForNumber(account.getNumber(),
                 account.getAciIdentityKeyPair().getPublicKey(),
-                address.getServiceId().equals(serviceId)
-                        ? address
-                        : new RecipientAddress(serviceId, address.number().orElse(null)),
+                address.number().get(),
                 theirIdentityKey);
     }
 
     private boolean trustIdentity(
-            ServiceId serviceId, Function<IdentityKey, Boolean> verifier, TrustLevel trustLevel
+            RecipientId recipientId, BiFunction<ServiceId, IdentityKey, Boolean> verifier, TrustLevel trustLevel
     ) {
+        final var serviceId = account.getRecipientAddressResolver()
+                .resolveRecipientAddress(recipientId)
+                .serviceId()
+                .orElse(null);
+        if (serviceId == null) {
+            return false;
+        }
         var identity = account.getIdentityKeyStore().getIdentityInfo(serviceId);
         if (identity == null) {
             return false;
         }
 
-        if (!verifier.apply(identity.getIdentityKey())) {
+        if (!verifier.apply(serviceId, identity.getIdentityKey())) {
             return false;
         }
 
         account.getIdentityKeyStore().setIdentityTrustLevel(serviceId, identity.getIdentityKey(), trustLevel);
         try {
-            final var address = account.getRecipientAddressResolver()
-                    .resolveRecipientAddress(account.getRecipientResolver().resolveRecipient(serviceId))
-                    .toSignalServiceAddress();
+            final var address = context.getRecipientHelper()
+                    .resolveSignalServiceAddress(account.getRecipientResolver().resolveRecipient(serviceId));
             context.getSyncHelper().sendVerifiedMessage(address, identity.getIdentityKey(), trustLevel);
         } catch (IOException e) {
             logger.warn("Failed to send verification sync message: {}", e.getMessage());
index 2c5dbe69b1ebac51a10b2438c5e36075bfc1f192..c20fc692ef3820d0a7207906a0f1842dc2ef097d 100644 (file)
@@ -12,6 +12,7 @@ import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.whispersystems.signalservice.api.SignalWebSocket;
 import org.whispersystems.signalservice.api.messages.SignalServiceEnvelope;
+import org.whispersystems.signalservice.api.push.ServiceId;
 import org.whispersystems.signalservice.api.websocket.WebSocketConnectionState;
 import org.whispersystems.signalservice.api.websocket.WebSocketUnavailableException;
 
@@ -225,8 +226,9 @@ public class ReceiveHelper {
                 if (exception instanceof UntrustedIdentityException) {
                     logger.debug("Keeping message with untrusted identity in message cache");
                     final var address = ((UntrustedIdentityException) exception).getSender();
-                    final var recipientId = account.getRecipientResolver().resolveRecipient(address.getServiceId());
-                    if (!envelope.hasSourceUuid()) {
+                    if (!envelope.hasSourceUuid() && address.uuid().isPresent()) {
+                        final var recipientId = account.getRecipientResolver()
+                                .resolveRecipient(ServiceId.from(address.uuid().get()));
                         try {
                             cachedMessage[0] = account.getMessageCache().replaceSender(cachedMessage[0], recipientId);
                         } catch (IOException ioException) {
index 9243cebabc795e694775769167301d7d6529268c..2a3866a5b00bd83f39c90cea3bc896f0138b778f 100644 (file)
@@ -182,8 +182,8 @@ public class RecipientHelper {
     public record RegisteredUser(Optional<ACI> aci, Optional<PNI> pni) {
 
         public RegisteredUser {
-            aci = aci.isPresent() && aci.get().equals(ServiceId.UNKNOWN) ? Optional.empty() : aci;
-            pni = pni.isPresent() && pni.get().equals(ServiceId.UNKNOWN) ? Optional.empty() : pni;
+            aci = aci.isPresent() && aci.get().isUnknown() ? Optional.empty() : aci;
+            pni = pni.isPresent() && pni.get().isUnknown() ? Optional.empty() : pni;
             if (aci.isEmpty() && pni.isEmpty()) {
                 throw new AssertionError("Must have either a ACI or PNI!");
             }
index d14c380735b1e82e29dd8aac3142896bea60da39..0f4d035ddfa4f5491a34418c15f5a403544c5f2f 100644 (file)
@@ -492,7 +492,11 @@ public class SendHelper {
 
             final var serviceId = account.getRecipientAddressResolver()
                     .resolveRecipientAddress(recipientId)
-                    .getServiceId();
+                    .serviceId()
+                    .orElse(null);
+            if (serviceId == null) {
+                continue;
+            }
             final var identity = account.getIdentityKeyStore().getIdentityInfo(serviceId);
             if (identity == null || !identity.getTrustLevel().isTrusted()) {
                 continue;
index 68eab7f04dfc22e998ddf2d82370a6317c14bee2..50eceb676837746c16fb0ae12689511c9ae26de3 100644 (file)
@@ -101,11 +101,15 @@ public class StorageHelper {
         }
 
         final var contactRecord = record.getContact().get();
-        final var address = new RecipientAddress(contactRecord.getServiceId(), contactRecord.getNumber().orElse(null));
+        final var serviceId = contactRecord.getServiceId();
+        if (contactRecord.getNumber().isEmpty() && serviceId.isUnknown()) {
+            return;
+        }
+        final var address = new RecipientAddress(serviceId, contactRecord.getNumber().orElse(null));
         var recipientId = account.getRecipientResolver().resolveRecipient(address);
-        if (contactRecord.getUsername().isPresent()) {
+        if (serviceId.isValid() && contactRecord.getUsername().isPresent()) {
             recipientId = account.getRecipientTrustedResolver()
-                    .resolveRecipientTrusted(contactRecord.getServiceId(), contactRecord.getUsername().get());
+                    .resolveRecipientTrusted(serviceId, contactRecord.getUsername().get());
         }
 
         final var contact = account.getContactStore().getContact(recipientId);
@@ -166,16 +170,15 @@ public class StorageHelper {
                 logger.warn("Received invalid contact profile key from storage");
             }
         }
-        if (contactRecord.getIdentityKey().isPresent()) {
+        if (contactRecord.getIdentityKey().isPresent() && serviceId.isValid()) {
             try {
                 logger.trace("Storing identity key {}", recipientId);
                 final var identityKey = new IdentityKey(contactRecord.getIdentityKey().get());
-                account.getIdentityKeyStore().saveIdentity(address.getServiceId(), identityKey);
+                account.getIdentityKeyStore().saveIdentity(serviceId, identityKey);
 
                 final var trustLevel = TrustLevel.fromIdentityState(contactRecord.getIdentityState());
                 if (trustLevel != null) {
-                    account.getIdentityKeyStore()
-                            .setIdentityTrustLevel(address.getServiceId(), identityKey, trustLevel);
+                    account.getIdentityKeyStore().setIdentityTrustLevel(serviceId, identityKey, trustLevel);
                 }
             } catch (InvalidKeyException e) {
                 logger.warn("Received invalid contact identity key from storage");
index b104eb84931341d2da5804fd28af0ea9e75fcfa3..bd892c5dddf6d66da1d4253fe9803ea53a0ad8c7 100644 (file)
@@ -813,7 +813,7 @@ public class SignalAccount implements Closeable {
                 if (identity.getAddress().serviceId().isEmpty()) {
                     continue;
                 }
-                final var serviceId = identity.getAddress().getServiceId();
+                final var serviceId = identity.getAddress().serviceId().get();
                 getIdentityKeyStore().saveIdentity(serviceId, identity.getIdentityKey());
                 getIdentityKeyStore().setIdentityTrustLevel(serviceId,
                         identity.getIdentityKey(),
index aa800a042bc93f0662e2567b8e6fb0bd14bd055a..a2f5162eb245f8dd4f9603c12ff77a43e49bab8c 100644 (file)
@@ -72,6 +72,10 @@ public class LegacyIdentityKeyStore {
         if (!file.exists()) {
             return null;
         }
+        final var address = addressResolver.resolveRecipientAddress(recipientId);
+        if (address.serviceId().isEmpty()) {
+            return null;
+        }
         try (var inputStream = new FileInputStream(file)) {
             var storage = objectMapper.readValue(inputStream, IdentityStorage.class);
 
@@ -79,7 +83,7 @@ public class LegacyIdentityKeyStore {
             var trustLevel = TrustLevel.fromInt(storage.trustLevel());
             var added = storage.addedTimestamp();
 
-            final var serviceId = addressResolver.resolveRecipientAddress(recipientId).getServiceId();
+            final var serviceId = address.serviceId().get();
             return new IdentityInfo(serviceId, id, trustLevel, added);
         } catch (IOException | InvalidKeyException e) {
             logger.warn("Failed to load identity key: {}", e.getMessage());
index d94a93a3dd9067a30816f03402e14d2205a06740..f323a5cb2c008cf88da3e7b00bab0f8488daabdb 100644 (file)
@@ -17,10 +17,10 @@ public record RecipientAddress(
      * @param number    The phone number of the user, if available.
      */
     public RecipientAddress {
-        if (serviceId.isPresent() && serviceId.get().equals(ServiceId.UNKNOWN)) {
+        if (serviceId.isPresent() && serviceId.get().isUnknown()) {
             serviceId = Optional.empty();
         }
-        if (pni.isPresent() && pni.get().equals(ServiceId.UNKNOWN)) {
+        if (pni.isPresent() && pni.get().isUnknown()) {
             pni = Optional.empty();
         }
         if (serviceId.isEmpty() && pni.isPresent()) {
@@ -88,10 +88,6 @@ public record RecipientAddress(
                 address.username.equals(this.username) ? Optional.empty() : this.username);
     }
 
-    public ServiceId getServiceId() {
-        return serviceId.orElse(ServiceId.UNKNOWN);
-    }
-
     public String getIdentifier() {
         if (serviceId.isPresent()) {
             return serviceId.get().toString();
@@ -173,7 +169,7 @@ public record RecipientAddress(
     }
 
     public SignalServiceAddress toSignalServiceAddress() {
-        return new SignalServiceAddress(getServiceId(), number);
+        return new SignalServiceAddress(serviceId.orElse(ServiceId.UNKNOWN), number);
     }
 
     public org.asamk.signal.manager.api.RecipientAddress toApiRecipientAddress() {
index efa72bf2abb9b350836126f7b202566d30ba6b97..16e80e453f663b697e907190817ff04fb2db8e45 100644 (file)
@@ -1,12 +1,12 @@
 package org.asamk.signal.manager.util;
 
 import org.asamk.signal.manager.api.Pair;
-import org.asamk.signal.manager.storage.recipients.RecipientAddress;
 import org.signal.libsignal.protocol.IdentityKey;
 import org.signal.libsignal.protocol.fingerprint.Fingerprint;
 import org.signal.libsignal.protocol.fingerprint.NumericFingerprintGenerator;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
+import org.whispersystems.signalservice.api.push.ServiceId;
 import org.whispersystems.signalservice.api.util.StreamDetails;
 import org.whispersystems.signalservice.internal.ServiceResponse;
 
@@ -56,31 +56,35 @@ public class Utils {
         }
     }
 
-    public static Fingerprint computeSafetyNumber(
-            boolean isUuidCapable,
-            RecipientAddress ownAddress,
-            IdentityKey ownIdentityKey,
-            RecipientAddress theirAddress,
-            IdentityKey theirIdentityKey
+    public static Fingerprint computeSafetyNumberForNumber(
+            String ownNumber, IdentityKey ownIdentityKey, String theirNumber, IdentityKey theirIdentityKey
     ) {
-        int version;
-        byte[] ownId;
-        byte[] theirId;
-
-        if (!isUuidCapable && ownAddress.number().isPresent() && theirAddress.number().isPresent()) {
-            // Version 1: E164 user
-            version = 1;
-            ownId = ownAddress.number().get().getBytes();
-            theirId = theirAddress.number().get().getBytes();
-        } else if (isUuidCapable && theirAddress.serviceId().isPresent()) {
-            // Version 2: UUID user
-            version = 2;
-            ownId = ownAddress.getServiceId().toByteArray();
-            theirId = theirAddress.getServiceId().toByteArray();
-        } else {
-            return null;
-        }
+        // Version 1: E164 user
+        final var version = 1;
+        final var ownId = ownNumber.getBytes(StandardCharsets.UTF_8);
+        final var theirId = theirNumber.getBytes(StandardCharsets.UTF_8);
+
+        return getFingerprint(version, ownId, ownIdentityKey, theirId, theirIdentityKey);
+    }
+
+    public static Fingerprint computeSafetyNumberForUuid(
+            ServiceId ownServiceId, IdentityKey ownIdentityKey, ServiceId theirServiceId, IdentityKey theirIdentityKey
+    ) {
+        // Version 2: UUID user
+        final var version = 2;
+        final var ownId = ownServiceId.toByteArray();
+        final var theirId = theirServiceId.toByteArray();
+
+        return getFingerprint(version, ownId, ownIdentityKey, theirId, theirIdentityKey);
+    }
 
+    private static Fingerprint getFingerprint(
+            final int version,
+            final byte[] ownId,
+            final IdentityKey ownIdentityKey,
+            final byte[] theirId,
+            final IdentityKey theirIdentityKey
+    ) {
         return new NumericFingerprintGenerator(5200).createFor(version,
                 ownId,
                 ownIdentityKey,