X-Git-Url: https://git.nmode.ca/signal-cli/blobdiff_plain/6cfddc0aff5785930c2264da683ba92a66963b73..b62694dbc75c2b52ce5fc946805f61f244f43dc0:/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 1ba78f6b..6d83f78f 100644 --- a/src/main/java/org/asamk/signal/storage/SignalAccount.java +++ b/src/main/java/org/asamk/signal/storage/SignalAccount.java @@ -10,12 +10,17 @@ import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.SerializationFeature; 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.JsonGroupStore; import org.asamk.signal.storage.protocol.JsonSignalProtocolStore; -import org.asamk.signal.storage.threads.JsonThreadStore; +import org.asamk.signal.storage.threads.LegacyJsonThreadStore; +import org.asamk.signal.storage.threads.ThreadInfo; 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.whispersystems.libsignal.IdentityKeyPair; import org.whispersystems.libsignal.state.PreKeyRecord; import org.whispersystems.libsignal.state.SignedPreKeyRecord; @@ -30,6 +35,7 @@ import java.nio.channels.Channels; import java.nio.channels.FileChannel; import java.nio.channels.FileLock; import java.util.Collection; +import java.util.UUID; public class SignalAccount { @@ -37,12 +43,13 @@ public class SignalAccount { private FileChannel fileChannel; private FileLock lock; private String username; + private UUID uuid; private int deviceId = SignalServiceAddress.DEFAULT_DEVICE_ID; private boolean isMultiDevice = false; private String password; private String registrationLockPin; private String signalingKey; - private byte[] profileKey; + private ProfileKey profileKey; private int preKeyIdOffset; private int nextSignedPreKeyId; @@ -51,7 +58,6 @@ public class SignalAccount { private JsonSignalProtocolStore signalProtocolStore; private JsonGroupStore groupStore; private JsonContactsStore contactStore; - private JsonThreadStore threadStore; private SignalAccount() { jsonProcessor.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.NONE); // disable autodetect @@ -70,7 +76,7 @@ public class SignalAccount { return account; } - public static SignalAccount create(String dataPath, String username, IdentityKeyPair identityKey, int registrationId, byte[] profileKey) throws IOException { + public static SignalAccount create(String dataPath, String username, IdentityKeyPair identityKey, int registrationId, ProfileKey profileKey) throws IOException { IOUtils.createPrivateDirectories(dataPath); SignalAccount account = new SignalAccount(); @@ -80,14 +86,13 @@ public class SignalAccount { account.profileKey = profileKey; account.signalProtocolStore = new JsonSignalProtocolStore(identityKey, registrationId); account.groupStore = new JsonGroupStore(); - account.threadStore = new JsonThreadStore(); account.contactStore = new JsonContactsStore(); account.registered = false; return account; } - public static SignalAccount createLinkedAccount(String dataPath, String username, String password, int deviceId, IdentityKeyPair identityKey, int registrationId, String signalingKey, byte[] profileKey) throws IOException { + public static SignalAccount createLinkedAccount(String dataPath, String username, String password, int deviceId, IdentityKeyPair identityKey, int registrationId, String signalingKey, ProfileKey profileKey) throws IOException { IOUtils.createPrivateDirectories(dataPath); SignalAccount account = new SignalAccount(); @@ -100,7 +105,6 @@ public class SignalAccount { account.signalingKey = signalingKey; account.signalProtocolStore = new JsonSignalProtocolStore(identityKey, registrationId); account.groupStore = new JsonGroupStore(); - account.threadStore = new JsonThreadStore(); account.contactStore = new JsonContactsStore(); account.registered = true; account.isMultiDevice = true; @@ -161,7 +165,11 @@ public class SignalAccount { nextSignedPreKeyId = 0; } if (rootNode.has("profileKey")) { - profileKey = Base64.decode(Util.getNotNullNode(rootNode, "profileKey").asText()); + 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); + } } signalProtocolStore = jsonProcessor.convertValue(Util.getNotNullNode(rootNode, "axolotlStore"), JsonSignalProtocolStore.class); @@ -183,10 +191,24 @@ public class SignalAccount { } JsonNode threadStoreNode = rootNode.get("threadStore"); if (threadStoreNode != null) { - threadStore = jsonProcessor.convertValue(threadStoreNode, JsonThreadStore.class); - } - if (threadStore == null) { - threadStore = new JsonThreadStore(); + LegacyJsonThreadStore threadStore = jsonProcessor.convertValue(threadStoreNode, LegacyJsonThreadStore.class); + // Migrate thread info to group and contact store + for (ThreadInfo thread : threadStore.getThreads()) { + try { + ContactInfo contactInfo = contactStore.getContact(new SignalServiceAddress(null, thread.id)); + if (contactInfo != null) { + contactInfo.messageExpirationTime = thread.messageExpirationTime; + contactStore.updateContact(contactInfo); + } else { + GroupInfo groupInfo = groupStore.getGroup(Base64.decode(thread.id)); + if (groupInfo != null) { + groupInfo.messageExpirationTime = thread.messageExpirationTime; + groupStore.updateGroup(groupInfo); + } + } + } catch (Exception ignored) { + } + } } } @@ -203,12 +225,11 @@ public class SignalAccount { .put("signalingKey", signalingKey) .put("preKeyIdOffset", preKeyIdOffset) .put("nextSignedPreKeyId", nextSignedPreKeyId) - .put("profileKey", Base64.encodeBytes(profileKey)) + .put("profileKey", Base64.encodeBytes(profileKey.serialize())) .put("registered", registered) .putPOJO("axolotlStore", signalProtocolStore) .putPOJO("groupStore", groupStore) .putPOJO("contactStore", contactStore) - .putPOJO("threadStore", threadStore) ; try { synchronized (fileChannel) { @@ -263,16 +284,16 @@ public class SignalAccount { return contactStore; } - public JsonThreadStore getThreadStore() { - return threadStore; - } - public String getUsername() { return username; } + public UUID getUuid() { + return uuid; + } + public SignalServiceAddress getSelfAddress() { - return new SignalServiceAddress(null, username); + return new SignalServiceAddress(uuid, username); } public int getDeviceId() { @@ -291,6 +312,10 @@ public class SignalAccount { return registrationLockPin; } + public String getRegistrationLock() { + return null; // TODO implement KBS + } + public void setRegistrationLockPin(final String registrationLockPin) { this.registrationLockPin = registrationLockPin; } @@ -303,11 +328,11 @@ public class SignalAccount { this.signalingKey = signalingKey; } - public byte[] getProfileKey() { + public ProfileKey getProfileKey() { return profileKey; } - public void setProfileKey(final byte[] profileKey) { + public void setProfileKey(final ProfileKey profileKey) { this.profileKey = profileKey; }