mirror of
https://github.com/AsamK/signal-cli
synced 2025-08-29 02:20:39 +00:00
Extract util methods to separate classes
This commit is contained in:
parent
4ab904b88e
commit
7443225d96
6 changed files with 168 additions and 131 deletions
|
@ -31,7 +31,10 @@ import org.asamk.Signal;
|
|||
import org.asamk.signal.storage.contacts.ContactInfo;
|
||||
import org.asamk.signal.storage.groups.GroupInfo;
|
||||
import org.asamk.signal.storage.protocol.JsonIdentityKeyStore;
|
||||
import org.asamk.signal.util.DateUtils;
|
||||
import org.asamk.signal.util.Hex;
|
||||
import org.asamk.signal.util.IOUtils;
|
||||
import org.asamk.signal.util.Util;
|
||||
import org.freedesktop.dbus.DBusConnection;
|
||||
import org.freedesktop.dbus.DBusSigHandler;
|
||||
import org.freedesktop.dbus.exceptions.DBusException;
|
||||
|
@ -52,15 +55,14 @@ import org.whispersystems.signalservice.internal.util.Base64;
|
|||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.StringWriter;
|
||||
import java.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
import java.nio.charset.Charset;
|
||||
import java.security.Security;
|
||||
import java.text.DateFormat;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.*;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.TimeoutException;
|
||||
|
||||
|
@ -69,8 +71,6 @@ public class Main {
|
|||
public static final String SIGNAL_BUSNAME = "org.asamk.Signal";
|
||||
public static final String SIGNAL_OBJECTPATH = "/org/asamk/Signal";
|
||||
|
||||
private static final TimeZone tzUTC = TimeZone.getTimeZone("UTC");
|
||||
|
||||
public static void main(String[] args) {
|
||||
// Workaround for BKS truststore
|
||||
Security.insertProviderAt(new org.bouncycastle.jce.provider.BouncyCastleProvider(), 1);
|
||||
|
@ -317,8 +317,8 @@ public class Main {
|
|||
for (DeviceInfo d : devices) {
|
||||
System.out.println("Device " + d.getId() + (d.getId() == m.getDeviceId() ? " (this device)" : "") + ":");
|
||||
System.out.println(" Name: " + d.getName());
|
||||
System.out.println(" Created: " + formatTimestamp(d.getCreated()));
|
||||
System.out.println(" Last seen: " + formatTimestamp(d.getLastSeen()));
|
||||
System.out.println(" Created: " + DateUtils.formatTimestamp(d.getCreated()));
|
||||
System.out.println(" Last seen: " + DateUtils.formatTimestamp(d.getLastSeen()));
|
||||
}
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
|
@ -373,7 +373,7 @@ public class Main {
|
|||
String messageText = ns.getString("message");
|
||||
if (messageText == null) {
|
||||
try {
|
||||
messageText = readAll(System.in);
|
||||
messageText = IOUtils.readAll(System.in, Charset.defaultCharset());
|
||||
} catch (IOException e) {
|
||||
System.err.println("Failed to read message from stdin: " + e.getMessage());
|
||||
System.err.println("Aborting sending.");
|
||||
|
@ -425,7 +425,7 @@ public class Main {
|
|||
@Override
|
||||
public void handle(Signal.MessageReceived s) {
|
||||
System.out.print(String.format("Envelope from: %s\nTimestamp: %s\nBody: %s\n",
|
||||
s.getSender(), formatTimestamp(s.getTimestamp()), s.getMessage()));
|
||||
s.getSender(), DateUtils.formatTimestamp(s.getTimestamp()), s.getMessage()));
|
||||
if (s.getGroupId().length > 0) {
|
||||
System.out.println("Group info:");
|
||||
System.out.println(" Id: " + Base64.encodeBytes(s.getGroupId()));
|
||||
|
@ -443,7 +443,7 @@ public class Main {
|
|||
@Override
|
||||
public void handle(Signal.ReceiptReceived s) {
|
||||
System.out.print(String.format("Receipt from: %s\nTimestamp: %s\n",
|
||||
s.getSender(), formatTimestamp(s.getTimestamp())));
|
||||
s.getSender(), DateUtils.formatTimestamp(s.getTimestamp())));
|
||||
}
|
||||
});
|
||||
} catch (UnsatisfiedLinkError e) {
|
||||
|
@ -708,7 +708,7 @@ public class Main {
|
|||
}
|
||||
|
||||
private static void printIdentityFingerprint(Manager m, String theirUsername, JsonIdentityKeyStore.Identity theirId) {
|
||||
String digits = formatSafetyNumber(m.computeSafetyNumber(theirUsername, theirId.getIdentityKey()));
|
||||
String digits = Util.formatSafetyNumber(m.computeSafetyNumber(theirUsername, theirId.getIdentityKey()));
|
||||
System.out.println(String.format("%s: %s Added: %s Fingerprint: %s Safety Number: %s", theirUsername,
|
||||
theirId.getTrustLevel(), theirId.getDateAdded(), Hex.toStringCondensed(theirId.getFingerprint()), digits));
|
||||
}
|
||||
|
@ -723,16 +723,6 @@ public class Main {
|
|||
}
|
||||
}
|
||||
|
||||
private static String formatSafetyNumber(String digits) {
|
||||
final int partCount = 12;
|
||||
int partSize = digits.length() / partCount;
|
||||
StringBuilder f = new StringBuilder(digits.length() + partCount);
|
||||
for (int i = 0; i < partCount; i++) {
|
||||
f.append(digits.substring(i * partSize, (i * partSize) + partSize)).append(" ");
|
||||
}
|
||||
return f.toString();
|
||||
}
|
||||
|
||||
private static void handleGroupNotFoundException(GroupNotFoundException e) {
|
||||
System.err.println("Failed to send to group: " + e.getMessage());
|
||||
System.err.println("Aborting sending.");
|
||||
|
@ -956,18 +946,6 @@ public class Main {
|
|||
System.err.println("Failed to send message: " + e.getMessage());
|
||||
}
|
||||
|
||||
private static String readAll(InputStream in) throws IOException {
|
||||
StringWriter output = new StringWriter();
|
||||
byte[] buffer = new byte[4096];
|
||||
long count = 0;
|
||||
int n;
|
||||
while (-1 != (n = System.in.read(buffer))) {
|
||||
output.write(new String(buffer, 0, n, Charset.defaultCharset()));
|
||||
count += n;
|
||||
}
|
||||
return output.toString();
|
||||
}
|
||||
|
||||
private static class ReceiveMessageHandler implements Manager.ReceiveMessageHandler {
|
||||
final Manager m;
|
||||
|
||||
|
@ -983,7 +961,7 @@ public class Main {
|
|||
if (source.getRelay().isPresent()) {
|
||||
System.out.println("Relayed by: " + source.getRelay().get());
|
||||
}
|
||||
System.out.println("Timestamp: " + formatTimestamp(envelope.getTimestamp()));
|
||||
System.out.println("Timestamp: " + DateUtils.formatTimestamp(envelope.getTimestamp()));
|
||||
if (envelope.isUnidentifiedSender()) {
|
||||
System.out.println("Sent by unidentified/sealed sender");
|
||||
}
|
||||
|
@ -1029,7 +1007,7 @@ public class Main {
|
|||
System.out.println("Received sync read messages list");
|
||||
for (ReadMessage rm : syncMessage.getRead().get()) {
|
||||
ContactInfo fromContact = m.getContact(rm.getSender());
|
||||
System.out.println("From: " + (fromContact == null ? "" : "“" + fromContact.name + "” ") + rm.getSender() + " Message timestamp: " + formatTimestamp(rm.getTimestamp()));
|
||||
System.out.println("From: " + (fromContact == null ? "" : "“" + fromContact.name + "” ") + rm.getSender() + " Message timestamp: " + DateUtils.formatTimestamp(rm.getTimestamp()));
|
||||
}
|
||||
}
|
||||
if (syncMessage.getRequest().isPresent()) {
|
||||
|
@ -1052,9 +1030,9 @@ public class Main {
|
|||
} else {
|
||||
to = "Unknown";
|
||||
}
|
||||
System.out.println("To: " + to + " , Message timestamp: " + formatTimestamp(sentTranscriptMessage.getTimestamp()));
|
||||
System.out.println("To: " + to + " , Message timestamp: " + DateUtils.formatTimestamp(sentTranscriptMessage.getTimestamp()));
|
||||
if (sentTranscriptMessage.getExpirationStartTimestamp() > 0) {
|
||||
System.out.println("Expiration started at: " + formatTimestamp(sentTranscriptMessage.getExpirationStartTimestamp()));
|
||||
System.out.println("Expiration started at: " + DateUtils.formatTimestamp(sentTranscriptMessage.getExpirationStartTimestamp()));
|
||||
}
|
||||
SignalServiceDataMessage message = sentTranscriptMessage.getMessage();
|
||||
handleSignalServiceDataMessage(message);
|
||||
|
@ -1071,7 +1049,7 @@ public class Main {
|
|||
System.out.println("Received sync message with verified identities:");
|
||||
final VerifiedMessage verifiedMessage = syncMessage.getVerified().get();
|
||||
System.out.println(" - " + verifiedMessage.getDestination() + ": " + verifiedMessage.getVerified());
|
||||
String safetyNumber = formatSafetyNumber(m.computeSafetyNumber(verifiedMessage.getDestination(), verifiedMessage.getIdentityKey()));
|
||||
String safetyNumber = Util.formatSafetyNumber(m.computeSafetyNumber(verifiedMessage.getDestination(), verifiedMessage.getIdentityKey()));
|
||||
System.out.println(" " + safetyNumber);
|
||||
}
|
||||
if (syncMessage.getConfiguration().isPresent()) {
|
||||
|
@ -1111,7 +1089,7 @@ public class Main {
|
|||
if (content.getReceiptMessage().isPresent()) {
|
||||
System.out.println("Received a receipt message");
|
||||
SignalServiceReceiptMessage receiptMessage = content.getReceiptMessage().get();
|
||||
System.out.println(" - When: " + formatTimestamp(receiptMessage.getWhen()));
|
||||
System.out.println(" - When: " + DateUtils.formatTimestamp(receiptMessage.getWhen()));
|
||||
if (receiptMessage.isDeliveryReceipt()) {
|
||||
System.out.println(" - Is delivery receipt");
|
||||
}
|
||||
|
@ -1120,14 +1098,14 @@ public class Main {
|
|||
}
|
||||
System.out.println(" - Timestamps:");
|
||||
for (long timestamp : receiptMessage.getTimestamps()) {
|
||||
System.out.println(" " + formatTimestamp(timestamp));
|
||||
System.out.println(" " + DateUtils.formatTimestamp(timestamp));
|
||||
}
|
||||
}
|
||||
if (content.getTypingMessage().isPresent()) {
|
||||
System.out.println("Received a typing message");
|
||||
SignalServiceTypingMessage typingMessage = content.getTypingMessage().get();
|
||||
System.out.println(" - Action: " + typingMessage.getAction());
|
||||
System.out.println(" - Timestamp: " + formatTimestamp(typingMessage.getTimestamp()));
|
||||
System.out.println(" - Timestamp: " + DateUtils.formatTimestamp(typingMessage.getTimestamp()));
|
||||
if (typingMessage.getGroupId().isPresent()) {
|
||||
GroupInfo group = m.getGroup(typingMessage.getGroupId().get());
|
||||
if (group != null) {
|
||||
|
@ -1145,7 +1123,7 @@ public class Main {
|
|||
}
|
||||
|
||||
private void handleSignalServiceDataMessage(SignalServiceDataMessage message) {
|
||||
System.out.println("Message timestamp: " + formatTimestamp(message.getTimestamp()));
|
||||
System.out.println("Message timestamp: " + DateUtils.formatTimestamp(message.getTimestamp()));
|
||||
|
||||
if (message.getBody().isPresent()) {
|
||||
System.out.println("Body: " + message.getBody().get());
|
||||
|
@ -1334,11 +1312,4 @@ public class Main {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static String formatTimestamp(long timestamp) {
|
||||
Date date = new Date(timestamp);
|
||||
final DateFormat df = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'"); // Quoted "Z" to indicate UTC, no timezone offset
|
||||
df.setTimeZone(tzUTC);
|
||||
return timestamp + " (" + df.format(date) + ")";
|
||||
}
|
||||
}
|
||||
|
|
|
@ -35,6 +35,7 @@ import org.asamk.signal.storage.protocol.JsonIdentityKeyStore;
|
|||
import org.asamk.signal.storage.protocol.JsonSignalProtocolStore;
|
||||
import org.asamk.signal.storage.threads.JsonThreadStore;
|
||||
import org.asamk.signal.storage.threads.ThreadInfo;
|
||||
import org.asamk.signal.util.IOUtils;
|
||||
import org.asamk.signal.util.KeyUtils;
|
||||
import org.asamk.signal.util.Util;
|
||||
import org.signal.libsignal.metadata.*;
|
||||
|
@ -81,23 +82,17 @@ import org.whispersystems.signalservice.internal.util.Base64;
|
|||
import java.io.*;
|
||||
import java.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
import java.net.URLDecoder;
|
||||
import java.net.URLEncoder;
|
||||
import java.nio.channels.Channels;
|
||||
import java.nio.channels.FileChannel;
|
||||
import java.nio.channels.FileLock;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.nio.file.StandardCopyOption;
|
||||
import java.nio.file.attribute.PosixFilePermission;
|
||||
import java.nio.file.attribute.PosixFilePermissions;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.TimeoutException;
|
||||
|
||||
import static java.nio.file.attribute.PosixFilePermission.*;
|
||||
|
||||
class Manager implements Signal {
|
||||
private final static String URL = "https://textsecure-service.whispersystems.org";
|
||||
private final static String CDN_URL = "https://cdn.signal.org";
|
||||
|
@ -189,30 +184,10 @@ class Manager implements Signal {
|
|||
|
||||
private File getMessageCacheFile(String sender, long now, long timestamp) throws IOException {
|
||||
String cachePath = getMessageCachePath(sender);
|
||||
createPrivateDirectories(cachePath);
|
||||
IOUtils.createPrivateDirectories(cachePath);
|
||||
return new File(cachePath + "/" + now + "_" + timestamp);
|
||||
}
|
||||
|
||||
private static void createPrivateDirectories(String path) throws IOException {
|
||||
final Path file = new File(path).toPath();
|
||||
try {
|
||||
Set<PosixFilePermission> perms = EnumSet.of(OWNER_READ, OWNER_WRITE, OWNER_EXECUTE);
|
||||
Files.createDirectories(file, PosixFilePermissions.asFileAttribute(perms));
|
||||
} catch (UnsupportedOperationException e) {
|
||||
Files.createDirectories(file);
|
||||
}
|
||||
}
|
||||
|
||||
private static void createPrivateFile(String path) throws IOException {
|
||||
final Path file = new File(path).toPath();
|
||||
try {
|
||||
Set<PosixFilePermission> perms = EnumSet.of(OWNER_READ, OWNER_WRITE);
|
||||
Files.createFile(file, PosixFilePermissions.asFileAttribute(perms));
|
||||
} catch (UnsupportedOperationException e) {
|
||||
Files.createFile(file);
|
||||
}
|
||||
}
|
||||
|
||||
public boolean userExists() {
|
||||
if (username == null) {
|
||||
return false;
|
||||
|
@ -238,9 +213,9 @@ class Manager implements Signal {
|
|||
if (fileChannel != null)
|
||||
return;
|
||||
|
||||
createPrivateDirectories(dataPath);
|
||||
IOUtils.createPrivateDirectories(dataPath);
|
||||
if (!new File(getFileName()).exists()) {
|
||||
createPrivateFile(getFileName());
|
||||
IOUtils.createPrivateFile(getFileName());
|
||||
}
|
||||
fileChannel = new RandomAccessFile(new File(getFileName()), "rw").getChannel();
|
||||
lock = fileChannel.tryLock();
|
||||
|
@ -334,7 +309,7 @@ class Manager implements Signal {
|
|||
File attachmentFile = getAttachmentFile(g.getAvatarId());
|
||||
if (!avatarFile.exists() && attachmentFile.exists()) {
|
||||
try {
|
||||
createPrivateDirectories(avatarsPath);
|
||||
IOUtils.createPrivateDirectories(avatarsPath);
|
||||
Files.copy(attachmentFile.toPath(), avatarFile.toPath(), StandardCopyOption.REPLACE_EXISTING);
|
||||
} catch (Exception e) {
|
||||
// Ignore
|
||||
|
@ -459,30 +434,8 @@ class Manager implements Signal {
|
|||
accountManager.removeDevice(deviceId);
|
||||
}
|
||||
|
||||
public static Map<String, String> getQueryMap(String query) {
|
||||
String[] params = query.split("&");
|
||||
Map<String, String> map = new HashMap<>();
|
||||
for (String param : params) {
|
||||
String name = null;
|
||||
final String[] paramParts = param.split("=");
|
||||
try {
|
||||
name = URLDecoder.decode(paramParts[0], "utf-8");
|
||||
} catch (UnsupportedEncodingException e) {
|
||||
// Impossible
|
||||
}
|
||||
String value = null;
|
||||
try {
|
||||
value = URLDecoder.decode(paramParts[1], "utf-8");
|
||||
} catch (UnsupportedEncodingException e) {
|
||||
// Impossible
|
||||
}
|
||||
map.put(name, value);
|
||||
}
|
||||
return map;
|
||||
}
|
||||
|
||||
public void addDeviceLink(URI linkUri) throws IOException, InvalidKeyException {
|
||||
Map<String, String> query = getQueryMap(linkUri.getRawQuery());
|
||||
Map<String, String> query = Util.getQueryMap(linkUri.getRawQuery());
|
||||
String deviceIdentifier = query.get("uuid");
|
||||
String publicKeyEncoded = query.get("pub_key");
|
||||
|
||||
|
@ -672,18 +625,6 @@ class Manager implements Signal {
|
|||
sendMessageLegacy(messageBuilder, g.members);
|
||||
}
|
||||
|
||||
private static String join(CharSequence separator, Iterable<? extends CharSequence> list) {
|
||||
StringBuilder buf = new StringBuilder();
|
||||
for (CharSequence str : list) {
|
||||
if (buf.length() > 0) {
|
||||
buf.append(separator);
|
||||
}
|
||||
buf.append(str);
|
||||
}
|
||||
|
||||
return buf.toString();
|
||||
}
|
||||
|
||||
public byte[] sendUpdateGroupMessage(byte[] groupId, String name, Collection<String> members, String avatarFile) throws IOException, EncapsulatedExceptions, GroupNotFoundException, AttachmentInvalidException {
|
||||
GroupInfo g;
|
||||
if (groupId == null) {
|
||||
|
@ -720,14 +661,14 @@ class Manager implements Signal {
|
|||
for (ContactTokenDetails contact : contacts) {
|
||||
newMembers.remove(contact.getNumber());
|
||||
}
|
||||
System.err.println("Failed to add members " + join(", ", newMembers) + " to group: Not registered on Signal");
|
||||
System.err.println("Failed to add members " + Util.join(", ", newMembers) + " to group: Not registered on Signal");
|
||||
System.err.println("Aborting…");
|
||||
System.exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
if (avatarFile != null) {
|
||||
createPrivateDirectories(avatarsPath);
|
||||
IOUtils.createPrivateDirectories(avatarsPath);
|
||||
File aFile = getGroupAvatarFile(g.groupId);
|
||||
Files.copy(Paths.get(avatarFile), aFile.toPath(), StandardCopyOption.REPLACE_EXISTING);
|
||||
}
|
||||
|
@ -920,7 +861,7 @@ class Manager implements Signal {
|
|||
return UnidentifiedAccess.deriveAccessKeyFrom(profileKey);
|
||||
}
|
||||
|
||||
private static byte[] getTargetUnidentifiedAccessKey(SignalServiceAddress recipient) {
|
||||
private byte[] getTargetUnidentifiedAccessKey(SignalServiceAddress recipient) {
|
||||
// TODO implement
|
||||
return null;
|
||||
}
|
||||
|
@ -1330,7 +1271,7 @@ class Manager implements Signal {
|
|||
if (syncMessage.getGroups().isPresent()) {
|
||||
File tmpFile = null;
|
||||
try {
|
||||
tmpFile = Util.createTempFile();
|
||||
tmpFile = IOUtils.createTempFile();
|
||||
try (InputStream attachmentAsStream = retrieveAttachmentAsStream(syncMessage.getGroups().get().asPointer(), tmpFile)) {
|
||||
DeviceGroupsInputStream s = new DeviceGroupsInputStream(attachmentAsStream);
|
||||
DeviceGroup g;
|
||||
|
@ -1372,7 +1313,7 @@ class Manager implements Signal {
|
|||
if (syncMessage.getContacts().isPresent()) {
|
||||
File tmpFile = null;
|
||||
try {
|
||||
tmpFile = Util.createTempFile();
|
||||
tmpFile = IOUtils.createTempFile();
|
||||
final ContactsMessage contactsMessage = syncMessage.getContacts().get();
|
||||
try (InputStream attachmentAsStream = retrieveAttachmentAsStream(contactsMessage.getContactsStream().asPointer(), tmpFile)) {
|
||||
DeviceContactsInputStream s = new DeviceContactsInputStream(attachmentAsStream);
|
||||
|
@ -1506,7 +1447,7 @@ class Manager implements Signal {
|
|||
}
|
||||
|
||||
private File retrieveContactAvatarAttachment(SignalServiceAttachment attachment, String number) throws IOException, InvalidMessageException {
|
||||
createPrivateDirectories(avatarsPath);
|
||||
IOUtils.createPrivateDirectories(avatarsPath);
|
||||
if (attachment.isPointer()) {
|
||||
SignalServiceAttachmentPointer pointer = attachment.asPointer();
|
||||
return retrieveAttachment(pointer, getContactAvatarFile(number), false);
|
||||
|
@ -1521,7 +1462,7 @@ class Manager implements Signal {
|
|||
}
|
||||
|
||||
private File retrieveGroupAvatarAttachment(SignalServiceAttachment attachment, byte[] groupId) throws IOException, InvalidMessageException {
|
||||
createPrivateDirectories(avatarsPath);
|
||||
IOUtils.createPrivateDirectories(avatarsPath);
|
||||
if (attachment.isPointer()) {
|
||||
SignalServiceAttachmentPointer pointer = attachment.asPointer();
|
||||
return retrieveAttachment(pointer, getGroupAvatarFile(groupId), false);
|
||||
|
@ -1536,7 +1477,7 @@ class Manager implements Signal {
|
|||
}
|
||||
|
||||
private File retrieveAttachment(SignalServiceAttachmentPointer pointer) throws IOException, InvalidMessageException {
|
||||
createPrivateDirectories(attachmentsPath);
|
||||
IOUtils.createPrivateDirectories(attachmentsPath);
|
||||
return retrieveAttachment(pointer, getAttachmentFile(pointer.getId()), true);
|
||||
}
|
||||
|
||||
|
@ -1571,7 +1512,7 @@ class Manager implements Signal {
|
|||
|
||||
final SignalServiceMessageReceiver messageReceiver = new SignalServiceMessageReceiver(serviceConfiguration, username, password, deviceId, signalingKey, USER_AGENT, null, timer);
|
||||
|
||||
File tmpFile = Util.createTempFile();
|
||||
File tmpFile = IOUtils.createTempFile();
|
||||
try (InputStream input = messageReceiver.retrieveAttachment(pointer, tmpFile, MAX_ATTACHMENT_SIZE)) {
|
||||
try (OutputStream output = new FileOutputStream(outputFile)) {
|
||||
byte[] buffer = new byte[4096];
|
||||
|
@ -1615,7 +1556,7 @@ class Manager implements Signal {
|
|||
}
|
||||
|
||||
private void sendGroups() throws IOException, UntrustedIdentityException {
|
||||
File groupsFile = Util.createTempFile();
|
||||
File groupsFile = IOUtils.createTempFile();
|
||||
|
||||
try {
|
||||
try (OutputStream fos = new FileOutputStream(groupsFile)) {
|
||||
|
@ -1650,7 +1591,7 @@ class Manager implements Signal {
|
|||
}
|
||||
|
||||
private void sendContacts() throws IOException, UntrustedIdentityException {
|
||||
File contactsFile = Util.createTempFile();
|
||||
File contactsFile = IOUtils.createTempFile();
|
||||
|
||||
try {
|
||||
try (OutputStream fos = new FileOutputStream(contactsFile)) {
|
||||
|
|
21
src/main/java/org/asamk/signal/util/DateUtils.java
Normal file
21
src/main/java/org/asamk/signal/util/DateUtils.java
Normal file
|
@ -0,0 +1,21 @@
|
|||
package org.asamk.signal.util;
|
||||
|
||||
import java.text.DateFormat;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Date;
|
||||
import java.util.TimeZone;
|
||||
|
||||
public class DateUtils {
|
||||
|
||||
private static final TimeZone tzUTC = TimeZone.getTimeZone("UTC");
|
||||
|
||||
private DateUtils() {
|
||||
}
|
||||
|
||||
public static String formatTimestamp(long timestamp) {
|
||||
Date date = new Date(timestamp);
|
||||
final DateFormat df = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'"); // Quoted "Z" to indicate UTC, no timezone offset
|
||||
df.setTimeZone(tzUTC);
|
||||
return timestamp + " (" + df.format(date) + ")";
|
||||
}
|
||||
}
|
|
@ -6,6 +6,9 @@ public class Hex {
|
|||
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'
|
||||
};
|
||||
|
||||
private Hex() {
|
||||
}
|
||||
|
||||
public static String toStringCondensed(byte[] bytes) {
|
||||
StringBuffer buf = new StringBuffer();
|
||||
for (int i = 0; i < bytes.length; i++) {
|
||||
|
|
55
src/main/java/org/asamk/signal/util/IOUtils.java
Normal file
55
src/main/java/org/asamk/signal/util/IOUtils.java
Normal file
|
@ -0,0 +1,55 @@
|
|||
package org.asamk.signal.util;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.StringWriter;
|
||||
import java.nio.charset.Charset;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.attribute.PosixFilePermission;
|
||||
import java.nio.file.attribute.PosixFilePermissions;
|
||||
import java.util.EnumSet;
|
||||
import java.util.Set;
|
||||
|
||||
import static java.nio.file.attribute.PosixFilePermission.*;
|
||||
|
||||
public class IOUtils {
|
||||
|
||||
private IOUtils() {
|
||||
}
|
||||
|
||||
public static File createTempFile() throws IOException {
|
||||
return File.createTempFile("signal_tmp_", ".tmp");
|
||||
}
|
||||
|
||||
public static String readAll(InputStream in, Charset charset) throws IOException {
|
||||
StringWriter output = new StringWriter();
|
||||
byte[] buffer = new byte[4096];
|
||||
int n;
|
||||
while (-1 != (n = in.read(buffer))) {
|
||||
output.write(new String(buffer, 0, n, charset));
|
||||
}
|
||||
return output.toString();
|
||||
}
|
||||
|
||||
public static void createPrivateDirectories(String path) throws IOException {
|
||||
final Path file = new File(path).toPath();
|
||||
try {
|
||||
Set<PosixFilePermission> perms = EnumSet.of(OWNER_READ, OWNER_WRITE, OWNER_EXECUTE);
|
||||
Files.createDirectories(file, PosixFilePermissions.asFileAttribute(perms));
|
||||
} catch (UnsupportedOperationException e) {
|
||||
Files.createDirectories(file);
|
||||
}
|
||||
}
|
||||
|
||||
public static void createPrivateFile(String path) throws IOException {
|
||||
final Path file = new File(path).toPath();
|
||||
try {
|
||||
Set<PosixFilePermission> perms = EnumSet.of(OWNER_READ, OWNER_WRITE);
|
||||
Files.createFile(file, PosixFilePermissions.asFileAttribute(perms));
|
||||
} catch (UnsupportedOperationException e) {
|
||||
Files.createFile(file);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,10 +1,56 @@
|
|||
package org.asamk.signal.util;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.net.URLDecoder;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
public class Util {
|
||||
public static File createTempFile() throws IOException {
|
||||
return File.createTempFile("signal_tmp_", ".tmp");
|
||||
|
||||
private Util() {
|
||||
}
|
||||
|
||||
public static String formatSafetyNumber(String digits) {
|
||||
final int partCount = 12;
|
||||
int partSize = digits.length() / partCount;
|
||||
StringBuilder f = new StringBuilder(digits.length() + partCount);
|
||||
for (int i = 0; i < partCount; i++) {
|
||||
f.append(digits, i * partSize, (i * partSize) + partSize).append(" ");
|
||||
}
|
||||
return f.toString();
|
||||
}
|
||||
|
||||
public static Map<String, String> getQueryMap(String query) {
|
||||
String[] params = query.split("&");
|
||||
Map<String, String> map = new HashMap<>();
|
||||
for (String param : params) {
|
||||
String name = null;
|
||||
final String[] paramParts = param.split("=");
|
||||
try {
|
||||
name = URLDecoder.decode(paramParts[0], "utf-8");
|
||||
} catch (UnsupportedEncodingException e) {
|
||||
// Impossible
|
||||
}
|
||||
String value = null;
|
||||
try {
|
||||
value = URLDecoder.decode(paramParts[1], "utf-8");
|
||||
} catch (UnsupportedEncodingException e) {
|
||||
// Impossible
|
||||
}
|
||||
map.put(name, value);
|
||||
}
|
||||
return map;
|
||||
}
|
||||
|
||||
public static String join(CharSequence separator, Iterable<? extends CharSequence> list) {
|
||||
StringBuilder buf = new StringBuilder();
|
||||
for (CharSequence str : list) {
|
||||
if (buf.length() > 0) {
|
||||
buf.append(separator);
|
||||
}
|
||||
buf.append(str);
|
||||
}
|
||||
|
||||
return buf.toString();
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue