X-Git-Url: https://git.nmode.ca/signal-cli/blobdiff_plain/2ef59d692ae92615105c6aa2603677a3fa584200..a96bd91770880fc53e279f8a0a75e90cd32d078a:/lib/src/main/java/org/asamk/signal/manager/Manager.java diff --git a/lib/src/main/java/org/asamk/signal/manager/Manager.java b/lib/src/main/java/org/asamk/signal/manager/Manager.java index 60263dd9..4bced5e2 100644 --- a/lib/src/main/java/org/asamk/signal/manager/Manager.java +++ b/lib/src/main/java/org/asamk/signal/manager/Manager.java @@ -146,6 +146,7 @@ import java.nio.file.Files; import java.security.SignatureException; import java.util.ArrayList; import java.util.Arrays; +import java.util.Base64; import java.util.Collection; import java.util.Date; import java.util.HashSet; @@ -532,11 +533,13 @@ public class Manager implements Closeable { return getRecipientProfile(address, false); } - private SignalProfile getRecipientProfile( + SignalProfile getRecipientProfile( SignalServiceAddress address, boolean force ) { var profileEntry = account.getProfileStore().getProfileEntry(address); if (profileEntry == null) { + // retrieve profile to get identity key + retrieveEncryptedProfile(address); return null; } var now = new Date().getTime(); @@ -549,14 +552,13 @@ public class Manager implements Closeable { profileEntry.setRequestPending(true); final SignalServiceProfile encryptedProfile; try { - encryptedProfile = profileHelper.retrieveProfileSync(address, SignalServiceProfile.RequestType.PROFILE) - .getProfile(); - } catch (IOException e) { - logger.warn("Failed to retrieve profile, ignoring: {}", e.getMessage()); - return null; + encryptedProfile = retrieveEncryptedProfile(address); } finally { profileEntry.setRequestPending(false); } + if (encryptedProfile == null) { + return null; + } final var profileKey = profileEntry.getProfileKey(); final var profile = decryptProfileAndDownloadAvatar(address, profileKey, encryptedProfile); @@ -567,6 +569,25 @@ public class Manager implements Closeable { return profileEntry.getProfile(); } + private SignalServiceProfile retrieveEncryptedProfile(SignalServiceAddress address) { + try { + final var profile = profileHelper.retrieveProfileSync(address, SignalServiceProfile.RequestType.PROFILE) + .getProfile(); + try { + account.getIdentityKeyStore() + .saveIdentity(resolveRecipient(address), + new IdentityKey(Base64.getDecoder().decode(profile.getIdentityKey())), + new Date()); + } catch (InvalidKeyException ignored) { + logger.warn("Got invalid identity key in profile for {}", address.getLegacyIdentifier()); + } + return profile; + } catch (IOException e) { + logger.warn("Failed to retrieve profile, ignoring: {}", e.getMessage()); + return null; + } + } + private ProfileKeyCredential getRecipientProfileKeyCredential(SignalServiceAddress address) { var profileEntry = account.getProfileStore().getProfileEntry(address); if (profileEntry == null) { @@ -1292,6 +1313,16 @@ public class Manager implements Closeable { unidentifiedAccessHelper.getAccessFor(recipients), isRecipientUpdate, message); + + for (var r : result) { + if (r.getIdentityFailure() != null) { + account.getIdentityKeyStore(). + saveIdentity(resolveRecipient(r.getAddress()), + r.getIdentityFailure().getIdentityKey(), + new Date()); + } + } + return new Pair<>(timestamp, result); } catch (UntrustedIdentityException e) { return new Pair<>(timestamp, List.of()); @@ -1612,19 +1643,31 @@ public class Manager implements Closeable { } private void retryFailedReceivedMessages(ReceiveMessageHandler handler, boolean ignoreAttachments) { + Set queuedActions = new HashSet<>(); for (var cachedMessage : account.getMessageCache().getCachedMessages()) { - retryFailedReceivedMessage(handler, ignoreAttachments, cachedMessage); + var actions = retryFailedReceivedMessage(handler, ignoreAttachments, cachedMessage); + if (actions != null) { + queuedActions.addAll(actions); + } + } + for (var action : queuedActions) { + try { + action.execute(this); + } catch (Throwable e) { + logger.warn("Message action failed.", e); + } } } - private void retryFailedReceivedMessage( + private List retryFailedReceivedMessage( final ReceiveMessageHandler handler, final boolean ignoreAttachments, final CachedMessage cachedMessage ) { var envelope = cachedMessage.loadEnvelope(); if (envelope == null) { - return; + return null; } SignalServiceContent content = null; + List actions = null; if (!envelope.isReceipt()) { try { content = decryptMessage(envelope); @@ -1638,24 +1681,18 @@ public class Manager implements Closeable { logger.warn("Failed to move cached message to recipient folder: {}", ioException.getMessage()); } } - return; + return null; } catch (Exception er) { // All other errors are not recoverable, so delete the cached message cachedMessage.delete(); - return; - } - var actions = handleMessage(envelope, content, ignoreAttachments); - for (var action : actions) { - try { - action.execute(this); - } catch (Throwable e) { - logger.warn("Message action failed.", e); - } + return null; } + actions = handleMessage(envelope, content, ignoreAttachments); } account.save(); handler.handleMessage(envelope, content, null); cachedMessage.delete(); + return actions; } public void receiveMessages( @@ -1717,6 +1754,7 @@ public class Manager implements Closeable { // Store uuid if we don't have it already resolveRecipientTrusted(envelope.getSourceAddress()); } + final var notAGroupMember = isNotAGroupMember(envelope, content); if (!envelope.isReceipt()) { try { content = decryptMessage(envelope); @@ -1742,16 +1780,17 @@ public class Manager implements Closeable { account.save(); if (isMessageBlocked(envelope, content)) { logger.info("Ignoring a message from blocked user/group: {}", envelope.getTimestamp()); - } else if (isNotAGroupMember(envelope, content)) { + } else if (notAGroupMember) { logger.info("Ignoring a message from a non group member: {}", envelope.getTimestamp()); } else { handler.handleMessage(envelope, content, exception); } if (cachedMessage[0] != null) { if (exception instanceof org.whispersystems.libsignal.UntrustedIdentityException) { + final var recipientId = resolveRecipient(((org.whispersystems.libsignal.UntrustedIdentityException) exception) + .getName()); + queuedActions.add(new RetrieveProfileAction(resolveSignalServiceAddress(recipientId))); if (!envelope.hasSource()) { - final var recipientId = resolveRecipient(((org.whispersystems.libsignal.UntrustedIdentityException) exception) - .getName()); try { cachedMessage[0] = account.getMessageCache().replaceSender(cachedMessage[0], recipientId); } catch (IOException ioException) { @@ -1865,7 +1904,7 @@ public class Manager implements Closeable { destination, ignoreAttachments)); } - if (syncMessage.getRequest().isPresent()) { + if (syncMessage.getRequest().isPresent() && account.isMasterDevice()) { var rm = syncMessage.getRequest().get(); if (rm.isContactsRequest()) { actions.add(SendSyncContactsAction.create()); @@ -1957,9 +1996,6 @@ public class Manager implements Closeable { try (var attachmentAsStream = retrieveAttachmentAsStream(contactsMessage.getContactsStream() .asPointer(), tmpFile)) { var s = new DeviceContactsInputStream(attachmentAsStream); - if (contactsMessage.isComplete()) { - account.getContactStore().clear(); - } DeviceContact c; while ((c = s.read()) != null) { if (c.getAddress().matches(account.getSelfAddress()) && c.getProfileKey().isPresent()) {