mirror of
https://github.com/AsamK/signal-cli
synced 2025-08-29 02:20:39 +00:00
Refactor Manager interface
This commit is contained in:
parent
b91c162159
commit
d72b838560
33 changed files with 416 additions and 169 deletions
|
@ -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<String> getAllLocalUsernames(File settingsPath) {
|
||||
static List<String> 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<String> pin) throws IOException, UnauthenticatedResponseException;
|
||||
|
||||
Profile getRecipientProfile(RecipientId recipientId);
|
||||
Profile getRecipientProfile(RecipientIdentifier.Single recipient) throws UnregisteredUserException;
|
||||
|
||||
List<GroupInfo> getGroups();
|
||||
List<Group> getGroups();
|
||||
|
||||
SendGroupMessageResults quitGroup(
|
||||
GroupId groupId, Set<RecipientIdentifier.Single> groupAdmins
|
||||
|
@ -221,15 +217,15 @@ public interface Manager extends Closeable {
|
|||
|
||||
void sendContacts() throws IOException;
|
||||
|
||||
List<Pair<RecipientId, Contact>> getContacts();
|
||||
List<Pair<RecipientAddress, Contact>> getContacts();
|
||||
|
||||
String getContactOrProfileName(RecipientIdentifier.Single recipientIdentifier);
|
||||
String getContactOrProfileName(RecipientIdentifier.Single recipient);
|
||||
|
||||
GroupInfo getGroup(GroupId groupId);
|
||||
Group getGroup(GroupId groupId);
|
||||
|
||||
List<IdentityInfo> getIdentities();
|
||||
List<Identity> getIdentities();
|
||||
|
||||
List<IdentityInfo> getIdentities(RecipientIdentifier.Single recipient);
|
||||
List<Identity> 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;
|
||||
|
||||
|
|
|
@ -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<GroupInfo> getGroups() {
|
||||
return account.getGroupStore().getGroups();
|
||||
public List<Group> 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<Pair<RecipientId, Contact>> getContacts() {
|
||||
return account.getContactStore().getContacts();
|
||||
public List<Pair<RecipientAddress, Contact>> 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<IdentityInfo> getIdentities() {
|
||||
return account.getIdentityKeyStore().getIdentities();
|
||||
public List<Identity> 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<IdentityInfo> getIdentities(RecipientIdentifier.Single recipient) {
|
||||
public List<Identity> 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<RecipientId> resolveRecipients(Collection<RecipientIdentifier.Single> recipients) throws UnregisteredUserException {
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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() {
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
99
lib/src/main/java/org/asamk/signal/manager/api/Group.java
Normal file
99
lib/src/main/java/org/asamk/signal/manager/api/Group.java
Normal file
|
@ -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<RecipientAddress> members;
|
||||
private final Set<RecipientAddress> pendingMembers;
|
||||
private final Set<RecipientAddress> requestingMembers;
|
||||
private final Set<RecipientAddress> 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<RecipientAddress> members,
|
||||
final Set<RecipientAddress> pendingMembers,
|
||||
final Set<RecipientAddress> requestingMembers,
|
||||
final Set<RecipientAddress> 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<RecipientAddress> getMembers() {
|
||||
return members;
|
||||
}
|
||||
|
||||
public Set<RecipientAddress> getPendingMembers() {
|
||||
return pendingMembers;
|
||||
}
|
||||
|
||||
public Set<RecipientAddress> getRequestingMembers() {
|
||||
return requestingMembers;
|
||||
}
|
||||
|
||||
public Set<RecipientAddress> getAdminMembers() {
|
||||
return adminMembers;
|
||||
}
|
||||
|
||||
public boolean isBlocked() {
|
||||
return isBlocked;
|
||||
}
|
||||
|
||||
public int getMessageExpirationTime() {
|
||||
return messageExpirationTime;
|
||||
}
|
||||
|
||||
public boolean isAnnouncementGroup() {
|
||||
return isAnnouncementGroup;
|
||||
}
|
||||
|
||||
public boolean isMember() {
|
||||
return isMember;
|
||||
}
|
||||
}
|
65
lib/src/main/java/org/asamk/signal/manager/api/Identity.java
Normal file
65
lib/src/main/java/org/asamk/signal/manager/api/Identity.java
Normal file
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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 {
|
||||
|
|
|
@ -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())
|
||||
|
|
|
@ -13,6 +13,8 @@ import java.util.List;
|
|||
*/
|
||||
public interface Signal extends DBusInterface {
|
||||
|
||||
String getNumber();
|
||||
|
||||
long sendMessage(
|
||||
String message, List<String> 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<Long> targetSentTimestamp
|
||||
String recipient, List<Long> messageIds
|
||||
) throws Error.Failure, Error.UntrustedIdentity;
|
||||
|
||||
long sendRemoteDeleteMessage(
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
|
||||
|
|
|
@ -37,7 +37,7 @@ public class BlockCommand implements JsonRpcLocalCommand {
|
|||
final Namespace ns, final Manager m, final OutputWriter outputWriter
|
||||
) throws CommandException {
|
||||
final var contacts = ns.<String>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) {
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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());
|
||||
|
|
|
@ -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.");
|
||||
|
|
|
@ -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());
|
||||
|
|
|
@ -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()));
|
||||
|
|
|
@ -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<String> resolveMembers(Manager m, Set<RecipientId> addresses) {
|
||||
return addresses.stream()
|
||||
.map(m::resolveSignalServiceAddress)
|
||||
.map(Util::getLegacyIdentifier)
|
||||
.collect(Collectors.toSet());
|
||||
private static Set<String> resolveMembers(Set<RecipientAddress> addresses) {
|
||||
return addresses.stream().map(RecipientAddress::getLegacyIdentifier).collect(Collectors.toSet());
|
||||
}
|
||||
|
||||
private static Set<JsonGroupMember> resolveJsonMembers(Manager m, Set<RecipientId> addresses) {
|
||||
private static Set<JsonGroupMember> resolveJsonMembers(Set<RecipientAddress> 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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<IdentityInfo> identities;
|
||||
List<Identity> 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()),
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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());
|
||||
|
|
|
@ -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.<Long>getList("target-timestamp");
|
||||
final var type = ns.getString("type");
|
||||
|
|
|
@ -45,7 +45,7 @@ public class SendTypingCommand implements JsonRpcLocalCommand {
|
|||
|
||||
final var recipientIdentifiers = new HashSet<RecipientIdentifier>();
|
||||
if (recipientStrings != null) {
|
||||
final var localNumber = m.getUsername();
|
||||
final var localNumber = m.getSelfNumber();
|
||||
recipientIdentifiers.addAll(CommandUtil.getSingleRecipientIdentifiers(recipientStrings, localNumber));
|
||||
}
|
||||
if (groupIdStrings != null) {
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
|
|
|
@ -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<String> attachments, final List<String> 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<String>(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<Long> timestamps
|
||||
final String recipient, final List<Long> 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<String> 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<String> 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();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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) {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue