X-Git-Url: https://git.nmode.ca/signal-cli/blobdiff_plain/b91c162159c7c28d049ceb8889c419791573d3bb..997b3c6a2a1f2e9a50fe579ac726677ea0d57d0c:/lib/src/main/java/org/asamk/signal/manager/ManagerImpl.java diff --git a/lib/src/main/java/org/asamk/signal/manager/ManagerImpl.java b/lib/src/main/java/org/asamk/signal/manager/ManagerImpl.java index d0fab350..a14f2d1f 100644 --- a/lib/src/main/java/org/asamk/signal/manager/ManagerImpl.java +++ b/lib/src/main/java/org/asamk/signal/manager/ManagerImpl.java @@ -18,18 +18,19 @@ package org.asamk.signal.manager; import org.asamk.signal.manager.actions.HandleAction; import org.asamk.signal.manager.api.Device; +import org.asamk.signal.manager.api.Group; +import org.asamk.signal.manager.api.Identity; import org.asamk.signal.manager.api.Message; import org.asamk.signal.manager.api.RecipientIdentifier; import org.asamk.signal.manager.api.SendGroupMessageResults; import org.asamk.signal.manager.api.SendMessageResults; import org.asamk.signal.manager.api.TypingAction; +import org.asamk.signal.manager.api.UpdateGroup; import org.asamk.signal.manager.config.ServiceConfig; import org.asamk.signal.manager.config.ServiceEnvironmentConfig; import org.asamk.signal.manager.groups.GroupId; import org.asamk.signal.manager.groups.GroupInviteLinkUrl; -import org.asamk.signal.manager.groups.GroupLinkState; import org.asamk.signal.manager.groups.GroupNotFoundException; -import org.asamk.signal.manager.groups.GroupPermission; import org.asamk.signal.manager.groups.GroupSendingNotAllowedException; import org.asamk.signal.manager.groups.LastGroupAdminException; import org.asamk.signal.manager.groups.NotAGroupMemberException; @@ -52,6 +53,7 @@ import org.asamk.signal.manager.storage.identities.IdentityInfo; import org.asamk.signal.manager.storage.messageCache.CachedMessage; import org.asamk.signal.manager.storage.recipients.Contact; import org.asamk.signal.manager.storage.recipients.Profile; +import org.asamk.signal.manager.storage.recipients.RecipientAddress; import org.asamk.signal.manager.storage.recipients.RecipientId; import org.asamk.signal.manager.storage.stickers.Sticker; import org.asamk.signal.manager.storage.stickers.StickerPackId; @@ -174,14 +176,13 @@ public class ManagerImpl implements Manager { this.attachmentHelper = new AttachmentHelper(dependencies, attachmentStore); this.pinHelper = new PinHelper(dependencies.getKeyBackupService()); - final var unidentifiedAccessHelper = new UnidentifiedAccessHelper(account::getProfileKey, - account.getProfileStore()::getProfileKey, - this::getRecipientProfile, - this::getSenderCertificate); + final var unidentifiedAccessHelper = new UnidentifiedAccessHelper(account, + dependencies, + account::getProfileKey, + this::getRecipientProfile); this.profileHelper = new ProfileHelper(account, dependencies, avatarStore, - account.getProfileStore()::getProfileKey, unidentifiedAccessHelper::getAccessFor, this::resolveSignalServiceAddress); final GroupV2Helper groupV2Helper = new GroupV2Helper(profileHelper::getRecipientProfileKeyCredential, @@ -196,7 +197,7 @@ public class ManagerImpl implements Manager { this::resolveSignalServiceAddress, account.getRecipientStore(), this::handleIdentityFailure, - this::getGroup, + this::getGroupInfo, this::refreshRegisteredUser); this.groupHelper = new GroupHelper(account, dependencies, @@ -206,7 +207,7 @@ public class ManagerImpl implements Manager { avatarStore, this::resolveSignalServiceAddress, account.getRecipientStore()); - this.storageHelper = new StorageHelper(account, dependencies, groupHelper); + this.storageHelper = new StorageHelper(account, dependencies, groupHelper, profileHelper); this.contactHelper = new ContactHelper(account); this.syncHelper = new SyncHelper(account, attachmentHelper, @@ -240,20 +241,10 @@ public class ManagerImpl implements Manager { } @Override - public String getUsername() { + public String getSelfNumber() { return account.getUsername(); } - @Override - public RecipientId getSelfRecipientId() { - return account.getSelfRecipientId(); - } - - @Override - public int getDeviceId() { - return account.getDeviceId(); - } - @Override public void checkAccountState() throws IOException { if (account.getLastReceiveTimestamp() == 0) { @@ -327,6 +318,33 @@ public class ManagerImpl implements Manager { account.isDiscoverableByPhoneNumber()); } + @Override + public void updateConfiguration( + final Boolean readReceipts, + final Boolean unidentifiedDeliveryIndicators, + final Boolean typingIndicators, + final Boolean linkPreviews + ) throws IOException, NotMasterDeviceException { + if (!account.isMasterDevice()) { + throw new NotMasterDeviceException(); + } + + final var configurationStore = account.getConfigurationStore(); + if (readReceipts != null) { + configurationStore.setReadReceipts(readReceipts); + } + if (unidentifiedDeliveryIndicators != null) { + configurationStore.setUnidentifiedDeliveryIndicators(unidentifiedDeliveryIndicators); + } + if (typingIndicators != null) { + configurationStore.setTypingIndicators(typingIndicators); + } + if (linkPreviews != null) { + configurationStore.setLinkPreviews(linkPreviews); + } + syncHelper.sendConfigurationMessage(); + } + /** * @param givenName if null, the previous givenName will be kept * @param familyName if null, the previous familyName will be kept @@ -385,12 +403,16 @@ public class ManagerImpl implements Manager { logger.debug("Failed to decrypt device name, maybe plain text?", e); } } - return new Device(d.getId(), deviceName, d.getCreated(), d.getLastSeen()); + return new Device(d.getId(), + deviceName, + d.getCreated(), + d.getLastSeen(), + d.getId() == account.getDeviceId()); }).collect(Collectors.toList()); } @Override - public void removeLinkedDevices(int deviceId) throws IOException { + public void removeLinkedDevices(long deviceId) throws IOException { dependencies.getAccountManager().removeDevice(deviceId); var devices = dependencies.getAccountManager().getDevices(); account.setMultiDevice(devices.size() > 1); @@ -442,13 +464,51 @@ public class ManagerImpl implements Manager { } @Override - public Profile getRecipientProfile(RecipientId recipientId) { + public Profile getRecipientProfile(RecipientIdentifier.Single recipient) throws UnregisteredUserException { + return profileHelper.getRecipientProfile(resolveRecipient(recipient)); + } + + private Profile getRecipientProfile(RecipientId recipientId) { return profileHelper.getRecipientProfile(recipientId); } @Override - public List getGroups() { - return account.getGroupStore().getGroups(); + public List getGroups() { + return account.getGroupStore().getGroups().stream().map(this::toGroup).collect(Collectors.toList()); + } + + private Group toGroup(final GroupInfo groupInfo) { + if (groupInfo == null) { + return null; + } + + return new Group(groupInfo.getGroupId(), + groupInfo.getTitle(), + groupInfo.getDescription(), + groupInfo.getGroupInviteLink(), + groupInfo.getMembers() + .stream() + .map(account.getRecipientStore()::resolveRecipientAddress) + .collect(Collectors.toSet()), + groupInfo.getPendingMembers() + .stream() + .map(account.getRecipientStore()::resolveRecipientAddress) + .collect(Collectors.toSet()), + groupInfo.getRequestingMembers() + .stream() + .map(account.getRecipientStore()::resolveRecipientAddress) + .collect(Collectors.toSet()), + groupInfo.getAdminMembers() + .stream() + .map(account.getRecipientStore()::resolveRecipientAddress) + .collect(Collectors.toSet()), + groupInfo.isBlocked(), + groupInfo.getMessageExpirationTimer(), + groupInfo.getPermissionAddMember(), + groupInfo.getPermissionEditDetails(), + groupInfo.getPermissionSendMessage(), + groupInfo.isMember(account.getSelfRecipientId()), + groupInfo.isAdmin(account.getSelfRecipientId())); } @Override @@ -473,35 +533,22 @@ public class ManagerImpl implements Manager { @Override public SendGroupMessageResults updateGroup( - GroupId groupId, - String name, - String description, - Set members, - Set removeMembers, - Set admins, - Set removeAdmins, - boolean resetGroupLink, - GroupLinkState groupLinkState, - GroupPermission addMemberPermission, - GroupPermission editDetailsPermission, - File avatarFile, - Integer expirationTimer, - Boolean isAnnouncementGroup + final GroupId groupId, final UpdateGroup updateGroup ) throws IOException, GroupNotFoundException, AttachmentInvalidException, NotAGroupMemberException, GroupSendingNotAllowedException { return groupHelper.updateGroup(groupId, - name, - description, - members == null ? null : resolveRecipients(members), - removeMembers == null ? null : resolveRecipients(removeMembers), - admins == null ? null : resolveRecipients(admins), - removeAdmins == null ? null : resolveRecipients(removeAdmins), - resetGroupLink, - groupLinkState, - addMemberPermission, - editDetailsPermission, - avatarFile, - expirationTimer, - isAnnouncementGroup); + updateGroup.getName(), + updateGroup.getDescription(), + updateGroup.getMembers() == null ? null : resolveRecipients(updateGroup.getMembers()), + updateGroup.getRemoveMembers() == null ? null : resolveRecipients(updateGroup.getRemoveMembers()), + updateGroup.getAdmins() == null ? null : resolveRecipients(updateGroup.getAdmins()), + updateGroup.getRemoveAdmins() == null ? null : resolveRecipients(updateGroup.getRemoveAdmins()), + updateGroup.isResetGroupLink(), + updateGroup.getGroupLinkState(), + updateGroup.getAddMemberPermission(), + updateGroup.getEditDetailsPermission(), + updateGroup.getAvatarFile(), + updateGroup.getExpirationTimer(), + updateGroup.getIsAnnouncementGroup()); } @Override @@ -667,7 +714,10 @@ public class ManagerImpl implements Manager { @Override public void setGroupBlocked( final GroupId groupId, final boolean blocked - ) throws GroupNotFoundException, IOException { + ) throws GroupNotFoundException, IOException, NotMasterDeviceException { + if (!account.isMasterDevice()) { + throw new NotMasterDeviceException(); + } groupHelper.setGroupBlocked(groupId, blocked); // TODO cycle our profile key syncHelper.sendBlockedList(); @@ -734,22 +784,6 @@ public class ManagerImpl implements Manager { } } - private byte[] getSenderCertificate() { - byte[] certificate; - try { - if (account.isPhoneNumberShared()) { - certificate = dependencies.getAccountManager().getSenderCertificate(); - } else { - certificate = dependencies.getAccountManager().getSenderCertificateForPhoneNumberPrivacy(); - } - } catch (IOException e) { - logger.warn("Failed to get sender certificate, ignoring: {}", e.getMessage()); - return null; - } - // TODO cache for a day - return certificate; - } - private RecipientId refreshRegisteredUser(RecipientId recipientId) throws IOException { final var address = resolveSignalServiceAddress(recipientId); if (!address.getNumber().isPresent()) { @@ -973,15 +1007,19 @@ public class ManagerImpl implements Manager { } @Override - public List> getContacts() { - return account.getContactStore().getContacts(); + public List> getContacts() { + return account.getContactStore() + .getContacts() + .stream() + .map(p -> new Pair<>(account.getRecipientStore().resolveRecipientAddress(p.first()), p.second())) + .collect(Collectors.toList()); } @Override - public String getContactOrProfileName(RecipientIdentifier.Single recipientIdentifier) { + public String getContactOrProfileName(RecipientIdentifier.Single recipient) { final RecipientId recipientId; try { - recipientId = resolveRecipient(recipientIdentifier); + recipientId = resolveRecipient(recipient); } catch (UnregisteredUserException e) { return null; } @@ -1000,24 +1038,46 @@ public class ManagerImpl implements Manager { } @Override - public GroupInfo getGroup(GroupId groupId) { + public Group getGroup(GroupId groupId) { + return toGroup(groupHelper.getGroup(groupId)); + } + + public GroupInfo getGroupInfo(GroupId groupId) { return groupHelper.getGroup(groupId); } @Override - public List getIdentities() { - return account.getIdentityKeyStore().getIdentities(); + public List getIdentities() { + return account.getIdentityKeyStore() + .getIdentities() + .stream() + .map(this::toIdentity) + .collect(Collectors.toList()); + } + + private Identity toIdentity(final IdentityInfo identityInfo) { + if (identityInfo == null) { + return null; + } + + final var address = account.getRecipientStore().resolveRecipientAddress(identityInfo.getRecipientId()); + return new Identity(address, + identityInfo.getIdentityKey(), + computeSafetyNumber(address.toSignalServiceAddress(), identityInfo.getIdentityKey()), + computeSafetyNumberForScanning(address.toSignalServiceAddress(), identityInfo.getIdentityKey()), + identityInfo.getTrustLevel(), + identityInfo.getDateAdded()); } @Override - public List getIdentities(RecipientIdentifier.Single recipient) { + public List getIdentities(RecipientIdentifier.Single recipient) { IdentityInfo identity; try { identity = account.getIdentityKeyStore().getIdentity(resolveRecipient(recipient)); } catch (UnregisteredUserException e) { identity = null; } - return identity == null ? List.of() : List.of(identity); + return identity == null ? List.of() : List.of(toIdentity(identity)); } /** @@ -1144,8 +1204,7 @@ public class ManagerImpl implements Manager { return fingerprint == null ? null : fingerprint.getDisplayableFingerprint().getDisplayText(); } - @Override - public byte[] computeSafetyNumberForScanning(SignalServiceAddress theirAddress, IdentityKey theirIdentityKey) { + private byte[] computeSafetyNumberForScanning(SignalServiceAddress theirAddress, IdentityKey theirIdentityKey) { final Fingerprint fingerprint = computeSafetyNumberFingerprint(theirAddress, theirIdentityKey); return fingerprint == null ? null : fingerprint.getScannableFingerprint().getSerialized(); } @@ -1165,13 +1224,7 @@ public class ManagerImpl implements Manager { return resolveSignalServiceAddress(resolveRecipient(address)); } - @Override - public SignalServiceAddress resolveSignalServiceAddress(UUID uuid) { - return resolveSignalServiceAddress(account.getRecipientStore().resolveRecipient(uuid)); - } - - @Override - public SignalServiceAddress resolveSignalServiceAddress(RecipientId recipientId) { + private SignalServiceAddress resolveSignalServiceAddress(RecipientId recipientId) { final var address = account.getRecipientStore().resolveRecipientAddress(recipientId); if (address.getUuid().isPresent()) { return address.toSignalServiceAddress(); @@ -1180,13 +1233,15 @@ public class ManagerImpl implements Manager { // Address in recipient store doesn't have a uuid, this shouldn't happen // Try to retrieve the uuid from the server final var number = address.getNumber().get(); + final UUID uuid; try { - return resolveSignalServiceAddress(getRegisteredUser(number)); + uuid = getRegisteredUser(number); } catch (IOException e) { logger.warn("Failed to get uuid for e164 number: {}", number, e); // Return SignalServiceAddress with unknown UUID return address.toSignalServiceAddress(); } + return resolveSignalServiceAddress(account.getRecipientStore().resolveRecipient(uuid)); } private Set resolveRecipients(Collection recipients) throws UnregisteredUserException {