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;
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;
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;
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<FileChannel, FileLock> pair = openFileChannel(fileName);
try {
SignalAccount account = new SignalAccount(pair.first(), pair.second());
}
}
- 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);
}
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);
}
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);
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) {
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()) {
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);
.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
}
}
} catch (Exception e) {
- System.err.println(String.format("Error saving file: %s", e.getMessage()));
+ logger.error("Error saving file: {}", e.getMessage());
}
}
- private static Pair<FileChannel, FileLock> openFileChannel(String fileName) throws IOException {
- FileChannel fileChannel = new RandomAccessFile(new File(fileName), "rw").getChannel();
+ private static Pair<FileChannel, FileLock> 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);
}