Line data Source code
1 : /*
2 : * Copyright (C) 2004-2026 Savoir-faire Linux Inc.
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 <https://www.gnu.org/licenses/>.
16 : */
17 : #pragma once
18 :
19 : #include "jami_contact.h"
20 :
21 : #include <dhtnet/certstore.h>
22 : #include <opendht/infohash.h>
23 : #include <opendht/crypto.h>
24 :
25 : #include <map>
26 : #include <mutex>
27 : #include <chrono>
28 :
29 : namespace jami {
30 :
31 : class ContactList
32 : {
33 : public:
34 : using clock = std::chrono::system_clock;
35 : using time_point = clock::time_point;
36 : using VerifyResult = dht::crypto::TrustList::VerifyResult;
37 :
38 : using OnContactAdded = std::function<void(const std::string&, bool)>;
39 : using OnContactRemoved = std::function<void(const std::string&, bool)>;
40 : using OnIncomingTrustRequest
41 : = std::function<
42 : void(const std::string&, const std::string&, const std::vector<uint8_t>&, TimePoint, TimePoint)>;
43 : using OnAcceptConversation = std::function<void(const std::string&, const std::string&)>;
44 : using OnConfirmation = std::function<void(const std::string&, const std::string&)>;
45 : using OnDevicesChanged = std::function<void(const std::map<dht::PkId, KnownDevice>&)>;
46 :
47 : struct OnChangeCallback
48 : {
49 : OnContactAdded contactAdded;
50 : OnContactRemoved contactRemoved;
51 : OnIncomingTrustRequest trustRequest;
52 : OnDevicesChanged devicesChanged;
53 : OnAcceptConversation acceptConversation;
54 : OnConfirmation onConfirmation;
55 : };
56 :
57 : ContactList(const std::string& accountId,
58 : const std::shared_ptr<crypto::Certificate>& cert,
59 : const std::filesystem::path& path,
60 : OnChangeCallback cb);
61 : ~ContactList();
62 :
63 10321 : const std::string& accountId() const { return accountId_; }
64 :
65 : void load();
66 : void save();
67 :
68 : /* Contacts */
69 : std::map<std::string, std::string> getContactDetails(const dht::InfoHash&) const;
70 : std::optional<Contact> getContactInfo(const dht::InfoHash&) const;
71 :
72 : bool removeContact(const dht::InfoHash&, bool ban);
73 : bool removeContactConversation(const dht::InfoHash&);
74 : bool addContact(const dht::InfoHash&, bool confirmed = false, const std::string& conversationId = "");
75 : bool updateConversation(const dht::InfoHash& h, const std::string& conversationId);
76 :
77 : bool setCertificateStatus(const std::string& cert_id, const dhtnet::tls::TrustStore::PermissionStatus status);
78 :
79 : bool setCertificateStatus(const std::shared_ptr<crypto::Certificate>& cert,
80 : dhtnet::tls::TrustStore::PermissionStatus status,
81 : bool local = true);
82 :
83 29341 : dhtnet::tls::TrustStore::PermissionStatus getCertificateStatus(const std::string& cert_id) const
84 : {
85 29341 : return trust_->getCertificateStatus(cert_id);
86 : }
87 :
88 0 : std::vector<std::string> getCertificatesByStatus(dhtnet::tls::TrustStore::PermissionStatus status) const
89 : {
90 0 : return trust_->getCertificatesByStatus(status);
91 : }
92 :
93 1749 : bool isAllowed(const crypto::Certificate& crt, bool allowPublic) { return trust_->isAllowed(crt, allowPublic); }
94 :
95 2014 : VerifyResult isValidAccountDevice(const crypto::Certificate& crt) const { return accountTrust_.verify(crt); }
96 :
97 : std::map<dht::InfoHash, Contact> getContacts() const;
98 : void setContacts(const std::map<dht::InfoHash, Contact>&);
99 : void updateContact(const dht::InfoHash&, const Contact&, bool emit = true);
100 :
101 : static std::map<dht::InfoHash, Contact> contactsFromPath(const std::filesystem::path& path);
102 :
103 : /** Should be called only after updateContact */
104 : void saveContacts() const;
105 :
106 : const std::filesystem::path& path() const { return path_; }
107 :
108 : /* Contact requests */
109 :
110 : /** Inform of a new contact request. Returns true if the request should be immediatly accepted
111 : * (already a contact). invited is the sender-embedded invite timestamp ({} if not
112 : * present/known). */
113 : bool onTrustRequest(const dht::InfoHash& peer_account,
114 : const std::shared_ptr<dht::crypto::PublicKey>& peer_device,
115 : TimePoint received,
116 : bool confirm,
117 : const std::string& conversationId,
118 : std::vector<uint8_t>&& payload,
119 : TimePoint invited = {});
120 : std::vector<std::map<std::string, std::string>> getTrustRequests() const;
121 : std::map<std::string, std::string> getTrustRequest(const dht::InfoHash& from) const;
122 : void acceptConversation(const std::string& convId,
123 : const std::string& deviceId = ""); // ToDO this is a bit dirty imho
124 : bool acceptTrustRequest(const dht::InfoHash& from);
125 : bool discardTrustRequest(const dht::InfoHash& from);
126 : bool discardTrustRequest(const dht::InfoHash& from, const std::string& conversationId, TimePoint declined);
127 :
128 : /* Devices */
129 : std::map<dht::PkId, KnownDevice> getKnownDevices() const;
130 : void foundAccountDevice(const dht::PkId& device,
131 : const std::string& name = {},
132 2000 : const time_point& last_sync = time_point::min());
133 : bool foundAccountDevice(const std::shared_ptr<dht::crypto::Certificate>& crt,
134 : const std::string& name = {},
135 3 : const time_point& last_sync = time_point::min(),
136 : bool notify = true);
137 : bool removeAccountDevice(const dht::PkId& device);
138 : void setAccountDeviceName(const dht::PkId& device, const std::string& name);
139 : std::string getAccountDeviceName(const dht::PkId& device) const;
140 :
141 : DeviceSync getSyncData() const;
142 : bool recordDeviceSync(const dht::PkId& device, const time_point& receivedAt);
143 :
144 : private:
145 : const std::string accountId_;
146 : const std::filesystem::path path_;
147 : mutable std::mutex mutex_;
148 : std::map<dht::InfoHash, Contact> contacts_;
149 : std::map<dht::InfoHash, TrustRequest> trustRequests_;
150 : std::map<dht::InfoHash, KnownDevice> knownDevicesLegacy_;
151 :
152 : mutable std::mutex devicesMutex_;
153 : std::map<dht::PkId, KnownDevice> knownDevices_;
154 :
155 : // Trust store with account main certificate as the only CA
156 : dht::crypto::TrustList accountTrust_;
157 : // Trust store for to match peer certificates
158 : std::unique_ptr<dhtnet::tls::TrustStore> trust_;
159 : std::string accountUri_;
160 :
161 : OnChangeCallback callbacks_;
162 :
163 : void loadContacts();
164 : void loadTrustRequests();
165 :
166 : void loadKnownDevices();
167 : void saveKnownDevices() const;
168 :
169 : /** Should be called only after onTrustRequest */
170 : void saveTrustRequests() const;
171 : };
172 :
173 : } // namespace jami
|