X-Git-Url: https://git.nmode.ca/signal-cli/blobdiff_plain/20e253372b0b976bc57c2b6cae2bced4bfa0333c..4acc9a96e34995c86c076d9020a40251c726c64c:/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 f3acb47c..dbb0ac04 100644 --- a/src/main/java/org/asamk/signal/storage/SignalAccount.java +++ b/src/main/java/org/asamk/signal/storage/SignalAccount.java @@ -13,6 +13,7 @@ import com.fasterxml.jackson.databind.node.ObjectNode; import org.asamk.signal.storage.contacts.ContactInfo; import org.asamk.signal.storage.contacts.JsonContactsStore; import org.asamk.signal.storage.groups.GroupInfo; +import org.asamk.signal.storage.groups.GroupInfoV1; import org.asamk.signal.storage.groups.JsonGroupStore; import org.asamk.signal.storage.profiles.ProfileStore; import org.asamk.signal.storage.protocol.JsonIdentityKeyStore; @@ -20,6 +21,7 @@ import org.asamk.signal.storage.protocol.JsonSignalProtocolStore; import org.asamk.signal.storage.protocol.RecipientStore; import org.asamk.signal.storage.protocol.SessionInfo; import org.asamk.signal.storage.protocol.SignalServiceAddressResolver; +import org.asamk.signal.storage.stickers.StickerStore; import org.asamk.signal.storage.threads.LegacyJsonThreadStore; import org.asamk.signal.storage.threads.ThreadInfo; import org.asamk.signal.util.IOUtils; @@ -34,6 +36,8 @@ import org.whispersystems.libsignal.util.Pair; import org.whispersystems.signalservice.api.push.SignalServiceAddress; import org.whispersystems.util.Base64; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; import java.io.Closeable; import java.io.File; import java.io.IOException; @@ -69,6 +73,7 @@ public class SignalAccount implements Closeable { private JsonContactsStore contactStore; private RecipientStore recipientStore; private ProfileStore profileStore; + private StickerStore stickerStore; private SignalAccount(final FileChannel fileChannel, final FileLock lock) { this.fileChannel = fileChannel; @@ -85,7 +90,7 @@ public class SignalAccount implements Closeable { final Pair pair = openFileChannel(fileName); try { SignalAccount account = new SignalAccount(pair.first(), pair.second()); - account.load(); + account.load(dataPath); return account; } catch (Throwable e) { pair.second().close(); @@ -107,10 +112,11 @@ public class SignalAccount implements Closeable { account.username = username; account.profileKey = profileKey; account.signalProtocolStore = new JsonSignalProtocolStore(identityKey, registrationId); - account.groupStore = new JsonGroupStore(); + account.groupStore = new JsonGroupStore(getGroupCachePath(dataPath, username)); account.contactStore = new JsonContactsStore(); account.recipientStore = new RecipientStore(); account.profileStore = new ProfileStore(); + account.stickerStore = new StickerStore(); account.registered = false; return account; @@ -133,10 +139,11 @@ public class SignalAccount implements Closeable { account.deviceId = deviceId; account.signalingKey = signalingKey; account.signalProtocolStore = new JsonSignalProtocolStore(identityKey, registrationId); - account.groupStore = new JsonGroupStore(); + account.groupStore = new JsonGroupStore(getGroupCachePath(dataPath, username)); account.contactStore = new JsonContactsStore(); account.recipientStore = new RecipientStore(); account.profileStore = new ProfileStore(); + account.stickerStore = new StickerStore(); account.registered = true; account.isMultiDevice = true; @@ -147,6 +154,10 @@ public class SignalAccount implements Closeable { return dataPath + "/" + username; } + private static File getGroupCachePath(String dataPath, String username) { + return new File(new File(dataPath, username + ".d"), "group-cache"); + } + public static boolean userExists(String dataPath, String username) { if (username == null) { return false; @@ -155,7 +166,7 @@ public class SignalAccount implements Closeable { return !(!f.exists() || f.isDirectory()); } - private void load() throws IOException { + private void load(String dataPath) throws IOException { JsonNode rootNode; synchronized (fileChannel) { fileChannel.position(0); @@ -207,9 +218,10 @@ public class SignalAccount implements Closeable { JsonNode groupStoreNode = rootNode.get("groupStore"); if (groupStoreNode != null) { groupStore = jsonProcessor.convertValue(groupStoreNode, JsonGroupStore.class); + groupStore.groupCachePath = getGroupCachePath(dataPath, username); } if (groupStore == null) { - groupStore = new JsonGroupStore(); + groupStore = new JsonGroupStore(getGroupCachePath(dataPath, username)); } JsonNode contactStoreNode = rootNode.get("contactStore"); @@ -234,9 +246,12 @@ public class SignalAccount implements Closeable { } for (GroupInfo group : groupStore.getGroups()) { - group.members = group.members.stream() - .map(m -> recipientStore.resolveServiceAddress(m)) - .collect(Collectors.toSet()); + if (group instanceof GroupInfoV1) { + GroupInfoV1 groupInfoV1 = (GroupInfoV1) group; + groupInfoV1.members = groupInfoV1.members.stream() + .map(m -> recipientStore.resolveServiceAddress(m)) + .collect(Collectors.toSet()); + } } for (SessionInfo session : signalProtocolStore.getSessions()) { @@ -256,6 +271,14 @@ public class SignalAccount implements Closeable { profileStore = new ProfileStore(); } + JsonNode stickerStoreNode = rootNode.get("stickerStore"); + if (stickerStoreNode != null) { + stickerStore = jsonProcessor.convertValue(stickerStoreNode, StickerStore.class); + } + if (stickerStore == null) { + stickerStore = new StickerStore(); + } + JsonNode threadStoreNode = rootNode.get("threadStore"); if (threadStoreNode != null) { LegacyJsonThreadStore threadStore = jsonProcessor.convertValue(threadStoreNode, LegacyJsonThreadStore.class); @@ -271,8 +294,8 @@ public class SignalAccount implements Closeable { contactStore.updateContact(contactInfo); } else { GroupInfo groupInfo = groupStore.getGroup(Base64.decode(thread.id)); - if (groupInfo != null) { - groupInfo.messageExpirationTime = thread.messageExpirationTime; + if (groupInfo instanceof GroupInfoV1) { + ((GroupInfoV1) groupInfo).messageExpirationTime = thread.messageExpirationTime; groupStore.updateGroup(groupInfo); } } @@ -303,13 +326,19 @@ public class SignalAccount implements Closeable { .putPOJO("contactStore", contactStore) .putPOJO("recipientStore", recipientStore) .putPOJO("profileStore", profileStore) + .putPOJO("stickerStore", stickerStore) ; try { - synchronized (fileChannel) { - fileChannel.position(0); - jsonProcessor.writeValue(Channels.newOutputStream(fileChannel), rootNode); - fileChannel.truncate(fileChannel.position()); - fileChannel.force(false); + try (ByteArrayOutputStream output = new ByteArrayOutputStream()) { + // Write to memory first to prevent corrupting the file in case of serialization errors + jsonProcessor.writeValue(output, rootNode); + ByteArrayInputStream input = new ByteArrayInputStream(output.toByteArray()); + synchronized (fileChannel) { + fileChannel.position(0); + input.transferTo(Channels.newOutputStream(fileChannel)); + fileChannel.truncate(fileChannel.position()); + fileChannel.force(false); + } } } catch (Exception e) { System.err.println(String.format("Error saving file: %s", e.getMessage())); @@ -363,6 +392,10 @@ public class SignalAccount implements Closeable { return profileStore; } + public StickerStore getStickerStore() { + return stickerStore; + } + public String getUsername() { return username; }