From: AsamK Date: Sun, 22 Aug 2021 09:28:09 +0000 (+0200) Subject: Extend json output with number and uuid fields X-Git-Tag: v0.9.0~58 X-Git-Url: https://git.nmode.ca/signal-cli/commitdiff_plain/5bbfd3259891e18a11cb878e14a9c17990b13d79 Extend json output with number and uuid fields --- diff --git a/lib/src/main/java/org/asamk/signal/manager/Manager.java b/lib/src/main/java/org/asamk/signal/manager/Manager.java index 9d0c355b..8aa7ed18 100644 --- a/lib/src/main/java/org/asamk/signal/manager/Manager.java +++ b/lib/src/main/java/org/asamk/signal/manager/Manager.java @@ -327,16 +327,32 @@ public class Manager implements Closeable { * This is used for checking a set of phone numbers for registration on Signal * * @param numbers The set of phone number in question - * @return A map of numbers to booleans. True if registered, false otherwise. Should never be null + * @return A map of numbers to canonicalized number and uuid. If a number is not registered the uuid is null. * @throws IOException if its unable to get the contacts to check if they're registered */ - public Map areUsersRegistered(Set numbers) throws IOException { + public Map> areUsersRegistered(Set numbers) throws IOException { + Map canonicalizedNumbers = numbers.stream().collect(Collectors.toMap(n -> n, n -> { + try { + return canonicalizePhoneNumber(n); + } catch (InvalidNumberException e) { + return ""; + } + })); + // Note "contactDetails" has no optionals. It only gives us info on users who are registered - var contactDetails = getRegisteredUsers(numbers); + var contactDetails = getRegisteredUsers(canonicalizedNumbers.values() + .stream() + .filter(s -> !s.isEmpty()) + .collect(Collectors.toSet())); - var registeredUsers = contactDetails.keySet(); + // Store numbers as recipients so we have the number/uuid association + contactDetails.forEach((number, uuid) -> resolveRecipientTrusted(new SignalServiceAddress(uuid, number))); - return numbers.stream().collect(Collectors.toMap(x -> x, registeredUsers::contains)); + return numbers.stream().collect(Collectors.toMap(n -> n, n -> { + final var number = canonicalizedNumbers.get(n); + final var uuid = contactDetails.get(number); + return new Pair<>(number.isEmpty() ? null : number, uuid); + })); } public void updateAccountAttributes() throws IOException { @@ -2724,14 +2740,16 @@ public class Manager implements Closeable { return account.getRecipientStore().resolveServiceAddress(recipientId); } - public RecipientId canonicalizeAndResolveRecipient(String identifier) throws InvalidNumberException { - var canonicalizedNumber = UuidUtil.isUuid(identifier) - ? identifier - : PhoneNumberFormatter.formatNumber(identifier, account.getUsername()); + private RecipientId canonicalizeAndResolveRecipient(String identifier) throws InvalidNumberException { + var canonicalizedNumber = UuidUtil.isUuid(identifier) ? identifier : canonicalizePhoneNumber(identifier); return resolveRecipient(canonicalizedNumber); } + private String canonicalizePhoneNumber(final String number) throws InvalidNumberException { + return PhoneNumberFormatter.formatNumber(number, account.getUsername()); + } + private RecipientId resolveRecipient(final String identifier) { var address = Utils.getSignalServiceAddressFromIdentifier(identifier); diff --git a/src/main/java/org/asamk/signal/commands/GetUserStatusCommand.java b/src/main/java/org/asamk/signal/commands/GetUserStatusCommand.java index 05bbea47..055dac9f 100644 --- a/src/main/java/org/asamk/signal/commands/GetUserStatusCommand.java +++ b/src/main/java/org/asamk/signal/commands/GetUserStatusCommand.java @@ -11,10 +11,12 @@ import org.asamk.signal.commands.exceptions.IOErrorException; import org.asamk.signal.manager.Manager; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import org.whispersystems.libsignal.util.Pair; import java.io.IOException; import java.util.HashSet; import java.util.Map; +import java.util.UUID; import java.util.stream.Collectors; public class GetUserStatusCommand implements JsonRpcLocalCommand { @@ -37,7 +39,7 @@ public class GetUserStatusCommand implements JsonRpcLocalCommand { final Namespace ns, final Manager m, final OutputWriter outputWriter ) throws CommandException { // Get a map of registration statuses - Map registered; + Map> registered; try { registered = m.areUsersRegistered(new HashSet<>(ns.getList("number"))); } catch (IOException e) { @@ -49,10 +51,11 @@ public class GetUserStatusCommand implements JsonRpcLocalCommand { if (outputWriter instanceof JsonWriter) { final var jsonWriter = (JsonWriter) outputWriter; - var jsonUserStatuses = registered.entrySet() - .stream() - .map(entry -> new JsonUserStatus(entry.getKey(), entry.getValue())) - .collect(Collectors.toList()); + var jsonUserStatuses = registered.entrySet().stream().map(entry -> { + final var number = entry.getValue().first(); + final var uuid = entry.getValue().second(); + return new JsonUserStatus(entry.getKey(), number, uuid == null ? null : uuid.toString(), uuid != null); + }).collect(Collectors.toList()); jsonWriter.write(jsonUserStatuses); } else { @@ -66,12 +69,18 @@ public class GetUserStatusCommand implements JsonRpcLocalCommand { private static final class JsonUserStatus { - public String name; + public final String name; - public boolean isRegistered; + public final String number; - public JsonUserStatus(String name, boolean isRegistered) { + public final String uuid; + + public final boolean isRegistered; + + public JsonUserStatus(String name, String number, String uuid, boolean isRegistered) { this.name = name; + this.number = number; + this.uuid = uuid; this.isRegistered = isRegistered; } } diff --git a/src/main/java/org/asamk/signal/json/JsonMention.java b/src/main/java/org/asamk/signal/json/JsonMention.java index 0fe78bc2..f0c66d00 100644 --- a/src/main/java/org/asamk/signal/json/JsonMention.java +++ b/src/main/java/org/asamk/signal/json/JsonMention.java @@ -6,13 +6,22 @@ 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; public class JsonMention { @JsonProperty + @Deprecated final String name; + @JsonProperty + final String number; + + @JsonProperty + final String uuid; + @JsonProperty final int start; @@ -20,8 +29,10 @@ public class JsonMention { final int length; JsonMention(SignalServiceDataMessage.Mention mention, Manager m) { - this.name = getLegacyIdentifier(m.resolveSignalServiceAddress(new SignalServiceAddress(mention.getUuid(), - null))); + final var address = m.resolveSignalServiceAddress(new SignalServiceAddress(mention.getUuid(), null)); + this.name = getLegacyIdentifier(address); + this.number = address.getNumber().orNull(); + this.uuid = address.getUuid().transform(UUID::toString).orNull(); this.start = mention.getStart(); this.length = mention.getLength(); } diff --git a/src/main/java/org/asamk/signal/json/JsonMessageEnvelope.java b/src/main/java/org/asamk/signal/json/JsonMessageEnvelope.java index 40f5ed21..c7a3f891 100644 --- a/src/main/java/org/asamk/signal/json/JsonMessageEnvelope.java +++ b/src/main/java/org/asamk/signal/json/JsonMessageEnvelope.java @@ -10,14 +10,22 @@ 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; public class JsonMessageEnvelope { @JsonProperty + @Deprecated final String source; + @JsonProperty + final String sourceNumber; + + @JsonProperty + final String sourceUuid; + @JsonProperty final String sourceName; @@ -55,14 +63,21 @@ public class JsonMessageEnvelope { if (!envelope.isUnidentifiedSender() && envelope.hasSource()) { var source = envelope.getSourceAddress(); this.source = getLegacyIdentifier(source); + this.sourceNumber = source.getNumber().orNull(); + this.sourceUuid = source.getUuid().transform(UUID::toString).orNull(); this.sourceDevice = envelope.getSourceDevice(); this.relay = source.getRelay().orNull(); } else if (envelope.isUnidentifiedSender() && content != null) { - this.source = getLegacyIdentifier(content.getSender()); + final var source = content.getSender(); + this.source = getLegacyIdentifier(source); + this.sourceNumber = source.getNumber().orNull(); + this.sourceUuid = source.getUuid().transform(UUID::toString).orNull(); this.sourceDevice = content.getSenderDevice(); this.relay = null; } else { this.source = null; + this.sourceNumber = null; + this.sourceUuid = null; this.sourceDevice = null; this.relay = null; } @@ -98,6 +113,8 @@ public class JsonMessageEnvelope { public JsonMessageEnvelope(Signal.MessageReceived messageReceived) { source = messageReceived.getSender(); + sourceNumber = null; + sourceUuid = null; sourceName = null; sourceDevice = null; relay = null; @@ -111,6 +128,8 @@ public class JsonMessageEnvelope { public JsonMessageEnvelope(Signal.ReceiptReceived receiptReceived) { source = receiptReceived.getSender(); + sourceNumber = null; + sourceUuid = null; sourceName = null; sourceDevice = null; relay = null; @@ -124,6 +143,8 @@ public class JsonMessageEnvelope { public JsonMessageEnvelope(Signal.SyncMessageReceived messageReceived) { source = messageReceived.getSource(); + sourceNumber = null; + sourceUuid = null; sourceName = null; sourceDevice = null; relay = null; diff --git a/src/main/java/org/asamk/signal/json/JsonQuote.java b/src/main/java/org/asamk/signal/json/JsonQuote.java index f90b492d..ecd31c1a 100644 --- a/src/main/java/org/asamk/signal/json/JsonQuote.java +++ b/src/main/java/org/asamk/signal/json/JsonQuote.java @@ -8,6 +8,7 @@ import org.whispersystems.signalservice.api.messages.SignalServiceDataMessage; import java.util.ArrayList; import java.util.List; +import java.util.UUID; import java.util.stream.Collectors; import static org.asamk.signal.util.Util.getLegacyIdentifier; @@ -18,8 +19,15 @@ public class JsonQuote { final long id; @JsonProperty + @Deprecated final String author; + @JsonProperty + final String authorNumber; + + @JsonProperty + final String authorUuid; + @JsonProperty final String text; @@ -32,7 +40,10 @@ public class JsonQuote { JsonQuote(SignalServiceDataMessage.Quote quote, Manager m) { this.id = quote.getId(); - this.author = getLegacyIdentifier(m.resolveSignalServiceAddress(quote.getAuthor())); + 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.text = quote.getText(); if (quote.getMentions() != null && quote.getMentions().size() > 0) { diff --git a/src/main/java/org/asamk/signal/json/JsonReaction.java b/src/main/java/org/asamk/signal/json/JsonReaction.java index e7d40fbe..ecea15fe 100644 --- a/src/main/java/org/asamk/signal/json/JsonReaction.java +++ b/src/main/java/org/asamk/signal/json/JsonReaction.java @@ -5,6 +5,8 @@ import com.fasterxml.jackson.annotation.JsonProperty; import org.asamk.signal.manager.Manager; import org.whispersystems.signalservice.api.messages.SignalServiceDataMessage.Reaction; +import java.util.UUID; + import static org.asamk.signal.util.Util.getLegacyIdentifier; public class JsonReaction { @@ -13,8 +15,15 @@ public class JsonReaction { final String emoji; @JsonProperty + @Deprecated final String targetAuthor; + @JsonProperty + final String targetAuthorNumber; + + @JsonProperty + final String targetAuthorUuid; + @JsonProperty final long targetSentTimestamp; @@ -23,7 +32,10 @@ public class JsonReaction { JsonReaction(Reaction reaction, Manager m) { this.emoji = reaction.getEmoji(); - this.targetAuthor = getLegacyIdentifier(m.resolveSignalServiceAddress(reaction.getTargetAuthor())); + 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.targetSentTimestamp = reaction.getTargetSentTimestamp(); this.isRemove = reaction.isRemove(); } diff --git a/src/main/java/org/asamk/signal/json/JsonSyncDataMessage.java b/src/main/java/org/asamk/signal/json/JsonSyncDataMessage.java index c9d88790..28c9d936 100644 --- a/src/main/java/org/asamk/signal/json/JsonSyncDataMessage.java +++ b/src/main/java/org/asamk/signal/json/JsonSyncDataMessage.java @@ -4,22 +4,43 @@ import com.fasterxml.jackson.annotation.JsonProperty; import org.asamk.Signal; import org.asamk.signal.manager.Manager; -import org.asamk.signal.util.Util; import org.whispersystems.signalservice.api.messages.multidevice.SentTranscriptMessage; +import java.util.UUID; + +import static org.asamk.signal.util.Util.getLegacyIdentifier; + class JsonSyncDataMessage extends JsonDataMessage { @JsonProperty + @Deprecated final String destination; + @JsonProperty + final String destinationNumber; + + @JsonProperty + final String destinationUuid; + JsonSyncDataMessage(SentTranscriptMessage transcriptMessage, Manager m) { super(transcriptMessage.getMessage(), m); - this.destination = transcriptMessage.getDestination().transform(Util::getLegacyIdentifier).orNull(); + if (transcriptMessage.getDestination().isPresent()) { + final var address = transcriptMessage.getDestination().get(); + this.destination = getLegacyIdentifier(address); + this.destinationNumber = address.getNumber().orNull(); + this.destinationUuid = address.getUuid().transform(UUID::toString).orNull(); + } else { + this.destination = null; + this.destinationNumber = null; + this.destinationUuid = null; + } } JsonSyncDataMessage(Signal.SyncMessageReceived messageReceived) { super(messageReceived); - destination = messageReceived.getDestination(); + this.destination = messageReceived.getDestination(); + this.destinationNumber = null; + this.destinationUuid = null; } } diff --git a/src/main/java/org/asamk/signal/json/JsonSyncMessage.java b/src/main/java/org/asamk/signal/json/JsonSyncMessage.java index 6e992bcb..5c951f0f 100644 --- a/src/main/java/org/asamk/signal/json/JsonSyncMessage.java +++ b/src/main/java/org/asamk/signal/json/JsonSyncMessage.java @@ -12,8 +12,6 @@ import java.util.Base64; import java.util.List; import java.util.stream.Collectors; -import static org.asamk.signal.util.Util.getLegacyIdentifier; - enum JsonSyncMessageType { CONTACTS_SYNC, GROUPS_SYNC, @@ -68,8 +66,7 @@ class JsonSyncMessage { this.readMessages = syncMessage.getRead() .get() .stream() - .map(message -> new JsonSyncReadMessage(getLegacyIdentifier(message.getSender()), - message.getTimestamp())) + .map(JsonSyncReadMessage::new) .collect(Collectors.toList()); } else { this.readMessages = null; diff --git a/src/main/java/org/asamk/signal/json/JsonSyncReadMessage.java b/src/main/java/org/asamk/signal/json/JsonSyncReadMessage.java index d65b0672..df307b45 100644 --- a/src/main/java/org/asamk/signal/json/JsonSyncReadMessage.java +++ b/src/main/java/org/asamk/signal/json/JsonSyncReadMessage.java @@ -2,16 +2,32 @@ package org.asamk.signal.json; import com.fasterxml.jackson.annotation.JsonProperty; +import org.whispersystems.signalservice.api.messages.multidevice.ReadMessage; + +import java.util.UUID; + +import static org.asamk.signal.util.Util.getLegacyIdentifier; + class JsonSyncReadMessage { @JsonProperty + @Deprecated final String sender; + @JsonProperty + final String senderNumber; + + @JsonProperty + final String senderUuid; + @JsonProperty final long timestamp; - public JsonSyncReadMessage(final String sender, final long timestamp) { - this.sender = sender; - this.timestamp = timestamp; + public JsonSyncReadMessage(final ReadMessage readMessage) { + final var sender = readMessage.getSender(); + this.sender = getLegacyIdentifier(sender); + this.senderNumber = sender.getNumber().orNull(); + this.senderUuid = sender.getUuid().transform(UUID::toString).orNull(); + this.timestamp = readMessage.getTimestamp(); } }