X-Git-Url: https://git.nmode.ca/signal-cli/blobdiff_plain/6cb867cbebec69a7652fec0b9e6cb2860e99bcbf..8e8eed7b061f1ed47cf9e30abb5e29ee08e3a3dc:/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 acd48c34..096f1c07 100644 --- a/lib/src/main/java/org/asamk/signal/manager/Manager.java +++ b/lib/src/main/java/org/asamk/signal/manager/Manager.java @@ -83,6 +83,7 @@ import org.whispersystems.signalservice.api.SignalServiceAccountManager; import org.whispersystems.signalservice.api.SignalServiceMessagePipe; import org.whispersystems.signalservice.api.SignalServiceMessageReceiver; import org.whispersystems.signalservice.api.SignalServiceMessageSender; +import org.whispersystems.signalservice.api.SignalSessionLock; import org.whispersystems.signalservice.api.crypto.SignalServiceCipher; import org.whispersystems.signalservice.api.crypto.UntrustedIdentityException; import org.whispersystems.signalservice.api.groupsv2.ClientZkOperations; @@ -161,6 +162,7 @@ import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; +import java.util.concurrent.locks.ReentrantLock; import java.util.function.Function; import java.util.stream.Collectors; @@ -193,6 +195,15 @@ public class Manager implements Closeable { private final PinHelper pinHelper; private final AvatarStore avatarStore; private final AttachmentStore attachmentStore; + private final SignalSessionLock sessionLock = new SignalSessionLock() { + private final ReentrantLock LEGACY_LOCK = new ReentrantLock(); + + @Override + public Lock acquire() { + LEGACY_LOCK.lock(); + return LEGACY_LOCK::unlock; + } + }; Manager( SignalAccount account, @@ -288,7 +299,7 @@ public class Manager implements Closeable { throw new NotRegisteredException(); } - var account = SignalAccount.load(pathConfig.getDataPath(), username); + var account = SignalAccount.load(pathConfig.getDataPath(), username, true); if (!account.isRegistered()) { throw new NotRegisteredException(); @@ -389,6 +400,7 @@ public class Manager implements Closeable { newProfile.getInternalServiceName(), newProfile.getAbout() == null ? "" : newProfile.getAbout(), newProfile.getAboutEmoji() == null ? "" : newProfile.getAboutEmoji(), + Optional.absent(), streamDetails); } @@ -534,6 +546,7 @@ public class Manager implements Closeable { account.getPassword(), account.getDeviceId(), account.getSignalProtocolStore(), + sessionLock, userAgent, account.isMultiDevice(), Optional.fromNullable(messagePipe), @@ -556,14 +569,6 @@ public class Manager implements Closeable { Profile getRecipientProfile( RecipientId recipientId, boolean force ) { - var profileKey = account.getProfileStore().getProfileKey(recipientId); - if (profileKey == null) { - if (force) { - // retrieve profile to get identity key - retrieveEncryptedProfile(recipientId); - } - return null; - } var profile = account.getProfileStore().getProfile(recipientId); var now = new Date().getTime(); @@ -590,7 +595,18 @@ public class Manager implements Closeable { return null; } - profile = decryptProfileAndDownloadAvatar(recipientId, profileKey, encryptedProfile); + var profileKey = account.getProfileStore().getProfileKey(recipientId); + if (profileKey == null) { + profile = new Profile(new Date().getTime(), + null, + null, + null, + null, + ProfileUtils.getUnidentifiedAccessMode(encryptedProfile, null), + ProfileUtils.getCapabilities(encryptedProfile)); + } else { + profile = decryptProfileAndDownloadAvatar(recipientId, profileKey, encryptedProfile); + } account.getProfileStore().storeProfile(recipientId, profile); return profile; @@ -769,10 +785,11 @@ public class Manager implements Closeable { public Pair> updateGroup( GroupId groupId, String name, List members, File avatarFile ) throws IOException, GroupNotFoundException, AttachmentInvalidException, InvalidNumberException, NotAGroupMemberException { - return sendUpdateGroupMessage(groupId, - name, - members == null ? null : getSignalServiceAddresses(members), - avatarFile); + final var membersRecipientIds = members == null ? null : getSignalServiceAddresses(members); + if (membersRecipientIds != null) { + membersRecipientIds.remove(account.getSelfRecipientId()); + } + return sendUpdateGroupMessage(groupId, name, membersRecipientIds, avatarFile); } private Pair> sendUpdateGroupMessage( @@ -1101,9 +1118,11 @@ public class Manager implements Closeable { } } - SendMessageResult renewSession(RecipientId recipientId) throws IOException { + void renewSession(RecipientId recipientId) throws IOException { account.getSessionStore().archiveSessions(recipientId); - return sendNullMessage(recipientId); + if (!recipientId.equals(getSelfRecipientId())) { + sendNullMessage(recipientId); + } } public String getContactName(String number) throws InvalidNumberException { @@ -1284,11 +1303,13 @@ public class Manager implements Closeable { } private byte[] getSenderCertificate() { - // TODO support UUID capable sender certificates - // byte[] certificate = accountManager.getSenderCertificateForPhoneNumberPrivacy(); byte[] certificate; try { - certificate = accountManager.getSenderCertificate(); + if (account.isPhoneNumberShared()) { + certificate = accountManager.getSenderCertificate(); + } else { + certificate = accountManager.getSenderCertificateForPhoneNumberPrivacy(); + } } catch (IOException e) { logger.warn("Failed to get sender certificate, ignoring: {}", e.getMessage()); return null; @@ -1503,18 +1524,12 @@ public class Manager implements Closeable { } } - private SignalServiceContent decryptMessage(SignalServiceEnvelope envelope) throws InvalidMetadataMessageException, ProtocolInvalidMessageException, ProtocolDuplicateMessageException, ProtocolLegacyMessageException, ProtocolInvalidKeyIdException, InvalidMetadataVersionException, ProtocolInvalidVersionException, ProtocolNoSessionException, ProtocolInvalidKeyException, SelfSendException, UnsupportedDataMessageException, org.whispersystems.libsignal.UntrustedIdentityException { + private SignalServiceContent decryptMessage(SignalServiceEnvelope envelope) throws InvalidMetadataMessageException, ProtocolInvalidMessageException, ProtocolDuplicateMessageException, ProtocolLegacyMessageException, ProtocolInvalidKeyIdException, InvalidMetadataVersionException, ProtocolInvalidVersionException, ProtocolNoSessionException, ProtocolInvalidKeyException, SelfSendException, UnsupportedDataMessageException, ProtocolUntrustedIdentityException { var cipher = new SignalServiceCipher(account.getSelfAddress(), account.getSignalProtocolStore(), + sessionLock, certificateValidator); - try { - return cipher.decrypt(envelope); - } catch (ProtocolUntrustedIdentityException e) { - if (e.getCause() instanceof org.whispersystems.libsignal.UntrustedIdentityException) { - throw (org.whispersystems.libsignal.UntrustedIdentityException) e.getCause(); - } - throw new AssertionError(e); - } + return cipher.decrypt(envelope); } private void handleEndSession(RecipientId recipientId) { @@ -1758,9 +1773,9 @@ public class Manager implements Closeable { if (!envelope.isReceipt()) { try { content = decryptMessage(envelope); - } catch (org.whispersystems.libsignal.UntrustedIdentityException e) { + } catch (ProtocolUntrustedIdentityException e) { if (!envelope.hasSource()) { - final var identifier = ((org.whispersystems.libsignal.UntrustedIdentityException) e).getName(); + final var identifier = e.getSender(); final var recipientId = resolveRecipient(identifier); try { account.getMessageCache().replaceSender(cachedMessage, recipientId); @@ -1837,6 +1852,7 @@ public class Manager implements Closeable { if (envelope.hasSource()) { // Store uuid if we don't have it already + // address/uuid in envelope is sent by server resolveRecipientTrusted(envelope.getSourceAddress()); } final var notAGroupMember = isNotAGroupMember(envelope, content); @@ -1846,6 +1862,11 @@ public class Manager implements Closeable { } catch (Exception e) { exception = e; } + if (!envelope.hasSource() && content != null) { + // Store uuid if we don't have it already + // address/uuid is validated by unidentified sender certificate + resolveRecipientTrusted(content.getSender()); + } var actions = handleMessage(envelope, content, ignoreAttachments); if (exception instanceof ProtocolInvalidMessageException) { final var sender = resolveRecipient(((ProtocolInvalidMessageException) exception).getSender()); @@ -1875,8 +1896,8 @@ public class Manager implements Closeable { handler.handleMessage(envelope, content, exception); } if (cachedMessage[0] != null) { - if (exception instanceof org.whispersystems.libsignal.UntrustedIdentityException) { - final var identifier = ((org.whispersystems.libsignal.UntrustedIdentityException) exception).getName(); + if (exception instanceof ProtocolUntrustedIdentityException) { + final var identifier = ((ProtocolUntrustedIdentityException) exception).getSender(); final var recipientId = resolveRecipient(identifier); queuedActions.add(new RetrieveProfileAction(recipientId)); if (!envelope.hasSource()) {