X-Git-Url: https://git.nmode.ca/signal-cli/blobdiff_plain/4acc9a96e34995c86c076d9020a40251c726c64c..9e6a3534275d5bac8454792e05280f13fa5ef13c:/src/main/java/org/asamk/signal/storage/SignalAccount.java diff --git a/src/main/java/org/asamk/signal/storage/SignalAccount.java b/src/main/java/org/asamk/signal/storage/SignalAccount.java index dbb0ac04..393d0449 100644 --- a/src/main/java/org/asamk/signal/storage/SignalAccount.java +++ b/src/main/java/org/asamk/signal/storage/SignalAccount.java @@ -10,6 +10,7 @@ import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.SerializationFeature; import com.fasterxml.jackson.databind.node.ObjectNode; +import org.asamk.signal.manager.groups.GroupId; import org.asamk.signal.storage.contacts.ContactInfo; import org.asamk.signal.storage.contacts.JsonContactsStore; import org.asamk.signal.storage.groups.GroupInfo; @@ -28,6 +29,8 @@ import org.asamk.signal.util.IOUtils; import org.asamk.signal.util.Util; import org.signal.zkgroup.InvalidInputException; import org.signal.zkgroup.profiles.ProfileKey; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.whispersystems.libsignal.IdentityKeyPair; import org.whispersystems.libsignal.state.PreKeyRecord; import org.whispersystems.libsignal.state.SignedPreKeyRecord; @@ -52,6 +55,8 @@ import java.util.stream.Collectors; public class SignalAccount implements Closeable { + final static Logger logger = LoggerFactory.getLogger(SignalAccount.class); + private final ObjectMapper jsonProcessor = new ObjectMapper(); private final FileChannel fileChannel; private final FileLock lock; @@ -85,8 +90,8 @@ public class SignalAccount implements Closeable { jsonProcessor.disable(JsonGenerator.Feature.AUTO_CLOSE_TARGET); } - public static SignalAccount load(String dataPath, String username) throws IOException { - final String fileName = getFileName(dataPath, username); + public static SignalAccount load(File dataPath, String username) throws IOException { + final File fileName = getFileName(dataPath, username); final Pair pair = openFileChannel(fileName); try { SignalAccount account = new SignalAccount(pair.first(), pair.second()); @@ -99,10 +104,12 @@ 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( + File dataPath, String username, IdentityKeyPair identityKey, int registrationId, ProfileKey profileKey + ) throws IOException { IOUtils.createPrivateDirectories(dataPath); - String fileName = getFileName(dataPath, username); - if (!new File(fileName).exists()) { + File fileName = getFileName(dataPath, username); + if (!fileName.exists()) { IOUtils.createPrivateFile(fileName); } @@ -122,10 +129,20 @@ public class SignalAccount implements Closeable { 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( + File dataPath, + String username, + UUID uuid, + String password, + int deviceId, + IdentityKeyPair identityKey, + int registrationId, + String signalingKey, + ProfileKey profileKey + ) throws IOException { IOUtils.createPrivateDirectories(dataPath); - String fileName = getFileName(dataPath, username); - if (!new File(fileName).exists()) { + File fileName = getFileName(dataPath, username); + if (!fileName.exists()) { IOUtils.createPrivateFile(fileName); } @@ -150,23 +167,31 @@ public class SignalAccount implements Closeable { return account; } - public static String getFileName(String dataPath, String username) { - return dataPath + "/" + username; + public static File getFileName(File dataPath, String username) { + return new File(dataPath, username); + } + + private static File getUserPath(final File dataPath, final String username) { + return new File(dataPath, username + ".d"); + } + + public static File getMessageCachePath(File dataPath, String username) { + return new File(getUserPath(dataPath, username), "msg-cache"); } - private static File getGroupCachePath(String dataPath, String username) { - return new File(new File(dataPath, username + ".d"), "group-cache"); + private static File getGroupCachePath(File dataPath, String username) { + return new File(getUserPath(dataPath, username), "group-cache"); } - public static boolean userExists(String dataPath, String username) { + public static boolean userExists(File dataPath, String username) { if (username == null) { return false; } - File f = new File(getFileName(dataPath, username)); + File f = getFileName(dataPath, username); return !(!f.exists() || f.isDirectory()); } - private void load(String dataPath) throws IOException { + private void load(File dataPath) throws IOException { JsonNode rootNode; synchronized (fileChannel) { fileChannel.position(0); @@ -209,11 +234,14 @@ public class SignalAccount implements Closeable { try { profileKey = new ProfileKey(Base64.decode(Util.getNotNullNode(rootNode, "profileKey").asText())); } 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(); JsonNode groupStoreNode = rootNode.get("groupStore"); if (groupStoreNode != null) { @@ -281,7 +309,8 @@ public class SignalAccount implements Closeable { JsonNode threadStoreNode = rootNode.get("threadStore"); 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 for (ThreadInfo thread : threadStore.getThreads()) { if (thread.id == null || thread.id.isEmpty()) { @@ -293,7 +322,7 @@ public class SignalAccount implements Closeable { contactInfo.messageExpirationTime = thread.messageExpirationTime; contactStore.updateContact(contactInfo); } else { - GroupInfo groupInfo = groupStore.getGroup(Base64.decode(thread.id)); + GroupInfo groupInfo = groupStore.getGroup(GroupId.fromBase64(thread.id)); if (groupInfo instanceof GroupInfoV1) { ((GroupInfoV1) groupInfo).messageExpirationTime = thread.messageExpirationTime; groupStore.updateGroup(groupInfo); @@ -326,8 +355,7 @@ public class SignalAccount implements Closeable { .putPOJO("contactStore", contactStore) .putPOJO("recipientStore", recipientStore) .putPOJO("profileStore", profileStore) - .putPOJO("stickerStore", stickerStore) - ; + .putPOJO("stickerStore", stickerStore); try { try (ByteArrayOutputStream output = new ByteArrayOutputStream()) { // Write to memory first to prevent corrupting the file in case of serialization errors @@ -341,17 +369,17 @@ public class SignalAccount implements Closeable { } } } catch (Exception e) { - System.err.println(String.format("Error saving file: %s", e.getMessage())); + logger.error("Error saving file: {}", e.getMessage()); } } - private static Pair openFileChannel(String fileName) throws IOException { - FileChannel fileChannel = new RandomAccessFile(new File(fileName), "rw").getChannel(); + private static Pair openFileChannel(File fileName) throws IOException { + FileChannel fileChannel = new RandomAccessFile(fileName, "rw").getChannel(); FileLock lock = fileChannel.tryLock(); if (lock == null) { - System.err.println("Config file is in use by another instance, waiting…"); + logger.info("Config file is in use by another instance, waiting…"); lock = fileChannel.lock(); - System.err.println("Config file lock acquired."); + logger.info("Config file lock acquired."); } return new Pair<>(fileChannel, lock); }