]> nmode's Git Repositories - signal-cli/blob - src/main/java/org/asamk/signal/storage/profiles/ProfileStore.java
662d0161b1e85b675794461ff4d003f149873839
[signal-cli] / src / main / java / org / asamk / signal / storage / profiles / ProfileStore.java
1 package org.asamk.signal.storage.profiles;
2
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;
14
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;
20
21 import java.io.IOException;
22 import java.util.ArrayList;
23 import java.util.List;
24 import java.util.UUID;
25
26 public class ProfileStore {
27
28 private static final ObjectMapper jsonProcessor = new ObjectMapper();
29
30 @JsonProperty("profiles")
31 @JsonDeserialize(using = ProfileStoreDeserializer.class)
32 @JsonSerialize(using = ProfileStoreSerializer.class)
33 private final List<SignalProfileEntry> profiles = new ArrayList<>();
34
35 public SignalProfileEntry getProfile(SignalServiceAddress serviceAddress) {
36 for (SignalProfileEntry entry : profiles) {
37 if (entry.getServiceAddress().matches(serviceAddress)) {
38 return entry;
39 }
40 }
41 return null;
42 }
43
44 public ProfileKey getProfileKey(SignalServiceAddress serviceAddress) {
45 for (SignalProfileEntry entry : profiles) {
46 if (entry.getServiceAddress().matches(serviceAddress)) {
47 return entry.getProfileKey();
48 }
49 }
50 return null;
51 }
52
53 public void updateProfile(SignalServiceAddress serviceAddress, ProfileKey profileKey, long now, SignalProfile profile) {
54 SignalProfileEntry newEntry = new SignalProfileEntry(serviceAddress, profileKey, now, profile);
55 for (int i = 0; i < profiles.size(); i++) {
56 if (profiles.get(i).getServiceAddress().matches(serviceAddress)) {
57 profiles.set(i, newEntry);
58 return;
59 }
60 }
61
62 profiles.add(newEntry);
63 }
64
65 public void storeProfileKey(SignalServiceAddress serviceAddress, ProfileKey profileKey) {
66 SignalProfileEntry newEntry = new SignalProfileEntry(serviceAddress, profileKey, 0, null);
67 for (int i = 0; i < profiles.size(); i++) {
68 if (profiles.get(i).getServiceAddress().matches(serviceAddress)) {
69 if (!profiles.get(i).getProfileKey().equals(profileKey)) {
70 profiles.set(i, newEntry);
71 }
72 return;
73 }
74 }
75
76 profiles.add(newEntry);
77 }
78
79 public static class ProfileStoreDeserializer extends JsonDeserializer<List<SignalProfileEntry>> {
80
81 @Override
82 public List<SignalProfileEntry> deserialize(JsonParser jsonParser, DeserializationContext deserializationContext) throws IOException {
83 JsonNode node = jsonParser.getCodec().readTree(jsonParser);
84
85 List<SignalProfileEntry> addresses = new ArrayList<>();
86
87 if (node.isArray()) {
88 for (JsonNode entry : node) {
89 String name = entry.hasNonNull("name")
90 ? entry.get("name").asText()
91 : null;
92 UUID uuid = entry.hasNonNull("uuid")
93 ? UuidUtil.parseOrNull(entry.get("uuid").asText())
94 : null;
95 final SignalServiceAddress serviceAddress = new SignalServiceAddress(uuid, name);
96 ProfileKey profileKey = null;
97 try {
98 profileKey = new ProfileKey(Base64.decode(entry.get("profileKey").asText()));
99 } catch (InvalidInputException ignored) {
100 }
101 long lastUpdateTimestamp = entry.get("lastUpdateTimestamp").asLong();
102 SignalProfile profile = jsonProcessor.treeToValue(entry.get("profile"), SignalProfile.class);
103 addresses.add(new SignalProfileEntry(serviceAddress, profileKey, lastUpdateTimestamp, profile));
104 }
105 }
106
107 return addresses;
108 }
109 }
110
111 public static class ProfileStoreSerializer extends JsonSerializer<List<SignalProfileEntry>> {
112
113 @Override
114 public void serialize(List<SignalProfileEntry> profiles, JsonGenerator json, SerializerProvider serializerProvider) throws IOException {
115 json.writeStartArray();
116 for (SignalProfileEntry profileEntry : profiles) {
117 final SignalServiceAddress address = profileEntry.getServiceAddress();
118 json.writeStartObject();
119 if (address.getNumber().isPresent()) {
120 json.writeStringField("name", address.getNumber().get());
121 }
122 if (address.getUuid().isPresent()) {
123 json.writeStringField("uuid", address.getUuid().get().toString());
124 }
125 json.writeStringField("profileKey", Base64.encodeBytes(profileEntry.getProfileKey().serialize()));
126 json.writeNumberField("lastUpdateTimestamp", profileEntry.getLastUpdateTimestamp());
127 json.writeObjectField("profile", profileEntry.getProfile());
128 json.writeEndObject();
129 }
130 json.writeEndArray();
131 }
132 }
133 }