}
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")
}
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) {
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;
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;
dependencies,
unidentifiedAccessHelper,
this::resolveSignalServiceAddress,
- this::resolveRecipient,
+ account.getRecipientStore(),
this::handleIdentityFailure,
this::getGroup,
this::refreshRegisteredUser);
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(),
this.incomingMessageHandler = new IncomingMessageHandler(account,
dependencies,
- this::resolveRecipient,
+ account.getRecipientStore(),
+ this::resolveSignalServiceAddress,
groupHelper,
contactHelper,
attachmentHelper,
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 "";
}
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);
}
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(
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,
public void setContactName(
RecipientIdentifier.Single recipient, String name
- ) throws NotMasterDeviceException {
+ ) throws NotMasterDeviceException, UnregisteredUserException {
if (!account.isMasterDevice()) {
throw new NotMasterDeviceException();
}
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 {
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) {
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);
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) {
}
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);
}
}
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())) {
}
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);
}
* @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);
* @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);
* @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 {
* @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);
}
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());
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(RecipientId recipientId) {
- return account.getRecipientStore().resolveServiceAddress(recipientId);
+ public SignalServiceAddress resolveSignalServiceAddress(UUID uuid) {
+ return resolveSignalServiceAddress(account.getRecipientStore().resolveRecipient(uuid));
}
- private String canonicalizePhoneNumber(final String number) throws InvalidNumberException {
- return PhoneNumberFormatter.formatNumber(number, account.getUsername());
- }
+ public SignalServiceAddress resolveSignalServiceAddress(RecipientId recipientId) {
+ final var address = account.getRecipientStore().resolveRecipientAddress(recipientId);
+ if (address.getUuid().isPresent()) {
+ return address.toSignalServiceAddress();
+ }
- private RecipientId resolveRecipient(final String identifier) {
- var address = Utils.getSignalServiceAddressFromIdentifier(identifier);
+ // 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();
+ }
+ }
- return resolveRecipient(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) {
- final SignalServiceAddress address;
+ private RecipientId resolveRecipient(final RecipientIdentifier.Single recipient) throws UnregisteredUserException {
if (recipient instanceof RecipientIdentifier.Uuid) {
- address = new SignalServiceAddress(((RecipientIdentifier.Uuid) recipient).uuid, null);
+ return account.getRecipientStore().resolveRecipient(((RecipientIdentifier.Uuid) recipient).uuid);
} else {
- address = new SignalServiceAddress(null, ((RecipientIdentifier.Number) recipient).number);
+ final var number = ((RecipientIdentifier.Number) recipient).number;
+ return account.getRecipientStore().resolveRecipient(number, () -> {
+ try {
+ return getRegisteredUser(number);
+ } catch (IOException e) {
+ return null;
+ }
+ });
}
-
- return resolveRecipient(address);
}
- public RecipientId resolveRecipient(SignalServiceAddress address) {
+ private RecipientId resolveRecipient(SignalServiceAddress address) {
return account.getRecipientStore().resolveRecipient(address);
}
--- /dev/null
+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;
+ }
+}
}
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());
}
}
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());
}
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))
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);
}
}
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));
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()) {
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));
final var memberUuids = members.stream()
.map(addressResolver::resolveSignalServiceAddress)
.map(SignalServiceAddress::getUuid)
- .filter(Optional::isPresent)
- .map(Optional::get)
.collect(Collectors.toSet());
return ejectMembers(groupInfoV2, memberUuids);
}
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)
: groupOperations.createGroupJoinDirect(profileKeyCredential);
change.setSourceUuid(UuidUtil.toByteString(addressResolver.resolveSignalServiceAddress(selfRecipientId)
- .getUuid()
- .get()));
+ .getUuid()));
return commitChange(groupSecretParams, decryptedGroupJoinInfo.getRevision(), change, groupLinkPassword);
}
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);
}
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);
}
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);
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();
+ }
}
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;
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;
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;
final SignalAccount account,
final SignalDependencies dependencies,
final RecipientResolver recipientResolver,
+ final SignalServiceAddressResolver addressResolver,
final GroupHelper groupHelper,
final ContactHelper contactHelper,
final AttachmentHelper attachmentHelper,
this.account = account;
this.dependencies = dependencies;
this.recipientResolver = recipientResolver;
+ this.addressResolver = addressResolver;
this.groupHelper = groupHelper;
this.contactHelper = contactHelper;
this.attachmentHelper = attachmentHelper;
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());
} 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.");
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());
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));
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 (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 (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.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.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.getBlockedList().isPresent()) {
- final var blockedListMessage = syncMessage.getBlockedList().get();
- for (var address : blockedListMessage.getAddresses()) {
- contactHelper.setContactBlocked(recipientResolver.resolveRecipient(address), true);
+ 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());
}
- 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 (installed) {
+ jobExecutor.enqueueJob(new RetrieveStickerPackJob(stickerPackId, m.getPackKey().get()));
}
}
- 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;
-
- 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 (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 (sticker != null) {
+ sticker.setInstalled(installed);
+ account.getStickerStore().updateSticker(sticker);
}
- 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();
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();
private Single<ProfileAndCredential> retrieveProfile(
RecipientId recipientId, SignalServiceProfile.RequestType requestType
- ) throws IOException {
+ ) {
var unidentifiedAccess = getUnidentifiedAccess(recipientId);
var profileKey = Optional.fromNullable(profileKeyProvider.getProfileKey(recipientId));
Optional<ProfileKey> profileKey,
Optional<UnidentifiedAccess> unidentifiedAccess,
SignalServiceProfile.RequestType requestType
- ) throws IOException {
+ ) {
var profileService = profileServiceProvider.getProfileService();
Single<ServiceResponse<ProfileAndCredential>> responseSingle;
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 -> {
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;
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;
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,
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 {
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());
}
}
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());
}
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);
}
}
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();
}
}
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());
}
}
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;
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;
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 {
private final GroupHelper groupHelper;
private final AvatarStore avatarStore;
private final SignalServiceAddressResolver addressResolver;
- private final RecipientResolver recipientResolver;
public SyncHelper(
final SignalAccount account,
final SendHelper sendHelper,
final GroupHelper groupHelper,
final AvatarStore avatarStore,
- final SignalServiceAddressResolver addressResolver,
- final RecipientResolver recipientResolver
+ final SignalServiceAddressResolver addressResolver
) {
this.account = account;
this.attachmentHelper = attachmentHelper;
this.groupHelper = groupHelper;
this.avatarStore = avatarStore;
this.addressResolver = addressResolver;
- this.recipientResolver = recipientResolver;
}
public void requestAllSyncData() throws IOException {
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;
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);
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);
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);
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")) {
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();
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 {
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));
+ }
+ }
}
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;
}
@JsonIgnore
- public SignalServiceAddress getAddress() {
- return new SignalServiceAddress(uuid, number);
+ public RecipientAddress getAddress() {
+ return new RecipientAddress(uuid, number);
}
}
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;
}
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());
}
}
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());
}
}
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());
}
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());
}
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;
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;
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));
}
}
}
- 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;
}
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);
}
} 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));
}
}
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;
* @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) {
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;
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()));
}
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,
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;
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() {
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;
}
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;
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;
}
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());
}
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;
}
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);
}
}
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;
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);
public boolean isMultiDevice() {
return isMultiDevice.get();
}
+
+ @Override
+ public Transaction beginTransaction() {
+ return () -> {
+ // No-op transaction should be safe, as it's only a performance improvement
+ };
+ }
}
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;
@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));
}
}
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;
public Recipient(
final RecipientId recipientId,
- final SignalServiceAddress address,
+ final RecipientAddress address,
final Contact contact,
final ProfileKey profileKey,
final ProfileKeyCredential profileKeyCredential,
return recipientId;
}
- public SignalServiceAddress getAddress() {
+ public RecipientAddress getAddress() {
return address;
}
public static final class Builder {
private RecipientId recipientId;
- private SignalServiceAddress address;
+ private RecipientAddress address;
private Contact contact;
private ProfileKey profileKey;
private ProfileKeyCredential profileKeyCredential;
return this;
}
- public Builder withAddress(final SignalServiceAddress val) {
+ public Builder withAddress(final RecipientAddress val) {
address = val;
return this;
}
--- /dev/null
+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;
+ }
+}
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);
}
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;
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);
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) {
this.lastId = lastId;
}
- public SignalServiceAddress resolveServiceAddress(RecipientId recipientId) {
+ public RecipientAddress resolveRecipientAddress(RecipientId recipientId) {
synchronized (recipients) {
return getRecipient(recipientId).getAddress();
}
}
}
- @Deprecated
- public SignalServiceAddress resolveServiceAddress(SignalServiceAddress address) {
- return resolveServiceAddress(resolveRecipient(address, false));
+ @Override
+ public RecipientId resolveRecipient(UUID uuid) {
+ return resolveRecipient(new RecipientAddress(uuid), false);
}
- public RecipientId resolveRecipient(UUID uuid) {
- return resolveRecipient(new SignalServiceAddress(uuid, null), false);
+ @Override
+ public RecipientId resolveRecipient(final String identifier) {
+ return resolveRecipient(Utils.getRecipientAddressFromIdentifier(identifier), false);
}
- public RecipientId resolveRecipient(String number) {
- return resolveRecipient(new SignalServiceAddress(null, number), false);
+ 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 resolveRecipientTrusted(SignalServiceAddress address) {
+ 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) {
return recipientIds;
}
- public RecipientId resolveRecipient(SignalServiceAddress address) {
- return resolveRecipient(address, false);
- }
-
@Override
public void storeContact(final RecipientId recipientId, final Contact contact) {
synchronized (recipients) {
* @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);
}
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());
}
"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());
}
"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());
}
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());
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()
.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()),
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;
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;
}
}
+ @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();
* @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) {
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;
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);
- }
- }
}
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
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()) {
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;
@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");
}
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()));
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());
}
} 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());
}
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;
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());
import org.slf4j.LoggerFactory;
import java.util.Set;
-import java.util.UUID;
import java.util.stream.Collectors;
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());
}
import java.util.Base64;
import java.util.List;
-import java.util.UUID;
import java.util.stream.Collectors;
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
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) {
} 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() + ")");
}
}
} 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() + ")");
}
}
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() + ")");
}
}
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());
}
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() + ")");
}
}
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());
}
} 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() + ")");
}
}
} 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() + ")");
}
}
} 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() + ")");
}
}
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;
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() + ")");
}
}
}
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;
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());
}
} 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() + ")");
}
}
} 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() + ")");
}
}
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;
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.");
}
}
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;
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();
}
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;
@JsonProperty
final Integer sourceDevice;
- @JsonProperty
- @JsonInclude(JsonInclude.Include.NON_NULL)
- final String relay;
-
@JsonProperty
final long timestamp;
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 {
sourceUuid = null;
sourceName = null;
sourceDevice = null;
- relay = null;
timestamp = messageReceived.getTimestamp();
receiptMessage = null;
dataMessage = new JsonDataMessage(messageReceived);
sourceUuid = null;
sourceName = null;
sourceDevice = null;
- relay = null;
timestamp = receiptReceived.getTimestamp();
receiptMessage = JsonReceiptMessage.deliveryReceipt(timestamp, List.of(timestamp));
dataMessage = null;
sourceUuid = null;
sourceName = null;
sourceDevice = null;
- relay = null;
timestamp = messageReceived.getTimestamp();
receiptMessage = null;
dataMessage = null;
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;
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) {
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 {
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();
}
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 {
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;
import org.whispersystems.signalservice.api.messages.multidevice.ReadMessage;
-import java.util.UUID;
-
import static org.asamk.signal.util.Util.getLegacyIdentifier;
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();
}
}
}
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() {