]> nmode's Git Repositories - signal-cli/blobdiff - lib/src/main/java/org/asamk/signal/manager/helper/IncomingMessageHandler.java
Update libsignal-service-java
[signal-cli] / lib / src / main / java / org / asamk / signal / manager / helper / IncomingMessageHandler.java
index cad112b52002fbf3d62a39d67e84d94f8f45aad1..dd9cb38fa5e9dd431b3216ffc699d87814c8fb85 100644 (file)
@@ -6,7 +6,6 @@ import org.asamk.signal.manager.actions.RefreshPreKeysAction;
 import org.asamk.signal.manager.actions.RenewSessionAction;
 import org.asamk.signal.manager.actions.ResendMessageAction;
 import org.asamk.signal.manager.actions.RetrieveProfileAction;
-import org.asamk.signal.manager.actions.RetrieveStorageDataAction;
 import org.asamk.signal.manager.actions.SendGroupInfoAction;
 import org.asamk.signal.manager.actions.SendGroupInfoRequestAction;
 import org.asamk.signal.manager.actions.SendProfileKeyAction;
@@ -17,12 +16,12 @@ import org.asamk.signal.manager.actions.SendSyncConfigurationAction;
 import org.asamk.signal.manager.actions.SendSyncContactsAction;
 import org.asamk.signal.manager.actions.SendSyncGroupsAction;
 import org.asamk.signal.manager.actions.SendSyncKeysAction;
+import org.asamk.signal.manager.actions.SyncStorageDataAction;
 import org.asamk.signal.manager.actions.UpdateAccountAttributesAction;
 import org.asamk.signal.manager.api.GroupId;
 import org.asamk.signal.manager.api.GroupNotFoundException;
 import org.asamk.signal.manager.api.MessageEnvelope;
 import org.asamk.signal.manager.api.Pair;
-import org.asamk.signal.manager.api.Profile;
 import org.asamk.signal.manager.api.ReceiveConfig;
 import org.asamk.signal.manager.api.StickerPackId;
 import org.asamk.signal.manager.api.TrustLevel;
@@ -32,6 +31,7 @@ import org.asamk.signal.manager.internal.SignalDependencies;
 import org.asamk.signal.manager.jobs.RetrieveStickerPackJob;
 import org.asamk.signal.manager.storage.SignalAccount;
 import org.asamk.signal.manager.storage.groups.GroupInfoV1;
+import org.asamk.signal.manager.storage.recipients.RecipientAddress;
 import org.asamk.signal.manager.storage.recipients.RecipientId;
 import org.asamk.signal.manager.storage.stickers.StickerPack;
 import org.signal.libsignal.metadata.ProtocolInvalidKeyException;
@@ -40,12 +40,10 @@ import org.signal.libsignal.metadata.ProtocolInvalidMessageException;
 import org.signal.libsignal.metadata.ProtocolNoSessionException;
 import org.signal.libsignal.metadata.ProtocolUntrustedIdentityException;
 import org.signal.libsignal.metadata.SelfSendException;
-import org.signal.libsignal.protocol.IdentityKeyPair;
 import org.signal.libsignal.protocol.InvalidMessageException;
+import org.signal.libsignal.protocol.UsePqRatchet;
 import org.signal.libsignal.protocol.groups.GroupSessionBuilder;
 import org.signal.libsignal.protocol.message.DecryptionErrorMessage;
-import org.signal.libsignal.protocol.state.KyberPreKeyRecord;
-import org.signal.libsignal.protocol.state.SignedPreKeyRecord;
 import org.signal.libsignal.zkgroup.InvalidInputException;
 import org.signal.libsignal.zkgroup.profiles.ProfileKey;
 import org.slf4j.Logger;
@@ -60,7 +58,6 @@ import org.whispersystems.signalservice.api.messages.SignalServiceEnvelope;
 import org.whispersystems.signalservice.api.messages.SignalServiceGroup;
 import org.whispersystems.signalservice.api.messages.SignalServiceGroupContext;
 import org.whispersystems.signalservice.api.messages.SignalServiceGroupV2;
-import org.whispersystems.signalservice.api.messages.SignalServiceMetadata;
 import org.whispersystems.signalservice.api.messages.SignalServicePniSignatureMessage;
 import org.whispersystems.signalservice.api.messages.SignalServiceReceiptMessage;
 import org.whispersystems.signalservice.api.messages.SignalServiceStoryMessage;
@@ -68,13 +65,10 @@ import org.whispersystems.signalservice.api.messages.multidevice.SignalServiceSy
 import org.whispersystems.signalservice.api.messages.multidevice.StickerPackOperationMessage;
 import org.whispersystems.signalservice.api.push.ServiceId;
 import org.whispersystems.signalservice.api.push.ServiceId.ACI;
-import org.whispersystems.signalservice.api.push.ServiceId.PNI;
+import org.whispersystems.signalservice.api.push.ServiceIdType;
 import org.whispersystems.signalservice.api.push.SignalServiceAddress;
-import org.whispersystems.signalservice.internal.push.SignalServiceProtos;
+import org.whispersystems.signalservice.internal.push.Envelope;
 import org.whispersystems.signalservice.internal.push.UnsupportedDataMessageException;
-import org.whispersystems.signalservice.internal.serialize.SignalServiceAddressProtobufSerializer;
-import org.whispersystems.signalservice.internal.serialize.SignalServiceMetadataProtobufSerializer;
-import org.whispersystems.signalservice.internal.serialize.protos.SignalServiceContentProto;
 
 import java.util.ArrayList;
 import java.util.List;
@@ -83,7 +77,7 @@ import java.util.stream.Collectors;
 
 public final class IncomingMessageHandler {
 
-    private final static Logger logger = LoggerFactory.getLogger(IncomingMessageHandler.class);
+    private static final Logger logger = LoggerFactory.getLogger(IncomingMessageHandler.class);
 
     private final SignalAccount account;
     private final SignalDependencies dependencies;
@@ -108,9 +102,11 @@ public final class IncomingMessageHandler {
         SignalServiceContent content = null;
         if (!envelope.isReceipt()) {
             account.getIdentityKeyStore().setRetryingDecryption(true);
+            final var destination = getDestination(envelope).serviceId();
             try {
-                final var cipherResult = dependencies.getCipher()
-                        .decrypt(envelope.getProto(), envelope.getServerDeliveredTimestamp());
+                final var cipherResult = dependencies.getCipher(destination == null
+                                || destination.equals(account.getAci()) ? ServiceIdType.ACI : ServiceIdType.PNI)
+                        .decrypt(envelope.getProto(), envelope.getServerDeliveredTimestamp(), UsePqRatchet.NO);
                 content = validate(envelope.getProto(), cipherResult, envelope.getServerDeliveredTimestamp());
                 if (content == null) {
                     return new Pair<>(List.of(), null);
@@ -139,19 +135,16 @@ public final class IncomingMessageHandler {
         final var actions = new ArrayList<HandleAction>();
         SignalServiceContent content = null;
         Exception exception = null;
-        try {
-            if (envelope.hasSourceServiceId()) {
+        envelope.getSourceServiceId().map(ServiceId::parseOrNull)
                 // Store uuid if we don't have it already
                 // uuid in envelope is sent by server
-                account.getRecipientTrustedResolver().resolveRecipientTrusted(envelope.getSourceAddress());
-            }
-        } catch (Exception e) {
-            exception = e;
-        }
+                .ifPresent(serviceId -> account.getRecipientResolver().resolveRecipient(serviceId));
         if (!envelope.isReceipt()) {
+            final var destination = getDestination(envelope).serviceId();
             try {
-                final var cipherResult = dependencies.getCipher()
-                        .decrypt(envelope.getProto(), envelope.getServerDeliveredTimestamp());
+                final var cipherResult = dependencies.getCipher(destination == null
+                                || destination.equals(account.getAci()) ? ServiceIdType.ACI : ServiceIdType.PNI)
+                        .decrypt(envelope.getProto(), envelope.getServerDeliveredTimestamp(), UsePqRatchet.NO);
                 content = validate(envelope.getProto(), cipherResult, envelope.getServerDeliveredTimestamp());
                 if (content == null) {
                     return new Pair<>(List.of(), null);
@@ -165,34 +158,22 @@ public final class IncomingMessageHandler {
             } catch (ProtocolInvalidKeyIdException | ProtocolInvalidKeyException | ProtocolNoSessionException |
                      ProtocolInvalidMessageException e) {
                 logger.debug("Failed to decrypt incoming message", e);
+                if (e instanceof ProtocolInvalidKeyIdException) {
+                    actions.add(RefreshPreKeysAction.create());
+                }
                 final var sender = account.getRecipientResolver().resolveRecipient(e.getSender());
                 if (context.getContactHelper().isContactBlocked(sender)) {
                     logger.debug("Received invalid message from blocked contact, ignoring.");
                 } else {
-                    final var senderProfile = context.getProfileHelper().getRecipientProfile(sender);
-                    final var selfProfile = context.getProfileHelper().getSelfProfile();
                     var serviceId = ServiceId.parseOrNull(e.getSender());
-                    if (serviceId == null) {
-                        // Workaround for libsignal-client issue #492
-                        serviceId = account.getRecipientAddressResolver()
-                                .resolveRecipientAddress(sender)
-                                .serviceId()
-                                .orElse(null);
-                    }
                     if (serviceId != null) {
                         final var isSelf = sender.equals(account.getSelfRecipientId())
                                 && e.getSenderDevice() == account.getDeviceId();
-                        final var isSenderSenderKeyCapable = senderProfile != null && senderProfile.getCapabilities()
-                                .contains(Profile.Capability.senderKey);
-                        final var isSelfSenderKeyCapable = selfProfile != null && selfProfile.getCapabilities()
-                                .contains(Profile.Capability.senderKey);
-                        final var destination = getDestination(envelope).serviceId();
-                        if (!isSelf && isSenderSenderKeyCapable && isSelfSenderKeyCapable) {
+                        logger.debug("Received invalid message, queuing renew session action.");
+                        actions.add(new RenewSessionAction(sender, serviceId, destination));
+                        if (!isSelf) {
                             logger.debug("Received invalid message, requesting message resend.");
-                            actions.add(new SendRetryMessageRequestAction(sender, serviceId, e, envelope, destination));
-                        } else {
-                            logger.debug("Received invalid message, queuing renew session action.");
-                            actions.add(new RenewSessionAction(sender, serviceId, destination));
+                            actions.add(new SendRetryMessageRequestAction(sender, e, envelope));
                         }
                     } else {
                         logger.debug("Received invalid message from invalid sender: {}", e.getSender());
@@ -213,11 +194,13 @@ public final class IncomingMessageHandler {
     }
 
     private SignalServiceContent validate(
-            SignalServiceProtos.Envelope envelope, SignalServiceCipherResult cipherResult, long serverDeliveredTimestamp
+            Envelope envelope,
+            SignalServiceCipherResult cipherResult,
+            long serverDeliveredTimestamp
     ) throws ProtocolInvalidKeyException, ProtocolInvalidMessageException, UnsupportedDataMessageException, InvalidMessageStructureException {
         final var content = cipherResult.getContent();
         final var envelopeMetadata = cipherResult.getMetadata();
-        final var validationResult = EnvelopeContentValidator.INSTANCE.validate(envelope, content);
+        final var validationResult = EnvelopeContentValidator.INSTANCE.validate(envelope, content, account.getAci());
 
         if (validationResult instanceof EnvelopeContentValidator.Result.Invalid v) {
             logger.warn("Invalid content! {}", v.getReason(), v.getThrowable());
@@ -231,26 +214,11 @@ public final class IncomingMessageHandler {
             return null;
         }
 
-        final var localAddress = new SignalServiceAddress(envelopeMetadata.getDestinationServiceId(),
-                Optional.ofNullable(account.getNumber()));
-        final var metadata = new SignalServiceMetadata(new SignalServiceAddress(envelopeMetadata.getSourceServiceId(),
-                Optional.ofNullable(envelopeMetadata.getSourceE164())),
-                envelopeMetadata.getSourceDeviceId(),
-                envelope.getTimestamp(),
-                envelope.getServerTimestamp(),
-                serverDeliveredTimestamp,
-                envelopeMetadata.getSealedSender(),
-                envelope.getServerGuid(),
-                Optional.ofNullable(envelopeMetadata.getGroupId()),
-                envelopeMetadata.getDestinationServiceId().toString());
-
-        final var contentProto = SignalServiceContentProto.newBuilder()
-                .setLocalAddress(SignalServiceAddressProtobufSerializer.toProtobuf(localAddress))
-                .setMetadata(SignalServiceMetadataProtobufSerializer.toProtobuf(metadata))
-                .setContent(content)
-                .build();
-
-        return SignalServiceContent.createFromProto(contentProto);
+        return SignalServiceContent.Companion.createFrom(account.getNumber(),
+                envelope,
+                envelopeMetadata,
+                content,
+                serverDeliveredTimestamp);
     }
 
     private List<HandleAction> checkAndHandleMessage(
@@ -318,7 +286,9 @@ public final class IncomingMessageHandler {
     }
 
     public List<HandleAction> handleMessage(
-            SignalServiceEnvelope envelope, SignalServiceContent content, ReceiveConfig receiveConfig
+            SignalServiceEnvelope envelope,
+            SignalServiceContent content,
+            ReceiveConfig receiveConfig
     ) {
         var actions = new ArrayList<HandleAction>();
         final var senderDeviceAddress = getSender(envelope, content);
@@ -327,6 +297,12 @@ public final class IncomingMessageHandler {
         final var senderDeviceId = senderDeviceAddress.deviceId();
         final var destination = getDestination(envelope);
 
+        if (account.getPni().equals(destination.serviceId)) {
+            account.getRecipientStore().markNeedsPniSignature(destination.recipientId, true);
+        } else if (account.getAci().equals(destination.serviceId)) {
+            account.getRecipientStore().markNeedsPniSignature(destination.recipientId, false);
+        }
+
         if (content.getReceiptMessage().isPresent()) {
             final var message = content.getReceiptMessage().get();
             if (message.isDeliveryReceipt()) {
@@ -363,8 +339,10 @@ public final class IncomingMessageHandler {
             }
         }
 
-        if (content.getDataMessage().isPresent()) {
-            var message = content.getDataMessage().get();
+        if (content.getDataMessage().isPresent() || content.getEditMessage().isPresent()) {
+            var message = content.getDataMessage().isPresent()
+                    ? content.getDataMessage().get()
+                    : content.getEditMessage().get().getDataMessage();
 
             if (content.isNeedsReceipt()) {
                 actions.add(new SendReceiptAction(sender,
@@ -411,7 +389,8 @@ public final class IncomingMessageHandler {
     }
 
     private boolean handlePniSignatureMessage(
-            final SignalServicePniSignatureMessage message, final SignalServiceAddress senderAddress
+            final SignalServicePniSignatureMessage message,
+            final SignalServiceAddress senderAddress
     ) {
         final var aci = senderAddress.getServiceId();
         final var aciIdentity = account.getIdentityKeyStore().getIdentityInfo(aci);
@@ -509,7 +488,7 @@ public final class IncomingMessageHandler {
                         sender,
                         destination == null
                                 ? null
-                                : new DeviceAddress(context.getRecipientHelper().resolveRecipient(destination),
+                                : new DeviceAddress(account.getRecipientResolver().resolveRecipient(destination),
                                         destination.getServiceId(),
                                         0),
                         ignoreAttachments));
@@ -537,6 +516,7 @@ public final class IncomingMessageHandler {
             if (rm.isConfigurationRequest()) {
                 actions.add(SendSyncConfigurationAction.create());
             }
+            actions.add(SyncStorageDataAction.create());
         }
         if (syncMessage.getGroups().isPresent()) {
             try {
@@ -549,12 +529,12 @@ public final class IncomingMessageHandler {
         }
         if (syncMessage.getBlockedList().isPresent()) {
             final var blockedListMessage = syncMessage.getBlockedList().get();
-            for (var address : blockedListMessage.getAddresses()) {
-                context.getContactHelper()
-                        .setContactBlocked(context.getRecipientHelper().resolveRecipient(address), true);
+            for (var individual : blockedListMessage.individuals) {
+                final var address = new RecipientAddress(individual.getAci(), individual.getE164());
+                final var recipientId = account.getRecipientResolver().resolveRecipient(address);
+                context.getContactHelper().setContactBlocked(recipientId, true);
             }
-            for (var groupId : blockedListMessage.getGroupIds()
-                    .stream()
+            for (var groupId : blockedListMessage.groupIds.stream()
                     .map(GroupId::unknownVersion)
                     .collect(Collectors.toSet())) {
                 try {
@@ -604,15 +584,28 @@ public final class IncomingMessageHandler {
         if (syncMessage.getFetchType().isPresent()) {
             switch (syncMessage.getFetchType().get()) {
                 case LOCAL_PROFILE -> actions.add(new RetrieveProfileAction(account.getSelfRecipientId()));
-                case STORAGE_MANIFEST -> actions.add(RetrieveStorageDataAction.create());
+                case STORAGE_MANIFEST -> actions.add(SyncStorageDataAction.create());
             }
         }
         if (syncMessage.getKeys().isPresent()) {
             final var keysMessage = syncMessage.getKeys().get();
-            if (keysMessage.getStorageService().isPresent()) {
-                final var storageKey = keysMessage.getStorageService().get();
+            if (keysMessage.getAccountEntropyPool() != null) {
+                final var aep = keysMessage.getAccountEntropyPool();
+                account.setAccountEntropyPool(aep);
+                actions.add(SyncStorageDataAction.create());
+            } else if (keysMessage.getMaster() != null) {
+                final var masterKey = keysMessage.getMaster();
+                account.setMasterKey(masterKey);
+                actions.add(SyncStorageDataAction.create());
+            } else if (keysMessage.getStorageService() != null) {
+                final var storageKey = keysMessage.getStorageService();
                 account.setStorageKey(storageKey);
-                actions.add(RetrieveStorageDataAction.create());
+                actions.add(SyncStorageDataAction.create());
+            }
+            if (keysMessage.getMediaRootBackupKey() != null) {
+                final var mrb = keysMessage.getMediaRootBackupKey();
+                account.setMediaRootBackupKey(mrb);
+                actions.add(SyncStorageDataAction.create());
             }
         }
         if (syncMessage.getConfiguration().isPresent()) {
@@ -635,26 +628,10 @@ public final class IncomingMessageHandler {
         if (syncMessage.getPniChangeNumber().isPresent()) {
             final var pniChangeNumber = syncMessage.getPniChangeNumber().get();
             logger.debug("Received PNI change number sync message, applying.");
-            if (pniChangeNumber.hasIdentityKeyPair()
-                    && pniChangeNumber.hasRegistrationId()
-                    && pniChangeNumber.hasSignedPreKey()
-                    && !envelope.getUpdatedPni().isEmpty()) {
-                logger.debug("New PNI: {}", envelope.getUpdatedPni());
-                try {
-                    final var updatedPni = PNI.parseOrThrow(envelope.getUpdatedPni());
-                    context.getAccountHelper()
-                            .setPni(updatedPni,
-                                    new IdentityKeyPair(pniChangeNumber.getIdentityKeyPair().toByteArray()),
-                                    pniChangeNumber.hasNewE164() ? pniChangeNumber.getNewE164() : null,
-                                    pniChangeNumber.getRegistrationId(),
-                                    new SignedPreKeyRecord(pniChangeNumber.getSignedPreKey().toByteArray()),
-                                    pniChangeNumber.hasLastResortKyberPreKey()
-                                            ? new KyberPreKeyRecord(pniChangeNumber.getLastResortKyberPreKey()
-                                            .toByteArray())
-                                            : null);
-                } catch (Exception e) {
-                    logger.warn("Failed to handle change number message", e);
-                }
+            final var updatedPniString = envelope.getUpdatedPni();
+            if (updatedPniString != null && !updatedPniString.isEmpty()) {
+                final var updatedPni = ServiceId.PNI.parseOrThrow(updatedPniString);
+                context.getAccountHelper().handlePniChangeNumberMessage(pniChangeNumber, updatedPni);
             }
         }
         return actions;
@@ -691,7 +668,7 @@ public final class IncomingMessageHandler {
         if (source == null) {
             return false;
         }
-        final var recipientId = context.getRecipientHelper().resolveRecipient(source);
+        final var recipientId = account.getRecipientResolver().resolveRecipient(source);
         if (context.getContactHelper().isContactBlocked(recipientId)) {
             return true;
         }
@@ -731,7 +708,7 @@ public final class IncomingMessageHandler {
 
         final var message = content.getDataMessage().orElse(null);
 
-        final var recipientId = context.getRecipientHelper().resolveRecipient(source);
+        final var recipientId = account.getRecipientResolver().resolveRecipient(source);
         if (!group.isMember(recipientId) && !(
                 group.isPendingMember(recipientId) && message != null && message.isGroupV2Update()
         )) {
@@ -782,10 +759,11 @@ public final class IncomingMessageHandler {
                             }
 
                             if (groupInfo.getMembers().isPresent()) {
+                                final var recipientResolver = account.getRecipientResolver();
                                 groupV1.addMembers(groupInfo.getMembers()
                                         .get()
                                         .stream()
-                                        .map(context.getRecipientHelper()::resolveRecipient)
+                                        .map(recipientResolver::resolveRecipient)
                                         .collect(Collectors.toSet()));
                             }
 
@@ -841,7 +819,9 @@ public final class IncomingMessageHandler {
                 }
             } else if (conversationPartnerAddress != null) {
                 context.getContactHelper()
-                        .setExpirationTimer(conversationPartnerAddress.recipientId(), message.getExpiresInSeconds());
+                        .setExpirationTimer(conversationPartnerAddress.recipientId(),
+                                message.getExpiresInSeconds(),
+                                message.getExpireTimerVersion());
             }
         }
         if (!ignoreAttachments) {
@@ -902,7 +882,9 @@ public final class IncomingMessageHandler {
     }
 
     private List<HandleAction> handleSignalServiceStoryMessage(
-            SignalServiceStoryMessage message, RecipientId source, boolean ignoreAttachments
+            SignalServiceStoryMessage message,
+            RecipientId source,
+            boolean ignoreAttachments
     ) {
         var actions = new ArrayList<HandleAction>();
         if (message.getGroupContext().isPresent()) {
@@ -958,8 +940,9 @@ public final class IncomingMessageHandler {
     }
 
     private SignalServiceAddress getSenderAddress(SignalServiceEnvelope envelope, SignalServiceContent content) {
-        if (!envelope.isUnidentifiedSender() && envelope.hasSourceServiceId()) {
-            return envelope.getSourceAddress();
+        final var serviceId = envelope.getSourceServiceId().map(ServiceId::parseOrNull).orElse(null);
+        if (!envelope.isUnidentifiedSender() && serviceId != null) {
+            return new SignalServiceAddress(serviceId);
         } else if (content != null) {
             return content.getSender();
         } else {
@@ -968,28 +951,25 @@ public final class IncomingMessageHandler {
     }
 
     private DeviceAddress getSender(SignalServiceEnvelope envelope, SignalServiceContent content) {
-        if (!envelope.isUnidentifiedSender() && envelope.hasSourceServiceId()) {
-            return new DeviceAddress(context.getRecipientHelper().resolveRecipient(envelope.getSourceAddress()),
-                    envelope.getSourceAddress().getServiceId(),
+        final var serviceId = envelope.getSourceServiceId().map(ServiceId::parseOrNull).orElse(null);
+        if (!envelope.isUnidentifiedSender() && serviceId != null) {
+            return new DeviceAddress(account.getRecipientResolver().resolveRecipient(serviceId),
+                    serviceId,
                     envelope.getSourceDevice());
         } else {
-            return new DeviceAddress(context.getRecipientHelper().resolveRecipient(content.getSender()),
+            return new DeviceAddress(account.getRecipientResolver().resolveRecipient(content.getSender()),
                     content.getSender().getServiceId(),
                     content.getSenderDevice());
         }
     }
 
     private DeviceAddress getDestination(SignalServiceEnvelope envelope) {
-        if (!envelope.hasDestinationUuid()) {
-            return new DeviceAddress(account.getSelfRecipientId(), account.getAci(), account.getDeviceId());
-        }
-        final var addressOptional = SignalServiceAddress.fromRaw(envelope.getDestinationServiceId(), null);
-        if (addressOptional.isEmpty()) {
+        final var destination = envelope.getDestinationServiceId();
+        if (destination == null || destination.isUnknown()) {
             return new DeviceAddress(account.getSelfRecipientId(), account.getAci(), account.getDeviceId());
         }
-        final var address = addressOptional.get();
-        return new DeviceAddress(context.getRecipientHelper().resolveRecipient(address),
-                address.getServiceId(),
+        return new DeviceAddress(account.getRecipientResolver().resolveRecipient(destination),
+                destination,
                 account.getDeviceId());
     }