1 /*
2  * Copyright (C) 2020 Finn Herzfeld
3  *
4  * This program is free software: you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation, either version 3 of the License, or
7  * (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
16  */
17 
18 package io.finn.signald.storage;
19 
20 import com.fasterxml.jackson.annotation.JsonIgnore;
21 import io.finn.signald.db.Recipient;
22 import java.util.ArrayList;
23 import java.util.List;
24 import java.util.UUID;
25 import org.signal.zkgroup.profiles.ProfileKey;
26 import org.signal.zkgroup.profiles.ProfileKeyCredential;
27 import org.whispersystems.libsignal.util.guava.Optional;
28 import org.whispersystems.signalservice.api.push.SignalServiceAddress;
29 
30 public class ProfileCredentialStore {
31   private static boolean unsaved = false;
32   public List<ProfileAndCredentialEntry> profiles = new ArrayList<>();
33 
34   @JsonIgnore
getProfileKeyCredential(UUID uuid)35   public ProfileKeyCredential getProfileKeyCredential(UUID uuid) {
36     ProfileAndCredentialEntry entry = get(new SignalServiceAddress(uuid, Optional.absent()));
37     if (entry != null) {
38       return entry.getProfileKeyCredential();
39     }
40     return null;
41   }
42 
43   @JsonIgnore
get(Recipient recipient)44   public ProfileAndCredentialEntry get(Recipient recipient) {
45     SignalServiceAddress address = recipient.getAddress();
46     for (ProfileAndCredentialEntry entry : profiles) {
47       if (entry.getServiceAddress().matches(address)) {
48         return entry;
49       }
50     }
51     return null;
52   }
53   @JsonIgnore
get(SignalServiceAddress address)54   public ProfileAndCredentialEntry get(SignalServiceAddress address) {
55     for (ProfileAndCredentialEntry entry : profiles) {
56       if (entry.getServiceAddress() == null) {
57         continue;
58       }
59       if (entry.getServiceAddress().matches(address)) {
60         return entry;
61       }
62     }
63     return null;
64   }
65 
66   @JsonIgnore
isUnsaved()67   public boolean isUnsaved() {
68     return unsaved;
69   }
70 
markSaved()71   public void markSaved() { unsaved = false; }
72 
storeProfileKey(Recipient recipient, ProfileKey profileKey)73   public ProfileAndCredentialEntry storeProfileKey(Recipient recipient, ProfileKey profileKey) {
74     ProfileAndCredentialEntry newEntry = new ProfileAndCredentialEntry(recipient.getAddress(), profileKey, 0, null, null, ProfileAndCredentialEntry.UnidentifiedAccessMode.UNKNOWN);
75     for (int i = 0; i < profiles.size(); i++) {
76       if (profiles.get(i).getServiceAddress().matches(recipient.getAddress())) {
77         if (!profiles.get(i).getProfileKey().equals(profileKey)) {
78           profiles.set(i, newEntry);
79           unsaved = true;
80         }
81         return newEntry;
82       }
83     }
84     profiles.add(newEntry);
85     unsaved = true;
86     return newEntry;
87   }
88 
update(SignalServiceAddress address, ProfileKey profileKey, long now, SignalProfile profile, ProfileKeyCredential profileKeyCredential, ProfileAndCredentialEntry.UnidentifiedAccessMode unidentifiedAccessMode)89   public ProfileAndCredentialEntry update(SignalServiceAddress address, ProfileKey profileKey, long now, SignalProfile profile, ProfileKeyCredential profileKeyCredential,
90                                           ProfileAndCredentialEntry.UnidentifiedAccessMode unidentifiedAccessMode) {
91     ProfileAndCredentialEntry entry = new ProfileAndCredentialEntry(address, profileKey, now, profile, profileKeyCredential, unidentifiedAccessMode);
92     for (int i = 0; i < profiles.size(); i++) {
93       if (profiles.get(i).getServiceAddress().matches(address)) {
94         // TODO: announce profile change
95         profiles.set(i, entry);
96         unsaved = true;
97         return entry;
98       }
99     }
100     profiles.add(entry);
101     unsaved = true;
102     return entry;
103   }
104 }
105