]> nmode's Git Repositories - signal-cli/blob - lib/src/main/java/org/asamk/signal/manager/storage/protocol/LegacyJsonIdentityKeyStore.java
4d94b455ed3f17172337ad4b692a673b62baa577
[signal-cli] / lib / src / main / java / org / asamk / signal / manager / storage / protocol / LegacyJsonIdentityKeyStore.java
1 package org.asamk.signal.manager.storage.protocol;
2
3 import com.fasterxml.jackson.core.JsonParser;
4 import com.fasterxml.jackson.databind.DeserializationContext;
5 import com.fasterxml.jackson.databind.JsonDeserializer;
6 import com.fasterxml.jackson.databind.JsonNode;
7
8 import org.asamk.signal.manager.api.TrustLevel;
9 import org.asamk.signal.manager.storage.Utils;
10 import org.asamk.signal.manager.storage.recipients.RecipientAddress;
11 import org.signal.libsignal.protocol.IdentityKey;
12 import org.signal.libsignal.protocol.IdentityKeyPair;
13 import org.signal.libsignal.protocol.InvalidKeyException;
14 import org.slf4j.Logger;
15 import org.slf4j.LoggerFactory;
16 import org.whispersystems.signalservice.api.push.ServiceId;
17 import org.whispersystems.signalservice.api.util.UuidUtil;
18
19 import java.io.IOException;
20 import java.util.ArrayList;
21 import java.util.Base64;
22 import java.util.Date;
23 import java.util.List;
24 import java.util.stream.Collectors;
25
26 public class LegacyJsonIdentityKeyStore {
27
28 private final static Logger logger = LoggerFactory.getLogger(LegacyJsonIdentityKeyStore.class);
29
30 private final List<LegacyIdentityInfo> identities;
31 private final IdentityKeyPair identityKeyPair;
32 private final int localRegistrationId;
33
34 private LegacyJsonIdentityKeyStore(
35 final List<LegacyIdentityInfo> identities, IdentityKeyPair identityKeyPair, int localRegistrationId
36 ) {
37 this.identities = identities;
38 this.identityKeyPair = identityKeyPair;
39 this.localRegistrationId = localRegistrationId;
40 }
41
42 public List<LegacyIdentityInfo> getIdentities() {
43 return identities.stream()
44 .map(LegacyIdentityInfo::getAddress)
45 .collect(Collectors.toSet())
46 .stream()
47 .map(this::getIdentity)
48 .toList();
49 }
50
51 public IdentityKeyPair getIdentityKeyPair() {
52 return identityKeyPair;
53 }
54
55 public int getLocalRegistrationId() {
56 return localRegistrationId;
57 }
58
59 private LegacyIdentityInfo getIdentity(RecipientAddress address) {
60 long maxDate = 0;
61 LegacyIdentityInfo maxIdentity = null;
62 for (var id : this.identities) {
63 if (!id.getAddress().matches(address)) {
64 continue;
65 }
66
67 final var time = id.getDateAdded().getTime();
68 if (maxIdentity == null || maxDate <= time) {
69 maxDate = time;
70 maxIdentity = id;
71 }
72 }
73 return maxIdentity;
74 }
75
76 public static class JsonIdentityKeyStoreDeserializer extends JsonDeserializer<LegacyJsonIdentityKeyStore> {
77
78 @Override
79 public LegacyJsonIdentityKeyStore deserialize(
80 JsonParser jsonParser, DeserializationContext deserializationContext
81 ) throws IOException {
82 JsonNode node = jsonParser.getCodec().readTree(jsonParser);
83
84 var localRegistrationId = node.get("registrationId").asInt();
85 var identityKeyPair = new IdentityKeyPair(Base64.getDecoder().decode(node.get("identityKey").asText()));
86
87 var identities = new ArrayList<LegacyIdentityInfo>();
88
89 var trustedKeysNode = node.get("trustedKeys");
90 if (trustedKeysNode.isArray()) {
91 for (var trustedKey : trustedKeysNode) {
92 var trustedKeyName = trustedKey.hasNonNull("name") ? trustedKey.get("name").asText() : null;
93
94 if (UuidUtil.isUuid(trustedKeyName)) {
95 // Ignore identities that were incorrectly created with UUIDs as name
96 continue;
97 }
98
99 var uuid = trustedKey.hasNonNull("uuid")
100 ? UuidUtil.parseOrNull(trustedKey.get("uuid").asText())
101 : null;
102 final var address = uuid == null
103 ? Utils.getRecipientAddressFromIdentifier(trustedKeyName)
104 : new RecipientAddress(ServiceId.from(uuid), trustedKeyName);
105 try {
106 var id = new IdentityKey(Base64.getDecoder().decode(trustedKey.get("identityKey").asText()), 0);
107 var trustLevel = trustedKey.hasNonNull("trustLevel") ? TrustLevel.fromInt(trustedKey.get(
108 "trustLevel").asInt()) : TrustLevel.TRUSTED_UNVERIFIED;
109 var added = trustedKey.hasNonNull("addedTimestamp") ? new Date(trustedKey.get("addedTimestamp")
110 .asLong()) : new Date();
111 identities.add(new LegacyIdentityInfo(address, id, trustLevel, added));
112 } catch (InvalidKeyException e) {
113 logger.warn("Error while decoding key for {}: {}", trustedKeyName, e.getMessage());
114 }
115 }
116 }
117
118 return new LegacyJsonIdentityKeyStore(identities, identityKeyPair, localRegistrationId);
119 }
120 }
121 }