30#include <gnutls/ocsp.h>
35 const std::shared_ptr<crypto::Certificate>&
cert,
36 const std::filesystem::path& path,
38 : accountId_(accountId)
44 accountTrust_.add(*
cert);
68 const dhtnet::tls::TrustStore::PermissionStatus status)
70 if (contacts_.find(dht::InfoHash(
cert_id)) != contacts_.end()) {
71 JAMI_LOG(
"[Account {}] [Contacts] Unable to set certificate status for existing contacts {}", accountId_,
cert_id);
74 return trust_->setCertificateStatus(
cert_id, status);
79 dhtnet::tls::TrustStore::PermissionStatus status,
82 return trust_->setCertificateStatus(
cert, status,
local);
88 JAMI_WARNING(
"[Account {}] [Contacts] addContact: {}, conversation: {}", accountId_, h, conversationId);
89 auto c = contacts_.find(h);
90 if (c == contacts_.end())
92 else if (c->second.isActive()
and c->second.confirmed == confirmed && c->second.conversationId == conversationId)
94 c->second.added = std::time(
nullptr);
98 c->second.removed = 0;
99 c->second.conversationId = conversationId;
100 c->second.confirmed |= confirmed;
101 auto hStr = h.toString();
102 trust_->setCertificateStatus(
hStr, dhtnet::tls::TrustStore::PermissionStatus::ALLOWED);
111 auto c = contacts_.find(h);
112 if (c != contacts_.end() && c->second.conversationId != conversationId) {
113 c->second.conversationId = conversationId;
121 std::unique_lock
lk(mutex_);
122 JAMI_WARNING(
"[Account {}] [Contacts] removeContact: {} (banned: {})", accountId_, h,
ban);
123 auto c = contacts_.find(h);
124 if (c == contacts_.end())
126 c->second.removed = std::time(
nullptr);
127 c->second.confirmed =
false;
128 c->second.banned =
ban;
129 auto uri = h.toString();
130 trust_->setCertificateStatus(uri,
131 ban ? dhtnet::tls::TrustStore::PermissionStatus::BANNED
132 : dhtnet::tls::TrustStore::PermissionStatus::UNDEFINED);
133 if (trustRequests_.erase(h) > 0)
138 auto filename = path_.filename().string();
140 .getJamiPluginManager()
141 .getChatServicesManager()
142 .cleanChatSubjects(filename, uri);
151 auto c = contacts_.find(h);
152 if (c == contacts_.end())
154 c->second.conversationId =
"";
159std::map<std::string, std::string>
162 const auto c = contacts_.find(h);
163 if (c == std::end(contacts_)) {
164 JAMI_WARNING(
"[Account {}] [Contacts] Contact '{}' not found", accountId_, h.to_view());
168 auto details = c->second.toMap();
170 details[
"id"] = c->first.toString();
175std::optional<Contact>
178 const auto c = contacts_.find(h);
179 if (c == std::end(contacts_)) {
180 JAMI_WARNING(
"[Account {}] [Contacts] Contact '{}' not found", accountId_, h.to_view());
186const std::map<dht::InfoHash, Contact>&
195 JAMI_LOG(
"[Account {}] [Contacts] replacing contact list (old: {} new: {})", accountId_, contacts_.size(), contacts.size());
196 contacts_ = contacts;
199 for (
auto& peer : contacts)
200 if (peer.second.isActive())
201 callbacks_.
contactAdded(peer.first.toString(), peer.second.confirmed);
208 JAMI_ERROR(
"[Account {}] [Contacts] updateContact: invalid contact ID", accountId_);
211 bool stateChanged {
false};
212 auto c = contacts_.find(
id);
213 if (c == contacts_.end()) {
215 c = contacts_.emplace(
id,
contact).first;
216 stateChanged = c->second.isActive()
or c->second.isBanned();
219 stateChanged = c->second.update(
contact);
223 std::lock_guard
lk(mutex_);
224 if (trustRequests_.erase(
id) > 0)
227 if (c->second.isActive()) {
228 trust_->setCertificateStatus(
id.
toString(), dhtnet::tls::TrustStore::PermissionStatus::ALLOWED);
232 if (c->second.banned)
233 trust_->setCertificateStatus(
id.
toString(),
234 dhtnet::tls::TrustStore::PermissionStatus::BANNED);
242ContactList::loadContacts()
244 decltype(contacts_) contacts;
249 msgpack::object_handle
oh = msgpack::unpack((
const char*)
file.data(),
file.size());
250 oh.get().convert(contacts);
251 }
catch (
const std::exception&
e) {
252 JAMI_WARNING(
"[Account {}] [Contacts] Error loading contacts: {}", accountId_,
e.what());
256 JAMI_WARNING(
"[Account {}] [Contacts] Loaded {} contacts", accountId_, contacts.size());
257 for (
auto& peer : contacts)
264 JAMI_LOG(
"[Account {}] [Contacts] saving {} contacts", accountId_, contacts_.size());
265 std::ofstream
file(path_ /
"contacts", std::ios::trunc | std::ios::binary);
266 msgpack::pack(
file, contacts_);
270ContactList::saveTrustRequests()
const
273 std::ofstream
file(path_ /
"incomingTrustRequests",
274 std::ios::trunc | std::ios::binary);
275 msgpack::pack(
file, trustRequests_);
279ContactList::loadTrustRequests()
283 std::map<dht::InfoHash, TrustRequest>
requests;
288 msgpack::object_handle
oh = msgpack::unpack((
const char*)
file.data(),
file.size());
290 }
catch (
const std::exception&
e) {
291 JAMI_WARNING(
"[Account {}] [Contacts] Error loading trust requests: {}", accountId_,
e.what());
295 JAMI_WARNING(
"[Account {}] [Contacts] Loaded {} contact requests", accountId_,
requests.size());
307 const std::shared_ptr<dht::crypto::PublicKey>&
peer_device,
310 const std::string& conversationId,
311 std::vector<uint8_t>&& payload)
315 std::unique_lock
lk(mutex_);
318 if (
contact != contacts_.end()) {
320 if (
contact->second.isBanned())
323 if (
contact->second.isActive()) {
329 contact->second.confirmed =
true;
336 if (req == trustRequests_.end()) {
344 if (received > req->second.received) {
346 req->second.conversationId = conversationId;
347 req->second.received = received;
348 req->second.payload = payload;
350 JAMI_LOG(
"[Account {}] [Contacts] Ignoring outdated trust request from {}",
373std::vector<std::map<std::string, std::string>>
376 using Map = std::map<std::string, std::string>;
377 std::vector<Map>
ret;
378 std::lock_guard
lk(mutex_);
379 ret.reserve(trustRequests_.size());
380 for (
const auto& r : trustRequests_) {
386 std::string(r.second.payload.begin(), r.second.payload.end())}});
391std::map<std::string, std::string>
394 using Map = std::map<std::string, std::string>;
395 std::lock_guard
lk(mutex_);
396 auto r = trustRequests_.find(from);
397 if (r == trustRequests_.end())
403 std::string(r->second.payload.begin(), r->second.payload.end())}};
410 std::unique_lock
lk(mutex_);
411 auto i = trustRequests_.find(from);
412 if (
i == trustRequests_.end())
414 auto convId =
i->second.conversationId;
416 trustRequests_.erase(
i);
433 std::lock_guard
lk(mutex_);
434 if (trustRequests_.erase(from) > 0) {
442ContactList::loadKnownDevices()
449 msgpack::object_handle
oh = msgpack::unpack((
const char*)
file.data(),
file.size());
451 std::map<dht::PkId, std::pair<std::string, uint64_t>>
knownDevices;
454 if (
auto crt = certStore.getCertificate(
d.first.toString())) {
456 JAMI_WARNING(
"[Account {}] [Contacts] Unable to add device {}", accountId_,
d.first);
458 JAMI_WARNING(
"[Account {}] [Contacts] Unable to find certificate for device {}", accountId_,
465 }
catch (
const std::exception&
e) {
466 JAMI_WARNING(
"[Account {}] [Contacts] Error loading devices: {}", accountId_,
e.what());
472ContactList::saveKnownDevices()
const
474 std::ofstream
file(path_ /
"knownDevices", std::ios::trunc | std::ios::binary);
476 std::map<dht::PkId, std::pair<std::string, uint64_t>> devices;
477 for (
const auto&
id : knownDevices_) {
478 devices.emplace(
id.
first,
479 std::make_pair(
id.
second.name, clock::to_time_t(
id.second.last_sync)));
482 msgpack::pack(
file, devices);
487 const std::string& name,
493 JAMI_LOG(
"[Account {}] [Contacts] Found account device: {} {}", accountId_, name, device);
498 if (
not name.empty()
and it.first->second.name != name) {
499 JAMI_LOG(
"[Account {}] [Contacts] Updating device name: {} {}", accountId_,
501 it.first->second.name = name;
510 const std::string& name,
517 auto id =
crt->getLongId();
522 JAMI_WARNING(
"[Account {}] [Contacts] Found invalid account device: {:s}: {:s}",
530 JAMI_LOG(
"[Account {}] [Contacts] Found account device: {} {}", accountId_, name,
id);
532 if (
crt->ocspResponse) {
533 unsigned int status =
crt->ocspResponse->getCertificateStatus();
535 JAMI_ERROR(
"[Account {}] Certificate {} has revoked OCSP status", accountId_,
id);
536 trust_->setCertificateStatus(
crt, dhtnet::tls::TrustStore::PermissionStatus::BANNED,
false);
545 if (
not name.empty()
and it.first->second.name != name) {
546 JAMI_LOG(
"[Account {}] [Contacts] updating device name: {} {}", accountId_, name,
id);
547 it.first->second.name = name;
560 if (knownDevices_.erase(device) > 0) {
570 auto dev = knownDevices_.find(device);
571 if (
dev != knownDevices_.end()) {
572 if (
dev->second.name != name) {
573 dev->second.name = name;
583 auto dev = knownDevices_.find(device);
584 if (
dev != knownDevices_.end()) {
585 return dev->second.name;
599 std::lock_guard
lk(mutex_);
601 for (
const auto& req : trustRequests_)
602 sync_data.trust_requests.emplace(req.first,
604 req.second.conversationId,
609 auto req = trustRequests_.lower_bound(dht::InfoHash::getRandom());
610 while (inserted++ < MAX_TRUST_REQUESTS) {
611 if (req == trustRequests_.end())
612 req = trustRequests_.begin();
613 sync_data.trust_requests.emplace(req->first,
614 TrustRequest {req->second.device,
615 req->second.conversationId,
616 req->second.received,
622 for (
const auto&
dev : knownDevices_) {
623 if (!
dev.second.certificate) {
624 JAMI_WARNING(
"[Account {}] [Contacts] No certificate found for {}", accountId_,
dev.first);
627 sync_data.devices.emplace(
dev.second.certificate->getLongId(),
628 KnownDeviceSync {dev.second.name,
629 dev.second.certificate->getId()});
635ContactList::syncDevice(
const dht::PkId& device,
const time_point& syncDate)
637 auto it = knownDevices_.find(device);
638 if (it == knownDevices_.end()) {
639 JAMI_WARNING(
"[Account {}] [Contacts] Dropping sync data from unknown device", accountId_);
642 if (it->second.last_sync >= syncDate) {
643 JAMI_LOG(
"[Account {}] [Contacts] Dropping outdated sync data", accountId_);
646 it->second.last_sync = syncDate;
static LIBJAMI_TEST_EXPORT Manager & instance()
dhtnet::tls::CertificateStore & certStore(const std::string &accountId) const
#define JAMI_ERROR(formatstr,...)
#define JAMI_WARNING(formatstr,...)
#define JAMI_LOG(formatstr,...)
std::vector< uint8_t > loadFile(const std::filesystem::path &path, const std::filesystem::path &default_dir)
Read the full content of a file at path.
std::filesystem::path getFullPath(const std::filesystem::path &base, const std::filesystem::path &path)
If path is relative, it is appended to base.
static constexpr std::string_view toString(AuthDecodingState state)
void emitSignal(Args... args)
static constexpr const char PAYLOAD[]
static constexpr const char RECEIVED[]
static constexpr const char CONVERSATIONID[]
static constexpr const char FROM[]
std::shared_ptr< dht::crypto::PublicKey > device