LCOV - code coverage report
Current view: top level - foo/src/jamidht - contact_list.cpp (source / functions) Hit Total Coverage
Test: jami-coverage-filtered.info Lines: 298 376 79.3 %
Date: 2025-12-18 10:07:43 Functions: 54 84 64.3 %

          Line data    Source code
       1             : /*
       2             :  *  Copyright (C) 2004-2025 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             : #include "contact_list.h"
      18             : #include "logger.h"
      19             : #include "jamiaccount.h"
      20             : #include "fileutils.h"
      21             : 
      22             : #include "manager.h"
      23             : #ifdef ENABLE_PLUGIN
      24             : #include "plugin/jamipluginmanager.h"
      25             : #endif
      26             : 
      27             : #include "account_const.h"
      28             : 
      29             : #include <fstream>
      30             : #include <gnutls/ocsp.h>
      31             : 
      32             : namespace jami {
      33             : 
      34         791 : ContactList::ContactList(const std::string& accountId,
      35             :                          const std::shared_ptr<crypto::Certificate>& cert,
      36             :                          const std::filesystem::path& path,
      37         791 :                          OnChangeCallback cb)
      38         791 :     : accountId_(accountId)
      39         791 :     , path_(path)
      40         791 :     , callbacks_(std::move(cb))
      41             : {
      42         791 :     if (cert) {
      43         791 :         trust_ = std::make_unique<dhtnet::tls::TrustStore>(jami::Manager::instance().certStore(accountId_));
      44         789 :         accountTrust_.add(*cert);
      45             :     }
      46         809 : }
      47             : 
      48         789 : ContactList::~ContactList() {}
      49             : 
      50             : void
      51          16 : ContactList::load()
      52             : {
      53          16 :     loadContacts();
      54          16 :     loadTrustRequests();
      55          16 :     loadKnownDevices();
      56          16 : }
      57             : 
      58             : void
      59           0 : ContactList::save()
      60             : {
      61           0 :     saveContacts();
      62           0 :     saveTrustRequests();
      63           0 :     saveKnownDevices();
      64           0 : }
      65             : 
      66             : bool
      67          83 : ContactList::setCertificateStatus(const std::string& cert_id, const dhtnet::tls::TrustStore::PermissionStatus status)
      68             : {
      69          83 :     std::unique_lock lk(mutex_);
      70          83 :     if (contacts_.find(dht::InfoHash(cert_id)) != contacts_.end()) {
      71          12 :         JAMI_LOG("[Account {}] [Contacts] Unable to set certificate status for existing contacts {}",
      72             :                  accountId_,
      73             :                  cert_id);
      74           3 :         return false;
      75             :     }
      76          80 :     return trust_->setCertificateStatus(cert_id, status);
      77          83 : }
      78             : 
      79             : bool
      80           0 : ContactList::setCertificateStatus(const std::shared_ptr<crypto::Certificate>& cert,
      81             :                                   dhtnet::tls::TrustStore::PermissionStatus status,
      82             :                                   bool local)
      83             : {
      84           0 :     return trust_->setCertificateStatus(cert, status, local);
      85             : }
      86             : 
      87             : bool
      88         170 : ContactList::addContact(const dht::InfoHash& h, bool confirmed, const std::string& conversationId)
      89             : {
      90         170 :     std::unique_lock lk(mutex_);
      91         680 :     JAMI_WARNING("[Account {}] [Contacts] addContact: {}, conversation: {}", accountId_, h, conversationId);
      92         170 :     auto c = contacts_.find(h);
      93         170 :     if (c == contacts_.end())
      94         100 :         c = contacts_.emplace(h, Contact {}).first;
      95          70 :     else if (c->second.isActive() and c->second.confirmed == confirmed && c->second.conversationId == conversationId)
      96          62 :         return false;
      97         108 :     c->second.added = std::time(nullptr);
      98             :     // NOTE: because we can re-add a contact after removing it
      99             :     // we should reset removed (as not removed anymore). This fix isActive()
     100             :     // if addContact is called just after removeContact during the same second
     101         108 :     c->second.removed = 0;
     102         108 :     c->second.conversationId = conversationId;
     103         108 :     c->second.confirmed |= confirmed;
     104         108 :     auto hStr = h.toString();
     105         108 :     trust_->setCertificateStatus(hStr, dhtnet::tls::TrustStore::PermissionStatus::ALLOWED);
     106         108 :     saveContacts();
     107         108 :     lk.unlock();
     108         108 :     callbacks_.contactAdded(hStr, c->second.confirmed);
     109         108 :     return true;
     110         170 : }
     111             : 
     112             : bool
     113          28 : ContactList::updateConversation(const dht::InfoHash& h, const std::string& conversationId, bool added)
     114             : {
     115          28 :     std::lock_guard lk(mutex_);
     116          28 :     auto c = contacts_.find(h);
     117          28 :     if (c != contacts_.end() && c->second.conversationId != conversationId) {
     118          12 :         c->second.conversationId = conversationId;
     119          12 :         if (added) {
     120           2 :             c->second.added = std::time(nullptr);
     121             :         }
     122          12 :         saveContacts();
     123          12 :         return true;
     124             :     }
     125          16 :     return false;
     126          28 : }
     127             : 
     128             : bool
     129          19 : ContactList::removeContact(const dht::InfoHash& h, bool ban)
     130             : {
     131          19 :     std::unique_lock lk(mutex_);
     132          76 :     JAMI_WARNING("[Account {}] [Contacts] removeContact: {} (banned: {})", accountId_, h, ban);
     133          19 :     auto c = contacts_.find(h);
     134          19 :     if (c == contacts_.end())
     135           4 :         c = contacts_.emplace(h, Contact {}).first;
     136          19 :     c->second.removed = std::time(nullptr);
     137          19 :     c->second.confirmed = false;
     138          19 :     c->second.banned = ban;
     139          19 :     c->second.conversationId = "";
     140          19 :     auto uri = h.toString();
     141          19 :     trust_->setCertificateStatus(uri,
     142             :                                  ban ? dhtnet::tls::TrustStore::PermissionStatus::BANNED
     143             :                                      : dhtnet::tls::TrustStore::PermissionStatus::UNDEFINED);
     144          19 :     if (trustRequests_.erase(h) > 0)
     145           3 :         saveTrustRequests();
     146          19 :     saveContacts();
     147          19 :     lk.unlock();
     148             : #ifdef ENABLE_PLUGIN
     149          19 :     auto filename = path_.filename().string();
     150          19 :     jami::Manager::instance().getJamiPluginManager().getChatServicesManager().cleanChatSubjects(filename, uri);
     151             : #endif
     152          19 :     callbacks_.contactRemoved(uri, ban);
     153          19 :     return true;
     154          19 : }
     155             : 
     156             : bool
     157           0 : ContactList::removeContactConversation(const dht::InfoHash& h)
     158             : {
     159           0 :     std::unique_lock lk(mutex_);
     160           0 :     auto c = contacts_.find(h);
     161           0 :     if (c == contacts_.end())
     162           0 :         return false;
     163           0 :     c->second.conversationId = "";
     164           0 :     saveContacts();
     165           0 :     return true;
     166           0 : }
     167             : 
     168             : std::map<std::string, std::string>
     169           8 : ContactList::getContactDetails(const dht::InfoHash& h) const
     170             : {
     171           8 :     std::unique_lock lk(mutex_);
     172           8 :     const auto c = contacts_.find(h);
     173           8 :     if (c == std::end(contacts_)) {
     174           0 :         JAMI_WARNING("[Account {}] [Contacts] Contact '{}' not found", accountId_, h.to_view());
     175           0 :         return {};
     176             :     }
     177             : 
     178           8 :     auto details = c->second.toMap();
     179           8 :     if (not details.empty())
     180           8 :         details["id"] = c->first.toString();
     181             : 
     182           8 :     return details;
     183           8 : }
     184             : 
     185             : std::optional<Contact>
     186         616 : ContactList::getContactInfo(const dht::InfoHash& h) const
     187             : {
     188         616 :     const auto c = contacts_.find(h);
     189         616 :     if (c == std::end(contacts_)) {
     190        1248 :         JAMI_WARNING("[Account {}] [Contacts] Contact '{}' not found", accountId_, h.to_view());
     191         312 :         return {};
     192             :     }
     193         304 :     return c->second;
     194             : }
     195             : 
     196             : const std::map<dht::InfoHash, Contact>&
     197        1727 : ContactList::getContacts() const
     198             : {
     199        1727 :     return contacts_;
     200             : }
     201             : 
     202             : void
     203         772 : ContactList::setContacts(const std::map<dht::InfoHash, Contact>& contacts)
     204             : {
     205        3088 :     JAMI_LOG("[Account {}] [Contacts] replacing contact list (old: {} new: {})",
     206             :              accountId_,
     207             :              contacts_.size(),
     208             :              contacts.size());
     209         772 :     contacts_ = contacts;
     210         772 :     saveContacts();
     211             :     // Set contacts is used when creating a new device, so just announce new contacts
     212         775 :     for (auto& peer : contacts)
     213           3 :         if (peer.second.isActive())
     214           3 :             callbacks_.contactAdded(peer.first.toString(), peer.second.confirmed);
     215         772 : }
     216             : 
     217             : void
     218          64 : ContactList::updateContact(const dht::InfoHash& id, const Contact& contact, bool emit)
     219             : {
     220          64 :     if (not id) {
     221           0 :         JAMI_ERROR("[Account {}] [Contacts] updateContact: invalid contact ID", accountId_);
     222           0 :         return;
     223             :     }
     224          64 :     bool stateChanged {false};
     225          64 :     auto c = contacts_.find(id);
     226          64 :     if (c == contacts_.end()) {
     227             :         // JAMI_DBG("[Contacts] New contact: %s", id.toString().c_str());
     228          13 :         c = contacts_.emplace(id, contact).first;
     229          13 :         stateChanged = c->second.isActive() or c->second.isBanned();
     230             :     } else {
     231             :         // JAMI_DBG("[Contacts] Updated contact: %s", id.toString().c_str());
     232          51 :         stateChanged = c->second.update(contact);
     233             :     }
     234          64 :     if (stateChanged) {
     235             :         {
     236          17 :             std::lock_guard lk(mutex_);
     237          17 :             if (trustRequests_.erase(id) > 0)
     238           8 :                 saveTrustRequests();
     239          17 :         }
     240          17 :         if (c->second.isActive()) {
     241          13 :             trust_->setCertificateStatus(id.toString(), dhtnet::tls::TrustStore::PermissionStatus::ALLOWED);
     242          13 :             if (emit)
     243          13 :                 callbacks_.contactAdded(id.toString(), c->second.confirmed);
     244             :         } else {
     245           4 :             if (c->second.banned)
     246           2 :                 trust_->setCertificateStatus(id.toString(), dhtnet::tls::TrustStore::PermissionStatus::BANNED);
     247           4 :             if (emit)
     248           4 :                 callbacks_.contactRemoved(id.toString(), c->second.banned);
     249             :         }
     250             :     }
     251             : }
     252             : 
     253             : void
     254          16 : ContactList::loadContacts()
     255             : {
     256          16 :     decltype(contacts_) contacts;
     257             :     try {
     258          32 :         std::lock_guard fileLock(dhtnet::fileutils::getFileLock(path_ / "contacts"));
     259             :         // read file
     260          16 :         auto file = fileutils::loadFile("contacts", path_);
     261             :         // load values
     262          16 :         msgpack::object_handle oh = msgpack::unpack((const char*) file.data(), file.size());
     263          16 :         oh.get().convert(contacts);
     264          16 :     } catch (const std::exception& e) {
     265           0 :         JAMI_WARNING("[Account {}] [Contacts] Error loading contacts: {}", accountId_, e.what());
     266           0 :         return;
     267           0 :     }
     268             : 
     269          64 :     JAMI_WARNING("[Account {}] [Contacts] Loaded {} contacts", accountId_, contacts.size());
     270          16 :     for (auto& peer : contacts)
     271           0 :         updateContact(peer.first, peer.second, false);
     272          16 : }
     273             : 
     274             : void
     275        1013 : ContactList::saveContacts() const
     276             : {
     277        4052 :     JAMI_LOG("[Account {}] [Contacts] saving {} contacts", accountId_, contacts_.size());
     278        2026 :     std::lock_guard fileLock(dhtnet::fileutils::getFileLock(path_ / "contacts"));
     279        2026 :     std::ofstream file(path_ / "contacts", std::ios::trunc | std::ios::binary);
     280        1013 :     msgpack::pack(file, contacts_);
     281        1013 : }
     282             : 
     283             : void
     284         128 : ContactList::saveTrustRequests() const
     285             : {
     286             :     // mutex_ MUST BE locked
     287         256 :     std::ofstream file(path_ / "incomingTrustRequests", std::ios::trunc | std::ios::binary);
     288         128 :     msgpack::pack(file, trustRequests_);
     289         128 : }
     290             : 
     291             : void
     292          16 : ContactList::loadTrustRequests()
     293             : {
     294          16 :     if (!std::filesystem::is_regular_file(fileutils::getFullPath(path_, "incomingTrustRequests")))
     295          16 :         return;
     296           0 :     std::map<dht::InfoHash, TrustRequest> requests;
     297             :     try {
     298             :         // read file
     299           0 :         auto file = fileutils::loadFile("incomingTrustRequests", path_);
     300             :         // load values
     301           0 :         msgpack::object_handle oh = msgpack::unpack((const char*) file.data(), file.size());
     302           0 :         oh.get().convert(requests);
     303           0 :     } catch (const std::exception& e) {
     304           0 :         JAMI_WARNING("[Account {}] [Contacts] Error loading trust requests: {}", accountId_, e.what());
     305           0 :         return;
     306           0 :     }
     307             : 
     308           0 :     JAMI_WARNING("[Account {}] [Contacts] Loaded {} contact requests", accountId_, requests.size());
     309           0 :     for (auto& tr : requests)
     310           0 :         onTrustRequest(tr.first,
     311           0 :                        tr.second.device,
     312             :                        tr.second.received,
     313             :                        false,
     314           0 :                        tr.second.conversationId,
     315           0 :                        std::move(tr.second.payload));
     316           0 : }
     317             : 
     318             : bool
     319         122 : ContactList::onTrustRequest(const dht::InfoHash& peer_account,
     320             :                             const std::shared_ptr<dht::crypto::PublicKey>& peer_device,
     321             :                             time_t received,
     322             :                             bool confirm,
     323             :                             const std::string& conversationId,
     324             :                             std::vector<uint8_t>&& payload)
     325             : {
     326         122 :     bool accept = false;
     327             :     // Check existing contact
     328         122 :     std::unique_lock lk(mutex_);
     329         122 :     auto contact = contacts_.find(peer_account);
     330         122 :     bool active = false;
     331         122 :     if (contact != contacts_.end()) {
     332             :         // Banned contact: discard request
     333          55 :         if (contact->second.isBanned())
     334           0 :             return false;
     335             : 
     336          55 :         if (contact->second.isActive()) {
     337          50 :             active = true;
     338             :             // Send confirmation
     339          50 :             if (not confirm)
     340          12 :                 accept = true;
     341          50 :             if (not contact->second.confirmed) {
     342          38 :                 contact->second.confirmed = true;
     343          38 :                 saveContacts();
     344          38 :                 callbacks_.contactAdded(peer_account.toString(), true);
     345             :             }
     346             :         }
     347             :     }
     348         122 :     if (not active) {
     349          72 :         auto req = trustRequests_.find(peer_account);
     350          72 :         if (req == trustRequests_.end()) {
     351             :             // Add trust request
     352          67 :             req = trustRequests_.emplace(peer_account, TrustRequest {peer_device, conversationId, received, payload})
     353             :                       .first;
     354             :         } else {
     355             :             // Update trust request
     356           5 :             if (received > req->second.received) {
     357           1 :                 req->second.device = peer_device;
     358           1 :                 req->second.conversationId = conversationId;
     359           1 :                 req->second.received = received;
     360           1 :                 req->second.payload = payload;
     361             :             } else {
     362          16 :                 JAMI_LOG("[Account {}] [Contacts] Ignoring outdated trust request from {}", accountId_, peer_account);
     363             :             }
     364             :         }
     365          72 :         saveTrustRequests();
     366             :     }
     367         122 :     lk.unlock();
     368             :     // Note: call JamiAccount's callback to build ConversationRequest anyway
     369         122 :     if (!confirm)
     370          83 :         callbacks_.trustRequest(peer_account.toString(), conversationId, std::move(payload), received);
     371          39 :     else if (active) {
     372             :         // Only notify if confirmed + not removed
     373          38 :         callbacks_.onConfirmation(peer_account.toString(), conversationId);
     374             :     }
     375         122 :     return accept;
     376         122 : }
     377             : 
     378             : /* trust requests */
     379             : 
     380             : std::vector<std::map<std::string, std::string>>
     381         700 : ContactList::getTrustRequests() const
     382             : {
     383             :     using Map = std::map<std::string, std::string>;
     384         700 :     std::vector<Map> ret;
     385         700 :     std::lock_guard lk(mutex_);
     386         700 :     ret.reserve(trustRequests_.size());
     387         716 :     for (const auto& r : trustRequests_) {
     388         144 :         ret.emplace_back(Map {{libjami::Account::TrustRequest::FROM, r.first.toString()},
     389          32 :                               {libjami::Account::TrustRequest::RECEIVED, std::to_string(r.second.received)},
     390          16 :                               {libjami::Account::TrustRequest::CONVERSATIONID, r.second.conversationId},
     391             :                               {libjami::Account::TrustRequest::PAYLOAD,
     392         112 :                                std::string(r.second.payload.begin(), r.second.payload.end())}});
     393             :     }
     394        1400 :     return ret;
     395         700 : }
     396             : 
     397             : std::map<std::string, std::string>
     398         207 : ContactList::getTrustRequest(const dht::InfoHash& from) const
     399             : {
     400             :     using Map = std::map<std::string, std::string>;
     401         207 :     std::lock_guard lk(mutex_);
     402         207 :     auto r = trustRequests_.find(from);
     403         207 :     if (r == trustRequests_.end())
     404         164 :         return {};
     405          86 :     return Map {{libjami::Account::TrustRequest::FROM, r->first.toString()},
     406          86 :                 {libjami::Account::TrustRequest::RECEIVED, std::to_string(r->second.received)},
     407          43 :                 {libjami::Account::TrustRequest::CONVERSATIONID, r->second.conversationId},
     408             :                 {libjami::Account::TrustRequest::PAYLOAD,
     409         301 :                  std::string(r->second.payload.begin(), r->second.payload.end())}};
     410         207 : }
     411             : 
     412             : bool
     413         193 : ContactList::acceptTrustRequest(const dht::InfoHash& from)
     414             : {
     415             :     // The contact sent us a TR so we are in its contact list
     416         193 :     std::unique_lock lk(mutex_);
     417         193 :     auto i = trustRequests_.find(from);
     418         193 :     if (i == trustRequests_.end())
     419         151 :         return false;
     420          42 :     auto convId = i->second.conversationId;
     421             :     // Clear trust request
     422          42 :     trustRequests_.erase(i);
     423          42 :     saveTrustRequests();
     424          42 :     lk.unlock();
     425          42 :     addContact(from, true, convId);
     426          42 :     return true;
     427         193 : }
     428             : 
     429             : void
     430          53 : ContactList::acceptConversation(const std::string& convId, const std::string& deviceId)
     431             : {
     432          53 :     if (callbacks_.acceptConversation)
     433          53 :         callbacks_.acceptConversation(convId, deviceId);
     434          53 : }
     435             : 
     436             : bool
     437           3 : ContactList::discardTrustRequest(const dht::InfoHash& from)
     438             : {
     439           3 :     std::lock_guard lk(mutex_);
     440           3 :     if (trustRequests_.erase(from) > 0) {
     441           3 :         saveTrustRequests();
     442           3 :         return true;
     443             :     }
     444           0 :     return false;
     445           3 : }
     446             : 
     447             : void
     448          16 : ContactList::loadKnownDevices()
     449             : {
     450          16 :     auto& certStore = jami::Manager::instance().certStore(accountId_);
     451             :     try {
     452             :         // read file
     453          16 :         auto file = fileutils::loadFile("knownDevices", path_);
     454             :         // load values
     455          16 :         msgpack::object_handle oh = msgpack::unpack((const char*) file.data(), file.size());
     456             : 
     457          16 :         std::map<dht::PkId, std::pair<std::string, uint64_t>> knownDevices;
     458          16 :         oh.get().convert(knownDevices);
     459          32 :         for (const auto& d : knownDevices) {
     460          32 :             if (auto crt = certStore.getCertificate(d.first.toString())) {
     461          16 :                 if (not foundAccountDevice(crt, d.second.first, clock::from_time_t(d.second.second), false))
     462           0 :                     JAMI_WARNING("[Account {}] [Contacts] Unable to add device {}", accountId_, d.first);
     463             :             } else {
     464           0 :                 JAMI_WARNING("[Account {}] [Contacts] Unable to find certificate for device {}", accountId_, d.first);
     465          16 :             }
     466             :         }
     467          16 :         if (not knownDevices.empty()) {
     468          16 :             callbacks_.devicesChanged(knownDevices_);
     469             :         }
     470          16 :     } catch (const std::exception& e) {
     471           0 :         JAMI_WARNING("[Account {}] [Contacts] Error loading devices: {}", accountId_, e.what());
     472           0 :         return;
     473           0 :     }
     474             : }
     475             : 
     476             : void
     477        2910 : ContactList::saveKnownDevices() const
     478             : {
     479        5820 :     std::ofstream file(path_ / "knownDevices", std::ios::trunc | std::ios::binary);
     480             : 
     481        2910 :     std::map<dht::PkId, std::pair<std::string, uint64_t>> devices;
     482     1010955 :     for (const auto& id : knownDevices_) {
     483     1008045 :         devices.emplace(id.first, std::make_pair(id.second.name, clock::to_time_t(id.second.last_sync)));
     484             :     }
     485             : 
     486        2910 :     msgpack::pack(file, devices);
     487        2910 : }
     488             : 
     489             : void
     490        2000 : ContactList::foundAccountDevice(const dht::PkId& device, const std::string& name, const time_point& updated)
     491             : {
     492             :     // insert device
     493        2000 :     auto it = knownDevices_.emplace(device, KnownDevice {{}, name, updated});
     494        2000 :     if (it.second) {
     495        8000 :         JAMI_LOG("[Account {}] [Contacts] Found account device: {} {}", accountId_, name, device);
     496        2000 :         saveKnownDevices();
     497        2000 :         callbacks_.devicesChanged(knownDevices_);
     498             :     } else {
     499             :         // update device name
     500           0 :         if (not name.empty() and it.first->second.name != name) {
     501           0 :             JAMI_LOG("[Account {}] [Contacts] Updating device name: {} {}", accountId_, name, device);
     502           0 :             it.first->second.name = name;
     503           0 :             saveKnownDevices();
     504           0 :             callbacks_.devicesChanged(knownDevices_);
     505             :         }
     506             :     }
     507        2000 : }
     508             : 
     509             : bool
     510        1936 : ContactList::foundAccountDevice(const std::shared_ptr<dht::crypto::Certificate>& crt,
     511             :                                 const std::string& name,
     512             :                                 const time_point& updated,
     513             :                                 bool notify)
     514             : {
     515        1936 :     if (not crt)
     516           0 :         return false;
     517             : 
     518        1936 :     auto id = crt->getLongId();
     519             : 
     520             :     // match certificate chain
     521        1936 :     auto verifyResult = accountTrust_.verify(*crt);
     522        1937 :     if (not verifyResult) {
     523           0 :         JAMI_WARNING("[Account {}] [Contacts] Found invalid account device: {:s}: {:s}",
     524             :                      accountId_,
     525             :                      id,
     526             :                      verifyResult.toString());
     527           0 :         return false;
     528             :     }
     529             : 
     530             :     // insert device
     531        1937 :     auto it = knownDevices_.emplace(id, KnownDevice {crt, name, updated});
     532        1937 :     if (it.second) {
     533        3444 :         JAMI_LOG("[Account {}] [Contacts] Found account device: {} {}", accountId_, name, id);
     534         861 :         jami::Manager::instance().certStore(accountId_).pinCertificate(crt);
     535         861 :         if (crt->ocspResponse) {
     536           0 :             unsigned int status = crt->ocspResponse->getCertificateStatus();
     537           0 :             if (status == GNUTLS_OCSP_CERT_REVOKED) {
     538           0 :                 JAMI_ERROR("[Account {}] Certificate {} has revoked OCSP status", accountId_, id);
     539           0 :                 trust_->setCertificateStatus(crt, dhtnet::tls::TrustStore::PermissionStatus::BANNED, false);
     540             :             }
     541             :         }
     542         861 :         if (notify) {
     543         845 :             saveKnownDevices();
     544         845 :             callbacks_.devicesChanged(knownDevices_);
     545             :         }
     546             :     } else {
     547             :         // update device name
     548        1076 :         if (not name.empty() and it.first->second.name != name) {
     549         248 :             JAMI_LOG("[Account {}] [Contacts] updating device name: {} {}", accountId_, name, id);
     550          62 :             it.first->second.name = name;
     551          62 :             if (notify) {
     552          62 :                 saveKnownDevices();
     553          62 :                 callbacks_.devicesChanged(knownDevices_);
     554             :             }
     555             :         }
     556             :     }
     557        1937 :     return true;
     558             : }
     559             : 
     560             : bool
     561           2 : ContactList::removeAccountDevice(const dht::PkId& device)
     562             : {
     563           2 :     if (knownDevices_.erase(device) > 0) {
     564           2 :         saveKnownDevices();
     565           2 :         return true;
     566             :     }
     567           0 :     return false;
     568             : }
     569             : 
     570             : void
     571          16 : ContactList::setAccountDeviceName(const dht::PkId& device, const std::string& name)
     572             : {
     573          16 :     auto dev = knownDevices_.find(device);
     574          16 :     if (dev != knownDevices_.end()) {
     575          16 :         if (dev->second.name != name) {
     576           1 :             dev->second.name = name;
     577           1 :             saveKnownDevices();
     578           1 :             callbacks_.devicesChanged(knownDevices_);
     579             :         }
     580             :     }
     581          16 : }
     582             : 
     583             : std::string
     584         772 : ContactList::getAccountDeviceName(const dht::PkId& device) const
     585             : {
     586         772 :     auto dev = knownDevices_.find(device);
     587         772 :     if (dev != knownDevices_.end()) {
     588         772 :         return dev->second.name;
     589             :     }
     590           0 :     return {};
     591             : }
     592             : 
     593             : DeviceSync
     594        1000 : ContactList::getSyncData() const
     595             : {
     596        1000 :     DeviceSync sync_data;
     597        1000 :     sync_data.date = clock::now().time_since_epoch().count();
     598             :     // sync_data.device_name = deviceName_;
     599        1001 :     sync_data.peers = getContacts();
     600             : 
     601             :     static constexpr size_t MAX_TRUST_REQUESTS = 20;
     602        1000 :     std::lock_guard lk(mutex_);
     603        1001 :     if (trustRequests_.size() <= MAX_TRUST_REQUESTS)
     604        1013 :         for (const auto& req : trustRequests_)
     605             :             sync_data.trust_requests
     606          13 :                 .emplace(req.first,
     607          26 :                          TrustRequest {req.second.device, req.second.conversationId, req.second.received, {}});
     608             :     else {
     609           0 :         size_t inserted = 0;
     610           0 :         auto req = trustRequests_.lower_bound(dht::InfoHash::getRandom());
     611           0 :         while (inserted++ < MAX_TRUST_REQUESTS) {
     612           0 :             if (req == trustRequests_.end())
     613           0 :                 req = trustRequests_.begin();
     614             :             sync_data.trust_requests
     615           0 :                 .emplace(req->first,
     616           0 :                          TrustRequest {req->second.device, req->second.conversationId, req->second.received, {}});
     617           0 :             ++req;
     618             :         }
     619             :     }
     620             : 
     621        8201 :     for (const auto& dev : knownDevices_) {
     622        7201 :         if (!dev.second.certificate) {
     623       24000 :             JAMI_WARNING("[Account {}] [Contacts] No certificate found for {}", accountId_, dev.first);
     624        6000 :             continue;
     625        6000 :         }
     626        1201 :         sync_data.devices.emplace(dev.second.certificate->getLongId(), KnownDeviceSync {dev.second.name});
     627             :     }
     628        2002 :     return sync_data;
     629        1001 : }
     630             : 
     631             : bool
     632           0 : ContactList::syncDevice(const dht::PkId& device, const time_point& syncDate)
     633             : {
     634           0 :     auto it = knownDevices_.find(device);
     635           0 :     if (it == knownDevices_.end()) {
     636           0 :         JAMI_WARNING("[Account {}] [Contacts] Dropping sync data from unknown device", accountId_);
     637           0 :         return false;
     638             :     }
     639           0 :     if (it->second.last_sync >= syncDate) {
     640           0 :         JAMI_LOG("[Account {}] [Contacts] Dropping outdated sync data", accountId_);
     641           0 :         return false;
     642             :     }
     643           0 :     it->second.last_sync = syncDate;
     644           0 :     return true;
     645             : }
     646             : 
     647             : } // namespace jami

Generated by: LCOV version 1.14