Refactor sticker store

This commit is contained in:
AsamK 2021-05-02 12:08:47 +02:00
parent 4e123a2dc3
commit 624fa4fda4
8 changed files with 214 additions and 171 deletions

View file

@ -39,6 +39,7 @@ import org.asamk.signal.manager.storage.recipients.Contact;
import org.asamk.signal.manager.storage.recipients.Profile; import org.asamk.signal.manager.storage.recipients.Profile;
import org.asamk.signal.manager.storage.recipients.RecipientId; import org.asamk.signal.manager.storage.recipients.RecipientId;
import org.asamk.signal.manager.storage.stickers.Sticker; import org.asamk.signal.manager.storage.stickers.Sticker;
import org.asamk.signal.manager.storage.stickers.StickerPackId;
import org.asamk.signal.manager.util.AttachmentUtils; import org.asamk.signal.manager.util.AttachmentUtils;
import org.asamk.signal.manager.util.IOUtils; import org.asamk.signal.manager.util.IOUtils;
import org.asamk.signal.manager.util.KeyUtils; import org.asamk.signal.manager.util.KeyUtils;
@ -1170,7 +1171,7 @@ public class Manager implements Closeable {
var packKey = KeyUtils.createStickerUploadKey(); var packKey = KeyUtils.createStickerUploadKey();
var packId = messageSender.uploadStickerManifest(manifest, packKey); var packId = messageSender.uploadStickerManifest(manifest, packKey);
var sticker = new Sticker(Hex.fromStringCondensed(packId), packKey); var sticker = new Sticker(StickerPackId.deserialize(Hex.fromStringCondensed(packId)), packKey);
account.getStickerStore().updateSticker(sticker); account.getStickerStore().updateSticker(sticker);
account.save(); account.save();
@ -1591,9 +1592,10 @@ public class Manager implements Closeable {
} }
if (message.getSticker().isPresent()) { if (message.getSticker().isPresent()) {
final var messageSticker = message.getSticker().get(); final var messageSticker = message.getSticker().get();
var sticker = account.getStickerStore().getSticker(messageSticker.getPackId()); final var stickerPackId = StickerPackId.deserialize(messageSticker.getPackId());
var sticker = account.getStickerStore().getSticker(stickerPackId);
if (sticker == null) { if (sticker == null) {
sticker = new Sticker(messageSticker.getPackId(), messageSticker.getPackKey()); sticker = new Sticker(stickerPackId, messageSticker.getPackKey());
account.getStickerStore().updateSticker(sticker); account.getStickerStore().updateSticker(sticker);
} }
} }
@ -2086,12 +2088,13 @@ public class Manager implements Closeable {
if (!m.getPackId().isPresent()) { if (!m.getPackId().isPresent()) {
continue; continue;
} }
var sticker = account.getStickerStore().getSticker(m.getPackId().get()); final var stickerPackId = StickerPackId.deserialize(m.getPackId().get());
var sticker = account.getStickerStore().getSticker(stickerPackId);
if (sticker == null) { if (sticker == null) {
if (!m.getPackKey().isPresent()) { if (!m.getPackKey().isPresent()) {
continue; continue;
} }
sticker = new Sticker(m.getPackId().get(), m.getPackKey().get()); sticker = new Sticker(stickerPackId, m.getPackKey().get());
} }
sticker.setInstalled(!m.getType().isPresent() sticker.setInstalled(!m.getType().isPresent()
|| m.getType().get() == StickerPackOperationMessage.Type.INSTALL); || m.getType().get() == StickerPackOperationMessage.Type.INSTALL);

View file

@ -1,13 +1,7 @@
package org.asamk.signal.manager.storage; package org.asamk.signal.manager.storage;
import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import org.asamk.signal.manager.groups.GroupId; import org.asamk.signal.manager.groups.GroupId;
import org.asamk.signal.manager.storage.contacts.ContactsStore; import org.asamk.signal.manager.storage.contacts.ContactsStore;
@ -32,7 +26,6 @@ import org.asamk.signal.manager.storage.stickers.StickerStore;
import org.asamk.signal.manager.storage.threads.LegacyJsonThreadStore; import org.asamk.signal.manager.storage.threads.LegacyJsonThreadStore;
import org.asamk.signal.manager.util.IOUtils; import org.asamk.signal.manager.util.IOUtils;
import org.asamk.signal.manager.util.KeyUtils; import org.asamk.signal.manager.util.KeyUtils;
import org.asamk.signal.manager.util.Utils;
import org.signal.zkgroup.InvalidInputException; import org.signal.zkgroup.InvalidInputException;
import org.signal.zkgroup.profiles.ProfileKey; import org.signal.zkgroup.profiles.ProfileKey;
import org.slf4j.Logger; import org.slf4j.Logger;
@ -69,9 +62,11 @@ public class SignalAccount implements Closeable {
private final static Logger logger = LoggerFactory.getLogger(SignalAccount.class); private final static Logger logger = LoggerFactory.getLogger(SignalAccount.class);
private final ObjectMapper jsonProcessor = new ObjectMapper(); private final ObjectMapper jsonProcessor = Utils.createStorageObjectMapper();
private final FileChannel fileChannel; private final FileChannel fileChannel;
private final FileLock lock; private final FileLock lock;
private String username; private String username;
private UUID uuid; private UUID uuid;
private int deviceId = SignalServiceAddress.DEFAULT_DEVICE_ID; private int deviceId = SignalServiceAddress.DEFAULT_DEVICE_ID;
@ -94,17 +89,13 @@ public class SignalAccount implements Closeable {
private JsonGroupStore groupStore; private JsonGroupStore groupStore;
private RecipientStore recipientStore; private RecipientStore recipientStore;
private StickerStore stickerStore; private StickerStore stickerStore;
private StickerStore.Storage stickerStoreStorage;
private MessageCache messageCache; private MessageCache messageCache;
private SignalAccount(final FileChannel fileChannel, final FileLock lock) { private SignalAccount(final FileChannel fileChannel, final FileLock lock) {
this.fileChannel = fileChannel; this.fileChannel = fileChannel;
this.lock = lock; this.lock = lock;
jsonProcessor.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.NONE); // disable autodetect
jsonProcessor.enable(SerializationFeature.INDENT_OUTPUT); // for pretty print
jsonProcessor.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
jsonProcessor.disable(JsonParser.Feature.AUTO_CLOSE_SOURCE);
jsonProcessor.disable(JsonGenerator.Feature.AUTO_CLOSE_TARGET);
} }
public static SignalAccount load(File dataPath, String username) throws IOException { public static SignalAccount load(File dataPath, String username) throws IOException {
@ -137,24 +128,10 @@ public class SignalAccount implements Closeable {
account.username = username; account.username = username;
account.profileKey = profileKey; account.profileKey = profileKey;
account.groupStore = new JsonGroupStore(getGroupCachePath(dataPath, username));
account.recipientStore = RecipientStore.load(getRecipientsStoreFile(dataPath, username),
account::mergeRecipients);
account.preKeyStore = new PreKeyStore(getPreKeysPath(dataPath, username));
account.signedPreKeyStore = new SignedPreKeyStore(getSignedPreKeysPath(dataPath, username));
account.sessionStore = new SessionStore(getSessionsPath(dataPath, username),
account.recipientStore::resolveRecipient);
account.identityKeyStore = new IdentityKeyStore(getIdentitiesPath(dataPath, username),
account.recipientStore::resolveRecipient,
identityKey,
registrationId);
account.signalProtocolStore = new SignalProtocolStore(account.preKeyStore,
account.signedPreKeyStore,
account.sessionStore,
account.identityKeyStore);
account.stickerStore = new StickerStore();
account.messageCache = new MessageCache(getMessageCachePath(dataPath, username)); account.initStores(dataPath, identityKey, registrationId);
account.groupStore = new JsonGroupStore(getGroupCachePath(dataPath, username));
account.stickerStore = new StickerStore(account::saveStickerStore);
account.registered = false; account.registered = false;
@ -163,6 +140,23 @@ public class SignalAccount implements Closeable {
return account; return account;
} }
private void initStores(
final File dataPath, final IdentityKeyPair identityKey, final int registrationId
) throws IOException {
recipientStore = RecipientStore.load(getRecipientsStoreFile(dataPath, username), this::mergeRecipients);
preKeyStore = new PreKeyStore(getPreKeysPath(dataPath, username));
signedPreKeyStore = new SignedPreKeyStore(getSignedPreKeysPath(dataPath, username));
sessionStore = new SessionStore(getSessionsPath(dataPath, username), recipientStore::resolveRecipient);
identityKeyStore = new IdentityKeyStore(getIdentitiesPath(dataPath, username),
recipientStore::resolveRecipient,
identityKey,
registrationId);
signalProtocolStore = new SignalProtocolStore(preKeyStore, signedPreKeyStore, sessionStore, identityKeyStore);
messageCache = new MessageCache(getMessageCachePath(dataPath, username));
}
public static SignalAccount createLinkedAccount( public static SignalAccount createLinkedAccount(
File dataPath, File dataPath,
String username, String username,
@ -187,29 +181,15 @@ public class SignalAccount implements Closeable {
account.password = password; account.password = password;
account.profileKey = profileKey; account.profileKey = profileKey;
account.deviceId = deviceId; account.deviceId = deviceId;
account.groupStore = new JsonGroupStore(getGroupCachePath(dataPath, username));
account.recipientStore = RecipientStore.load(getRecipientsStoreFile(dataPath, username),
account::mergeRecipients);
account.recipientStore.resolveRecipientTrusted(account.getSelfAddress());
account.preKeyStore = new PreKeyStore(getPreKeysPath(dataPath, username));
account.signedPreKeyStore = new SignedPreKeyStore(getSignedPreKeysPath(dataPath, username));
account.sessionStore = new SessionStore(getSessionsPath(dataPath, username),
account.recipientStore::resolveRecipient);
account.identityKeyStore = new IdentityKeyStore(getIdentitiesPath(dataPath, username),
account.recipientStore::resolveRecipient,
identityKey,
registrationId);
account.signalProtocolStore = new SignalProtocolStore(account.preKeyStore,
account.signedPreKeyStore,
account.sessionStore,
account.identityKeyStore);
account.stickerStore = new StickerStore();
account.messageCache = new MessageCache(getMessageCachePath(dataPath, username)); account.initStores(dataPath, identityKey, registrationId);
account.groupStore = new JsonGroupStore(getGroupCachePath(dataPath, username));
account.stickerStore = new StickerStore(account::saveStickerStore);
account.registered = true; account.registered = true;
account.isMultiDevice = true; account.isMultiDevice = true;
account.recipientStore.resolveRecipientTrusted(account.getSelfAddress());
account.migrateLegacyConfigs(); account.migrateLegacyConfigs();
return account; return account;
@ -347,20 +327,10 @@ public class SignalAccount implements Closeable {
registrationId = legacySignalProtocolStore.getLegacyIdentityKeyStore().getLocalRegistrationId(); registrationId = legacySignalProtocolStore.getLegacyIdentityKeyStore().getLocalRegistrationId();
} }
recipientStore = RecipientStore.load(getRecipientsStoreFile(dataPath, username), this::mergeRecipients); initStores(dataPath, identityKeyPair, registrationId);
preKeyStore = new PreKeyStore(getPreKeysPath(dataPath, username));
signedPreKeyStore = new SignedPreKeyStore(getSignedPreKeysPath(dataPath, username));
sessionStore = new SessionStore(getSessionsPath(dataPath, username), recipientStore::resolveRecipient);
identityKeyStore = new IdentityKeyStore(getIdentitiesPath(dataPath, username),
recipientStore::resolveRecipient,
identityKeyPair,
registrationId);
loadLegacyStores(rootNode, legacySignalProtocolStore); loadLegacyStores(rootNode, legacySignalProtocolStore);
signalProtocolStore = new SignalProtocolStore(preKeyStore, signedPreKeyStore, sessionStore, identityKeyStore);
var groupStoreNode = rootNode.get("groupStore"); var groupStoreNode = rootNode.get("groupStore");
if (groupStoreNode != null) { if (groupStoreNode != null) {
groupStore = jsonProcessor.convertValue(groupStoreNode, JsonGroupStore.class); groupStore = jsonProcessor.convertValue(groupStoreNode, JsonGroupStore.class);
@ -370,15 +340,12 @@ public class SignalAccount implements Closeable {
groupStore = new JsonGroupStore(getGroupCachePath(dataPath, username)); groupStore = new JsonGroupStore(getGroupCachePath(dataPath, username));
} }
var stickerStoreNode = rootNode.get("stickerStore"); if (rootNode.hasNonNull("stickerStore")) {
if (stickerStoreNode != null) { stickerStoreStorage = jsonProcessor.convertValue(rootNode.get("stickerStore"), StickerStore.Storage.class);
stickerStore = jsonProcessor.convertValue(stickerStoreNode, StickerStore.class); stickerStore = StickerStore.fromStorage(stickerStoreStorage, this::saveStickerStore);
} else {
stickerStore = new StickerStore(this::saveStickerStore);
} }
if (stickerStore == null) {
stickerStore = new StickerStore();
}
messageCache = new MessageCache(getMessageCachePath(dataPath, username));
loadLegacyThreadStore(rootNode); loadLegacyThreadStore(rootNode);
} }
@ -538,10 +505,13 @@ public class SignalAccount implements Closeable {
} }
} }
public void save() { private void saveStickerStore(StickerStore.Storage storage) {
if (fileChannel == null) { this.stickerStoreStorage = storage;
return; save();
} }
public void save() {
synchronized (fileChannel) {
var rootNode = jsonProcessor.createObjectNode(); var rootNode = jsonProcessor.createObjectNode();
rootNode.put("username", username) rootNode.put("username", username)
.put("uuid", uuid == null ? null : uuid.toString()) .put("uuid", uuid == null ? null : uuid.toString())
@ -565,23 +535,22 @@ public class SignalAccount implements Closeable {
.put("profileKey", Base64.getEncoder().encodeToString(profileKey.serialize())) .put("profileKey", Base64.getEncoder().encodeToString(profileKey.serialize()))
.put("registered", registered) .put("registered", registered)
.putPOJO("groupStore", groupStore) .putPOJO("groupStore", groupStore)
.putPOJO("stickerStore", stickerStore); .putPOJO("stickerStore", stickerStoreStorage);
try { try {
try (var output = new ByteArrayOutputStream()) { try (var output = new ByteArrayOutputStream()) {
// Write to memory first to prevent corrupting the file in case of serialization errors // Write to memory first to prevent corrupting the file in case of serialization errors
jsonProcessor.writeValue(output, rootNode); jsonProcessor.writeValue(output, rootNode);
var input = new ByteArrayInputStream(output.toByteArray()); var input = new ByteArrayInputStream(output.toByteArray());
synchronized (fileChannel) {
fileChannel.position(0); fileChannel.position(0);
input.transferTo(Channels.newOutputStream(fileChannel)); input.transferTo(Channels.newOutputStream(fileChannel));
fileChannel.truncate(fileChannel.position()); fileChannel.truncate(fileChannel.position());
fileChannel.force(false); fileChannel.force(false);
} }
}
} catch (Exception e) { } catch (Exception e) {
logger.error("Error saving file: {}", e.getMessage()); logger.error("Error saving file: {}", e.getMessage());
} }
} }
}
private static Pair<FileChannel, FileLock> openFileChannel(File fileName) throws IOException { private static Pair<FileChannel, FileLock> openFileChannel(File fileName) throws IOException {
var fileChannel = new RandomAccessFile(fileName, "rw").getChannel(); var fileChannel = new RandomAccessFile(fileName, "rw").getChannel();

View file

@ -5,9 +5,12 @@ import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.core.JsonGenerator; import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.core.JsonParser; import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.databind.DeserializationFeature; import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature; import com.fasterxml.jackson.databind.SerializationFeature;
import java.io.InvalidObjectException;
public class Utils { public class Utils {
private Utils() { private Utils() {
@ -24,4 +27,14 @@ public class Utils {
return jsonProcessor; return jsonProcessor;
} }
public static JsonNode getNotNullNode(JsonNode parent, String name) throws InvalidObjectException {
var node = parent.get(name);
if (node == null || node.isNull()) {
throw new InvalidObjectException(String.format("Incorrect file format: expected parameter %s not found ",
name));
}
return node;
}
} }

View file

@ -1,5 +1,6 @@
package org.asamk.signal.manager.storage.groups; package org.asamk.signal.manager.storage.groups;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.core.JsonGenerator; import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.core.JsonParser; import com.fasterxml.jackson.core.JsonParser;
@ -39,6 +40,7 @@ public class JsonGroupStore {
private final static Logger logger = LoggerFactory.getLogger(JsonGroupStore.class); private final static Logger logger = LoggerFactory.getLogger(JsonGroupStore.class);
private static final ObjectMapper jsonProcessor = new ObjectMapper(); private static final ObjectMapper jsonProcessor = new ObjectMapper();
@JsonIgnore
public File groupCachePath; public File groupCachePath;
@JsonProperty("groups") @JsonProperty("groups")
@ -137,6 +139,7 @@ public class JsonGroupStore {
return null; return null;
} }
@JsonIgnore
public List<GroupInfo> getGroups() { public List<GroupInfo> getGroups() {
final var groups = this.groups.values(); final var groups = this.groups.values();
for (var group : groups) { for (var group : groups) {

View file

@ -2,22 +2,22 @@ package org.asamk.signal.manager.storage.stickers;
public class Sticker { public class Sticker {
private final byte[] packId; private final StickerPackId packId;
private final byte[] packKey; private final byte[] packKey;
private boolean installed; private boolean installed;
public Sticker(final byte[] packId, final byte[] packKey) { public Sticker(final StickerPackId packId, final byte[] packKey) {
this.packId = packId; this.packId = packId;
this.packKey = packKey; this.packKey = packKey;
} }
public Sticker(final byte[] packId, final byte[] packKey, final boolean installed) { public Sticker(final StickerPackId packId, final byte[] packKey, final boolean installed) {
this.packId = packId; this.packId = packId;
this.packKey = packKey; this.packKey = packKey;
this.installed = installed; this.installed = installed;
} }
public byte[] getPackId() { public StickerPackId getPackId() {
return packId; return packId;
} }

View file

@ -0,0 +1,35 @@
package org.asamk.signal.manager.storage.stickers;
import java.util.Arrays;
public class StickerPackId {
private final byte[] id;
private StickerPackId(final byte[] id) {
this.id = id;
}
public static StickerPackId deserialize(byte[] packId) {
return new StickerPackId(packId);
}
public byte[] serialize() {
return id;
}
@Override
public boolean equals(final Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
final StickerPackId that = (StickerPackId) o;
return Arrays.equals(id, that.id);
}
@Override
public int hashCode() {
return Arrays.hashCode(id);
}
}

View file

@ -1,69 +1,102 @@
package org.asamk.signal.manager.storage.stickers; package org.asamk.signal.manager.storage.stickers;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.JsonDeserializer;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.SerializerProvider;
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import java.io.IOException;
import java.util.Base64; import java.util.Base64;
import java.util.HashMap; import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;
public class StickerStore { public class StickerStore {
@JsonSerialize(using = StickersSerializer.class) private final Map<StickerPackId, Sticker> stickers;
@JsonDeserialize(using = StickersDeserializer.class)
private final Map<byte[], Sticker> stickers = new HashMap<>();
public Sticker getSticker(byte[] packId) { private final Saver saver;
public StickerStore(final Saver saver) {
this.saver = saver;
stickers = new HashMap<>();
}
public StickerStore(final Map<StickerPackId, Sticker> stickers, final Saver saver) {
this.stickers = stickers;
this.saver = saver;
}
public static StickerStore fromStorage(Storage storage, Saver saver) {
final var packIds = new HashSet<StickerPackId>();
final var stickers = storage.stickers.stream().map(s -> {
var packId = StickerPackId.deserialize(Base64.getDecoder().decode(s.packId));
if (packIds.contains(packId)) {
// Remove legacy duplicate packIds ...
return null;
}
packIds.add(packId);
var packKey = Base64.getDecoder().decode(s.packKey);
var installed = s.installed;
return new Sticker(packId, packKey, installed);
}).filter(Objects::nonNull).collect(Collectors.toMap(Sticker::getPackId, s -> s));
return new StickerStore(stickers, saver);
}
public Sticker getSticker(StickerPackId packId) {
synchronized (stickers) {
return stickers.get(packId); return stickers.get(packId);
} }
}
public void updateSticker(Sticker sticker) { public void updateSticker(Sticker sticker) {
Storage storage;
synchronized (stickers) {
stickers.put(sticker.getPackId(), sticker); stickers.put(sticker.getPackId(), sticker);
storage = toStorageLocked();
}
saver.save(storage);
} }
private static class StickersSerializer extends JsonSerializer<Map<byte[], Sticker>> { private Storage toStorageLocked() {
return new Storage(stickers.values()
@Override .stream()
public void serialize( .map(s -> new Storage.Sticker(Base64.getEncoder().encodeToString(s.getPackId().serialize()),
final Map<byte[], Sticker> value, final JsonGenerator jgen, final SerializerProvider provider Base64.getEncoder().encodeToString(s.getPackKey()),
) throws IOException { s.isInstalled()))
final var stickers = value.values(); .collect(Collectors.toList()));
jgen.writeStartArray(stickers.size()); }
for (var sticker : stickers) {
jgen.writeStartObject(); public static class Storage {
jgen.writeStringField("packId", Base64.getEncoder().encodeToString(sticker.getPackId()));
jgen.writeStringField("packKey", Base64.getEncoder().encodeToString(sticker.getPackKey())); public List<Storage.Sticker> stickers;
jgen.writeBooleanField("installed", sticker.isInstalled());
jgen.writeEndObject(); // For deserialization
private Storage() {
}
public Storage(final List<Sticker> stickers) {
this.stickers = stickers;
}
private static class Sticker {
public String packId;
public String packKey;
public boolean installed;
// For deserialization
private Sticker() {
}
public Sticker(final String packId, final String packKey, final boolean installed) {
this.packId = packId;
this.packKey = packKey;
this.installed = installed;
} }
jgen.writeEndArray();
} }
} }
private static class StickersDeserializer extends JsonDeserializer<Map<byte[], Sticker>> { public interface Saver {
@Override void save(Storage storage);
public Map<byte[], Sticker> deserialize(
JsonParser jsonParser, DeserializationContext deserializationContext
) throws IOException {
var stickers = new HashMap<byte[], Sticker>();
JsonNode node = jsonParser.getCodec().readTree(jsonParser);
for (var n : node) {
var packId = Base64.getDecoder().decode(n.get("packId").asText());
var packKey = Base64.getDecoder().decode(n.get("packKey").asText());
var installed = n.get("installed").asBoolean(false);
stickers.put(packId, new Sticker(packId, packKey, installed));
}
return stickers;
}
} }
} }

View file

@ -1,7 +1,5 @@
package org.asamk.signal.manager.util; package org.asamk.signal.manager.util;
import com.fasterxml.jackson.databind.JsonNode;
import org.whispersystems.libsignal.IdentityKey; import org.whispersystems.libsignal.IdentityKey;
import org.whispersystems.libsignal.fingerprint.NumericFingerprintGenerator; import org.whispersystems.libsignal.fingerprint.NumericFingerprintGenerator;
import org.whispersystems.signalservice.api.push.SignalServiceAddress; import org.whispersystems.signalservice.api.push.SignalServiceAddress;
@ -13,7 +11,6 @@ import java.io.File;
import java.io.FileInputStream; import java.io.FileInputStream;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.io.InvalidObjectException;
import java.net.URLConnection; import java.net.URLConnection;
import java.nio.file.Files; import java.nio.file.Files;
@ -80,14 +77,4 @@ public class Utils {
return new SignalServiceAddress(null, identifier); return new SignalServiceAddress(null, identifier);
} }
} }
public static JsonNode getNotNullNode(JsonNode parent, String name) throws InvalidObjectException {
var node = parent.get(name);
if (node == null || node.isNull()) {
throw new InvalidObjectException(String.format("Incorrect file format: expected parameter %s not found ",
name));
}
return node;
}
} }