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;
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;
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;
import org.signal.libsignal.metadata.ProtocolUntrustedIdentityException;
import org.signal.libsignal.metadata.SelfSendException;
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.zkgroup.InvalidInputException;
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.ServiceIdType;
import org.whispersystems.signalservice.api.push.SignalServiceAddress;
import org.whispersystems.signalservice.internal.push.Envelope;
import org.whispersystems.signalservice.internal.push.UnsupportedDataMessageException;
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);
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);
} 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());
}
private SignalServiceContent validate(
- 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());
}
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);
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()) {
}
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);
sender,
destination == null
? null
- : new DeviceAddress(context.getRecipientHelper().resolveRecipient(destination),
+ : new DeviceAddress(account.getRecipientResolver().resolveRecipient(destination),
destination.getServiceId(),
0),
ignoreAttachments));
if (rm.isConfigurationRequest()) {
actions.add(SendSyncConfigurationAction.create());
}
+ actions.add(SyncStorageDataAction.create());
}
if (syncMessage.getGroups().isPresent()) {
try {
}
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 {
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()) {
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;
}
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()
)) {
}
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()));
}
}
} else if (conversationPartnerAddress != null) {
context.getContactHelper()
- .setExpirationTimer(conversationPartnerAddress.recipientId(), message.getExpiresInSeconds());
+ .setExpirationTimer(conversationPartnerAddress.recipientId(),
+ message.getExpiresInSeconds(),
+ message.getExpireTimerVersion());
}
}
if (!ignoreAttachments) {
}
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()) {
}
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 {
}
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());
}