Line data Source code
1 : /*
2 : * Copyright (C) 2004-2024 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 : #ifdef HAVE_CONFIG_H
20 : #include "config.h"
21 : #endif
22 :
23 : #include "contact_list.h"
24 : #include "logger.h"
25 : #if HAVE_RINGNS
26 : #include "namedirectory.h"
27 : #endif
28 :
29 : #include <opendht/crypto.h>
30 : #include <optional>
31 : #include <functional>
32 : #include <map>
33 : #include <string>
34 : #include <filesystem>
35 :
36 : namespace dht {
37 : class DhtRunner;
38 : }
39 :
40 : namespace jami {
41 :
42 : using DeviceId = dht::PkId;
43 : struct AccountArchive;
44 :
45 : struct AccountInfo
46 : {
47 : dht::crypto::Identity identity;
48 : std::unique_ptr<ContactList> contacts;
49 : std::string accountId;
50 : std::string deviceId;
51 : std::shared_ptr<dht::crypto::PublicKey> devicePk;
52 : std::shared_ptr<dht::Value> announce;
53 : std::string ethAccount;
54 : std::string username;
55 : std::string photo;
56 : };
57 :
58 : template<typename To, typename From>
59 : std::unique_ptr<To>
60 783 : dynamic_unique_cast(std::unique_ptr<From>&& p)
61 : {
62 783 : if (auto cast = dynamic_cast<To*>(p.get())) {
63 783 : std::unique_ptr<To> result(cast);
64 783 : p.release();
65 783 : return result;
66 783 : }
67 0 : return {};
68 : }
69 :
70 : class AccountManager: public std::enable_shared_from_this<AccountManager>
71 : {
72 : public:
73 : using OnChangeCallback = ContactList::OnChangeCallback;
74 : using clock = std::chrono::system_clock;
75 : using time_point = clock::time_point;
76 : using OnNewDeviceCb = std::function<void(const std::shared_ptr<dht::crypto::Certificate>&)>;
77 : using OnDeviceAnnouncedCb = std::function<void()>;
78 :
79 799 : AccountManager(const std::filesystem::path& path, const std::string& nameServer)
80 1598 : : path_(path)
81 799 : , nameDir_(NameDirectory::instance(nameServer)) {};
82 :
83 : virtual ~AccountManager();
84 :
85 : constexpr static const char* const DHT_TYPE_NS = "cx.ring";
86 :
87 : // Auth
88 :
89 : enum class AuthError { UNKNOWN, INVALID_ARGUMENTS, SERVER_ERROR, NETWORK };
90 :
91 : using AuthSuccessCallback = std::function<void(const AccountInfo& info,
92 : const std::map<std::string, std::string>& config,
93 : std::string&& receipt,
94 : std::vector<uint8_t>&& receipt_signature)>;
95 :
96 : using AuthFailureCallback = std::function<void(AuthError error, const std::string& message)>;
97 : using DeviceSyncCallback = std::function<void(DeviceSync&& syncData)>;
98 : using CertRequest = std::future<std::unique_ptr<dht::crypto::CertificateRequest>>;
99 : using PrivateKey = std::shared_future<std::shared_ptr<dht::crypto::PrivateKey>>;
100 :
101 : CertRequest buildRequest(PrivateKey fDeviceKey);
102 :
103 : struct AccountCredentials
104 : {
105 : std::string scheme;
106 : std::string uri;
107 : std::string password_scheme;
108 : std::string password;
109 783 : virtual ~AccountCredentials() {};
110 : };
111 :
112 : virtual void initAuthentication(const std::string& accountId,
113 : PrivateKey request,
114 : std::string deviceName,
115 : std::unique_ptr<AccountCredentials> credentials,
116 : AuthSuccessCallback onSuccess,
117 : AuthFailureCallback onFailure,
118 : const OnChangeCallback& onChange)
119 : = 0;
120 :
121 : virtual bool changePassword(const std::string& password_old, const std::string& password_new) = 0;
122 :
123 : virtual void syncDevices() = 0;
124 : virtual void onSyncData(DeviceSync&& device, bool checkDevice = true);
125 :
126 0 : virtual bool isPasswordValid(const std::string& /*password*/) { return false; };
127 0 : virtual std::vector<uint8_t> getPasswordKey(const std::string& /*password*/) { return {}; };
128 :
129 : dht::crypto::Identity loadIdentity(const std::string& accountId,
130 : const std::string& crt_path,
131 : const std::string& key_path,
132 : const std::string& key_pwd) const;
133 :
134 : const AccountInfo* useIdentity(const std::string& accountId,
135 : const dht::crypto::Identity& id,
136 : const std::string& receipt,
137 : const std::vector<uint8_t>& receiptSignature,
138 : const std::string& username,
139 : const OnChangeCallback& onChange);
140 : Json::Value announceFromReceipt(const std::string& receipt);
141 :
142 698 : void setDht(const std::shared_ptr<dht::DhtRunner>& dht) { dht_ = dht; }
143 :
144 : virtual void startSync(const OnNewDeviceCb& cb, const OnDeviceAnnouncedCb& dcb, bool publishPresence = true);
145 :
146 77280 : const AccountInfo* getInfo() const { return info_.get(); }
147 :
148 : void reloadContacts();
149 :
150 : // Device management
151 :
152 : enum class AddDeviceResult {
153 : SUCCESS_SHOW_PIN = 0,
154 : ERROR_CREDENTIALS,
155 : ERROR_NETWORK,
156 : };
157 : using AddDeviceCallback = std::function<void(AddDeviceResult, std::string pin)>;
158 :
159 : enum class RevokeDeviceResult {
160 : SUCCESS = 0,
161 : ERROR_CREDENTIALS,
162 : ERROR_NETWORK,
163 : };
164 : using RevokeDeviceCallback = std::function<void(RevokeDeviceResult)>;
165 :
166 0 : virtual void addDevice(const std::string& /*password*/, AddDeviceCallback) {};
167 0 : virtual bool revokeDevice(const std::string& /*device*/,
168 : std::string_view /*scheme*/,
169 : const std::string& /*password*/,
170 : RevokeDeviceCallback)
171 : {
172 0 : return false;
173 : };
174 :
175 : const std::map<dht::PkId, KnownDevice>& getKnownDevices() const;
176 : bool foundAccountDevice(const std::shared_ptr<dht::crypto::Certificate>& crt,
177 : const std::string& name = {},
178 1221 : const time_point& last_sync = time_point::min());
179 : // bool removeAccountDevice(const dht::InfoHash& device);
180 : void setAccountDeviceName(/*const dht::InfoHash& device, */ const std::string& name);
181 : std::string getAccountDeviceName() const;
182 :
183 : void forEachDevice(const dht::InfoHash& to,
184 : std::function<void(const std::shared_ptr<dht::crypto::PublicKey>&)>&& op,
185 : std::function<void(bool)>&& end = {});
186 :
187 : using PeerCertificateCb = std::function<void(const std::shared_ptr<dht::crypto::Certificate>& crt,
188 : const dht::InfoHash& peer_account)>;
189 : void onPeerMessage(const dht::crypto::PublicKey& peer_device,
190 : bool allowPublic,
191 : PeerCertificateCb&& cb);
192 : bool onPeerCertificate(const std::shared_ptr<dht::crypto::Certificate>& crt,
193 : bool allowPublic,
194 : dht::InfoHash& account_id);
195 :
196 : /**
197 : * Inform that a potential peer device have been found.
198 : * Returns true only if the device certificate is a valid device certificate.
199 : * In that case (true is returned) the account_id parameter is set to the peer account ID.
200 : */
201 : static bool foundPeerDevice(const std::shared_ptr<dht::crypto::Certificate>& crt,
202 : dht::InfoHash& account_id);
203 :
204 : // Contact requests
205 :
206 : std::vector<std::map<std::string, std::string>> getTrustRequests() const;
207 : // Note: includeConversation used for compatibility test, do not use if not in test env.
208 : bool acceptTrustRequest(const std::string& from, bool includeConversation = true);
209 : bool discardTrustRequest(const std::string& from);
210 :
211 : void sendTrustRequest(const std::string& to,
212 : const std::string& convId,
213 : const std::vector<uint8_t>& payload);
214 : void sendTrustRequestConfirm(const dht::InfoHash& to,
215 : const std::string& conversationId); // TODO ideally no convId here
216 :
217 : // Contact
218 :
219 : /**
220 : * Add contact to the account contact list.
221 : * Set confirmed if we know the contact also added us.
222 : */
223 : bool addContact(const dht::InfoHash& uri,
224 : bool confirmed = false,
225 : const std::string& conversationId = "");
226 : void removeContact(const std::string& uri, bool banned = true);
227 : void removeContactConversation(const std::string& uri); // for non swarm contacts
228 : void updateContactConversation(const std::string& uri, const std::string& convId);
229 : std::vector<std::map<std::string, std::string>> getContacts(bool includeRemoved = false) const;
230 :
231 : /** Obtain details about one account contact in serializable form. */
232 : std::map<std::string, std::string> getContactDetails(const std::string& uri) const;
233 :
234 : virtual bool findCertificate(
235 : const dht::InfoHash& h,
236 : std::function<void(const std::shared_ptr<dht::crypto::Certificate>&)>&& cb = {});
237 :
238 : virtual bool findCertificate(
239 : const dht::PkId& h,
240 : std::function<void(const std::shared_ptr<dht::crypto::Certificate>&)>&& cb = {});
241 :
242 : bool setCertificateStatus(const std::string& cert_id, dhtnet::tls::TrustStore::PermissionStatus status);
243 : bool setCertificateStatus(const std::shared_ptr<crypto::Certificate>& cert,
244 : dhtnet::tls::TrustStore::PermissionStatus status,
245 : bool local = true);
246 : std::vector<std::string> getCertificatesByStatus(dhtnet::tls::TrustStore::PermissionStatus status);
247 : dhtnet::tls::TrustStore::PermissionStatus getCertificateStatus(const std::string& cert_id) const;
248 : bool isAllowed(const crypto::Certificate& crt, bool allowPublic = false);
249 :
250 : static std::shared_ptr<dht::Value> parseAnnounce(const std::string& announceBase64,
251 : const std::string& accountId,
252 : const std::string& deviceSha1);
253 :
254 : // Name resolver
255 : using LookupCallback = NameDirectory::LookupCallback;
256 : using SearchResult = NameDirectory::SearchResult;
257 : using SearchCallback = NameDirectory::SearchCallback;
258 : using RegistrationCallback = NameDirectory::RegistrationCallback;
259 : using SearchResponse = NameDirectory::Response;
260 :
261 : virtual void lookupUri(const std::string& name,
262 : const std::string& defaultServer,
263 : LookupCallback cb);
264 : virtual void lookupAddress(const std::string& address, LookupCallback cb);
265 0 : virtual bool searchUser(const std::string& /*query*/, SearchCallback /*cb*/) { return false; }
266 : virtual void registerName(const std::string& name,
267 : std::string_view scheme,
268 : const std::string& password,
269 : RegistrationCallback cb)
270 : = 0;
271 :
272 : dhtnet::tls::CertificateStore& certStore() const;
273 :
274 : protected:
275 : std::filesystem::path path_;
276 : OnChangeCallback onChange_;
277 : std::unique_ptr<AccountInfo> info_;
278 : std::string accountId_;
279 : std::shared_ptr<dht::DhtRunner> dht_;
280 : std::reference_wrapper<NameDirectory> nameDir_;
281 : };
282 :
283 : } // namespace jami
|