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