LCOV - code coverage report
Current view: top level - foo/src/jamidht - jamiaccount.h (source / functions) Hit Total Coverage
Test: jami-coverage-filtered.info Lines: 32 36 88.9 %
Date: 2026-04-01 09:29:43 Functions: 18 20 90.0 %

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

Generated by: LCOV version 1.14