mirror of
https://github.com/AsamK/signal-cli
synced 2025-08-28 18:10:38 +00:00
Update libsignal-service-java
This commit is contained in:
parent
85c5caeaca
commit
8bcd8d87d2
52 changed files with 692 additions and 551 deletions
|
@ -14,7 +14,7 @@ repositories {
|
|||
}
|
||||
|
||||
dependencies {
|
||||
api("com.github.turasa:signal-service-java:2.15.3_unofficial_25")
|
||||
api("com.github.turasa:signal-service-java:2.15.3_unofficial_26")
|
||||
implementation("com.google.protobuf:protobuf-javalite:3.10.0")
|
||||
implementation("org.bouncycastle:bcprov-jdk15on:1.69")
|
||||
implementation("org.slf4j:slf4j-api:1.7.30")
|
||||
|
|
|
@ -82,7 +82,7 @@ public class AvatarStore {
|
|||
}
|
||||
|
||||
private String getLegacyIdentifier(final SignalServiceAddress address) {
|
||||
return address.getNumber().or(() -> address.getUuid().get().toString());
|
||||
return address.getNumber().or(() -> address.getUuid().toString());
|
||||
}
|
||||
|
||||
private File getProfileAvatarFile(SignalServiceAddress address) {
|
||||
|
|
|
@ -73,7 +73,6 @@ import org.whispersystems.libsignal.state.SignedPreKeyRecord;
|
|||
import org.whispersystems.libsignal.util.Pair;
|
||||
import org.whispersystems.libsignal.util.guava.Optional;
|
||||
import org.whispersystems.signalservice.api.SignalSessionLock;
|
||||
import org.whispersystems.signalservice.api.crypto.UntrustedIdentityException;
|
||||
import org.whispersystems.signalservice.api.groupsv2.GroupLinkNotActiveException;
|
||||
import org.whispersystems.signalservice.api.messages.SendMessageResult;
|
||||
import org.whispersystems.signalservice.api.messages.SignalServiceAttachmentRemoteId;
|
||||
|
@ -83,6 +82,7 @@ import org.whispersystems.signalservice.api.messages.SignalServiceEnvelope;
|
|||
import org.whispersystems.signalservice.api.messages.SignalServiceReceiptMessage;
|
||||
import org.whispersystems.signalservice.api.messages.SignalServiceTypingMessage;
|
||||
import org.whispersystems.signalservice.api.push.SignalServiceAddress;
|
||||
import org.whispersystems.signalservice.api.push.exceptions.UnregisteredUserException;
|
||||
import org.whispersystems.signalservice.api.util.DeviceNameUtil;
|
||||
import org.whispersystems.signalservice.api.util.InvalidNumberException;
|
||||
import org.whispersystems.signalservice.api.util.PhoneNumberFormatter;
|
||||
|
@ -200,7 +200,7 @@ public class Manager implements Closeable {
|
|||
dependencies,
|
||||
unidentifiedAccessHelper,
|
||||
this::resolveSignalServiceAddress,
|
||||
this::resolveRecipient,
|
||||
account.getRecipientStore(),
|
||||
this::handleIdentityFailure,
|
||||
this::getGroup,
|
||||
this::refreshRegisteredUser);
|
||||
|
@ -211,15 +211,14 @@ public class Manager implements Closeable {
|
|||
groupV2Helper,
|
||||
avatarStore,
|
||||
this::resolveSignalServiceAddress,
|
||||
this::resolveRecipient);
|
||||
account.getRecipientStore());
|
||||
this.contactHelper = new ContactHelper(account);
|
||||
this.syncHelper = new SyncHelper(account,
|
||||
attachmentHelper,
|
||||
sendHelper,
|
||||
groupHelper,
|
||||
avatarStore,
|
||||
this::resolveSignalServiceAddress,
|
||||
this::resolveRecipient);
|
||||
this::resolveSignalServiceAddress);
|
||||
|
||||
this.context = new Context(account,
|
||||
dependencies.getAccountManager(),
|
||||
|
@ -233,7 +232,8 @@ public class Manager implements Closeable {
|
|||
|
||||
this.incomingMessageHandler = new IncomingMessageHandler(account,
|
||||
dependencies,
|
||||
this::resolveRecipient,
|
||||
account.getRecipientStore(),
|
||||
this::resolveSignalServiceAddress,
|
||||
groupHelper,
|
||||
contactHelper,
|
||||
attachmentHelper,
|
||||
|
@ -328,7 +328,7 @@ public class Manager implements Closeable {
|
|||
public Map<String, Pair<String, UUID>> areUsersRegistered(Set<String> numbers) throws IOException {
|
||||
Map<String, String> canonicalizedNumbers = numbers.stream().collect(Collectors.toMap(n -> n, n -> {
|
||||
try {
|
||||
return canonicalizePhoneNumber(n);
|
||||
return PhoneNumberFormatter.formatNumber(n, account.getUsername());
|
||||
} catch (InvalidNumberException e) {
|
||||
return "";
|
||||
}
|
||||
|
@ -490,7 +490,7 @@ public class Manager implements Closeable {
|
|||
public SendGroupMessageResults quitGroup(
|
||||
GroupId groupId, Set<RecipientIdentifier.Single> groupAdmins
|
||||
) throws GroupNotFoundException, IOException, NotAGroupMemberException, LastGroupAdminException {
|
||||
final var newAdmins = getRecipientIds(groupAdmins);
|
||||
final var newAdmins = resolveRecipients(groupAdmins);
|
||||
return groupHelper.quitGroup(groupId, newAdmins);
|
||||
}
|
||||
|
||||
|
@ -501,7 +501,7 @@ public class Manager implements Closeable {
|
|||
public Pair<GroupId, SendGroupMessageResults> createGroup(
|
||||
String name, Set<RecipientIdentifier.Single> members, File avatarFile
|
||||
) throws IOException, AttachmentInvalidException {
|
||||
return groupHelper.createGroup(name, members == null ? null : getRecipientIds(members), avatarFile);
|
||||
return groupHelper.createGroup(name, members == null ? null : resolveRecipients(members), avatarFile);
|
||||
}
|
||||
|
||||
public SendGroupMessageResults updateGroup(
|
||||
|
@ -523,10 +523,10 @@ public class Manager implements Closeable {
|
|||
return groupHelper.updateGroup(groupId,
|
||||
name,
|
||||
description,
|
||||
members == null ? null : getRecipientIds(members),
|
||||
removeMembers == null ? null : getRecipientIds(removeMembers),
|
||||
admins == null ? null : getRecipientIds(admins),
|
||||
removeAdmins == null ? null : getRecipientIds(removeAdmins),
|
||||
members == null ? null : resolveRecipients(members),
|
||||
removeMembers == null ? null : resolveRecipients(removeMembers),
|
||||
admins == null ? null : resolveRecipients(admins),
|
||||
removeAdmins == null ? null : resolveRecipients(removeAdmins),
|
||||
resetGroupLink,
|
||||
groupLinkState,
|
||||
addMemberPermission,
|
||||
|
@ -662,7 +662,7 @@ public class Manager implements Closeable {
|
|||
|
||||
public void setContactName(
|
||||
RecipientIdentifier.Single recipient, String name
|
||||
) throws NotMasterDeviceException {
|
||||
) throws NotMasterDeviceException, UnregisteredUserException {
|
||||
if (!account.isMasterDevice()) {
|
||||
throw new NotMasterDeviceException();
|
||||
}
|
||||
|
@ -755,53 +755,28 @@ public class Manager implements Closeable {
|
|||
return certificate;
|
||||
}
|
||||
|
||||
private Set<RecipientId> getRecipientIds(Collection<RecipientIdentifier.Single> recipients) {
|
||||
final var signalServiceAddresses = new HashSet<SignalServiceAddress>(recipients.size());
|
||||
final var addressesMissingUuid = new HashSet<SignalServiceAddress>();
|
||||
|
||||
for (var number : recipients) {
|
||||
final var resolvedAddress = resolveSignalServiceAddress(resolveRecipient(number));
|
||||
if (resolvedAddress.getUuid().isPresent()) {
|
||||
signalServiceAddresses.add(resolvedAddress);
|
||||
} else {
|
||||
addressesMissingUuid.add(resolvedAddress);
|
||||
}
|
||||
}
|
||||
|
||||
final var numbersMissingUuid = addressesMissingUuid.stream()
|
||||
.map(a -> a.getNumber().get())
|
||||
.collect(Collectors.toSet());
|
||||
Map<String, UUID> registeredUsers;
|
||||
try {
|
||||
registeredUsers = getRegisteredUsers(numbersMissingUuid);
|
||||
} catch (IOException e) {
|
||||
logger.warn("Failed to resolve uuids from server, ignoring: {}", e.getMessage());
|
||||
registeredUsers = Map.of();
|
||||
}
|
||||
|
||||
for (var address : addressesMissingUuid) {
|
||||
final var number = address.getNumber().get();
|
||||
if (registeredUsers.containsKey(number)) {
|
||||
final var newAddress = resolveSignalServiceAddress(resolveRecipientTrusted(new SignalServiceAddress(
|
||||
registeredUsers.get(number),
|
||||
number)));
|
||||
signalServiceAddresses.add(newAddress);
|
||||
} else {
|
||||
signalServiceAddresses.add(address);
|
||||
}
|
||||
}
|
||||
|
||||
return signalServiceAddresses.stream().map(this::resolveRecipient).collect(Collectors.toSet());
|
||||
}
|
||||
|
||||
private RecipientId refreshRegisteredUser(RecipientId recipientId) throws IOException {
|
||||
final var address = resolveSignalServiceAddress(recipientId);
|
||||
if (!address.getNumber().isPresent()) {
|
||||
return recipientId;
|
||||
}
|
||||
final var number = address.getNumber().get();
|
||||
final var uuidMap = getRegisteredUsers(Set.of(number));
|
||||
return resolveRecipientTrusted(new SignalServiceAddress(uuidMap.getOrDefault(number, null), number));
|
||||
final var uuid = getRegisteredUser(number);
|
||||
return resolveRecipientTrusted(new SignalServiceAddress(uuid, number));
|
||||
}
|
||||
|
||||
private UUID getRegisteredUser(final String number) throws IOException {
|
||||
final Map<String, UUID> uuidMap;
|
||||
try {
|
||||
uuidMap = getRegisteredUsers(Set.of(number));
|
||||
} catch (NumberFormatException e) {
|
||||
throw new UnregisteredUserException(number, e);
|
||||
}
|
||||
final var uuid = uuidMap.get(number);
|
||||
if (uuid == null) {
|
||||
throw new UnregisteredUserException(number, null);
|
||||
}
|
||||
return uuid;
|
||||
}
|
||||
|
||||
private Map<String, UUID> getRegisteredUsers(final Set<String> numbers) throws IOException {
|
||||
|
@ -856,9 +831,9 @@ public class Manager implements Closeable {
|
|||
cachedMessage.delete();
|
||||
return null;
|
||||
}
|
||||
if (!envelope.hasSource()) {
|
||||
if (!envelope.hasSourceUuid()) {
|
||||
final var identifier = e.getSender();
|
||||
final var recipientId = resolveRecipient(identifier);
|
||||
final var recipientId = account.getRecipientStore().resolveRecipient(identifier);
|
||||
try {
|
||||
account.getMessageCache().replaceSender(cachedMessage, recipientId);
|
||||
} catch (IOException ioException) {
|
||||
|
@ -901,8 +876,8 @@ public class Manager implements Closeable {
|
|||
logger.debug("Checking for new message from server");
|
||||
try {
|
||||
var result = signalWebSocket.readOrEmpty(unit.toMillis(timeout), envelope1 -> {
|
||||
final var recipientId = envelope1.hasSource()
|
||||
? resolveRecipient(envelope1.getSourceIdentifier())
|
||||
final var recipientId = envelope1.hasSourceUuid()
|
||||
? resolveRecipient(envelope1.getSourceAddress())
|
||||
: null;
|
||||
// store message on disk, before acknowledging receipt to the server
|
||||
cachedMessage[0] = account.getMessageCache().cacheMessage(envelope1, recipientId);
|
||||
|
@ -944,10 +919,10 @@ public class Manager implements Closeable {
|
|||
handleQueuedActions(queuedActions);
|
||||
}
|
||||
if (cachedMessage[0] != null) {
|
||||
if (exception instanceof ProtocolUntrustedIdentityException) {
|
||||
final var identifier = ((ProtocolUntrustedIdentityException) exception).getSender();
|
||||
final var recipientId = resolveRecipient(identifier);
|
||||
if (!envelope.hasSource()) {
|
||||
if (exception instanceof UntrustedIdentityException) {
|
||||
final var address = ((UntrustedIdentityException) exception).getSender();
|
||||
final var recipientId = resolveRecipient(address);
|
||||
if (!envelope.hasSourceUuid()) {
|
||||
try {
|
||||
cachedMessage[0] = account.getMessageCache().replaceSender(cachedMessage[0], recipientId);
|
||||
} catch (IOException ioException) {
|
||||
|
@ -977,7 +952,12 @@ public class Manager implements Closeable {
|
|||
}
|
||||
|
||||
public boolean isContactBlocked(final RecipientIdentifier.Single recipient) {
|
||||
final var recipientId = resolveRecipient(recipient);
|
||||
final RecipientId recipientId;
|
||||
try {
|
||||
recipientId = resolveRecipient(recipient);
|
||||
} catch (UnregisteredUserException e) {
|
||||
return false;
|
||||
}
|
||||
return contactHelper.isContactBlocked(recipientId);
|
||||
}
|
||||
|
||||
|
@ -994,7 +974,12 @@ public class Manager implements Closeable {
|
|||
}
|
||||
|
||||
public String getContactOrProfileName(RecipientIdentifier.Single recipientIdentifier) {
|
||||
final var recipientId = resolveRecipient(recipientIdentifier);
|
||||
final RecipientId recipientId;
|
||||
try {
|
||||
recipientId = resolveRecipient(recipientIdentifier);
|
||||
} catch (UnregisteredUserException e) {
|
||||
return null;
|
||||
}
|
||||
|
||||
final var contact = account.getContactStore().getContact(recipientId);
|
||||
if (contact != null && !Util.isEmpty(contact.getName())) {
|
||||
|
@ -1018,7 +1003,12 @@ public class Manager implements Closeable {
|
|||
}
|
||||
|
||||
public List<IdentityInfo> getIdentities(RecipientIdentifier.Single recipient) {
|
||||
final var identity = account.getIdentityKeyStore().getIdentity(resolveRecipient(recipient));
|
||||
IdentityInfo identity;
|
||||
try {
|
||||
identity = account.getIdentityKeyStore().getIdentity(resolveRecipient(recipient));
|
||||
} catch (UnregisteredUserException e) {
|
||||
identity = null;
|
||||
}
|
||||
return identity == null ? List.of() : List.of(identity);
|
||||
}
|
||||
|
||||
|
@ -1029,7 +1019,12 @@ public class Manager implements Closeable {
|
|||
* @param fingerprint Fingerprint
|
||||
*/
|
||||
public boolean trustIdentityVerified(RecipientIdentifier.Single recipient, byte[] fingerprint) {
|
||||
var recipientId = resolveRecipient(recipient);
|
||||
RecipientId recipientId;
|
||||
try {
|
||||
recipientId = resolveRecipient(recipient);
|
||||
} catch (UnregisteredUserException e) {
|
||||
return false;
|
||||
}
|
||||
return trustIdentity(recipientId,
|
||||
identityKey -> Arrays.equals(identityKey.serialize(), fingerprint),
|
||||
TrustLevel.TRUSTED_VERIFIED);
|
||||
|
@ -1042,8 +1037,13 @@ public class Manager implements Closeable {
|
|||
* @param safetyNumber Safety number
|
||||
*/
|
||||
public boolean trustIdentityVerifiedSafetyNumber(RecipientIdentifier.Single recipient, String safetyNumber) {
|
||||
var recipientId = resolveRecipient(recipient);
|
||||
var address = account.getRecipientStore().resolveServiceAddress(recipientId);
|
||||
RecipientId recipientId;
|
||||
try {
|
||||
recipientId = resolveRecipient(recipient);
|
||||
} catch (UnregisteredUserException e) {
|
||||
return false;
|
||||
}
|
||||
var address = resolveSignalServiceAddress(recipientId);
|
||||
return trustIdentity(recipientId,
|
||||
identityKey -> safetyNumber.equals(computeSafetyNumber(address, identityKey)),
|
||||
TrustLevel.TRUSTED_VERIFIED);
|
||||
|
@ -1056,8 +1056,13 @@ public class Manager implements Closeable {
|
|||
* @param safetyNumber Scannable safety number
|
||||
*/
|
||||
public boolean trustIdentityVerifiedSafetyNumber(RecipientIdentifier.Single recipient, byte[] safetyNumber) {
|
||||
var recipientId = resolveRecipient(recipient);
|
||||
var address = account.getRecipientStore().resolveServiceAddress(recipientId);
|
||||
RecipientId recipientId;
|
||||
try {
|
||||
recipientId = resolveRecipient(recipient);
|
||||
} catch (UnregisteredUserException e) {
|
||||
return false;
|
||||
}
|
||||
var address = resolveSignalServiceAddress(recipientId);
|
||||
return trustIdentity(recipientId, identityKey -> {
|
||||
final var fingerprint = computeSafetyNumberFingerprint(address, identityKey);
|
||||
try {
|
||||
|
@ -1074,7 +1079,12 @@ public class Manager implements Closeable {
|
|||
* @param recipient username of the identity
|
||||
*/
|
||||
public boolean trustIdentityAllKeys(RecipientIdentifier.Single recipient) {
|
||||
var recipientId = resolveRecipient(recipient);
|
||||
RecipientId recipientId;
|
||||
try {
|
||||
recipientId = resolveRecipient(recipient);
|
||||
} catch (UnregisteredUserException e) {
|
||||
return false;
|
||||
}
|
||||
return trustIdentity(recipientId, identityKey -> true, TrustLevel.TRUSTED_UNVERIFIED);
|
||||
}
|
||||
|
||||
|
@ -1092,7 +1102,7 @@ public class Manager implements Closeable {
|
|||
|
||||
account.getIdentityKeyStore().setIdentityTrustLevel(recipientId, identity.getIdentityKey(), trustLevel);
|
||||
try {
|
||||
var address = account.getRecipientStore().resolveServiceAddress(recipientId);
|
||||
var address = resolveSignalServiceAddress(recipientId);
|
||||
syncHelper.sendVerifiedMessage(address, identity.getIdentityKey(), trustLevel);
|
||||
} catch (IOException e) {
|
||||
logger.warn("Failed to send verification sync message: {}", e.getMessage());
|
||||
|
@ -1136,48 +1146,61 @@ public class Manager implements Closeable {
|
|||
theirIdentityKey);
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public SignalServiceAddress resolveSignalServiceAddress(String identifier) {
|
||||
var address = Utils.getSignalServiceAddressFromIdentifier(identifier);
|
||||
|
||||
return resolveSignalServiceAddress(address);
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public SignalServiceAddress resolveSignalServiceAddress(SignalServiceAddress address) {
|
||||
if (address.matches(account.getSelfAddress())) {
|
||||
return account.getSelfAddress();
|
||||
}
|
||||
|
||||
return account.getRecipientStore().resolveServiceAddress(address);
|
||||
return resolveSignalServiceAddress(resolveRecipient(address));
|
||||
}
|
||||
|
||||
public SignalServiceAddress resolveSignalServiceAddress(UUID uuid) {
|
||||
return resolveSignalServiceAddress(account.getRecipientStore().resolveRecipient(uuid));
|
||||
}
|
||||
|
||||
public SignalServiceAddress resolveSignalServiceAddress(RecipientId recipientId) {
|
||||
return account.getRecipientStore().resolveServiceAddress(recipientId);
|
||||
}
|
||||
|
||||
private String canonicalizePhoneNumber(final String number) throws InvalidNumberException {
|
||||
return PhoneNumberFormatter.formatNumber(number, account.getUsername());
|
||||
}
|
||||
|
||||
private RecipientId resolveRecipient(final String identifier) {
|
||||
var address = Utils.getSignalServiceAddressFromIdentifier(identifier);
|
||||
|
||||
return resolveRecipient(address);
|
||||
}
|
||||
|
||||
private RecipientId resolveRecipient(final RecipientIdentifier.Single recipient) {
|
||||
final SignalServiceAddress address;
|
||||
if (recipient instanceof RecipientIdentifier.Uuid) {
|
||||
address = new SignalServiceAddress(((RecipientIdentifier.Uuid) recipient).uuid, null);
|
||||
} else {
|
||||
address = new SignalServiceAddress(null, ((RecipientIdentifier.Number) recipient).number);
|
||||
final var address = account.getRecipientStore().resolveRecipientAddress(recipientId);
|
||||
if (address.getUuid().isPresent()) {
|
||||
return address.toSignalServiceAddress();
|
||||
}
|
||||
|
||||
return resolveRecipient(address);
|
||||
// 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();
|
||||
try {
|
||||
return resolveSignalServiceAddress(getRegisteredUser(number));
|
||||
} catch (IOException e) {
|
||||
logger.warn("Failed to get uuid for e164 number: {}", number, e);
|
||||
// Return SignalServiceAddress with unknown UUID
|
||||
return address.toSignalServiceAddress();
|
||||
}
|
||||
}
|
||||
|
||||
public RecipientId resolveRecipient(SignalServiceAddress address) {
|
||||
private Set<RecipientId> resolveRecipients(Collection<RecipientIdentifier.Single> recipients) throws UnregisteredUserException {
|
||||
final var recipientIds = new HashSet<RecipientId>(recipients.size());
|
||||
for (var number : recipients) {
|
||||
final var recipientId = resolveRecipient(number);
|
||||
recipientIds.add(recipientId);
|
||||
}
|
||||
return recipientIds;
|
||||
}
|
||||
|
||||
private RecipientId resolveRecipient(final RecipientIdentifier.Single recipient) throws UnregisteredUserException {
|
||||
if (recipient instanceof RecipientIdentifier.Uuid) {
|
||||
return account.getRecipientStore().resolveRecipient(((RecipientIdentifier.Uuid) recipient).uuid);
|
||||
} else {
|
||||
final var number = ((RecipientIdentifier.Number) recipient).number;
|
||||
return account.getRecipientStore().resolveRecipient(number, () -> {
|
||||
try {
|
||||
return getRegisteredUser(number);
|
||||
} catch (IOException e) {
|
||||
return null;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private RecipientId resolveRecipient(SignalServiceAddress address) {
|
||||
return account.getRecipientStore().resolveRecipient(address);
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,27 @@
|
|||
package org.asamk.signal.manager;
|
||||
|
||||
import org.whispersystems.signalservice.api.push.SignalServiceAddress;
|
||||
|
||||
public class UntrustedIdentityException extends Exception {
|
||||
|
||||
private final SignalServiceAddress sender;
|
||||
private final Integer senderDevice;
|
||||
|
||||
public UntrustedIdentityException(final SignalServiceAddress sender) {
|
||||
this(sender, null);
|
||||
}
|
||||
|
||||
public UntrustedIdentityException(final SignalServiceAddress sender, final Integer senderDevice) {
|
||||
super("Untrusted identity: " + sender.getIdentifier());
|
||||
this.sender = sender;
|
||||
this.senderDevice = senderDevice;
|
||||
}
|
||||
|
||||
public SignalServiceAddress getSender() {
|
||||
return sender;
|
||||
}
|
||||
|
||||
public Integer getSenderDevice() {
|
||||
return senderDevice;
|
||||
}
|
||||
}
|
|
@ -32,9 +32,7 @@ public abstract class RecipientIdentifier {
|
|||
}
|
||||
|
||||
public static Single fromAddress(SignalServiceAddress address) {
|
||||
return address.getUuid().isPresent()
|
||||
? new Uuid(address.getUuid().get())
|
||||
: new Number(address.getNumber().get());
|
||||
return new Uuid(address.getUuid());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -150,11 +150,9 @@ public class GroupV2Helper {
|
|||
|
||||
if (!areMembersValid(members)) return null;
|
||||
|
||||
var self = new GroupCandidate(addressResolver.resolveSignalServiceAddress(selfRecipientIdProvider.getSelfRecipientId())
|
||||
.getUuid()
|
||||
.orNull(), Optional.fromNullable(profileKeyCredential));
|
||||
var self = new GroupCandidate(getSelfUuid(), Optional.fromNullable(profileKeyCredential));
|
||||
var candidates = members.stream()
|
||||
.map(member -> new GroupCandidate(addressResolver.resolveSignalServiceAddress(member).getUuid().get(),
|
||||
.map(member -> new GroupCandidate(addressResolver.resolveSignalServiceAddress(member).getUuid(),
|
||||
Optional.fromNullable(profileKeyCredentialProvider.getProfileKeyCredential(member))))
|
||||
.collect(Collectors.toSet());
|
||||
|
||||
|
@ -169,18 +167,6 @@ public class GroupV2Helper {
|
|||
}
|
||||
|
||||
private boolean areMembersValid(final Set<RecipientId> members) {
|
||||
final var noUuidCapability = members.stream()
|
||||
.map(addressResolver::resolveSignalServiceAddress)
|
||||
.filter(address -> !address.getUuid().isPresent())
|
||||
.map(SignalServiceAddress::getNumber)
|
||||
.map(Optional::get)
|
||||
.collect(Collectors.toSet());
|
||||
if (noUuidCapability.size() > 0) {
|
||||
logger.warn("Cannot create a V2 group as some members don't have a UUID: {}",
|
||||
String.join(", ", noUuidCapability));
|
||||
return false;
|
||||
}
|
||||
|
||||
final var noGv2Capability = members.stream()
|
||||
.map(profileProvider::getProfile)
|
||||
.filter(profile -> profile != null && !profile.getCapabilities().contains(Profile.Capability.gv2))
|
||||
|
@ -214,11 +200,8 @@ public class GroupV2Helper {
|
|||
change.setModifyAvatar(GroupChange.Actions.ModifyAvatarAction.newBuilder().setAvatar(avatarCdnKey));
|
||||
}
|
||||
|
||||
final var uuid = addressResolver.resolveSignalServiceAddress(this.selfRecipientIdProvider.getSelfRecipientId())
|
||||
.getUuid();
|
||||
if (uuid.isPresent()) {
|
||||
change.setSourceUuid(UuidUtil.toByteString(uuid.get()));
|
||||
}
|
||||
final var uuid = getSelfUuid();
|
||||
change.setSourceUuid(UuidUtil.toByteString(uuid));
|
||||
|
||||
return commitChange(groupInfoV2, change);
|
||||
}
|
||||
|
@ -233,13 +216,11 @@ public class GroupV2Helper {
|
|||
}
|
||||
|
||||
var candidates = newMembers.stream()
|
||||
.map(member -> new GroupCandidate(addressResolver.resolveSignalServiceAddress(member).getUuid().get(),
|
||||
.map(member -> new GroupCandidate(addressResolver.resolveSignalServiceAddress(member).getUuid(),
|
||||
Optional.fromNullable(profileKeyCredentialProvider.getProfileKeyCredential(member))))
|
||||
.collect(Collectors.toSet());
|
||||
|
||||
final var uuid = addressResolver.resolveSignalServiceAddress(selfRecipientIdProvider.getSelfRecipientId())
|
||||
.getUuid()
|
||||
.get();
|
||||
final var uuid = getSelfUuid();
|
||||
final var change = groupOperations.createModifyGroupMembershipChange(candidates, uuid);
|
||||
|
||||
change.setSourceUuid(UuidUtil.toByteString(uuid));
|
||||
|
@ -251,9 +232,7 @@ public class GroupV2Helper {
|
|||
GroupInfoV2 groupInfoV2, Set<RecipientId> membersToMakeAdmin
|
||||
) throws IOException {
|
||||
var pendingMembersList = groupInfoV2.getGroup().getPendingMembersList();
|
||||
final var selfUuid = addressResolver.resolveSignalServiceAddress(selfRecipientIdProvider.getSelfRecipientId())
|
||||
.getUuid()
|
||||
.get();
|
||||
final var selfUuid = getSelfUuid();
|
||||
var selfPendingMember = DecryptedGroupUtil.findPendingByUuid(pendingMembersList, selfUuid);
|
||||
|
||||
if (selfPendingMember.isPresent()) {
|
||||
|
@ -263,7 +242,6 @@ public class GroupV2Helper {
|
|||
final var adminUuids = membersToMakeAdmin.stream()
|
||||
.map(addressResolver::resolveSignalServiceAddress)
|
||||
.map(SignalServiceAddress::getUuid)
|
||||
.map(Optional::get)
|
||||
.collect(Collectors.toList());
|
||||
final GroupsV2Operations.GroupOperations groupOperations = getGroupOperations(groupInfoV2);
|
||||
return commitChange(groupInfoV2, groupOperations.createLeaveAndPromoteMembersToAdmin(selfUuid, adminUuids));
|
||||
|
@ -275,8 +253,6 @@ public class GroupV2Helper {
|
|||
final var memberUuids = members.stream()
|
||||
.map(addressResolver::resolveSignalServiceAddress)
|
||||
.map(SignalServiceAddress::getUuid)
|
||||
.filter(Optional::isPresent)
|
||||
.map(Optional::get)
|
||||
.collect(Collectors.toSet());
|
||||
return ejectMembers(groupInfoV2, memberUuids);
|
||||
}
|
||||
|
@ -288,8 +264,6 @@ public class GroupV2Helper {
|
|||
final var memberUuids = members.stream()
|
||||
.map(addressResolver::resolveSignalServiceAddress)
|
||||
.map(SignalServiceAddress::getUuid)
|
||||
.filter(Optional::isPresent)
|
||||
.map(Optional::get)
|
||||
.map(uuid -> DecryptedGroupUtil.findPendingByUuid(pendingMembersList, uuid))
|
||||
.filter(Optional::isPresent)
|
||||
.map(Optional::get)
|
||||
|
@ -360,8 +334,7 @@ public class GroupV2Helper {
|
|||
: groupOperations.createGroupJoinDirect(profileKeyCredential);
|
||||
|
||||
change.setSourceUuid(UuidUtil.toByteString(addressResolver.resolveSignalServiceAddress(selfRecipientId)
|
||||
.getUuid()
|
||||
.get()));
|
||||
.getUuid()));
|
||||
|
||||
return commitChange(groupSecretParams, decryptedGroupJoinInfo.getRevision(), change, groupLinkPassword);
|
||||
}
|
||||
|
@ -378,9 +351,7 @@ public class GroupV2Helper {
|
|||
final var change = groupOperations.createAcceptInviteChange(profileKeyCredential);
|
||||
|
||||
final var uuid = addressResolver.resolveSignalServiceAddress(selfRecipientId).getUuid();
|
||||
if (uuid.isPresent()) {
|
||||
change.setSourceUuid(UuidUtil.toByteString(uuid.get()));
|
||||
}
|
||||
change.setSourceUuid(UuidUtil.toByteString(uuid));
|
||||
|
||||
return commitChange(groupInfoV2, change);
|
||||
}
|
||||
|
@ -391,7 +362,7 @@ public class GroupV2Helper {
|
|||
final GroupsV2Operations.GroupOperations groupOperations = getGroupOperations(groupInfoV2);
|
||||
final var address = addressResolver.resolveSignalServiceAddress(recipientId);
|
||||
final var newRole = admin ? Member.Role.ADMINISTRATOR : Member.Role.DEFAULT;
|
||||
final var change = groupOperations.createChangeMemberRole(address.getUuid().get(), newRole);
|
||||
final var change = groupOperations.createChangeMemberRole(address.getUuid(), newRole);
|
||||
return commitChange(groupInfoV2, change);
|
||||
}
|
||||
|
||||
|
@ -473,10 +444,7 @@ public class GroupV2Helper {
|
|||
final DecryptedGroup decryptedGroupState;
|
||||
|
||||
try {
|
||||
decryptedChange = groupOperations.decryptChange(changeActions,
|
||||
addressResolver.resolveSignalServiceAddress(selfRecipientIdProvider.getSelfRecipientId())
|
||||
.getUuid()
|
||||
.get());
|
||||
decryptedChange = groupOperations.decryptChange(changeActions, getSelfUuid());
|
||||
decryptedGroupState = DecryptedGroupUtil.apply(previousGroupState, decryptedChange);
|
||||
} catch (VerificationFailedException | InvalidGroupStateException | NotAbleToApplyGroupV2ChangeException e) {
|
||||
throw new IOException(e);
|
||||
|
@ -543,13 +511,15 @@ public class GroupV2Helper {
|
|||
final var credentials = groupsV2Api.getCredentials(today);
|
||||
// TODO cache credentials until they expire
|
||||
var authCredentialResponse = credentials.get(today);
|
||||
final var uuid = addressResolver.resolveSignalServiceAddress(this.selfRecipientIdProvider.getSelfRecipientId())
|
||||
.getUuid()
|
||||
.get();
|
||||
final var uuid = getSelfUuid();
|
||||
try {
|
||||
return groupsV2Api.getGroupsV2AuthorizationString(uuid, today, groupSecretParams, authCredentialResponse);
|
||||
} catch (VerificationFailedException e) {
|
||||
throw new IOException(e);
|
||||
}
|
||||
}
|
||||
|
||||
private UUID getSelfUuid() {
|
||||
return addressResolver.resolveSignalServiceAddress(this.selfRecipientIdProvider.getSelfRecipientId()).getUuid();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,6 +4,7 @@ import org.asamk.signal.manager.JobExecutor;
|
|||
import org.asamk.signal.manager.Manager;
|
||||
import org.asamk.signal.manager.SignalDependencies;
|
||||
import org.asamk.signal.manager.TrustLevel;
|
||||
import org.asamk.signal.manager.UntrustedIdentityException;
|
||||
import org.asamk.signal.manager.actions.HandleAction;
|
||||
import org.asamk.signal.manager.actions.RenewSessionAction;
|
||||
import org.asamk.signal.manager.actions.RetrieveProfileAction;
|
||||
|
@ -34,6 +35,7 @@ import org.whispersystems.signalservice.api.messages.SignalServiceContent;
|
|||
import org.whispersystems.signalservice.api.messages.SignalServiceDataMessage;
|
||||
import org.whispersystems.signalservice.api.messages.SignalServiceEnvelope;
|
||||
import org.whispersystems.signalservice.api.messages.SignalServiceGroup;
|
||||
import org.whispersystems.signalservice.api.messages.multidevice.SignalServiceSyncMessage;
|
||||
import org.whispersystems.signalservice.api.messages.multidevice.StickerPackOperationMessage;
|
||||
import org.whispersystems.signalservice.api.push.SignalServiceAddress;
|
||||
|
||||
|
@ -48,6 +50,7 @@ public final class IncomingMessageHandler {
|
|||
private final SignalAccount account;
|
||||
private final SignalDependencies dependencies;
|
||||
private final RecipientResolver recipientResolver;
|
||||
private final SignalServiceAddressResolver addressResolver;
|
||||
private final GroupHelper groupHelper;
|
||||
private final ContactHelper contactHelper;
|
||||
private final AttachmentHelper attachmentHelper;
|
||||
|
@ -58,6 +61,7 @@ public final class IncomingMessageHandler {
|
|||
final SignalAccount account,
|
||||
final SignalDependencies dependencies,
|
||||
final RecipientResolver recipientResolver,
|
||||
final SignalServiceAddressResolver addressResolver,
|
||||
final GroupHelper groupHelper,
|
||||
final ContactHelper contactHelper,
|
||||
final AttachmentHelper attachmentHelper,
|
||||
|
@ -67,6 +71,7 @@ public final class IncomingMessageHandler {
|
|||
this.account = account;
|
||||
this.dependencies = dependencies;
|
||||
this.recipientResolver = recipientResolver;
|
||||
this.addressResolver = addressResolver;
|
||||
this.groupHelper = groupHelper;
|
||||
this.contactHelper = contactHelper;
|
||||
this.attachmentHelper = attachmentHelper;
|
||||
|
@ -80,7 +85,7 @@ public final class IncomingMessageHandler {
|
|||
final Manager.ReceiveMessageHandler handler
|
||||
) {
|
||||
final var actions = new ArrayList<HandleAction>();
|
||||
if (envelope.hasSource()) {
|
||||
if (envelope.hasSourceUuid()) {
|
||||
// Store uuid if we don't have it already
|
||||
// address/uuid in envelope is sent by server
|
||||
account.getRecipientStore().resolveRecipientTrusted(envelope.getSourceAddress());
|
||||
|
@ -93,6 +98,8 @@ public final class IncomingMessageHandler {
|
|||
} catch (ProtocolUntrustedIdentityException e) {
|
||||
final var recipientId = account.getRecipientStore().resolveRecipient(e.getSender());
|
||||
actions.add(new RetrieveProfileAction(recipientId));
|
||||
exception = new UntrustedIdentityException(addressResolver.resolveSignalServiceAddress(recipientId),
|
||||
e.getSenderDevice());
|
||||
} catch (ProtocolInvalidMessageException e) {
|
||||
final var sender = account.getRecipientStore().resolveRecipient(e.getSender());
|
||||
logger.debug("Received invalid message, queuing renew session action.");
|
||||
|
@ -102,7 +109,7 @@ public final class IncomingMessageHandler {
|
|||
exception = e;
|
||||
}
|
||||
|
||||
if (!envelope.hasSource() && content != null) {
|
||||
if (!envelope.hasSourceUuid() && content != null) {
|
||||
// Store uuid if we don't have it already
|
||||
// address/uuid is validated by unidentified sender certificate
|
||||
account.getRecipientStore().resolveRecipientTrusted(content.getSender());
|
||||
|
@ -113,7 +120,7 @@ public final class IncomingMessageHandler {
|
|||
logger.info("Ignoring a message from blocked user/group: {}", envelope.getTimestamp());
|
||||
} else if (isNotAllowedToSendToGroup(envelope, content)) {
|
||||
logger.info("Ignoring a group message from an unauthorized sender (no member or admin): {} {}",
|
||||
(envelope.hasSource() ? envelope.getSourceAddress() : content.getSender()).getIdentifier(),
|
||||
(envelope.hasSourceUuid() ? envelope.getSourceAddress() : content.getSender()).getIdentifier(),
|
||||
envelope.getTimestamp());
|
||||
} else {
|
||||
actions.addAll(handleMessage(envelope, content, ignoreAttachments));
|
||||
|
@ -126,146 +133,153 @@ public final class IncomingMessageHandler {
|
|||
SignalServiceEnvelope envelope, SignalServiceContent content, boolean ignoreAttachments
|
||||
) {
|
||||
var actions = new ArrayList<HandleAction>();
|
||||
if (content != null) {
|
||||
final RecipientId sender;
|
||||
if (!envelope.isUnidentifiedSender() && envelope.hasSource()) {
|
||||
sender = recipientResolver.resolveRecipient(envelope.getSourceAddress());
|
||||
} else {
|
||||
sender = recipientResolver.resolveRecipient(content.getSender());
|
||||
if (content == null) {
|
||||
return actions;
|
||||
}
|
||||
|
||||
final RecipientId sender;
|
||||
if (!envelope.isUnidentifiedSender() && envelope.hasSourceUuid()) {
|
||||
sender = recipientResolver.resolveRecipient(envelope.getSourceAddress());
|
||||
} else {
|
||||
sender = recipientResolver.resolveRecipient(content.getSender());
|
||||
}
|
||||
|
||||
if (content.getDataMessage().isPresent()) {
|
||||
var message = content.getDataMessage().get();
|
||||
|
||||
if (content.isNeedsReceipt()) {
|
||||
actions.add(new SendReceiptAction(sender, message.getTimestamp()));
|
||||
}
|
||||
|
||||
if (content.getDataMessage().isPresent()) {
|
||||
var message = content.getDataMessage().get();
|
||||
actions.addAll(handleSignalServiceDataMessage(message,
|
||||
false,
|
||||
sender,
|
||||
account.getSelfRecipientId(),
|
||||
ignoreAttachments));
|
||||
}
|
||||
|
||||
if (content.isNeedsReceipt()) {
|
||||
actions.add(new SendReceiptAction(sender, message.getTimestamp()));
|
||||
}
|
||||
if (content.getSyncMessage().isPresent()) {
|
||||
var syncMessage = content.getSyncMessage().get();
|
||||
actions.addAll(handleSyncMessage(syncMessage, sender, ignoreAttachments));
|
||||
}
|
||||
|
||||
actions.addAll(handleSignalServiceDataMessage(message,
|
||||
false,
|
||||
sender,
|
||||
account.getSelfRecipientId(),
|
||||
ignoreAttachments));
|
||||
return actions;
|
||||
}
|
||||
|
||||
private List<HandleAction> handleSyncMessage(
|
||||
final SignalServiceSyncMessage syncMessage, final RecipientId sender, final boolean ignoreAttachments
|
||||
) {
|
||||
var actions = new ArrayList<HandleAction>();
|
||||
account.setMultiDevice(true);
|
||||
if (syncMessage.getSent().isPresent()) {
|
||||
var message = syncMessage.getSent().get();
|
||||
final var destination = message.getDestination().orNull();
|
||||
actions.addAll(handleSignalServiceDataMessage(message.getMessage(),
|
||||
true,
|
||||
sender,
|
||||
destination == null ? null : recipientResolver.resolveRecipient(destination),
|
||||
ignoreAttachments));
|
||||
}
|
||||
if (syncMessage.getRequest().isPresent() && account.isMasterDevice()) {
|
||||
var rm = syncMessage.getRequest().get();
|
||||
if (rm.isContactsRequest()) {
|
||||
actions.add(SendSyncContactsAction.create());
|
||||
}
|
||||
if (content.getSyncMessage().isPresent()) {
|
||||
account.setMultiDevice(true);
|
||||
var syncMessage = content.getSyncMessage().get();
|
||||
if (syncMessage.getSent().isPresent()) {
|
||||
var message = syncMessage.getSent().get();
|
||||
final var destination = message.getDestination().orNull();
|
||||
actions.addAll(handleSignalServiceDataMessage(message.getMessage(),
|
||||
true,
|
||||
sender,
|
||||
destination == null ? null : recipientResolver.resolveRecipient(destination),
|
||||
ignoreAttachments));
|
||||
if (rm.isGroupsRequest()) {
|
||||
actions.add(SendSyncGroupsAction.create());
|
||||
}
|
||||
if (rm.isBlockedListRequest()) {
|
||||
actions.add(SendSyncBlockedListAction.create());
|
||||
}
|
||||
// TODO Handle rm.isConfigurationRequest(); rm.isKeysRequest();
|
||||
}
|
||||
if (syncMessage.getGroups().isPresent()) {
|
||||
logger.warn("Received a group v1 sync message, that can't be handled anymore, ignoring.");
|
||||
}
|
||||
if (syncMessage.getBlockedList().isPresent()) {
|
||||
final var blockedListMessage = syncMessage.getBlockedList().get();
|
||||
for (var address : blockedListMessage.getAddresses()) {
|
||||
contactHelper.setContactBlocked(recipientResolver.resolveRecipient(address), true);
|
||||
}
|
||||
for (var groupId : blockedListMessage.getGroupIds()
|
||||
.stream()
|
||||
.map(GroupId::unknownVersion)
|
||||
.collect(Collectors.toSet())) {
|
||||
try {
|
||||
groupHelper.setGroupBlocked(groupId, true);
|
||||
} catch (GroupNotFoundException e) {
|
||||
logger.warn("BlockedListMessage contained groupID that was not found in GroupStore: {}",
|
||||
groupId.toBase64());
|
||||
}
|
||||
if (syncMessage.getRequest().isPresent() && account.isMasterDevice()) {
|
||||
var rm = syncMessage.getRequest().get();
|
||||
if (rm.isContactsRequest()) {
|
||||
actions.add(SendSyncContactsAction.create());
|
||||
}
|
||||
if (rm.isGroupsRequest()) {
|
||||
actions.add(SendSyncGroupsAction.create());
|
||||
}
|
||||
if (rm.isBlockedListRequest()) {
|
||||
actions.add(SendSyncBlockedListAction.create());
|
||||
}
|
||||
// TODO Handle rm.isConfigurationRequest(); rm.isKeysRequest();
|
||||
}
|
||||
}
|
||||
if (syncMessage.getContacts().isPresent()) {
|
||||
try {
|
||||
final var contactsMessage = syncMessage.getContacts().get();
|
||||
attachmentHelper.retrieveAttachment(contactsMessage.getContactsStream(),
|
||||
syncHelper::handleSyncDeviceContacts);
|
||||
} catch (Exception e) {
|
||||
logger.warn("Failed to handle received sync contacts, ignoring: {}", e.getMessage());
|
||||
}
|
||||
}
|
||||
if (syncMessage.getVerified().isPresent()) {
|
||||
final var verifiedMessage = syncMessage.getVerified().get();
|
||||
account.getIdentityKeyStore()
|
||||
.setIdentityTrustLevel(account.getRecipientStore()
|
||||
.resolveRecipientTrusted(verifiedMessage.getDestination()),
|
||||
verifiedMessage.getIdentityKey(),
|
||||
TrustLevel.fromVerifiedState(verifiedMessage.getVerified()));
|
||||
}
|
||||
if (syncMessage.getStickerPackOperations().isPresent()) {
|
||||
final var stickerPackOperationMessages = syncMessage.getStickerPackOperations().get();
|
||||
for (var m : stickerPackOperationMessages) {
|
||||
if (!m.getPackId().isPresent()) {
|
||||
continue;
|
||||
}
|
||||
if (syncMessage.getGroups().isPresent()) {
|
||||
try {
|
||||
final var groupsMessage = syncMessage.getGroups().get();
|
||||
attachmentHelper.retrieveAttachment(groupsMessage, syncHelper::handleSyncDeviceGroups);
|
||||
} catch (Exception e) {
|
||||
logger.warn("Failed to handle received sync groups, ignoring: {}", e.getMessage());
|
||||
}
|
||||
}
|
||||
if (syncMessage.getBlockedList().isPresent()) {
|
||||
final var blockedListMessage = syncMessage.getBlockedList().get();
|
||||
for (var address : blockedListMessage.getAddresses()) {
|
||||
contactHelper.setContactBlocked(recipientResolver.resolveRecipient(address), true);
|
||||
}
|
||||
for (var groupId : blockedListMessage.getGroupIds()
|
||||
.stream()
|
||||
.map(GroupId::unknownVersion)
|
||||
.collect(Collectors.toSet())) {
|
||||
try {
|
||||
groupHelper.setGroupBlocked(groupId, true);
|
||||
} catch (GroupNotFoundException e) {
|
||||
logger.warn("BlockedListMessage contained groupID that was not found in GroupStore: {}",
|
||||
groupId.toBase64());
|
||||
}
|
||||
}
|
||||
}
|
||||
if (syncMessage.getContacts().isPresent()) {
|
||||
try {
|
||||
final var contactsMessage = syncMessage.getContacts().get();
|
||||
attachmentHelper.retrieveAttachment(contactsMessage.getContactsStream(),
|
||||
syncHelper::handleSyncDeviceContacts);
|
||||
} catch (Exception e) {
|
||||
logger.warn("Failed to handle received sync contacts, ignoring: {}", e.getMessage());
|
||||
}
|
||||
}
|
||||
if (syncMessage.getVerified().isPresent()) {
|
||||
final var verifiedMessage = syncMessage.getVerified().get();
|
||||
account.getIdentityKeyStore()
|
||||
.setIdentityTrustLevel(account.getRecipientStore()
|
||||
.resolveRecipientTrusted(verifiedMessage.getDestination()),
|
||||
verifiedMessage.getIdentityKey(),
|
||||
TrustLevel.fromVerifiedState(verifiedMessage.getVerified()));
|
||||
}
|
||||
if (syncMessage.getStickerPackOperations().isPresent()) {
|
||||
final var stickerPackOperationMessages = syncMessage.getStickerPackOperations().get();
|
||||
for (var m : stickerPackOperationMessages) {
|
||||
if (!m.getPackId().isPresent()) {
|
||||
continue;
|
||||
}
|
||||
final var stickerPackId = StickerPackId.deserialize(m.getPackId().get());
|
||||
final var installed = !m.getType().isPresent()
|
||||
|| m.getType().get() == StickerPackOperationMessage.Type.INSTALL;
|
||||
final var stickerPackId = StickerPackId.deserialize(m.getPackId().get());
|
||||
final var installed = !m.getType().isPresent()
|
||||
|| m.getType().get() == StickerPackOperationMessage.Type.INSTALL;
|
||||
|
||||
var sticker = account.getStickerStore().getSticker(stickerPackId);
|
||||
if (m.getPackKey().isPresent()) {
|
||||
if (sticker == null) {
|
||||
sticker = new Sticker(stickerPackId, m.getPackKey().get());
|
||||
}
|
||||
if (installed) {
|
||||
jobExecutor.enqueueJob(new RetrieveStickerPackJob(stickerPackId, m.getPackKey().get()));
|
||||
}
|
||||
}
|
||||
var sticker = account.getStickerStore().getSticker(stickerPackId);
|
||||
if (m.getPackKey().isPresent()) {
|
||||
if (sticker == null) {
|
||||
sticker = new Sticker(stickerPackId, m.getPackKey().get());
|
||||
}
|
||||
if (installed) {
|
||||
jobExecutor.enqueueJob(new RetrieveStickerPackJob(stickerPackId, m.getPackKey().get()));
|
||||
}
|
||||
}
|
||||
|
||||
if (sticker != null) {
|
||||
sticker.setInstalled(installed);
|
||||
account.getStickerStore().updateSticker(sticker);
|
||||
}
|
||||
}
|
||||
if (sticker != null) {
|
||||
sticker.setInstalled(installed);
|
||||
account.getStickerStore().updateSticker(sticker);
|
||||
}
|
||||
if (syncMessage.getFetchType().isPresent()) {
|
||||
switch (syncMessage.getFetchType().get()) {
|
||||
case LOCAL_PROFILE:
|
||||
actions.add(new RetrieveProfileAction(account.getSelfRecipientId()));
|
||||
case STORAGE_MANIFEST:
|
||||
// TODO
|
||||
}
|
||||
}
|
||||
if (syncMessage.getKeys().isPresent()) {
|
||||
final var keysMessage = syncMessage.getKeys().get();
|
||||
if (keysMessage.getStorageService().isPresent()) {
|
||||
final var storageKey = keysMessage.getStorageService().get();
|
||||
account.setStorageKey(storageKey);
|
||||
}
|
||||
}
|
||||
if (syncMessage.getConfiguration().isPresent()) {
|
||||
}
|
||||
}
|
||||
if (syncMessage.getFetchType().isPresent()) {
|
||||
switch (syncMessage.getFetchType().get()) {
|
||||
case LOCAL_PROFILE:
|
||||
actions.add(new RetrieveProfileAction(account.getSelfRecipientId()));
|
||||
case STORAGE_MANIFEST:
|
||||
// TODO
|
||||
}
|
||||
}
|
||||
}
|
||||
if (syncMessage.getKeys().isPresent()) {
|
||||
final var keysMessage = syncMessage.getKeys().get();
|
||||
if (keysMessage.getStorageService().isPresent()) {
|
||||
final var storageKey = keysMessage.getStorageService().get();
|
||||
account.setStorageKey(storageKey);
|
||||
}
|
||||
}
|
||||
if (syncMessage.getConfiguration().isPresent()) {
|
||||
// TODO
|
||||
}
|
||||
return actions;
|
||||
}
|
||||
|
||||
private boolean isMessageBlocked(SignalServiceEnvelope envelope, SignalServiceContent content) {
|
||||
SignalServiceAddress source;
|
||||
if (!envelope.isUnidentifiedSender() && envelope.hasSource()) {
|
||||
if (!envelope.isUnidentifiedSender() && envelope.hasSourceUuid()) {
|
||||
source = envelope.getSourceAddress();
|
||||
} else if (content != null) {
|
||||
source = content.getSender();
|
||||
|
@ -290,7 +304,7 @@ public final class IncomingMessageHandler {
|
|||
|
||||
private boolean isNotAllowedToSendToGroup(SignalServiceEnvelope envelope, SignalServiceContent content) {
|
||||
SignalServiceAddress source;
|
||||
if (!envelope.isUnidentifiedSender() && envelope.hasSource()) {
|
||||
if (!envelope.isUnidentifiedSender() && envelope.hasSourceUuid()) {
|
||||
source = envelope.getSourceAddress();
|
||||
} else if (content != null) {
|
||||
source = content.getSender();
|
||||
|
|
|
@ -273,7 +273,7 @@ public final class ProfileHelper {
|
|||
|
||||
private Single<ProfileAndCredential> retrieveProfile(
|
||||
RecipientId recipientId, SignalServiceProfile.RequestType requestType
|
||||
) throws IOException {
|
||||
) {
|
||||
var unidentifiedAccess = getUnidentifiedAccess(recipientId);
|
||||
var profileKey = Optional.fromNullable(profileKeyProvider.getProfileKey(recipientId));
|
||||
|
||||
|
@ -286,7 +286,7 @@ public final class ProfileHelper {
|
|||
Optional<ProfileKey> profileKey,
|
||||
Optional<UnidentifiedAccess> unidentifiedAccess,
|
||||
SignalServiceProfile.RequestType requestType
|
||||
) throws IOException {
|
||||
) {
|
||||
var profileService = profileServiceProvider.getProfileService();
|
||||
|
||||
Single<ServiceResponse<ProfileAndCredential>> responseSingle;
|
||||
|
@ -294,11 +294,7 @@ public final class ProfileHelper {
|
|||
responseSingle = profileService.getProfile(address, profileKey, unidentifiedAccess, requestType);
|
||||
} catch (NoClassDefFoundError e) {
|
||||
// Native zkgroup lib not available for ProfileKey
|
||||
if (!address.getNumber().isPresent()) {
|
||||
throw new NotFoundException("Can't request profile without number");
|
||||
}
|
||||
var addressWithoutUuid = new SignalServiceAddress(Optional.absent(), address.getNumber());
|
||||
responseSingle = profileService.getProfile(addressWithoutUuid, profileKey, unidentifiedAccess, requestType);
|
||||
responseSingle = profileService.getProfile(address, Optional.absent(), unidentifiedAccess, requestType);
|
||||
}
|
||||
|
||||
return responseSingle.map(pair -> {
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package org.asamk.signal.manager.helper;
|
||||
|
||||
import org.asamk.signal.manager.SignalDependencies;
|
||||
import org.asamk.signal.manager.UntrustedIdentityException;
|
||||
import org.asamk.signal.manager.groups.GroupId;
|
||||
import org.asamk.signal.manager.groups.GroupNotFoundException;
|
||||
import org.asamk.signal.manager.groups.GroupSendingNotAllowedException;
|
||||
|
@ -13,8 +14,8 @@ import org.asamk.signal.manager.storage.recipients.RecipientResolver;
|
|||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.whispersystems.libsignal.util.guava.Optional;
|
||||
import org.whispersystems.signalservice.api.SignalServiceMessageSender;
|
||||
import org.whispersystems.signalservice.api.crypto.ContentHint;
|
||||
import org.whispersystems.signalservice.api.crypto.UntrustedIdentityException;
|
||||
import org.whispersystems.signalservice.api.messages.SendMessageResult;
|
||||
import org.whispersystems.signalservice.api.messages.SignalServiceDataMessage;
|
||||
import org.whispersystems.signalservice.api.messages.SignalServiceReceiptMessage;
|
||||
|
@ -43,6 +44,20 @@ public class SendHelper {
|
|||
private final GroupProvider groupProvider;
|
||||
private final RecipientRegistrationRefresher recipientRegistrationRefresher;
|
||||
|
||||
private final SignalServiceMessageSender.IndividualSendEvents sendEvents = new SignalServiceMessageSender.IndividualSendEvents() {
|
||||
@Override
|
||||
public void onMessageEncrypted() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onMessageSent() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSyncMessageSent() {
|
||||
}
|
||||
};
|
||||
|
||||
public SendHelper(
|
||||
final SignalAccount account,
|
||||
final SignalDependencies dependencies,
|
||||
|
@ -145,9 +160,12 @@ public class SendHelper {
|
|||
final SignalServiceReceiptMessage receiptMessage, final RecipientId recipientId
|
||||
) throws IOException, UntrustedIdentityException {
|
||||
final var messageSender = dependencies.getMessageSender();
|
||||
messageSender.sendReceipt(addressResolver.resolveSignalServiceAddress(recipientId),
|
||||
unidentifiedAccessHelper.getAccessFor(recipientId),
|
||||
receiptMessage);
|
||||
final var address = addressResolver.resolveSignalServiceAddress(recipientId);
|
||||
try {
|
||||
messageSender.sendReceipt(address, unidentifiedAccessHelper.getAccessFor(recipientId), receiptMessage);
|
||||
} catch (org.whispersystems.signalservice.api.crypto.UntrustedIdentityException e) {
|
||||
throw new UntrustedIdentityException(address);
|
||||
}
|
||||
}
|
||||
|
||||
public SendMessageResult sendNullMessage(RecipientId recipientId) throws IOException {
|
||||
|
@ -162,7 +180,7 @@ public class SendHelper {
|
|||
final var newAddress = addressResolver.resolveSignalServiceAddress(newRecipientId);
|
||||
return messageSender.sendNullMessage(newAddress, unidentifiedAccessHelper.getAccessFor(newRecipientId));
|
||||
}
|
||||
} catch (UntrustedIdentityException e) {
|
||||
} catch (org.whispersystems.signalservice.api.crypto.UntrustedIdentityException e) {
|
||||
return SendMessageResult.identityFailure(address, e.getIdentityKey());
|
||||
}
|
||||
}
|
||||
|
@ -183,7 +201,7 @@ public class SendHelper {
|
|||
var messageSender = dependencies.getMessageSender();
|
||||
try {
|
||||
return messageSender.sendSyncMessage(message, unidentifiedAccessHelper.getAccessForSync());
|
||||
} catch (UntrustedIdentityException e) {
|
||||
} catch (org.whispersystems.signalservice.api.crypto.UntrustedIdentityException e) {
|
||||
var address = addressResolver.resolveSignalServiceAddress(account.getSelfRecipientId());
|
||||
return SendMessageResult.identityFailure(address, e.getIdentityKey());
|
||||
}
|
||||
|
@ -195,11 +213,15 @@ public class SendHelper {
|
|||
var messageSender = dependencies.getMessageSender();
|
||||
final var address = addressResolver.resolveSignalServiceAddress(recipientId);
|
||||
try {
|
||||
messageSender.sendTyping(address, unidentifiedAccessHelper.getAccessFor(recipientId), message);
|
||||
} catch (UnregisteredUserException e) {
|
||||
final var newRecipientId = recipientRegistrationRefresher.refreshRecipientRegistration(recipientId);
|
||||
final var newAddress = addressResolver.resolveSignalServiceAddress(newRecipientId);
|
||||
messageSender.sendTyping(newAddress, unidentifiedAccessHelper.getAccessFor(newRecipientId), message);
|
||||
try {
|
||||
messageSender.sendTyping(address, unidentifiedAccessHelper.getAccessFor(recipientId), message);
|
||||
} catch (UnregisteredUserException e) {
|
||||
final var newRecipientId = recipientRegistrationRefresher.refreshRecipientRegistration(recipientId);
|
||||
final var newAddress = addressResolver.resolveSignalServiceAddress(newRecipientId);
|
||||
messageSender.sendTyping(newAddress, unidentifiedAccessHelper.getAccessFor(newRecipientId), message);
|
||||
}
|
||||
} catch (org.whispersystems.signalservice.api.crypto.UntrustedIdentityException e) {
|
||||
throw new UntrustedIdentityException(address);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -247,7 +269,7 @@ public class SendHelper {
|
|||
message,
|
||||
sendResult -> logger.trace("Partial message send result: {}", sendResult.isSuccess()),
|
||||
() -> false);
|
||||
} catch (UntrustedIdentityException e) {
|
||||
} catch (org.whispersystems.signalservice.api.crypto.UntrustedIdentityException e) {
|
||||
return List.of();
|
||||
}
|
||||
}
|
||||
|
@ -263,15 +285,17 @@ public class SendHelper {
|
|||
return messageSender.sendDataMessage(address,
|
||||
unidentifiedAccessHelper.getAccessFor(recipientId),
|
||||
ContentHint.DEFAULT,
|
||||
message);
|
||||
message,
|
||||
sendEvents);
|
||||
} catch (UnregisteredUserException e) {
|
||||
final var newRecipientId = recipientRegistrationRefresher.refreshRecipientRegistration(recipientId);
|
||||
return messageSender.sendDataMessage(addressResolver.resolveSignalServiceAddress(newRecipientId),
|
||||
unidentifiedAccessHelper.getAccessFor(newRecipientId),
|
||||
ContentHint.DEFAULT,
|
||||
message);
|
||||
message,
|
||||
sendEvents);
|
||||
}
|
||||
} catch (UntrustedIdentityException e) {
|
||||
} catch (org.whispersystems.signalservice.api.crypto.UntrustedIdentityException e) {
|
||||
return SendMessageResult.identityFailure(address, e.getIdentityKey());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,11 +2,9 @@ package org.asamk.signal.manager.helper;
|
|||
|
||||
import org.asamk.signal.manager.AvatarStore;
|
||||
import org.asamk.signal.manager.TrustLevel;
|
||||
import org.asamk.signal.manager.groups.GroupId;
|
||||
import org.asamk.signal.manager.storage.SignalAccount;
|
||||
import org.asamk.signal.manager.storage.groups.GroupInfoV1;
|
||||
import org.asamk.signal.manager.storage.recipients.Contact;
|
||||
import org.asamk.signal.manager.storage.recipients.RecipientResolver;
|
||||
import org.asamk.signal.manager.util.AttachmentUtils;
|
||||
import org.asamk.signal.manager.util.IOUtils;
|
||||
import org.slf4j.Logger;
|
||||
|
@ -21,7 +19,6 @@ import org.whispersystems.signalservice.api.messages.multidevice.DeviceContact;
|
|||
import org.whispersystems.signalservice.api.messages.multidevice.DeviceContactsInputStream;
|
||||
import org.whispersystems.signalservice.api.messages.multidevice.DeviceContactsOutputStream;
|
||||
import org.whispersystems.signalservice.api.messages.multidevice.DeviceGroup;
|
||||
import org.whispersystems.signalservice.api.messages.multidevice.DeviceGroupsInputStream;
|
||||
import org.whispersystems.signalservice.api.messages.multidevice.DeviceGroupsOutputStream;
|
||||
import org.whispersystems.signalservice.api.messages.multidevice.RequestMessage;
|
||||
import org.whispersystems.signalservice.api.messages.multidevice.SignalServiceSyncMessage;
|
||||
|
@ -36,7 +33,6 @@ import java.io.InputStream;
|
|||
import java.io.OutputStream;
|
||||
import java.nio.file.Files;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class SyncHelper {
|
||||
|
@ -49,7 +45,6 @@ public class SyncHelper {
|
|||
private final GroupHelper groupHelper;
|
||||
private final AvatarStore avatarStore;
|
||||
private final SignalServiceAddressResolver addressResolver;
|
||||
private final RecipientResolver recipientResolver;
|
||||
|
||||
public SyncHelper(
|
||||
final SignalAccount account,
|
||||
|
@ -57,8 +52,7 @@ public class SyncHelper {
|
|||
final SendHelper sendHelper,
|
||||
final GroupHelper groupHelper,
|
||||
final AvatarStore avatarStore,
|
||||
final SignalServiceAddressResolver addressResolver,
|
||||
final RecipientResolver recipientResolver
|
||||
final SignalServiceAddressResolver addressResolver
|
||||
) {
|
||||
this.account = account;
|
||||
this.attachmentHelper = attachmentHelper;
|
||||
|
@ -66,7 +60,6 @@ public class SyncHelper {
|
|||
this.groupHelper = groupHelper;
|
||||
this.avatarStore = avatarStore;
|
||||
this.addressResolver = addressResolver;
|
||||
this.recipientResolver = recipientResolver;
|
||||
}
|
||||
|
||||
public void requestAllSyncData() throws IOException {
|
||||
|
@ -222,48 +215,6 @@ public class SyncHelper {
|
|||
sendHelper.sendSyncMessage(SignalServiceSyncMessage.forVerified(verifiedMessage));
|
||||
}
|
||||
|
||||
public void handleSyncDeviceGroups(final InputStream input) {
|
||||
final var s = new DeviceGroupsInputStream(input);
|
||||
DeviceGroup g;
|
||||
while (true) {
|
||||
try {
|
||||
g = s.read();
|
||||
} catch (IOException e) {
|
||||
logger.warn("Sync groups contained invalid group, ignoring: {}", e.getMessage());
|
||||
continue;
|
||||
}
|
||||
if (g == null) {
|
||||
break;
|
||||
}
|
||||
var syncGroup = account.getGroupStore().getOrCreateGroupV1(GroupId.v1(g.getId()));
|
||||
if (syncGroup != null) {
|
||||
if (g.getName().isPresent()) {
|
||||
syncGroup.name = g.getName().get();
|
||||
}
|
||||
syncGroup.addMembers(g.getMembers()
|
||||
.stream()
|
||||
.map(recipientResolver::resolveRecipient)
|
||||
.collect(Collectors.toSet()));
|
||||
if (!g.isActive()) {
|
||||
syncGroup.removeMember(account.getSelfRecipientId());
|
||||
} else {
|
||||
// Add ourself to the member set as it's marked as active
|
||||
syncGroup.addMembers(List.of(account.getSelfRecipientId()));
|
||||
}
|
||||
syncGroup.blocked = g.isBlocked();
|
||||
if (g.getColor().isPresent()) {
|
||||
syncGroup.color = g.getColor().get();
|
||||
}
|
||||
|
||||
if (g.getAvatar().isPresent()) {
|
||||
groupHelper.downloadGroupAvatar(syncGroup.getGroupId(), g.getAvatar().get());
|
||||
}
|
||||
syncGroup.archived = g.isArchived();
|
||||
account.getGroupStore().updateGroup(syncGroup);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void handleSyncDeviceContacts(final InputStream input) {
|
||||
final var s = new DeviceContactsInputStream(input);
|
||||
DeviceContact c;
|
||||
|
|
|
@ -152,7 +152,7 @@ public class SignalAccount implements Closeable {
|
|||
|
||||
account.initStores(dataPath, identityKey, registrationId, trustNewIdentity);
|
||||
account.groupStore = new GroupStore(getGroupCachePath(dataPath, username),
|
||||
account.recipientStore::resolveRecipient,
|
||||
account.recipientStore,
|
||||
account::saveGroupStore);
|
||||
account.stickerStore = new StickerStore(account::saveStickerStore);
|
||||
|
||||
|
@ -174,9 +174,9 @@ public class SignalAccount implements Closeable {
|
|||
|
||||
preKeyStore = new PreKeyStore(getPreKeysPath(dataPath, username));
|
||||
signedPreKeyStore = new SignedPreKeyStore(getSignedPreKeysPath(dataPath, username));
|
||||
sessionStore = new SessionStore(getSessionsPath(dataPath, username), recipientStore::resolveRecipient);
|
||||
sessionStore = new SessionStore(getSessionsPath(dataPath, username), recipientStore);
|
||||
identityKeyStore = new IdentityKeyStore(getIdentitiesPath(dataPath, username),
|
||||
recipientStore::resolveRecipient,
|
||||
recipientStore,
|
||||
identityKey,
|
||||
registrationId,
|
||||
trustNewIdentity);
|
||||
|
@ -254,7 +254,7 @@ public class SignalAccount implements Closeable {
|
|||
|
||||
account.initStores(dataPath, identityKey, registrationId, trustNewIdentity);
|
||||
account.groupStore = new GroupStore(getGroupCachePath(dataPath, username),
|
||||
account.recipientStore::resolveRecipient,
|
||||
account.recipientStore,
|
||||
account::saveGroupStore);
|
||||
account.stickerStore = new StickerStore(account::saveStickerStore);
|
||||
|
||||
|
@ -453,12 +453,10 @@ public class SignalAccount implements Closeable {
|
|||
groupStoreStorage = jsonProcessor.convertValue(rootNode.get("groupStore"), GroupStore.Storage.class);
|
||||
groupStore = GroupStore.fromStorage(groupStoreStorage,
|
||||
getGroupCachePath(dataPath, username),
|
||||
recipientStore::resolveRecipient,
|
||||
recipientStore,
|
||||
this::saveGroupStore);
|
||||
} else {
|
||||
groupStore = new GroupStore(getGroupCachePath(dataPath, username),
|
||||
recipientStore::resolveRecipient,
|
||||
this::saveGroupStore);
|
||||
groupStore = new GroupStore(getGroupCachePath(dataPath, username), recipientStore, this::saveGroupStore);
|
||||
}
|
||||
|
||||
if (rootNode.hasNonNull("stickerStore")) {
|
||||
|
@ -572,7 +570,7 @@ public class SignalAccount implements Closeable {
|
|||
var profileStoreNode = rootNode.get("profileStore");
|
||||
final var legacyProfileStore = jsonProcessor.convertValue(profileStoreNode, LegacyProfileStore.class);
|
||||
for (var profileEntry : legacyProfileStore.getProfileEntries()) {
|
||||
var recipientId = recipientStore.resolveRecipient(profileEntry.getServiceAddress());
|
||||
var recipientId = recipientStore.resolveRecipient(profileEntry.getAddress());
|
||||
recipientStore.storeProfileKeyCredential(recipientId, profileEntry.getProfileKeyCredential());
|
||||
recipientStore.storeProfileKey(recipientId, profileEntry.getProfileKey());
|
||||
final var profile = profileEntry.getProfile();
|
||||
|
|
|
@ -9,7 +9,11 @@ import com.fasterxml.jackson.databind.JsonNode;
|
|||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.fasterxml.jackson.databind.SerializationFeature;
|
||||
|
||||
import org.asamk.signal.manager.storage.recipients.RecipientAddress;
|
||||
import org.whispersystems.signalservice.api.util.UuidUtil;
|
||||
|
||||
import java.io.InvalidObjectException;
|
||||
import java.util.Optional;
|
||||
|
||||
public class Utils {
|
||||
|
||||
|
@ -37,4 +41,12 @@ public class Utils {
|
|||
|
||||
return node;
|
||||
}
|
||||
|
||||
public static RecipientAddress getRecipientAddressFromIdentifier(final String identifier) {
|
||||
if (UuidUtil.isUuid(identifier)) {
|
||||
return new RecipientAddress(UuidUtil.parseOrThrow(identifier));
|
||||
} else {
|
||||
return new RecipientAddress(Optional.empty(), Optional.of(identifier));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,7 +3,7 @@ package org.asamk.signal.manager.storage.contacts;
|
|||
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
|
||||
import org.whispersystems.signalservice.api.push.SignalServiceAddress;
|
||||
import org.asamk.signal.manager.storage.recipients.RecipientAddress;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
|
@ -42,7 +42,7 @@ public class LegacyContactInfo {
|
|||
}
|
||||
|
||||
@JsonIgnore
|
||||
public SignalServiceAddress getAddress() {
|
||||
return new SignalServiceAddress(uuid, number);
|
||||
public RecipientAddress getAddress() {
|
||||
return new RecipientAddress(uuid, number);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,7 +9,6 @@ import org.signal.storageservice.protos.groups.Member;
|
|||
import org.signal.storageservice.protos.groups.local.DecryptedGroup;
|
||||
import org.signal.storageservice.protos.groups.local.EnabledState;
|
||||
import org.signal.zkgroup.groups.GroupMasterKey;
|
||||
import org.whispersystems.signalservice.api.push.SignalServiceAddress;
|
||||
import org.whispersystems.signalservice.api.util.UuidUtil;
|
||||
|
||||
import java.util.Set;
|
||||
|
@ -89,7 +88,7 @@ public class GroupInfoV2 extends GroupInfo {
|
|||
}
|
||||
return group.getMembersList()
|
||||
.stream()
|
||||
.map(m -> new SignalServiceAddress(UuidUtil.parseOrThrow(m.getUuid().toByteArray()), null))
|
||||
.map(m -> UuidUtil.parseOrThrow(m.getUuid().toByteArray()))
|
||||
.map(recipientResolver::resolveRecipient)
|
||||
.collect(Collectors.toSet());
|
||||
}
|
||||
|
@ -101,7 +100,7 @@ public class GroupInfoV2 extends GroupInfo {
|
|||
}
|
||||
return group.getPendingMembersList()
|
||||
.stream()
|
||||
.map(m -> new SignalServiceAddress(UuidUtil.parseOrThrow(m.getUuid().toByteArray()), null))
|
||||
.map(m -> UuidUtil.parseOrThrow(m.getUuid().toByteArray()))
|
||||
.map(recipientResolver::resolveRecipient)
|
||||
.collect(Collectors.toSet());
|
||||
}
|
||||
|
@ -113,7 +112,7 @@ public class GroupInfoV2 extends GroupInfo {
|
|||
}
|
||||
return group.getRequestingMembersList()
|
||||
.stream()
|
||||
.map(m -> new SignalServiceAddress(UuidUtil.parseOrThrow(m.getUuid().toByteArray()), null))
|
||||
.map(m -> UuidUtil.parseOrThrow(m.getUuid().toByteArray()))
|
||||
.map(recipientResolver::resolveRecipient)
|
||||
.collect(Collectors.toSet());
|
||||
}
|
||||
|
@ -126,7 +125,7 @@ public class GroupInfoV2 extends GroupInfo {
|
|||
return group.getMembersList()
|
||||
.stream()
|
||||
.filter(m -> m.getRole() == Member.Role.ADMINISTRATOR)
|
||||
.map(m -> new SignalServiceAddress(UuidUtil.parseOrThrow(m.getUuid().toByteArray()), null))
|
||||
.map(m -> UuidUtil.parseOrThrow(m.getUuid().toByteArray()))
|
||||
.map(recipientResolver::resolveRecipient)
|
||||
.collect(Collectors.toSet());
|
||||
}
|
||||
|
|
|
@ -14,6 +14,7 @@ import org.asamk.signal.manager.groups.GroupId;
|
|||
import org.asamk.signal.manager.groups.GroupIdV1;
|
||||
import org.asamk.signal.manager.groups.GroupIdV2;
|
||||
import org.asamk.signal.manager.groups.GroupUtils;
|
||||
import org.asamk.signal.manager.storage.recipients.RecipientAddress;
|
||||
import org.asamk.signal.manager.storage.recipients.RecipientId;
|
||||
import org.asamk.signal.manager.storage.recipients.RecipientResolver;
|
||||
import org.asamk.signal.manager.util.IOUtils;
|
||||
|
@ -22,7 +23,6 @@ import org.signal.zkgroup.InvalidInputException;
|
|||
import org.signal.zkgroup.groups.GroupMasterKey;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.whispersystems.signalservice.api.push.SignalServiceAddress;
|
||||
import org.whispersystems.signalservice.api.util.UuidUtil;
|
||||
import org.whispersystems.signalservice.internal.util.Hex;
|
||||
|
||||
|
@ -78,7 +78,7 @@ public class GroupStore {
|
|||
final var g1 = (Storage.GroupV1) g;
|
||||
final var members = g1.members.stream().map(m -> {
|
||||
if (m.recipientId == null) {
|
||||
return recipientResolver.resolveRecipient(new SignalServiceAddress(UuidUtil.parseOrNull(m.uuid),
|
||||
return recipientResolver.resolveRecipient(new RecipientAddress(UuidUtil.parseOrNull(m.uuid),
|
||||
m.number));
|
||||
}
|
||||
|
||||
|
@ -343,17 +343,17 @@ public class GroupStore {
|
|||
}
|
||||
}
|
||||
|
||||
private static final class JsonSignalServiceAddress {
|
||||
private static final class JsonRecipientAddress {
|
||||
|
||||
public String uuid;
|
||||
|
||||
public String number;
|
||||
|
||||
// For deserialization
|
||||
public JsonSignalServiceAddress() {
|
||||
public JsonRecipientAddress() {
|
||||
}
|
||||
|
||||
JsonSignalServiceAddress(final String uuid, final String number) {
|
||||
JsonRecipientAddress(final String uuid, final String number) {
|
||||
this.uuid = uuid;
|
||||
this.number = number;
|
||||
}
|
||||
|
@ -370,7 +370,7 @@ public class GroupStore {
|
|||
if (address.recipientId != null) {
|
||||
jgen.writeNumber(address.recipientId);
|
||||
} else if (address.uuid != null) {
|
||||
jgen.writeObject(new JsonSignalServiceAddress(address.uuid, address.number));
|
||||
jgen.writeObject(new JsonRecipientAddress(address.uuid, address.number));
|
||||
} else {
|
||||
jgen.writeString(address.number);
|
||||
}
|
||||
|
@ -393,7 +393,7 @@ public class GroupStore {
|
|||
} else if (n.isNumber()) {
|
||||
addresses.add(new Member(n.numberValue().longValue(), null, null));
|
||||
} else {
|
||||
var address = jsonParser.getCodec().treeToValue(n, JsonSignalServiceAddress.class);
|
||||
var address = jsonParser.getCodec().treeToValue(n, JsonRecipientAddress.class);
|
||||
addresses.add(new Member(null, address.uuid, address.number));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,7 +6,6 @@ import org.asamk.signal.manager.TrustLevel;
|
|||
import org.asamk.signal.manager.storage.recipients.RecipientId;
|
||||
import org.asamk.signal.manager.storage.recipients.RecipientResolver;
|
||||
import org.asamk.signal.manager.util.IOUtils;
|
||||
import org.asamk.signal.manager.util.Utils;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.whispersystems.libsignal.IdentityKey;
|
||||
|
@ -177,7 +176,7 @@ public class IdentityKeyStore implements org.whispersystems.libsignal.state.Iden
|
|||
* @param identifier can be either a serialized uuid or a e164 phone number
|
||||
*/
|
||||
private RecipientId resolveRecipient(String identifier) {
|
||||
return resolver.resolveRecipient(Utils.getSignalServiceAddressFromIdentifier(identifier));
|
||||
return resolver.resolveRecipient(identifier);
|
||||
}
|
||||
|
||||
private File getIdentityFile(final RecipientId recipientId) {
|
||||
|
|
|
@ -8,10 +8,10 @@ import com.fasterxml.jackson.databind.JsonNode;
|
|||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
|
||||
|
||||
import org.asamk.signal.manager.storage.recipients.RecipientAddress;
|
||||
import org.signal.zkgroup.InvalidInputException;
|
||||
import org.signal.zkgroup.profiles.ProfileKey;
|
||||
import org.signal.zkgroup.profiles.ProfileKeyCredential;
|
||||
import org.whispersystems.signalservice.api.push.SignalServiceAddress;
|
||||
import org.whispersystems.signalservice.api.util.UuidUtil;
|
||||
|
||||
import java.io.IOException;
|
||||
|
@ -45,7 +45,7 @@ public class LegacyProfileStore {
|
|||
for (var entry : node) {
|
||||
var name = entry.hasNonNull("name") ? entry.get("name").asText() : null;
|
||||
var uuid = entry.hasNonNull("uuid") ? UuidUtil.parseOrNull(entry.get("uuid").asText()) : null;
|
||||
final var serviceAddress = new SignalServiceAddress(uuid, name);
|
||||
final var address = new RecipientAddress(uuid, name);
|
||||
ProfileKey profileKey = null;
|
||||
try {
|
||||
profileKey = new ProfileKey(Base64.getDecoder().decode(entry.get("profileKey").asText()));
|
||||
|
@ -61,7 +61,7 @@ public class LegacyProfileStore {
|
|||
}
|
||||
var lastUpdateTimestamp = entry.get("lastUpdateTimestamp").asLong();
|
||||
var profile = jsonProcessor.treeToValue(entry.get("profile"), SignalProfile.class);
|
||||
profileEntries.add(new LegacySignalProfileEntry(serviceAddress,
|
||||
profileEntries.add(new LegacySignalProfileEntry(address,
|
||||
profileKey,
|
||||
lastUpdateTimestamp,
|
||||
profile,
|
||||
|
|
|
@ -1,12 +1,12 @@
|
|||
package org.asamk.signal.manager.storage.profiles;
|
||||
|
||||
import org.asamk.signal.manager.storage.recipients.RecipientAddress;
|
||||
import org.signal.zkgroup.profiles.ProfileKey;
|
||||
import org.signal.zkgroup.profiles.ProfileKeyCredential;
|
||||
import org.whispersystems.signalservice.api.push.SignalServiceAddress;
|
||||
|
||||
public class LegacySignalProfileEntry {
|
||||
|
||||
private final SignalServiceAddress serviceAddress;
|
||||
private final RecipientAddress address;
|
||||
|
||||
private final ProfileKey profileKey;
|
||||
|
||||
|
@ -17,21 +17,21 @@ public class LegacySignalProfileEntry {
|
|||
private final ProfileKeyCredential profileKeyCredential;
|
||||
|
||||
public LegacySignalProfileEntry(
|
||||
final SignalServiceAddress serviceAddress,
|
||||
final RecipientAddress address,
|
||||
final ProfileKey profileKey,
|
||||
final long lastUpdateTimestamp,
|
||||
final SignalProfile profile,
|
||||
final ProfileKeyCredential profileKeyCredential
|
||||
) {
|
||||
this.serviceAddress = serviceAddress;
|
||||
this.address = address;
|
||||
this.profileKey = profileKey;
|
||||
this.lastUpdateTimestamp = lastUpdateTimestamp;
|
||||
this.profile = profile;
|
||||
this.profileKeyCredential = profileKeyCredential;
|
||||
}
|
||||
|
||||
public SignalServiceAddress getServiceAddress() {
|
||||
return serviceAddress;
|
||||
public RecipientAddress getAddress() {
|
||||
return address;
|
||||
}
|
||||
|
||||
public ProfileKey getProfileKey() {
|
||||
|
|
|
@ -1,30 +1,30 @@
|
|||
package org.asamk.signal.manager.storage.protocol;
|
||||
|
||||
import org.asamk.signal.manager.TrustLevel;
|
||||
import org.asamk.signal.manager.storage.recipients.RecipientAddress;
|
||||
import org.whispersystems.libsignal.IdentityKey;
|
||||
import org.whispersystems.signalservice.api.push.SignalServiceAddress;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
public class LegacyIdentityInfo {
|
||||
|
||||
SignalServiceAddress address;
|
||||
RecipientAddress address;
|
||||
IdentityKey identityKey;
|
||||
TrustLevel trustLevel;
|
||||
Date added;
|
||||
|
||||
LegacyIdentityInfo(SignalServiceAddress address, IdentityKey identityKey, TrustLevel trustLevel, Date added) {
|
||||
LegacyIdentityInfo(RecipientAddress address, IdentityKey identityKey, TrustLevel trustLevel, Date added) {
|
||||
this.address = address;
|
||||
this.identityKey = identityKey;
|
||||
this.trustLevel = trustLevel;
|
||||
this.added = added;
|
||||
}
|
||||
|
||||
public SignalServiceAddress getAddress() {
|
||||
public RecipientAddress getAddress() {
|
||||
return address;
|
||||
}
|
||||
|
||||
public void setAddress(final SignalServiceAddress address) {
|
||||
public void setAddress(final RecipientAddress address) {
|
||||
this.address = address;
|
||||
}
|
||||
|
||||
|
|
|
@ -6,13 +6,13 @@ import com.fasterxml.jackson.databind.JsonDeserializer;
|
|||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
|
||||
import org.asamk.signal.manager.TrustLevel;
|
||||
import org.asamk.signal.manager.util.Utils;
|
||||
import org.asamk.signal.manager.storage.Utils;
|
||||
import org.asamk.signal.manager.storage.recipients.RecipientAddress;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.whispersystems.libsignal.IdentityKey;
|
||||
import org.whispersystems.libsignal.IdentityKeyPair;
|
||||
import org.whispersystems.libsignal.InvalidKeyException;
|
||||
import org.whispersystems.signalservice.api.push.SignalServiceAddress;
|
||||
import org.whispersystems.signalservice.api.util.UuidUtil;
|
||||
|
||||
import java.io.IOException;
|
||||
|
@ -55,11 +55,11 @@ public class LegacyJsonIdentityKeyStore {
|
|||
return localRegistrationId;
|
||||
}
|
||||
|
||||
private LegacyIdentityInfo getIdentity(SignalServiceAddress serviceAddress) {
|
||||
private LegacyIdentityInfo getIdentity(RecipientAddress address) {
|
||||
long maxDate = 0;
|
||||
LegacyIdentityInfo maxIdentity = null;
|
||||
for (var id : this.identities) {
|
||||
if (!id.address.matches(serviceAddress)) {
|
||||
if (!id.getAddress().matches(address)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -98,16 +98,16 @@ public class LegacyJsonIdentityKeyStore {
|
|||
var uuid = trustedKey.hasNonNull("uuid")
|
||||
? UuidUtil.parseOrNull(trustedKey.get("uuid").asText())
|
||||
: null;
|
||||
final var serviceAddress = uuid == null
|
||||
? Utils.getSignalServiceAddressFromIdentifier(trustedKeyName)
|
||||
: new SignalServiceAddress(uuid, trustedKeyName);
|
||||
final var address = uuid == null
|
||||
? Utils.getRecipientAddressFromIdentifier(trustedKeyName)
|
||||
: new RecipientAddress(uuid, trustedKeyName);
|
||||
try {
|
||||
var id = new IdentityKey(Base64.getDecoder().decode(trustedKey.get("identityKey").asText()), 0);
|
||||
var trustLevel = trustedKey.hasNonNull("trustLevel") ? TrustLevel.fromInt(trustedKey.get(
|
||||
"trustLevel").asInt()) : TrustLevel.TRUSTED_UNVERIFIED;
|
||||
var added = trustedKey.hasNonNull("addedTimestamp") ? new Date(trustedKey.get("addedTimestamp")
|
||||
.asLong()) : new Date();
|
||||
identities.add(new LegacyIdentityInfo(serviceAddress, id, trustLevel, added));
|
||||
identities.add(new LegacyIdentityInfo(address, id, trustLevel, added));
|
||||
} catch (InvalidKeyException e) {
|
||||
logger.warn("Error while decoding key for {}: {}", trustedKeyName, e.getMessage());
|
||||
}
|
||||
|
|
|
@ -5,8 +5,8 @@ import com.fasterxml.jackson.databind.DeserializationContext;
|
|||
import com.fasterxml.jackson.databind.JsonDeserializer;
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
|
||||
import org.asamk.signal.manager.util.Utils;
|
||||
import org.whispersystems.signalservice.api.push.SignalServiceAddress;
|
||||
import org.asamk.signal.manager.storage.Utils;
|
||||
import org.asamk.signal.manager.storage.recipients.RecipientAddress;
|
||||
import org.whispersystems.signalservice.api.util.UuidUtil;
|
||||
|
||||
import java.io.IOException;
|
||||
|
@ -45,12 +45,12 @@ public class LegacyJsonSessionStore {
|
|||
}
|
||||
|
||||
var uuid = session.hasNonNull("uuid") ? UuidUtil.parseOrNull(session.get("uuid").asText()) : null;
|
||||
final var serviceAddress = uuid == null
|
||||
? Utils.getSignalServiceAddressFromIdentifier(sessionName)
|
||||
: new SignalServiceAddress(uuid, sessionName);
|
||||
final var address = uuid == null
|
||||
? Utils.getRecipientAddressFromIdentifier(sessionName)
|
||||
: new RecipientAddress(uuid, sessionName);
|
||||
final var deviceId = session.get("deviceId").asInt();
|
||||
final var record = Base64.getDecoder().decode(session.get("record").asText());
|
||||
var sessionInfo = new LegacySessionInfo(serviceAddress, deviceId, record);
|
||||
var sessionInfo = new LegacySessionInfo(address, deviceId, record);
|
||||
sessions.add(sessionInfo);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,16 +1,16 @@
|
|||
package org.asamk.signal.manager.storage.protocol;
|
||||
|
||||
import org.whispersystems.signalservice.api.push.SignalServiceAddress;
|
||||
import org.asamk.signal.manager.storage.recipients.RecipientAddress;
|
||||
|
||||
public class LegacySessionInfo {
|
||||
|
||||
public SignalServiceAddress address;
|
||||
public RecipientAddress address;
|
||||
|
||||
public int deviceId;
|
||||
|
||||
public byte[] sessionRecord;
|
||||
|
||||
LegacySessionInfo(final SignalServiceAddress address, final int deviceId, final byte[] sessionRecord) {
|
||||
LegacySessionInfo(final RecipientAddress address, final int deviceId, final byte[] sessionRecord) {
|
||||
this.address = address;
|
||||
this.deviceId = deviceId;
|
||||
this.sessionRecord = sessionRecord;
|
||||
|
|
|
@ -129,6 +129,11 @@ public class SignalProtocolStore implements SignalServiceDataStore {
|
|||
sessionStore.archiveSession(address);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<SignalProtocolAddress> getAllAddressesWithActiveSessions(final List<String> addressNames) {
|
||||
return sessionStore.getAllAddressesWithActiveSessions(addressNames);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SignedPreKeyRecord loadSignedPreKey(int signedPreKeyId) throws InvalidKeyIdException {
|
||||
return signedPreKeyStore.loadSignedPreKey(signedPreKeyId);
|
||||
|
@ -189,4 +194,11 @@ public class SignalProtocolStore implements SignalServiceDataStore {
|
|||
public boolean isMultiDevice() {
|
||||
return isMultiDevice.get();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Transaction beginTransaction() {
|
||||
return () -> {
|
||||
// No-op transaction should be safe, as it's only a performance improvement
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,7 +7,6 @@ import com.fasterxml.jackson.databind.JsonDeserializer;
|
|||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
|
||||
|
||||
import org.whispersystems.signalservice.api.push.SignalServiceAddress;
|
||||
import org.whispersystems.signalservice.api.util.UuidUtil;
|
||||
|
||||
import java.io.IOException;
|
||||
|
@ -18,28 +17,27 @@ public class LegacyRecipientStore {
|
|||
|
||||
@JsonProperty("recipientStore")
|
||||
@JsonDeserialize(using = RecipientStoreDeserializer.class)
|
||||
private final List<SignalServiceAddress> addresses = new ArrayList<>();
|
||||
private final List<RecipientAddress> addresses = new ArrayList<>();
|
||||
|
||||
public List<SignalServiceAddress> getAddresses() {
|
||||
public List<RecipientAddress> getAddresses() {
|
||||
return addresses;
|
||||
}
|
||||
|
||||
public static class RecipientStoreDeserializer extends JsonDeserializer<List<SignalServiceAddress>> {
|
||||
public static class RecipientStoreDeserializer extends JsonDeserializer<List<RecipientAddress>> {
|
||||
|
||||
@Override
|
||||
public List<SignalServiceAddress> deserialize(
|
||||
public List<RecipientAddress> deserialize(
|
||||
JsonParser jsonParser, DeserializationContext deserializationContext
|
||||
) throws IOException {
|
||||
JsonNode node = jsonParser.getCodec().readTree(jsonParser);
|
||||
|
||||
var addresses = new ArrayList<SignalServiceAddress>();
|
||||
var addresses = new ArrayList<RecipientAddress>();
|
||||
|
||||
if (node.isArray()) {
|
||||
for (var recipient : node) {
|
||||
var recipientName = recipient.get("name").asText();
|
||||
var uuid = UuidUtil.parseOrThrow(recipient.get("uuid").asText());
|
||||
final var serviceAddress = new SignalServiceAddress(uuid, recipientName);
|
||||
addresses.add(serviceAddress);
|
||||
addresses.add(new RecipientAddress(uuid, recipientName));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -2,13 +2,12 @@ package org.asamk.signal.manager.storage.recipients;
|
|||
|
||||
import org.signal.zkgroup.profiles.ProfileKey;
|
||||
import org.signal.zkgroup.profiles.ProfileKeyCredential;
|
||||
import org.whispersystems.signalservice.api.push.SignalServiceAddress;
|
||||
|
||||
public class Recipient {
|
||||
|
||||
private final RecipientId recipientId;
|
||||
|
||||
private final SignalServiceAddress address;
|
||||
private final RecipientAddress address;
|
||||
|
||||
private final Contact contact;
|
||||
|
||||
|
@ -20,7 +19,7 @@ public class Recipient {
|
|||
|
||||
public Recipient(
|
||||
final RecipientId recipientId,
|
||||
final SignalServiceAddress address,
|
||||
final RecipientAddress address,
|
||||
final Contact contact,
|
||||
final ProfileKey profileKey,
|
||||
final ProfileKeyCredential profileKeyCredential,
|
||||
|
@ -62,7 +61,7 @@ public class Recipient {
|
|||
return recipientId;
|
||||
}
|
||||
|
||||
public SignalServiceAddress getAddress() {
|
||||
public RecipientAddress getAddress() {
|
||||
return address;
|
||||
}
|
||||
|
||||
|
@ -85,7 +84,7 @@ public class Recipient {
|
|||
public static final class Builder {
|
||||
|
||||
private RecipientId recipientId;
|
||||
private SignalServiceAddress address;
|
||||
private RecipientAddress address;
|
||||
private Contact contact;
|
||||
private ProfileKey profileKey;
|
||||
private ProfileKeyCredential profileKeyCredential;
|
||||
|
@ -99,7 +98,7 @@ public class Recipient {
|
|||
return this;
|
||||
}
|
||||
|
||||
public Builder withAddress(final SignalServiceAddress val) {
|
||||
public Builder withAddress(final RecipientAddress val) {
|
||||
address = val;
|
||||
return this;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,89 @@
|
|||
package org.asamk.signal.manager.storage.recipients;
|
||||
|
||||
import org.whispersystems.signalservice.api.push.SignalServiceAddress;
|
||||
import org.whispersystems.signalservice.api.util.UuidUtil;
|
||||
|
||||
import java.util.Optional;
|
||||
import java.util.UUID;
|
||||
|
||||
public class RecipientAddress {
|
||||
|
||||
private final Optional<UUID> uuid;
|
||||
private final Optional<String> e164;
|
||||
|
||||
/**
|
||||
* Construct a RecipientAddress.
|
||||
*
|
||||
* @param uuid The UUID of the user, if available.
|
||||
* @param e164 The phone number of the user, if available.
|
||||
*/
|
||||
public RecipientAddress(Optional<UUID> uuid, Optional<String> e164) {
|
||||
if (!uuid.isPresent() && !e164.isPresent()) {
|
||||
throw new AssertionError("Must have either a UUID or E164 number!");
|
||||
}
|
||||
|
||||
this.uuid = uuid;
|
||||
this.e164 = e164;
|
||||
}
|
||||
|
||||
public RecipientAddress(UUID uuid, String e164) {
|
||||
this(Optional.ofNullable(uuid), Optional.ofNullable(e164));
|
||||
}
|
||||
|
||||
public RecipientAddress(SignalServiceAddress address) {
|
||||
this.uuid = Optional.of(address.getUuid());
|
||||
this.e164 = Optional.ofNullable(address.getNumber().orNull());
|
||||
}
|
||||
|
||||
public RecipientAddress(UUID uuid) {
|
||||
this.uuid = Optional.of(uuid);
|
||||
this.e164 = Optional.empty();
|
||||
}
|
||||
|
||||
public Optional<String> getNumber() {
|
||||
return e164;
|
||||
}
|
||||
|
||||
public Optional<UUID> getUuid() {
|
||||
return uuid;
|
||||
}
|
||||
|
||||
public String getIdentifier() {
|
||||
if (uuid.isPresent()) {
|
||||
return uuid.get().toString();
|
||||
} else if (e164.isPresent()) {
|
||||
return e164.get();
|
||||
} 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())
|
||||
);
|
||||
}
|
||||
|
||||
public SignalServiceAddress toSignalServiceAddress() {
|
||||
return new SignalServiceAddress(uuid.orElse(UuidUtil.UNKNOWN_UUID),
|
||||
org.whispersystems.libsignal.util.guava.Optional.fromNullable(e164.orElse(null)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(final Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
|
||||
final RecipientAddress that = (RecipientAddress) o;
|
||||
|
||||
if (!uuid.equals(that.uuid)) return false;
|
||||
return e164.equals(that.e164);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int result = uuid.hashCode();
|
||||
result = 31 * result + e164.hashCode();
|
||||
return result;
|
||||
}
|
||||
}
|
|
@ -2,7 +2,15 @@ package org.asamk.signal.manager.storage.recipients;
|
|||
|
||||
import org.whispersystems.signalservice.api.push.SignalServiceAddress;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
public interface RecipientResolver {
|
||||
|
||||
RecipientId resolveRecipient(String identifier);
|
||||
|
||||
RecipientId resolveRecipient(RecipientAddress address);
|
||||
|
||||
RecipientId resolveRecipient(SignalServiceAddress address);
|
||||
|
||||
RecipientId resolveRecipient(UUID uuid);
|
||||
}
|
||||
|
|
|
@ -12,6 +12,7 @@ import org.slf4j.Logger;
|
|||
import org.slf4j.LoggerFactory;
|
||||
import org.whispersystems.libsignal.util.Pair;
|
||||
import org.whispersystems.signalservice.api.push.SignalServiceAddress;
|
||||
import org.whispersystems.signalservice.api.push.exceptions.UnregisteredUserException;
|
||||
import org.whispersystems.signalservice.api.util.UuidUtil;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
|
@ -30,9 +31,10 @@ import java.util.Objects;
|
|||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
import java.util.function.Supplier;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class RecipientStore implements ContactsStore, ProfileStore {
|
||||
public class RecipientStore implements RecipientResolver, ContactsStore, ProfileStore {
|
||||
|
||||
private final static Logger logger = LoggerFactory.getLogger(RecipientStore.class);
|
||||
|
||||
|
@ -51,9 +53,8 @@ public class RecipientStore implements ContactsStore, ProfileStore {
|
|||
final var storage = objectMapper.readValue(inputStream, Storage.class);
|
||||
final var recipients = storage.recipients.stream().map(r -> {
|
||||
final var recipientId = new RecipientId(r.id);
|
||||
final var address = new SignalServiceAddress(org.whispersystems.libsignal.util.guava.Optional.fromNullable(
|
||||
r.uuid).transform(UuidUtil::parseOrThrow),
|
||||
org.whispersystems.libsignal.util.guava.Optional.fromNullable(r.number));
|
||||
final var address = new RecipientAddress(Optional.ofNullable(r.uuid).map(UuidUtil::parseOrThrow),
|
||||
Optional.ofNullable(r.number));
|
||||
|
||||
Contact contact = null;
|
||||
if (r.contact != null) {
|
||||
|
@ -119,7 +120,7 @@ public class RecipientStore implements ContactsStore, ProfileStore {
|
|||
this.lastId = lastId;
|
||||
}
|
||||
|
||||
public SignalServiceAddress resolveServiceAddress(RecipientId recipientId) {
|
||||
public RecipientAddress resolveRecipientAddress(RecipientId recipientId) {
|
||||
synchronized (recipients) {
|
||||
return getRecipient(recipientId).getAddress();
|
||||
}
|
||||
|
@ -134,24 +135,52 @@ public class RecipientStore implements ContactsStore, ProfileStore {
|
|||
}
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public SignalServiceAddress resolveServiceAddress(SignalServiceAddress address) {
|
||||
return resolveServiceAddress(resolveRecipient(address, false));
|
||||
}
|
||||
|
||||
@Override
|
||||
public RecipientId resolveRecipient(UUID uuid) {
|
||||
return resolveRecipient(new SignalServiceAddress(uuid, null), false);
|
||||
return resolveRecipient(new RecipientAddress(uuid), false);
|
||||
}
|
||||
|
||||
public RecipientId resolveRecipient(String number) {
|
||||
return resolveRecipient(new SignalServiceAddress(null, number), false);
|
||||
@Override
|
||||
public RecipientId resolveRecipient(final String identifier) {
|
||||
return resolveRecipient(Utils.getRecipientAddressFromIdentifier(identifier), false);
|
||||
}
|
||||
|
||||
public RecipientId resolveRecipientTrusted(SignalServiceAddress address) {
|
||||
public RecipientId resolveRecipient(
|
||||
final String number, Supplier<UUID> uuidSupplier
|
||||
) throws UnregisteredUserException {
|
||||
final Optional<Recipient> byNumber;
|
||||
synchronized (recipients) {
|
||||
byNumber = findByNumberLocked(number);
|
||||
}
|
||||
if (byNumber.isEmpty() || byNumber.get().getAddress().getUuid().isEmpty()) {
|
||||
final var uuid = uuidSupplier.get();
|
||||
if (uuid == null) {
|
||||
throw new UnregisteredUserException(number, null);
|
||||
}
|
||||
|
||||
return resolveRecipient(new RecipientAddress(uuid, number), false);
|
||||
}
|
||||
return byNumber.get().getRecipientId();
|
||||
}
|
||||
|
||||
public RecipientId resolveRecipient(RecipientAddress address) {
|
||||
return resolveRecipient(address, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public RecipientId resolveRecipient(final SignalServiceAddress address) {
|
||||
return resolveRecipient(new RecipientAddress(address), false);
|
||||
}
|
||||
|
||||
public RecipientId resolveRecipientTrusted(RecipientAddress address) {
|
||||
return resolveRecipient(address, true);
|
||||
}
|
||||
|
||||
public List<RecipientId> resolveRecipientsTrusted(List<SignalServiceAddress> addresses) {
|
||||
public RecipientId resolveRecipientTrusted(SignalServiceAddress address) {
|
||||
return resolveRecipient(new RecipientAddress(address), true);
|
||||
}
|
||||
|
||||
public List<RecipientId> resolveRecipientsTrusted(List<RecipientAddress> addresses) {
|
||||
final List<RecipientId> recipientIds;
|
||||
final List<Pair<RecipientId, RecipientId>> toBeMerged = new ArrayList<>();
|
||||
synchronized (recipients) {
|
||||
|
@ -169,10 +198,6 @@ public class RecipientStore implements ContactsStore, ProfileStore {
|
|||
return recipientIds;
|
||||
}
|
||||
|
||||
public RecipientId resolveRecipient(SignalServiceAddress address) {
|
||||
return resolveRecipient(address, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void storeContact(final RecipientId recipientId, final Contact contact) {
|
||||
synchronized (recipients) {
|
||||
|
@ -262,7 +287,7 @@ public class RecipientStore implements ContactsStore, ProfileStore {
|
|||
* @param isHighTrust true, if the number/uuid connection was obtained from a trusted source.
|
||||
* Has no effect, if the address contains only a number or a uuid.
|
||||
*/
|
||||
private RecipientId resolveRecipient(SignalServiceAddress address, boolean isHighTrust) {
|
||||
private RecipientId resolveRecipient(RecipientAddress address, boolean isHighTrust) {
|
||||
final Pair<RecipientId, Optional<RecipientId>> pair;
|
||||
synchronized (recipients) {
|
||||
pair = resolveRecipientLocked(address, isHighTrust);
|
||||
|
@ -278,30 +303,26 @@ public class RecipientStore implements ContactsStore, ProfileStore {
|
|||
}
|
||||
|
||||
private Pair<RecipientId, Optional<RecipientId>> resolveRecipientLocked(
|
||||
SignalServiceAddress address, boolean isHighTrust
|
||||
RecipientAddress address, boolean isHighTrust
|
||||
) {
|
||||
final var byNumber = !address.getNumber().isPresent()
|
||||
final var byNumber = address.getNumber().isEmpty()
|
||||
? Optional.<Recipient>empty()
|
||||
: findByNameLocked(address.getNumber().get());
|
||||
final var byUuid = !address.getUuid().isPresent()
|
||||
: findByNumberLocked(address.getNumber().get());
|
||||
final var byUuid = address.getUuid().isEmpty() || address.getUuid().get().equals(UuidUtil.UNKNOWN_UUID)
|
||||
? Optional.<Recipient>empty()
|
||||
: findByUuidLocked(address.getUuid().get());
|
||||
|
||||
if (byNumber.isEmpty() && byUuid.isEmpty()) {
|
||||
logger.debug("Got new recipient, both uuid and number are unknown");
|
||||
|
||||
if (isHighTrust || !address.getUuid().isPresent() || !address.getNumber().isPresent()) {
|
||||
if (isHighTrust || address.getUuid().isEmpty() || address.getNumber().isEmpty()) {
|
||||
return new Pair<>(addNewRecipientLocked(address), Optional.empty());
|
||||
}
|
||||
|
||||
return new Pair<>(addNewRecipientLocked(new SignalServiceAddress(address.getUuid().get(), null)),
|
||||
Optional.empty());
|
||||
return new Pair<>(addNewRecipientLocked(new RecipientAddress(address.getUuid().get())), Optional.empty());
|
||||
}
|
||||
|
||||
if (!isHighTrust
|
||||
|| !address.getUuid().isPresent()
|
||||
|| !address.getNumber().isPresent()
|
||||
|| byNumber.equals(byUuid)) {
|
||||
if (!isHighTrust || address.getUuid().isEmpty() || address.getNumber().isEmpty() || byNumber.equals(byUuid)) {
|
||||
return new Pair<>(byUuid.or(() -> byNumber).map(Recipient::getRecipientId).get(), Optional.empty());
|
||||
}
|
||||
|
||||
|
@ -317,7 +338,7 @@ public class RecipientStore implements ContactsStore, ProfileStore {
|
|||
"Got recipient existing with number, but different uuid, so stripping its number and adding new recipient");
|
||||
|
||||
updateRecipientAddressLocked(byNumber.get().getRecipientId(),
|
||||
new SignalServiceAddress(byNumber.get().getAddress().getUuid().get(), null));
|
||||
new RecipientAddress(byNumber.get().getAddress().getUuid().get()));
|
||||
return new Pair<>(addNewRecipientLocked(address), Optional.empty());
|
||||
}
|
||||
|
||||
|
@ -331,7 +352,7 @@ public class RecipientStore implements ContactsStore, ProfileStore {
|
|||
"Got separate recipients for high trust number and uuid, recipient for number has different uuid, so stripping its number");
|
||||
|
||||
updateRecipientAddressLocked(byNumber.get().getRecipientId(),
|
||||
new SignalServiceAddress(byNumber.get().getAddress().getUuid().get(), null));
|
||||
new RecipientAddress(byNumber.get().getAddress().getUuid().get()));
|
||||
updateRecipientAddressLocked(byUuid.get().getRecipientId(), address);
|
||||
return new Pair<>(byUuid.get().getRecipientId(), Optional.empty());
|
||||
}
|
||||
|
@ -342,14 +363,14 @@ public class RecipientStore implements ContactsStore, ProfileStore {
|
|||
return new Pair<>(byUuid.get().getRecipientId(), byNumber.map(Recipient::getRecipientId));
|
||||
}
|
||||
|
||||
private RecipientId addNewRecipientLocked(final SignalServiceAddress serviceAddress) {
|
||||
private RecipientId addNewRecipientLocked(final RecipientAddress address) {
|
||||
final var nextRecipientId = nextIdLocked();
|
||||
storeRecipientLocked(nextRecipientId, new Recipient(nextRecipientId, serviceAddress, null, null, null, null));
|
||||
storeRecipientLocked(nextRecipientId, new Recipient(nextRecipientId, address, null, null, null, null));
|
||||
return nextRecipientId;
|
||||
}
|
||||
|
||||
private void updateRecipientAddressLocked(
|
||||
final RecipientId recipientId, final SignalServiceAddress address
|
||||
final RecipientId recipientId, final RecipientAddress address
|
||||
) {
|
||||
final var recipient = recipients.get(recipientId);
|
||||
storeRecipientLocked(recipientId, Recipient.newBuilder(recipient).withAddress(address).build());
|
||||
|
@ -380,7 +401,7 @@ public class RecipientStore implements ContactsStore, ProfileStore {
|
|||
saveLocked();
|
||||
}
|
||||
|
||||
private Optional<Recipient> findByNameLocked(final String number) {
|
||||
private Optional<Recipient> findByNumberLocked(final String number) {
|
||||
return recipients.entrySet()
|
||||
.stream()
|
||||
.filter(entry -> entry.getValue().getAddress().getNumber().isPresent() && number.equals(entry.getValue()
|
||||
|
@ -431,8 +452,8 @@ public class RecipientStore implements ContactsStore, ProfileStore {
|
|||
.map(Enum::name)
|
||||
.collect(Collectors.toSet()));
|
||||
return new Storage.Recipient(pair.getKey().getId(),
|
||||
recipient.getAddress().getNumber().orNull(),
|
||||
recipient.getAddress().getUuid().transform(UUID::toString).orNull(),
|
||||
recipient.getAddress().getNumber().orElse(null),
|
||||
recipient.getAddress().getUuid().map(UUID::toString).orElse(null),
|
||||
recipient.getProfileKey() == null
|
||||
? null
|
||||
: base64.encodeToString(recipient.getProfileKey().serialize()),
|
||||
|
|
|
@ -3,7 +3,6 @@ package org.asamk.signal.manager.storage.sessions;
|
|||
import org.asamk.signal.manager.storage.recipients.RecipientId;
|
||||
import org.asamk.signal.manager.storage.recipients.RecipientResolver;
|
||||
import org.asamk.signal.manager.util.IOUtils;
|
||||
import org.asamk.signal.manager.util.Utils;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.whispersystems.libsignal.NoSessionException;
|
||||
|
@ -23,6 +22,7 @@ import java.util.HashMap;
|
|||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
import java.util.stream.Collectors;
|
||||
|
@ -150,6 +150,19 @@ public class SessionStore implements SignalServiceSessionStore {
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<SignalProtocolAddress> getAllAddressesWithActiveSessions(final List<String> addressNames) {
|
||||
final var recipientIdToNameMap = addressNames.stream()
|
||||
.collect(Collectors.toMap(this::resolveRecipient, name -> name));
|
||||
synchronized (cachedSessions) {
|
||||
return recipientIdToNameMap.keySet()
|
||||
.stream()
|
||||
.flatMap(recipientId -> getKeysLocked(recipientId).stream())
|
||||
.map(key -> new SignalProtocolAddress(recipientIdToNameMap.get(key.recipientId), key.getDeviceId()))
|
||||
.collect(Collectors.toSet());
|
||||
}
|
||||
}
|
||||
|
||||
public void archiveAllSessions() {
|
||||
synchronized (cachedSessions) {
|
||||
final var keys = getKeysLocked();
|
||||
|
@ -198,7 +211,7 @@ public class SessionStore implements SignalServiceSessionStore {
|
|||
* @param identifier can be either a serialized uuid or a e164 phone number
|
||||
*/
|
||||
private RecipientId resolveRecipient(String identifier) {
|
||||
return resolver.resolveRecipient(Utils.getSignalServiceAddressFromIdentifier(identifier));
|
||||
return resolver.resolveRecipient(identifier);
|
||||
}
|
||||
|
||||
private Key getKey(final SignalProtocolAddress address) {
|
||||
|
|
|
@ -48,11 +48,11 @@ public class Utils {
|
|||
byte[] ownId;
|
||||
byte[] theirId;
|
||||
|
||||
if (isUuidCapable && ownAddress.getUuid().isPresent() && theirAddress.getUuid().isPresent()) {
|
||||
if (isUuidCapable) {
|
||||
// Version 2: UUID user
|
||||
version = 2;
|
||||
ownId = UuidUtil.toByteArray(ownAddress.getUuid().get());
|
||||
theirId = UuidUtil.toByteArray(theirAddress.getUuid().get());
|
||||
ownId = UuidUtil.toByteArray(ownAddress.getUuid());
|
||||
theirId = UuidUtil.toByteArray(theirAddress.getUuid());
|
||||
} else {
|
||||
// Version 1: E164 user
|
||||
version = 1;
|
||||
|
@ -69,12 +69,4 @@ public class Utils {
|
|||
theirId,
|
||||
theirIdentityKey);
|
||||
}
|
||||
|
||||
public static SignalServiceAddress getSignalServiceAddressFromIdentifier(final String identifier) {
|
||||
if (UuidUtil.isUuid(identifier)) {
|
||||
return new SignalServiceAddress(UuidUtil.parseOrNull(identifier), null);
|
||||
} else {
|
||||
return new SignalServiceAddress(null, identifier);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -136,8 +136,8 @@ run_main -u "$NUMBER_2" listGroups -d
|
|||
run_main -u "$NUMBER_2" --output=json listGroups -d
|
||||
run_main -u "$NUMBER_1" receive
|
||||
run_main -u "$NUMBER_1" updateGroup -g "$GROUP_ID" -m "$NUMBER_2"
|
||||
run_main -u "$NUMBER_1" block "$GROUP_ID"
|
||||
run_main -u "$NUMBER_1" unblock "$GROUP_ID"
|
||||
run_main -u "$NUMBER_1" --verbose block -g "$GROUP_ID"
|
||||
run_main -u "$NUMBER_1" --verbose unblock -g "$GROUP_ID"
|
||||
|
||||
## Identities
|
||||
run_main -u "$NUMBER_1" listIdentities
|
||||
|
|
|
@ -45,7 +45,7 @@ public class JsonDbusReceiveMessageHandler extends JsonReceiveMessageHandler {
|
|||
e.printStackTrace();
|
||||
}
|
||||
} else if (content != null) {
|
||||
final var sender = !envelope.isUnidentifiedSender() && envelope.hasSource()
|
||||
final var sender = !envelope.isUnidentifiedSender() && envelope.hasSourceUuid()
|
||||
? envelope.getSourceAddress()
|
||||
: content.getSender();
|
||||
if (content.getReceiptMessage().isPresent()) {
|
||||
|
|
|
@ -1,12 +1,12 @@
|
|||
package org.asamk.signal;
|
||||
|
||||
import org.asamk.signal.manager.Manager;
|
||||
import org.asamk.signal.manager.UntrustedIdentityException;
|
||||
import org.asamk.signal.manager.api.RecipientIdentifier;
|
||||
import org.asamk.signal.manager.groups.GroupId;
|
||||
import org.asamk.signal.manager.groups.GroupUtils;
|
||||
import org.asamk.signal.util.DateUtils;
|
||||
import org.asamk.signal.util.Util;
|
||||
import org.signal.libsignal.metadata.ProtocolUntrustedIdentityException;
|
||||
import org.slf4j.helpers.MessageFormatter;
|
||||
import org.whispersystems.signalservice.api.messages.SignalServiceAttachment;
|
||||
import org.whispersystems.signalservice.api.messages.SignalServiceContent;
|
||||
|
@ -38,12 +38,9 @@ public class ReceiveMessageHandler implements Manager.ReceiveMessageHandler {
|
|||
|
||||
@Override
|
||||
public void handleMessage(SignalServiceEnvelope envelope, SignalServiceContent content, Throwable exception) {
|
||||
if (envelope.hasSource()) {
|
||||
if (envelope.hasSourceUuid()) {
|
||||
var source = envelope.getSourceAddress();
|
||||
writer.println("Envelope from: {} (device: {})", formatContact(source), envelope.getSourceDevice());
|
||||
if (source.getRelay().isPresent()) {
|
||||
writer.println("Relayed by: {}", source.getRelay().get());
|
||||
}
|
||||
} else {
|
||||
writer.println("Envelope from: unknown source");
|
||||
}
|
||||
|
@ -56,8 +53,8 @@ public class ReceiveMessageHandler implements Manager.ReceiveMessageHandler {
|
|||
writer.println("Got receipt.");
|
||||
} else if (envelope.isSignalMessage() || envelope.isPreKeySignalMessage() || envelope.isUnidentifiedSender()) {
|
||||
if (exception != null) {
|
||||
if (exception instanceof ProtocolUntrustedIdentityException) {
|
||||
var e = (ProtocolUntrustedIdentityException) exception;
|
||||
if (exception instanceof UntrustedIdentityException) {
|
||||
var e = (UntrustedIdentityException) exception;
|
||||
writer.println(
|
||||
"The user’s key is untrusted, either the user has reinstalled Signal or a third party sent this message.");
|
||||
final var recipientName = getLegacyIdentifier(m.resolveSignalServiceAddress(e.getSender()));
|
||||
|
@ -630,7 +627,7 @@ public class ReceiveMessageHandler implements Manager.ReceiveMessageHandler {
|
|||
private void printMention(
|
||||
PlainTextWriter writer, SignalServiceDataMessage.Mention mention
|
||||
) {
|
||||
final var address = m.resolveSignalServiceAddress(new SignalServiceAddress(mention.getUuid(), null));
|
||||
final var address = m.resolveSignalServiceAddress(mention.getUuid());
|
||||
writer.println("- {}: {} (length: {})", formatContact(address), mention.getStart(), mention.getLength());
|
||||
}
|
||||
|
||||
|
|
|
@ -74,9 +74,14 @@ public class JoinGroupCommand implements JsonRpcLocalCommand {
|
|||
} catch (GroupPatchNotAcceptedException e) {
|
||||
throw new UserErrorException("Failed to join group, maybe already a member");
|
||||
} catch (IOException e) {
|
||||
throw new IOErrorException("Failed to send message: " + e.getMessage());
|
||||
throw new IOErrorException("Failed to send message: "
|
||||
+ e.getMessage()
|
||||
+ " ("
|
||||
+ e.getClass().getSimpleName()
|
||||
+ ")");
|
||||
} catch (DBusExecutionException e) {
|
||||
throw new UnexpectedErrorException("Failed to send message: " + e.getMessage());
|
||||
throw new UnexpectedErrorException("Failed to send message: " + e.getMessage() + " (" + e.getClass()
|
||||
.getSimpleName() + ")");
|
||||
} catch (GroupLinkNotActiveException e) {
|
||||
throw new UserErrorException("Group link is not valid: " + e.getMessage());
|
||||
}
|
||||
|
|
|
@ -8,7 +8,6 @@ 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;
|
||||
|
@ -47,7 +46,7 @@ public class ListContactsCommand implements JsonRpcLocalCommand {
|
|||
final var address = m.resolveSignalServiceAddress(contactPair.first());
|
||||
final var contact = contactPair.second();
|
||||
return new JsonContact(address.getNumber().orNull(),
|
||||
address.getUuid().transform(UUID::toString).orNull(),
|
||||
address.getUuid().toString(),
|
||||
contact.getName(),
|
||||
contact.isBlocked(),
|
||||
contact.getMessageExpirationTime());
|
||||
|
|
|
@ -16,7 +16,6 @@ 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 {
|
||||
|
@ -46,8 +45,7 @@ public class ListGroupsCommand implements JsonRpcLocalCommand {
|
|||
private static Set<JsonGroupMember> resolveJsonMembers(Manager m, Set<RecipientId> addresses) {
|
||||
return addresses.stream()
|
||||
.map(m::resolveSignalServiceAddress)
|
||||
.map(address -> new JsonGroupMember(address.getNumber().orNull(),
|
||||
address.getUuid().transform(UUID::toString).orNull()))
|
||||
.map(address -> new JsonGroupMember(address.getNumber().orNull(), address.getUuid().toString()))
|
||||
.collect(Collectors.toSet());
|
||||
}
|
||||
|
||||
|
|
|
@ -18,7 +18,6 @@ import org.whispersystems.signalservice.api.push.SignalServiceAddress;
|
|||
|
||||
import java.util.Base64;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class ListIdentitiesCommand implements JsonRpcLocalCommand {
|
||||
|
@ -72,7 +71,7 @@ public class ListIdentitiesCommand implements JsonRpcLocalCommand {
|
|||
var safetyNumber = Util.formatSafetyNumber(m.computeSafetyNumber(address, id.getIdentityKey()));
|
||||
var scannableSafetyNumber = m.computeSafetyNumberForScanning(address, id.getIdentityKey());
|
||||
return new JsonIdentity(address.getNumber().orNull(),
|
||||
address.getUuid().transform(UUID::toString).orNull(),
|
||||
address.getUuid().toString(),
|
||||
Hex.toString(id.getFingerprint()),
|
||||
safetyNumber,
|
||||
scannableSafetyNumber == null
|
||||
|
|
|
@ -66,7 +66,11 @@ public class QuitGroupCommand implements JsonRpcLocalCommand {
|
|||
m.deleteGroup(groupId);
|
||||
}
|
||||
} catch (IOException e) {
|
||||
throw new IOErrorException("Failed to send message: " + e.getMessage());
|
||||
throw new IOErrorException("Failed to send message: "
|
||||
+ e.getMessage()
|
||||
+ " ("
|
||||
+ e.getClass().getSimpleName()
|
||||
+ ")");
|
||||
} catch (GroupNotFoundException e) {
|
||||
throw new UserErrorException("Failed to send to group: " + e.getMessage());
|
||||
} catch (LastGroupAdminException e) {
|
||||
|
|
|
@ -64,7 +64,8 @@ public class RemoteDeleteCommand implements DbusCommand, JsonRpcLocalCommand {
|
|||
} catch (GroupNotFoundException | NotAGroupMemberException | GroupSendingNotAllowedException e) {
|
||||
throw new UserErrorException(e.getMessage());
|
||||
} catch (IOException e) {
|
||||
throw new UnexpectedErrorException("Failed to send message: " + e.getMessage());
|
||||
throw new UnexpectedErrorException("Failed to send message: " + e.getMessage() + " (" + e.getClass()
|
||||
.getSimpleName() + ")");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -104,7 +105,8 @@ public class RemoteDeleteCommand implements DbusCommand, JsonRpcLocalCommand {
|
|||
} catch (Signal.Error.GroupNotFound e) {
|
||||
throw new UserErrorException("Failed to send to group: " + e.getMessage());
|
||||
} catch (DBusExecutionException e) {
|
||||
throw new UnexpectedErrorException("Failed to send message: " + e.getMessage());
|
||||
throw new UnexpectedErrorException("Failed to send message: " + e.getMessage() + " (" + e.getClass()
|
||||
.getSimpleName() + ")");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -85,7 +85,8 @@ public class SendCommand implements DbusCommand, JsonRpcLocalCommand {
|
|||
m.sendEndSessionMessage(singleRecipients);
|
||||
return;
|
||||
} catch (IOException e) {
|
||||
throw new UnexpectedErrorException("Failed to send message: " + e.getMessage());
|
||||
throw new UnexpectedErrorException("Failed to send message: " + e.getMessage() + " (" + e.getClass()
|
||||
.getSimpleName() + ")");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -108,7 +109,8 @@ public class SendCommand implements DbusCommand, JsonRpcLocalCommand {
|
|||
outputResult(outputWriter, results.getTimestamp());
|
||||
ErrorUtils.handleSendMessageResults(results.getResults());
|
||||
} catch (AttachmentInvalidException | IOException e) {
|
||||
throw new UnexpectedErrorException("Failed to send message: " + e.getMessage());
|
||||
throw new UnexpectedErrorException("Failed to send message: " + e.getMessage() + " (" + e.getClass()
|
||||
.getSimpleName() + ")");
|
||||
} catch (GroupNotFoundException | NotAGroupMemberException | GroupSendingNotAllowedException e) {
|
||||
throw new UserErrorException(e.getMessage());
|
||||
}
|
||||
|
@ -141,9 +143,11 @@ public class SendCommand implements DbusCommand, JsonRpcLocalCommand {
|
|||
signal.sendEndSessionMessage(recipients);
|
||||
return;
|
||||
} catch (Signal.Error.UntrustedIdentity e) {
|
||||
throw new UntrustedKeyErrorException("Failed to send message: " + e.getMessage());
|
||||
throw new UntrustedKeyErrorException("Failed to send message: " + e.getMessage() + " (" + e.getClass()
|
||||
.getSimpleName() + ")");
|
||||
} catch (DBusExecutionException e) {
|
||||
throw new UnexpectedErrorException("Failed to send message: " + e.getMessage());
|
||||
throw new UnexpectedErrorException("Failed to send message: " + e.getMessage() + " (" + e.getClass()
|
||||
.getSimpleName() + ")");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -182,7 +186,8 @@ public class SendCommand implements DbusCommand, JsonRpcLocalCommand {
|
|||
outputResult(outputWriter, timestamp);
|
||||
return;
|
||||
} catch (Signal.Error.UntrustedIdentity e) {
|
||||
throw new UntrustedKeyErrorException("Failed to send message: " + e.getMessage());
|
||||
throw new UntrustedKeyErrorException("Failed to send message: " + e.getMessage() + " (" + e.getClass()
|
||||
.getSimpleName() + ")");
|
||||
} catch (DBusExecutionException e) {
|
||||
throw new UnexpectedErrorException("Failed to send note to self message: " + e.getMessage());
|
||||
}
|
||||
|
@ -194,9 +199,11 @@ public class SendCommand implements DbusCommand, JsonRpcLocalCommand {
|
|||
} catch (UnknownObject e) {
|
||||
throw new UserErrorException("Failed to find dbus object, maybe missing the -u flag: " + e.getMessage());
|
||||
} catch (Signal.Error.UntrustedIdentity e) {
|
||||
throw new UntrustedKeyErrorException("Failed to send message: " + e.getMessage());
|
||||
throw new UntrustedKeyErrorException("Failed to send message: " + e.getMessage() + " (" + e.getClass()
|
||||
.getSimpleName() + ")");
|
||||
} catch (DBusExecutionException e) {
|
||||
throw new UnexpectedErrorException("Failed to send message: " + e.getMessage());
|
||||
throw new UnexpectedErrorException("Failed to send message: " + e.getMessage() + " (" + e.getClass()
|
||||
.getSimpleName() + ")");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -80,7 +80,8 @@ public class SendReactionCommand implements DbusCommand, JsonRpcLocalCommand {
|
|||
} catch (GroupNotFoundException | NotAGroupMemberException | GroupSendingNotAllowedException e) {
|
||||
throw new UserErrorException(e.getMessage());
|
||||
} catch (IOException e) {
|
||||
throw new UnexpectedErrorException("Failed to send message: " + e.getMessage());
|
||||
throw new UnexpectedErrorException("Failed to send message: " + e.getMessage() + " (" + e.getClass()
|
||||
.getSimpleName() + ")");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -127,7 +128,8 @@ public class SendReactionCommand implements DbusCommand, JsonRpcLocalCommand {
|
|||
} catch (Signal.Error.GroupNotFound e) {
|
||||
throw new UserErrorException("Failed to send to group: " + e.getMessage());
|
||||
} catch (DBusExecutionException e) {
|
||||
throw new UnexpectedErrorException("Failed to send message: " + e.getMessage());
|
||||
throw new UnexpectedErrorException("Failed to send message: " + e.getMessage() + " (" + e.getClass()
|
||||
.getSimpleName() + ")");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -7,8 +7,8 @@ import org.asamk.signal.OutputWriter;
|
|||
import org.asamk.signal.commands.exceptions.CommandException;
|
||||
import org.asamk.signal.commands.exceptions.UserErrorException;
|
||||
import org.asamk.signal.manager.Manager;
|
||||
import org.asamk.signal.manager.UntrustedIdentityException;
|
||||
import org.asamk.signal.util.CommandUtil;
|
||||
import org.whispersystems.signalservice.api.crypto.UntrustedIdentityException;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
|
@ -51,7 +51,8 @@ public class SendReceiptCommand implements JsonRpcLocalCommand {
|
|||
throw new UserErrorException("Unknown receipt type: " + type);
|
||||
}
|
||||
} catch (IOException | UntrustedIdentityException e) {
|
||||
throw new UserErrorException("Failed to send message: " + e.getMessage());
|
||||
throw new UserErrorException("Failed to send message: " + e.getMessage() + " (" + e.getClass()
|
||||
.getSimpleName() + ")");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,13 +8,13 @@ import org.asamk.signal.OutputWriter;
|
|||
import org.asamk.signal.commands.exceptions.CommandException;
|
||||
import org.asamk.signal.commands.exceptions.UserErrorException;
|
||||
import org.asamk.signal.manager.Manager;
|
||||
import org.asamk.signal.manager.UntrustedIdentityException;
|
||||
import org.asamk.signal.manager.api.RecipientIdentifier;
|
||||
import org.asamk.signal.manager.api.TypingAction;
|
||||
import org.asamk.signal.manager.groups.GroupNotFoundException;
|
||||
import org.asamk.signal.manager.groups.GroupSendingNotAllowedException;
|
||||
import org.asamk.signal.manager.groups.NotAGroupMemberException;
|
||||
import org.asamk.signal.util.CommandUtil;
|
||||
import org.whispersystems.signalservice.api.crypto.UntrustedIdentityException;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.HashSet;
|
||||
|
@ -59,7 +59,8 @@ public class SendTypingCommand implements JsonRpcLocalCommand {
|
|||
try {
|
||||
m.sendTypingMessage(action, recipientIdentifiers);
|
||||
} catch (IOException | UntrustedIdentityException e) {
|
||||
throw new UserErrorException("Failed to send message: " + e.getMessage());
|
||||
throw new UserErrorException("Failed to send message: " + e.getMessage() + " (" + e.getClass()
|
||||
.getSimpleName() + ")");
|
||||
} catch (GroupNotFoundException | NotAGroupMemberException | GroupSendingNotAllowedException e) {
|
||||
throw new UserErrorException("Failed to send to group: " + e.getMessage());
|
||||
}
|
||||
|
|
|
@ -174,7 +174,8 @@ public class UpdateGroupCommand implements DbusCommand, JsonRpcLocalCommand {
|
|||
} catch (GroupNotFoundException | NotAGroupMemberException | GroupSendingNotAllowedException e) {
|
||||
throw new UserErrorException(e.getMessage());
|
||||
} catch (IOException e) {
|
||||
throw new UnexpectedErrorException("Failed to send message: " + e.getMessage());
|
||||
throw new UnexpectedErrorException("Failed to send message: " + e.getMessage() + " (" + e.getClass()
|
||||
.getSimpleName() + ")");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -210,7 +211,8 @@ public class UpdateGroupCommand implements DbusCommand, JsonRpcLocalCommand {
|
|||
} catch (Signal.Error.AttachmentInvalid e) {
|
||||
throw new UserErrorException("Failed to add avatar attachment for group\": " + e.getMessage());
|
||||
} catch (DBusExecutionException e) {
|
||||
throw new UnexpectedErrorException("Failed to send message: " + e.getMessage());
|
||||
throw new UnexpectedErrorException("Failed to send message: " + e.getMessage() + " (" + e.getClass()
|
||||
.getSimpleName() + ")");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -21,6 +21,7 @@ import org.whispersystems.libsignal.util.Pair;
|
|||
import org.whispersystems.libsignal.util.guava.Optional;
|
||||
import org.whispersystems.signalservice.api.groupsv2.GroupLinkNotActiveException;
|
||||
import org.whispersystems.signalservice.api.messages.SendMessageResult;
|
||||
import org.whispersystems.signalservice.api.push.exceptions.UnregisteredUserException;
|
||||
import org.whispersystems.signalservice.api.util.InvalidNumberException;
|
||||
|
||||
import java.io.File;
|
||||
|
@ -244,6 +245,8 @@ public class DbusSignalImpl implements Signal {
|
|||
m.setContactName(getSingleRecipientIdentifier(number, m.getUsername()), name);
|
||||
} catch (NotMasterDeviceException e) {
|
||||
throw new Error.Failure("This command doesn't work on linked devices.");
|
||||
} catch (UnregisteredUserException e) {
|
||||
throw new Error.Failure("Contact is not registered.");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -4,9 +4,6 @@ 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 java.util.UUID;
|
||||
|
||||
import static org.asamk.signal.util.Util.getLegacyIdentifier;
|
||||
|
||||
|
@ -29,10 +26,10 @@ public class JsonMention {
|
|||
final int length;
|
||||
|
||||
JsonMention(SignalServiceDataMessage.Mention mention, Manager m) {
|
||||
final var address = m.resolveSignalServiceAddress(new SignalServiceAddress(mention.getUuid(), null));
|
||||
final var address = m.resolveSignalServiceAddress(mention.getUuid());
|
||||
this.name = getLegacyIdentifier(address);
|
||||
this.number = address.getNumber().orNull();
|
||||
this.uuid = address.getUuid().transform(UUID::toString).orNull();
|
||||
this.uuid = address.getUuid().toString();
|
||||
this.start = mention.getStart();
|
||||
this.length = mention.getLength();
|
||||
}
|
||||
|
|
|
@ -5,14 +5,13 @@ import com.fasterxml.jackson.annotation.JsonProperty;
|
|||
|
||||
import org.asamk.Signal;
|
||||
import org.asamk.signal.manager.Manager;
|
||||
import org.asamk.signal.manager.UntrustedIdentityException;
|
||||
import org.asamk.signal.manager.api.RecipientIdentifier;
|
||||
import org.signal.libsignal.metadata.ProtocolUntrustedIdentityException;
|
||||
import org.whispersystems.signalservice.api.messages.SignalServiceContent;
|
||||
import org.whispersystems.signalservice.api.messages.SignalServiceEnvelope;
|
||||
import org.whispersystems.signalservice.api.util.InvalidNumberException;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
|
||||
import static org.asamk.signal.util.Util.getLegacyIdentifier;
|
||||
|
||||
|
@ -34,10 +33,6 @@ public class JsonMessageEnvelope {
|
|||
@JsonProperty
|
||||
final Integer sourceDevice;
|
||||
|
||||
@JsonProperty
|
||||
@JsonInclude(JsonInclude.Include.NON_NULL)
|
||||
final String relay;
|
||||
|
||||
@JsonProperty
|
||||
final long timestamp;
|
||||
|
||||
|
@ -64,34 +59,30 @@ public class JsonMessageEnvelope {
|
|||
public JsonMessageEnvelope(
|
||||
SignalServiceEnvelope envelope, SignalServiceContent content, Throwable exception, Manager m
|
||||
) {
|
||||
if (!envelope.isUnidentifiedSender() && envelope.hasSource()) {
|
||||
var source = envelope.getSourceAddress();
|
||||
if (!envelope.isUnidentifiedSender() && envelope.hasSourceUuid()) {
|
||||
var source = m.resolveSignalServiceAddress(envelope.getSourceAddress());
|
||||
this.source = getLegacyIdentifier(source);
|
||||
this.sourceNumber = source.getNumber().orNull();
|
||||
this.sourceUuid = source.getUuid().transform(UUID::toString).orNull();
|
||||
this.sourceUuid = source.getUuid().toString();
|
||||
this.sourceDevice = envelope.getSourceDevice();
|
||||
this.relay = source.getRelay().orNull();
|
||||
} else if (envelope.isUnidentifiedSender() && content != null) {
|
||||
final var source = content.getSender();
|
||||
final var source = m.resolveSignalServiceAddress(content.getSender());
|
||||
this.source = getLegacyIdentifier(source);
|
||||
this.sourceNumber = source.getNumber().orNull();
|
||||
this.sourceUuid = source.getUuid().transform(UUID::toString).orNull();
|
||||
this.sourceUuid = source.getUuid().toString();
|
||||
this.sourceDevice = content.getSenderDevice();
|
||||
this.relay = null;
|
||||
} else if (exception instanceof ProtocolUntrustedIdentityException) {
|
||||
var e = (ProtocolUntrustedIdentityException) exception;
|
||||
} else if (exception instanceof UntrustedIdentityException) {
|
||||
var e = (UntrustedIdentityException) exception;
|
||||
final var source = m.resolveSignalServiceAddress(e.getSender());
|
||||
this.source = getLegacyIdentifier(source);
|
||||
this.sourceNumber = source.getNumber().orNull();
|
||||
this.sourceUuid = source.getUuid().transform(UUID::toString).orNull();
|
||||
this.sourceUuid = source.getUuid().toString();
|
||||
this.sourceDevice = e.getSenderDevice();
|
||||
this.relay = null;
|
||||
} else {
|
||||
this.source = null;
|
||||
this.sourceNumber = null;
|
||||
this.sourceUuid = null;
|
||||
this.sourceDevice = null;
|
||||
this.relay = null;
|
||||
}
|
||||
String name;
|
||||
try {
|
||||
|
@ -129,7 +120,6 @@ public class JsonMessageEnvelope {
|
|||
sourceUuid = null;
|
||||
sourceName = null;
|
||||
sourceDevice = null;
|
||||
relay = null;
|
||||
timestamp = messageReceived.getTimestamp();
|
||||
receiptMessage = null;
|
||||
dataMessage = new JsonDataMessage(messageReceived);
|
||||
|
@ -144,7 +134,6 @@ public class JsonMessageEnvelope {
|
|||
sourceUuid = null;
|
||||
sourceName = null;
|
||||
sourceDevice = null;
|
||||
relay = null;
|
||||
timestamp = receiptReceived.getTimestamp();
|
||||
receiptMessage = JsonReceiptMessage.deliveryReceipt(timestamp, List.of(timestamp));
|
||||
dataMessage = null;
|
||||
|
@ -159,7 +148,6 @@ public class JsonMessageEnvelope {
|
|||
sourceUuid = null;
|
||||
sourceName = null;
|
||||
sourceDevice = null;
|
||||
relay = null;
|
||||
timestamp = messageReceived.getTimestamp();
|
||||
receiptMessage = null;
|
||||
dataMessage = null;
|
||||
|
|
|
@ -8,7 +8,6 @@ import org.whispersystems.signalservice.api.messages.SignalServiceDataMessage;
|
|||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static org.asamk.signal.util.Util.getLegacyIdentifier;
|
||||
|
@ -43,7 +42,7 @@ public class JsonQuote {
|
|||
final var address = m.resolveSignalServiceAddress(quote.getAuthor());
|
||||
this.author = getLegacyIdentifier(address);
|
||||
this.authorNumber = address.getNumber().orNull();
|
||||
this.authorUuid = address.getUuid().transform(UUID::toString).orNull();
|
||||
this.authorUuid = address.getUuid().toString();
|
||||
this.text = quote.getText();
|
||||
|
||||
if (quote.getMentions() != null && quote.getMentions().size() > 0) {
|
||||
|
|
|
@ -5,8 +5,6 @@ import com.fasterxml.jackson.annotation.JsonProperty;
|
|||
import org.asamk.signal.manager.Manager;
|
||||
import org.whispersystems.signalservice.api.messages.SignalServiceDataMessage.Reaction;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
import static org.asamk.signal.util.Util.getLegacyIdentifier;
|
||||
|
||||
public class JsonReaction {
|
||||
|
@ -35,7 +33,7 @@ public class JsonReaction {
|
|||
final var address = m.resolveSignalServiceAddress(reaction.getTargetAuthor());
|
||||
this.targetAuthor = getLegacyIdentifier(address);
|
||||
this.targetAuthorNumber = address.getNumber().orNull();
|
||||
this.targetAuthorUuid = address.getUuid().transform(UUID::toString).orNull();
|
||||
this.targetAuthorUuid = address.getUuid().toString();
|
||||
this.targetSentTimestamp = reaction.getTargetSentTimestamp();
|
||||
this.isRemove = reaction.isRemove();
|
||||
}
|
||||
|
|
|
@ -6,8 +6,6 @@ import org.asamk.Signal;
|
|||
import org.asamk.signal.manager.Manager;
|
||||
import org.whispersystems.signalservice.api.messages.multidevice.SentTranscriptMessage;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
import static org.asamk.signal.util.Util.getLegacyIdentifier;
|
||||
|
||||
class JsonSyncDataMessage extends JsonDataMessage {
|
||||
|
@ -29,7 +27,7 @@ class JsonSyncDataMessage extends JsonDataMessage {
|
|||
final var address = transcriptMessage.getDestination().get();
|
||||
this.destination = getLegacyIdentifier(address);
|
||||
this.destinationNumber = address.getNumber().orNull();
|
||||
this.destinationUuid = address.getUuid().transform(UUID::toString).orNull();
|
||||
this.destinationUuid = address.getUuid().toString();
|
||||
} else {
|
||||
this.destination = null;
|
||||
this.destinationNumber = null;
|
||||
|
|
|
@ -4,8 +4,6 @@ import com.fasterxml.jackson.annotation.JsonProperty;
|
|||
|
||||
import org.whispersystems.signalservice.api.messages.multidevice.ReadMessage;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
import static org.asamk.signal.util.Util.getLegacyIdentifier;
|
||||
|
||||
class JsonSyncReadMessage {
|
||||
|
@ -27,7 +25,7 @@ class JsonSyncReadMessage {
|
|||
final var sender = readMessage.getSender();
|
||||
this.sender = getLegacyIdentifier(sender);
|
||||
this.senderNumber = sender.getNumber().orNull();
|
||||
this.senderUuid = sender.getUuid().transform(UUID::toString).orNull();
|
||||
this.senderUuid = sender.getUuid().toString();
|
||||
this.timestamp = readMessage.getTimestamp();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -60,7 +60,7 @@ public class Util {
|
|||
}
|
||||
|
||||
public static String getLegacyIdentifier(final SignalServiceAddress address) {
|
||||
return address.getNumber().or(() -> address.getUuid().get().toString());
|
||||
return address.getNumber().or(() -> address.getUuid().toString());
|
||||
}
|
||||
|
||||
public static ObjectMapper createJsonObjectMapper() {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue