X-Git-Url: https://git.nmode.ca/signal-cli/blobdiff_plain/a1014ba39c7ad8a90e4257df4bb919ef2114f9f1..0091c1cf266de225f84d507bb473ac22582d3b15:/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 d55362de..7f0c48dc 100644 --- a/lib/src/main/java/org/asamk/signal/manager/Manager.java +++ b/lib/src/main/java/org/asamk/signal/manager/Manager.java @@ -265,6 +265,10 @@ public class Manager implements Closeable { return account.getSelfAddress(); } + public RecipientId getSelfRecipientId() { + return account.getSelfRecipientId(); + } + private IdentityKeyPair getIdentityKeyPair() { return account.getIdentityKeyPair(); } @@ -312,11 +316,9 @@ public class Manager implements Closeable { public void checkAccountState() throws IOException { if (accountManager.getPreKeysCount() < ServiceConfig.PREKEY_MINIMUM_COUNT) { refreshPreKeys(); - account.save(); } if (account.getUuid() == null) { account.setUuid(accountManager.getOwnUuid()); - account.save(); } updateAccountAttributes(); } @@ -404,16 +406,19 @@ public class Manager implements Closeable { // If this is the master device, other users can't send messages to this number anymore. // If this is a linked device, other users can still send messages, but this device doesn't receive them anymore. accountManager.setGcmId(Optional.absent()); + + account.setRegistered(false); + } + + public void deleteAccount() throws IOException { accountManager.deleteAccount(); account.setRegistered(false); - account.save(); } public List getLinkedDevices() throws IOException { var devices = accountManager.getDevices(); account.setMultiDevice(devices.size() > 1); - account.save(); return devices; } @@ -421,7 +426,6 @@ public class Manager implements Closeable { accountManager.removeDevice(deviceId); var devices = accountManager.getDevices(); account.setMultiDevice(devices.size() > 1); - account.save(); } public void addDeviceLink(URI linkUri) throws IOException, InvalidKeyException { @@ -440,7 +444,6 @@ public class Manager implements Closeable { Optional.of(account.getProfileKey().serialize()), verificationCode); account.setMultiDevice(true); - account.save(); } public void setRegistrationLockPin(Optional pin) throws IOException, UnauthenticatedResponseException { @@ -454,8 +457,7 @@ public class Manager implements Closeable { pinHelper.setRegistrationLockPin(pin.get(), masterKey); - account.setRegistrationLockPin(pin.get()); - account.setPinMasterKey(masterKey); + account.setRegistrationLockPin(pin.get(), masterKey); } else { // Remove legacy registration lock accountManager.removeRegistrationLockV1(); @@ -463,10 +465,8 @@ public class Manager implements Closeable { // Remove KBS Pin pinHelper.removeRegistrationLockPin(); - account.setRegistrationLockPin(null); - account.setPinMasterKey(null); + account.setRegistrationLockPin(null, null); } - account.save(); } void refreshPreKeys() throws IOException { @@ -673,7 +673,7 @@ public class Manager implements Closeable { if (g == null) { throw new GroupNotFoundException(groupId); } - if (!g.isMember(account.getSelfAddress())) { + if (!g.isMember(account.getSelfRecipientId())) { throw new NotAGroupMemberException(groupId, g.getTitle()); } return g; @@ -684,7 +684,7 @@ public class Manager implements Closeable { if (g == null) { throw new GroupNotFoundException(groupId); } - if (!g.isMember(account.getSelfAddress()) && !g.isPendingMember(account.getSelfAddress())) { + if (!g.isMember(account.getSelfRecipientId()) && !g.isPendingMember(account.getSelfRecipientId())) { throw new NotAGroupMemberException(groupId, g.getTitle()); } return g; @@ -725,7 +725,7 @@ public class Manager implements Closeable { GroupUtils.setGroupContext(messageBuilder, g); messageBuilder.withExpiration(g.getMessageExpirationTime()); - return sendMessage(messageBuilder, g.getMembersWithout(account.getSelfAddress())); + return sendMessage(messageBuilder, g.getMembersWithout(account.getSelfRecipientId())); } public Pair> sendQuitGroupMessage(GroupId groupId) throws GroupNotFoundException, IOException, NotAGroupMemberException { @@ -736,17 +736,17 @@ public class Manager implements Closeable { var groupInfoV1 = (GroupInfoV1) g; var group = SignalServiceGroup.newBuilder(SignalServiceGroup.Type.QUIT).withId(groupId.serialize()).build(); messageBuilder = SignalServiceDataMessage.newBuilder().asGroupMessage(group); - groupInfoV1.removeMember(account.getSelfAddress()); + groupInfoV1.removeMember(account.getSelfRecipientId()); account.getGroupStore().updateGroup(groupInfoV1); } else { final var groupInfoV2 = (GroupInfoV2) g; final var groupGroupChangePair = groupHelper.leaveGroup(groupInfoV2); - groupInfoV2.setGroup(groupGroupChangePair.first()); + groupInfoV2.setGroup(groupGroupChangePair.first(), this::resolveRecipient); messageBuilder = getGroupUpdateMessageBuilder(groupInfoV2, groupGroupChangePair.second().toByteArray()); account.getGroupStore().updateGroup(groupInfoV2); } - return sendMessage(messageBuilder, g.getMembersWithout(account.getSelfAddress())); + return sendMessage(messageBuilder, g.getMembersWithout(account.getSelfRecipientId())); } public Pair> updateGroup( @@ -754,11 +754,7 @@ public class Manager implements Closeable { ) throws IOException, GroupNotFoundException, AttachmentInvalidException, InvalidNumberException, NotAGroupMemberException { return sendUpdateGroupMessage(groupId, name, - members == null - ? null - : getSignalServiceAddresses(members).stream() - .map(this::resolveRecipient) - .collect(Collectors.toSet()), + members == null ? null : getSignalServiceAddresses(members), avatarFile); } @@ -769,16 +765,20 @@ public class Manager implements Closeable { SignalServiceDataMessage.Builder messageBuilder; if (groupId == null) { // Create new group - var gv2 = groupHelper.createGroupV2(name == null ? "" : name, + var gv2Pair = groupHelper.createGroupV2(name == null ? "" : name, members == null ? Set.of() : members, avatarFile); - if (gv2 == null) { + if (gv2Pair == null) { var gv1 = new GroupInfoV1(GroupIdV1.createRandom()); - gv1.addMembers(List.of(account.getSelfAddress())); + gv1.addMembers(List.of(account.getSelfRecipientId())); updateGroupV1(gv1, name, members, avatarFile); messageBuilder = getGroupUpdateMessageBuilder(gv1); g = gv1; } else { + final var gv2 = gv2Pair.first(); + final var decryptedGroup = gv2Pair.second(); + + gv2.setGroup(decryptedGroup, this::resolveRecipient); if (avatarFile != null) { avatarStore.storeGroupAvatar(gv2.getGroupId(), outputStream -> IOUtils.copyFileToStream(avatarFile, outputStream)); @@ -792,7 +792,7 @@ public class Manager implements Closeable { final var groupInfoV2 = (GroupInfoV2) group; Pair> result = null; - if (groupInfoV2.isPendingMember(getSelfAddress())) { + if (groupInfoV2.isPendingMember(account.getSelfRecipientId())) { var groupGroupChangePair = groupHelper.acceptInvite(groupInfoV2); result = sendUpdateGroupMessage(groupInfoV2, groupGroupChangePair.first(), @@ -801,10 +801,7 @@ public class Manager implements Closeable { if (members != null) { final var newMembers = new HashSet<>(members); - newMembers.removeAll(group.getMembers() - .stream() - .map(this::resolveRecipient) - .collect(Collectors.toSet())); + newMembers.removeAll(group.getMembers()); if (newMembers.size() > 0) { var groupGroupChangePair = groupHelper.updateGroupV2(groupInfoV2, newMembers); result = sendUpdateGroupMessage(groupInfoV2, @@ -834,7 +831,8 @@ public class Manager implements Closeable { account.getGroupStore().updateGroup(g); - final var result = sendMessage(messageBuilder, g.getMembersIncludingPendingWithout(account.getSelfAddress())); + final var result = sendMessage(messageBuilder, + g.getMembersIncludingPendingWithout(account.getSelfRecipientId())); return new Pair<>(g.getGroupId(), result.second()); } @@ -846,12 +844,13 @@ public class Manager implements Closeable { } if (members != null) { - final var memberAddresses = members.stream() + final var newMemberAddresses = members.stream() + .filter(member -> !g.isMember(member)) .map(this::resolveSignalServiceAddress) .collect(Collectors.toList()); final var newE164Members = new HashSet(); - for (var member : memberAddresses) { - if (g.isMember(member) || !member.getNumber().isPresent()) { + for (var member : newMemberAddresses) { + if (!member.getNumber().isPresent()) { continue; } newE164Members.add(member.getNumber().get()); @@ -866,7 +865,7 @@ public class Manager implements Closeable { + " to group: Not registered on Signal"); } - g.addMembers(memberAddresses); + g.addMembers(members); } if (avatarFile != null) { @@ -928,10 +927,10 @@ public class Manager implements Closeable { private Pair> sendUpdateGroupMessage( GroupInfoV2 group, DecryptedGroup newDecryptedGroup, GroupChange groupChange ) throws IOException { - group.setGroup(newDecryptedGroup); + group.setGroup(newDecryptedGroup, this::resolveRecipient); final var messageBuilder = getGroupUpdateMessageBuilder(group, groupChange.toByteArray()); account.getGroupStore().updateGroup(group); - return sendMessage(messageBuilder, group.getMembersIncludingPendingWithout(account.getSelfAddress())); + return sendMessage(messageBuilder, group.getMembersIncludingPendingWithout(account.getSelfRecipientId())); } Pair> sendGroupInfoMessage( @@ -944,21 +943,24 @@ public class Manager implements Closeable { } g = (GroupInfoV1) group; - if (!g.isMember(recipient)) { + if (!g.isMember(resolveRecipient(recipient))) { throw new NotAGroupMemberException(groupId, g.name); } var messageBuilder = getGroupUpdateMessageBuilder(g); // Send group message only to the recipient who requested it - return sendMessage(messageBuilder, List.of(recipient)); + return sendMessage(messageBuilder, Set.of(resolveRecipient(recipient))); } private SignalServiceDataMessage.Builder getGroupUpdateMessageBuilder(GroupInfoV1 g) throws AttachmentInvalidException { var group = SignalServiceGroup.newBuilder(SignalServiceGroup.Type.UPDATE) .withId(g.getGroupId().serialize()) .withName(g.name) - .withMembers(new ArrayList<>(g.getMembers())); + .withMembers(g.getMembers() + .stream() + .map(this::resolveSignalServiceAddress) + .collect(Collectors.toList())); try { final var attachment = createGroupAvatarAttachment(g.getGroupId()); @@ -991,7 +993,7 @@ public class Manager implements Closeable { var messageBuilder = SignalServiceDataMessage.newBuilder().asGroupMessage(group.build()); // Send group info request message to the recipient who sent us a message with this groupId - return sendMessage(messageBuilder, List.of(recipient)); + return sendMessage(messageBuilder, Set.of(resolveRecipient(recipient))); } void sendReceipt( @@ -1076,7 +1078,6 @@ public class Manager implements Closeable { for (var address : signalServiceAddresses) { handleEndSession(address); } - account.save(); throw e; } } @@ -1091,7 +1092,6 @@ public class Manager implements Closeable { var contact = account.getContactStore().getContact(recipientId); final var builder = contact == null ? Contact.newBuilder() : Contact.newBuilder(contact); account.getContactStore().storeContact(recipientId, builder.withName(name).build()); - account.save(); } public void setContactBlocked(String number, boolean blocked) throws InvalidNumberException { @@ -1102,7 +1102,6 @@ public class Manager implements Closeable { var contact = account.getContactStore().getContact(recipientId); final var builder = contact == null ? Contact.newBuilder() : Contact.newBuilder(contact); account.getContactStore().storeContact(recipientId, builder.withBlocked(blocked).build()); - account.save(); } public void setGroupBlocked(final GroupId groupId, final boolean blocked) throws GroupNotFoundException { @@ -1113,7 +1112,6 @@ public class Manager implements Closeable { group.setBlocked(blocked); account.getGroupStore().updateGroup(group); - account.save(); } private void setExpirationTimer(RecipientId recipientId, int messageExpirationTimer) { @@ -1126,9 +1124,9 @@ public class Manager implements Closeable { .storeContact(recipientId, builder.withMessageExpirationTime(messageExpirationTimer).build()); } - private void sendExpirationTimerUpdate(SignalServiceAddress address) throws IOException { + private void sendExpirationTimerUpdate(RecipientId recipientId) throws IOException { final var messageBuilder = SignalServiceDataMessage.newBuilder().asExpirationUpdate(); - sendMessage(messageBuilder, List.of(address)); + sendMessage(messageBuilder, Set.of(recipientId)); } /** @@ -1139,8 +1137,7 @@ public class Manager implements Closeable { ) throws IOException, InvalidNumberException { var recipientId = canonicalizeAndResolveRecipient(number); setExpirationTimer(recipientId, messageExpirationTimer); - sendExpirationTimerUpdate(resolveSignalServiceAddress(recipientId)); - account.save(); + sendExpirationTimerUpdate(recipientId); } /** @@ -1173,7 +1170,6 @@ public class Manager implements Closeable { var sticker = new Sticker(StickerPackId.deserialize(Hex.fromStringCondensed(packId)), packKey); account.getStickerStore().updateSticker(sticker); - account.save(); try { return new URI("https", @@ -1266,7 +1262,7 @@ public class Manager implements Closeable { messageSender.sendMessage(message, unidentifiedAccessHelper.getAccessForSync()); } - private Collection getSignalServiceAddresses(Collection numbers) throws InvalidNumberException { + private Set getSignalServiceAddresses(Collection numbers) throws InvalidNumberException { final var signalServiceAddresses = new HashSet(numbers.size()); final var addressesMissingUuid = new HashSet(); @@ -1302,7 +1298,7 @@ public class Manager implements Closeable { } } - return signalServiceAddresses; + return signalServiceAddresses.stream().map(this::resolveRecipient).collect(Collectors.toSet()); } private Map getRegisteredUsers(final Set numbersMissingUuid) throws IOException { @@ -1316,10 +1312,8 @@ public class Manager implements Closeable { } private Pair> sendMessage( - SignalServiceDataMessage.Builder messageBuilder, Collection recipients + SignalServiceDataMessage.Builder messageBuilder, Set recipientIds ) throws IOException { - recipients = recipients.stream().map(this::resolveSignalServiceAddress).collect(Collectors.toSet()); - final var recipientIds = recipients.stream().map(this::resolveRecipient).collect(Collectors.toSet()); final var timestamp = System.currentTimeMillis(); messageBuilder.withTimestamp(timestamp); getOrCreateMessagePipe(); @@ -1331,8 +1325,12 @@ public class Manager implements Closeable { try { var messageSender = createMessageSender(); final var isRecipientUpdate = false; - var result = messageSender.sendMessage(new ArrayList<>(recipients), - unidentifiedAccessHelper.getAccessFor(recipientIds), + final var recipientIdList = new ArrayList<>(recipientIds); + final var addresses = recipientIdList.stream() + .map(this::resolveSignalServiceAddress) + .collect(Collectors.toList()); + var result = messageSender.sendMessage(addresses, + unidentifiedAccessHelper.getAccessFor(recipientIdList), isRecipientUpdate, message); @@ -1352,23 +1350,22 @@ public class Manager implements Closeable { } else { // Send to all individually, so sync messages are sent correctly messageBuilder.withProfileKey(account.getProfileKey().serialize()); - var results = new ArrayList(recipients.size()); - for (var address : recipients) { - final var contact = account.getContactStore().getContact(resolveRecipient(address)); + var results = new ArrayList(recipientIds.size()); + for (var recipientId : recipientIds) { + final var contact = account.getContactStore().getContact(recipientId); final var expirationTime = contact != null ? contact.getMessageExpirationTime() : 0; messageBuilder.withExpiration(expirationTime); message = messageBuilder.build(); - results.add(sendMessage(address, message)); + results.add(sendMessage(resolveSignalServiceAddress(recipientId), message)); } return new Pair<>(timestamp, results); } } finally { if (message != null && message.isEndSession()) { - for (var recipient : recipients) { + for (var recipient : recipientIds) { handleEndSession(recipient); } } - account.save(); } } @@ -1379,19 +1376,15 @@ public class Manager implements Closeable { messageBuilder.withTimestamp(timestamp); getOrCreateMessagePipe(); getOrCreateUnidentifiedMessagePipe(); - try { - final var recipientId = account.getSelfRecipientId(); + final var recipientId = account.getSelfRecipientId(); - final var contact = account.getContactStore().getContact(recipientId); - final var expirationTime = contact != null ? contact.getMessageExpirationTime() : 0; - messageBuilder.withExpiration(expirationTime); + final var contact = account.getContactStore().getContact(recipientId); + final var expirationTime = contact != null ? contact.getMessageExpirationTime() : 0; + messageBuilder.withExpiration(expirationTime); - var message = messageBuilder.build(); - final var result = sendSelfMessage(message); - return new Pair<>(timestamp, result); - } finally { - account.save(); - } + var message = messageBuilder.build(); + final var result = sendSelfMessage(message); + return new Pair<>(timestamp, result); } private SendMessageResult sendSelfMessage(SignalServiceDataMessage message) throws IOException { @@ -1448,8 +1441,8 @@ public class Manager implements Closeable { } } - private void handleEndSession(SignalServiceAddress source) { - account.getSessionStore().deleteAllSessions(source.getIdentifier()); + private void handleEndSession(RecipientId recipientId) { + account.getSessionStore().deleteAllSessions(recipientId); } private List handleSignalServiceDataMessage( @@ -1486,7 +1479,7 @@ public class Manager implements Closeable { groupV1.addMembers(groupInfo.getMembers() .get() .stream() - .map(this::resolveSignalServiceAddress) + .map(this::resolveRecipient) .collect(Collectors.toSet())); } @@ -1500,7 +1493,7 @@ public class Manager implements Closeable { break; case QUIT: { if (groupV1 != null) { - groupV1.removeMember(source); + groupV1.removeMember(resolveRecipient(source)); account.getGroupStore().updateGroup(groupV1); } break; @@ -1527,7 +1520,7 @@ public class Manager implements Closeable { final var conversationPartnerAddress = isSync ? destination : source; if (conversationPartnerAddress != null && message.isEndSession()) { - handleEndSession(conversationPartnerAddress); + handleEndSession(resolveRecipient(conversationPartnerAddress)); } if (message.isExpirationUpdate() || message.getBody().isPresent()) { if (message.getGroupContext().isPresent()) { @@ -1613,7 +1606,7 @@ public class Manager implements Closeable { final GroupInfoV2 groupInfoV2; if (groupInfo instanceof GroupInfoV1) { // Received a v2 group message for a v1 group, we need to locally migrate the group - account.getGroupStore().deleteGroup(groupInfo.getGroupId()); + account.getGroupStore().deleteGroupV1(((GroupInfoV1) groupInfo).getGroupId()); groupInfoV2 = new GroupInfoV2(groupId, groupMasterKey); logger.info("Locally migrated group {} to group v2, id: {}", groupInfo.getGroupId().toBase64(), @@ -1641,7 +1634,7 @@ public class Manager implements Closeable { downloadGroupAvatar(groupId, groupSecretParams, avatar); } } - groupInfoV2.setGroup(group); + groupInfoV2.setGroup(group, this::resolveRecipient); account.getGroupStore().updateGroup(groupInfoV2); } @@ -1707,7 +1700,6 @@ public class Manager implements Closeable { } actions = handleMessage(envelope, content, ignoreAttachments); } - account.save(); handler.handleMessage(envelope, content, null); cachedMessage.delete(); return actions; @@ -1755,7 +1747,6 @@ public class Manager implements Closeable { logger.warn("Message action failed.", e); } } - account.save(); queuedActions.clear(); queuedActions = null; } @@ -1795,7 +1786,6 @@ public class Manager implements Closeable { queuedActions.addAll(actions); } } - account.save(); if (isMessageBlocked(envelope, content)) { logger.info("Ignoring a message from blocked user/group: {}", envelope.getTimestamp()); } else if (notAGroupMember) { @@ -1885,7 +1875,7 @@ public class Manager implements Closeable { } var groupId = GroupUtils.getGroupId(message.getGroupContext().get()); var group = getGroup(groupId); - if (group != null && !group.isMember(source)) { + if (group != null && !group.isMember(resolveRecipient(source))) { return true; } } @@ -1959,13 +1949,13 @@ public class Manager implements Closeable { } syncGroup.addMembers(g.getMembers() .stream() - .map(this::resolveSignalServiceAddress) + .map(this::resolveRecipient) .collect(Collectors.toSet())); if (!g.isActive()) { - syncGroup.removeMember(account.getSelfAddress()); + syncGroup.removeMember(account.getSelfRecipientId()); } else { // Add ourself to the member set as it's marked as active - syncGroup.addMembers(List.of(account.getSelfAddress())); + syncGroup.addMembers(List.of(account.getSelfRecipientId())); } syncGroup.blocked = g.isBlocked(); if (g.getColor().isPresent()) { @@ -1975,7 +1965,6 @@ public class Manager implements Closeable { if (g.getAvatar().isPresent()) { downloadGroupAvatar(g.getAvatar().get(), syncGroup.getGroupId()); } - syncGroup.inboxPosition = g.getInboxPosition().orNull(); syncGroup.archived = g.isArchived(); account.getGroupStore().updateGroup(syncGroup); } @@ -2282,13 +2271,16 @@ public class Manager implements Closeable { var groupInfo = (GroupInfoV1) record; out.write(new DeviceGroup(groupInfo.getGroupId().serialize(), Optional.fromNullable(groupInfo.name), - new ArrayList<>(groupInfo.getMembers()), + groupInfo.getMembers() + .stream() + .map(this::resolveSignalServiceAddress) + .collect(Collectors.toList()), createGroupAvatarAttachment(groupInfo.getGroupId()), - groupInfo.isMember(account.getSelfAddress()), + groupInfo.isMember(account.getSelfRecipientId()), Optional.of(groupInfo.messageExpirationTime), Optional.fromNullable(groupInfo.color), groupInfo.blocked, - Optional.fromNullable(groupInfo.inboxPosition), + Optional.absent(), groupInfo.archived)); } } @@ -2434,7 +2426,7 @@ public class Manager implements Closeable { final var group = account.getGroupStore().getGroup(groupId); if (group instanceof GroupInfoV2 && ((GroupInfoV2) group).getGroup() == null) { final var groupSecretParams = GroupSecretParams.deriveFromMasterKey(((GroupInfoV2) group).getMasterKey()); - ((GroupInfoV2) group).setGroup(groupHelper.getDecryptedGroup(groupSecretParams)); + ((GroupInfoV2) group).setGroup(groupHelper.getDecryptedGroup(groupSecretParams), this::resolveRecipient); account.getGroupStore().updateGroup(group); } return group;