1 package org
.asamk
.signal
.manager
.storage
.protocol
;
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
;
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
.util
.UuidUtil
;
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
;
25 public class LegacyJsonIdentityKeyStore
{
27 private final static Logger logger
= LoggerFactory
.getLogger(LegacyJsonIdentityKeyStore
.class);
29 private final List
<LegacyIdentityInfo
> identities
;
30 private final IdentityKeyPair identityKeyPair
;
31 private final int localRegistrationId
;
33 private LegacyJsonIdentityKeyStore(
34 final List
<LegacyIdentityInfo
> identities
, IdentityKeyPair identityKeyPair
, int localRegistrationId
36 this.identities
= identities
;
37 this.identityKeyPair
= identityKeyPair
;
38 this.localRegistrationId
= localRegistrationId
;
41 public List
<LegacyIdentityInfo
> getIdentities() {
42 return identities
.stream()
43 .map(LegacyIdentityInfo
::getAddress
)
44 .collect(Collectors
.toSet())
46 .map(this::getIdentity
)
50 public IdentityKeyPair
getIdentityKeyPair() {
51 return identityKeyPair
;
54 public int getLocalRegistrationId() {
55 return localRegistrationId
;
58 private LegacyIdentityInfo
getIdentity(RecipientAddress address
) {
60 LegacyIdentityInfo maxIdentity
= null;
61 for (var id
: this.identities
) {
62 if (!id
.getAddress().matches(address
)) {
66 final var time
= id
.getDateAdded().getTime();
67 if (maxIdentity
== null || maxDate
<= time
) {
75 public static class JsonIdentityKeyStoreDeserializer
extends JsonDeserializer
<LegacyJsonIdentityKeyStore
> {
78 public LegacyJsonIdentityKeyStore
deserialize(
79 JsonParser jsonParser
, DeserializationContext deserializationContext
80 ) throws IOException
{
81 JsonNode node
= jsonParser
.getCodec().readTree(jsonParser
);
83 var localRegistrationId
= node
.get("registrationId").asInt();
84 var identityKeyPair
= new IdentityKeyPair(Base64
.getDecoder().decode(node
.get("identityKey").asText()));
86 var identities
= new ArrayList
<LegacyIdentityInfo
>();
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;
93 if (UuidUtil
.isUuid(trustedKeyName
)) {
94 // Ignore identities that were incorrectly created with UUIDs as name
98 var uuid
= trustedKey
.hasNonNull("uuid")
99 ? UuidUtil
.parseOrNull(trustedKey
.get("uuid").asText())
101 final var address
= uuid
== null
102 ? Utils
.getRecipientAddressFromIdentifier(trustedKeyName
)
103 : new RecipientAddress(uuid
, trustedKeyName
);
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());
117 return new LegacyJsonIdentityKeyStore(identities
, identityKeyPair
, localRegistrationId
);