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 : #include "def.h"
20 : #ifdef HAVE_CONFIG_H
21 : #include "config.h"
22 : #endif
23 :
24 : #include "sip/sipaccountbase.h"
25 : #include "jami/datatransfer_interface.h"
26 : #include "jamidht/conversation.h"
27 : #include "data_transfer.h"
28 : #include "uri.h"
29 : #include "jamiaccount_config.h"
30 :
31 : #include "noncopyable.h"
32 : #include "ring_types.h" // enable_if_base_of
33 : #include "scheduled_executor.h"
34 : #include "gitserver.h"
35 : #include "channel_handler.h"
36 : #include "conversation_module.h"
37 : #include "sync_module.h"
38 : #include "conversationrepository.h"
39 :
40 : #include <dhtnet/diffie-hellman.h>
41 : #include <dhtnet/tls_session.h>
42 : #include <dhtnet/multiplexed_socket.h>
43 : #include <dhtnet/certstore.h>
44 : #include <dhtnet/connectionmanager.h>
45 : #include <dhtnet/upnp/mapping.h>
46 : #include <dhtnet/ip_utils.h>
47 : #include <dhtnet/fileutils.h>
48 :
49 : #include <opendht/dhtrunner.h>
50 : #include <opendht/default_types.h>
51 :
52 : #include <pjsip/sip_types.h>
53 : #include <json/json.h>
54 :
55 : #include <chrono>
56 : #include <functional>
57 : #include <future>
58 : #include <list>
59 : #include <map>
60 : #include <optional>
61 : #include <vector>
62 : #include <filesystem>
63 :
64 : #if HAVE_RINGNS
65 : #include "namedirectory.h"
66 : #endif
67 :
68 : namespace dev {
69 : template<unsigned N>
70 : class FixedHash;
71 : using h160 = FixedHash<20>;
72 : using Address = h160;
73 : } // namespace dev
74 :
75 : namespace jami {
76 :
77 : class IceTransport;
78 : struct Contact;
79 : struct AccountArchive;
80 : class DhtPeerConnector;
81 : class AccountManager;
82 : struct AccountInfo;
83 : class SipTransport;
84 : class ChanneledOutgoingTransfer;
85 : class SyncModule;
86 : struct TextMessageCtx;
87 :
88 : using SipConnectionKey = std::pair<std::string /* uri */, DeviceId>;
89 :
90 : static constexpr const char MIME_TYPE_IM_COMPOSING[] {"application/im-iscomposing+xml"};
91 :
92 : /**
93 : * @brief Ring Account is build on top of SIPAccountBase and uses DHT to handle call connectivity.
94 : */
95 : class JamiAccount : public SIPAccountBase
96 : {
97 : public:
98 : constexpr static auto ACCOUNT_TYPE = ACCOUNT_TYPE_JAMI;
99 : constexpr static const std::pair<uint16_t, uint16_t> DHT_PORT_RANGE {4000, 8888};
100 : constexpr static int ICE_STREAMS_COUNT {1};
101 : constexpr static int ICE_COMP_COUNT_PER_STREAM {1};
102 :
103 3188 : std::string_view getAccountType() const override { return ACCOUNT_TYPE; }
104 :
105 5800 : std::shared_ptr<JamiAccount> shared()
106 : {
107 5800 : return std::static_pointer_cast<JamiAccount>(shared_from_this());
108 : }
109 : std::shared_ptr<JamiAccount const> shared() const
110 : {
111 : return std::static_pointer_cast<JamiAccount const>(shared_from_this());
112 : }
113 62849 : std::weak_ptr<JamiAccount> weak()
114 : {
115 62849 : return std::static_pointer_cast<JamiAccount>(shared_from_this());
116 : }
117 : std::weak_ptr<JamiAccount const> weak() const
118 : {
119 : return std::static_pointer_cast<JamiAccount const>(shared_from_this());
120 : }
121 :
122 3834 : const std::filesystem::path& getPath() const { return idPath_; }
123 :
124 22407 : const JamiAccountConfig& config() const
125 : {
126 22407 : return *static_cast<const JamiAccountConfig*>(&Account::config());
127 : }
128 :
129 799 : JamiAccountConfig::Credentials consumeConfigCredentials()
130 : {
131 799 : auto conf = static_cast<JamiAccountConfig*>(config_.get());
132 799 : return std::move(conf->credentials);
133 : }
134 :
135 : void loadConfig() override;
136 :
137 : /**
138 : * Constructor
139 : * @param accountID The account identifier
140 : */
141 : JamiAccount(const std::string& accountId);
142 :
143 : ~JamiAccount() noexcept;
144 :
145 : /**
146 : * Retrieve volatile details such as recent registration errors
147 : * @return std::map< std::string, std::string > The account volatile details
148 : */
149 : virtual std::map<std::string, std::string> getVolatileAccountDetails() const override;
150 :
151 779 : std::unique_ptr<AccountConfig> buildConfig() const override
152 : {
153 779 : return std::make_unique<JamiAccountConfig>(getAccountID(), idPath_);
154 : }
155 :
156 : /**
157 : * Adds an account id to the list of accounts to track on the DHT for
158 : * buddy presence.
159 : *
160 : * @param buddy_id The buddy id.
161 : */
162 : void trackBuddyPresence(const std::string& buddy_id, bool track);
163 :
164 : /**
165 : * Tells for each tracked account id if it has been seen online so far
166 : * in the last DeviceAnnouncement::TYPE.expiration minutes.
167 : *
168 : * @return map of buddy_uri to bool (online or not)
169 : */
170 : std::map<std::string, bool> getTrackedBuddyPresence() const;
171 :
172 : void setActiveCodecs(const std::vector<unsigned>& list) override;
173 :
174 : /**
175 : * Connect to the DHT.
176 : */
177 : void doRegister() override;
178 :
179 : /**
180 : * Disconnect from the DHT.
181 : */
182 : void doUnregister(std::function<void(bool)> cb = {}) override;
183 :
184 : /**
185 : * Set the registration state of the specified link
186 : * @param state The registration state of underlying VoIPLink
187 : */
188 : void setRegistrationState(RegistrationState state,
189 : int detail_code = 0,
190 : const std::string& detail_str = {}) override;
191 :
192 : /**
193 : * @return pj_str_t "From" uri based on account information.
194 : * From RFC3261: "The To header field first and foremost specifies the desired
195 : * logical" recipient of the request, or the address-of-record of the
196 : * user or resource that is the target of this request. [...] As such, it is
197 : * very important that the From URI not contain IP addresses or the FQDN
198 : * of the host on which the UA is running, since these are not logical
199 : * names."
200 : */
201 : std::string getFromUri() const override;
202 :
203 : /**
204 : * This method adds the correct scheme, hostname and append
205 : * the ;transport= parameter at the end of the uri, in accordance with RFC3261.
206 : * It is expected that "port" is present in the internal hostname_.
207 : *
208 : * @return pj_str_t "To" uri based on @param username
209 : * @param username A string formatted as : "username"
210 : */
211 : std::string getToUri(const std::string& username) const override;
212 :
213 : /**
214 : * In the current version, "srv" uri is obtained in the preformated
215 : * way: hostname:port. This method adds the correct scheme and append
216 : * the ;transport= parameter at the end of the uri, in accordance with RFC3261.
217 : *
218 : * @return pj_str_t "server" uri based on @param hostPort
219 : * @param hostPort A string formatted as : "hostname:port"
220 : */
221 : std::string getServerUri() const { return ""; };
222 :
223 : void setIsComposing(const std::string& conversationUri, bool isWriting) override;
224 :
225 : bool setMessageDisplayed(const std::string& conversationUri,
226 : const std::string& messageId,
227 : int status) override;
228 :
229 : /**
230 : * Get the contact header for
231 : * @return The contact header based on account information
232 : */
233 : std::string getContactHeader(const std::shared_ptr<SipTransport>& sipTransport);
234 :
235 : /* Returns true if the username and/or hostname match this account */
236 : MatchRank matches(std::string_view username, std::string_view hostname) const override;
237 :
238 : /**
239 : * Create outgoing SIPCall.
240 : * @note Accepts several urls:
241 : * + jami:uri for calling someone
242 : * + swarm:id for calling a group (will host or join if an active call is detected)
243 : * + rdv:id/uri/device/confId to join a specific conference hosted on (uri, device)
244 : * @param[in] toUrl The address to call
245 : * @param[in] mediaList list of medias
246 : * @return A shared pointer on the created call.
247 : */
248 : std::shared_ptr<Call> newOutgoingCall(std::string_view toUrl,
249 : const std::vector<libjami::MediaMap>& mediaList) override;
250 :
251 : /**
252 : * Create incoming SIPCall.
253 : * @param[in] from The origin of the call
254 : * @param mediaList A list of media
255 : * @param sipTr: SIP Transport
256 : * @return A shared pointer on the created call.
257 : */
258 : std::shared_ptr<SIPCall> newIncomingCall(
259 : const std::string& from,
260 : const std::vector<libjami::MediaMap>& mediaList,
261 : const std::shared_ptr<SipTransport>& sipTr = {}) override;
262 :
263 : void onTextMessage(const std::string& id,
264 : const std::string& from,
265 : const std::string& deviceId,
266 : const std::map<std::string, std::string>& payloads) override;
267 : void loadConversation(const std::string& convId);
268 :
269 0 : virtual bool isTlsEnabled() const override { return true; }
270 453 : bool isSrtpEnabled() const override { return true; }
271 :
272 0 : virtual bool getSrtpFallback() const override { return false; }
273 :
274 : bool setCertificateStatus(const std::string& cert_id,
275 : dhtnet::tls::TrustStore::PermissionStatus status);
276 : bool setCertificateStatus(const std::shared_ptr<crypto::Certificate>& cert,
277 : dhtnet::tls::TrustStore::PermissionStatus status,
278 : bool local = true);
279 : std::vector<std::string> getCertificatesByStatus(
280 : dhtnet::tls::TrustStore::PermissionStatus status);
281 :
282 : bool findCertificate(const std::string& id);
283 : bool findCertificate(
284 : const dht::InfoHash& h,
285 : std::function<void(const std::shared_ptr<dht::crypto::Certificate>&)>&& cb = {});
286 : bool findCertificate(
287 : const dht::PkId& h,
288 : std::function<void(const std::shared_ptr<dht::crypto::Certificate>&)>&& cb = {});
289 :
290 : /* contact requests */
291 : std::vector<std::map<std::string, std::string>> getTrustRequests() const;
292 : // Note: includeConversation used for compatibility test. Do not change
293 : bool acceptTrustRequest(const std::string& from, bool includeConversation = true);
294 : bool discardTrustRequest(const std::string& from);
295 : void declineConversationRequest(const std::string& conversationId);
296 :
297 : /**
298 : * Add contact to the account contact list.
299 : * Set confirmed if we know the contact also added us.
300 : */
301 : void addContact(const std::string& uri, bool confirmed = false);
302 : void removeContact(const std::string& uri, bool banned = true);
303 : std::vector<std::map<std::string, std::string>> getContacts(bool includeRemoved = false) const;
304 :
305 : ///
306 : /// Obtain details about one account contact in serializable form.
307 : ///
308 : std::map<std::string, std::string> getContactDetails(const std::string& uri) const;
309 :
310 : void sendTrustRequest(const std::string& to, const std::vector<uint8_t>& payload);
311 : void sendMessage(const std::string& to,
312 : const std::string& deviceId,
313 : const std::map<std::string, std::string>& payloads,
314 : uint64_t id,
315 : bool retryOnTimeout = true,
316 : bool onlyConnected = false) override;
317 :
318 : uint64_t sendTextMessage(const std::string& to,
319 : const std::string& deviceId,
320 : const std::map<std::string, std::string>& payloads,
321 : uint64_t refreshToken = 0,
322 : bool onlyConnected = false) override;
323 : void sendInstantMessage(const std::string& convId,
324 : const std::map<std::string, std::string>& msg);
325 :
326 : /**
327 : * Create and return ICE options.
328 : */
329 : dhtnet::IceTransportOptions getIceOptions() const noexcept override;
330 : void getIceOptions(std::function<void(dhtnet::IceTransportOptions&&)> cb) const noexcept;
331 : dhtnet::IpAddr getPublishedIpAddress(uint16_t family = PF_UNSPEC) const override;
332 :
333 : /* Devices */
334 : void addDevice(const std::string& password);
335 : /**
336 : * Export the archive to a file
337 : * @param destinationPath
338 : * @param (optional) password, if not provided, will update the contacts only if the archive
339 : * doesn't have a password
340 : * @return if the archive was exported
341 : */
342 : bool exportArchive(const std::string& destinationPath,
343 : std::string_view scheme = {},
344 : const std::string& password = {});
345 : bool revokeDevice(const std::string& device,
346 : std::string_view scheme = {},
347 : const std::string& password = {});
348 : std::map<std::string, std::string> getKnownDevices() const;
349 :
350 : bool isPasswordValid(const std::string& password);
351 : std::vector<uint8_t> getPasswordKey(const std::string& password);
352 :
353 : bool changeArchivePassword(const std::string& password_old, const std::string& password_new);
354 :
355 : void connectivityChanged() override;
356 :
357 : // overloaded methods
358 : void flush() override;
359 :
360 : #if HAVE_RINGNS
361 : void lookupName(const std::string& name);
362 : void lookupAddress(const std::string& address);
363 : void registerName(const std::string& name,
364 : const std::string& scheme,
365 : const std::string& password);
366 : #endif
367 : bool searchUser(const std::string& nameQuery);
368 :
369 : /// \return true if the given DHT message identifier has been treated
370 : /// \note if message has not been treated yet this method store this id and returns true at
371 : /// further calls
372 : bool isMessageTreated(dht::Value::Id id);
373 :
374 682 : std::shared_ptr<dht::DhtRunner> dht() { return dht_; }
375 :
376 2145 : const dht::crypto::Identity& identity() const { return id_; }
377 :
378 : void forEachDevice(const dht::InfoHash& to,
379 : std::function<void(const std::shared_ptr<dht::crypto::PublicKey>&)>&& op,
380 : std::function<void(bool)>&& end = {});
381 :
382 : bool setPushNotificationToken(const std::string& pushDeviceToken = "") override;
383 : bool setPushNotificationTopic(const std::string& topic) override;
384 : bool setPushNotificationConfig(const std::map<std::string, std::string>& data) override;
385 :
386 : /**
387 : * To be called by clients with relevant data when a push notification is received.
388 : */
389 : void pushNotificationReceived(const std::string& from,
390 : const std::map<std::string, std::string>& data);
391 :
392 : std::string getUserUri() const override;
393 :
394 : /**
395 : * Get last messages (should be used to retrieve messages when launching the client)
396 : * @param base_timestamp
397 : */
398 : std::vector<libjami::Message> getLastMessages(const uint64_t& base_timestamp) override;
399 :
400 : /**
401 : * Start Publish the Jami Account onto the Network
402 : */
403 : void startAccountPublish();
404 :
405 : /**
406 : * Start Discovery the Jami Account from the Network
407 : */
408 : void startAccountDiscovery();
409 :
410 : void saveConfig() const override;
411 :
412 791 : inline void editConfig(std::function<void(JamiAccountConfig& conf)>&& edit)
413 : {
414 791 : Account::editConfig(
415 791 : [&](AccountConfig& conf) { edit(*static_cast<JamiAccountConfig*>(&conf)); });
416 791 : }
417 :
418 : /**
419 : * Get current discovered peers account id and display name
420 : */
421 : std::map<std::string, std::string> getNearbyPeers() const override;
422 :
423 : std::map<std::string, std::string> getProfileVcard() const;
424 : void sendProfileToPeers();
425 : void updateProfile(const std::string& displayName, const std::filesystem::path& avatarPath);
426 :
427 : #ifdef LIBJAMI_TESTABLE
428 1 : dhtnet::ConnectionManager& connectionManager() { return *connectionManager_; }
429 :
430 : /**
431 : * Only used for tests, disable sha3sum verification for transfers.
432 : * @param newValue
433 : */
434 : void noSha3sumVerification(bool newValue);
435 :
436 2 : void publishPresence(bool newValue) { publishPresence_ = newValue; }
437 : #endif
438 :
439 : /**
440 : * This should be called before flushing the account.
441 : * ConnectionManager needs the account to exists
442 : */
443 : void shutdownConnections();
444 :
445 : std::string_view currentDeviceId() const;
446 :
447 : // Received a new commit notification
448 :
449 : bool handleMessage(const std::string& from,
450 : const std::pair<std::string, std::string>& message) override;
451 :
452 : void monitor();
453 : // conversationId optional
454 : std::vector<std::map<std::string, std::string>> getConnectionList(
455 : const std::string& conversationId = "");
456 : std::vector<std::map<std::string, std::string>> getChannelList(const std::string& connectionId);
457 :
458 : // File transfer
459 : void sendFile(const std::string& conversationId,
460 : const std::filesystem::path& path,
461 : const std::string& name,
462 : const std::string& replyTo);
463 :
464 : void transferFile(const std::string& conversationId,
465 : const std::string& path,
466 : const std::string& deviceId,
467 : const std::string& fileId,
468 : const std::string& interactionId,
469 : size_t start = 0,
470 : size_t end = 0,
471 : const std::string& sha3Sum = "",
472 : uint64_t lastWriteTime = 0,
473 : std::function<void()> onFinished = {});
474 :
475 : void askForFileChannel(const std::string& conversationId,
476 : const std::string& deviceId,
477 : const std::string& interactionId,
478 : const std::string& fileId,
479 : size_t start = 0,
480 : size_t end = 0);
481 :
482 : void askForProfile(const std::string& conversationId,
483 : const std::string& deviceId,
484 : const std::string& memberUri);
485 :
486 : /**
487 : * Retrieve linked transfer manager
488 : * @param id conversationId or empty for fallback
489 : * @return linked transfer manager
490 : */
491 : std::shared_ptr<TransferManager> dataTransfer(const std::string& id = "");
492 :
493 : /**
494 : * Used to get the instance of the ConversationModule class which is
495 : * responsible for managing conversations and messages between users.
496 : * @param noCreate whether or not to create a new instance
497 : * @return conversationModule instance
498 : */
499 : ConversationModule* convModule(bool noCreation = false);
500 : SyncModule* syncModule();
501 :
502 : /**
503 : * Check (via the cache) if we need to send our profile to a specific device
504 : * @param peerUri Uri that will receive the profile
505 : * @param deviceId Device that will receive the profile
506 : * @param sha3Sum SHA3 hash of the profile
507 : */
508 : // Note: when swarm will be merged, this can be moved in transferManager
509 : bool needToSendProfile(const std::string& peerUri,
510 : const std::string& deviceId,
511 : const std::string& sha3Sum);
512 : /**
513 : * Send Profile via cached SIP connection
514 : * @param convId Conversation's identifier (can be empty for self profile on sync)
515 : * @param peerUri Uri that will receive the profile
516 : * @param deviceId Device that will receive the profile
517 : */
518 : void sendProfile(const std::string& convId,
519 : const std::string& peerUri,
520 : const std::string& deviceId);
521 : /**
522 : * Send profile via cached SIP connection
523 : * @param peerUri Uri that will receive the profile
524 : * @param deviceId Device that will receive the profile
525 : */
526 : void sendProfile(const std::string& peerUri, const std::string& deviceId);
527 : /**
528 : * Clear sent profiles (because of a removed contact or new trust request)
529 : * @param peerUri Uri used to clear cache
530 : */
531 : void clearProfileCache(const std::string& peerUri);
532 :
533 : std::filesystem::path profilePath() const;
534 :
535 50512 : const std::shared_ptr<AccountManager>& accountManager() { return accountManager_; }
536 :
537 : bool sha3SumVerify() const;
538 :
539 : /**
540 : * Change certificate's validity period
541 : * @param pwd Password for the archive
542 : * @param id Certificate to update ({} for updating the whole chain)
543 : * @param validity New validity
544 : * @note forceReloadAccount may be necessary to retrigger the migration
545 : */
546 : bool setValidity(std::string_view scheme,
547 : const std::string& pwd,
548 : const dht::InfoHash& id,
549 : int64_t validity);
550 : /**
551 : * Try to reload the account to force the identity to be updated
552 : */
553 : void forceReloadAccount();
554 :
555 : void reloadContacts();
556 :
557 : /**
558 : * Make sure appdata/contacts.yml contains correct information
559 : * @param removedConv The current removed conversations
560 : */
561 : void unlinkConversations(const std::set<std::string>& removedConv);
562 :
563 : bool isValidAccountDevice(const dht::crypto::Certificate& cert) const;
564 :
565 : /**
566 : * Join incoming call to hosted conference
567 : * @param callId The call to join
568 : * @param destination conversation/uri/device/confId to join
569 : */
570 : void handleIncomingConversationCall(const std::string& callId, const std::string& destination);
571 :
572 : /**
573 : * The DRT component is composed on some special nodes, that are usually present but not
574 : * connected. This kind of node corresponds to devices with push notifications & proxy and are
575 : * stored in the mobile nodes
576 : */
577 385 : bool isMobile() const { return config().proxyEnabled and not config().deviceKey.empty(); }
578 :
579 : #ifdef LIBJAMI_TESTABLE
580 1 : std::map<Uri::Scheme, std::unique_ptr<ChannelHandlerInterface>>& channelHandlers()
581 : {
582 1 : return channelHandlers_;
583 : };
584 : #endif
585 :
586 45930 : dhtnet::tls::CertificateStore& certStore() const { return *certStore_; }
587 : /**
588 : * Check if a Device is connected
589 : * @param deviceId
590 : * @return true if connected
591 : */
592 : bool isConnectedWith(const DeviceId& deviceId) const;
593 :
594 : /**
595 : * Send a presence note
596 : * @param note
597 : */
598 : void sendPresenceNote(const std::string& note);
599 :
600 : private:
601 : NON_COPYABLE(JamiAccount);
602 :
603 : using clock = std::chrono::system_clock;
604 : using time_point = clock::time_point;
605 :
606 : /**
607 : * Private structures
608 : */
609 : struct PendingCall;
610 : struct PendingMessage;
611 : struct BuddyInfo;
612 : struct DiscoveredPeer;
613 :
614 0 : inline std::string getProxyConfigKey() const
615 : {
616 0 : const auto& conf = config();
617 0 : return dht::InfoHash::get(conf.proxyServer + conf.proxyListUrl).toString();
618 : }
619 :
620 : /**
621 : * Compute archive encryption key and DHT storage location from password and PIN.
622 : */
623 : static std::pair<std::vector<uint8_t>, dht::InfoHash> computeKeys(const std::string& password,
624 : const std::string& pin,
625 : bool previous = false);
626 :
627 : void trackPresence(const dht::InfoHash& h, BuddyInfo& buddy);
628 :
629 : void doRegister_();
630 :
631 784 : const dht::ValueType USER_PROFILE_TYPE = {9, "User profile", std::chrono::hours(24 * 7)};
632 :
633 : void startOutgoingCall(const std::shared_ptr<SIPCall>& call, const std::string& toUri);
634 :
635 : void onConnectedOutgoingCall(const std::shared_ptr<SIPCall>& call,
636 : const std::string& to_id,
637 : dhtnet::IpAddr target);
638 :
639 : /**
640 : * Start a SIP Call
641 : * @param call The current call
642 : * @return true if all is correct
643 : */
644 : bool SIPStartCall(SIPCall& call, const dhtnet::IpAddr& target);
645 :
646 : /**
647 : * Update tracking info when buddy appears offline.
648 : */
649 : void onTrackedBuddyOffline(const dht::InfoHash&);
650 :
651 : /**
652 : * Update tracking info when buddy appears offline.
653 : */
654 : void onTrackedBuddyOnline(const dht::InfoHash&);
655 :
656 : /**
657 : * Maps require port via UPnP and other async ops
658 : */
659 : void registerAsyncOps();
660 : /**
661 : * Add port mapping callback function.
662 : */
663 : void onPortMappingAdded(uint16_t port_used, bool success);
664 : void forEachPendingCall(const DeviceId& deviceId,
665 : const std::function<void(const std::shared_ptr<SIPCall>&)>& cb);
666 :
667 : void loadAccountFromDHT(const std::string& archive_password, const std::string& archive_pin);
668 : void loadAccount(const std::string& archive_password_scheme = {},
669 : const std::string& archive_password = {},
670 : const std::string& archive_pin = {},
671 : const std::string& archive_path = {});
672 :
673 : std::vector<std::string> loadBootstrap() const;
674 :
675 : static std::pair<std::string, std::string> saveIdentity(const dht::crypto::Identity id,
676 : const std::filesystem::path& path,
677 : const std::string& name);
678 :
679 : void replyToIncomingIceMsg(const std::shared_ptr<SIPCall>&,
680 : const std::shared_ptr<IceTransport>&,
681 : const std::shared_ptr<IceTransport>&,
682 : const dht::IceCandidates&,
683 : const std::shared_ptr<dht::crypto::Certificate>& from_cert,
684 : const dht::InfoHash& from);
685 :
686 : void loadCachedUrl(const std::string& url,
687 : const std::filesystem::path& cachePath,
688 : const std::chrono::seconds& cacheDuration,
689 : std::function<void(const dht::http::Response& response)>);
690 :
691 : std::string getDhtProxyServer(const std::string& serverList);
692 : void loadCachedProxyServer(std::function<void(const std::string&)> cb);
693 :
694 : /**
695 : * The TLS settings, used only if tls is chosen as a sip transport.
696 : */
697 : void generateDhParams();
698 :
699 : void newOutgoingCallHelper(const std::shared_ptr<SIPCall>& call, const Uri& uri);
700 : std::shared_ptr<SIPCall> newSwarmOutgoingCallHelper(
701 : const Uri& uri, const std::vector<libjami::MediaMap>& mediaList);
702 : std::shared_ptr<SIPCall> createSubCall(const std::shared_ptr<SIPCall>& mainCall);
703 :
704 : std::filesystem::path idPath_ {};
705 : std::filesystem::path cachePath_ {};
706 : std::filesystem::path dataPath_ {};
707 :
708 : #if HAVE_RINGNS
709 : mutable std::mutex registeredNameMutex_;
710 : std::string registeredName_;
711 :
712 696 : bool setRegisteredName(const std::string& name)
713 : {
714 696 : std::lock_guard<std::mutex> lock(registeredNameMutex_);
715 696 : if (registeredName_ != name) {
716 1 : registeredName_ = name;
717 1 : return true;
718 : }
719 695 : return false;
720 696 : }
721 4611 : std::string getRegisteredName() const
722 : {
723 4611 : std::lock_guard<std::mutex> lock(registeredNameMutex_);
724 9222 : return registeredName_;
725 4611 : }
726 : #endif
727 : std::shared_ptr<dht::Logger> logger_;
728 : std::shared_ptr<dhtnet::tls::CertificateStore> certStore_;
729 :
730 : std::shared_ptr<dht::DhtRunner> dht_ {};
731 : std::shared_ptr<AccountManager> accountManager_;
732 : dht::crypto::Identity id_ {};
733 :
734 : mutable std::mutex messageMutex_ {};
735 : std::map<dht::Value::Id, PendingMessage> sentMessages_;
736 : dhtnet::fileutils::IdList treatedMessages_;
737 :
738 : /* tracked buddies presence */
739 : mutable std::mutex buddyInfoMtx;
740 : std::map<dht::InfoHash, BuddyInfo> trackedBuddies_;
741 :
742 : mutable std::mutex dhtValuesMtx_;
743 :
744 : std::atomic_int syncCnt_ {0};
745 :
746 : /**
747 : * DHT port actually used.
748 : * This holds the actual DHT port, which might different from the port
749 : * set in the configuration. This can be the case if UPnP is used.
750 : */
751 700 : in_port_t dhtPortUsed()
752 : {
753 700 : return (upnpCtrl_ and dhtUpnpMapping_.isValid()) ? dhtUpnpMapping_.getExternalPort()
754 700 : : config().dhtPort;
755 : }
756 :
757 : /* Current UPNP mapping */
758 : dhtnet::upnp::Mapping dhtUpnpMapping_ {dhtnet::upnp::PortType::UDP};
759 :
760 : /**
761 : * Proxy
762 : */
763 : std::string proxyServerCached_ {};
764 :
765 : /**
766 : * Optional: via_addr construct from received parameters
767 : */
768 : pjsip_host_port via_addr_ {};
769 :
770 : pjsip_transport* via_tp_ {nullptr};
771 :
772 : mutable std::mutex connManagerMtx_ {};
773 : std::unique_ptr<dhtnet::ConnectionManager> connectionManager_;
774 :
775 : virtual void updateUpnpController() override;
776 :
777 : std::mutex discoveryMapMtx_;
778 : std::shared_ptr<dht::PeerDiscovery> peerDiscovery_;
779 : std::map<dht::InfoHash, DiscoveredPeer> discoveredPeers_;
780 : std::map<std::string, std::string> discoveredPeerMap_;
781 :
782 : std::set<std::shared_ptr<dht::http::Request>> requests_;
783 :
784 : mutable std::mutex sipConnsMtx_ {};
785 : struct SipConnection
786 : {
787 : std::shared_ptr<SipTransport> transport;
788 : // Needs to keep track of that channel to access underlying ICE
789 : // information, as the SipTransport use a generic transport
790 : std::shared_ptr<dhtnet::ChannelSocket> channel;
791 : };
792 : // NOTE: here we use a vector to avoid race conditions. In fact the contact
793 : // can ask for a SIP channel when we are creating a new SIP Channel with this
794 : // peer too.
795 : std::map<SipConnectionKey, std::vector<SipConnection>> sipConns_;
796 :
797 : std::mutex pendingCallsMutex_;
798 : std::map<DeviceId, std::vector<std::shared_ptr<SIPCall>>> pendingCalls_;
799 :
800 : std::mutex onConnectionClosedMtx_ {};
801 : std::map<DeviceId, std::function<void(const DeviceId&, bool)>> onConnectionClosed_ {};
802 : /**
803 : * onConnectionClosed contains callbacks that need to be called if a sub call is failing
804 : * @param deviceId The device we are calling
805 : * @param eraseDummy Erase the dummy call (a temporary subcall that must be stop when we will
806 : * not create new subcalls)
807 : */
808 : void callConnectionClosed(const DeviceId& deviceId, bool eraseDummy);
809 :
810 : /**
811 : * Ask a device to open a channeled SIP socket
812 : * @param peerId The contact who owns the device
813 : * @param deviceId The device to ask
814 : * @param forceNewConnection If we want a new SIP connection
815 : * @param pc A pending call to stop if the request fails
816 : * @note triggers cacheSIPConnection
817 : */
818 : void requestSIPConnection(const std::string& peerId,
819 : const DeviceId& deviceId,
820 : const std::string& connectionType,
821 : bool forceNewConnection = false,
822 : const std::shared_ptr<SIPCall>& pc = {});
823 : /**
824 : * Store a new SIP connection into sipConnections_
825 : * @param channel The new sip channel
826 : * @param peerId The contact who owns the device
827 : * @param deviceId Device linked to that transport
828 : */
829 : void cacheSIPConnection(std::shared_ptr<dhtnet::ChannelSocket>&& channel,
830 : const std::string& peerId,
831 : const DeviceId& deviceId);
832 : /**
833 : * Shutdown a SIP connection
834 : * @param channel The channel to close
835 : * @param peerId The contact who owns the device
836 : * @param deviceId Device linked to that transport
837 : */
838 : void shutdownSIPConnection(const std::shared_ptr<dhtnet::ChannelSocket>& channel,
839 : const std::string& peerId,
840 : const DeviceId& deviceId);
841 :
842 : void requestMessageConnection(const std::string& peerId,
843 : const DeviceId& deviceId,
844 : const std::string& connectionType,
845 : bool forceNewConnection);
846 :
847 : // File transfers
848 : std::mutex transfersMtx_ {};
849 : std::set<std::string> incomingFileTransfers_ {};
850 :
851 : /**
852 : * Helper used to send SIP messages on a channeled connection
853 : * @param conn The connection used
854 : * @param to Peer URI
855 : * @param ctx Context passed to the send request
856 : * @param token Token used
857 : * @param data Message to send
858 : * @param cb Callback to trigger when message is sent
859 : * @throw runtime_error if connection is invalid
860 : * @return if the request will be sent
861 : */
862 : bool sendSIPMessage(SipConnection& conn,
863 : const std::string& to,
864 : void* ctx,
865 : uint64_t token,
866 : const std::map<std::string, std::string>& data,
867 : pjsip_endpt_send_callback cb);
868 : void onSIPMessageSent(const std::shared_ptr<TextMessageCtx>& ctx, int code);
869 :
870 : std::mutex gitServersMtx_ {};
871 : std::map<dht::Value::Id, std::unique_ptr<GitServer>> gitServers_ {};
872 :
873 : //// File transfer (for profiles)
874 : std::shared_ptr<TransferManager> nonSwarmTransferManager_;
875 :
876 : std::atomic_bool deviceAnnounced_ {false};
877 : std::atomic_bool noSha3sumVerification_ {false};
878 :
879 : bool publishPresence_ {true};
880 :
881 : std::map<Uri::Scheme, std::unique_ptr<ChannelHandlerInterface>> channelHandlers_ {};
882 :
883 : std::unique_ptr<ConversationModule> convModule_;
884 : std::mutex moduleMtx_;
885 : std::unique_ptr<SyncModule> syncModule_;
886 :
887 : std::mutex rdvMtx_;
888 :
889 : int dhtBoundPort_ {0};
890 :
891 : void initConnectionManager();
892 :
893 : enum class PresenceState : int { DISCONNECTED = 0, AVAILABLE, CONNECTED };
894 : std::map<std::string, PresenceState> presenceState_;
895 : std::string presenceNote_;
896 : };
897 :
898 : static inline std::ostream&
899 : operator<<(std::ostream& os, const JamiAccount& acc)
900 : {
901 : os << "[Account " << acc.getAccountID() << "] ";
902 : return os;
903 : }
904 :
905 : } // namespace jami
|