LCOV - code coverage report
Current view: top level - src/jamidht - contact_list.cpp (source / functions) Coverage Total Hit
Test: jami-coverage-filtered.info Lines: 80.2 % 379 304
Test Date: 2026-06-13 09:18:46 Functions: 67.1 % 85 57

            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              : #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          792 : ContactList::ContactList(const std::string& accountId,
      35              :                          const std::shared_ptr<crypto::Certificate>& cert,
      36              :                          const std::filesystem::path& path,
      37          792 :                          OnChangeCallback cb)
      38          792 :     : accountId_(accountId)
      39          792 :     , path_(path)
      40          792 :     , callbacks_(std::move(cb))
      41              : {
      42          792 :     if (cert) {
      43          792 :         trust_ = std::make_unique<dhtnet::tls::TrustStore>(jami::Manager::instance().certStore(accountId_));
      44          792 :         accountTrust_.add(*cert);
      45              :     }
      46          792 : }
      47              : 
      48          792 : 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          217 : ContactList::addContact(const dht::InfoHash& h, bool confirmed, const std::string& conversationId)
      89              : {
      90          217 :     std::unique_lock lk(mutex_);
      91          868 :     JAMI_WARNING("[Account {}] [Contacts] addContact: {}, conversation: {}", accountId_, h, conversationId);
      92          217 :     auto c = contacts_.find(h);
      93          217 :     if (c == contacts_.end())
      94          100 :         c = contacts_.emplace(h, Contact {}).first;
      95          117 :     else if (c->second.isActive() and c->second.confirmed == confirmed && c->second.conversationId == conversationId)
      96          109 :         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          217 : }
     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            6 : ContactList::getContactDetails(const dht::InfoHash& h) const
     170              : {
     171            6 :     std::unique_lock lk(mutex_);
     172            6 :     const auto c = contacts_.find(h);
     173           12 :     if (c == std::end(contacts_)) {
     174            0 :         JAMI_WARNING("[Account {}] [Contacts] Contact '{}' not found", accountId_, h.to_view());
     175            0 :         return {};
     176              :     }
     177              : 
     178            6 :     auto details = c->second.toMap();
     179            6 :     if (not details.empty())
     180           18 :         details["id"] = c->first.toString();
     181              : 
     182            6 :     return details;
     183            6 : }
     184              : 
     185              : std::optional<Contact>
     186         1305 : ContactList::getContactInfo(const dht::InfoHash& h) const
     187              : {
     188         1305 :     const auto c = contacts_.find(h);
     189         2610 :     if (c == std::end(contacts_)) {
     190         3176 :         JAMI_WARNING("[Account {}] [Contacts] Contact '{}' not found", accountId_, h.to_view());
     191          794 :         return {};
     192              :     }
     193          511 :     return c->second;
     194              : }
     195              : 
     196              : const std::map<dht::InfoHash, Contact>&
     197         1706 : ContactList::getContacts() const
     198              : {
     199         1706 :     return contacts_;
     200              : }
     201              : 
     202              : void
     203          775 : ContactList::setContacts(const std::map<dht::InfoHash, Contact>& contacts)
     204              : {
     205         3100 :     JAMI_LOG("[Account {}] [Contacts] replacing contact list (old: {} new: {})",
     206              :              accountId_,
     207              :              contacts_.size(),
     208              :              contacts.size());
     209          775 :     contacts_ = contacts;
     210          775 :     saveContacts();
     211              :     // Set contacts is used when creating a new device, so just announce new contacts
     212          778 :     for (auto& peer : contacts)
     213            3 :         if (peer.second.isActive())
     214            3 :             callbacks_.contactAdded(peer.first.toString(), peer.second.confirmed);
     215          775 : }
     216              : 
     217              : void
     218           73 : ContactList::updateContact(const dht::InfoHash& id, const Contact& contact, bool emit)
     219              : {
     220           73 :     if (not id) {
     221            0 :         JAMI_ERROR("[Account {}] [Contacts] updateContact: invalid contact ID", accountId_);
     222            0 :         return;
     223              :     }
     224           73 :     bool stateChanged {false};
     225           73 :     auto c = contacts_.find(id);
     226           73 :     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           60 :         stateChanged = c->second.update(contact);
     233              :     }
     234           73 :     if (stateChanged) {
     235              :         {
     236           17 :             std::lock_guard lk(mutex_);
     237           17 :             if (trustRequests_.erase(id) > 0)
     238            7 :                 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              : std::map<dht::InfoHash, Contact>
     254           60 : ContactList::contactsFromPath(const std::filesystem::path& path)
     255              : {
     256           60 :     std::map<dht::InfoHash, Contact> contacts;
     257              :     try {
     258           60 :         std::lock_guard fileLock(dhtnet::fileutils::getFileLock(path / "contacts"));
     259           60 :         auto file = fileutils::loadFile("contacts", path);
     260           60 :         msgpack::object_handle oh = msgpack::unpack((const char*) file.data(), file.size());
     261           60 :         oh.get().convert(contacts);
     262           60 :     } catch (const std::exception& e) {
     263            0 :         JAMI_WARNING("[Contacts] Error loading contacts from {}: {}", path.string(), e.what());
     264            0 :     }
     265           60 :     return contacts;
     266            0 : }
     267              : 
     268              : void
     269           16 : ContactList::loadContacts()
     270              : {
     271           16 :     auto contacts = contactsFromPath(path_);
     272           64 :     JAMI_WARNING("[Account {}] [Contacts] Loaded {} contacts", accountId_, contacts.size());
     273           16 :     for (auto& peer : contacts)
     274            0 :         updateContact(peer.first, peer.second, false);
     275           16 : }
     276              : 
     277              : void
     278         1026 : ContactList::saveContacts() const
     279              : {
     280         4104 :     JAMI_LOG("[Account {}] [Contacts] saving {} contacts", accountId_, contacts_.size());
     281         1026 :     std::lock_guard fileLock(dhtnet::fileutils::getFileLock(path_ / "contacts"));
     282         1026 :     std::ofstream file(path_ / "contacts", std::ios::trunc | std::ios::binary);
     283         1026 :     msgpack::pack(file, contacts_);
     284         1026 : }
     285              : 
     286              : void
     287          146 : ContactList::saveTrustRequests() const
     288              : {
     289              :     // mutex_ MUST BE locked
     290          146 :     std::ofstream file(path_ / "incomingTrustRequests", std::ios::trunc | std::ios::binary);
     291          146 :     msgpack::pack(file, trustRequests_);
     292          146 : }
     293              : 
     294              : void
     295           16 : ContactList::loadTrustRequests()
     296              : {
     297           16 :     if (!std::filesystem::is_regular_file(fileutils::getFullPath(path_, "incomingTrustRequests")))
     298           16 :         return;
     299            0 :     std::map<dht::InfoHash, TrustRequest> requests;
     300              :     try {
     301              :         // read file
     302            0 :         auto file = fileutils::loadFile("incomingTrustRequests", path_);
     303              :         // load values
     304            0 :         msgpack::object_handle oh = msgpack::unpack((const char*) file.data(), file.size());
     305            0 :         oh.get().convert(requests);
     306            0 :     } catch (const std::exception& e) {
     307            0 :         JAMI_WARNING("[Account {}] [Contacts] Error loading trust requests: {}", accountId_, e.what());
     308            0 :         return;
     309            0 :     }
     310              : 
     311            0 :     JAMI_WARNING("[Account {}] [Contacts] Loaded {} contact requests", accountId_, requests.size());
     312            0 :     for (auto& tr : requests)
     313            0 :         onTrustRequest(tr.first,
     314            0 :                        tr.second.device,
     315              :                        tr.second.received,
     316              :                        false,
     317            0 :                        tr.second.conversationId,
     318            0 :                        std::move(tr.second.payload));
     319            0 : }
     320              : 
     321              : bool
     322          208 : ContactList::onTrustRequest(const dht::InfoHash& peer_account,
     323              :                             const std::shared_ptr<dht::crypto::PublicKey>& peer_device,
     324              :                             time_t received,
     325              :                             bool confirm,
     326              :                             const std::string& conversationId,
     327              :                             std::vector<uint8_t>&& payload)
     328              : {
     329          208 :     bool accept = false;
     330              :     // Check existing contact
     331          208 :     std::unique_lock lk(mutex_);
     332          208 :     auto contact = contacts_.find(peer_account);
     333          208 :     bool active = false;
     334          208 :     if (contact != contacts_.end()) {
     335              :         // Banned contact: discard request
     336          120 :         if (contact->second.isBanned())
     337            0 :             return false;
     338              : 
     339          120 :         if (contact->second.isActive()) {
     340          117 :             active = true;
     341              :             // Send confirmation
     342          117 :             if (not confirm)
     343           47 :                 accept = true;
     344          117 :             if (not contact->second.confirmed) {
     345           39 :                 contact->second.confirmed = true;
     346           39 :                 saveContacts();
     347           39 :                 callbacks_.contactAdded(peer_account.toString(), true);
     348              :             }
     349              :         }
     350              :     }
     351          208 :     if (not active) {
     352           91 :         auto req = trustRequests_.find(peer_account);
     353           91 :         if (req == trustRequests_.end()) {
     354              :             // Add trust request
     355           67 :             req = trustRequests_.emplace(peer_account, TrustRequest {peer_device, conversationId, received, payload})
     356              :                       .first;
     357              :         } else {
     358              :             // Update trust request
     359           24 :             if (received > req->second.received) {
     360            3 :                 req->second.device = peer_device;
     361            3 :                 req->second.conversationId = conversationId;
     362            3 :                 req->second.received = received;
     363            3 :                 req->second.payload = payload;
     364              :             } else {
     365           84 :                 JAMI_LOG("[Account {}] [Contacts] Ignoring outdated trust request from {}", accountId_, peer_account);
     366              :             }
     367              :         }
     368           91 :         saveTrustRequests();
     369              :     }
     370          208 :     lk.unlock();
     371              :     // Note: call JamiAccount's callback to build ConversationRequest anyway
     372          208 :     if (!confirm)
     373          135 :         callbacks_.trustRequest(peer_account.toString(), conversationId, std::move(payload), received);
     374           73 :     else if (active) {
     375              :         // Only notify if confirmed + not removed
     376           70 :         callbacks_.onConfirmation(peer_account.toString(), conversationId);
     377              :     }
     378          208 :     return accept;
     379          208 : }
     380              : 
     381              : /* trust requests */
     382              : 
     383              : std::vector<std::map<std::string, std::string>>
     384          703 : ContactList::getTrustRequests() const
     385              : {
     386              :     using Map = std::map<std::string, std::string>;
     387          703 :     std::vector<Map> ret;
     388          703 :     std::lock_guard lk(mutex_);
     389          703 :     ret.reserve(trustRequests_.size());
     390          718 :     for (const auto& r : trustRequests_) {
     391          105 :         ret.emplace_back(Map {{libjami::Account::TrustRequest::FROM, r.first.toString()},
     392           15 :                               {libjami::Account::TrustRequest::RECEIVED, std::to_string(r.second.received)},
     393           15 :                               {libjami::Account::TrustRequest::CONVERSATIONID, r.second.conversationId},
     394              :                               {libjami::Account::TrustRequest::PAYLOAD,
     395          120 :                                std::string(r.second.payload.begin(), r.second.payload.end())}});
     396              :     }
     397         1406 :     return ret;
     398          733 : }
     399              : 
     400              : std::map<std::string, std::string>
     401          218 : ContactList::getTrustRequest(const dht::InfoHash& from) const
     402              : {
     403              :     using Map = std::map<std::string, std::string>;
     404          218 :     std::lock_guard lk(mutex_);
     405          218 :     auto r = trustRequests_.find(from);
     406          218 :     if (r == trustRequests_.end())
     407          175 :         return {};
     408           43 :     return Map {{libjami::Account::TrustRequest::FROM, r->first.toString()},
     409           86 :                 {libjami::Account::TrustRequest::RECEIVED, std::to_string(r->second.received)},
     410           86 :                 {libjami::Account::TrustRequest::CONVERSATIONID, r->second.conversationId},
     411              :                 {libjami::Account::TrustRequest::PAYLOAD,
     412          387 :                  std::string(r->second.payload.begin(), r->second.payload.end())}};
     413          390 : }
     414              : 
     415              : bool
     416          204 : ContactList::acceptTrustRequest(const dht::InfoHash& from)
     417              : {
     418              :     // The contact sent us a TR so we are in its contact list
     419          204 :     std::unique_lock lk(mutex_);
     420          204 :     auto i = trustRequests_.find(from);
     421          204 :     if (i == trustRequests_.end())
     422          162 :         return false;
     423           42 :     auto convId = i->second.conversationId;
     424              :     // Clear trust request
     425           42 :     trustRequests_.erase(i);
     426           42 :     saveTrustRequests();
     427           42 :     lk.unlock();
     428           42 :     addContact(from, true, convId);
     429           42 :     return true;
     430          204 : }
     431              : 
     432              : void
     433          129 : ContactList::acceptConversation(const std::string& convId, const std::string& deviceId)
     434              : {
     435          129 :     if (callbacks_.acceptConversation)
     436          129 :         callbacks_.acceptConversation(convId, deviceId);
     437          129 : }
     438              : 
     439              : bool
     440            3 : ContactList::discardTrustRequest(const dht::InfoHash& from)
     441              : {
     442            3 :     std::lock_guard lk(mutex_);
     443            3 :     if (trustRequests_.erase(from) > 0) {
     444            3 :         saveTrustRequests();
     445            3 :         return true;
     446              :     }
     447            0 :     return false;
     448            3 : }
     449              : 
     450              : void
     451           16 : ContactList::loadKnownDevices()
     452              : {
     453           16 :     auto& certStore = jami::Manager::instance().certStore(accountId_);
     454              :     try {
     455              :         // read file
     456           16 :         auto file = fileutils::loadFile("knownDevices", path_);
     457              :         // load values
     458           16 :         msgpack::object_handle oh = msgpack::unpack((const char*) file.data(), file.size());
     459              : 
     460           16 :         std::map<dht::PkId, std::pair<std::string, uint64_t>> knownDevices;
     461           16 :         oh.get().convert(knownDevices);
     462           32 :         for (const auto& d : knownDevices) {
     463           16 :             if (auto crt = certStore.getCertificate(d.first.toString())) {
     464           16 :                 if (not foundAccountDevice(crt, d.second.first, clock::from_time_t(d.second.second), false))
     465            0 :                     JAMI_WARNING("[Account {}] [Contacts] Unable to add device {}", accountId_, d.first);
     466              :             } else {
     467            0 :                 JAMI_WARNING("[Account {}] [Contacts] Unable to find certificate for device {}", accountId_, d.first);
     468           16 :             }
     469              :         }
     470           16 :         if (not knownDevices.empty()) {
     471           16 :             callbacks_.devicesChanged(knownDevices_);
     472              :         }
     473           16 :     } catch (const std::exception& e) {
     474            0 :         JAMI_WARNING("[Account {}] [Contacts] Error loading devices: {}", accountId_, e.what());
     475            0 :         return;
     476            0 :     }
     477              : }
     478              : 
     479              : void
     480         2913 : ContactList::saveKnownDevices() const
     481              : {
     482         2913 :     std::ofstream file(path_ / "knownDevices", std::ios::trunc | std::ios::binary);
     483              : 
     484         2913 :     std::map<dht::PkId, std::pair<std::string, uint64_t>> devices;
     485      1010744 :     for (const auto& id : knownDevices_) {
     486      1007829 :         devices.emplace(id.first, std::make_pair(id.second.name, clock::to_time_t(id.second.last_sync)));
     487              :     }
     488              : 
     489         2917 :     msgpack::pack(file, devices);
     490         2913 : }
     491              : 
     492              : void
     493         2000 : ContactList::foundAccountDevice(const dht::PkId& device, const std::string& name, const time_point& updated)
     494              : {
     495              :     // insert device
     496         2000 :     auto it = knownDevices_.emplace(device, KnownDevice {{}, name, updated});
     497         2000 :     if (it.second) {
     498         8000 :         JAMI_LOG("[Account {}] [Contacts] Found account device: {} {}", accountId_, name, device);
     499         2000 :         saveKnownDevices();
     500         2000 :         callbacks_.devicesChanged(knownDevices_);
     501              :     } else {
     502              :         // update device name
     503            0 :         if (not name.empty() and it.first->second.name != name) {
     504            0 :             JAMI_LOG("[Account {}] [Contacts] Updating device name: {} {}", accountId_, name, device);
     505            0 :             it.first->second.name = name;
     506            0 :             saveKnownDevices();
     507            0 :             callbacks_.devicesChanged(knownDevices_);
     508              :         }
     509              :     }
     510         2000 : }
     511              : 
     512              : bool
     513         1974 : ContactList::foundAccountDevice(const std::shared_ptr<dht::crypto::Certificate>& crt,
     514              :                                 const std::string& name,
     515              :                                 const time_point& updated,
     516              :                                 bool notify)
     517              : {
     518         1974 :     if (not crt)
     519            0 :         return false;
     520              : 
     521         1974 :     auto id = crt->getLongId();
     522              : 
     523              :     // match certificate chain
     524         1974 :     auto verifyResult = accountTrust_.verify(*crt);
     525         1974 :     if (not verifyResult) {
     526           12 :         JAMI_WARNING("[Account {}] [Contacts] Found invalid account device: {:s}: {:s}",
     527              :                      accountId_,
     528              :                      id,
     529              :                      verifyResult.toString());
     530            3 :         return false;
     531              :     }
     532              : 
     533              :     // insert device
     534         1971 :     auto it = knownDevices_.emplace(id, KnownDevice {crt, name, updated});
     535         1971 :     if (it.second) {
     536         3452 :         JAMI_LOG("[Account {}] [Contacts] Found account device: {} {}", accountId_, name, id);
     537          863 :         jami::Manager::instance().certStore(accountId_).pinCertificate(crt);
     538          863 :         if (crt->ocspResponse) {
     539            0 :             unsigned int status = crt->ocspResponse->getCertificateStatus();
     540            0 :             if (status == GNUTLS_OCSP_CERT_REVOKED) {
     541            0 :                 JAMI_ERROR("[Account {}] Certificate {} has revoked OCSP status", accountId_, id);
     542            0 :                 trust_->setCertificateStatus(crt, dhtnet::tls::TrustStore::PermissionStatus::BANNED, false);
     543              :             }
     544              :         }
     545          863 :         if (notify) {
     546          847 :             saveKnownDevices();
     547          847 :             callbacks_.devicesChanged(knownDevices_);
     548              :         }
     549              :     } else {
     550              :         // update device name
     551         1108 :         if (not name.empty() and it.first->second.name != name) {
     552          252 :             JAMI_LOG("[Account {}] [Contacts] updating device name: {} {}", accountId_, name, id);
     553           63 :             it.first->second.name = name;
     554           63 :             if (notify) {
     555           63 :                 saveKnownDevices();
     556           63 :                 callbacks_.devicesChanged(knownDevices_);
     557              :             }
     558              :         }
     559              :     }
     560         1971 :     return true;
     561              : }
     562              : 
     563              : bool
     564            2 : ContactList::removeAccountDevice(const dht::PkId& device)
     565              : {
     566            2 :     if (knownDevices_.erase(device) > 0) {
     567            2 :         saveKnownDevices();
     568            2 :         return true;
     569              :     }
     570            0 :     return false;
     571              : }
     572              : 
     573              : void
     574           16 : ContactList::setAccountDeviceName(const dht::PkId& device, const std::string& name)
     575              : {
     576           16 :     auto dev = knownDevices_.find(device);
     577           16 :     if (dev != knownDevices_.end()) {
     578           16 :         if (dev->second.name != name) {
     579            1 :             dev->second.name = name;
     580            1 :             saveKnownDevices();
     581            1 :             callbacks_.devicesChanged(knownDevices_);
     582              :         }
     583              :     }
     584           16 : }
     585              : 
     586              : std::string
     587          775 : ContactList::getAccountDeviceName(const dht::PkId& device) const
     588              : {
     589          775 :     auto dev = knownDevices_.find(device);
     590          775 :     if (dev != knownDevices_.end()) {
     591          774 :         return dev->second.name;
     592              :     }
     593            1 :     return {};
     594              : }
     595              : 
     596              : DeviceSync
     597         1017 : ContactList::getSyncData() const
     598              : {
     599         1017 :     DeviceSync sync_data;
     600         1017 :     sync_data.date = clock::now().time_since_epoch().count();
     601              :     // sync_data.device_name = deviceName_;
     602         1017 :     sync_data.peers = getContacts();
     603              : 
     604              :     static constexpr size_t MAX_TRUST_REQUESTS = 20;
     605         1017 :     std::lock_guard lk(mutex_);
     606         1017 :     if (trustRequests_.size() <= MAX_TRUST_REQUESTS)
     607         1032 :         for (const auto& req : trustRequests_)
     608              :             sync_data.trust_requests
     609           30 :                 .emplace(req.first,
     610           15 :                          TrustRequest {req.second.device, req.second.conversationId, req.second.received, {}});
     611              :     else {
     612            0 :         size_t inserted = 0;
     613            0 :         auto req = trustRequests_.lower_bound(dht::InfoHash::getRandom());
     614            0 :         while (inserted++ < MAX_TRUST_REQUESTS) {
     615            0 :             if (req == trustRequests_.end())
     616            0 :                 req = trustRequests_.begin();
     617              :             sync_data.trust_requests
     618            0 :                 .emplace(req->first,
     619            0 :                          TrustRequest {req->second.device, req->second.conversationId, req->second.received, {}});
     620            0 :             ++req;
     621              :         }
     622              :     }
     623              : 
     624         8743 :     for (const auto& dev : knownDevices_) {
     625         7727 :         if (!dev.second.certificate) {
     626        25984 :             JAMI_WARNING("[Account {}] [Contacts] No certificate found for {}", accountId_, dev.first);
     627         6496 :             continue;
     628         6496 :         }
     629         1230 :         sync_data.devices.emplace(dev.second.certificate->getLongId(), KnownDeviceSync {dev.second.name});
     630              :     }
     631         2034 :     return sync_data;
     632         1017 : }
     633              : 
     634              : bool
     635            0 : ContactList::syncDevice(const dht::PkId& device, const time_point& syncDate)
     636              : {
     637            0 :     auto it = knownDevices_.find(device);
     638            0 :     if (it == knownDevices_.end()) {
     639            0 :         JAMI_WARNING("[Account {}] [Contacts] Dropping sync data from unknown device", accountId_);
     640            0 :         return false;
     641              :     }
     642            0 :     if (it->second.last_sync >= syncDate) {
     643            0 :         JAMI_LOG("[Account {}] [Contacts] Dropping outdated sync data", accountId_);
     644            0 :         return false;
     645              :     }
     646            0 :     it->second.last_sync = syncDate;
     647            0 :     return true;
     648              : }
     649              : 
     650              : } // namespace jami
        

Generated by: LCOV version 2.0-1