From d72b838560b1a4186ac121c7d605773b49fcdf46 Mon Sep 17 00:00:00 2001 From: AsamK Date: Sat, 18 Sep 2021 10:19:56 +0200 Subject: [PATCH] Refactor Manager interface --- .../org/asamk/signal/manager/Manager.java | 40 +++--- .../org/asamk/signal/manager/ManagerImpl.java | 123 +++++++++++++----- .../signal/manager/RegistrationManager.java | 8 +- .../signal/manager/UserAlreadyExists.java | 10 +- .../org/asamk/signal/manager/api/Device.java | 8 +- .../org/asamk/signal/manager/api/Group.java | 99 ++++++++++++++ .../asamk/signal/manager/api/Identity.java | 65 +++++++++ .../manager/api/RecipientIdentifier.java | 22 ++++ .../storage/recipients/RecipientAddress.java | 10 ++ src/main/java/org/asamk/Signal.java | 4 +- src/main/java/org/asamk/signal/App.java | 2 +- .../asamk/signal/ReceiveMessageHandler.java | 8 +- .../asamk/signal/commands/BlockCommand.java | 2 +- .../asamk/signal/commands/DaemonCommand.java | 2 +- .../signal/commands/JoinGroupCommand.java | 4 +- .../asamk/signal/commands/LinkCommand.java | 4 +- .../signal/commands/ListContactsCommand.java | 11 +- .../signal/commands/ListDevicesCommand.java | 2 +- .../signal/commands/ListGroupsCommand.java | 49 ++++--- .../commands/ListIdentitiesCommand.java | 18 +-- .../signal/commands/QuitGroupCommand.java | 2 +- .../signal/commands/SendReactionCommand.java | 2 +- .../signal/commands/SendReceiptCommand.java | 2 +- .../signal/commands/SendTypingCommand.java | 2 +- .../asamk/signal/commands/TrustCommand.java | 2 +- .../asamk/signal/commands/UnblockCommand.java | 3 +- .../signal/commands/UpdateContactCommand.java | 2 +- .../signal/commands/UpdateGroupCommand.java | 2 +- .../signal/dbus/DbusSignalControlImpl.java | 2 +- .../org/asamk/signal/dbus/DbusSignalImpl.java | 68 +++++----- .../org/asamk/signal/json/JsonMention.java | 3 +- .../signal/json/JsonMessageEnvelope.java | 2 +- .../org/asamk/signal/util/CommandUtil.java | 2 +- 33 files changed, 416 insertions(+), 169 deletions(-) create mode 100644 lib/src/main/java/org/asamk/signal/manager/api/Group.java create mode 100644 lib/src/main/java/org/asamk/signal/manager/api/Identity.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 d2eb0f8f..cba438f8 100644 --- a/lib/src/main/java/org/asamk/signal/manager/Manager.java +++ b/lib/src/main/java/org/asamk/signal/manager/Manager.java @@ -1,6 +1,8 @@ package org.asamk.signal.manager; 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; @@ -17,12 +19,10 @@ import org.asamk.signal.manager.groups.GroupSendingNotAllowedException; import org.asamk.signal.manager.groups.LastGroupAdminException; import org.asamk.signal.manager.groups.NotAGroupMemberException; import org.asamk.signal.manager.storage.SignalAccount; -import org.asamk.signal.manager.storage.groups.GroupInfo; -import org.asamk.signal.manager.storage.identities.IdentityInfo; import org.asamk.signal.manager.storage.identities.TrustNewIdentity; import org.asamk.signal.manager.storage.recipients.Contact; import org.asamk.signal.manager.storage.recipients.Profile; -import org.asamk.signal.manager.storage.recipients.RecipientId; +import org.asamk.signal.manager.storage.recipients.RecipientAddress; import org.whispersystems.libsignal.IdentityKey; import org.whispersystems.libsignal.InvalidKeyException; import org.whispersystems.libsignal.util.Pair; @@ -51,7 +51,7 @@ import java.util.stream.Collectors; public interface Manager extends Closeable { static Manager init( - String username, + String number, File settingsPath, ServiceEnvironment serviceEnvironment, String userAgent, @@ -59,11 +59,11 @@ public interface Manager extends Closeable { ) throws IOException, NotRegisteredException { var pathConfig = PathConfig.createDefault(settingsPath); - if (!SignalAccount.userExists(pathConfig.getDataPath(), username)) { + if (!SignalAccount.userExists(pathConfig.getDataPath(), number)) { throw new NotRegisteredException(); } - var account = SignalAccount.load(pathConfig.getDataPath(), username, true, trustNewIdentity); + var account = SignalAccount.load(pathConfig.getDataPath(), number, true, trustNewIdentity); if (!account.isRegistered()) { throw new NotRegisteredException(); @@ -74,7 +74,7 @@ public interface Manager extends Closeable { return new ManagerImpl(account, pathConfig, serviceEnvironmentConfig, userAgent); } - static List getAllLocalUsernames(File settingsPath) { + static List getAllLocalNumbers(File settingsPath) { var pathConfig = PathConfig.createDefault(settingsPath); final var dataPath = pathConfig.getDataPath(); final var files = dataPath.listFiles(); @@ -90,11 +90,7 @@ public interface Manager extends Closeable { .collect(Collectors.toList()); } - String getUsername(); - - RecipientId getSelfRecipientId(); - - int getDeviceId(); + String getSelfNumber(); void checkAccountState() throws IOException; @@ -120,9 +116,9 @@ public interface Manager extends Closeable { void setRegistrationLockPin(Optional pin) throws IOException, UnauthenticatedResponseException; - Profile getRecipientProfile(RecipientId recipientId); + Profile getRecipientProfile(RecipientIdentifier.Single recipient) throws UnregisteredUserException; - List getGroups(); + List getGroups(); SendGroupMessageResults quitGroup( GroupId groupId, Set groupAdmins @@ -221,15 +217,15 @@ public interface Manager extends Closeable { void sendContacts() throws IOException; - List> getContacts(); + List> getContacts(); - String getContactOrProfileName(RecipientIdentifier.Single recipientIdentifier); + String getContactOrProfileName(RecipientIdentifier.Single recipient); - GroupInfo getGroup(GroupId groupId); + Group getGroup(GroupId groupId); - List getIdentities(); + List getIdentities(); - List getIdentities(RecipientIdentifier.Single recipient); + List getIdentities(RecipientIdentifier.Single recipient); boolean trustIdentityVerified(RecipientIdentifier.Single recipient, byte[] fingerprint); @@ -241,14 +237,8 @@ public interface Manager extends Closeable { String computeSafetyNumber(SignalServiceAddress theirAddress, IdentityKey theirIdentityKey); - byte[] computeSafetyNumberForScanning(SignalServiceAddress theirAddress, IdentityKey theirIdentityKey); - SignalServiceAddress resolveSignalServiceAddress(SignalServiceAddress address); - SignalServiceAddress resolveSignalServiceAddress(UUID uuid); - - SignalServiceAddress resolveSignalServiceAddress(RecipientId recipientId); - @Override void close() throws IOException; 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..de60fa50 100644 --- a/lib/src/main/java/org/asamk/signal/manager/ManagerImpl.java +++ b/lib/src/main/java/org/asamk/signal/manager/ManagerImpl.java @@ -18,6 +18,8 @@ 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; @@ -52,6 +54,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; @@ -196,7 +199,7 @@ public class ManagerImpl implements Manager { this::resolveSignalServiceAddress, account.getRecipientStore(), this::handleIdentityFailure, - this::getGroup, + this::getGroupInfo, this::refreshRegisteredUser); this.groupHelper = new GroupHelper(account, dependencies, @@ -240,20 +243,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) { @@ -385,7 +378,11 @@ 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()); } @@ -442,13 +439,48 @@ 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.getMessageExpirationTime(), + groupInfo.isAnnouncementGroup(), + groupInfo.isMember(account.getSelfRecipientId())); } @Override @@ -973,15 +1005,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 +1036,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 +1202,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 +1222,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 +1231,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 { diff --git a/lib/src/main/java/org/asamk/signal/manager/RegistrationManager.java b/lib/src/main/java/org/asamk/signal/manager/RegistrationManager.java index 978f1fd5..ff94c19b 100644 --- a/lib/src/main/java/org/asamk/signal/manager/RegistrationManager.java +++ b/lib/src/main/java/org/asamk/signal/manager/RegistrationManager.java @@ -91,18 +91,18 @@ public class RegistrationManager implements Closeable { } public static RegistrationManager init( - String username, File settingsPath, ServiceEnvironment serviceEnvironment, String userAgent + String number, File settingsPath, ServiceEnvironment serviceEnvironment, String userAgent ) throws IOException { var pathConfig = PathConfig.createDefault(settingsPath); final var serviceConfiguration = ServiceConfig.getServiceEnvironmentConfig(serviceEnvironment, userAgent); - if (!SignalAccount.userExists(pathConfig.getDataPath(), username)) { + if (!SignalAccount.userExists(pathConfig.getDataPath(), number)) { var identityKey = KeyUtils.generateIdentityKeyPair(); var registrationId = KeyHelper.generateRegistrationId(false); var profileKey = KeyUtils.createProfileKey(); var account = SignalAccount.create(pathConfig.getDataPath(), - username, + number, identityKey, registrationId, profileKey, @@ -111,7 +111,7 @@ public class RegistrationManager implements Closeable { return new RegistrationManager(account, pathConfig, serviceConfiguration, userAgent); } - var account = SignalAccount.load(pathConfig.getDataPath(), username, true, TrustNewIdentity.ON_FIRST_USE); + var account = SignalAccount.load(pathConfig.getDataPath(), number, true, TrustNewIdentity.ON_FIRST_USE); return new RegistrationManager(account, pathConfig, serviceConfiguration, userAgent); } diff --git a/lib/src/main/java/org/asamk/signal/manager/UserAlreadyExists.java b/lib/src/main/java/org/asamk/signal/manager/UserAlreadyExists.java index d506f0c6..905392c5 100644 --- a/lib/src/main/java/org/asamk/signal/manager/UserAlreadyExists.java +++ b/lib/src/main/java/org/asamk/signal/manager/UserAlreadyExists.java @@ -4,16 +4,16 @@ import java.io.File; public class UserAlreadyExists extends Exception { - private final String username; + private final String number; private final File fileName; - public UserAlreadyExists(String username, File fileName) { - this.username = username; + public UserAlreadyExists(String number, File fileName) { + this.number = number; this.fileName = fileName; } - public String getUsername() { - return username; + public String getNumber() { + return number; } public File getFileName() { diff --git a/lib/src/main/java/org/asamk/signal/manager/api/Device.java b/lib/src/main/java/org/asamk/signal/manager/api/Device.java index 76074cbf..9ee0d36a 100644 --- a/lib/src/main/java/org/asamk/signal/manager/api/Device.java +++ b/lib/src/main/java/org/asamk/signal/manager/api/Device.java @@ -6,12 +6,14 @@ public class Device { private final String name; private final long created; private final long lastSeen; + private final boolean thisDevice; - public Device(long id, String name, long created, long lastSeen) { + public Device(long id, String name, long created, long lastSeen, final boolean thisDevice) { this.id = id; this.name = name; this.created = created; this.lastSeen = lastSeen; + this.thisDevice = thisDevice; } public long getId() { @@ -29,4 +31,8 @@ public class Device { public long getLastSeen() { return lastSeen; } + + public boolean isThisDevice() { + return thisDevice; + } } diff --git a/lib/src/main/java/org/asamk/signal/manager/api/Group.java b/lib/src/main/java/org/asamk/signal/manager/api/Group.java new file mode 100644 index 00000000..650e10b6 --- /dev/null +++ b/lib/src/main/java/org/asamk/signal/manager/api/Group.java @@ -0,0 +1,99 @@ +package org.asamk.signal.manager.api; + +import org.asamk.signal.manager.groups.GroupId; +import org.asamk.signal.manager.groups.GroupInviteLinkUrl; +import org.asamk.signal.manager.storage.recipients.RecipientAddress; + +import java.util.Set; + +public class Group { + + private final GroupId groupId; + private final String title; + private final String description; + private final GroupInviteLinkUrl groupInviteLinkUrl; + private final Set members; + private final Set pendingMembers; + private final Set requestingMembers; + private final Set adminMembers; + private final boolean isBlocked; + private final int messageExpirationTime; + private final boolean isAnnouncementGroup; + private final boolean isMember; + + public Group( + final GroupId groupId, + final String title, + final String description, + final GroupInviteLinkUrl groupInviteLinkUrl, + final Set members, + final Set pendingMembers, + final Set requestingMembers, + final Set adminMembers, + final boolean isBlocked, + final int messageExpirationTime, + final boolean isAnnouncementGroup, + final boolean isMember + ) { + this.groupId = groupId; + this.title = title; + this.description = description; + this.groupInviteLinkUrl = groupInviteLinkUrl; + this.members = members; + this.pendingMembers = pendingMembers; + this.requestingMembers = requestingMembers; + this.adminMembers = adminMembers; + this.isBlocked = isBlocked; + this.messageExpirationTime = messageExpirationTime; + this.isAnnouncementGroup = isAnnouncementGroup; + this.isMember = isMember; + } + + public GroupId getGroupId() { + return groupId; + } + + public String getTitle() { + return title; + } + + public String getDescription() { + return description; + } + + public GroupInviteLinkUrl getGroupInviteLinkUrl() { + return groupInviteLinkUrl; + } + + public Set getMembers() { + return members; + } + + public Set getPendingMembers() { + return pendingMembers; + } + + public Set getRequestingMembers() { + return requestingMembers; + } + + public Set getAdminMembers() { + return adminMembers; + } + + public boolean isBlocked() { + return isBlocked; + } + + public int getMessageExpirationTime() { + return messageExpirationTime; + } + + public boolean isAnnouncementGroup() { + return isAnnouncementGroup; + } + + public boolean isMember() { + return isMember; + } +} diff --git a/lib/src/main/java/org/asamk/signal/manager/api/Identity.java b/lib/src/main/java/org/asamk/signal/manager/api/Identity.java new file mode 100644 index 00000000..4f6f21f6 --- /dev/null +++ b/lib/src/main/java/org/asamk/signal/manager/api/Identity.java @@ -0,0 +1,65 @@ +package org.asamk.signal.manager.api; + +import org.asamk.signal.manager.TrustLevel; +import org.asamk.signal.manager.storage.recipients.RecipientAddress; +import org.whispersystems.libsignal.IdentityKey; + +import java.util.Date; + +public class Identity { + + private final RecipientAddress recipient; + private final IdentityKey identityKey; + private final String safetyNumber; + private final byte[] scannableSafetyNumber; + private final TrustLevel trustLevel; + private final Date dateAdded; + + public Identity( + final RecipientAddress recipient, + final IdentityKey identityKey, + final String safetyNumber, + final byte[] scannableSafetyNumber, + final TrustLevel trustLevel, + final Date dateAdded + ) { + this.recipient = recipient; + this.identityKey = identityKey; + this.safetyNumber = safetyNumber; + this.scannableSafetyNumber = scannableSafetyNumber; + this.trustLevel = trustLevel; + this.dateAdded = dateAdded; + } + + public RecipientAddress getRecipient() { + return recipient; + } + + public IdentityKey getIdentityKey() { + return this.identityKey; + } + + public TrustLevel getTrustLevel() { + return this.trustLevel; + } + + boolean isTrusted() { + return trustLevel == TrustLevel.TRUSTED_UNVERIFIED || trustLevel == TrustLevel.TRUSTED_VERIFIED; + } + + public Date getDateAdded() { + return this.dateAdded; + } + + public byte[] getFingerprint() { + return identityKey.getPublicKey().serialize(); + } + + public String getSafetyNumber() { + return safetyNumber; + } + + public byte[] getScannableSafetyNumber() { + return scannableSafetyNumber; + } +} diff --git a/lib/src/main/java/org/asamk/signal/manager/api/RecipientIdentifier.java b/lib/src/main/java/org/asamk/signal/manager/api/RecipientIdentifier.java index cb0a08bb..be1029e6 100644 --- a/lib/src/main/java/org/asamk/signal/manager/api/RecipientIdentifier.java +++ b/lib/src/main/java/org/asamk/signal/manager/api/RecipientIdentifier.java @@ -1,6 +1,7 @@ package org.asamk.signal.manager.api; import org.asamk.signal.manager.groups.GroupId; +import org.asamk.signal.manager.storage.recipients.RecipientAddress; import org.whispersystems.signalservice.api.push.SignalServiceAddress; import org.whispersystems.signalservice.api.util.InvalidNumberException; import org.whispersystems.signalservice.api.util.PhoneNumberFormatter; @@ -29,6 +30,17 @@ public abstract class RecipientIdentifier { public static Single fromAddress(SignalServiceAddress address) { return new Uuid(address.getUuid()); } + + public static Single fromAddress(RecipientAddress address) { + if (address.getNumber().isPresent()) { + return new Number(address.getNumber().get()); + } else if (address.getUuid().isPresent()) { + return new Uuid(address.getUuid().get()); + } + throw new AssertionError("RecipientAddress without identifier"); + } + + public abstract String getIdentifier(); } public static class Uuid extends Single { @@ -53,6 +65,11 @@ public abstract class RecipientIdentifier { public int hashCode() { return uuid.hashCode(); } + + @Override + public String getIdentifier() { + return uuid.toString(); + } } public static class Number extends Single { @@ -77,6 +94,11 @@ public abstract class RecipientIdentifier { public int hashCode() { return number.hashCode(); } + + @Override + public String getIdentifier() { + return number; + } } public static class Group extends RecipientIdentifier { diff --git a/lib/src/main/java/org/asamk/signal/manager/storage/recipients/RecipientAddress.java b/lib/src/main/java/org/asamk/signal/manager/storage/recipients/RecipientAddress.java index 88877d83..c0f5b0b8 100644 --- a/lib/src/main/java/org/asamk/signal/manager/storage/recipients/RecipientAddress.java +++ b/lib/src/main/java/org/asamk/signal/manager/storage/recipients/RecipientAddress.java @@ -57,6 +57,16 @@ public class RecipientAddress { } } + public String getLegacyIdentifier() { + if (e164.isPresent()) { + return e164.get(); + } else if (uuid.isPresent()) { + return uuid.get().toString(); + } else { + throw new AssertionError("Given the checks in the constructor, this should not be possible."); + } + } + public boolean matches(RecipientAddress other) { return (uuid.isPresent() && other.uuid.isPresent() && uuid.get().equals(other.uuid.get())) || ( e164.isPresent() && other.e164.isPresent() && e164.get().equals(other.e164.get()) diff --git a/src/main/java/org/asamk/Signal.java b/src/main/java/org/asamk/Signal.java index b19fba8d..2105ca76 100644 --- a/src/main/java/org/asamk/Signal.java +++ b/src/main/java/org/asamk/Signal.java @@ -13,6 +13,8 @@ import java.util.List; */ public interface Signal extends DBusInterface { + String getNumber(); + long sendMessage( String message, List attachments, String recipient ) throws Error.AttachmentInvalid, Error.Failure, Error.InvalidNumber, Error.UntrustedIdentity; @@ -26,7 +28,7 @@ public interface Signal extends DBusInterface { ) throws Error.Failure, Error.GroupNotFound, Error.UntrustedIdentity; void sendReadReceipt( - String recipient, List targetSentTimestamp + String recipient, List messageIds ) throws Error.Failure, Error.UntrustedIdentity; long sendRemoteDeleteMessage( diff --git a/src/main/java/org/asamk/signal/App.java b/src/main/java/org/asamk/signal/App.java index 4aa510d6..e81b7018 100644 --- a/src/main/java/org/asamk/signal/App.java +++ b/src/main/java/org/asamk/signal/App.java @@ -161,7 +161,7 @@ public class App { } if (username == null) { - var usernames = Manager.getAllLocalUsernames(dataPath); + var usernames = Manager.getAllLocalNumbers(dataPath); if (command instanceof MultiLocalCommand) { handleMultiLocalCommand((MultiLocalCommand) command, diff --git a/src/main/java/org/asamk/signal/ReceiveMessageHandler.java b/src/main/java/org/asamk/signal/ReceiveMessageHandler.java index bc9244f8..35790678 100644 --- a/src/main/java/org/asamk/signal/ReceiveMessageHandler.java +++ b/src/main/java/org/asamk/signal/ReceiveMessageHandler.java @@ -61,13 +61,13 @@ public class ReceiveMessageHandler implements Manager.ReceiveMessageHandler { final var recipientName = getLegacyIdentifier(m.resolveSignalServiceAddress(e.getSender())); writer.println( "Use 'signal-cli -u {} listIdentities -n {}', verify the key and run 'signal-cli -u {} trust -v \"FINGER_PRINT\" {}' to mark it as trusted", - m.getUsername(), + m.getSelfNumber(), recipientName, - m.getUsername(), + m.getSelfNumber(), recipientName); writer.println( "If you don't care about security, use 'signal-cli -u {} trust -a {}' to trust it without verification", - m.getUsername(), + m.getSelfNumber(), recipientName); } else { writer.println("Exception: {} ({})", exception.getMessage(), exception.getClass().getSimpleName()); @@ -657,7 +657,7 @@ public class ReceiveMessageHandler implements Manager.ReceiveMessageHandler { private void printMention( PlainTextWriter writer, SignalServiceDataMessage.Mention mention ) { - final var address = m.resolveSignalServiceAddress(mention.getUuid()); + final var address = m.resolveSignalServiceAddress(new SignalServiceAddress(mention.getUuid())); writer.println("- {}: {} (length: {})", formatContact(address), mention.getStart(), mention.getLength()); } diff --git a/src/main/java/org/asamk/signal/commands/BlockCommand.java b/src/main/java/org/asamk/signal/commands/BlockCommand.java index 5394022e..516224f5 100644 --- a/src/main/java/org/asamk/signal/commands/BlockCommand.java +++ b/src/main/java/org/asamk/signal/commands/BlockCommand.java @@ -37,7 +37,7 @@ public class BlockCommand implements JsonRpcLocalCommand { final Namespace ns, final Manager m, final OutputWriter outputWriter ) throws CommandException { final var contacts = ns.getList("recipient"); - for (var contact : CommandUtil.getSingleRecipientIdentifiers(contacts, m.getUsername())) { + for (var contact : CommandUtil.getSingleRecipientIdentifiers(contacts, m.getSelfNumber())) { try { m.setContactBlocked(contact, true); } catch (NotMasterDeviceException e) { diff --git a/src/main/java/org/asamk/signal/commands/DaemonCommand.java b/src/main/java/org/asamk/signal/commands/DaemonCommand.java index 4a322b99..9878de15 100644 --- a/src/main/java/org/asamk/signal/commands/DaemonCommand.java +++ b/src/main/java/org/asamk/signal/commands/DaemonCommand.java @@ -95,7 +95,7 @@ public class DaemonCommand implements MultiLocalCommand { try (var conn = DBusConnection.getConnection(busType)) { final var signalControl = new DbusSignalControlImpl(c, m -> { try { - final var objectPath = DbusConfig.getObjectPath(m.getUsername()); + final var objectPath = DbusConfig.getObjectPath(m.getSelfNumber()); return run(conn, objectPath, m, outputWriter, ignoreAttachments); } catch (DBusException e) { logger.error("Failed to export object", e); diff --git a/src/main/java/org/asamk/signal/commands/JoinGroupCommand.java b/src/main/java/org/asamk/signal/commands/JoinGroupCommand.java index f5585881..1e06ea9c 100644 --- a/src/main/java/org/asamk/signal/commands/JoinGroupCommand.java +++ b/src/main/java/org/asamk/signal/commands/JoinGroupCommand.java @@ -57,14 +57,14 @@ public class JoinGroupCommand implements JsonRpcLocalCommand { var newGroupId = results.first(); if (outputWriter instanceof JsonWriter) { final var writer = (JsonWriter) outputWriter; - if (!m.getGroup(newGroupId).isMember(m.getSelfRecipientId())) { + if (!m.getGroup(newGroupId).isMember()) { writer.write(Map.of("groupId", newGroupId.toBase64(), "onlyRequested", true)); } else { writer.write(Map.of("groupId", newGroupId.toBase64())); } } else { final var writer = (PlainTextWriter) outputWriter; - if (!m.getGroup(newGroupId).isMember(m.getSelfRecipientId())) { + if (!m.getGroup(newGroupId).isMember()) { writer.println("Requested to join group \"{}\"", newGroupId.toBase64()); } else { writer.println("Joined group \"{}\"", newGroupId.toBase64()); diff --git a/src/main/java/org/asamk/signal/commands/LinkCommand.java b/src/main/java/org/asamk/signal/commands/LinkCommand.java index fbc03300..1d697299 100644 --- a/src/main/java/org/asamk/signal/commands/LinkCommand.java +++ b/src/main/java/org/asamk/signal/commands/LinkCommand.java @@ -44,7 +44,7 @@ public class LinkCommand implements ProvisioningCommand { try { writer.println("{}", m.getDeviceLinkUri()); try (var manager = m.finishDeviceLink(deviceName)) { - writer.println("Associated with: {}", manager.getUsername()); + writer.println("Associated with: {}", manager.getSelfNumber()); } } catch (TimeoutException e) { throw new UserErrorException("Link request timed out, please try again."); @@ -52,7 +52,7 @@ public class LinkCommand implements ProvisioningCommand { throw new IOErrorException("Link request error: " + e.getMessage(), e); } catch (UserAlreadyExists e) { throw new UserErrorException("The user " - + e.getUsername() + + e.getNumber() + " already exists\nDelete \"" + e.getFileName() + "\" before trying again."); diff --git a/src/main/java/org/asamk/signal/commands/ListContactsCommand.java b/src/main/java/org/asamk/signal/commands/ListContactsCommand.java index 5e609a48..b6dfc3ce 100644 --- a/src/main/java/org/asamk/signal/commands/ListContactsCommand.java +++ b/src/main/java/org/asamk/signal/commands/ListContactsCommand.java @@ -8,10 +8,9 @@ import org.asamk.signal.OutputWriter; import org.asamk.signal.PlainTextWriter; import org.asamk.signal.manager.Manager; +import java.util.UUID; import java.util.stream.Collectors; -import static org.asamk.signal.util.Util.getLegacyIdentifier; - public class ListContactsCommand implements JsonRpcLocalCommand { @Override @@ -33,7 +32,7 @@ public class ListContactsCommand implements JsonRpcLocalCommand { for (var c : contacts) { final var contact = c.second(); writer.println("Number: {} Name: {} Blocked: {} Message expiration: {}", - getLegacyIdentifier(m.resolveSignalServiceAddress(c.first())), + c.first().getLegacyIdentifier(), contact.getName(), contact.isBlocked(), contact.getMessageExpirationTime() == 0 @@ -43,10 +42,10 @@ public class ListContactsCommand implements JsonRpcLocalCommand { } else { final var writer = (JsonWriter) outputWriter; final var jsonContacts = contacts.stream().map(contactPair -> { - final var address = m.resolveSignalServiceAddress(contactPair.first()); + final var address = contactPair.first(); final var contact = contactPair.second(); - return new JsonContact(address.getNumber().orNull(), - address.getUuid().toString(), + return new JsonContact(address.getNumber().orElse(null), + address.getUuid().map(UUID::toString).orElse(null), contact.getName(), contact.isBlocked(), contact.getMessageExpirationTime()); diff --git a/src/main/java/org/asamk/signal/commands/ListDevicesCommand.java b/src/main/java/org/asamk/signal/commands/ListDevicesCommand.java index ad0d3531..1de5b842 100644 --- a/src/main/java/org/asamk/signal/commands/ListDevicesCommand.java +++ b/src/main/java/org/asamk/signal/commands/ListDevicesCommand.java @@ -46,7 +46,7 @@ public class ListDevicesCommand implements JsonRpcLocalCommand { if (outputWriter instanceof PlainTextWriter) { final var writer = (PlainTextWriter) outputWriter; for (var d : devices) { - writer.println("- Device {}{}:", d.getId(), (d.getId() == m.getDeviceId() ? " (this device)" : "")); + writer.println("- Device {}{}:", d.getId(), (d.isThisDevice() ? " (this device)" : "")); writer.indent(w -> { w.println("Name: {}", d.getName()); w.println("Created: {}", DateUtils.formatTimestamp(d.getCreated())); diff --git a/src/main/java/org/asamk/signal/commands/ListGroupsCommand.java b/src/main/java/org/asamk/signal/commands/ListGroupsCommand.java index b53577be..1eda53ce 100644 --- a/src/main/java/org/asamk/signal/commands/ListGroupsCommand.java +++ b/src/main/java/org/asamk/signal/commands/ListGroupsCommand.java @@ -9,13 +9,13 @@ import org.asamk.signal.OutputWriter; import org.asamk.signal.PlainTextWriter; import org.asamk.signal.commands.exceptions.CommandException; import org.asamk.signal.manager.Manager; -import org.asamk.signal.manager.storage.groups.GroupInfo; -import org.asamk.signal.manager.storage.recipients.RecipientId; -import org.asamk.signal.util.Util; +import org.asamk.signal.manager.api.Group; +import org.asamk.signal.manager.storage.recipients.RecipientAddress; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.util.Set; +import java.util.UUID; import java.util.stream.Collectors; public class ListGroupsCommand implements JsonRpcLocalCommand { @@ -35,44 +35,41 @@ public class ListGroupsCommand implements JsonRpcLocalCommand { .help("List the members and group invite links of each group. If output=json, then this is always set"); } - private static Set resolveMembers(Manager m, Set addresses) { - return addresses.stream() - .map(m::resolveSignalServiceAddress) - .map(Util::getLegacyIdentifier) - .collect(Collectors.toSet()); + private static Set resolveMembers(Set addresses) { + return addresses.stream().map(RecipientAddress::getLegacyIdentifier).collect(Collectors.toSet()); } - private static Set resolveJsonMembers(Manager m, Set addresses) { + private static Set resolveJsonMembers(Set addresses) { return addresses.stream() - .map(m::resolveSignalServiceAddress) - .map(address -> new JsonGroupMember(address.getNumber().orNull(), address.getUuid().toString())) + .map(address -> new JsonGroupMember(address.getNumber().orElse(null), + address.getUuid().map(UUID::toString).orElse(null))) .collect(Collectors.toSet()); } private static void printGroupPlainText( - PlainTextWriter writer, Manager m, GroupInfo group, boolean detailed + PlainTextWriter writer, Group group, boolean detailed ) { if (detailed) { - final var groupInviteLink = group.getGroupInviteLink(); + final var groupInviteLink = group.getGroupInviteLinkUrl(); writer.println( "Id: {} Name: {} Description: {} Active: {} Blocked: {} Members: {} Pending members: {} Requesting members: {} Admins: {} Message expiration: {} Link: {}", group.getGroupId().toBase64(), group.getTitle(), group.getDescription(), - group.isMember(m.getSelfRecipientId()), + group.isMember(), group.isBlocked(), - resolveMembers(m, group.getMembers()), - resolveMembers(m, group.getPendingMembers()), - resolveMembers(m, group.getRequestingMembers()), - resolveMembers(m, group.getAdminMembers()), + resolveMembers(group.getMembers()), + resolveMembers(group.getPendingMembers()), + resolveMembers(group.getRequestingMembers()), + resolveMembers(group.getAdminMembers()), group.getMessageExpirationTime() == 0 ? "disabled" : group.getMessageExpirationTime() + "s", groupInviteLink == null ? '-' : groupInviteLink.getUrl()); } else { writer.println("Id: {} Name: {} Active: {} Blocked: {}", group.getGroupId().toBase64(), group.getTitle(), - group.isMember(m.getSelfRecipientId()), + group.isMember(), group.isBlocked()); } } @@ -87,18 +84,18 @@ public class ListGroupsCommand implements JsonRpcLocalCommand { final var jsonWriter = (JsonWriter) outputWriter; var jsonGroups = groups.stream().map(group -> { - final var groupInviteLink = group.getGroupInviteLink(); + final var groupInviteLink = group.getGroupInviteLinkUrl(); return new JsonGroup(group.getGroupId().toBase64(), group.getTitle(), group.getDescription(), - group.isMember(m.getSelfRecipientId()), + group.isMember(), group.isBlocked(), group.getMessageExpirationTime(), - resolveJsonMembers(m, group.getMembers()), - resolveJsonMembers(m, group.getPendingMembers()), - resolveJsonMembers(m, group.getRequestingMembers()), - resolveJsonMembers(m, group.getAdminMembers()), + resolveJsonMembers(group.getMembers()), + resolveJsonMembers(group.getPendingMembers()), + resolveJsonMembers(group.getRequestingMembers()), + resolveJsonMembers(group.getAdminMembers()), groupInviteLink == null ? null : groupInviteLink.getUrl()); }).collect(Collectors.toList()); @@ -107,7 +104,7 @@ public class ListGroupsCommand implements JsonRpcLocalCommand { final var writer = (PlainTextWriter) outputWriter; boolean detailed = ns.getBoolean("detailed"); for (var group : groups) { - printGroupPlainText(writer, m, group, detailed); + printGroupPlainText(writer, group, detailed); } } } diff --git a/src/main/java/org/asamk/signal/commands/ListIdentitiesCommand.java b/src/main/java/org/asamk/signal/commands/ListIdentitiesCommand.java index 02cd1d9f..ed2942a5 100644 --- a/src/main/java/org/asamk/signal/commands/ListIdentitiesCommand.java +++ b/src/main/java/org/asamk/signal/commands/ListIdentitiesCommand.java @@ -8,7 +8,7 @@ import org.asamk.signal.OutputWriter; import org.asamk.signal.PlainTextWriter; import org.asamk.signal.commands.exceptions.CommandException; import org.asamk.signal.manager.Manager; -import org.asamk.signal.manager.storage.identities.IdentityInfo; +import org.asamk.signal.manager.api.Identity; import org.asamk.signal.util.CommandUtil; import org.asamk.signal.util.Hex; import org.asamk.signal.util.Util; @@ -29,9 +29,9 @@ public class ListIdentitiesCommand implements JsonRpcLocalCommand { return "listIdentities"; } - private static void printIdentityFingerprint(PlainTextWriter writer, Manager m, IdentityInfo theirId) { - final SignalServiceAddress address = m.resolveSignalServiceAddress(theirId.getRecipientId()); - var digits = Util.formatSafetyNumber(m.computeSafetyNumber(address, theirId.getIdentityKey())); + private static void printIdentityFingerprint(PlainTextWriter writer, Manager m, Identity theirId) { + final SignalServiceAddress address = theirId.getRecipient().toSignalServiceAddress(); + var digits = Util.formatSafetyNumber(theirId.getSafetyNumber()); writer.println("{}: {} Added: {} Fingerprint: {} Safety Number: {}", address.getNumber().orNull(), theirId.getTrustLevel(), @@ -52,11 +52,11 @@ public class ListIdentitiesCommand implements JsonRpcLocalCommand { ) throws CommandException { var number = ns.getString("number"); - List identities; + List identities; if (number == null) { identities = m.getIdentities(); } else { - identities = m.getIdentities(CommandUtil.getSingleRecipientIdentifier(number, m.getUsername())); + identities = m.getIdentities(CommandUtil.getSingleRecipientIdentifier(number, m.getSelfNumber())); } if (outputWriter instanceof PlainTextWriter) { @@ -67,9 +67,9 @@ public class ListIdentitiesCommand implements JsonRpcLocalCommand { } else { final var writer = (JsonWriter) outputWriter; final var jsonIdentities = identities.stream().map(id -> { - final var address = m.resolveSignalServiceAddress(id.getRecipientId()); - var safetyNumber = Util.formatSafetyNumber(m.computeSafetyNumber(address, id.getIdentityKey())); - var scannableSafetyNumber = m.computeSafetyNumberForScanning(address, id.getIdentityKey()); + final var address = id.getRecipient().toSignalServiceAddress(); + var safetyNumber = Util.formatSafetyNumber(id.getSafetyNumber()); + var scannableSafetyNumber = id.getScannableSafetyNumber(); return new JsonIdentity(address.getNumber().orNull(), address.getUuid().toString(), Hex.toString(id.getFingerprint()), diff --git a/src/main/java/org/asamk/signal/commands/QuitGroupCommand.java b/src/main/java/org/asamk/signal/commands/QuitGroupCommand.java index 67a6596b..7635f8ae 100644 --- a/src/main/java/org/asamk/signal/commands/QuitGroupCommand.java +++ b/src/main/java/org/asamk/signal/commands/QuitGroupCommand.java @@ -50,7 +50,7 @@ public class QuitGroupCommand implements JsonRpcLocalCommand { ) throws CommandException { final var groupId = CommandUtil.getGroupId(ns.getString("group-id")); - var groupAdmins = CommandUtil.getSingleRecipientIdentifiers(ns.getList("admin"), m.getUsername()); + var groupAdmins = CommandUtil.getSingleRecipientIdentifiers(ns.getList("admin"), m.getSelfNumber()); try { try { diff --git a/src/main/java/org/asamk/signal/commands/SendReactionCommand.java b/src/main/java/org/asamk/signal/commands/SendReactionCommand.java index 338e70ac..f8c3c358 100644 --- a/src/main/java/org/asamk/signal/commands/SendReactionCommand.java +++ b/src/main/java/org/asamk/signal/commands/SendReactionCommand.java @@ -72,7 +72,7 @@ public class SendReactionCommand implements DbusCommand, JsonRpcLocalCommand { try { final var results = m.sendMessageReaction(emoji, isRemove, - CommandUtil.getSingleRecipientIdentifier(targetAuthor, m.getUsername()), + CommandUtil.getSingleRecipientIdentifier(targetAuthor, m.getSelfNumber()), targetTimestamp, recipientIdentifiers); outputResult(outputWriter, results.getTimestamp()); diff --git a/src/main/java/org/asamk/signal/commands/SendReceiptCommand.java b/src/main/java/org/asamk/signal/commands/SendReceiptCommand.java index 0d5772ec..5dd29682 100644 --- a/src/main/java/org/asamk/signal/commands/SendReceiptCommand.java +++ b/src/main/java/org/asamk/signal/commands/SendReceiptCommand.java @@ -37,7 +37,7 @@ public class SendReceiptCommand implements JsonRpcLocalCommand { final Namespace ns, final Manager m, final OutputWriter outputWriter ) throws CommandException { final var recipientString = ns.getString("recipient"); - final var recipient = CommandUtil.getSingleRecipientIdentifier(recipientString, m.getUsername()); + final var recipient = CommandUtil.getSingleRecipientIdentifier(recipientString, m.getSelfNumber()); final var targetTimestamps = ns.getList("target-timestamp"); final var type = ns.getString("type"); diff --git a/src/main/java/org/asamk/signal/commands/SendTypingCommand.java b/src/main/java/org/asamk/signal/commands/SendTypingCommand.java index 3a965e47..cfe66770 100644 --- a/src/main/java/org/asamk/signal/commands/SendTypingCommand.java +++ b/src/main/java/org/asamk/signal/commands/SendTypingCommand.java @@ -45,7 +45,7 @@ public class SendTypingCommand implements JsonRpcLocalCommand { final var recipientIdentifiers = new HashSet(); if (recipientStrings != null) { - final var localNumber = m.getUsername(); + final var localNumber = m.getSelfNumber(); recipientIdentifiers.addAll(CommandUtil.getSingleRecipientIdentifiers(recipientStrings, localNumber)); } if (groupIdStrings != null) { diff --git a/src/main/java/org/asamk/signal/commands/TrustCommand.java b/src/main/java/org/asamk/signal/commands/TrustCommand.java index aedc2c3e..9e59ad86 100644 --- a/src/main/java/org/asamk/signal/commands/TrustCommand.java +++ b/src/main/java/org/asamk/signal/commands/TrustCommand.java @@ -38,7 +38,7 @@ public class TrustCommand implements JsonRpcLocalCommand { final Namespace ns, final Manager m, final OutputWriter outputWriter ) throws CommandException { var recipentString = ns.getString("recipient"); - var recipient = CommandUtil.getSingleRecipientIdentifier(recipentString, m.getUsername()); + var recipient = CommandUtil.getSingleRecipientIdentifier(recipentString, m.getSelfNumber()); if (ns.getBoolean("trust-all-known-keys")) { boolean res = m.trustIdentityAllKeys(recipient); if (!res) { diff --git a/src/main/java/org/asamk/signal/commands/UnblockCommand.java b/src/main/java/org/asamk/signal/commands/UnblockCommand.java index 812065bc..7cf209fa 100644 --- a/src/main/java/org/asamk/signal/commands/UnblockCommand.java +++ b/src/main/java/org/asamk/signal/commands/UnblockCommand.java @@ -36,7 +36,8 @@ public class UnblockCommand implements JsonRpcLocalCommand { public void handleCommand( final Namespace ns, final Manager m, final OutputWriter outputWriter ) throws CommandException { - for (var contactNumber : CommandUtil.getSingleRecipientIdentifiers(ns.getList("recipient"), m.getUsername())) { + for (var contactNumber : CommandUtil.getSingleRecipientIdentifiers(ns.getList("recipient"), + m.getSelfNumber())) { try { m.setContactBlocked(contactNumber, false); } catch (NotMasterDeviceException e) { diff --git a/src/main/java/org/asamk/signal/commands/UpdateContactCommand.java b/src/main/java/org/asamk/signal/commands/UpdateContactCommand.java index 6c2916eb..46641668 100644 --- a/src/main/java/org/asamk/signal/commands/UpdateContactCommand.java +++ b/src/main/java/org/asamk/signal/commands/UpdateContactCommand.java @@ -33,7 +33,7 @@ public class UpdateContactCommand implements JsonRpcLocalCommand { final Namespace ns, final Manager m, final OutputWriter outputWriter ) throws CommandException { var recipientString = ns.getString("recipient"); - var recipient = CommandUtil.getSingleRecipientIdentifier(recipientString, m.getUsername()); + var recipient = CommandUtil.getSingleRecipientIdentifier(recipientString, m.getSelfNumber()); try { var expiration = ns.getInt("expiration"); diff --git a/src/main/java/org/asamk/signal/commands/UpdateGroupCommand.java b/src/main/java/org/asamk/signal/commands/UpdateGroupCommand.java index b0269894..49cd4719 100644 --- a/src/main/java/org/asamk/signal/commands/UpdateGroupCommand.java +++ b/src/main/java/org/asamk/signal/commands/UpdateGroupCommand.java @@ -116,7 +116,7 @@ public class UpdateGroupCommand implements DbusCommand, JsonRpcLocalCommand { final var groupIdString = ns.getString("group-id"); var groupId = CommandUtil.getGroupId(groupIdString); - final var localNumber = m.getUsername(); + final var localNumber = m.getSelfNumber(); var groupName = ns.getString("name"); var groupDescription = ns.getString("description"); diff --git a/src/main/java/org/asamk/signal/dbus/DbusSignalControlImpl.java b/src/main/java/org/asamk/signal/dbus/DbusSignalControlImpl.java index 6ec8d964..be628bde 100644 --- a/src/main/java/org/asamk/signal/dbus/DbusSignalControlImpl.java +++ b/src/main/java/org/asamk/signal/dbus/DbusSignalControlImpl.java @@ -160,7 +160,7 @@ public class DbusSignalControlImpl implements org.asamk.SignalControl { synchronized (receiveThreads) { return receiveThreads.stream() .map(Pair::first) - .map(Manager::getUsername) + .map(Manager::getSelfNumber) .map(u -> new DBusPath(DbusConfig.getObjectPath(u))) .collect(Collectors.toList()); } diff --git a/src/main/java/org/asamk/signal/dbus/DbusSignalImpl.java b/src/main/java/org/asamk/signal/dbus/DbusSignalImpl.java index e975a671..c8208774 100644 --- a/src/main/java/org/asamk/signal/dbus/DbusSignalImpl.java +++ b/src/main/java/org/asamk/signal/dbus/DbusSignalImpl.java @@ -8,6 +8,7 @@ import org.asamk.signal.manager.NotMasterDeviceException; import org.asamk.signal.manager.StickerPackInvalidException; import org.asamk.signal.manager.UntrustedIdentityException; import org.asamk.signal.manager.api.Device; +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.TypingAction; @@ -17,9 +18,9 @@ import org.asamk.signal.manager.groups.GroupNotFoundException; import org.asamk.signal.manager.groups.GroupSendingNotAllowedException; import org.asamk.signal.manager.groups.LastGroupAdminException; import org.asamk.signal.manager.groups.NotAGroupMemberException; -import org.asamk.signal.manager.storage.identities.IdentityInfo; +import org.asamk.signal.manager.storage.recipients.Profile; +import org.asamk.signal.manager.storage.recipients.RecipientAddress; import org.asamk.signal.util.ErrorUtils; -import org.asamk.signal.util.Util; import org.freedesktop.dbus.exceptions.DBusExecutionException; import org.whispersystems.libsignal.InvalidKeyException; import org.whispersystems.libsignal.util.Pair; @@ -45,8 +46,6 @@ import java.util.UUID; import java.util.stream.Collectors; import java.util.stream.Stream; -import static org.asamk.signal.util.Util.getLegacyIdentifier; - public class DbusSignalImpl implements Signal { private final Manager m; @@ -67,6 +66,11 @@ public class DbusSignalImpl implements Signal { return objectPath; } + @Override + public String getNumber() { + return m.getSelfNumber(); + } + @Override public void addDevice(String uri) { try { @@ -123,7 +127,7 @@ public class DbusSignalImpl implements Signal { public long sendMessage(final String message, final List attachments, final List recipients) { try { final var results = m.sendMessage(new Message(message, attachments), - getSingleRecipientIdentifiers(recipients, m.getUsername()).stream() + getSingleRecipientIdentifiers(recipients, m.getSelfNumber()).stream() .map(RecipientIdentifier.class::cast) .collect(Collectors.toSet())); @@ -153,7 +157,7 @@ public class DbusSignalImpl implements Signal { ) { try { final var results = m.sendRemoteDeleteMessage(targetSentTimestamp, - getSingleRecipientIdentifiers(recipients, m.getUsername()).stream() + getSingleRecipientIdentifiers(recipients, m.getSelfNumber()).stream() .map(RecipientIdentifier.class::cast) .collect(Collectors.toSet())); checkSendMessageResults(results.getTimestamp(), results.getResults()); @@ -205,9 +209,9 @@ public class DbusSignalImpl implements Signal { try { final var results = m.sendMessageReaction(emoji, remove, - getSingleRecipientIdentifier(targetAuthor, m.getUsername()), + getSingleRecipientIdentifier(targetAuthor, m.getSelfNumber()), targetSentTimestamp, - getSingleRecipientIdentifiers(recipients, m.getUsername()).stream() + getSingleRecipientIdentifiers(recipients, m.getSelfNumber()).stream() .map(RecipientIdentifier.class::cast) .collect(Collectors.toSet())); checkSendMessageResults(results.getTimestamp(), results.getResults()); @@ -227,7 +231,7 @@ public class DbusSignalImpl implements Signal { var recipients = new ArrayList(1); recipients.add(recipient); m.sendTypingMessage(stop ? TypingAction.STOP : TypingAction.START, - getSingleRecipientIdentifiers(recipients, m.getUsername()).stream() + getSingleRecipientIdentifiers(recipients, m.getSelfNumber()).stream() .map(RecipientIdentifier.class::cast) .collect(Collectors.toSet())); } catch (IOException e) { @@ -241,10 +245,10 @@ public class DbusSignalImpl implements Signal { @Override public void sendReadReceipt( - final String recipient, final List timestamps + final String recipient, final List messageIds ) throws Error.Failure, Error.UntrustedIdentity { try { - m.sendReadReceipt(getSingleRecipientIdentifier(recipient, m.getUsername()), timestamps); + m.sendReadReceipt(getSingleRecipientIdentifier(recipient, m.getSelfNumber()), messageIds); } catch (IOException e) { throw new Error.Failure(e.getMessage()); } catch (UntrustedIdentityException e) { @@ -291,7 +295,7 @@ public class DbusSignalImpl implements Signal { @Override public void sendEndSessionMessage(final List recipients) { try { - final var results = m.sendEndSessionMessage(getSingleRecipientIdentifiers(recipients, m.getUsername())); + final var results = m.sendEndSessionMessage(getSingleRecipientIdentifiers(recipients, m.getSelfNumber())); checkSendMessageResults(results.getTimestamp(), results.getResults()); } catch (IOException e) { throw new Error.Failure(e.getMessage()); @@ -325,7 +329,7 @@ public class DbusSignalImpl implements Signal { try { final var results = m.sendMessageReaction(emoji, remove, - getSingleRecipientIdentifier(targetAuthor, m.getUsername()), + getSingleRecipientIdentifier(targetAuthor, m.getSelfNumber()), targetSentTimestamp, Set.of(new RecipientIdentifier.Group(getGroupId(groupId)))); checkSendMessageResults(results.getTimestamp(), results.getResults()); @@ -341,13 +345,13 @@ public class DbusSignalImpl implements Signal { // the profile name @Override public String getContactName(final String number) { - return m.getContactOrProfileName(getSingleRecipientIdentifier(number, m.getUsername())); + return m.getContactOrProfileName(getSingleRecipientIdentifier(number, m.getSelfNumber())); } @Override public void setContactName(final String number, final String name) { try { - m.setContactName(getSingleRecipientIdentifier(number, m.getUsername()), name); + m.setContactName(getSingleRecipientIdentifier(number, m.getSelfNumber()), name); } catch (NotMasterDeviceException e) { throw new Error.Failure("This command doesn't work on linked devices."); } catch (UnregisteredUserException e) { @@ -358,7 +362,7 @@ public class DbusSignalImpl implements Signal { @Override public void setExpirationTimer(final String number, final int expiration) { try { - m.setExpirationTimer(getSingleRecipientIdentifier(number, m.getUsername()), expiration); + m.setExpirationTimer(getSingleRecipientIdentifier(number, m.getSelfNumber()), expiration); } catch (IOException e) { throw new Error.Failure(e.getMessage()); } @@ -367,7 +371,7 @@ public class DbusSignalImpl implements Signal { @Override public void setContactBlocked(final String number, final boolean blocked) { try { - m.setContactBlocked(getSingleRecipientIdentifier(number, m.getUsername()), blocked); + m.setContactBlocked(getSingleRecipientIdentifier(number, m.getSelfNumber()), blocked); } catch (NotMasterDeviceException e) { throw new Error.Failure("This command doesn't work on linked devices."); } catch (IOException e) { @@ -412,11 +416,7 @@ public class DbusSignalImpl implements Signal { if (group == null) { return List.of(); } else { - return group.getMembers() - .stream() - .map(m::resolveSignalServiceAddress) - .map(Util::getLegacyIdentifier) - .collect(Collectors.toList()); + return group.getMembers().stream().map(RecipientAddress::getLegacyIdentifier).collect(Collectors.toList()); } } @@ -432,7 +432,7 @@ public class DbusSignalImpl implements Signal { if (avatar.isEmpty()) { avatar = null; } - final var memberIdentifiers = getSingleRecipientIdentifiers(members, m.getUsername()); + final var memberIdentifiers = getSingleRecipientIdentifiers(members, m.getSelfNumber()); if (groupId == null) { final var results = m.createGroup(name, memberIdentifiers, avatar == null ? null : new File(avatar)); checkSendMessageResults(results.second().getTimestamp(), results.second().getResults()); @@ -573,10 +573,9 @@ public class DbusSignalImpl implements Signal { // all numbers the system knows @Override public List listNumbers() { - return Stream.concat(m.getIdentities().stream().map(IdentityInfo::getRecipientId), + return Stream.concat(m.getIdentities().stream().map(Identity::getRecipient), m.getContacts().stream().map(Pair::first)) - .map(m::resolveSignalServiceAddress) - .map(a -> a.getNumber().orNull()) + .map(a -> a.getNumber().orElse(null)) .filter(Objects::nonNull) .distinct() .collect(Collectors.toList()); @@ -589,16 +588,19 @@ public class DbusSignalImpl implements Signal { var contacts = m.getContacts(); for (var c : contacts) { if (name.equals(c.second().getName())) { - numbers.add(getLegacyIdentifier(m.resolveSignalServiceAddress(c.first()))); + numbers.add(c.first().getLegacyIdentifier()); } } // Try profiles if no contact name was found for (var identity : m.getIdentities()) { - final var recipientId = identity.getRecipientId(); - final var address = m.resolveSignalServiceAddress(recipientId); - var number = address.getNumber().orNull(); + final var address = identity.getRecipient(); + var number = address.getNumber().orElse(null); if (number != null) { - var profile = m.getRecipientProfile(recipientId); + Profile profile = null; + try { + profile = m.getRecipientProfile(RecipientIdentifier.Single.fromAddress(address)); + } catch (UnregisteredUserException ignored) { + } if (profile != null && profile.getDisplayName().equals(name)) { numbers.add(number); } @@ -639,7 +641,7 @@ public class DbusSignalImpl implements Signal { @Override public boolean isContactBlocked(final String number) { - return m.isContactBlocked(getSingleRecipientIdentifier(number, m.getUsername())); + return m.isContactBlocked(getSingleRecipientIdentifier(number, m.getSelfNumber())); } @Override @@ -658,7 +660,7 @@ public class DbusSignalImpl implements Signal { if (group == null) { return false; } else { - return group.isMember(m.getSelfRecipientId()); + return group.isMember(); } } diff --git a/src/main/java/org/asamk/signal/json/JsonMention.java b/src/main/java/org/asamk/signal/json/JsonMention.java index b24768b7..3c6f2eec 100644 --- a/src/main/java/org/asamk/signal/json/JsonMention.java +++ b/src/main/java/org/asamk/signal/json/JsonMention.java @@ -4,6 +4,7 @@ import com.fasterxml.jackson.annotation.JsonProperty; import org.asamk.signal.manager.Manager; import org.whispersystems.signalservice.api.messages.SignalServiceDataMessage; +import org.whispersystems.signalservice.api.push.SignalServiceAddress; import static org.asamk.signal.util.Util.getLegacyIdentifier; @@ -26,7 +27,7 @@ public class JsonMention { final int length; JsonMention(SignalServiceDataMessage.Mention mention, Manager m) { - final var address = m.resolveSignalServiceAddress(mention.getUuid()); + final var address = m.resolveSignalServiceAddress(new SignalServiceAddress(mention.getUuid())); this.name = getLegacyIdentifier(address); this.number = address.getNumber().orNull(); this.uuid = address.getUuid().toString(); diff --git a/src/main/java/org/asamk/signal/json/JsonMessageEnvelope.java b/src/main/java/org/asamk/signal/json/JsonMessageEnvelope.java index 7b884b0e..e49e6125 100644 --- a/src/main/java/org/asamk/signal/json/JsonMessageEnvelope.java +++ b/src/main/java/org/asamk/signal/json/JsonMessageEnvelope.java @@ -86,7 +86,7 @@ public class JsonMessageEnvelope { } String name; try { - name = m.getContactOrProfileName(RecipientIdentifier.Single.fromString(this.source, m.getUsername())); + name = m.getContactOrProfileName(RecipientIdentifier.Single.fromString(this.source, m.getSelfNumber())); } catch (InvalidNumberException | NullPointerException e) { name = null; } diff --git a/src/main/java/org/asamk/signal/util/CommandUtil.java b/src/main/java/org/asamk/signal/util/CommandUtil.java index 18b38a2a..0a624e6b 100644 --- a/src/main/java/org/asamk/signal/util/CommandUtil.java +++ b/src/main/java/org/asamk/signal/util/CommandUtil.java @@ -28,7 +28,7 @@ public class CommandUtil { recipientIdentifiers.add(RecipientIdentifier.NoteToSelf.INSTANCE); } if (recipientStrings != null) { - final var localNumber = m.getUsername(); + final var localNumber = m.getSelfNumber(); recipientIdentifiers.addAll(CommandUtil.getSingleRecipientIdentifiers(recipientStrings, localNumber)); } if (groupIdStrings != null) { -- 2.50.1