Reformat project

This commit is contained in:
AsamK 2020-12-08 20:59:20 +01:00
parent 4f2261e86f
commit 591c0fe8a3
51 changed files with 579 additions and 335 deletions

View file

@ -67,6 +67,7 @@
<option name="BINARY_OPERATION_SIGN_ON_NEXT_LINE" value="true" /> <option name="BINARY_OPERATION_SIGN_ON_NEXT_LINE" value="true" />
<option name="TERNARY_OPERATION_WRAP" value="5" /> <option name="TERNARY_OPERATION_WRAP" value="5" />
<option name="TERNARY_OPERATION_SIGNS_ON_NEXT_LINE" value="true" /> <option name="TERNARY_OPERATION_SIGNS_ON_NEXT_LINE" value="true" />
<option name="ENUM_CONSTANTS_WRAP" value="2" />
</codeStyleSettings> </codeStyleSettings>
<codeStyleSettings language="XML"> <codeStyleSettings language="XML">
<arrangement> <arrangement>

View file

@ -13,13 +13,19 @@ import java.util.List;
*/ */
public interface Signal extends DBusInterface { public interface Signal extends DBusInterface {
long sendMessage(String message, List<String> attachments, String recipient) throws Error.AttachmentInvalid, Error.Failure, Error.InvalidNumber; long sendMessage(
String message, List<String> attachments, String recipient
) throws Error.AttachmentInvalid, Error.Failure, Error.InvalidNumber;
long sendMessage(String message, List<String> attachments, List<String> recipients) throws Error.AttachmentInvalid, Error.Failure, Error.InvalidNumber, Error.UnregisteredUser, Error.UntrustedIdentity; long sendMessage(
String message, List<String> attachments, List<String> recipients
) throws Error.AttachmentInvalid, Error.Failure, Error.InvalidNumber, Error.UnregisteredUser, Error.UntrustedIdentity;
void sendEndSessionMessage(List<String> recipients) throws Error.Failure, Error.InvalidNumber, Error.UnregisteredUser, Error.UntrustedIdentity; void sendEndSessionMessage(List<String> recipients) throws Error.Failure, Error.InvalidNumber, Error.UnregisteredUser, Error.UntrustedIdentity;
long sendGroupMessage(String message, List<String> attachments, byte[] groupId) throws Error.GroupNotFound, Error.Failure, Error.AttachmentInvalid, Error.UnregisteredUser, Error.UntrustedIdentity; long sendGroupMessage(
String message, List<String> attachments, byte[] groupId
) throws Error.GroupNotFound, Error.Failure, Error.AttachmentInvalid, Error.UnregisteredUser, Error.UntrustedIdentity;
String getContactName(String number) throws Error.InvalidNumber; String getContactName(String number) throws Error.InvalidNumber;
@ -35,7 +41,9 @@ public interface Signal extends DBusInterface {
List<String> getGroupMembers(byte[] groupId); List<String> getGroupMembers(byte[] groupId);
byte[] updateGroup(byte[] groupId, String name, List<String> members, String avatar) throws Error.AttachmentInvalid, Error.Failure, Error.InvalidNumber, Error.GroupNotFound, Error.UnregisteredUser, Error.UntrustedIdentity; byte[] updateGroup(
byte[] groupId, String name, List<String> members, String avatar
) throws Error.AttachmentInvalid, Error.Failure, Error.InvalidNumber, Error.GroupNotFound, Error.UnregisteredUser, Error.UntrustedIdentity;
boolean isRegistered(); boolean isRegistered();
@ -47,7 +55,14 @@ public interface Signal extends DBusInterface {
private final String message; private final String message;
private final List<String> attachments; private final List<String> attachments;
public MessageReceived(String objectpath, long timestamp, String sender, byte[] groupId, String message, List<String> attachments) throws DBusException { public MessageReceived(
String objectpath,
long timestamp,
String sender,
byte[] groupId,
String message,
List<String> attachments
) throws DBusException {
super(objectpath, timestamp, sender, groupId, message, attachments); super(objectpath, timestamp, sender, groupId, message, attachments);
this.timestamp = timestamp; this.timestamp = timestamp;
this.sender = sender; this.sender = sender;
@ -106,7 +121,15 @@ public interface Signal extends DBusInterface {
private final String message; private final String message;
private final List<String> attachments; private final List<String> attachments;
public SyncMessageReceived(String objectpath, long timestamp, String source, String destination, byte[] groupId, String message, List<String> attachments) throws DBusException { public SyncMessageReceived(
String objectpath,
long timestamp,
String source,
String destination,
byte[] groupId,
String message,
List<String> attachments
) throws DBusException {
super(objectpath, timestamp, source, destination, groupId, message, attachments); super(objectpath, timestamp, source, destination, groupId, message, attachments);
this.timestamp = timestamp; this.timestamp = timestamp;
this.source = source; this.source = source;

View file

@ -29,30 +29,33 @@ public class JsonDbusReceiveMessageHandler extends JsonReceiveMessageHandler {
this.objectPath = objectPath; this.objectPath = objectPath;
} }
static void sendReceivedMessageToDbus(SignalServiceEnvelope envelope, SignalServiceContent content, DBusConnection conn, final String objectPath, Manager m) { static void sendReceivedMessageToDbus(
SignalServiceEnvelope envelope,
SignalServiceContent content,
DBusConnection conn,
final String objectPath,
Manager m
) {
if (envelope.isReceipt()) { if (envelope.isReceipt()) {
try { try {
conn.sendMessage(new Signal.ReceiptReceived( conn.sendMessage(new Signal.ReceiptReceived(objectPath, envelope.getTimestamp(),
objectPath,
envelope.getTimestamp(),
// A receipt envelope always has a source address // A receipt envelope always has a source address
envelope.getSourceAddress().getLegacyIdentifier() envelope.getSourceAddress().getLegacyIdentifier()));
));
} catch (DBusException e) { } catch (DBusException e) {
e.printStackTrace(); e.printStackTrace();
} }
} else if (content != null) { } else if (content != null) {
final SignalServiceAddress sender = !envelope.isUnidentifiedSender() && envelope.hasSource() ? envelope.getSourceAddress() : content.getSender(); final SignalServiceAddress sender = !envelope.isUnidentifiedSender() && envelope.hasSource()
? envelope.getSourceAddress()
: content.getSender();
if (content.getReceiptMessage().isPresent()) { if (content.getReceiptMessage().isPresent()) {
final SignalServiceReceiptMessage receiptMessage = content.getReceiptMessage().get(); final SignalServiceReceiptMessage receiptMessage = content.getReceiptMessage().get();
if (receiptMessage.isDeliveryReceipt()) { if (receiptMessage.isDeliveryReceipt()) {
for (long timestamp : receiptMessage.getTimestamps()) { for (long timestamp : receiptMessage.getTimestamps()) {
try { try {
conn.sendMessage(new Signal.ReceiptReceived( conn.sendMessage(new Signal.ReceiptReceived(objectPath,
objectPath,
timestamp, timestamp,
sender.getLegacyIdentifier() sender.getLegacyIdentifier()));
));
} catch (DBusException e) { } catch (DBusException e) {
e.printStackTrace(); e.printStackTrace();
} }
@ -62,13 +65,13 @@ public class JsonDbusReceiveMessageHandler extends JsonReceiveMessageHandler {
SignalServiceDataMessage message = content.getDataMessage().get(); SignalServiceDataMessage message = content.getDataMessage().get();
byte[] groupId = getGroupId(m, message); byte[] groupId = getGroupId(m, message);
if (!message.isEndSession() && if (!message.isEndSession() && (
(groupId == null groupId == null
|| message.getGroupContext().get().getGroupV1Type() == null || message.getGroupContext().get().getGroupV1Type() == null
|| message.getGroupContext().get().getGroupV1Type() == SignalServiceGroup.Type.DELIVER)) { || message.getGroupContext().get().getGroupV1Type() == SignalServiceGroup.Type.DELIVER
)) {
try { try {
conn.sendMessage(new Signal.MessageReceived( conn.sendMessage(new Signal.MessageReceived(objectPath,
objectPath,
message.getTimestamp(), message.getTimestamp(),
sender.getLegacyIdentifier(), sender.getLegacyIdentifier(),
groupId != null ? groupId : new byte[0], groupId != null ? groupId : new byte[0],
@ -83,16 +86,19 @@ public class JsonDbusReceiveMessageHandler extends JsonReceiveMessageHandler {
if (sync_message.getSent().isPresent()) { if (sync_message.getSent().isPresent()) {
SentTranscriptMessage transcript = sync_message.getSent().get(); SentTranscriptMessage transcript = sync_message.getSent().get();
if (transcript.getDestination().isPresent() || transcript.getMessage().getGroupContext().isPresent()) { if (transcript.getDestination().isPresent() || transcript.getMessage()
.getGroupContext()
.isPresent()) {
SignalServiceDataMessage message = transcript.getMessage(); SignalServiceDataMessage message = transcript.getMessage();
byte[] groupId = getGroupId(m, message); byte[] groupId = getGroupId(m, message);
try { try {
conn.sendMessage(new Signal.SyncMessageReceived( conn.sendMessage(new Signal.SyncMessageReceived(objectPath,
objectPath,
transcript.getTimestamp(), transcript.getTimestamp(),
sender.getLegacyIdentifier(), sender.getLegacyIdentifier(),
transcript.getDestination().isPresent() ? transcript.getDestination().get().getLegacyIdentifier() : "", transcript.getDestination().isPresent() ? transcript.getDestination()
.get()
.getLegacyIdentifier() : "",
groupId != null ? groupId : new byte[0], groupId != null ? groupId : new byte[0],
message.getBody().isPresent() ? message.getBody().get() : "", message.getBody().isPresent() ? message.getBody().get() : "",
JsonDbusReceiveMessageHandler.getAttachments(message, m))); JsonDbusReceiveMessageHandler.getAttachments(message, m)));

View file

@ -84,8 +84,8 @@ public class Main {
busType = DBusConnection.DBusBusType.SESSION; busType = DBusConnection.DBusBusType.SESSION;
} }
try (DBusConnection dBusConn = DBusConnection.getConnection(busType)) { try (DBusConnection dBusConn = DBusConnection.getConnection(busType)) {
Signal ts = dBusConn.getRemoteObject( Signal ts = dBusConn.getRemoteObject(DbusConfig.SIGNAL_BUSNAME,
DbusConfig.SIGNAL_BUSNAME, DbusConfig.SIGNAL_OBJECTPATH, DbusConfig.SIGNAL_OBJECTPATH,
Signal.class); Signal.class);
return handleCommands(ns, ts, dBusConn); return handleCommands(ns, ts, dBusConn);
@ -103,7 +103,8 @@ public class Main {
dataPath = getDefaultDataPath(); dataPath = getDefaultDataPath();
} }
final SignalServiceConfiguration serviceConfiguration = ServiceConfig.createDefaultServiceConfiguration(BaseConfig.USER_AGENT); final SignalServiceConfiguration serviceConfiguration = ServiceConfig.createDefaultServiceConfiguration(
BaseConfig.USER_AGENT);
if (username == null) { if (username == null) {
ProvisioningManager pm = new ProvisioningManager(dataPath, serviceConfiguration, BaseConfig.USER_AGENT); ProvisioningManager pm = new ProvisioningManager(dataPath, serviceConfiguration, BaseConfig.USER_AGENT);
@ -225,21 +226,14 @@ public class Main {
.description("Commandline interface for Signal.") .description("Commandline interface for Signal.")
.version(BaseConfig.PROJECT_NAME + " " + BaseConfig.PROJECT_VERSION); .version(BaseConfig.PROJECT_NAME + " " + BaseConfig.PROJECT_VERSION);
parser.addArgument("-v", "--version") parser.addArgument("-v", "--version").help("Show package version.").action(Arguments.version());
.help("Show package version.")
.action(Arguments.version());
parser.addArgument("--config") parser.addArgument("--config")
.help("Set the path, where to store the config (Default: $XDG_DATA_HOME/signal-cli , $HOME/.local/share/signal-cli)."); .help("Set the path, where to store the config (Default: $XDG_DATA_HOME/signal-cli , $HOME/.local/share/signal-cli).");
MutuallyExclusiveGroup mut = parser.addMutuallyExclusiveGroup(); MutuallyExclusiveGroup mut = parser.addMutuallyExclusiveGroup();
mut.addArgument("-u", "--username") mut.addArgument("-u", "--username").help("Specify your phone number, that will be used for verification.");
.help("Specify your phone number, that will be used for verification."); mut.addArgument("--dbus").help("Make request via user dbus.").action(Arguments.storeTrue());
mut.addArgument("--dbus") mut.addArgument("--dbus-system").help("Make request via system dbus.").action(Arguments.storeTrue());
.help("Make request via user dbus.")
.action(Arguments.storeTrue());
mut.addArgument("--dbus-system")
.help("Make request via system dbus.")
.action(Arguments.storeTrue());
Subparsers subparsers = parser.addSubparsers() Subparsers subparsers = parser.addSubparsers()
.title("subcommands") .title("subcommands")

View file

@ -52,7 +52,9 @@ public class ReceiveMessageHandler implements Manager.ReceiveMessageHandler {
if (!envelope.isUnidentifiedSender() && envelope.hasSource()) { if (!envelope.isUnidentifiedSender() && envelope.hasSource()) {
SignalServiceAddress source = envelope.getSourceAddress(); SignalServiceAddress source = envelope.getSourceAddress();
ContactInfo sourceContact = m.getContact(source.getLegacyIdentifier()); ContactInfo sourceContact = m.getContact(source.getLegacyIdentifier());
System.out.println(String.format("Envelope from: %s (device: %d)", (sourceContact == null ? "" : "" + sourceContact.name + "") + source.getLegacyIdentifier(), envelope.getSourceDevice())); System.out.println(String.format("Envelope from: %s (device: %d)",
(sourceContact == null ? "" : "" + sourceContact.name + "") + source.getLegacyIdentifier(),
envelope.getSourceDevice()));
if (source.getRelay().isPresent()) { if (source.getRelay().isPresent()) {
System.out.println("Relayed by: " + source.getRelay().get()); System.out.println("Relayed by: " + source.getRelay().get());
} }
@ -70,18 +72,35 @@ public class ReceiveMessageHandler implements Manager.ReceiveMessageHandler {
if (exception != null) { if (exception != null) {
if (exception instanceof org.whispersystems.libsignal.UntrustedIdentityException) { if (exception instanceof org.whispersystems.libsignal.UntrustedIdentityException) {
org.whispersystems.libsignal.UntrustedIdentityException e = (org.whispersystems.libsignal.UntrustedIdentityException) exception; org.whispersystems.libsignal.UntrustedIdentityException e = (org.whispersystems.libsignal.UntrustedIdentityException) exception;
System.out.println("The users key is untrusted, either the user has reinstalled Signal or a third party sent this message."); System.out.println(
System.out.println("Use 'signal-cli -u " + m.getUsername() + " listIdentities -n " + e.getName() + "', verify the key and run 'signal-cli -u " + m.getUsername() + " trust -v \"FINGER_PRINT\" " + e.getName() + "' to mark it as trusted"); "The users key is untrusted, either the user has reinstalled Signal or a third party sent this message.");
System.out.println("If you don't care about security, use 'signal-cli -u " + m.getUsername() + " trust -a " + e.getName() + "' to trust it without verification"); System.out.println("Use 'signal-cli -u "
+ m.getUsername()
+ " listIdentities -n "
+ e.getName()
+ "', verify the key and run 'signal-cli -u "
+ m.getUsername()
+ " trust -v \"FINGER_PRINT\" "
+ e.getName()
+ "' to mark it as trusted");
System.out.println("If you don't care about security, use 'signal-cli -u "
+ m.getUsername()
+ " trust -a "
+ e.getName()
+ "' to trust it without verification");
} else { } else {
System.out.println("Exception: " + exception.getMessage() + " (" + exception.getClass().getSimpleName() + ")"); System.out.println("Exception: " + exception.getMessage() + " (" + exception.getClass()
.getSimpleName() + ")");
} }
} }
if (content == null) { if (content == null) {
System.out.println("Failed to decrypt message."); System.out.println("Failed to decrypt message.");
} else { } else {
ContactInfo sourceContact = m.getContact(content.getSender().getLegacyIdentifier()); ContactInfo sourceContact = m.getContact(content.getSender().getLegacyIdentifier());
System.out.println(String.format("Sender: %s (device: %d)", (sourceContact == null ? "" : "" + sourceContact.name + "") + content.getSender().getLegacyIdentifier(), content.getSenderDevice())); System.out.println(String.format("Sender: %s (device: %d)",
(sourceContact == null ? "" : "" + sourceContact.name + "") + content.getSender()
.getLegacyIdentifier(),
content.getSenderDevice()));
if (content.getDataMessage().isPresent()) { if (content.getDataMessage().isPresent()) {
SignalServiceDataMessage message = content.getDataMessage().get(); SignalServiceDataMessage message = content.getDataMessage().get();
handleSignalServiceDataMessage(message); handleSignalServiceDataMessage(message);
@ -107,7 +126,11 @@ public class ReceiveMessageHandler implements Manager.ReceiveMessageHandler {
System.out.println("Received sync read messages list"); System.out.println("Received sync read messages list");
for (ReadMessage rm : syncMessage.getRead().get()) { for (ReadMessage rm : syncMessage.getRead().get()) {
ContactInfo fromContact = m.getContact(rm.getSender().getLegacyIdentifier()); ContactInfo fromContact = m.getContact(rm.getSender().getLegacyIdentifier());
System.out.println("From: " + (fromContact == null ? "" : "" + fromContact.name + "") + rm.getSender().getLegacyIdentifier() + " Message timestamp: " + DateUtils.formatTimestamp(rm.getTimestamp())); System.out.println("From: "
+ (fromContact == null ? "" : "" + fromContact.name + "")
+ rm.getSender().getLegacyIdentifier()
+ " Message timestamp: "
+ DateUtils.formatTimestamp(rm.getTimestamp()));
} }
} }
if (syncMessage.getRequest().isPresent()) { if (syncMessage.getRequest().isPresent()) {
@ -140,15 +163,19 @@ public class ReceiveMessageHandler implements Manager.ReceiveMessageHandler {
StringBuilder toBuilder = new StringBuilder(); StringBuilder toBuilder = new StringBuilder();
for (SignalServiceAddress dest : sentTranscriptMessage.getRecipients()) { for (SignalServiceAddress dest : sentTranscriptMessage.getRecipients()) {
ContactInfo destContact = m.getContact(dest.getLegacyIdentifier()); ContactInfo destContact = m.getContact(dest.getLegacyIdentifier());
toBuilder.append(destContact == null ? "" : "" + destContact.name + "").append(dest.getLegacyIdentifier()).append(" "); toBuilder.append(destContact == null ? "" : "" + destContact.name + "")
.append(dest.getLegacyIdentifier())
.append(" ");
} }
to = toBuilder.toString(); to = toBuilder.toString();
} else { } else {
to = "Unknown"; to = "Unknown";
} }
System.out.println("To: " + to + " , Message timestamp: " + DateUtils.formatTimestamp(sentTranscriptMessage.getTimestamp())); System.out.println("To: " + to + " , Message timestamp: " + DateUtils.formatTimestamp(
sentTranscriptMessage.getTimestamp()));
if (sentTranscriptMessage.getExpirationStartTimestamp() > 0) { if (sentTranscriptMessage.getExpirationStartTimestamp() > 0) {
System.out.println("Expiration started at: " + DateUtils.formatTimestamp(sentTranscriptMessage.getExpirationStartTimestamp())); System.out.println("Expiration started at: " + DateUtils.formatTimestamp(
sentTranscriptMessage.getExpirationStartTimestamp()));
} }
SignalServiceDataMessage message = sentTranscriptMessage.getMessage(); SignalServiceDataMessage message = sentTranscriptMessage.getMessage();
handleSignalServiceDataMessage(message); handleSignalServiceDataMessage(message);
@ -164,24 +191,38 @@ public class ReceiveMessageHandler implements Manager.ReceiveMessageHandler {
if (syncMessage.getVerified().isPresent()) { if (syncMessage.getVerified().isPresent()) {
System.out.println("Received sync message with verified identities:"); System.out.println("Received sync message with verified identities:");
final VerifiedMessage verifiedMessage = syncMessage.getVerified().get(); final VerifiedMessage verifiedMessage = syncMessage.getVerified().get();
System.out.println(" - " + verifiedMessage.getDestination() + ": " + verifiedMessage.getVerified()); System.out.println(" - "
String safetyNumber = Util.formatSafetyNumber(m.computeSafetyNumber(verifiedMessage.getDestination(), verifiedMessage.getIdentityKey())); + verifiedMessage.getDestination()
+ ": "
+ verifiedMessage.getVerified());
String safetyNumber = Util.formatSafetyNumber(m.computeSafetyNumber(verifiedMessage.getDestination(),
verifiedMessage.getIdentityKey()));
System.out.println(" " + safetyNumber); System.out.println(" " + safetyNumber);
} }
if (syncMessage.getConfiguration().isPresent()) { if (syncMessage.getConfiguration().isPresent()) {
System.out.println("Received sync message with configuration:"); System.out.println("Received sync message with configuration:");
final ConfigurationMessage configurationMessage = syncMessage.getConfiguration().get(); final ConfigurationMessage configurationMessage = syncMessage.getConfiguration().get();
if (configurationMessage.getReadReceipts().isPresent()) { if (configurationMessage.getReadReceipts().isPresent()) {
System.out.println(" - Read receipts: " + (configurationMessage.getReadReceipts().get() ? "enabled" : "disabled")); System.out.println(" - Read receipts: " + (
configurationMessage.getReadReceipts().get() ? "enabled" : "disabled"
));
} }
if (configurationMessage.getLinkPreviews().isPresent()) { if (configurationMessage.getLinkPreviews().isPresent()) {
System.out.println(" - Link previews: " + (configurationMessage.getLinkPreviews().get() ? "enabled" : "disabled")); System.out.println(" - Link previews: " + (
configurationMessage.getLinkPreviews().get() ? "enabled" : "disabled"
));
} }
if (configurationMessage.getTypingIndicators().isPresent()) { if (configurationMessage.getTypingIndicators().isPresent()) {
System.out.println(" - Typing indicators: " + (configurationMessage.getTypingIndicators().get() ? "enabled" : "disabled")); System.out.println(" - Typing indicators: " + (
configurationMessage.getTypingIndicators().get() ? "enabled" : "disabled"
));
} }
if (configurationMessage.getUnidentifiedDeliveryIndicators().isPresent()) { if (configurationMessage.getUnidentifiedDeliveryIndicators().isPresent()) {
System.out.println(" - Unidentified Delivery Indicators: " + (configurationMessage.getUnidentifiedDeliveryIndicators().get() ? "enabled" : "disabled")); System.out.println(" - Unidentified Delivery Indicators: " + (
configurationMessage.getUnidentifiedDeliveryIndicators().get()
? "enabled"
: "disabled"
));
} }
} }
if (syncMessage.getFetchType().isPresent()) { if (syncMessage.getFetchType().isPresent()) {
@ -195,7 +236,8 @@ public class ReceiveMessageHandler implements Manager.ReceiveMessageHandler {
System.out.println(" - Timestamp:" + viewOnceOpenMessage.getTimestamp()); System.out.println(" - Timestamp:" + viewOnceOpenMessage.getTimestamp());
} }
if (syncMessage.getStickerPackOperations().isPresent()) { if (syncMessage.getStickerPackOperations().isPresent()) {
final List<StickerPackOperationMessage> stickerPackOperationMessages = syncMessage.getStickerPackOperations().get(); final List<StickerPackOperationMessage> stickerPackOperationMessages = syncMessage.getStickerPackOperations()
.get();
System.out.println("Received sync message with sticker pack operations:"); System.out.println("Received sync message with sticker pack operations:");
for (StickerPackOperationMessage m : stickerPackOperationMessages) { for (StickerPackOperationMessage m : stickerPackOperationMessages) {
System.out.println(" - " + m.getType().toString()); System.out.println(" - " + m.getType().toString());
@ -208,21 +250,27 @@ public class ReceiveMessageHandler implements Manager.ReceiveMessageHandler {
} }
} }
if (syncMessage.getMessageRequestResponse().isPresent()) { if (syncMessage.getMessageRequestResponse().isPresent()) {
final MessageRequestResponseMessage requestResponseMessage = syncMessage.getMessageRequestResponse().get(); final MessageRequestResponseMessage requestResponseMessage = syncMessage.getMessageRequestResponse()
.get();
System.out.println("Received message request response:"); System.out.println("Received message request response:");
System.out.println(" Type: " + requestResponseMessage.getType()); System.out.println(" Type: " + requestResponseMessage.getType());
if (requestResponseMessage.getGroupId().isPresent()) { if (requestResponseMessage.getGroupId().isPresent()) {
System.out.println(" Group id: " + Base64.encodeBytes(requestResponseMessage.getGroupId().get())); System.out.println(" Group id: " + Base64.encodeBytes(requestResponseMessage.getGroupId()
.get()));
} }
if (requestResponseMessage.getPerson().isPresent()) { if (requestResponseMessage.getPerson().isPresent()) {
System.out.println(" Person: " + requestResponseMessage.getPerson().get().getLegacyIdentifier()); System.out.println(" Person: " + requestResponseMessage.getPerson()
.get()
.getLegacyIdentifier());
} }
} }
if (syncMessage.getKeys().isPresent()) { if (syncMessage.getKeys().isPresent()) {
final KeysMessage keysMessage = syncMessage.getKeys().get(); final KeysMessage keysMessage = syncMessage.getKeys().get();
System.out.println("Received sync message with keys:"); System.out.println("Received sync message with keys:");
if (keysMessage.getStorageService().isPresent()) { if (keysMessage.getStorageService().isPresent()) {
System.out.println(" With storage key length: " + keysMessage.getStorageService().get().serialize().length); System.out.println(" With storage key length: " + keysMessage.getStorageService()
.get()
.serialize().length);
} else { } else {
System.out.println(" With empty storage key"); System.out.println(" With empty storage key");
} }
@ -246,7 +294,10 @@ public class ReceiveMessageHandler implements Manager.ReceiveMessageHandler {
if (callMessage.getIceUpdateMessages().isPresent()) { if (callMessage.getIceUpdateMessages().isPresent()) {
List<IceUpdateMessage> iceUpdateMessages = callMessage.getIceUpdateMessages().get(); List<IceUpdateMessage> iceUpdateMessages = callMessage.getIceUpdateMessages().get();
for (IceUpdateMessage iceUpdateMessage : iceUpdateMessages) { for (IceUpdateMessage iceUpdateMessage : iceUpdateMessages) {
System.out.println("Ice update message: " + iceUpdateMessage.getId() + ", sdp: " + iceUpdateMessage.getSdp()); System.out.println("Ice update message: "
+ iceUpdateMessage.getId()
+ ", sdp: "
+ iceUpdateMessage.getSdp());
} }
} }
if (callMessage.getOfferMessage().isPresent()) { if (callMessage.getOfferMessage().isPresent()) {
@ -386,7 +437,8 @@ public class ReceiveMessageHandler implements Manager.ReceiveMessageHandler {
final SignalServiceDataMessage.Reaction reaction = message.getReaction().get(); final SignalServiceDataMessage.Reaction reaction = message.getReaction().get();
System.out.println("Reaction:"); System.out.println("Reaction:");
System.out.println(" - Emoji: " + reaction.getEmoji()); System.out.println(" - Emoji: " + reaction.getEmoji());
System.out.println(" - Target author: " + m.resolveSignalServiceAddress(reaction.getTargetAuthor()).getLegacyIdentifier()); System.out.println(" - Target author: " + m.resolveSignalServiceAddress(reaction.getTargetAuthor())
.getLegacyIdentifier());
System.out.println(" - Target timestamp: " + reaction.getTargetSentTimestamp()); System.out.println(" - Target timestamp: " + reaction.getTargetSentTimestamp());
System.out.println(" - Is remove: " + reaction.isRemove()); System.out.println(" - Is remove: " + reaction.isRemove());
} }
@ -417,7 +469,13 @@ public class ReceiveMessageHandler implements Manager.ReceiveMessageHandler {
final List<SignalServiceDataMessage.Mention> mentions = message.getMentions().get(); final List<SignalServiceDataMessage.Mention> mentions = message.getMentions().get();
System.out.println("Mentions: "); System.out.println("Mentions: ");
for (SignalServiceDataMessage.Mention mention : mentions) { for (SignalServiceDataMessage.Mention mention : mentions) {
System.out.println("- " + mention.getUuid() + ": " + mention.getStart() + " (length: " + mention.getLength() + ")"); System.out.println("- "
+ mention.getUuid()
+ ": "
+ mention.getStart()
+ " (length: "
+ mention.getLength()
+ ")");
} }
} }
@ -430,12 +488,22 @@ public class ReceiveMessageHandler implements Manager.ReceiveMessageHandler {
} }
private void printAttachment(SignalServiceAttachment attachment) { private void printAttachment(SignalServiceAttachment attachment) {
System.out.println("- " + attachment.getContentType() + " (" + (attachment.isPointer() ? "Pointer" : "") + (attachment.isStream() ? "Stream" : "") + ")"); System.out.println("- " + attachment.getContentType() + " (" + (attachment.isPointer() ? "Pointer" : "") + (
attachment.isStream() ? "Stream" : ""
) + ")");
if (attachment.isPointer()) { if (attachment.isPointer()) {
final SignalServiceAttachmentPointer pointer = attachment.asPointer(); final SignalServiceAttachmentPointer pointer = attachment.asPointer();
System.out.println(" Id: " + pointer.getRemoteId() + " Key length: " + pointer.getKey().length); System.out.println(" Id: " + pointer.getRemoteId() + " Key length: " + pointer.getKey().length);
System.out.println(" Filename: " + (pointer.getFileName().isPresent() ? pointer.getFileName().get() : "-")); System.out.println(" Filename: " + (
System.out.println(" Size: " + (pointer.getSize().isPresent() ? pointer.getSize().get() + " bytes" : "<unavailable>") + (pointer.getPreview().isPresent() ? " (Preview is available: " + pointer.getPreview().get().length + " bytes)" : "")); pointer.getFileName().isPresent() ? pointer.getFileName().get() : "-"
));
System.out.println(" Size: " + (
pointer.getSize().isPresent() ? pointer.getSize().get() + " bytes" : "<unavailable>"
) + (
pointer.getPreview().isPresent() ? " (Preview is available: "
+ pointer.getPreview().get().length
+ " bytes)" : ""
));
System.out.println(" Voice note: " + (pointer.getVoiceNote() ? "yes" : "no")); System.out.println(" Voice note: " + (pointer.getVoiceNote() ? "yes" : "no"));
System.out.println(" Dimensions: " + pointer.getWidth() + "x" + pointer.getHeight()); System.out.println(" Dimensions: " + pointer.getWidth() + "x" + pointer.getHeight());
File file = m.getAttachmentFile(pointer.getRemoteId()); File file = m.getAttachmentFile(pointer.getRemoteId());

View file

@ -13,12 +13,8 @@ public class BlockCommand implements LocalCommand {
@Override @Override
public void attachToSubparser(final Subparser subparser) { public void attachToSubparser(final Subparser subparser) {
subparser.addArgument("contact") subparser.addArgument("contact").help("Contact number").nargs("*");
.help("Contact number") subparser.addArgument("-g", "--group").help("Group ID").nargs("*");
.nargs("*");
subparser.addArgument("-g", "--group")
.help("Group ID")
.nargs("*");
subparser.help("Block the given contacts or groups (no messages will be received)"); subparser.help("Block the given contacts or groups (no messages will be received)");
} }

View file

@ -60,7 +60,13 @@ public class DaemonCommand implements LocalCommand {
} }
boolean ignoreAttachments = ns.getBoolean("ignore_attachments"); boolean ignoreAttachments = ns.getBoolean("ignore_attachments");
try { try {
m.receiveMessages(1, TimeUnit.HOURS, false, ignoreAttachments, ns.getBoolean("json") ? new JsonDbusReceiveMessageHandler(m, conn, SIGNAL_OBJECTPATH) : new DbusReceiveMessageHandler(m, conn, SIGNAL_OBJECTPATH)); m.receiveMessages(1,
TimeUnit.HOURS,
false,
ignoreAttachments,
ns.getBoolean("json")
? new JsonDbusReceiveMessageHandler(m, conn, SIGNAL_OBJECTPATH)
: new DbusReceiveMessageHandler(m, conn, SIGNAL_OBJECTPATH));
return 0; return 0;
} catch (IOException e) { } catch (IOException e) {
System.err.println("Error while receiving messages: " + e.getMessage()); System.err.println("Error while receiving messages: " + e.getMessage());

View file

@ -16,8 +16,7 @@ public class LinkCommand implements ProvisioningCommand {
@Override @Override
public void attachToSubparser(final Subparser subparser) { public void attachToSubparser(final Subparser subparser) {
subparser.addArgument("-n", "--name") subparser.addArgument("-n", "--name").help("Specify a name to describe this new device.");
.help("Specify a name to describe this new device.");
} }
@Override @Override
@ -43,7 +42,11 @@ public class LinkCommand implements ProvisioningCommand {
e.printStackTrace(); e.printStackTrace();
return 2; return 2;
} catch (UserAlreadyExists e) { } catch (UserAlreadyExists e) {
System.err.println("The user " + e.getUsername() + " already exists\nDelete \"" + e.getFileName() + "\" before trying again."); System.err.println("The user "
+ e.getUsername()
+ " already exists\nDelete \""
+ e.getFileName()
+ "\" before trying again.");
return 1; return 1;
} }
return 0; return 0;

View file

@ -25,7 +25,10 @@ public class ListDevicesCommand implements LocalCommand {
try { try {
List<DeviceInfo> devices = m.getLinkedDevices(); List<DeviceInfo> devices = m.getLinkedDevices();
for (DeviceInfo d : devices) { for (DeviceInfo d : devices) {
System.out.println("Device " + d.getId() + (d.getId() == m.getDeviceId() ? " (this device)" : "") + ":"); System.out.println("Device "
+ d.getId()
+ (d.getId() == m.getDeviceId() ? " (this device)" : "")
+ ":");
System.out.println(" Name: " + d.getName()); System.out.println(" Name: " + d.getName());
System.out.println(" Created: " + DateUtils.formatTimestamp(d.getCreated())); System.out.println(" Created: " + DateUtils.formatTimestamp(d.getCreated()));
System.out.println(" Last seen: " + DateUtils.formatTimestamp(d.getLastSeen())); System.out.println(" Last seen: " + DateUtils.formatTimestamp(d.getLastSeen()));

View file

@ -35,18 +35,27 @@ public class ListGroupsCommand implements LocalCommand {
.map(SignalServiceAddress::getLegacyIdentifier) .map(SignalServiceAddress::getLegacyIdentifier)
.collect(Collectors.toSet()); .collect(Collectors.toSet());
System.out.println(String.format("Id: %s Name: %s Active: %s Blocked: %b Members: %s Pending members: %s Requesting members: %s", System.out.println(String.format(
Base64.encodeBytes(group.groupId), group.getTitle(), group.isMember(m.getSelfAddress()), group.isBlocked(), members, pendingMembers, requestingMembers)); "Id: %s Name: %s Active: %s Blocked: %b Members: %s Pending members: %s Requesting members: %s",
Base64.encodeBytes(group.groupId),
group.getTitle(),
group.isMember(m.getSelfAddress()),
group.isBlocked(),
members,
pendingMembers,
requestingMembers));
} else { } else {
System.out.println(String.format("Id: %s Name: %s Active: %s Blocked: %b", System.out.println(String.format("Id: %s Name: %s Active: %s Blocked: %b",
Base64.encodeBytes(group.groupId), group.getTitle(), group.isMember(m.getSelfAddress()), group.isBlocked())); Base64.encodeBytes(group.groupId),
group.getTitle(),
group.isMember(m.getSelfAddress()),
group.isBlocked()));
} }
} }
@Override @Override
public void attachToSubparser(final Subparser subparser) { public void attachToSubparser(final Subparser subparser) {
subparser.addArgument("-d", "--detailed").action(Arguments.storeTrue()) subparser.addArgument("-d", "--detailed").action(Arguments.storeTrue()).help("List members of each group");
.help("List members of each group");
subparser.help("List group name and ids"); subparser.help("List group name and ids");
} }

View file

@ -15,14 +15,17 @@ public class ListIdentitiesCommand implements LocalCommand {
private static void printIdentityFingerprint(Manager m, JsonIdentityKeyStore.Identity theirId) { private static void printIdentityFingerprint(Manager m, JsonIdentityKeyStore.Identity theirId) {
String digits = Util.formatSafetyNumber(m.computeSafetyNumber(theirId.getAddress(), theirId.getIdentityKey())); String digits = Util.formatSafetyNumber(m.computeSafetyNumber(theirId.getAddress(), theirId.getIdentityKey()));
System.out.println(String.format("%s: %s Added: %s Fingerprint: %s Safety Number: %s", theirId.getAddress().getNumber().orNull(), System.out.println(String.format("%s: %s Added: %s Fingerprint: %s Safety Number: %s",
theirId.getTrustLevel(), theirId.getDateAdded(), Hex.toString(theirId.getFingerprint()), digits)); theirId.getAddress().getNumber().orNull(),
theirId.getTrustLevel(),
theirId.getDateAdded(),
Hex.toString(theirId.getFingerprint()),
digits));
} }
@Override @Override
public void attachToSubparser(final Subparser subparser) { public void attachToSubparser(final Subparser subparser) {
subparser.addArgument("-n", "--number") subparser.addArgument("-n", "--number").help("Only show identity keys for the given phone number.");
.help("Only show identity keys for the given phone number.");
} }
@Override @Override

View file

@ -25,9 +25,7 @@ public class QuitGroupCommand implements LocalCommand {
@Override @Override
public void attachToSubparser(final Subparser subparser) { public void attachToSubparser(final Subparser subparser) {
subparser.addArgument("-g", "--group") subparser.addArgument("-g", "--group").required(true).help("Specify the recipient group ID.");
.required(true)
.help("Specify the recipient group ID.");
} }
@Override @Override
@ -38,7 +36,8 @@ public class QuitGroupCommand implements LocalCommand {
} }
try { try {
final Pair<Long, List<SendMessageResult>> results = m.sendQuitGroupMessage(Util.decodeGroupId(ns.getString("group"))); final byte[] groupId = Util.decodeGroupId(ns.getString("group"));
final Pair<Long, List<SendMessageResult>> results = m.sendQuitGroupMessage(groupId);
return handleTimestampAndSendMessageResults(results.first(), results.second()); return handleTimestampAndSendMessageResults(results.first(), results.second());
} catch (IOException e) { } catch (IOException e) {
handleIOException(e); handleIOException(e);

View file

@ -63,7 +63,9 @@ public class ReceiveCommand implements ExtendedDbusCommand, LocalCommand {
} }
} else { } else {
System.out.print(String.format("Envelope from: %s\nTimestamp: %s\nBody: %s\n", System.out.print(String.format("Envelope from: %s\nTimestamp: %s\nBody: %s\n",
messageReceived.getSender(), DateUtils.formatTimestamp(messageReceived.getTimestamp()), messageReceived.getMessage())); messageReceived.getSender(),
DateUtils.formatTimestamp(messageReceived.getTimestamp()),
messageReceived.getMessage()));
if (messageReceived.getGroupId().length > 0) { if (messageReceived.getGroupId().length > 0) {
System.out.println("Group info:"); System.out.println("Group info:");
System.out.println(" Id: " + Base64.encodeBytes(messageReceived.getGroupId())); System.out.println(" Id: " + Base64.encodeBytes(messageReceived.getGroupId()));
@ -78,23 +80,23 @@ public class ReceiveCommand implements ExtendedDbusCommand, LocalCommand {
} }
}); });
dbusconnection.addSigHandler(Signal.ReceiptReceived.class, dbusconnection.addSigHandler(Signal.ReceiptReceived.class, receiptReceived -> {
receiptReceived -> { if (jsonProcessor != null) {
if (jsonProcessor != null) { JsonMessageEnvelope envelope = new JsonMessageEnvelope(receiptReceived);
JsonMessageEnvelope envelope = new JsonMessageEnvelope(receiptReceived); ObjectNode result = jsonProcessor.createObjectNode();
ObjectNode result = jsonProcessor.createObjectNode(); result.putPOJO("envelope", envelope);
result.putPOJO("envelope", envelope); try {
try { jsonProcessor.writeValue(System.out, result);
jsonProcessor.writeValue(System.out, result); System.out.println();
System.out.println(); } catch (IOException e) {
} catch (IOException e) { e.printStackTrace();
e.printStackTrace(); }
} } else {
} else { System.out.print(String.format("Receipt from: %s\nTimestamp: %s\n",
System.out.print(String.format("Receipt from: %s\nTimestamp: %s\n", receiptReceived.getSender(),
receiptReceived.getSender(), DateUtils.formatTimestamp(receiptReceived.getTimestamp()))); DateUtils.formatTimestamp(receiptReceived.getTimestamp())));
} }
}); });
dbusconnection.addSigHandler(Signal.SyncMessageReceived.class, syncReceived -> { dbusconnection.addSigHandler(Signal.SyncMessageReceived.class, syncReceived -> {
if (jsonProcessor != null) { if (jsonProcessor != null) {
@ -109,7 +111,10 @@ public class ReceiveCommand implements ExtendedDbusCommand, LocalCommand {
} }
} else { } else {
System.out.print(String.format("Sync Envelope from: %s to: %s\nTimestamp: %s\nBody: %s\n", System.out.print(String.format("Sync Envelope from: %s to: %s\nTimestamp: %s\nBody: %s\n",
syncReceived.getSource(), syncReceived.getDestination(), DateUtils.formatTimestamp(syncReceived.getTimestamp()), syncReceived.getMessage())); syncReceived.getSource(),
syncReceived.getDestination(),
DateUtils.formatTimestamp(syncReceived.getTimestamp()),
syncReceived.getMessage()));
if (syncReceived.getGroupId().length > 0) { if (syncReceived.getGroupId().length > 0) {
System.out.println("Group info:"); System.out.println("Group info:");
System.out.println(" Id: " + Base64.encodeBytes(syncReceived.getGroupId())); System.out.println(" Id: " + Base64.encodeBytes(syncReceived.getGroupId()));
@ -156,8 +161,14 @@ public class ReceiveCommand implements ExtendedDbusCommand, LocalCommand {
} }
boolean ignoreAttachments = ns.getBoolean("ignore_attachments"); boolean ignoreAttachments = ns.getBoolean("ignore_attachments");
try { try {
final Manager.ReceiveMessageHandler handler = ns.getBoolean("json") ? new JsonReceiveMessageHandler(m) : new ReceiveMessageHandler(m); final Manager.ReceiveMessageHandler handler = ns.getBoolean("json")
m.receiveMessages((long) (timeout * 1000), TimeUnit.MILLISECONDS, returnOnTimeout, ignoreAttachments, handler); ? new JsonReceiveMessageHandler(m)
: new ReceiveMessageHandler(m);
m.receiveMessages((long) (timeout * 1000),
TimeUnit.MILLISECONDS,
returnOnTimeout,
ignoreAttachments,
handler);
return 0; return 0;
} catch (IOException e) { } catch (IOException e) {
System.err.println("Error while receiving messages: " + e.getMessage()); System.err.println("Error while receiving messages: " + e.getMessage());

View file

@ -22,16 +22,10 @@ public class SendCommand implements DbusCommand {
@Override @Override
public void attachToSubparser(final Subparser subparser) { public void attachToSubparser(final Subparser subparser) {
subparser.addArgument("-g", "--group") subparser.addArgument("-g", "--group").help("Specify the recipient group ID.");
.help("Specify the recipient group ID."); subparser.addArgument("recipient").help("Specify the recipients' phone number.").nargs("*");
subparser.addArgument("recipient") subparser.addArgument("-m", "--message").help("Specify the message, if missing standard input is used.");
.help("Specify the recipients' phone number.") subparser.addArgument("-a", "--attachment").nargs("*").help("Add file as attachment");
.nargs("*");
subparser.addArgument("-m", "--message")
.help("Specify the message, if missing standard input is used.");
subparser.addArgument("-a", "--attachment")
.nargs("*")
.help("Add file as attachment");
subparser.addArgument("-e", "--endsession") subparser.addArgument("-e", "--endsession")
.help("Clear session state and send end session message.") .help("Clear session state and send end session message.")
.action(Arguments.storeTrue()); .action(Arguments.storeTrue());
@ -44,7 +38,9 @@ public class SendCommand implements DbusCommand {
return 1; return 1;
} }
if ((ns.getList("recipient") == null || ns.getList("recipient").size() == 0) && (ns.getBoolean("endsession") || ns.getString("group") == null)) { if ((ns.getList("recipient") == null || ns.getList("recipient").size() == 0) && (
ns.getBoolean("endsession") || ns.getString("group") == null
)) {
System.err.println("No recipients given"); System.err.println("No recipients given");
System.err.println("Aborting sending."); System.err.println("Aborting sending.");
return 1; return 1;

View file

@ -29,11 +29,8 @@ public class SendReactionCommand implements LocalCommand {
@Override @Override
public void attachToSubparser(final Subparser subparser) { public void attachToSubparser(final Subparser subparser) {
subparser.help("Send reaction to a previously received or sent message."); subparser.help("Send reaction to a previously received or sent message.");
subparser.addArgument("-g", "--group") subparser.addArgument("-g", "--group").help("Specify the recipient group ID.");
.help("Specify the recipient group ID."); subparser.addArgument("recipient").help("Specify the recipients' phone number.").nargs("*");
subparser.addArgument("recipient")
.help("Specify the recipients' phone number.")
.nargs("*");
subparser.addArgument("-e", "--emoji") subparser.addArgument("-e", "--emoji")
.required(true) .required(true)
.help("Specify the emoji, should be a single unicode grapheme cluster."); .help("Specify the emoji, should be a single unicode grapheme cluster.");
@ -44,9 +41,7 @@ public class SendReactionCommand implements LocalCommand {
.required(true) .required(true)
.type(long.class) .type(long.class)
.help("Specify the timestamp of the message to which to react."); .help("Specify the timestamp of the message to which to react.");
subparser.addArgument("-r", "--remove") subparser.addArgument("-r", "--remove").help("Remove a reaction.").action(Arguments.storeTrue());
.help("Remove a reaction.")
.action(Arguments.storeTrue());
} }
@Override @Override
@ -73,7 +68,11 @@ public class SendReactionCommand implements LocalCommand {
byte[] groupId = Util.decodeGroupId(ns.getString("group")); byte[] groupId = Util.decodeGroupId(ns.getString("group"));
results = m.sendGroupMessageReaction(emoji, isRemove, targetAuthor, targetTimestamp, groupId); results = m.sendGroupMessageReaction(emoji, isRemove, targetAuthor, targetTimestamp, groupId);
} else { } else {
results = m.sendMessageReaction(emoji, isRemove, targetAuthor, targetTimestamp, ns.getList("recipient")); results = m.sendMessageReaction(emoji,
isRemove,
targetAuthor,
targetTimestamp,
ns.getList("recipient"));
} }
handleTimestampAndSendMessageResults(results.first(), results.second()); handleTimestampAndSendMessageResults(results.first(), results.second());
return 0; return 0;

View file

@ -16,9 +16,7 @@ public class TrustCommand implements LocalCommand {
@Override @Override
public void attachToSubparser(final Subparser subparser) { public void attachToSubparser(final Subparser subparser) {
subparser.addArgument("number") subparser.addArgument("number").help("Specify the phone number, for which to set the trust.").required(true);
.help("Specify the phone number, for which to set the trust.")
.required(true);
MutuallyExclusiveGroup mutTrust = subparser.addMutuallyExclusiveGroup(); MutuallyExclusiveGroup mutTrust = subparser.addMutuallyExclusiveGroup();
mutTrust.addArgument("-a", "--trust-all-known-keys") mutTrust.addArgument("-a", "--trust-all-known-keys")
.help("Trust all known keys of this user, only use this for testing.") .help("Trust all known keys of this user, only use this for testing.")
@ -49,7 +47,8 @@ public class TrustCommand implements LocalCommand {
try { try {
fingerprintBytes = Hex.toByteArray(safetyNumber.toLowerCase(Locale.ROOT)); fingerprintBytes = Hex.toByteArray(safetyNumber.toLowerCase(Locale.ROOT));
} catch (Exception e) { } catch (Exception e) {
System.err.println("Failed to parse the fingerprint, make sure the fingerprint is a correctly encoded hex string without additional characters."); System.err.println(
"Failed to parse the fingerprint, make sure the fingerprint is a correctly encoded hex string without additional characters.");
return 1; return 1;
} }
boolean res; boolean res;
@ -60,7 +59,8 @@ public class TrustCommand implements LocalCommand {
return 1; return 1;
} }
if (!res) { if (!res) {
System.err.println("Failed to set the trust for the fingerprint of this number, make sure the number and the fingerprint are correct."); System.err.println(
"Failed to set the trust for the fingerprint of this number, make sure the number and the fingerprint are correct.");
return 1; return 1;
} }
} else if (safetyNumber.length() == 60) { } else if (safetyNumber.length() == 60) {
@ -72,15 +72,18 @@ public class TrustCommand implements LocalCommand {
return 1; return 1;
} }
if (!res) { if (!res) {
System.err.println("Failed to set the trust for the safety number of this phone number, make sure the phone number and the safety number are correct."); System.err.println(
"Failed to set the trust for the safety number of this phone number, make sure the phone number and the safety number are correct.");
return 1; return 1;
} }
} else { } else {
System.err.println("Safety number has invalid format, either specify the old hex fingerprint or the new safety number"); System.err.println(
"Safety number has invalid format, either specify the old hex fingerprint or the new safety number");
return 1; return 1;
} }
} else { } else {
System.err.println("You need to specify the fingerprint/safety number you have verified with -v SAFETY_NUMBER"); System.err.println(
"You need to specify the fingerprint/safety number you have verified with -v SAFETY_NUMBER");
return 1; return 1;
} }
} }

View file

@ -13,12 +13,8 @@ public class UnblockCommand implements LocalCommand {
@Override @Override
public void attachToSubparser(final Subparser subparser) { public void attachToSubparser(final Subparser subparser) {
subparser.addArgument("contact") subparser.addArgument("contact").help("Contact number").nargs("*");
.help("Contact number") subparser.addArgument("-g", "--group").help("Group ID").nargs("*");
.nargs("*");
subparser.addArgument("-g", "--group")
.help("Group ID")
.nargs("*");
subparser.help("Unblock the given contacts or groups (messages will be received again)"); subparser.help("Unblock the given contacts or groups (messages will be received again)");
} }

View file

@ -12,11 +12,8 @@ public class UpdateContactCommand implements LocalCommand {
@Override @Override
public void attachToSubparser(final Subparser subparser) { public void attachToSubparser(final Subparser subparser) {
subparser.addArgument("number") subparser.addArgument("number").help("Contact number");
.help("Contact number"); subparser.addArgument("-n", "--name").required(true).help("New contact name");
subparser.addArgument("-n", "--name")
.required(true)
.help("New contact name");
subparser.addArgument("-e", "--expiration") subparser.addArgument("-e", "--expiration")
.required(false) .required(false)
.type(int.class) .type(int.class)

View file

@ -19,15 +19,10 @@ public class UpdateGroupCommand implements DbusCommand {
@Override @Override
public void attachToSubparser(final Subparser subparser) { public void attachToSubparser(final Subparser subparser) {
subparser.addArgument("-g", "--group") subparser.addArgument("-g", "--group").help("Specify the recipient group ID.");
.help("Specify the recipient group ID."); subparser.addArgument("-n", "--name").help("Specify the new group name.");
subparser.addArgument("-n", "--name") subparser.addArgument("-a", "--avatar").help("Specify a new group avatar image file");
.help("Specify the new group name."); subparser.addArgument("-m", "--member").nargs("*").help("Specify one or more members to add to the group");
subparser.addArgument("-a", "--avatar")
.help("Specify a new group avatar image file");
subparser.addArgument("-m", "--member")
.nargs("*")
.help("Specify one or more members to add to the group");
} }
@Override @Override

View file

@ -14,16 +14,11 @@ public class UpdateProfileCommand implements LocalCommand {
@Override @Override
public void attachToSubparser(final Subparser subparser) { public void attachToSubparser(final Subparser subparser) {
final MutuallyExclusiveGroup avatarOptions = subparser.addMutuallyExclusiveGroup() final MutuallyExclusiveGroup avatarOptions = subparser.addMutuallyExclusiveGroup().required(true);
.required(true); avatarOptions.addArgument("--avatar").help("Path to new profile avatar");
avatarOptions.addArgument("--avatar") avatarOptions.addArgument("--remove-avatar").action(Arguments.storeTrue());
.help("Path to new profile avatar");
avatarOptions.addArgument("--remove-avatar")
.action(Arguments.storeTrue());
subparser.addArgument("--name") subparser.addArgument("--name").required(true).help("New profile name");
.required(true)
.help("New profile name");
subparser.help("Set a name and avatar image for the user profile"); subparser.help("Set a name and avatar image for the user profile");
} }

View file

@ -12,10 +12,8 @@ public class VerifyCommand implements LocalCommand {
@Override @Override
public void attachToSubparser(final Subparser subparser) { public void attachToSubparser(final Subparser subparser) {
subparser.addArgument("verificationCode") subparser.addArgument("verificationCode").help("The verification code you received via sms or voice call.");
.help("The verification code you received via sms or voice call."); subparser.addArgument("-p", "--pin").help("The registration lock PIN, that was set by the user (Optional)");
subparser.addArgument("-p", "--pin")
.help("The registration lock PIN, that was set by the user (Optional)");
} }
@Override @Override
@ -30,7 +28,8 @@ public class VerifyCommand implements LocalCommand {
m.verifyAccount(verificationCode, pin); m.verifyAccount(verificationCode, pin);
return 0; return 0;
} catch (LockedException e) { } catch (LockedException e) {
System.err.println("Verification failed! This number is locked with a pin. Hours remaining until reset: " + (e.getTimeRemaining() / 1000 / 60 / 60)); System.err.println("Verification failed! This number is locked with a pin. Hours remaining until reset: "
+ (e.getTimeRemaining() / 1000 / 60 / 60));
System.err.println("Use '--pin PIN_CODE' to specify the registration lock PIN"); System.err.println("Use '--pin PIN_CODE' to specify the registration lock PIN");
return 3; return 3;
} catch (IOException e) { } catch (IOException e) {

View file

@ -45,8 +45,7 @@ public class DbusSignalImpl implements Signal {
} }
private static void checkSendMessageResults( private static void checkSendMessageResults(
long timestamp, long timestamp, List<SendMessageResult> results
List<SendMessageResult> results
) throws DBusExecutionException { ) throws DBusExecutionException {
List<String> errors = ErrorUtils.getErrorMessagesFromSendMessageResults(results); List<String> errors = ErrorUtils.getErrorMessagesFromSendMessageResults(results);
if (errors.size() == 0) { if (errors.size() == 0) {

View file

@ -41,19 +41,13 @@ class JsonDataMessage {
timestamp = messageReceived.getTimestamp(); timestamp = messageReceived.getTimestamp();
message = messageReceived.getMessage(); message = messageReceived.getMessage();
groupInfo = new JsonGroupInfo(messageReceived.getGroupId()); groupInfo = new JsonGroupInfo(messageReceived.getGroupId());
attachments = messageReceived.getAttachments() attachments = messageReceived.getAttachments().stream().map(JsonAttachment::new).collect(Collectors.toList());
.stream()
.map(JsonAttachment::new)
.collect(Collectors.toList());
} }
public JsonDataMessage(Signal.SyncMessageReceived messageReceived) { public JsonDataMessage(Signal.SyncMessageReceived messageReceived) {
timestamp = messageReceived.getTimestamp(); timestamp = messageReceived.getTimestamp();
message = messageReceived.getMessage(); message = messageReceived.getMessage();
groupInfo = new JsonGroupInfo(messageReceived.getGroupId()); groupInfo = new JsonGroupInfo(messageReceived.getGroupId());
attachments = messageReceived.getAttachments() attachments = messageReceived.getAttachments().stream().map(JsonAttachment::new).collect(Collectors.toList());
.stream()
.map(JsonAttachment::new)
.collect(Collectors.toList());
} }
} }

View file

@ -23,7 +23,9 @@ class JsonReceiptMessage {
this.timestamps = receiptMessage.getTimestamps(); this.timestamps = receiptMessage.getTimestamps();
} }
private JsonReceiptMessage(final long when, final boolean isDelivery, final boolean isRead, final List<Long> timestamps) { private JsonReceiptMessage(
final long when, final boolean isDelivery, final boolean isRead, final List<Long> timestamps
) {
this.when = when; this.when = when;
this.isDelivery = isDelivery; this.isDelivery = isDelivery;
this.isRead = isRead; this.isRead = isRead;

View file

@ -0,0 +1,28 @@
package org.asamk.signal.manager;
import org.asamk.signal.storage.groups.GroupInfo;
import org.asamk.signal.storage.groups.GroupInfoV1;
import org.asamk.signal.storage.groups.GroupInfoV2;
import org.whispersystems.signalservice.api.messages.SignalServiceDataMessage;
import org.whispersystems.signalservice.api.messages.SignalServiceGroup;
import org.whispersystems.signalservice.api.messages.SignalServiceGroupV2;
public class GroupUtils {
public static void setGroupContext(
final SignalServiceDataMessage.Builder messageBuilder, final GroupInfo groupInfo
) {
if (groupInfo instanceof GroupInfoV1) {
SignalServiceGroup group = SignalServiceGroup.newBuilder(SignalServiceGroup.Type.DELIVER)
.withId(groupInfo.groupId)
.build();
messageBuilder.asGroupMessage(group);
} else {
final GroupInfoV2 groupInfoV2 = (GroupInfoV2) groupInfo;
SignalServiceGroupV2 group = SignalServiceGroupV2.newBuilder(groupInfoV2.getMasterKey())
.withRevision(groupInfoV2.getGroup() == null ? 0 : groupInfoV2.getGroup().getRevision())
.build();
messageBuilder.asGroupMessage(group);
}
}
}

View file

@ -30,8 +30,7 @@ class SendReceiptAction implements HandleAction {
if (this == o) return true; if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false; if (o == null || getClass() != o.getClass()) return false;
final SendReceiptAction that = (SendReceiptAction) o; final SendReceiptAction that = (SendReceiptAction) o;
return timestamp == that.timestamp && return timestamp == that.timestamp && address.equals(that.address);
address.equals(that.address);
} }
@Override @Override
@ -111,8 +110,7 @@ class SendGroupInfoRequestAction implements HandleAction {
if (this == o) return true; if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false; if (o == null || getClass() != o.getClass()) return false;
final SendGroupInfoRequestAction that = (SendGroupInfoRequestAction) o; final SendGroupInfoRequestAction that = (SendGroupInfoRequestAction) o;
return address.equals(that.address) && return address.equals(that.address) && Arrays.equals(groupId, that.groupId);
Arrays.equals(groupId, that.groupId);
} }
@Override @Override
@ -143,8 +141,7 @@ class SendGroupUpdateAction implements HandleAction {
if (this == o) return true; if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false; if (o == null || getClass() != o.getClass()) return false;
final SendGroupUpdateAction that = (SendGroupUpdateAction) o; final SendGroupUpdateAction that = (SendGroupUpdateAction) o;
return address.equals(that.address) && return address.equals(that.address) && Arrays.equals(groupId, that.groupId);
Arrays.equals(groupId, that.groupId);
} }
@Override @Override

View file

@ -704,7 +704,7 @@ public class Manager implements Closeable {
) throws IOException, GroupNotFoundException, NotAGroupMemberException { ) throws IOException, GroupNotFoundException, NotAGroupMemberException {
final GroupInfo g = getGroupForSending(groupId); final GroupInfo g = getGroupForSending(groupId);
GroupHelper.setGroupContext(messageBuilder, g); GroupUtils.setGroupContext(messageBuilder, g);
messageBuilder.withExpiration(g.getMessageExpirationTime()); messageBuilder.withExpiration(g.getMessageExpirationTime());
return sendMessage(messageBuilder, g.getMembersWithout(account.getSelfAddress())); return sendMessage(messageBuilder, g.getMembersWithout(account.getSelfAddress()));

View file

@ -7,11 +7,7 @@ public class PathConfig {
private final String avatarsPath; private final String avatarsPath;
public static PathConfig createDefault(final String settingsPath) { public static PathConfig createDefault(final String settingsPath) {
return new PathConfig( return new PathConfig(settingsPath + "/data", settingsPath + "/attachments", settingsPath + "/avatars");
settingsPath + "/data",
settingsPath + "/attachments",
settingsPath + "/avatars"
);
} }
private PathConfig(final String dataPath, final String attachmentsPath, final String avatarsPath) { private PathConfig(final String dataPath, final String attachmentsPath, final String avatarsPath) {

View file

@ -70,12 +70,19 @@ public class ProvisioningManager {
public String getDeviceLinkUri() throws TimeoutException, IOException { public String getDeviceLinkUri() throws TimeoutException, IOException {
String deviceUuid = accountManager.getNewDeviceUuid(); String deviceUuid = accountManager.getNewDeviceUuid();
return Utils.createDeviceLinkUri(new Utils.DeviceLinkInfo(deviceUuid, identityKey.getPublicKey().getPublicKey())); return Utils.createDeviceLinkUri(new Utils.DeviceLinkInfo(deviceUuid,
identityKey.getPublicKey().getPublicKey()));
} }
public String finishDeviceLink(String deviceName) throws IOException, InvalidKeyException, TimeoutException, UserAlreadyExists { public String finishDeviceLink(String deviceName) throws IOException, InvalidKeyException, TimeoutException, UserAlreadyExists {
String signalingKey = KeyUtils.createSignalingKey(); String signalingKey = KeyUtils.createSignalingKey();
SignalServiceAccountManager.NewDeviceRegistrationReturn ret = accountManager.finishNewDeviceRegistration(identityKey, signalingKey, false, true, registrationId, deviceName); SignalServiceAccountManager.NewDeviceRegistrationReturn ret = accountManager.finishNewDeviceRegistration(
identityKey,
signalingKey,
false,
true,
registrationId,
deviceName);
String username = ret.getNumber(); String username = ret.getNumber();
// TODO do this check before actually registering // TODO do this check before actually registering
@ -96,7 +103,15 @@ public class ProvisioningManager {
} }
} }
try (SignalAccount account = SignalAccount.createLinkedAccount(pathConfig.getDataPath(), username, ret.getUuid(), password, ret.getDeviceId(), ret.getIdentity(), registrationId, signalingKey, profileKey)) { try (SignalAccount account = SignalAccount.createLinkedAccount(pathConfig.getDataPath(),
username,
ret.getUuid(),
password,
ret.getDeviceId(),
ret.getIdentity(),
registrationId,
signalingKey,
profileKey)) {
account.save(); account.save();
try (Manager m = new Manager(account, pathConfig, serviceConfiguration, userAgent)) { try (Manager m = new Manager(account, pathConfig, serviceConfiguration, userAgent)) {

View file

@ -61,26 +61,27 @@ public class ServiceConfig {
} }
public static SignalServiceConfiguration createDefaultServiceConfiguration(String userAgent) { public static SignalServiceConfiguration createDefaultServiceConfiguration(String userAgent) {
final Interceptor userAgentInterceptor = chain -> final Interceptor userAgentInterceptor = chain -> chain.proceed(chain.request()
chain.proceed(chain.request().newBuilder() .newBuilder()
.header("User-Agent", userAgent) .header("User-Agent", userAgent)
.build()); .build());
final List<Interceptor> interceptors = Collections.singletonList(userAgentInterceptor); final List<Interceptor> interceptors = Collections.singletonList(userAgentInterceptor);
return new SignalServiceConfiguration( return new SignalServiceConfiguration(new SignalServiceUrl[]{new SignalServiceUrl(URL, TRUST_STORE)},
new SignalServiceUrl[]{new SignalServiceUrl(URL, TRUST_STORE)}, makeSignalCdnUrlMapFor(new SignalCdnUrl[]{new SignalCdnUrl(CDN_URL, TRUST_STORE)},
makeSignalCdnUrlMapFor(new SignalCdnUrl[]{new SignalCdnUrl(CDN_URL, TRUST_STORE)}, new SignalCdnUrl[]{new SignalCdnUrl(CDN2_URL, TRUST_STORE)}), new SignalCdnUrl[]{new SignalCdnUrl(CDN2_URL, TRUST_STORE)}),
new SignalContactDiscoveryUrl[0], new SignalContactDiscoveryUrl[0],
new SignalKeyBackupServiceUrl[]{new SignalKeyBackupServiceUrl(SIGNAL_KEY_BACKUP_URL, TRUST_STORE)}, new SignalKeyBackupServiceUrl[]{new SignalKeyBackupServiceUrl(SIGNAL_KEY_BACKUP_URL, TRUST_STORE)},
new SignalStorageUrl[]{new SignalStorageUrl(STORAGE_URL, TRUST_STORE)}, new SignalStorageUrl[]{new SignalStorageUrl(STORAGE_URL, TRUST_STORE)},
interceptors, interceptors,
dns, dns,
zkGroupServerPublicParams zkGroupServerPublicParams);
);
} }
private static Map<Integer, SignalCdnUrl[]> makeSignalCdnUrlMapFor(SignalCdnUrl[] cdn0Urls, SignalCdnUrl[] cdn2Urls) { private static Map<Integer, SignalCdnUrl[]> makeSignalCdnUrlMapFor(
SignalCdnUrl[] cdn0Urls, SignalCdnUrl[] cdn2Urls
) {
return Map.of(0, cdn0Urls, 2, cdn2Urls); return Map.of(0, cdn0Urls, 2, cdn2Urls);
} }

View file

@ -81,7 +81,21 @@ class Utils {
Optional<String> caption = Optional.absent(); Optional<String> caption = Optional.absent();
Optional<String> blurHash = Optional.absent(); Optional<String> blurHash = Optional.absent();
final Optional<ResumableUploadSpec> resumableUploadSpec = Optional.absent(); final Optional<ResumableUploadSpec> resumableUploadSpec = Optional.absent();
return new SignalServiceAttachmentStream(attachmentStream, mime, attachmentSize, Optional.of(attachmentFile.getName()), false, false, preview, 0, 0, uploadTimestamp, caption, blurHash, null, null, resumableUploadSpec); return new SignalServiceAttachmentStream(attachmentStream,
mime,
attachmentSize,
Optional.of(attachmentFile.getName()),
false,
false,
preview,
0,
0,
uploadTimestamp,
caption,
blurHash,
null,
null,
resumableUploadSpec);
} }
static StreamDetails createStreamDetailsFromFile(File file) throws IOException { static StreamDetails createStreamDetailsFromFile(File file) throws IOException {
@ -96,7 +110,8 @@ class Utils {
static CertificateValidator getCertificateValidator() { static CertificateValidator getCertificateValidator() {
try { try {
ECPublicKey unidentifiedSenderTrustRoot = Curve.decodePoint(Base64.decode(ServiceConfig.UNIDENTIFIED_SENDER_TRUST_ROOT), 0); ECPublicKey unidentifiedSenderTrustRoot = Curve.decodePoint(Base64.decode(ServiceConfig.UNIDENTIFIED_SENDER_TRUST_ROOT),
0);
return new CertificateValidator(unidentifiedSenderTrustRoot); return new CertificateValidator(unidentifiedSenderTrustRoot);
} catch (InvalidKeyException | IOException e) { } catch (InvalidKeyException | IOException e) {
throw new AssertionError(e); throw new AssertionError(e);
@ -116,7 +131,11 @@ class Utils {
} }
static String createDeviceLinkUri(DeviceLinkInfo info) { static String createDeviceLinkUri(DeviceLinkInfo info) {
return "tsdevice:/?uuid=" + URLEncoder.encode(info.deviceIdentifier, StandardCharsets.UTF_8) + "&pub_key=" + URLEncoder.encode(Base64.encodeBytesWithoutPadding(info.deviceKey.serialize()), StandardCharsets.UTF_8); return "tsdevice:/?uuid="
+ URLEncoder.encode(info.deviceIdentifier, StandardCharsets.UTF_8)
+ "&pub_key="
+ URLEncoder.encode(Base64.encodeBytesWithoutPadding(info.deviceKey.serialize()),
StandardCharsets.UTF_8);
} }
static DeviceLinkInfo parseDeviceLinkUri(URI linkUri) throws IOException, InvalidKeyException { static DeviceLinkInfo parseDeviceLinkUri(URI linkUri) throws IOException, InvalidKeyException {
@ -180,7 +199,15 @@ class Utils {
Optional<SignalServiceAddress> addressOptional = sourceUuid == null && source.isEmpty() Optional<SignalServiceAddress> addressOptional = sourceUuid == null && source.isEmpty()
? Optional.absent() ? Optional.absent()
: Optional.of(new SignalServiceAddress(sourceUuid, source)); : Optional.of(new SignalServiceAddress(sourceUuid, source));
return new SignalServiceEnvelope(type, addressOptional, sourceDevice, timestamp, legacyMessage, content, serverReceivedTimestamp, serverDeliveredTimestamp, uuid); return new SignalServiceEnvelope(type,
addressOptional,
sourceDevice,
timestamp,
legacyMessage,
content,
serverReceivedTimestamp,
serverDeliveredTimestamp,
uuid);
} }
} }
@ -230,13 +257,18 @@ class Utils {
return outputFile; return outputFile;
} }
static String computeSafetyNumber(SignalServiceAddress ownAddress, IdentityKey ownIdentityKey, SignalServiceAddress theirAddress, IdentityKey theirIdentityKey) { static String computeSafetyNumber(
SignalServiceAddress ownAddress,
IdentityKey ownIdentityKey,
SignalServiceAddress theirAddress,
IdentityKey theirIdentityKey
) {
int version; int version;
byte[] ownId; byte[] ownId;
byte[] theirId; byte[] theirId;
if (ServiceConfig.capabilities.isUuid() if (ServiceConfig.capabilities.isUuid() && ownAddress.getUuid().isPresent() && theirAddress.getUuid()
&& ownAddress.getUuid().isPresent() && theirAddress.getUuid().isPresent()) { .isPresent()) {
// Version 2: UUID user // Version 2: UUID user
version = 2; version = 2;
ownId = UuidUtil.toByteArray(ownAddress.getUuid().get()); ownId = UuidUtil.toByteArray(ownAddress.getUuid().get());
@ -251,7 +283,11 @@ class Utils {
theirId = theirAddress.getNumber().get().getBytes(); theirId = theirAddress.getNumber().get().getBytes();
} }
Fingerprint fingerprint = new NumericFingerprintGenerator(5200).createFor(version, ownId, ownIdentityKey, theirId, theirIdentityKey); Fingerprint fingerprint = new NumericFingerprintGenerator(5200).createFor(version,
ownId,
ownIdentityKey,
theirId,
theirIdentityKey);
return fingerprint.getDisplayableFingerprint().getDisplayText(); return fingerprint.getDisplayableFingerprint().getDisplayText();
} }

View file

@ -1,17 +1,11 @@
package org.asamk.signal.manager.helper; package org.asamk.signal.manager.helper;
import org.asamk.signal.storage.groups.GroupInfo;
import org.asamk.signal.storage.groups.GroupInfoV1;
import org.asamk.signal.storage.groups.GroupInfoV2;
import org.signal.storageservice.protos.groups.Member; import org.signal.storageservice.protos.groups.Member;
import org.signal.zkgroup.groups.GroupSecretParams; import org.signal.zkgroup.groups.GroupSecretParams;
import org.signal.zkgroup.profiles.ProfileKeyCredential; import org.signal.zkgroup.profiles.ProfileKeyCredential;
import org.whispersystems.libsignal.util.guava.Optional; import org.whispersystems.libsignal.util.guava.Optional;
import org.whispersystems.signalservice.api.groupsv2.GroupCandidate; import org.whispersystems.signalservice.api.groupsv2.GroupCandidate;
import org.whispersystems.signalservice.api.groupsv2.GroupsV2Operations; import org.whispersystems.signalservice.api.groupsv2.GroupsV2Operations;
import org.whispersystems.signalservice.api.messages.SignalServiceDataMessage;
import org.whispersystems.signalservice.api.messages.SignalServiceGroup;
import org.whispersystems.signalservice.api.messages.SignalServiceGroupV2;
import org.whispersystems.signalservice.api.push.SignalServiceAddress; import org.whispersystems.signalservice.api.push.SignalServiceAddress;
import java.util.Collection; import java.util.Collection;
@ -40,23 +34,6 @@ public class GroupHelper {
this.groupsV2Operations = groupsV2Operations; this.groupsV2Operations = groupsV2Operations;
} }
public static void setGroupContext(
final SignalServiceDataMessage.Builder messageBuilder, final GroupInfo groupInfo
) {
if (groupInfo instanceof GroupInfoV1) {
SignalServiceGroup group = SignalServiceGroup.newBuilder(SignalServiceGroup.Type.DELIVER)
.withId(groupInfo.groupId)
.build();
messageBuilder.asGroupMessage(group);
} else {
final GroupInfoV2 groupInfoV2 = (GroupInfoV2) groupInfo;
SignalServiceGroupV2 group = SignalServiceGroupV2.newBuilder(groupInfoV2.getMasterKey())
.withRevision(groupInfoV2.getGroup() == null ? 0 : groupInfoV2.getGroup().getRevision())
.build();
messageBuilder.asGroupMessage(group);
}
}
public GroupsV2Operations.NewGroup createGroupV2( public GroupsV2Operations.NewGroup createGroupV2(
String name, Collection<SignalServiceAddress> members, byte[] avatar String name, Collection<SignalServiceAddress> members, byte[] avatar
) { ) {

View file

@ -46,8 +46,7 @@ public final class ProfileHelper {
} }
public ProfileAndCredential retrieveProfileSync( public ProfileAndCredential retrieveProfileSync(
SignalServiceAddress recipient, SignalServiceAddress recipient, SignalServiceProfile.RequestType requestType
SignalServiceProfile.RequestType requestType
) throws IOException { ) throws IOException {
try { try {
return retrieveProfile(recipient, requestType).get(10, TimeUnit.SECONDS); return retrieveProfile(recipient, requestType).get(10, TimeUnit.SECONDS);
@ -65,28 +64,31 @@ public final class ProfileHelper {
} }
public ListenableFuture<ProfileAndCredential> retrieveProfile( public ListenableFuture<ProfileAndCredential> retrieveProfile(
SignalServiceAddress address, SignalServiceAddress address, SignalServiceProfile.RequestType requestType
SignalServiceProfile.RequestType requestType
) { ) {
Optional<UnidentifiedAccess> unidentifiedAccess = getUnidentifiedAccess(address); Optional<UnidentifiedAccess> unidentifiedAccess = getUnidentifiedAccess(address);
Optional<ProfileKey> profileKey = Optional.fromNullable(profileKeyProvider.getProfileKey(address)); Optional<ProfileKey> profileKey = Optional.fromNullable(profileKeyProvider.getProfileKey(address));
if (unidentifiedAccess.isPresent()) { if (unidentifiedAccess.isPresent()) {
return new CascadingFuture<>(Arrays.asList(() -> getPipeRetrievalFuture(address, profileKey, unidentifiedAccess, requestType), return new CascadingFuture<>(Arrays.asList(() -> getPipeRetrievalFuture(address,
profileKey,
unidentifiedAccess,
requestType),
() -> getSocketRetrievalFuture(address, profileKey, unidentifiedAccess, requestType), () -> getSocketRetrievalFuture(address, profileKey, unidentifiedAccess, requestType),
() -> getPipeRetrievalFuture(address, profileKey, Optional.absent(), requestType), () -> getPipeRetrievalFuture(address, profileKey, Optional.absent(), requestType),
() -> getSocketRetrievalFuture(address, profileKey, Optional.absent(), requestType)), () -> getSocketRetrievalFuture(address, profileKey, Optional.absent(), requestType)),
e -> !(e instanceof NotFoundException)); e -> !(e instanceof NotFoundException));
} else { } else {
return new CascadingFuture<>(Arrays.asList(() -> getPipeRetrievalFuture(address, profileKey, Optional.absent(), requestType), return new CascadingFuture<>(Arrays.asList(() -> getPipeRetrievalFuture(address,
() -> getSocketRetrievalFuture(address, profileKey, Optional.absent(), requestType)), profileKey,
Optional.absent(),
requestType), () -> getSocketRetrievalFuture(address, profileKey, Optional.absent(), requestType)),
e -> !(e instanceof NotFoundException)); e -> !(e instanceof NotFoundException));
} }
} }
public String decryptName( public String decryptName(
ProfileKey profileKey, ProfileKey profileKey, String encryptedName
String encryptedName
) throws InvalidCiphertextException, IOException { ) throws InvalidCiphertextException, IOException {
if (encryptedName == null) { if (encryptedName == null) {
return null; return null;

View file

@ -24,7 +24,12 @@ public class UnidentifiedAccessHelper {
private final UnidentifiedAccessSenderCertificateProvider senderCertificateProvider; private final UnidentifiedAccessSenderCertificateProvider senderCertificateProvider;
public UnidentifiedAccessHelper(final SelfProfileKeyProvider selfProfileKeyProvider, final ProfileKeyProvider profileKeyProvider, final ProfileProvider profileProvider, final UnidentifiedAccessSenderCertificateProvider senderCertificateProvider) { public UnidentifiedAccessHelper(
final SelfProfileKeyProvider selfProfileKeyProvider,
final ProfileKeyProvider profileKeyProvider,
final ProfileProvider profileProvider,
final UnidentifiedAccessSenderCertificateProvider senderCertificateProvider
) {
this.selfProfileKeyProvider = selfProfileKeyProvider; this.selfProfileKeyProvider = selfProfileKeyProvider;
this.profileKeyProvider = profileKeyProvider; this.profileKeyProvider = profileKeyProvider;
this.profileProvider = profileProvider; this.profileProvider = profileProvider;
@ -62,19 +67,16 @@ public class UnidentifiedAccessHelper {
} }
try { try {
return Optional.of(new UnidentifiedAccessPair( return Optional.of(new UnidentifiedAccessPair(new UnidentifiedAccess(selfUnidentifiedAccessKey,
new UnidentifiedAccess(selfUnidentifiedAccessKey, selfUnidentifiedAccessCertificate), selfUnidentifiedAccessCertificate),
new UnidentifiedAccess(selfUnidentifiedAccessKey, selfUnidentifiedAccessCertificate) new UnidentifiedAccess(selfUnidentifiedAccessKey, selfUnidentifiedAccessCertificate)));
));
} catch (InvalidCertificateException e) { } catch (InvalidCertificateException e) {
return Optional.absent(); return Optional.absent();
} }
} }
public List<Optional<UnidentifiedAccessPair>> getAccessFor(Collection<SignalServiceAddress> recipients) { public List<Optional<UnidentifiedAccessPair>> getAccessFor(Collection<SignalServiceAddress> recipients) {
return recipients.stream() return recipients.stream().map(this::getAccessFor).collect(Collectors.toList());
.map(this::getAccessFor)
.collect(Collectors.toList());
} }
public Optional<UnidentifiedAccessPair> getAccessFor(SignalServiceAddress recipient) { public Optional<UnidentifiedAccessPair> getAccessFor(SignalServiceAddress recipient) {
@ -82,15 +84,16 @@ public class UnidentifiedAccessHelper {
byte[] selfUnidentifiedAccessKey = getSelfUnidentifiedAccessKey(); byte[] selfUnidentifiedAccessKey = getSelfUnidentifiedAccessKey();
byte[] selfUnidentifiedAccessCertificate = senderCertificateProvider.getSenderCertificate(); byte[] selfUnidentifiedAccessCertificate = senderCertificateProvider.getSenderCertificate();
if (recipientUnidentifiedAccessKey == null || selfUnidentifiedAccessKey == null || selfUnidentifiedAccessCertificate == null) { if (recipientUnidentifiedAccessKey == null
|| selfUnidentifiedAccessKey == null
|| selfUnidentifiedAccessCertificate == null) {
return Optional.absent(); return Optional.absent();
} }
try { try {
return Optional.of(new UnidentifiedAccessPair( return Optional.of(new UnidentifiedAccessPair(new UnidentifiedAccess(recipientUnidentifiedAccessKey,
new UnidentifiedAccess(recipientUnidentifiedAccessKey, selfUnidentifiedAccessCertificate), selfUnidentifiedAccessCertificate),
new UnidentifiedAccess(selfUnidentifiedAccessKey, selfUnidentifiedAccessCertificate) new UnidentifiedAccess(selfUnidentifiedAccessKey, selfUnidentifiedAccessCertificate)));
));
} catch (InvalidCertificateException e) { } catch (InvalidCertificateException e) {
return Optional.absent(); return Optional.absent();
} }

View file

@ -99,7 +99,9 @@ public class SignalAccount implements Closeable {
} }
} }
public static SignalAccount create(String dataPath, String username, IdentityKeyPair identityKey, int registrationId, ProfileKey profileKey) throws IOException { public static SignalAccount create(
String dataPath, String username, IdentityKeyPair identityKey, int registrationId, ProfileKey profileKey
) throws IOException {
IOUtils.createPrivateDirectories(dataPath); IOUtils.createPrivateDirectories(dataPath);
String fileName = getFileName(dataPath, username); String fileName = getFileName(dataPath, username);
if (!new File(fileName).exists()) { if (!new File(fileName).exists()) {
@ -122,7 +124,17 @@ public class SignalAccount implements Closeable {
return account; return account;
} }
public static SignalAccount createLinkedAccount(String dataPath, String username, UUID uuid, String password, int deviceId, IdentityKeyPair identityKey, int registrationId, String signalingKey, ProfileKey profileKey) throws IOException { public static SignalAccount createLinkedAccount(
String dataPath,
String username,
UUID uuid,
String password,
int deviceId,
IdentityKeyPair identityKey,
int registrationId,
String signalingKey,
ProfileKey profileKey
) throws IOException {
IOUtils.createPrivateDirectories(dataPath); IOUtils.createPrivateDirectories(dataPath);
String fileName = getFileName(dataPath, username); String fileName = getFileName(dataPath, username);
if (!new File(fileName).exists()) { if (!new File(fileName).exists()) {
@ -209,11 +221,14 @@ public class SignalAccount implements Closeable {
try { try {
profileKey = new ProfileKey(Base64.decode(Util.getNotNullNode(rootNode, "profileKey").asText())); profileKey = new ProfileKey(Base64.decode(Util.getNotNullNode(rootNode, "profileKey").asText()));
} catch (InvalidInputException e) { } catch (InvalidInputException e) {
throw new IOException("Config file contains an invalid profileKey, needs to be base64 encoded array of 32 bytes", e); throw new IOException(
"Config file contains an invalid profileKey, needs to be base64 encoded array of 32 bytes",
e);
} }
} }
signalProtocolStore = jsonProcessor.convertValue(Util.getNotNullNode(rootNode, "axolotlStore"), JsonSignalProtocolStore.class); signalProtocolStore = jsonProcessor.convertValue(Util.getNotNullNode(rootNode, "axolotlStore"),
JsonSignalProtocolStore.class);
registered = Util.getNotNullNode(rootNode, "registered").asBoolean(); registered = Util.getNotNullNode(rootNode, "registered").asBoolean();
JsonNode groupStoreNode = rootNode.get("groupStore"); JsonNode groupStoreNode = rootNode.get("groupStore");
if (groupStoreNode != null) { if (groupStoreNode != null) {
@ -281,7 +296,8 @@ public class SignalAccount implements Closeable {
JsonNode threadStoreNode = rootNode.get("threadStore"); JsonNode threadStoreNode = rootNode.get("threadStore");
if (threadStoreNode != null) { if (threadStoreNode != null) {
LegacyJsonThreadStore threadStore = jsonProcessor.convertValue(threadStoreNode, LegacyJsonThreadStore.class); LegacyJsonThreadStore threadStore = jsonProcessor.convertValue(threadStoreNode,
LegacyJsonThreadStore.class);
// Migrate thread info to group and contact store // Migrate thread info to group and contact store
for (ThreadInfo thread : threadStore.getThreads()) { for (ThreadInfo thread : threadStore.getThreads()) {
if (thread.id == null || thread.id.isEmpty()) { if (thread.id == null || thread.id.isEmpty()) {
@ -326,8 +342,7 @@ public class SignalAccount implements Closeable {
.putPOJO("contactStore", contactStore) .putPOJO("contactStore", contactStore)
.putPOJO("recipientStore", recipientStore) .putPOJO("recipientStore", recipientStore)
.putPOJO("profileStore", profileStore) .putPOJO("profileStore", profileStore)
.putPOJO("stickerStore", stickerStore) .putPOJO("stickerStore", stickerStore);
;
try { try {
try (ByteArrayOutputStream output = new ByteArrayOutputStream()) { try (ByteArrayOutputStream output = new ByteArrayOutputStream()) {
// Write to memory first to prevent corrupting the file in case of serialization errors // Write to memory first to prevent corrupting the file in case of serialization errors

View file

@ -52,7 +52,18 @@ public class GroupInfoV1 extends GroupInfo {
return name; return name;
} }
public GroupInfoV1(@JsonProperty("groupId") byte[] groupId, @JsonProperty("name") String name, @JsonProperty("members") Collection<SignalServiceAddress> members, @JsonProperty("avatarId") long _ignored_avatarId, @JsonProperty("color") String color, @JsonProperty("blocked") boolean blocked, @JsonProperty("inboxPosition") Integer inboxPosition, @JsonProperty("archived") boolean archived, @JsonProperty("messageExpirationTime") int messageExpirationTime, @JsonProperty("active") boolean _ignored_active) { public GroupInfoV1(
@JsonProperty("groupId") byte[] groupId,
@JsonProperty("name") String name,
@JsonProperty("members") Collection<SignalServiceAddress> members,
@JsonProperty("avatarId") long _ignored_avatarId,
@JsonProperty("color") String color,
@JsonProperty("blocked") boolean blocked,
@JsonProperty("inboxPosition") Integer inboxPosition,
@JsonProperty("archived") boolean archived,
@JsonProperty("messageExpirationTime") int messageExpirationTime,
@JsonProperty("active") boolean _ignored_active
) {
super(groupId); super(groupId);
this.name = name; this.name = name;
this.members.addAll(members); this.members.addAll(members);
@ -123,7 +134,9 @@ public class GroupInfoV1 extends GroupInfo {
private static class MembersSerializer extends JsonSerializer<Set<SignalServiceAddress>> { private static class MembersSerializer extends JsonSerializer<Set<SignalServiceAddress>> {
@Override @Override
public void serialize(final Set<SignalServiceAddress> value, final JsonGenerator jgen, final SerializerProvider provider) throws IOException { public void serialize(
final Set<SignalServiceAddress> value, final JsonGenerator jgen, final SerializerProvider provider
) throws IOException {
jgen.writeStartArray(value.size()); jgen.writeStartArray(value.size());
for (SignalServiceAddress address : value) { for (SignalServiceAddress address : value) {
if (address.getUuid().isPresent()) { if (address.getUuid().isPresent()) {
@ -139,7 +152,9 @@ public class GroupInfoV1 extends GroupInfo {
private static class MembersDeserializer extends JsonDeserializer<Set<SignalServiceAddress>> { private static class MembersDeserializer extends JsonDeserializer<Set<SignalServiceAddress>> {
@Override @Override
public Set<SignalServiceAddress> deserialize(JsonParser jsonParser, DeserializationContext deserializationContext) throws IOException { public Set<SignalServiceAddress> deserialize(
JsonParser jsonParser, DeserializationContext deserializationContext
) throws IOException {
Set<SignalServiceAddress> addresses = new HashSet<>(); Set<SignalServiceAddress> addresses = new HashSet<>();
JsonNode node = jsonParser.getCodec().readTree(jsonParser); JsonNode node = jsonParser.getCodec().readTree(jsonParser);
for (JsonNode n : node) { for (JsonNode n : node) {

View file

@ -46,7 +46,8 @@ public class GroupInfoV2 extends GroupInfo {
if (this.group == null) { if (this.group == null) {
return Collections.emptySet(); return Collections.emptySet();
} }
return group.getMembersList().stream() return group.getMembersList()
.stream()
.map(m -> new SignalServiceAddress(UuidUtil.parseOrThrow(m.getUuid().toByteArray()), null)) .map(m -> new SignalServiceAddress(UuidUtil.parseOrThrow(m.getUuid().toByteArray()), null))
.collect(Collectors.toSet()); .collect(Collectors.toSet());
} }
@ -56,7 +57,8 @@ public class GroupInfoV2 extends GroupInfo {
if (this.group == null) { if (this.group == null) {
return Collections.emptySet(); return Collections.emptySet();
} }
return group.getPendingMembersList().stream() return group.getPendingMembersList()
.stream()
.map(m -> new SignalServiceAddress(UuidUtil.parseOrThrow(m.getUuid().toByteArray()), null)) .map(m -> new SignalServiceAddress(UuidUtil.parseOrThrow(m.getUuid().toByteArray()), null))
.collect(Collectors.toSet()); .collect(Collectors.toSet());
} }
@ -66,7 +68,8 @@ public class GroupInfoV2 extends GroupInfo {
if (this.group == null) { if (this.group == null) {
return Collections.emptySet(); return Collections.emptySet();
} }
return group.getRequestingMembersList().stream() return group.getRequestingMembersList()
.stream()
.map(m -> new SignalServiceAddress(UuidUtil.parseOrThrow(m.getUuid().toByteArray()), null)) .map(m -> new SignalServiceAddress(UuidUtil.parseOrThrow(m.getUuid().toByteArray()), null))
.collect(Collectors.toSet()); .collect(Collectors.toSet());
} }

View file

@ -104,9 +104,7 @@ public class JsonGroupStore {
@Override @Override
public void serialize( public void serialize(
final Map<String, GroupInfo> value, final Map<String, GroupInfo> value, final JsonGenerator jgen, final SerializerProvider provider
final JsonGenerator jgen,
final SerializerProvider provider
) throws IOException { ) throws IOException {
final Collection<GroupInfo> groups = value.values(); final Collection<GroupInfo> groups = value.values();
jgen.writeStartArray(groups.size()); jgen.writeStartArray(groups.size());
@ -132,8 +130,7 @@ public class JsonGroupStore {
@Override @Override
public Map<String, GroupInfo> deserialize( public Map<String, GroupInfo> deserialize(
JsonParser jsonParser, JsonParser jsonParser, DeserializationContext deserializationContext
DeserializationContext deserializationContext
) throws IOException { ) throws IOException {
Map<String, GroupInfo> groups = new HashMap<>(); Map<String, GroupInfo> groups = new HashMap<>();
JsonNode node = jsonParser.getCodec().readTree(jsonParser); JsonNode node = jsonParser.getCodec().readTree(jsonParser);

View file

@ -26,7 +26,14 @@ public class SignalProfile {
@JsonProperty @JsonProperty
private final Capabilities capabilities; private final Capabilities capabilities;
public SignalProfile(final String identityKey, final String name, final File avatarFile, final String unidentifiedAccess, final boolean unrestrictedUnidentifiedAccess, final SignalServiceProfile.Capabilities capabilities) { public SignalProfile(
final String identityKey,
final String name,
final File avatarFile,
final String unidentifiedAccess,
final boolean unrestrictedUnidentifiedAccess,
final SignalServiceProfile.Capabilities capabilities
) {
this.identityKey = identityKey; this.identityKey = identityKey;
this.name = name; this.name = name;
this.avatarFile = avatarFile; this.avatarFile = avatarFile;
@ -38,7 +45,13 @@ public class SignalProfile {
this.capabilities.gv2 = capabilities.isGv2(); this.capabilities.gv2 = capabilities.isGv2();
} }
public SignalProfile(@JsonProperty("identityKey") final String identityKey, @JsonProperty("name") final String name, @JsonProperty("unidentifiedAccess") final String unidentifiedAccess, @JsonProperty("unrestrictedUnidentifiedAccess") final boolean unrestrictedUnidentifiedAccess, @JsonProperty("capabilities") final Capabilities capabilities) { public SignalProfile(
@JsonProperty("identityKey") final String identityKey,
@JsonProperty("name") final String name,
@JsonProperty("unidentifiedAccess") final String unidentifiedAccess,
@JsonProperty("unrestrictedUnidentifiedAccess") final boolean unrestrictedUnidentifiedAccess,
@JsonProperty("capabilities") final Capabilities capabilities
) {
this.identityKey = identityKey; this.identityKey = identityKey;
this.name = name; this.name = name;
this.avatarFile = null; this.avatarFile = null;
@ -73,14 +86,23 @@ public class SignalProfile {
@Override @Override
public String toString() { public String toString() {
return "SignalProfile{" + return "SignalProfile{"
"identityKey='" + identityKey + '\'' + + "identityKey='"
", name='" + name + '\'' + + identityKey
", avatarFile=" + avatarFile + + '\''
", unidentifiedAccess='" + unidentifiedAccess + '\'' + + ", name='"
", unrestrictedUnidentifiedAccess=" + unrestrictedUnidentifiedAccess + + name
", capabilities=" + capabilities + + '\''
'}'; + ", avatarFile="
+ avatarFile
+ ", unidentifiedAccess='"
+ unidentifiedAccess
+ '\''
+ ", unrestrictedUnidentifiedAccess="
+ unrestrictedUnidentifiedAccess
+ ", capabilities="
+ capabilities
+ '}';
} }
public static class Capabilities { public static class Capabilities {

View file

@ -63,7 +63,10 @@ public class JsonIdentityKeyStore implements IdentityKeyStore {
@Override @Override
public boolean saveIdentity(SignalProtocolAddress address, IdentityKey identityKey) { public boolean saveIdentity(SignalProtocolAddress address, IdentityKey identityKey) {
return saveIdentity(resolveSignalServiceAddress(address.getName()), identityKey, TrustLevel.TRUSTED_UNVERIFIED, null); return saveIdentity(resolveSignalServiceAddress(address.getName()),
identityKey,
TrustLevel.TRUSTED_UNVERIFIED,
null);
} }
/** /**
@ -75,7 +78,9 @@ public class JsonIdentityKeyStore implements IdentityKeyStore {
* @param trustLevel Level of trust: untrusted, trusted, trusted and verified * @param trustLevel Level of trust: untrusted, trusted, trusted and verified
* @param added Added timestamp, if null and the key is newly added, the current time is used. * @param added Added timestamp, if null and the key is newly added, the current time is used.
*/ */
public boolean saveIdentity(SignalServiceAddress serviceAddress, IdentityKey identityKey, TrustLevel trustLevel, Date added) { public boolean saveIdentity(
SignalServiceAddress serviceAddress, IdentityKey identityKey, TrustLevel trustLevel, Date added
) {
for (Identity id : identities) { for (Identity id : identities) {
if (!id.address.matches(serviceAddress) || !id.identityKey.equals(identityKey)) { if (!id.address.matches(serviceAddress) || !id.identityKey.equals(identityKey)) {
continue; continue;
@ -99,7 +104,9 @@ public class JsonIdentityKeyStore implements IdentityKeyStore {
* @param identityKey The user's public key * @param identityKey The user's public key
* @param trustLevel Level of trust: untrusted, trusted, trusted and verified * @param trustLevel Level of trust: untrusted, trusted, trusted and verified
*/ */
public void setIdentityTrustLevel(SignalServiceAddress serviceAddress, IdentityKey identityKey, TrustLevel trustLevel) { public void setIdentityTrustLevel(
SignalServiceAddress serviceAddress, IdentityKey identityKey, TrustLevel trustLevel
) {
for (Identity id : identities) { for (Identity id : identities) {
if (!id.address.matches(serviceAddress) || !id.identityKey.equals(identityKey)) { if (!id.address.matches(serviceAddress) || !id.identityKey.equals(identityKey)) {
continue; continue;
@ -178,7 +185,9 @@ public class JsonIdentityKeyStore implements IdentityKeyStore {
public static class JsonIdentityKeyStoreDeserializer extends JsonDeserializer<JsonIdentityKeyStore> { public static class JsonIdentityKeyStoreDeserializer extends JsonDeserializer<JsonIdentityKeyStore> {
@Override @Override
public JsonIdentityKeyStore deserialize(JsonParser jsonParser, DeserializationContext deserializationContext) throws IOException { public JsonIdentityKeyStore deserialize(
JsonParser jsonParser, DeserializationContext deserializationContext
) throws IOException {
JsonNode node = jsonParser.getCodec().readTree(jsonParser); JsonNode node = jsonParser.getCodec().readTree(jsonParser);
try { try {
@ -190,25 +199,24 @@ public class JsonIdentityKeyStore implements IdentityKeyStore {
JsonNode trustedKeysNode = node.get("trustedKeys"); JsonNode trustedKeysNode = node.get("trustedKeys");
if (trustedKeysNode.isArray()) { if (trustedKeysNode.isArray()) {
for (JsonNode trustedKey : trustedKeysNode) { for (JsonNode trustedKey : trustedKeysNode) {
String trustedKeyName = trustedKey.hasNonNull("name") String trustedKeyName = trustedKey.hasNonNull("name") ? trustedKey.get("name").asText() : null;
? trustedKey.get("name").asText()
: null;
if (UuidUtil.isUuid(trustedKeyName)) { if (UuidUtil.isUuid(trustedKeyName)) {
// Ignore identities that were incorrectly created with UUIDs as name // Ignore identities that were incorrectly created with UUIDs as name
continue; continue;
} }
UUID uuid = trustedKey.hasNonNull("uuid") UUID uuid = trustedKey.hasNonNull("uuid") ? UuidUtil.parseOrNull(trustedKey.get("uuid")
? UuidUtil.parseOrNull(trustedKey.get("uuid").asText()) .asText()) : null;
: null;
final SignalServiceAddress serviceAddress = uuid == null final SignalServiceAddress serviceAddress = uuid == null
? Util.getSignalServiceAddressFromIdentifier(trustedKeyName) ? Util.getSignalServiceAddressFromIdentifier(trustedKeyName)
: new SignalServiceAddress(uuid, trustedKeyName); : new SignalServiceAddress(uuid, trustedKeyName);
try { try {
IdentityKey id = new IdentityKey(Base64.decode(trustedKey.get("identityKey").asText()), 0); IdentityKey id = new IdentityKey(Base64.decode(trustedKey.get("identityKey").asText()), 0);
TrustLevel trustLevel = trustedKey.has("trustLevel") ? TrustLevel.fromInt(trustedKey.get("trustLevel").asInt()) : TrustLevel.TRUSTED_UNVERIFIED; TrustLevel trustLevel = trustedKey.has("trustLevel") ? TrustLevel.fromInt(trustedKey.get(
Date added = trustedKey.has("addedTimestamp") ? new Date(trustedKey.get("addedTimestamp").asLong()) : new Date(); "trustLevel").asInt()) : TrustLevel.TRUSTED_UNVERIFIED;
Date added = trustedKey.has("addedTimestamp") ? new Date(trustedKey.get("addedTimestamp")
.asLong()) : new Date();
keyStore.saveIdentity(serviceAddress, id, trustLevel, added); keyStore.saveIdentity(serviceAddress, id, trustLevel, added);
} catch (InvalidKeyException | IOException e) { } catch (InvalidKeyException | IOException e) {
System.out.println(String.format("Error while decoding key for: %s", trustedKeyName)); System.out.println(String.format("Error while decoding key for: %s", trustedKeyName));
@ -226,10 +234,13 @@ public class JsonIdentityKeyStore implements IdentityKeyStore {
public static class JsonIdentityKeyStoreSerializer extends JsonSerializer<JsonIdentityKeyStore> { public static class JsonIdentityKeyStoreSerializer extends JsonSerializer<JsonIdentityKeyStore> {
@Override @Override
public void serialize(JsonIdentityKeyStore jsonIdentityKeyStore, JsonGenerator json, SerializerProvider serializerProvider) throws IOException { public void serialize(
JsonIdentityKeyStore jsonIdentityKeyStore, JsonGenerator json, SerializerProvider serializerProvider
) throws IOException {
json.writeStartObject(); json.writeStartObject();
json.writeNumberField("registrationId", jsonIdentityKeyStore.getLocalRegistrationId()); json.writeNumberField("registrationId", jsonIdentityKeyStore.getLocalRegistrationId());
json.writeStringField("identityKey", Base64.encodeBytes(jsonIdentityKeyStore.getIdentityKeyPair().serialize())); json.writeStringField("identityKey",
Base64.encodeBytes(jsonIdentityKeyStore.getIdentityKeyPair().serialize()));
json.writeArrayFieldStart("trustedKeys"); json.writeArrayFieldStart("trustedKeys");
for (Identity trustedKey : jsonIdentityKeyStore.identities) { for (Identity trustedKey : jsonIdentityKeyStore.identities) {
json.writeStartObject(); json.writeStartObject();
@ -279,8 +290,7 @@ public class JsonIdentityKeyStore implements IdentityKeyStore {
} }
boolean isTrusted() { boolean isTrusted() {
return trustLevel == TrustLevel.TRUSTED_UNVERIFIED || return trustLevel == TrustLevel.TRUSTED_UNVERIFIED || trustLevel == TrustLevel.TRUSTED_VERIFIED;
trustLevel == TrustLevel.TRUSTED_VERIFIED;
} }
public IdentityKey getIdentityKey() { public IdentityKey getIdentityKey() {

View file

@ -60,7 +60,9 @@ class JsonPreKeyStore implements PreKeyStore {
public static class JsonPreKeyStoreDeserializer extends JsonDeserializer<JsonPreKeyStore> { public static class JsonPreKeyStoreDeserializer extends JsonDeserializer<JsonPreKeyStore> {
@Override @Override
public JsonPreKeyStore deserialize(JsonParser jsonParser, DeserializationContext deserializationContext) throws IOException { public JsonPreKeyStore deserialize(
JsonParser jsonParser, DeserializationContext deserializationContext
) throws IOException {
JsonNode node = jsonParser.getCodec().readTree(jsonParser); JsonNode node = jsonParser.getCodec().readTree(jsonParser);
Map<Integer, byte[]> preKeyMap = new HashMap<>(); Map<Integer, byte[]> preKeyMap = new HashMap<>();
@ -86,7 +88,9 @@ class JsonPreKeyStore implements PreKeyStore {
public static class JsonPreKeyStoreSerializer extends JsonSerializer<JsonPreKeyStore> { public static class JsonPreKeyStoreSerializer extends JsonSerializer<JsonPreKeyStore> {
@Override @Override
public void serialize(JsonPreKeyStore jsonPreKeyStore, JsonGenerator json, SerializerProvider serializerProvider) throws IOException { public void serialize(
JsonPreKeyStore jsonPreKeyStore, JsonGenerator json, SerializerProvider serializerProvider
) throws IOException {
json.writeStartArray(); json.writeStartArray();
for (Map.Entry<Integer, byte[]> preKey : jsonPreKeyStore.store.entrySet()) { for (Map.Entry<Integer, byte[]> preKey : jsonPreKeyStore.store.entrySet()) {
json.writeStartObject(); json.writeStartObject();

View file

@ -126,24 +126,22 @@ class JsonSessionStore implements SessionStore {
public static class JsonSessionStoreDeserializer extends JsonDeserializer<JsonSessionStore> { public static class JsonSessionStoreDeserializer extends JsonDeserializer<JsonSessionStore> {
@Override @Override
public JsonSessionStore deserialize(JsonParser jsonParser, DeserializationContext deserializationContext) throws IOException { public JsonSessionStore deserialize(
JsonParser jsonParser, DeserializationContext deserializationContext
) throws IOException {
JsonNode node = jsonParser.getCodec().readTree(jsonParser); JsonNode node = jsonParser.getCodec().readTree(jsonParser);
JsonSessionStore sessionStore = new JsonSessionStore(); JsonSessionStore sessionStore = new JsonSessionStore();
if (node.isArray()) { if (node.isArray()) {
for (JsonNode session : node) { for (JsonNode session : node) {
String sessionName = session.hasNonNull("name") String sessionName = session.hasNonNull("name") ? session.get("name").asText() : null;
? session.get("name").asText()
: null;
if (UuidUtil.isUuid(sessionName)) { if (UuidUtil.isUuid(sessionName)) {
// Ignore sessions that were incorrectly created with UUIDs as name // Ignore sessions that were incorrectly created with UUIDs as name
continue; continue;
} }
UUID uuid = session.hasNonNull("uuid") UUID uuid = session.hasNonNull("uuid") ? UuidUtil.parseOrNull(session.get("uuid").asText()) : null;
? UuidUtil.parseOrNull(session.get("uuid").asText())
: null;
final SignalServiceAddress serviceAddress = uuid == null final SignalServiceAddress serviceAddress = uuid == null
? Util.getSignalServiceAddressFromIdentifier(sessionName) ? Util.getSignalServiceAddressFromIdentifier(sessionName)
: new SignalServiceAddress(uuid, sessionName); : new SignalServiceAddress(uuid, sessionName);
@ -165,7 +163,9 @@ class JsonSessionStore implements SessionStore {
public static class JsonSessionStoreSerializer extends JsonSerializer<JsonSessionStore> { public static class JsonSessionStoreSerializer extends JsonSerializer<JsonSessionStore> {
@Override @Override
public void serialize(JsonSessionStore jsonSessionStore, JsonGenerator json, SerializerProvider serializerProvider) throws IOException { public void serialize(
JsonSessionStore jsonSessionStore, JsonGenerator json, SerializerProvider serializerProvider
) throws IOException {
json.writeStartArray(); json.writeStartArray();
for (SessionInfo sessionInfo : jsonSessionStore.sessions) { for (SessionInfo sessionInfo : jsonSessionStore.sessions) {
json.writeStartObject(); json.writeStartObject();

View file

@ -42,7 +42,12 @@ public class JsonSignalProtocolStore implements SignalProtocolStore {
public JsonSignalProtocolStore() { public JsonSignalProtocolStore() {
} }
public JsonSignalProtocolStore(JsonPreKeyStore preKeyStore, JsonSessionStore sessionStore, JsonSignedPreKeyStore signedPreKeyStore, JsonIdentityKeyStore identityKeyStore) { public JsonSignalProtocolStore(
JsonPreKeyStore preKeyStore,
JsonSessionStore sessionStore,
JsonSignedPreKeyStore signedPreKeyStore,
JsonIdentityKeyStore identityKeyStore
) {
this.preKeyStore = preKeyStore; this.preKeyStore = preKeyStore;
this.sessionStore = sessionStore; this.sessionStore = sessionStore;
this.signedPreKeyStore = signedPreKeyStore; this.signedPreKeyStore = signedPreKeyStore;
@ -80,7 +85,9 @@ public class JsonSignalProtocolStore implements SignalProtocolStore {
identityKeyStore.saveIdentity(serviceAddress, identityKey, trustLevel, null); identityKeyStore.saveIdentity(serviceAddress, identityKey, trustLevel, null);
} }
public void setIdentityTrustLevel(SignalServiceAddress serviceAddress, IdentityKey identityKey, TrustLevel trustLevel) { public void setIdentityTrustLevel(
SignalServiceAddress serviceAddress, IdentityKey identityKey, TrustLevel trustLevel
) {
identityKeyStore.setIdentityTrustLevel(serviceAddress, identityKey, trustLevel); identityKeyStore.setIdentityTrustLevel(serviceAddress, identityKey, trustLevel);
} }

View file

@ -77,7 +77,9 @@ class JsonSignedPreKeyStore implements SignedPreKeyStore {
public static class JsonSignedPreKeyStoreDeserializer extends JsonDeserializer<JsonSignedPreKeyStore> { public static class JsonSignedPreKeyStoreDeserializer extends JsonDeserializer<JsonSignedPreKeyStore> {
@Override @Override
public JsonSignedPreKeyStore deserialize(JsonParser jsonParser, DeserializationContext deserializationContext) throws IOException { public JsonSignedPreKeyStore deserialize(
JsonParser jsonParser, DeserializationContext deserializationContext
) throws IOException {
JsonNode node = jsonParser.getCodec().readTree(jsonParser); JsonNode node = jsonParser.getCodec().readTree(jsonParser);
Map<Integer, byte[]> preKeyMap = new HashMap<>(); Map<Integer, byte[]> preKeyMap = new HashMap<>();
@ -103,7 +105,9 @@ class JsonSignedPreKeyStore implements SignedPreKeyStore {
public static class JsonSignedPreKeyStoreSerializer extends JsonSerializer<JsonSignedPreKeyStore> { public static class JsonSignedPreKeyStoreSerializer extends JsonSerializer<JsonSignedPreKeyStore> {
@Override @Override
public void serialize(JsonSignedPreKeyStore jsonPreKeyStore, JsonGenerator json, SerializerProvider serializerProvider) throws IOException { public void serialize(
JsonSignedPreKeyStore jsonPreKeyStore, JsonGenerator json, SerializerProvider serializerProvider
) throws IOException {
json.writeStartArray(); json.writeStartArray();
for (Map.Entry<Integer, byte[]> signedPreKey : jsonPreKeyStore.store.entrySet()) { for (Map.Entry<Integer, byte[]> signedPreKey : jsonPreKeyStore.store.entrySet()) {
json.writeStartObject(); json.writeStartObject();

View file

@ -49,7 +49,9 @@ public class RecipientStore {
public static class RecipientStoreDeserializer extends JsonDeserializer<Set<SignalServiceAddress>> { public static class RecipientStoreDeserializer extends JsonDeserializer<Set<SignalServiceAddress>> {
@Override @Override
public Set<SignalServiceAddress> deserialize(JsonParser jsonParser, DeserializationContext deserializationContext) throws IOException { public Set<SignalServiceAddress> deserialize(
JsonParser jsonParser, DeserializationContext deserializationContext
) throws IOException {
JsonNode node = jsonParser.getCodec().readTree(jsonParser); JsonNode node = jsonParser.getCodec().readTree(jsonParser);
Set<SignalServiceAddress> addresses = new HashSet<>(); Set<SignalServiceAddress> addresses = new HashSet<>();
@ -70,7 +72,9 @@ public class RecipientStore {
public static class RecipientStoreSerializer extends JsonSerializer<Set<SignalServiceAddress>> { public static class RecipientStoreSerializer extends JsonSerializer<Set<SignalServiceAddress>> {
@Override @Override
public void serialize(Set<SignalServiceAddress> addresses, JsonGenerator json, SerializerProvider serializerProvider) throws IOException { public void serialize(
Set<SignalServiceAddress> addresses, JsonGenerator json, SerializerProvider serializerProvider
) throws IOException {
json.writeStartArray(); json.writeStartArray();
for (SignalServiceAddress address : addresses) { for (SignalServiceAddress address : addresses) {
json.writeStartObject(); json.writeStartObject();

View file

@ -37,7 +37,9 @@ public class StickerStore {
private static class StickersSerializer extends JsonSerializer<Map<byte[], Sticker>> { private static class StickersSerializer extends JsonSerializer<Map<byte[], Sticker>> {
@Override @Override
public void serialize(final Map<byte[], Sticker> value, final JsonGenerator jgen, final SerializerProvider provider) throws IOException { public void serialize(
final Map<byte[], Sticker> value, final JsonGenerator jgen, final SerializerProvider provider
) throws IOException {
final Collection<Sticker> stickers = value.values(); final Collection<Sticker> stickers = value.values();
jgen.writeStartArray(stickers.size()); jgen.writeStartArray(stickers.size());
for (Sticker sticker : stickers) { for (Sticker sticker : stickers) {
@ -54,7 +56,9 @@ public class StickerStore {
private static class StickersDeserializer extends JsonDeserializer<Map<byte[], Sticker>> { private static class StickersDeserializer extends JsonDeserializer<Map<byte[], Sticker>> {
@Override @Override
public Map<byte[], Sticker> deserialize(JsonParser jsonParser, DeserializationContext deserializationContext) throws IOException { public Map<byte[], Sticker> deserialize(
JsonParser jsonParser, DeserializationContext deserializationContext
) throws IOException {
Map<byte[], Sticker> stickers = new HashMap<>(); Map<byte[], Sticker> stickers = new HashMap<>();
JsonNode node = jsonParser.getCodec().readTree(jsonParser); JsonNode node = jsonParser.getCodec().readTree(jsonParser);
for (JsonNode n : node) { for (JsonNode n : node) {

View file

@ -34,7 +34,9 @@ public class LegacyJsonThreadStore {
private static class MapToListSerializer extends JsonSerializer<Map<?, ?>> { private static class MapToListSerializer extends JsonSerializer<Map<?, ?>> {
@Override @Override
public void serialize(final Map<?, ?> value, final JsonGenerator jgen, final SerializerProvider provider) throws IOException { public void serialize(
final Map<?, ?> value, final JsonGenerator jgen, final SerializerProvider provider
) throws IOException {
jgen.writeObject(value.values()); jgen.writeObject(value.values());
} }
} }
@ -42,7 +44,9 @@ public class LegacyJsonThreadStore {
private static class ThreadsDeserializer extends JsonDeserializer<Map<String, ThreadInfo>> { private static class ThreadsDeserializer extends JsonDeserializer<Map<String, ThreadInfo>> {
@Override @Override
public Map<String, ThreadInfo> deserialize(JsonParser jsonParser, DeserializationContext deserializationContext) throws IOException { public Map<String, ThreadInfo> deserialize(
JsonParser jsonParser, DeserializationContext deserializationContext
) throws IOException {
Map<String, ThreadInfo> threads = new HashMap<>(); Map<String, ThreadInfo> threads = new HashMap<>();
JsonNode node = jsonParser.getCodec().readTree(jsonParser); JsonNode node = jsonParser.getCodec().readTree(jsonParser);
for (JsonNode n : node) { for (JsonNode n : node) {

View file

@ -17,7 +17,8 @@ public class ErrorUtils {
public static void handleAssertionError(AssertionError e) { public static void handleAssertionError(AssertionError e) {
System.err.println("Failed to send/receive message (Assertion): " + e.getMessage()); System.err.println("Failed to send/receive message (Assertion): " + e.getMessage());
e.printStackTrace(); e.printStackTrace();
System.err.println("If you use an Oracle JRE please check if you have unlimited strength crypto enabled, see README"); System.err.println(
"If you use an Oracle JRE please check if you have unlimited strength crypto enabled, see README");
} }
public static int handleTimestampAndSendMessageResults(long timestamp, List<SendMessageResult> results) { public static int handleTimestampAndSendMessageResults(long timestamp, List<SendMessageResult> results) {

View file

@ -2,9 +2,7 @@ package org.asamk.signal.util;
public class Hex { public class Hex {
private final static char[] HEX_DIGITS = { private final static char[] HEX_DIGITS = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'
};
private Hex() { private Hex() {
} }

View file

@ -16,10 +16,13 @@ public class SecurityProvider extends Provider {
// Workaround for BKS truststore // Workaround for BKS truststore
put("KeyStore.BKS", org.bouncycastle.jcajce.provider.keystore.bc.BcKeyStoreSpi.Std.class.getCanonicalName()); put("KeyStore.BKS", org.bouncycastle.jcajce.provider.keystore.bc.BcKeyStoreSpi.Std.class.getCanonicalName());
put("KeyStore.BKS-V1", org.bouncycastle.jcajce.provider.keystore.bc.BcKeyStoreSpi.Version1.class.getCanonicalName()); put("KeyStore.BKS-V1",
put("KeyStore.BouncyCastle", org.bouncycastle.jcajce.provider.keystore.bc.BcKeyStoreSpi.BouncyCastleStore.class.getCanonicalName()); org.bouncycastle.jcajce.provider.keystore.bc.BcKeyStoreSpi.Version1.class.getCanonicalName());
put("KeyStore.BouncyCastle",
org.bouncycastle.jcajce.provider.keystore.bc.BcKeyStoreSpi.BouncyCastleStore.class.getCanonicalName());
put("KeyFactory.X.509", org.bouncycastle.jcajce.provider.asymmetric.x509.KeyFactory.class.getCanonicalName()); put("KeyFactory.X.509", org.bouncycastle.jcajce.provider.asymmetric.x509.KeyFactory.class.getCanonicalName());
put("CertificateFactory.X.509", org.bouncycastle.jcajce.provider.asymmetric.x509.CertificateFactory.class.getCanonicalName()); put("CertificateFactory.X.509",
org.bouncycastle.jcajce.provider.asymmetric.x509.CertificateFactory.class.getCanonicalName());
} }
public static class DefaultRandom extends SecureRandomSpi { public static class DefaultRandom extends SecureRandomSpi {

View file

@ -41,7 +41,8 @@ public class Util {
public static JsonNode getNotNullNode(JsonNode parent, String name) throws InvalidObjectException { public static JsonNode getNotNullNode(JsonNode parent, String name) throws InvalidObjectException {
JsonNode node = parent.get(name); JsonNode node = parent.get(name);
if (node == null) { if (node == null) {
throw new InvalidObjectException(String.format("Incorrect file format: expected parameter %s not found ", name)); throw new InvalidObjectException(String.format("Incorrect file format: expected parameter %s not found ",
name));
} }
return node; return node;