1 package org
.asamk
.signal
.storage
.profiles
;
3 import com
.fasterxml
.jackson
.annotation
.JsonProperty
;
4 import com
.fasterxml
.jackson
.core
.JsonGenerator
;
5 import com
.fasterxml
.jackson
.core
.JsonParser
;
6 import com
.fasterxml
.jackson
.databind
.DeserializationContext
;
7 import com
.fasterxml
.jackson
.databind
.JsonDeserializer
;
8 import com
.fasterxml
.jackson
.databind
.JsonNode
;
9 import com
.fasterxml
.jackson
.databind
.JsonSerializer
;
10 import com
.fasterxml
.jackson
.databind
.ObjectMapper
;
11 import com
.fasterxml
.jackson
.databind
.SerializerProvider
;
12 import com
.fasterxml
.jackson
.databind
.annotation
.JsonDeserialize
;
13 import com
.fasterxml
.jackson
.databind
.annotation
.JsonSerialize
;
15 import org
.signal
.zkgroup
.InvalidInputException
;
16 import org
.signal
.zkgroup
.profiles
.ProfileKey
;
17 import org
.whispersystems
.signalservice
.api
.push
.SignalServiceAddress
;
18 import org
.whispersystems
.signalservice
.api
.util
.UuidUtil
;
19 import org
.whispersystems
.util
.Base64
;
21 import java
.io
.IOException
;
22 import java
.util
.ArrayList
;
23 import java
.util
.HashMap
;
24 import java
.util
.List
;
25 import java
.util
.UUID
;
27 public class ProfileStore
{
29 private static final ObjectMapper jsonProcessor
= new ObjectMapper();
31 @JsonProperty("profiles")
32 @JsonDeserialize(using
= ProfileStoreDeserializer
.class)
33 @JsonSerialize(using
= ProfileStoreSerializer
.class)
34 private final List
<SignalProfileEntry
> profiles
= new ArrayList
<>();
36 public SignalProfileEntry
getProfile(SignalServiceAddress serviceAddress
) {
37 for (SignalProfileEntry entry
: profiles
) {
38 if (entry
.getServiceAddress().matches(serviceAddress
)) {
45 public void updateProfile(SignalServiceAddress serviceAddress
, ProfileKey profileKey
, long now
, SignalProfile profile
) {
46 SignalProfileEntry newEntry
= new SignalProfileEntry(serviceAddress
, profileKey
, now
, profile
);
47 for (int i
= 0; i
< profiles
.size(); i
++) {
48 if (profiles
.get(i
).getServiceAddress().matches(serviceAddress
)) {
49 profiles
.set(i
, newEntry
);
54 profiles
.add(newEntry
);
57 public static class ProfileStoreDeserializer
extends JsonDeserializer
<List
<SignalProfileEntry
>> {
60 public List
<SignalProfileEntry
> deserialize(JsonParser jsonParser
, DeserializationContext deserializationContext
) throws IOException
{
61 JsonNode node
= jsonParser
.getCodec().readTree(jsonParser
);
63 List
<SignalProfileEntry
> addresses
= new ArrayList
<>();
66 for (JsonNode entry
: node
) {
67 String name
= entry
.hasNonNull("name")
68 ? entry
.get("name").asText()
70 UUID uuid
= entry
.hasNonNull("uuid")
71 ? UuidUtil
.parseOrNull(entry
.get("uuid").asText())
73 final SignalServiceAddress serviceAddress
= new SignalServiceAddress(uuid
, name
);
74 ProfileKey profileKey
= null;
76 profileKey
= new ProfileKey(Base64
.decode(entry
.get("profileKey").asText()));
77 } catch (InvalidInputException ignored
) {
79 long lastUpdateTimestamp
= entry
.get("lastUpdateTimestamp").asLong();
80 SignalProfile profile
= jsonProcessor
.treeToValue(entry
.get("profile"), SignalProfile
.class);
81 addresses
.add(new SignalProfileEntry(serviceAddress
, profileKey
, lastUpdateTimestamp
, profile
));
89 public static class ProfileStoreSerializer
extends JsonSerializer
<List
<SignalProfileEntry
>> {
92 public void serialize(List
<SignalProfileEntry
> profiles
, JsonGenerator json
, SerializerProvider serializerProvider
) throws IOException
{
93 json
.writeStartArray();
94 for (SignalProfileEntry profileEntry
: profiles
) {
95 final SignalServiceAddress address
= profileEntry
.getServiceAddress();
96 json
.writeStartObject();
97 if (address
.getNumber().isPresent()) {
98 json
.writeStringField("name", address
.getNumber().get());
100 if (address
.getUuid().isPresent()) {
101 json
.writeStringField("uuid", address
.getUuid().get().toString());
103 json
.writeStringField("profileKey", Base64
.encodeBytes(profileEntry
.getProfileKey().serialize()));
104 json
.writeNumberField("lastUpdateTimestamp", profileEntry
.getLastUpdateTimestamp());
105 json
.writeObjectField("profile", profileEntry
.getProfile());
106 json
.writeEndObject();
108 json
.writeEndArray();