diff --git a/contrib/src/msgpack/rules.mak b/contrib/src/msgpack/rules.mak index 0d0508ad18e7d8af90ce967a7c1362cc0de6ac3d..e35817a3774d07642721d1b2445f823b60e62c01 100644 --- a/contrib/src/msgpack/rules.mak +++ b/contrib/src/msgpack/rules.mak @@ -3,7 +3,7 @@ MSGPACK_VERSION := cpp-3.2.0 MSGPACK_URL := https://github.com/msgpack/msgpack-c/archive/$(MSGPACK_VERSION).tar.gz PKGS += msgpack -ifeq ($(call need_pkg,"msgpack >= 1.1"),) +ifeq ($(call need_pkg,"msgpack >= 3.0.0"),) PKGS_FOUND += msgpack endif diff --git a/contrib/src/opendht/SHA512SUMS b/contrib/src/opendht/SHA512SUMS index c749f4bf0de6c8bb64a404974fa5109efdab508a..92b2b30aa4ac0c86cfdc2694f4d2daa7e5bdc799 100644 --- a/contrib/src/opendht/SHA512SUMS +++ b/contrib/src/opendht/SHA512SUMS @@ -1 +1 @@ -75d3da56bb9cb4ccc3afcb29b68a19f551f7a0f10193bf9a6efb2acaed2b4243c39daf96d8ab4e080596d44e15da1198a91cfaa7cd457ccdbb3d10a08f9b5fb0 opendht-2.2.0.tar.gz \ No newline at end of file +11cb53c1145793fb92d54a7775a00783bb8216939d87c31c9b12433a274b4f728cfa46de64bd111d14817264bee2bab12511549c8a544f863ddfdbbe2261c140 opendht-efda4af94c6310b3966dc850f20467b6309d0a43.tar.gz diff --git a/contrib/src/opendht/package.json b/contrib/src/opendht/package.json index caaf490eaf1821b011d046a62984d13ec6f52aab..742ac166744caec8867617a081bdc9659139c6ea 100644 --- a/contrib/src/opendht/package.json +++ b/contrib/src/opendht/package.json @@ -1,6 +1,6 @@ { "name": "opendht", - "version": "2.2.0", + "version": "efda4af94c6310b3966dc850f20467b6309d0a43", "url": "https://github.com/savoirfairelinux/opendht/archive/__VERSION__.tar.gz", "deps": [ "argon2", diff --git a/contrib/src/opendht/rules.mak b/contrib/src/opendht/rules.mak index 43e0c64fe1b8ba392bf15a2dacf74bfcceff2e8d..642383ad8d90499e314cabc45c5cb77d75b72b93 100644 --- a/contrib/src/opendht/rules.mak +++ b/contrib/src/opendht/rules.mak @@ -1,5 +1,5 @@ # OPENDHT -OPENDHT_VERSION := 2.2.0 +OPENDHT_VERSION := efda4af94c6310b3966dc850f20467b6309d0a43 OPENDHT_URL := https://github.com/savoirfairelinux/opendht/archive/$(OPENDHT_VERSION).tar.gz PKGS += opendht diff --git a/src/jamidht/account_manager.cpp b/src/jamidht/account_manager.cpp index 855c13bca0a910a90902c33797bd60d5a386e074..ee5ce2b0c2e24cf0a9f4e0faaf018a808ab827be 100644 --- a/src/jamidht/account_manager.cpp +++ b/src/jamidht/account_manager.cpp @@ -177,7 +177,8 @@ AccountManager::useIdentity(const dht::crypto::Identity& identity, info->contacts = std::move(contactList); info->contacts->load(); info->accountId = id; - info->deviceId = identity.first->getPublicKey().getId().toString(); + info->devicePk = identity.first->getSharedPublicKey(); + info->deviceId = info->devicePk->getLongId().toString(); info->announce = std::move(announce); info->ethAccount = root["eth"].asString(); info->username = username; @@ -212,6 +213,7 @@ AccountManager::startSync(const OnNewDeviceCb& cb, const OnDeviceAnnouncedCb& dc for (const auto& crl : info_->identity.second->issuer->getRevocationLists()) dht_->put(h, crl, dht::DoneCallback {}, {}, true); dht_->listen<DeviceAnnouncement>(h, [this, cb = std::move(cb)](DeviceAnnouncement&& dev) { + // dev.from findCertificate(dev.dev, [this, cb](const std::shared_ptr<dht::crypto::Certificate>& crt) { foundAccountDevice(crt); @@ -235,13 +237,13 @@ AccountManager::startSync(const OnNewDeviceCb& cb, const OnDeviceAnnouncedCb& dc JAMI_WARN("can't announce device: no announcement..."); } - auto inboxKey = dht::InfoHash::get("inbox:" + info_->deviceId); + auto inboxKey = dht::InfoHash::get("inbox:" + info_->devicePk->getId().toString()); dht_->listen<dht::TrustRequest>(inboxKey, [this](dht::TrustRequest&& v) { if (v.service != DHT_TYPE_NS) return true; // allowPublic always true for trust requests (only forbidden if banned) - onPeerMessage(v.from, + onPeerMessage(*v.owner, true, [this, v](const std::shared_ptr<dht::crypto::Certificate>&, dht::InfoHash peer_account) mutable { @@ -251,7 +253,7 @@ AccountManager::startSync(const OnNewDeviceCb& cb, const OnDeviceAnnouncedCb& dc v.conversationId.c_str()); if (info_) if (info_->contacts->onTrustRequest(peer_account, - v.from, + v.owner, time(nullptr), v.confirm, v.conversationId, @@ -264,7 +266,7 @@ AccountManager::startSync(const OnNewDeviceCb& cb, const OnDeviceAnnouncedCb& dc }); } -const std::map<dht::InfoHash, KnownDevice>& +const std::map<dht::PkId, KnownDevice>& AccountManager::getKnownDevices() const { return info_->contacts->getKnownDevices(); @@ -282,14 +284,14 @@ void AccountManager::setAccountDeviceName(const std::string& name) { if (info_) - info_->contacts->setAccountDeviceName(dht::InfoHash(info_->deviceId), name); + info_->contacts->setAccountDeviceName(DeviceId(info_->deviceId), name); } std::string AccountManager::getAccountDeviceName() const { if (info_) - return info_->contacts->getAccountDeviceName(dht::InfoHash(info_->deviceId)); + return info_->contacts->getAccountDeviceName(DeviceId(info_->deviceId)); return {}; } @@ -334,7 +336,7 @@ AccountManager::foundPeerDevice(const std::shared_ptr<dht::crypto::Certificate>& } void -AccountManager::onPeerMessage(const dht::InfoHash& peer_device, +AccountManager::onPeerMessage(const dht::crypto::PublicKey& peer_device, bool allowPublic, std::function<void(const std::shared_ptr<dht::crypto::Certificate>& crt, const dht::InfoHash& peer_account)>&& cb) @@ -346,8 +348,8 @@ AccountManager::onPeerMessage(const dht::InfoHash& peer_device, return; } - findCertificate(peer_device, - [this, peer_device, cb = std::move(cb), allowPublic]( + findCertificate(peer_device.getId(), + [this, cb = std::move(cb), allowPublic]( const std::shared_ptr<dht::crypto::Certificate>& cert) { dht::InfoHash peer_account_id; if (onPeerCertificate(cert, allowPublic, peer_account_id)) { @@ -576,6 +578,26 @@ AccountManager::findCertificate( return true; } +bool +AccountManager::findCertificate( + const dht::PkId& id, std::function<void(const std::shared_ptr<dht::crypto::Certificate>&)>&& cb) +{ + if (auto cert = tls::CertificateStore::instance().getCertificate(id.toString())) { + if (cb) + cb(cert); + } else { + /*dht_->findCertificate(id, [cb](const std::shared_ptr<dht::crypto::Certificate>& crt) { + if (crt) + tls::CertificateStore::instance().pinCertificate(crt); + if (cb) + cb(crt); + });*/ + if (cb) + cb(nullptr); + } + return true; +} + bool AccountManager::setCertificateStatus(const std::string& cert_id, tls::TrustStore::PermissionStatus status) @@ -656,14 +678,15 @@ AccountManager::sendTrustRequest(const std::string& to, if (info_->contacts->addContact(toH, false, convId)) { syncDevices(); } - forEachDevice(toH, [this, toH, convId, payload](const dht::InfoHash& dev) { - JAMI_WARN("sending trust request to: %s / %s", - toH.toString().c_str(), - dev.toString().c_str()); - dht_->putEncrypted(dht::InfoHash::get("inbox:" + dev.toString()), - dev, - dht::TrustRequest(DHT_TYPE_NS, convId, payload)); - }); + forEachDevice(toH, + [this, toH, convId, payload](const std::shared_ptr<dht::crypto::PublicKey>& dev) { + JAMI_WARN("sending trust request to: %s / %s", + toH.toString().c_str(), + dev->getLongId().toString().c_str()); + dht_->putEncrypted(dht::InfoHash::get("inbox:" + dev->getId().toString()), + dev, + dht::TrustRequest(DHT_TYPE_NS, convId, payload)); + }); } void @@ -677,18 +700,21 @@ AccountManager::sendTrustRequestConfirm(const dht::InfoHash& toH, const std::str if (!convId.empty() && info_) info_->contacts->acceptConversation(convId); - forEachDevice(toH, [this, toH, answer](const dht::InfoHash& dev) { + forEachDevice(toH, [this, toH, answer](const std::shared_ptr<dht::crypto::PublicKey>& dev) { JAMI_WARN("sending trust request reply: %s / %s", toH.toString().c_str(), - dev.toString().c_str()); - dht_->putEncrypted(dht::InfoHash::get("inbox:" + dev.toString()), dev, answer); + dev->getLongId().toString().c_str()); + dht_->putEncrypted(dht::InfoHash::get("inbox:" + info_->devicePk->getId().toString()), + dev, + answer); }); } void -AccountManager::forEachDevice(const dht::InfoHash& to, - std::function<void(const dht::InfoHash&)>&& op, - std::function<void(bool)>&& end) +AccountManager::forEachDevice( + const dht::InfoHash& to, + std::function<void(const std::shared_ptr<dht::crypto::PublicKey>&)>&& op, + std::function<void(bool)>&& end) { if (not dht_) { JAMI_ERR("forEachDevice: no dht"); @@ -696,26 +722,63 @@ AccountManager::forEachDevice(const dht::InfoHash& to, end(false); return; } - auto treatedDevices = std::make_shared<std::set<dht::InfoHash>>(); dht_->get<dht::crypto::RevocationList>(to, [to](dht::crypto::RevocationList&& crl) { tls::CertificateStore::instance().pinRevocationList(to.toString(), std::move(crl)); return true; }); + + struct State + { + unsigned remaining {0}; + std::set<dht::PkId> treatedDevices {}; + std::function<void(const std::shared_ptr<dht::crypto::PublicKey>&)> onDevice; + std::function<void(bool)> onEnd; + + void found(std::shared_ptr<dht::crypto::PublicKey> pk) + { + remaining--; + if (pk && *pk) { + auto longId = pk->getLongId(); + if (treatedDevices.emplace(longId).second) { + onDevice(pk); + } + } + ended(); + } + + void ended() + { + if (remaining == 0 && onEnd) { + JAMI_DBG("Found %lu devices", treatedDevices.size()); + onEnd(not treatedDevices.empty()); + onDevice = {}; + onEnd = {}; + } + } + }; + auto state = std::make_shared<State>(); + state->onDevice = std::move(op); + state->onEnd = std::move(end); + dht_->get<DeviceAnnouncement>( to, - [to, treatedDevices, op = std::move(op)](DeviceAnnouncement&& dev) { + [this, to, state](DeviceAnnouncement&& dev) { if (dev.from != to) return true; - if (treatedDevices->emplace(dev.dev).second) { - op(dev.dev); + if (dev.pk) { + state->found(std::move(dev.pk)); + } else { + state->remaining++; + findCertificate(dev.dev, + [state](const std::shared_ptr<dht::crypto::Certificate>& cert) { + state->found(cert ? std::make_shared<dht::crypto::PublicKey>( + cert->getPublicKey()) + : std::shared_ptr<dht::crypto::PublicKey> {}); + }); } return true; }, - [=, end = std::move(end)](bool /*ok*/) { - JAMI_DBG("Found %lu devices for %s", treatedDevices->size(), to.to_c_str()); - if (end) - end(not treatedDevices->empty()); - }); + [state](bool /*ok*/) { state->ended(); }); } void diff --git a/src/jamidht/account_manager.h b/src/jamidht/account_manager.h index 2638004510860c7f5e037fd53a20a9a06468213a..0c751e60e7238e743f965798be4cb062ff760c97 100644 --- a/src/jamidht/account_manager.h +++ b/src/jamidht/account_manager.h @@ -40,6 +40,7 @@ class DhtRunner; namespace jami { +using DeviceId = dht::PkId; struct AccountArchive; struct AccountInfo @@ -50,6 +51,7 @@ struct AccountInfo std::map<std::string, ConversationRequest> conversationsRequests; std::string accountId; std::string deviceId; + std::shared_ptr<dht::crypto::PublicKey> devicePk; std::shared_ptr<dht::Value> announce; std::string ethAccount; std::string username; @@ -166,7 +168,7 @@ public: return false; }; - const std::map<dht::InfoHash, KnownDevice>& getKnownDevices() const; + const std::map<dht::PkId, KnownDevice>& getKnownDevices() const; bool foundAccountDevice(const std::shared_ptr<dht::crypto::Certificate>& crt, const std::string& name = {}, const time_point& last_sync = time_point::min()); @@ -175,12 +177,12 @@ public: std::string getAccountDeviceName() const; void forEachDevice(const dht::InfoHash& to, - std::function<void(const dht::InfoHash&)>&& op, + std::function<void(const std::shared_ptr<dht::crypto::PublicKey>&)>&& op, std::function<void(bool)>&& end = {}); using PeerCertificateCb = std::function<void(const std::shared_ptr<dht::crypto::Certificate>& crt, const dht::InfoHash& peer_account)>; - void onPeerMessage(const dht::InfoHash& peer_device, bool allowPublic, PeerCertificateCb&& cb); + void onPeerMessage(const dht::crypto::PublicKey& peer_device, bool allowPublic, PeerCertificateCb&& cb); bool onPeerCertificate(const std::shared_ptr<dht::crypto::Certificate>& crt, bool allowPublic, dht::InfoHash& account_id); @@ -237,6 +239,11 @@ public: virtual bool findCertificate( const dht::InfoHash& h, std::function<void(const std::shared_ptr<dht::crypto::Certificate>&)>&& cb = {}); + + virtual bool findCertificate( + const dht::PkId& h, + std::function<void(const std::shared_ptr<dht::crypto::Certificate>&)>&& cb = {}); + bool setCertificateStatus(const std::string& cert_id, tls::TrustStore::PermissionStatus status); std::vector<std::string> getCertificatesByStatus(tls::TrustStore::PermissionStatus status); tls::TrustStore::PermissionStatus getCertificateStatus(const std::string& cert_id) const; diff --git a/src/jamidht/archive_account_manager.cpp b/src/jamidht/archive_account_manager.cpp index 612c9af846d7c9e5dc9866cdd3bc12353b959f0c..28249e94e4917df8d95a92330900cf5e50dfadb7 100644 --- a/src/jamidht/archive_account_manager.cpp +++ b/src/jamidht/archive_account_manager.cpp @@ -341,7 +341,8 @@ ArchiveAccountManager::onArchiveLoaded(AuthContext& ctx, AccountArchive&& a) info->identity.first = ctx.key.get(); info->identity.second = deviceCertificate; info->accountId = a.id.second->getId().toString(); - info->deviceId = deviceCertificate->getPublicKey().getId().toString(); + info->devicePk = info->identity.first->getSharedPublicKey(); + info->deviceId = info->devicePk->getLongId().toString(); if (ctx.deviceName.empty()) ctx.deviceName = info->deviceId.substr(8); @@ -399,12 +400,16 @@ ArchiveAccountManager::makeReceipt(const dht::crypto::Identity& id, auto devId = device.getId(); DeviceAnnouncement announcement; announcement.dev = devId; + announcement.pk = std::make_shared<dht::crypto::PublicKey>(device.getPublicKey()); dht::Value ann_val {announcement}; ann_val.sign(*id.first); + auto packedAnnoucement = ann_val.getPacked(); + JAMI_DBG("[Auth] device announcement size: %zu", packedAnnoucement.size()); + std::ostringstream is; is << "{\"id\":\"" << id.second->getId() << "\",\"dev\":\"" << devId << "\",\"eth\":\"" - << ethAccount << "\",\"announce\":\"" << base64::encode(ann_val.getPacked()) << "\"}"; + << ethAccount << "\",\"announce\":\"" << base64::encode(packedAnnoucement) << "\"}"; // auto announce_ = ; return {is.str(), std::make_shared<dht::Value>(std::move(ann_val))}; @@ -444,11 +449,12 @@ ArchiveAccountManager::syncDevices() // don't send sync data to ourself if (dev.first.toString() == info_->deviceId) continue; + auto pk = std::make_shared<dht::crypto::PublicKey>(dev.second.certificate->getPublicKey()); JAMI_DBG("sending device sync to %s %s", dev.second.name.c_str(), dev.first.toString().c_str()); - auto syncDeviceKey = dht::InfoHash::get("inbox:" + dev.first.toString()); - dht_->putEncrypted(syncDeviceKey, dev.first, sync_data); + auto syncDeviceKey = dht::InfoHash::get("inbox:" + pk->getId().toString()); + dht_->putEncrypted(syncDeviceKey, pk, sync_data); } } @@ -457,23 +463,26 @@ ArchiveAccountManager::startSync(const OnNewDeviceCb& cb, const OnDeviceAnnounce { AccountManager::startSync(std::move(cb), std::move(dcb)); - dht_->listen<DeviceSync>(dht::InfoHash::get("inbox:" + info_->deviceId), [this](DeviceSync&& sync) { - // Received device sync data. - // check device certificate - findCertificate(sync.from, - [this, sync](const std::shared_ptr<dht::crypto::Certificate>& cert) mutable { - if (!cert or cert->getId() != sync.from) { - JAMI_WARN("Can't find certificate for device %s", - sync.from.toString().c_str()); - return; - } - if (not foundAccountDevice(cert)) - return; - onSyncData(std::move(sync)); - }); + dht_->listen<DeviceSync>( + dht::InfoHash::get("inbox:" + info_->devicePk->getId().toString()), + [this](DeviceSync&& sync) { + // Received device sync data. + // check device certificate + findCertificate(sync.from, + [this, + sync](const std::shared_ptr<dht::crypto::Certificate>& cert) mutable { + if (!cert or cert->getId() != sync.from) { + JAMI_WARN("Can't find certificate for device %s", + sync.from.toString().c_str()); + return; + } + if (not foundAccountDevice(cert)) + return; + onSyncData(std::move(sync)); + }); - return true; - }); + return true; + }); } void @@ -482,14 +491,14 @@ ArchiveAccountManager::onSyncData(DeviceSync&& sync, bool checkDevice) auto sync_date = clock::time_point(clock::duration(sync.date)); if (checkDevice) { // If the DHT is used, we need to check the device here - if (not info_->contacts->syncDevice(sync.from, sync_date)) { + if (not info_->contacts->syncDevice(sync.owner->getLongId(), sync_date)) { return; } } // Sync known devices JAMI_DBG("[Contacts] received device sync data (%lu devices, %lu contacts)", - sync.devices_known.size(), + sync.devices_known.size() + sync.devices.size(), sync.peers.size()); for (const auto& d : sync.devices_known) { findCertificate(d.first, [this, d](const std::shared_ptr<dht::crypto::Certificate>& crt) { @@ -499,6 +508,15 @@ ArchiveAccountManager::onSyncData(DeviceSync&& sync, bool checkDevice) foundAccountDevice(crt, d.second); }); } + for (const auto& d : sync.devices) { + findCertificate(d.second.sha1, + [this, d](const std::shared_ptr<dht::crypto::Certificate>& crt) { + if (not crt || crt->getLongId() != d.first) + return; + // std::lock_guard<std::mutex> lock(deviceListMutex_); + foundAccountDevice(crt, d.second.name); + }); + } // saveKnownDevices(); // Sync contacts @@ -702,7 +720,7 @@ ArchiveAccountManager::revokeDevice(const std::string& password, tls::CertificateStore::instance().loadRevocations(*a.id.second); this_.saveArchive(a, password); - this_.info_->contacts->removeAccountDevice(crt->getId()); + this_.info_->contacts->removeAccountDevice(crt->getLongId()); cb(RevokeDeviceResult::SUCCESS); this_.syncDevices(); }); diff --git a/src/jamidht/connectionmanager.cpp b/src/jamidht/connectionmanager.cpp index 437bbf667c47f8714b110a0d0645d9d84539f508..a25799167035e52afead23281a2cd477ce1d570b 100644 --- a/src/jamidht/connectionmanager.cpp +++ b/src/jamidht/connectionmanager.cpp @@ -109,7 +109,7 @@ public: dht::Value::Id vid; }; - void connectDeviceStartIce(const DeviceId& deviceId, const dht::Value::Id& vid); + void connectDeviceStartIce(const std::shared_ptr<dht::crypto::PublicKey>& devicePk, const dht::Value::Id& vid); void connectDeviceOnNegoDone(const DeviceId& deviceId, const std::string& name, const dht::Value::Id& vid, @@ -136,7 +136,7 @@ public: /** * Triggered when a PeerConnectionRequest comes from the DHT */ - void answerTo(IceTransport& ice, const dht::Value::Id& id, const DeviceId& from); + void answerTo(IceTransport& ice, const dht::Value::Id& id, const std::shared_ptr<dht::crypto::PublicKey>& fromPk); void onRequestStartIce(const PeerConnectionRequest& req); void onRequestOnNegoDone(const PeerConnectionRequest& req); void onDhtPeerRequest(const PeerConnectionRequest& req, @@ -144,7 +144,7 @@ public: void addNewMultiplexedSocket(const DeviceId& deviceId, const dht::Value::Id& vid); void onPeerResponse(const PeerConnectionRequest& req); - void onDhtConnected(const DeviceId& deviceId); + void onDhtConnected(const dht::crypto::PublicKey& devicePk); /** * Triggered when a new TLS socket is ready to use @@ -262,8 +262,9 @@ public: }; void -ConnectionManager::Impl::connectDeviceStartIce(const DeviceId& deviceId, const dht::Value::Id& vid) +ConnectionManager::Impl::connectDeviceStartIce(const std::shared_ptr<dht::crypto::PublicKey>& devicePk, const dht::Value::Id& vid) { + auto deviceId = devicePk->getLongId(); auto info = getInfo(deviceId, vid); if (!info) { return; @@ -305,8 +306,8 @@ ConnectionManager::Impl::connectDeviceStartIce(const DeviceId& deviceId, const d // Send connection request through DHT JAMI_DBG() << account << "Request connection to " << deviceId; account.dht()->putEncrypted(dht::InfoHash::get(PeerConnectionRequest::key_prefix - + deviceId.toString()), - deviceId, + + devicePk->getId().toString()), + devicePk, value, [deviceId](bool ok) { if (!ok) @@ -396,7 +397,7 @@ ConnectionManager::Impl::connectDevice(const DeviceId& deviceId, [w = weak(), deviceId, name, cb = std::move(cb), noNewSocket]( const std::shared_ptr<dht::crypto::Certificate>& cert) { if (!cert) { - JAMI_ERR("Invalid certificate found for device %s", + JAMI_ERR("No valid certificate found for device %s", deviceId.to_c_str()); cb(nullptr, deviceId); return; @@ -419,7 +420,8 @@ ConnectionManager::Impl::connectDevice(const std::shared_ptr<dht::crypto::Certif cert = std::move(cert), cb = std::move(cb), noNewSocket] { - auto deviceId = cert->getId(); + auto devicePk = std::make_shared<dht::crypto::PublicKey>(cert->getPublicKey()); + auto deviceId = devicePk->getLongId(); auto sthis = w.lock(); if (!sthis || sthis->isDestroying_) { cb(nullptr, deviceId); @@ -488,6 +490,7 @@ ConnectionManager::Impl::connectDevice(const std::shared_ptr<dht::crypto::Certif // If no socket exists, we need to initiate an ICE connection. sthis->account.getIceOptions([w, deviceId = std::move(deviceId), + devicePk = std::move(devicePk), name = std::move(name), cert = std::move(cert), vid, @@ -498,6 +501,7 @@ ConnectionManager::Impl::connectDevice(const std::shared_ptr<dht::crypto::Certif ice_config.tcpEnable = true; ice_config.onInitDone = [w, deviceId = std::move(deviceId), + devicePk = std::move(devicePk), name = std::move(name), cert = std::move(cert), vid, @@ -514,9 +518,9 @@ ConnectionManager::Impl::connectDevice(const std::shared_ptr<dht::crypto::Certif } dht::ThreadPool::io().run( - [w = std::move(w), deviceId = std::move(deviceId), vid = std::move(vid)] { + [w = std::move(w), devicePk = std::move(devicePk), vid = std::move(vid)] { if (auto sthis = w.lock()) - sthis->connectDeviceStartIce(deviceId, vid); + sthis->connectDeviceStartIce(devicePk, vid); }); }; ice_config.onNegoDone = [w, @@ -607,7 +611,7 @@ ConnectionManager::Impl::sendChannelRequest(std::shared_ptr<MultiplexedSocket>& void ConnectionManager::Impl::onPeerResponse(const PeerConnectionRequest& req) { - auto device = req.from; + auto device = req.owner->getLongId(); JAMI_INFO() << account << " New response received from " << device.to_c_str(); if (auto info = getInfo(device, req.id)) { std::lock_guard<std::mutex> lk {info->mutex_}; @@ -620,12 +624,12 @@ ConnectionManager::Impl::onPeerResponse(const PeerConnectionRequest& req) } void -ConnectionManager::Impl::onDhtConnected(const DeviceId& deviceId) +ConnectionManager::Impl::onDhtConnected(const dht::crypto::PublicKey& devicePk) { if (!account.dht()) return; account.dht()->listen<PeerConnectionRequest>( - dht::InfoHash::get(PeerConnectionRequest::key_prefix + deviceId.toString()), + dht::InfoHash::get(PeerConnectionRequest::key_prefix + devicePk.getId().toString()), [w = weak()](PeerConnectionRequest&& req) { auto shared = w.lock(); if (!shared) @@ -635,9 +639,9 @@ ConnectionManager::Impl::onDhtConnected(const DeviceId& deviceId) return true; } if (req.isAnswer) { - JAMI_DBG() << "Received request answer from " << req.from; + JAMI_DBG() << "Received request answer from " << req.owner->getLongId(); } else { - JAMI_DBG() << "Received request from " << req.from; + JAMI_DBG() << "Received request from " << req.owner->getLongId(); } // Hack: // Note: This reschedule on the io pool should not be necessary @@ -666,7 +670,7 @@ ConnectionManager::Impl::onDhtConnected(const DeviceId& deviceId) } else { JAMI_WARN() << shared->account - << "Rejected untrusted connection request from " << req.from; + << "Rejected untrusted connection request from " << req.owner->getLongId(); } }); } @@ -728,7 +732,7 @@ ConnectionManager::Impl::onTlsNegotiationDone(bool ok, } void -ConnectionManager::Impl::answerTo(IceTransport& ice, const dht::Value::Id& id, const DeviceId& from) +ConnectionManager::Impl::answerTo(IceTransport& ice, const dht::Value::Id& id, const std::shared_ptr<dht::crypto::PublicKey>& from) { // NOTE: This is a shortest version of a real SDP message to save some bits auto iceAttributes = ice.getLocalAttributes(); @@ -747,22 +751,23 @@ ConnectionManager::Impl::answerTo(IceTransport& ice, const dht::Value::Id& id, c auto value = std::make_shared<dht::Value>(std::move(val)); value->user_type = "peer_request"; - JAMI_DBG() << account << "[CNX] connection accepted, DHT reply to " << from; + JAMI_DBG() << account << "[CNX] connection accepted, DHT reply to " << from->getLongId(); account.dht()->putEncrypted( - dht::InfoHash::get(PeerConnectionRequest::key_prefix + from.toString()), + dht::InfoHash::get(PeerConnectionRequest::key_prefix + from->getId().toString()), from, value, [from](bool ok) { if (!ok) JAMI_ERR("Tried to answer to connection request from %s, but put failed", - from.to_c_str()); + from->getLongId().to_c_str()); }); } void ConnectionManager::Impl::onRequestStartIce(const PeerConnectionRequest& req) { - auto info = getInfo(req.from, req.id); + auto deviceId = req.owner->getLongId(); + auto info = getInfo(deviceId, req.id); if (!info) return; @@ -771,17 +776,17 @@ ConnectionManager::Impl::onRequestStartIce(const PeerConnectionRequest& req) if (!ice) { JAMI_ERR("No ICE detected"); if (connReadyCb_) - connReadyCb_(req.from, "", nullptr); + connReadyCb_(deviceId, "", nullptr); return; } auto sdp = ice->parseIceCandidates(req.ice_msg); - answerTo(*ice, req.id, req.from); + answerTo(*ice, req.id, req.owner); if (not ice->startIce({sdp.rem_ufrag, sdp.rem_pwd}, std::move(sdp.rem_candidates))) { JAMI_ERR("[Account:%s] start ICE failed - fallback to TURN", account.getAccountID().c_str()); ice = nullptr; if (connReadyCb_) - connReadyCb_(req.from, "", nullptr); + connReadyCb_(deviceId, "", nullptr); return; } } @@ -789,7 +794,8 @@ ConnectionManager::Impl::onRequestStartIce(const PeerConnectionRequest& req) void ConnectionManager::Impl::onRequestOnNegoDone(const PeerConnectionRequest& req) { - auto info = getInfo(req.from, req.id); + auto deviceId = req.owner->getLongId(); + auto info = getInfo(deviceId, req.id); if (!info) return; @@ -798,7 +804,7 @@ ConnectionManager::Impl::onRequestOnNegoDone(const PeerConnectionRequest& req) if (!ice) { JAMI_ERR("No ICE detected"); if (connReadyCb_) - connReadyCb_(req.from, "", nullptr); + connReadyCb_(deviceId, "", nullptr); return; } @@ -826,7 +832,7 @@ ConnectionManager::Impl::onRequestOnNegoDone(const PeerConnectionRequest& req) }); info->tls_->setOnReady( - [w = weak(), deviceId = std::move(req.from), vid = std::move(req.id)](bool ok) { + [w = weak(), deviceId = std::move(deviceId), vid = std::move(req.id)](bool ok) { if (auto shared = w.lock()) shared->onTlsNegotiationDone(ok, deviceId, vid); }); @@ -836,39 +842,38 @@ void ConnectionManager::Impl::onDhtPeerRequest(const PeerConnectionRequest& req, const std::shared_ptr<dht::crypto::Certificate>& /*cert*/) { - auto deviceId = req.from.toString(); - JAMI_INFO() << account << "New connection requested by " << deviceId.c_str(); - if (!iceReqCb_ || !iceReqCb_(req.from)) { + auto deviceId = req.owner->getLongId(); + JAMI_INFO() << account << "New connection requested by " << deviceId; + if (!iceReqCb_ || !iceReqCb_(deviceId)) { JAMI_INFO("[Account:%s] refuse connection from %s", account.getAccountID().c_str(), - deviceId.c_str()); + deviceId.toString().c_str()); return; } // Because the connection is accepted, create an ICE socket. - account.getIceOptions([w = weak(), req](auto&& ice_config) { - auto deviceId = req.from.toString(); + account.getIceOptions([w = weak(), req, deviceId](auto&& ice_config) { auto shared = w.lock(); if (!shared) return; // Note: used when the ice negotiation fails to erase // all stored structures. - auto eraseInfo = [w, id = req.id, from = req.from] { + auto eraseInfo = [w, id = req.id, deviceId] { if (auto shared = w.lock()) { std::lock_guard<std::mutex> lk(shared->infosMtx_); - shared->infos_.erase({from, id}); + shared->infos_.erase({deviceId, id}); } }; ice_config.tcpEnable = true; - ice_config.onInitDone = [w, req, eraseInfo](bool ok) { + ice_config.onInitDone = [w, req, deviceId, eraseInfo](bool ok) { auto shared = w.lock(); if (!shared) return; if (!ok) { JAMI_ERR("Cannot initialize ICE session."); if (shared->connReadyCb_) - shared->connReadyCb_(req.from, "", nullptr); + shared->connReadyCb_(deviceId, "", nullptr); runOnMainThread([eraseInfo = std::move(eraseInfo)] { eraseInfo(); }); return; } @@ -881,14 +886,14 @@ ConnectionManager::Impl::onDhtPeerRequest(const PeerConnectionRequest& req, }); }; - ice_config.onNegoDone = [w, req, eraseInfo](bool ok) { + ice_config.onNegoDone = [w, req, eraseInfo, deviceId](bool ok) { auto shared = w.lock(); if (!shared) return; if (!ok) { JAMI_ERR("ICE negotiation failed"); if (shared->connReadyCb_) - shared->connReadyCb_(req.from, "", nullptr); + shared->connReadyCb_(deviceId, "", nullptr); runOnMainThread([eraseInfo = std::move(eraseInfo)] { eraseInfo(); }); return; } @@ -903,11 +908,11 @@ ConnectionManager::Impl::onDhtPeerRequest(const PeerConnectionRequest& req, auto info = std::make_shared<ConnectionInfo>(); { std::lock_guard<std::mutex> lk(shared->infosMtx_); - shared->infos_[{req.from, req.id}] = info; + shared->infos_[{deviceId, req.id}] = info; } JAMI_INFO("[Account:%s] accepting connection from %s", shared->account.getAccountID().c_str(), - deviceId.c_str()); + deviceId.toString().c_str()); std::unique_lock<std::mutex> lk {info->mutex_}; ice_config.streamsCount = JamiAccount::ICE_STREAMS_COUNT; ice_config.compCountPerStream = JamiAccount::ICE_COMP_COUNT_PER_STREAM; @@ -918,7 +923,7 @@ ConnectionManager::Impl::onDhtPeerRequest(const PeerConnectionRequest& req, if (not info->ice_) { JAMI_ERR("Cannot initialize ICE session."); if (shared->connReadyCb_) - shared->connReadyCb_(req.from, "", nullptr); + shared->connReadyCb_(deviceId, "", nullptr); eraseInfo(); } }); @@ -946,7 +951,7 @@ ConnectionManager::Impl::addNewMultiplexedSocket(const DeviceId& deviceId, const }); info->socket_->onShutdown([w = weak(), deviceId, vid]() { // Cancel current outgoing connections - dht::ThreadPool::io().run([w, deviceId = dht::InfoHash(deviceId), vid] { + dht::ThreadPool::io().run([w, deviceId, vid] { auto sthis = w.lock(); if (!sthis) return; @@ -1045,9 +1050,9 @@ ConnectionManager::closeConnectionsWith(const DeviceId& deviceId) } void -ConnectionManager::onDhtConnected(const DeviceId& deviceId) +ConnectionManager::onDhtConnected(const dht::crypto::PublicKey& devicePk) { - pimpl_->onDhtConnected(deviceId); + pimpl_->onDhtConnected(devicePk); } void diff --git a/src/jamidht/connectionmanager.h b/src/jamidht/connectionmanager.h index 8f2c649284908ff02de0ec0daa724dfefbc2e33f..7a7c95c5769ea7ac399f760b0eeb407c16dda7ae 100644 --- a/src/jamidht/connectionmanager.h +++ b/src/jamidht/connectionmanager.h @@ -114,7 +114,7 @@ public: * Method to call to listen to incoming requests * @param deviceId Account's device */ - void onDhtConnected(const DeviceId& deviceId); + void onDhtConnected(const dht::crypto::PublicKey& devicePk); /** * Add a callback to decline or accept incoming ICE connections diff --git a/src/jamidht/contact_list.cpp b/src/jamidht/contact_list.cpp index 36f5ba6c7de03153b0afeb2dd9f1c7272f557972..de114ca5e07c9837ac716f2243fbf80d930079e2 100644 --- a/src/jamidht/contact_list.cpp +++ b/src/jamidht/contact_list.cpp @@ -257,7 +257,7 @@ ContactList::loadTrustRequests() bool ContactList::onTrustRequest(const dht::InfoHash& peer_account, - const dht::InfoHash& peer_device, + const std::shared_ptr<dht::crypto::PublicKey>& peer_device, time_t received, bool confirm, const std::string& conversationId, @@ -383,38 +383,52 @@ ContactList::discardTrustRequest(const dht::InfoHash& from) void ContactList::loadKnownDevices() { - std::map<dht::InfoHash, std::pair<std::string, uint64_t>> knownDevices; try { // read file - auto file = fileutils::loadFile("knownDevicesNames", path_); + auto file = fileutils::loadFile("knownDevices", path_); // load values msgpack::object_handle oh = msgpack::unpack((const char*) file.data(), file.size()); + + std::map<dht::PkId, std::pair<std::string, uint64_t>> knownDevices; oh.get().convert(knownDevices); + for (const auto& d : knownDevices) { + /*JAMI_DBG("[Contacts] loading known account device %s %s", + d.second.first.c_str(), + d.first.toString().c_str());*/ + if (auto crt = tls::CertificateStore::instance().getCertificate(d.first.toString())) { + if (not foundAccountDevice(crt, d.second.first, clock::from_time_t(d.second.second))) + JAMI_WARN("[Contacts] can't add device %s", d.first.toString().c_str()); + } else { + JAMI_WARN("[Contacts] can't find certificate for device %s", d.first.toString().c_str()); + } + } } catch (const std::exception& e) { - JAMI_WARN("[Contacts] error loading devices: %s", e.what()); - return; - } - - for (const auto& d : knownDevices) { - /*JAMI_DBG("[Contacts] loading known account device %s %s", - d.second.first.c_str(), - d.first.toString().c_str());*/ - if (auto crt = tls::CertificateStore::instance().getCertificate(d.first.toString())) { - if (not foundAccountDevice(crt, d.second.first, clock::from_time_t(d.second.second))) - JAMI_WARN("[Contacts] can't add device %s", d.first.toString().c_str()); - } else { - JAMI_WARN("[Contacts] can't find certificate for device %s", d.first.toString().c_str()); + // Legacy fallback + try { + auto file = fileutils::loadFile("knownDevicesNames", path_); + msgpack::object_handle oh = msgpack::unpack((const char*) file.data(), file.size()); + std::map<dht::InfoHash, std::pair<std::string, uint64_t>> knownDevices; + oh.get().convert(knownDevices); + for (const auto& d : knownDevices) { + if (auto crt = tls::CertificateStore::instance().getCertificate(d.first.toString())) { + if (not foundAccountDevice(crt, d.second.first, clock::from_time_t(d.second.second))) + JAMI_WARN("[Contacts] can't add device %s", d.first.toString().c_str()); + } + } + } catch (const std::exception& e) { + JAMI_WARN("[Contacts] error loading devices: %s", e.what()); } + return; } } void ContactList::saveKnownDevices() const { - std::ofstream file(path_ + DIR_SEPARATOR_STR "knownDevicesNames", + std::ofstream file(path_ + DIR_SEPARATOR_STR "knownDevices", std::ios::trunc | std::ios::binary); - std::map<dht::InfoHash, std::pair<std::string, uint64_t>> devices; + std::map<dht::PkId, std::pair<std::string, uint64_t>> devices; for (const auto& id : knownDevices_) devices.emplace(id.first, std::make_pair(id.second.name, clock::to_time_t(id.second.last_sync))); @@ -423,7 +437,7 @@ ContactList::saveKnownDevices() const } void -ContactList::foundAccountDevice(const dht::InfoHash& device, +ContactList::foundAccountDevice(const dht::PkId& device, const std::string& name, const time_point& updated) { @@ -454,7 +468,7 @@ ContactList::foundAccountDevice(const std::shared_ptr<dht::crypto::Certificate>& if (not crt) return false; - auto id = crt->getId(); + auto id = crt->getLongId(); // match certificate chain auto verifyResult = accountTrust_.verify(*crt); @@ -472,18 +486,9 @@ ContactList::foundAccountDevice(const std::shared_ptr<dht::crypto::Certificate>& tls::CertificateStore::instance().pinCertificate(crt); if (crt->ocspResponse) { unsigned int status = crt->ocspResponse->getCertificateStatus(); - if (status == GNUTLS_OCSP_CERT_GOOD) { - JAMI_DBG("Certificate %s has good OCSP status", id.to_c_str()); - trust_.setCertificateStatus(id.toString(), - tls::TrustStore::PermissionStatus::ALLOWED); - } else if (status == GNUTLS_OCSP_CERT_REVOKED) { + if (status == GNUTLS_OCSP_CERT_REVOKED) { JAMI_ERR("Certificate %s has revoked OCSP status", id.to_c_str()); - trust_.setCertificateStatus(id.toString(), - tls::TrustStore::PermissionStatus::BANNED); - } else { - JAMI_ERR("Certificate %s has unknown OCSP status", id.to_c_str()); - trust_.setCertificateStatus(id.toString(), - tls::TrustStore::PermissionStatus::UNDEFINED); + trust_.setCertificateStatus(crt, tls::TrustStore::PermissionStatus::BANNED, false); } } saveKnownDevices(); @@ -501,7 +506,7 @@ ContactList::foundAccountDevice(const std::shared_ptr<dht::crypto::Certificate>& } bool -ContactList::removeAccountDevice(const dht::InfoHash& device) +ContactList::removeAccountDevice(const dht::PkId& device) { if (knownDevices_.erase(device) > 0) { saveKnownDevices(); @@ -511,7 +516,7 @@ ContactList::removeAccountDevice(const dht::InfoHash& device) } void -ContactList::setAccountDeviceName(const dht::InfoHash& device, const std::string& name) +ContactList::setAccountDeviceName(const dht::PkId& device, const std::string& name) { auto dev = knownDevices_.find(device); if (dev != knownDevices_.end()) { @@ -523,7 +528,7 @@ ContactList::setAccountDeviceName(const dht::InfoHash& device, const std::string } std::string -ContactList::getAccountDeviceName(const dht::InfoHash& device) const +ContactList::getAccountDeviceName(const dht::PkId& device) const { auto dev = knownDevices_.find(device); if (dev != knownDevices_.end()) { @@ -564,13 +569,15 @@ ContactList::getSyncData() const } for (const auto& dev : knownDevices_) { - sync_data.devices_known.emplace(dev.first, dev.second.name); + sync_data.devices.emplace(dev.second.certificate->getLongId(), KnownDeviceSync { + dev.second.name, dev.second.certificate->getId() + }); } return sync_data; } bool -ContactList::syncDevice(const dht::InfoHash& device, const time_point& syncDate) +ContactList::syncDevice(const dht::PkId& device, const time_point& syncDate) { auto it = knownDevices_.find(device); if (it == knownDevices_.end()) { diff --git a/src/jamidht/contact_list.h b/src/jamidht/contact_list.h index d394634724db1f2daacea995e6422dc07b212a2f..7fddb6196423bafe1f7c6f6f4b4d233f39c9b1e0 100644 --- a/src/jamidht/contact_list.h +++ b/src/jamidht/contact_list.h @@ -44,7 +44,7 @@ public: void(const std::string&, const std::string&, const std::vector<uint8_t>&, time_t)>; using OnAcceptConversation = std::function<void(const std::string&)>; using OnConfirmation = std::function<void(const std::string&, const std::string&)>; - using OnDevicesChanged = std::function<void(const std::map<dht::InfoHash, KnownDevice>&)>; + using OnDevicesChanged = std::function<void(const std::map<dht::PkId, KnownDevice>&)>; struct OnChangeCallback { @@ -74,6 +74,7 @@ public: bool setCertificateStatus(const std::string& cert_id, const tls::TrustStore::PermissionStatus status); + bool setCertificateStatus(const std::shared_ptr<crypto::Certificate>& cert, tls::TrustStore::PermissionStatus status, bool local = true); @@ -112,7 +113,7 @@ public: /** Inform of a new contact request. Returns true if the request should be immediatly accepted * (already a contact) */ bool onTrustRequest(const dht::InfoHash& peer_account, - const dht::InfoHash& peer_device, + const std::shared_ptr<dht::crypto::PublicKey>& peer_device, time_t received, bool confirm, const std::string& conversationId, @@ -127,26 +128,28 @@ public: void saveTrustRequests() const; /* Devices */ - const std::map<dht::InfoHash, KnownDevice>& getKnownDevices() const { return knownDevices_; } - void foundAccountDevice(const dht::InfoHash& device, + const std::map<dht::PkId, KnownDevice>& getKnownDevices() const { return knownDevices_; } + void foundAccountDevice(const dht::PkId& device, const std::string& name = {}, const time_point& last_sync = time_point::min()); bool foundAccountDevice(const std::shared_ptr<dht::crypto::Certificate>& crt, const std::string& name = {}, const time_point& last_sync = time_point::min()); - bool removeAccountDevice(const dht::InfoHash& device); - void setAccountDeviceName(const dht::InfoHash& device, const std::string& name); - std::string getAccountDeviceName(const dht::InfoHash& device) const; + bool removeAccountDevice(const dht::PkId& device); + void setAccountDeviceName(const dht::PkId& device, const std::string& name); + std::string getAccountDeviceName(const dht::PkId& device) const; DeviceSync getSyncData() const; - bool syncDevice(const dht::InfoHash& device, const time_point& syncDate); + bool syncDevice(const dht::PkId& device, const time_point& syncDate); // void onSyncData(DeviceSync&& device); private: mutable std::mutex lock; std::map<dht::InfoHash, Contact> contacts_; std::map<dht::InfoHash, TrustRequest> trustRequests_; - std::map<dht::InfoHash, KnownDevice> knownDevices_; + std::map<dht::InfoHash, KnownDevice> knownDevicesLegacy_; + + std::map<dht::PkId, KnownDevice> knownDevices_; // Trust store with account main certificate as the only CA dht::crypto::TrustList accountTrust_; diff --git a/src/jamidht/conversationrepository.cpp b/src/jamidht/conversationrepository.cpp index 28455dbd50b4aaa838d3cae9283f155bbca63a39..1442f507a4b49504d2e5de7a4978796a937295ff 100644 --- a/src/jamidht/conversationrepository.cpp +++ b/src/jamidht/conversationrepository.cpp @@ -238,7 +238,7 @@ add_initial_files(GitRepository& repo, } // /devices - std::string devicePath = devicesPath + "/" + cert->getId().toString() + ".crt"; + std::string devicePath = devicesPath + "/" + deviceId + ".crt"; file = fileutils::ofstream(devicePath, std::ios::trunc | std::ios::binary); if (!file.is_open()) { JAMI_ERR("Could not write data to %s", devicePath.c_str()); diff --git a/src/jamidht/jami_contact.h b/src/jamidht/jami_contact.h index 357da962b2455a5eed73a26efe6130821f46f36a..2b3658d43182d9076c8de8fd1a1d40211405b36a 100644 --- a/src/jamidht/jami_contact.h +++ b/src/jamidht/jami_contact.h @@ -126,7 +126,7 @@ struct Contact struct TrustRequest { - dht::InfoHash device; + std::shared_ptr<dht::crypto::PublicKey> device; std::string conversationId; time_t received; std::vector<uint8_t> payload; @@ -141,7 +141,14 @@ private: public: static const constexpr dht::ValueType& TYPE = dht::ValueType::USER_DATA; dht::InfoHash dev; - MSGPACK_DEFINE_MAP(dev); + std::shared_ptr<dht::crypto::PublicKey> pk; + MSGPACK_DEFINE_MAP(dev, pk) +}; + +struct KnownDeviceSync { + std::string name; + dht::InfoHash sha1; + MSGPACK_DEFINE_MAP(name, sha1) }; struct DeviceSync : public dht::EncryptedValue<DeviceSync> @@ -149,10 +156,11 @@ struct DeviceSync : public dht::EncryptedValue<DeviceSync> static const constexpr dht::ValueType& TYPE = dht::ValueType::USER_DATA; uint64_t date; std::string device_name; - std::map<dht::InfoHash, std::string> devices_known; + std::map<dht::InfoHash, std::string> devices_known; // Legacy + std::map<dht::PkId, KnownDeviceSync> devices; std::map<dht::InfoHash, Contact> peers; std::map<dht::InfoHash, TrustRequest> trust_requests; - MSGPACK_DEFINE_MAP(date, device_name, devices_known, peers, trust_requests) + MSGPACK_DEFINE_MAP(date, device_name, devices_known, devices, peers, trust_requests) }; struct KnownDevice diff --git a/src/jamidht/jamiaccount.cpp b/src/jamidht/jamiaccount.cpp index d384a7be354d6cf326c217694dca49276eb8d602..d60053bd37c74b9f8a78ff914dee4b880306bcb3 100644 --- a/src/jamidht/jamiaccount.cpp +++ b/src/jamidht/jamiaccount.cpp @@ -212,7 +212,7 @@ struct JamiAccount::PendingConversationFetch struct JamiAccount::PendingMessage { - std::set<dht::InfoHash> to; + std::set<DeviceId> to; }; struct AccountPeerInfo @@ -677,15 +677,17 @@ JamiAccount::startOutgoingCall(const std::shared_ptr<SIPCall>& call, const std:: // Find listening devices for this account accountManager_->forEachDevice( peer_account, - [this, devices = std::move(devices), sendRequest](const DeviceId& dev) { + [this, devices = std::move(devices), sendRequest]( + const std::shared_ptr<dht::crypto::PublicKey>& dev) { // Test if already sent via a SIP transport - if (devices.find(dev) != devices.end()) + auto deviceId = dev->getLongId(); + if (devices.find(deviceId) != devices.end()) return; { std::lock_guard<std::mutex> lk(onConnectionClosedMtx_); - onConnectionClosed_[dev] = sendRequest; + onConnectionClosed_[deviceId] = sendRequest; } - sendRequest(dev, false); + sendRequest(deviceId, false); }, [wCall](bool ok) { if (not ok) { @@ -1177,7 +1179,7 @@ JamiAccount::loadAccount(const std::string& archive_password, reqMap); } }, - [this](const std::map<dht::InfoHash, KnownDevice>& devices) { + [this](const std::map<DeviceId, KnownDevice>& devices) { std::map<std::string, std::string> ids; for (auto& d : devices) { auto id = d.first.toString(); @@ -1927,9 +1929,21 @@ JamiAccount::trackPresence(const dht::InfoHash& h, BuddyInfo& buddy) } } } - if (needsSync) - sthis->requestSIPConnection(h.toString(), - dev.dev); // Both sides will sync conversations + if (needsSync) { + if (dev.pk) { + sthis->requestSIPConnection(h.toString(), dev.pk->getLongId()); + } else { + sthis->findCertificate( + dev.dev, + [sthis, h](const std::shared_ptr<dht::crypto::Certificate>& cert) { + if (cert) { + auto pk = std::make_shared<dht::crypto::PublicKey>( + cert->getPublicKey()); + sthis->requestSIPConnection(h.toString(), pk->getLongId()); + } + }); + } + } } if (isConnected and not wasConnected) { sthis->onTrackedBuddyOnline(h); @@ -1985,7 +1999,7 @@ JamiAccount::onTrackedBuddyOffline(const dht::InfoHash& contactId) } void -JamiAccount::syncConversations(const std::string& peer, const std::string& deviceId) +JamiAccount::syncConversations(const std::string& peer, const DeviceId& deviceId) { // Sync conversations where peer is member std::set<std::string> toFetch; @@ -2171,7 +2185,7 @@ JamiAccount::doRegister_() [this](const std::shared_ptr<dht::crypto::Certificate>& crt) { if (!crt) return; - auto deviceId = crt->getId().toString(); + auto deviceId = crt->getLongId().toString(); if (accountManager_->getInfo()->deviceId == deviceId) return; @@ -2179,7 +2193,7 @@ JamiAccount::doRegister_() if (!connectionManager_) connectionManager_ = std::make_unique<ConnectionManager>(*this); auto channelName = "sync://" + deviceId; - if (connectionManager_->isConnecting(crt->getId(), channelName)) { + if (connectionManager_->isConnecting(crt->getLongId(), channelName)) { JAMI_INFO("[Account %s] Already connecting to %s", getAccountID().c_str(), deviceId.c_str()); @@ -2190,7 +2204,7 @@ JamiAccount::doRegister_() [this](std::shared_ptr<ChannelSocket> socket, const DeviceId& deviceId) { if (socket) - syncWith(deviceId.toString(), socket); + syncWith(deviceId, socket); }); }, [this] { @@ -2211,7 +2225,7 @@ JamiAccount::doRegister_() std::unique_lock<std::mutex> lkCM(connManagerMtx_); if (!connectionManager_) connectionManager_ = std::make_unique<ConnectionManager>(*this); - connectionManager_->onDhtConnected(DeviceId(accountManager_->getInfo()->deviceId)); + connectionManager_->onDhtConnected(*accountManager_->getInfo()->devicePk); connectionManager_->onICERequest([this](const DeviceId& deviceId) { std::promise<bool> accept; std::future<bool> fut = accept.get_future(); @@ -2358,9 +2372,17 @@ JamiAccount::doRegister_() auto sep = name.find_last_of('/'); auto conversationId = name.substr(sep + 1); auto remoteDevice = name.substr(6, sep - 6); - auto currentDevice = currentDeviceId(); - if (remoteDevice != currentDevice || currentDevice == deviceId.to_c_str()) { - // Check if wanted remote it's our side (git://removeDevice/conversationId) + + auto isServer = false; + if (!DeviceId(remoteDevice)) { + // This means that the remoteDevice is a short Id, so with a non up-to-date client + isServer = remoteDevice + == accountManager_->getInfo()->devicePk->getId().toString(); + } else { + isServer = remoteDevice == currentDeviceId(); + } + if (!isServer || currentDeviceId() == deviceId.to_c_str()) { + // Check if wanted remote it's our side (git://remoteDevice/conversationId) return; } JAMI_WARN("[Account %s] New channel asked from %s with name %s", @@ -2390,7 +2412,7 @@ JamiAccount::doRegister_() } } - auto sock = gitSocket(deviceId.toString(), conversationId); + auto sock = gitSocket(deviceId, conversationId); if (sock != std::nullopt && sock->lock() == channel) { // The onConnectionReady is already used as client (for retrieving messages) // So it's not the server socket @@ -2492,29 +2514,38 @@ JamiAccount::doRegister_() lkCM.unlock(); // Note: this code should be unused unless for DHT text messages - auto inboxDeviceKey = dht::InfoHash::get("inbox:" + accountManager_->getInfo()->deviceId); + auto inboxDeviceKey = dht::InfoHash::get( + "inbox:" + accountManager_->getInfo()->devicePk->getId().toString()); dht_->listen<dht::ImMessage>(inboxDeviceKey, [this, inboxDeviceKey](dht::ImMessage&& v) { auto msgId = to_hex_string(v.id); if (isMessageTreated(msgId)) return true; - accountManager_->onPeerMessage( - v.from, - dhtPublicInCalls_, - [this, v, inboxDeviceKey, msgId](const std::shared_ptr<dht::crypto::Certificate>&, - const dht::InfoHash& peer_account) { - auto now = clock::to_time_t(clock::now()); - std::string datatype = utf8_make_valid(v.datatype); - if (datatype.empty()) { - datatype = "text/plain"; - } - std::map<std::string, std::string> payloads = { - {datatype, utf8_make_valid(v.msg)}}; - onTextMessage(msgId, peer_account.toString(), payloads); - JAMI_DBG() << "Sending message confirmation " << v.id; - dht_->putEncrypted(inboxDeviceKey, - v.from, - dht::ImMessage(v.id, std::string(), now)); - }); + accountManager_ + ->onPeerMessage(*v.owner, + dhtPublicInCalls_, + [this, + v, + inboxDeviceKey, + msgId](const std::shared_ptr<dht::crypto::Certificate>& cert, + const dht::InfoHash& peer_account) { + auto now = clock::to_time_t(clock::now()); + std::string datatype = utf8_make_valid(v.datatype); + if (datatype.empty()) { + datatype = "text/plain"; + } + std::map<std::string, std::string> payloads = { + {datatype, utf8_make_valid(v.msg)}}; + auto pk = std::make_shared<dht::crypto::PublicKey>( + cert->getPublicKey()); + onTextMessage(msgId, + peer_account.toString(), + pk->getLongId().toString(), + payloads); + JAMI_DBG() << "Sending message confirmation " << v.id; + dht_->putEncrypted(inboxDeviceKey, + v.from, + dht::ImMessage(v.id, std::string(), now)); + }); return true; }); @@ -2535,11 +2566,12 @@ JamiAccount::doRegister_() void JamiAccount::onTextMessage(const std::string& id, const std::string& from, + const std::string& deviceId, const std::map<std::string, std::string>& payloads) { try { const std::string fromUri {parseJamiUri(from)}; - SIPAccountBase::onTextMessage(id, fromUri, payloads); + SIPAccountBase::onTextMessage(id, fromUri, deviceId, payloads); } catch (...) { } } @@ -2651,6 +2683,15 @@ JamiAccount::findCertificate( return false; } +bool +JamiAccount::findCertificate( + const dht::PkId& id, std::function<void(const std::shared_ptr<dht::crypto::Certificate>&)>&& cb) +{ + if (accountManager_) + return accountManager_->findCertificate(id, std::move(cb)); + return false; +} + bool JamiAccount::findCertificate(const std::string& crt_id) { @@ -2767,7 +2808,7 @@ JamiAccount::getKnownDevices() const if (not accountManager_ or not accountManager_->getInfo()) return {}; std::map<std::string, std::string> ids; - for (auto& d : accountManager_->getKnownDevices()) { + for (const auto& d : accountManager_->getKnownDevices()) { auto id = d.first.toString(); auto label = d.second.name.empty() ? id.substr(0, 8) : d.second.name; ids.emplace(std::move(id), std::move(label)); @@ -3166,7 +3207,7 @@ JamiAccount::sendTrustRequest(const std::string& to, const std::vector<uint8_t>& void JamiAccount::forEachDevice(const dht::InfoHash& to, - std::function<void(const dht::InfoHash&)>&& op, + std::function<void(const std::shared_ptr<dht::crypto::PublicKey>&)>&& op, std::function<void(bool)>&& end) { accountManager_->forEachDevice(to, std::move(op), std::move(end)); @@ -3304,24 +3345,26 @@ JamiAccount::sendTextMessage(const std::string& to, // Find listening devices for this account accountManager_->forEachDevice( toH, - [this, confirm, to, token, payloads, now, devices](const dht::InfoHash& dev) { + [this, confirm, to, token, payloads, now, devices]( + const std::shared_ptr<dht::crypto::PublicKey>& dev) { // Test if already sent - if (devices->find(dev) != devices->end()) { + auto deviceId = dev->getLongId(); + if (devices->find(deviceId) != devices->end()) { return; } - if (dev.toString() == currentDeviceId()) { - devices->emplace(dev); + if (deviceId.toString() == currentDeviceId()) { + devices->emplace(deviceId); return; } // Else, ask for a channel and send a DHT message - requestSIPConnection(to, dev); + requestSIPConnection(to, deviceId); { std::lock_guard<std::mutex> lock(messageMutex_); - sentMessages_[token].to.emplace(dev); + sentMessages_[token].to.emplace(deviceId); } - auto h = dht::InfoHash::get("inbox:" + dev.toString()); + auto h = dht::InfoHash::get("inbox:" + dev->getId().toString()); std::lock_guard<std::mutex> l(confirm->lock); auto list_token = dht_->listen<dht::ImMessage>(h, [this, to, token, confirm](dht::ImMessage&& msg) { @@ -3333,7 +3376,7 @@ JamiAccount::sendTextMessage(const std::string& to, std::lock_guard<std::mutex> lock(messageMutex_); auto e = sentMessages_.find(msg.id); if (e == sentMessages_.end() - or e->second.to.find(msg.from) == e->second.to.end()) { + or e->second.to.find(msg.owner->getLongId()) == e->second.to.end()) { JAMI_DBG() << "[Account " << getAccountID() << "] [message " << token << "] Message not found"; return true; @@ -3387,7 +3430,7 @@ JamiAccount::sendTextMessage(const std::string& to, }); JAMI_DBG() << "[Account " << getAccountID() << "] [message " << token - << "] Sending message for device " << dev.toString(); + << "] Sending message for device " << deviceId.toString(); }, [this, to, token, devices, confirm](bool ok) { if (devices->size() == 1 && devices->begin()->toString() == currentDeviceId()) { @@ -3691,29 +3734,32 @@ JamiAccount::acceptConversationRequest(const std::string& conversationId) JAMI_WARN("Invalid member detected: %s", request->from.c_str()); return; } - forEachDevice(memberHash, [this, request = *request](const dht::InfoHash& dev) { - if (dev == dht()->getId()) - return; - connectionManager().connectDevice( - dev, - "git://" + dev.toString() + "/" + request.conversationId, - [this, request](std::shared_ptr<ChannelSocket> socket, const DeviceId& dev) { - if (socket) { - std::unique_lock<std::mutex> lk(pendingConversationsFetchMtx_); - auto& pending = pendingConversationsFetch_[request.conversationId]; - if (!pending.ready) { - pending.ready = true; - pending.deviceId = dev.toString(); - lk.unlock(); - // Save the git socket - addGitSocket(dev.toString(), request.conversationId, socket); - } else { - lk.unlock(); - socket->shutdown(); - } - } - }); - }); + forEachDevice(memberHash, + [this, request = *request](const std::shared_ptr<dht::crypto::PublicKey>& dev) { + auto deviceId = dev->getLongId(); + if (deviceId == dht()->getPublicKey()->getLongId()) + return; + connectionManager().connectDevice( + deviceId, + "git://" + deviceId.toString() + "/" + request.conversationId, + [this, request](std::shared_ptr<ChannelSocket> socket, + const DeviceId& dev) { + if (socket) { + std::unique_lock<std::mutex> lk(pendingConversationsFetchMtx_); + auto& pending = pendingConversationsFetch_[request.conversationId]; + if (!pending.ready) { + pending.ready = true; + pending.deviceId = dev.toString(); + lk.unlock(); + // Save the git socket + addGitSocket(dev, request.conversationId, socket); + } else { + lk.unlock(); + socket->shutdown(); + } + } + }); + }); accountManager_->rmConversationRequest(conversationId); ConvInfo info; info.id = conversationId; @@ -4206,7 +4252,7 @@ JamiAccount::onNewGitCommit(const std::string& peer, peer.c_str(), conversationId.c_str(), commitId.c_str()); - fetchNewCommits(peer, deviceId, conversationId, commitId); + fetchNewCommits(peer, DeviceId(deviceId), conversationId, commitId); } void @@ -4223,14 +4269,14 @@ JamiAccount::onMessageDisplayed(const std::string& peer, void JamiAccount::fetchNewCommits(const std::string& peer, - const std::string& deviceId, + const DeviceId& deviceId, const std::string& conversationId, const std::string& commitId) { JAMI_DBG("[Account %s] fetch commits for peer %s on device %s", getAccountID().c_str(), peer.c_str(), - deviceId.c_str()); + deviceId.to_c_str()); std::unique_lock<std::mutex> lk(conversationsMtx_); auto conversation = conversations_.find(conversationId); @@ -4242,10 +4288,10 @@ JamiAccount::fetchNewCommits(const std::string& peer, conversationId.c_str()); return; } - if (conversation->second->isBanned(deviceId)) { + if (conversation->second->isBanned(deviceId.toString())) { JAMI_WARN("[Account %s] %s is a banned device in conversation %s", getAccountID().c_str(), - deviceId.c_str(), + deviceId.to_c_str(), conversationId.c_str()); return; } @@ -4260,7 +4306,7 @@ JamiAccount::fetchNewCommits(const std::string& peer, if (hasGitSocket(deviceId, conversationId)) { conversation->second->sync( peer, - deviceId, + deviceId.toString(), [peer, deviceId, conversationId, commitId, w = weak()](bool ok) { auto shared = w.lock(); if (!shared) @@ -4269,12 +4315,12 @@ JamiAccount::fetchNewCommits(const std::string& peer, JAMI_WARN("[Account %s] Could not fetch new commit from %s for %s, other " "peer may be disconnected", shared->getAccountID().c_str(), - deviceId.c_str(), + deviceId.to_c_str(), conversationId.c_str()); shared->removeGitSocket(deviceId, conversationId); JAMI_INFO("[Account %s] Relaunch sync with %s for %s", shared->getAccountID().c_str(), - deviceId.c_str(), + deviceId.to_c_str(), conversationId.c_str()); runOnMainThread([=]() { if (auto shared = w.lock()) @@ -4294,8 +4340,8 @@ JamiAccount::fetchNewCommits(const std::string& peer, if (!connectionManager_) return; connectionManager_->connectDevice( - DeviceId(deviceId), - "git://" + deviceId + "/" + conversationId, + deviceId, + "git://" + deviceId.toString() + "/" + conversationId, [this, conversationId, commitId, peer](std::shared_ptr<ChannelSocket> socket, const DeviceId& deviceId) { dht::ThreadPool::io().run([w = weak(), @@ -4312,7 +4358,7 @@ JamiAccount::fetchNewCommits(const std::string& peer, if (!conversation->second) return; if (socket) { - shared->addGitSocket(deviceId.toString(), conversationId, socket); + shared->addGitSocket(deviceId, conversationId, socket); conversation->second->sync( peer, @@ -4327,7 +4373,7 @@ JamiAccount::fetchNewCommits(const std::string& peer, shared->getAccountID().c_str(), deviceId.to_c_str(), conversationId.c_str()); - shared->removeGitSocket(deviceId.toString(), conversationId); + shared->removeGitSocket(deviceId, conversationId); } }, commitId); @@ -4545,7 +4591,7 @@ JamiAccount::cacheTurnServers() void JamiAccount::callConnectionClosed(const DeviceId& deviceId, bool eraseDummy) { - std::function<void(const dht::InfoHash&, bool)> cb; + std::function<void(const DeviceId&, bool)> cb; { std::lock_guard<std::mutex> lk(onConnectionClosedMtx_); auto it = onConnectionClosed_.find(deviceId); @@ -4561,7 +4607,7 @@ JamiAccount::callConnectionClosed(const DeviceId& deviceId, bool eraseDummy) } } dht::ThreadPool::io().run( - [w = weak(), cb = std::move(cb), id = std::move(deviceId), erase = std::move(eraseDummy)] { + [w = weak(), cb = std::move(cb), id = deviceId, erase = std::move(eraseDummy)] { if (auto acc = w.lock()) { if (cb) cb(id, erase); @@ -4813,7 +4859,7 @@ JamiAccount::cacheSIPConnection(std::shared_ptr<ChannelSocket>&& socket, sendProfile(deviceId.toString()); - syncConversations(peerId, deviceId.toString()); + syncConversations(peerId, deviceId); // Retry messages messageEngine_.onPeerOnline(peerId); @@ -4876,16 +4922,15 @@ JamiAccount::cacheSyncConnection(std::shared_ptr<ChannelSocket>&& socket, const std::string& peerId, const DeviceId& device) { - auto deviceId = device.toString(); std::unique_lock<std::mutex> lk(syncConnectionsMtx_); - syncConnections_[deviceId].emplace_back(socket); + syncConnections_[device].emplace_back(socket); - socket->onShutdown([w = weak(), peerId, deviceId, socket]() { + socket->onShutdown([w = weak(), peerId, device, socket]() { auto shared = w.lock(); if (!shared) return; std::lock_guard<std::mutex> lk(shared->syncConnectionsMtx_); - auto& connections = shared->syncConnections_[deviceId]; + auto& connections = shared->syncConnections_[device]; auto conn = connections.begin(); while (conn != connections.end()) { if (*conn == socket) @@ -4895,7 +4940,7 @@ JamiAccount::cacheSyncConnection(std::shared_ptr<ChannelSocket>&& socket, } }); - socket->setOnRecv([this, deviceId, peerId](const uint8_t* buf, size_t len) { + socket->setOnRecv([this, deviceId = device, peerId](const uint8_t* buf, size_t len) { if (!buf) return len; @@ -4968,7 +5013,7 @@ JamiAccount::cacheSyncConnection(std::shared_ptr<ChannelSocket>&& socket, JAMI_INFO("[Account %s] New request detected for conversation %s (device %s)", getAccountID().c_str(), convId.c_str(), - deviceId.c_str()); + deviceId.to_c_str()); emitSignal<DRing::ConversationSignal::ConversationRequestReceived>(getAccountID(), convId, @@ -4980,7 +5025,7 @@ JamiAccount::cacheSyncConnection(std::shared_ptr<ChannelSocket>&& socket, } void -JamiAccount::syncWith(const std::string& deviceId, const std::shared_ptr<ChannelSocket>& socket) +JamiAccount::syncWith(const DeviceId& deviceId, const std::shared_ptr<ChannelSocket>& socket) { if (!socket) return; @@ -5249,13 +5294,13 @@ JamiAccount::monitor() const } void -JamiAccount::cloneConversation(const std::string& deviceId, +JamiAccount::cloneConversation(const DeviceId& deviceId, const std::string&, const std::string& convId) { JAMI_DBG("[Account %s] Clone conversation on device %s", getAccountID().c_str(), - deviceId.c_str()); + deviceId.to_c_str()); if (!isConversation(convId)) { { @@ -5273,32 +5318,32 @@ JamiAccount::cloneConversation(const std::string& deviceId, std::lock_guard<std::mutex> lkCM(connManagerMtx_); if (!connectionManager_) return; - connectionManager_ - ->connectDevice(DeviceId(deviceId), - "git://" + deviceId + "/" + convId, - [this, convId](std::shared_ptr<ChannelSocket> socket, - const DeviceId& deviceId) { - if (socket) { - std::unique_lock<std::mutex> lk(pendingConversationsFetchMtx_); - auto& pending = pendingConversationsFetch_[convId]; - if (!pending.ready) { - pending.ready = true; - pending.deviceId = deviceId.toString(); - lk.unlock(); - // Save the git socket - addGitSocket(deviceId.toString(), convId, socket); - checkConversationsEvents(); - } else { - lk.unlock(); - socket->shutdown(); - } - } - }); + connectionManager_->connectDevice(deviceId, + fmt::format("git://{}/{}", deviceId, convId), + [this, convId](std::shared_ptr<ChannelSocket> socket, + const DeviceId& deviceId) { + if (socket) { + std::unique_lock<std::mutex> lk( + pendingConversationsFetchMtx_); + auto& pending = pendingConversationsFetch_[convId]; + if (!pending.ready) { + pending.ready = true; + pending.deviceId = deviceId.toString(); + lk.unlock(); + // Save the git socket + addGitSocket(deviceId, convId, socket); + checkConversationsEvents(); + } else { + lk.unlock(); + socket->shutdown(); + } + } + }); JAMI_INFO("[Account %s] New conversation detected: %s. Ask device %s to clone it", getAccountID().c_str(), convId.c_str(), - deviceId.c_str()); + deviceId.to_c_str()); } else { JAMI_INFO("[Account %s] Already have conversation %s", getAccountID().c_str(), @@ -5480,7 +5525,9 @@ JamiAccount::askForFileChannel(const std::string& conversationId, for (const auto& member : members) { accountManager_->forEachDevice(dht::InfoHash(member), [this, tryDevice = std::move(tryDevice)]( - const DeviceId& dev) { tryDevice(dev); }); + const std::shared_ptr<dht::crypto::PublicKey>& dev) { + tryDevice(dev->getLongId()); + }); } } } diff --git a/src/jamidht/jamiaccount.h b/src/jamidht/jamiaccount.h index 735b9b4a3ac5fe6870870c08cbe8006f2130346d..e994994bff41385ca95a4eaeeaae2ca51ca88292 100644 --- a/src/jamidht/jamiaccount.h +++ b/src/jamidht/jamiaccount.h @@ -89,7 +89,7 @@ class SipTransport; class ChanneledOutgoingTransfer; using SipConnectionKey = std::pair<std::string /* accountId */, DeviceId>; -using GitSocketList = std::map<std::string, /* device Id */ +using GitSocketList = std::map<DeviceId, /* device Id */ std::map<std::string, /* conversation */ std::shared_ptr<ChannelSocket> /* related socket */ >>; @@ -282,6 +282,7 @@ public: void onTextMessage(const std::string& id, const std::string& from, + const std::string& deviceId, const std::map<std::string, std::string>& payloads) override; virtual bool isTlsEnabled() const override { return true; } @@ -298,6 +299,9 @@ public: bool findCertificate( const dht::InfoHash& h, std::function<void(const std::shared_ptr<dht::crypto::Certificate>&)>&& cb = {}); + bool findCertificate( + const dht::PkId& h, + std::function<void(const std::shared_ptr<dht::crypto::Certificate>&)>&& cb = {}); /* contact requests */ std::vector<std::map<std::string, std::string>> getTrustRequests() const; @@ -397,7 +401,7 @@ public: const std::shared_future<tls::DhParams> dhParams() const { return dhParams_; } void forEachDevice(const dht::InfoHash& to, - std::function<void(const dht::InfoHash&)>&& op, + std::function<void(const std::shared_ptr<dht::crypto::PublicKey>&)>&& op, std::function<void(bool)>&& end = {}); /** @@ -465,7 +469,7 @@ public: * ConnectionManager needs the account to exists */ void shutdownConnections(); - std::optional<std::weak_ptr<ChannelSocket>> gitSocket(const std::string& deviceId, + std::optional<std::weak_ptr<ChannelSocket>> gitSocket(const DeviceId& deviceId, const std::string& conversationId) const { auto deviceSockets = gitSocketList_.find(deviceId); @@ -478,12 +482,12 @@ public: } return socketIt->second; } - bool hasGitSocket(const std::string& deviceId, const std::string& conversationId) const + bool hasGitSocket(const DeviceId& deviceId, const std::string& conversationId) const { return gitSocket(deviceId, conversationId) != std::nullopt; } - void addGitSocket(const std::string& deviceId, + void addGitSocket(const DeviceId& deviceId, const std::string& conversationId, const std::shared_ptr<ChannelSocket>& socket) { @@ -491,7 +495,7 @@ public: deviceSockets[conversationId] = socket; } - void removeGitSocket(const std::string& deviceId, const std::string& conversationId) + void removeGitSocket(const DeviceId& deviceId, const std::string& conversationId) { auto deviceSockets = gitSocketList_.find(deviceId); if (deviceSockets == gitSocketList_.end()) { @@ -581,7 +585,7 @@ public: * @param commitId (optional) */ void fetchNewCommits(const std::string& peer, - const std::string& deviceId, + const DeviceId& deviceId, const std::string& conversationId, const std::string& commitId = ""); @@ -598,7 +602,7 @@ public: * @param deviceId * @param convId */ - void cloneConversation(const std::string& deviceId, + void cloneConversation(const DeviceId& deviceId, const std::string& peer, const std::string& convId); @@ -730,7 +734,7 @@ private: /** * Sync conversations with detected peer */ - void syncConversations(const std::string& peer, const std::string& deviceId); + void syncConversations(const std::string& peer, const DeviceId& deviceId); /** * Maps require port via UPnP and other async ops @@ -950,8 +954,7 @@ private: // Sync connections std::mutex syncConnectionsMtx_; - std::map<std::string /* deviceId */, std::vector<std::shared_ptr<ChannelSocket>>> - syncConnections_; + std::map<DeviceId /* deviceId */, std::vector<std::shared_ptr<ChannelSocket>>> syncConnections_; /** * Ask a device to open a channeled SIP socket @@ -1028,7 +1031,7 @@ private: void checkConversationsEvents(); bool handlePendingConversations(); - void syncWith(const std::string& deviceId, const std::shared_ptr<ChannelSocket>& socket); + void syncWith(const DeviceId& deviceId, const std::shared_ptr<ChannelSocket>& socket); void syncInfos(const std::shared_ptr<ChannelSocket>& socket); void syncWithConnected(); diff --git a/src/jamidht/multiplexed_socket.h b/src/jamidht/multiplexed_socket.h index bbee47f4d67d41103fddc7f65a9c9f66c9932194..eaac36e6703f30ebc82737db944b5b1dfe3d1030 100644 --- a/src/jamidht/multiplexed_socket.h +++ b/src/jamidht/multiplexed_socket.h @@ -27,7 +27,7 @@ class IceTransport; class ChannelSocket; class TlsSocketEndpoint; -using DeviceId = dht::InfoHash; +using DeviceId = dht::PkId; using OnConnectionRequestCb = std::function< bool(const DeviceId& /* device id */, const uint16_t& /* id */, const std::string& /* name */)>; using OnConnectionReadyCb diff --git a/src/jamidht/p2p.cpp b/src/jamidht/p2p.cpp index 0966e596699786589985f263c028bef01a9eb687..452b255674204aa37549bb6b9d605a31664ba3a6 100644 --- a/src/jamidht/p2p.cpp +++ b/src/jamidht/p2p.cpp @@ -226,7 +226,7 @@ DhtPeerConnector::requestConnection( } std::string channelName = "file://" + std::to_string(tid); - std::vector<DeviceId> devices; + std::vector<dht::InfoHash> contacts; if (!info.conversationId.empty()) { // TODO remove preSwarmCompat // In a one_to_one conv with an old version, the contact here can be in an invited @@ -238,35 +238,35 @@ DhtPeerConnector::requestConnection( auto infos = acc->conversationInfos(info.conversationId); preSwarmCompat = infos["mode"] == "0"; } - for (const auto& member : members) { - devices.emplace_back(DeviceId(member.at("uri"))); - } if (!preSwarmCompat) - channelName = "data-transfer://" + info.conversationId + "/" + acc->currentDeviceId() - + "/" + std::to_string(tid); + channelName = fmt::format("data-transfer://{}/{}/{}", info.conversationId, acc->currentDeviceId(), tid); // If peer is not empty this means that we want to send to one device only if (!info.peer.empty()) { acc->connectionManager().connectDevice(DeviceId(info.peer), channelName, channelReadyCb); return; } + for (const auto& member : members) { + contacts.emplace_back(dht::InfoHash(member.at("uri"))); + } } else { - devices.emplace_back(DeviceId(info.peer)); + contacts.emplace_back(dht::InfoHash(info.peer)); } - for (const auto& peer_h : devices) { + for (const auto& peer_h : contacts) { acc->forEachDevice( peer_h, [this, channelName, tid, channelReadyCb = std::move(channelReadyCb)]( - const dht::InfoHash& dev_h) { + const std::shared_ptr<dht::crypto::PublicKey>& dev) { auto acc = pimpl_->account.lock(); if (!acc) return; - if (dev_h == acc->dht()->getId()) { + auto deviceId = dev->getLongId(); + if (deviceId == acc->dht()->getPublicKey()->getLongId()) { // No connection to same device return; } - acc->connectionManager().connectDevice(dev_h, channelName, channelReadyCb); + acc->connectionManager().connectDevice(deviceId, channelName, channelReadyCb); }, [peer_h, onChanneledCancelled, accId = acc->getAccountID()](bool found) { diff --git a/src/jamidht/server_account_manager.cpp b/src/jamidht/server_account_manager.cpp index caa903cc99ee92c01db81de61b74f03ad2f9a915..0560a63fb525634f8f1aa29c55993c3b4ac38efb 100644 --- a/src/jamidht/server_account_manager.cpp +++ b/src/jamidht/server_account_manager.cpp @@ -146,7 +146,8 @@ ServerAccountManager::initAuthentication(PrivateKey key, auto info = std::make_unique<AccountInfo>(); info->identity.first = ctx->key.get(); info->identity.second = cert; - info->deviceId = cert->getPublicKey().getId().toString(); + info->devicePk = std::make_shared<dht::crypto::PublicKey>(cert->getPublicKey()); + info->deviceId = info->devicePk->getLongId().toString(); info->accountId = accountCert->getId().toString(); info->contacts = std::make_unique<ContactList>(accountCert, this_.path_, @@ -430,7 +431,7 @@ ServerAccountManager::syncDevices() } else { for (unsigned i = 0, n = json.size(); i < n; i++) { const auto& e = json[i]; - dht::InfoHash deviceId(e["deviceId"].asString()); + dht::PkId deviceId(e["deviceId"].asString()); if (deviceId) { this_.info_->contacts->foundAccountDevice(deviceId, e["alias"].asString(), diff --git a/src/manager.cpp b/src/manager.cpp index 9c2a1ae9759d2a9d6615bd37e20284268cea6489..25b86fed4099d65d81d30944782ff4fea22e3848 100644 --- a/src/manager.cpp +++ b/src/manager.cpp @@ -3460,7 +3460,7 @@ Manager::gitSocket(const std::string& accountId, const std::string& conversationId) { if (const auto acc = getAccount<JamiAccount>(accountId)) - return acc->gitSocket(deviceId, conversationId); + return acc->gitSocket(DeviceId(deviceId), conversationId); return std::nullopt; } diff --git a/src/security/certstore.cpp b/src/security/certstore.cpp index 288922cd32d4e7b579a664326b02c47cd2d2eda3..7864fa5d4e3f914bf1c343f59f8e4ab5a34fc67a 100644 --- a/src/security/certstore.cpp +++ b/src/security/certstore.cpp @@ -72,8 +72,8 @@ CertificateStore::loadLocalCertificates() if (id != f) throw std::logic_error({}); while (crt) { - auto id_str = crt->getId().toString(); - certs_.emplace(id_str, crt); + certs_.emplace(crt->getId().toString(), crt); + certs_.emplace(crt->getLongId().toString(), crt); loadRevocations(*crt); crt = crt->issuer; ++n; @@ -252,6 +252,8 @@ CertificateStore::pinCertificatePath(const std::string& path, scerts.emplace_back(shared); auto e = certs_.emplace(shared->getId().toString(), shared); ids.emplace_back(e.first->first); + e = certs_.emplace(shared->getLongId().toString(), shared); + ids.emplace_back(e.first->first); } paths_.emplace(path, std::move(scerts)); } @@ -308,14 +310,19 @@ CertificateStore::pinCertificate(const std::shared_ptr<crypto::Certificate>& cer while (c) { bool inserted; auto id = c->getId().toString(); + auto longId = c->getLongId().toString(); decltype(certs_)::iterator it; std::tie(it, inserted) = certs_.emplace(id, c); + if (not inserted) + it->second = c; + std::tie(it, inserted) = certs_.emplace(longId, c); if (not inserted) it->second = c; if (local) { for (const auto& crl : c->getRevocationLists()) pinRevocationList(id, *crl); } + ids.emplace_back(longId); ids.emplace_back(id); c = c->issuer; sig |= inserted; diff --git a/src/sip/sipaccountbase.cpp b/src/sip/sipaccountbase.cpp index c563cbb38dea68790520801037d4ff97c8e9e006..91d6465e79623ce2368b823641fa0753adc43d4d 100644 --- a/src/sip/sipaccountbase.cpp +++ b/src/sip/sipaccountbase.cpp @@ -540,6 +540,7 @@ SIPAccountBase::getIceOptions() const noexcept void SIPAccountBase::onTextMessage(const std::string& id, const std::string& from, + const std::string& deviceId, const std::map<std::string, std::string>& payloads) { JAMI_DBG("Text message received from %s, %zu part(s)", from.c_str(), payloads.size()); @@ -641,10 +642,12 @@ SIPAccountBase::onTextMessage(const std::string& id, JAMI_WARN("Received indication for new commit available in conversation %s", json["id"].asString().c_str()); - onNewGitCommit(from, - json["deviceId"].asString(), - json["id"].asString(), - json["commit"].asString()); + if (deviceId.empty()) { + JAMI_ERR() << "Incorrect deviceId. Can't retrieve history"; + return; + } + + onNewGitCommit(from, deviceId, json["id"].asString(), json["commit"].asString()); return; } else if (m.first == MIME_TYPE_INVITE_JSON) { Json::Value json; diff --git a/src/sip/sipaccountbase.h b/src/sip/sipaccountbase.h index a4bbb70d98930dad8d07de84773a73fbac5dabed..0f6bca8ad6d766ad25cdd5c5908381bf7ca63fa6 100644 --- a/src/sip/sipaccountbase.h +++ b/src/sip/sipaccountbase.h @@ -273,6 +273,7 @@ public: virtual void onTextMessage(const std::string& id, const std::string& from, + const std::string& deviceId, const std::map<std::string, std::string>& payloads); /* Returns true if the username and/or hostname match this account */ diff --git a/src/sip/siptransport.cpp b/src/sip/siptransport.cpp index 2220d5d0bce8d20ef3577c6e4a057bd9793c740f..ec21427189d09225b95fbbba899798adaa5fa8ef 100644 --- a/src/sip/siptransport.cpp +++ b/src/sip/siptransport.cpp @@ -414,7 +414,7 @@ SipTransportBroker::getChanneledTransport(const std::shared_ptr<ChannelSocket>& std::move(cb)); auto tr = sips_tr->getTransportBase(); auto sip_tr = std::make_shared<SipTransport>(tr); - sip_tr->setIsChanneledTransport(); + sip_tr->setDeviceId(socket->deviceId().toString()); sips_tr.release(); // managed by PJSIP now { diff --git a/src/sip/siptransport.h b/src/sip/siptransport.h index 0357e5e80ef5b06cdcbf0d5ec1313f22707cb710..c74e39f90208199a2d6ae6d7768de67b70b72dfc 100644 --- a/src/sip/siptransport.h +++ b/src/sip/siptransport.h @@ -113,8 +113,8 @@ public: /** Only makes sense for connection-oriented transports */ bool isConnected() const noexcept { return connected_; } - void setIsIceTransport() { isIceTransport_ = true; } - void setIsChanneledTransport() { isChanneledTransport_ = true; } + inline void setDeviceId(const std::string& deviceId) { deviceId_ = deviceId; } + inline std::string_view deviceId() const { return deviceId_; } inline void setAccount(const std::shared_ptr<SIPAccountBase>& account) { account_ = account; } inline const std::weak_ptr<SIPAccountBase>& getAccount() const { return account_; } @@ -132,8 +132,7 @@ private: std::weak_ptr<SIPAccountBase> account_ {}; bool connected_ {false}; - bool isIceTransport_ {false}; - bool isChanneledTransport_ {false}; + std::string deviceId_ {}; TlsInfos tlsInfos_; }; diff --git a/src/sip/sipvoiplink.cpp b/src/sip/sipvoiplink.cpp index 8e0b738320d2c30a2ed9ad31852678d1df173942..7c534838988c1d3ef0550aa0d83be143d714b8d9 100644 --- a/src/sip/sipvoiplink.cpp +++ b/src/sip/sipvoiplink.cpp @@ -355,7 +355,7 @@ transaction_request_cb(pjsip_rx_data* rdata) } catch (...) { } } - account->onTextMessage(id, peerNumber, payloads); + account->onTextMessage(id, peerNumber, std::string(transport->deviceId()), payloads); } return PJ_FALSE; } diff --git a/test/unitTest/conversationRepository/conversationRepository.cpp b/test/unitTest/conversationRepository/conversationRepository.cpp index 0c54aac5bfb8a1afd36451ece01c9e49eaf8dc36..2d8fb93c29d979628a38a7794dabb0ffe029947e 100644 --- a/test/unitTest/conversationRepository/conversationRepository.cpp +++ b/test/unitTest/conversationRepository/conversationRepository.cpp @@ -124,7 +124,7 @@ void ConversationRepositoryTest::testCreateRepository() { auto aliceAccount = Manager::instance().getAccount<JamiAccount>(aliceId); - auto aliceDeviceId = aliceAccount->currentDeviceId(); + auto aliceDeviceId = DeviceId(std::string(aliceAccount->currentDeviceId())); auto uri = aliceAccount->getUsername(); auto repository = ConversationRepository::createConversation(aliceAccount->weak()); @@ -152,7 +152,8 @@ ConversationRepositoryTest::testCreateRepository() CPPUNIT_ASSERT(aliceAccount->identity().second->getPublicKey().checkSignature(data, pk)); // 2. Check created files - auto CRLsPath = repoPath + DIR_SEPARATOR_STR + "CRLs" + DIR_SEPARATOR_STR + aliceDeviceId; + auto CRLsPath = repoPath + DIR_SEPARATOR_STR + "CRLs" + DIR_SEPARATOR_STR + + aliceDeviceId.toString(); CPPUNIT_ASSERT(fileutils::isDirectory(repoPath)); auto adminCrt = repoPath + DIR_SEPARATOR_STR + "admins" + DIR_SEPARATOR_STR + uri + ".crt"; @@ -167,8 +168,8 @@ ConversationRepositoryTest::testCreateRepository() CPPUNIT_ASSERT(adminCrtStr == parentCert); - auto deviceCrt = repoPath + DIR_SEPARATOR_STR + "devices" + DIR_SEPARATOR_STR + aliceDeviceId - + ".crt"; + auto deviceCrt = repoPath + DIR_SEPARATOR_STR + "devices" + DIR_SEPARATOR_STR + + aliceDeviceId.toString() + ".crt"; CPPUNIT_ASSERT(fileutils::isFile(deviceCrt)); crt = std::ifstream(deviceCrt); @@ -183,9 +184,9 @@ ConversationRepositoryTest::testCloneViaChannelSocket() { auto aliceAccount = Manager::instance().getAccount<JamiAccount>(aliceId); auto bobAccount = Manager::instance().getAccount<JamiAccount>(bobId); - auto aliceDeviceId = std::string(aliceAccount->currentDeviceId()); + auto aliceDeviceId = DeviceId(std::string(aliceAccount->currentDeviceId())); auto uri = aliceAccount->getUsername(); - auto bobDeviceId = std::string(bobAccount->currentDeviceId()); + auto bobDeviceId = DeviceId(std::string(bobAccount->currentDeviceId())); bobAccount->connectionManager().onICERequest([](const DeviceId&) { return true; }); aliceAccount->connectionManager().onICERequest([](const DeviceId&) { return true; }); @@ -220,7 +221,7 @@ ConversationRepositoryTest::testCloneViaChannelSocket() rcv.notify_one(); }); - aliceAccount->connectionManager().connectDevice(DeviceId(bobDeviceId), + aliceAccount->connectionManager().connectDevice(bobDeviceId, "git://*", [&](std::shared_ptr<ChannelSocket> socket, const DeviceId&) { @@ -241,7 +242,7 @@ ConversationRepositoryTest::testCloneViaChannelSocket() GitServer gs(aliceId, repository->id(), sendSocket); auto cloned = ConversationRepository::cloneConversation(bobAccount->weak(), - aliceDeviceId, + aliceDeviceId.toString(), repository->id()); gs.stop(); @@ -265,7 +266,8 @@ ConversationRepositoryTest::testCloneViaChannelSocket() CPPUNIT_ASSERT(aliceAccount->identity().second->getPublicKey().checkSignature(data, pk)); // 2. Check created files - auto CRLsPath = clonedPath + DIR_SEPARATOR_STR + "CRLs" + DIR_SEPARATOR_STR + aliceDeviceId; + auto CRLsPath = clonedPath + DIR_SEPARATOR_STR + "CRLs" + DIR_SEPARATOR_STR + + aliceDeviceId.toString(); CPPUNIT_ASSERT(fileutils::isDirectory(clonedPath)); auto adminCrt = clonedPath + DIR_SEPARATOR_STR + "admins" + DIR_SEPARATOR_STR + uri + ".crt"; @@ -280,8 +282,8 @@ ConversationRepositoryTest::testCloneViaChannelSocket() CPPUNIT_ASSERT(adminCrtStr == parentCert); - auto deviceCrt = clonedPath + DIR_SEPARATOR_STR + "devices" + DIR_SEPARATOR_STR + aliceDeviceId - + ".crt"; + auto deviceCrt = clonedPath + DIR_SEPARATOR_STR + "devices" + DIR_SEPARATOR_STR + + aliceDeviceId.toString() + ".crt"; CPPUNIT_ASSERT(fileutils::isFile(deviceCrt)); crt = std::ifstream(deviceCrt); @@ -365,8 +367,8 @@ ConversationRepositoryTest::testFetch() { auto aliceAccount = Manager::instance().getAccount<JamiAccount>(aliceId); auto bobAccount = Manager::instance().getAccount<JamiAccount>(bobId); - auto aliceDeviceId = std::string(aliceAccount->currentDeviceId()); - auto bobDeviceId = std::string(bobAccount->currentDeviceId()); + auto aliceDeviceId = DeviceId(std::string(aliceAccount->currentDeviceId())); + auto bobDeviceId = DeviceId(std::string(bobAccount->currentDeviceId())); bobAccount->connectionManager().onICERequest([](const DeviceId&) { return true; }); aliceAccount->connectionManager().onICERequest([](const DeviceId&) { return true; }); @@ -401,7 +403,7 @@ ConversationRepositoryTest::testFetch() rcv.notify_one(); }); - aliceAccount->connectionManager().connectDevice(DeviceId(bobDeviceId), + aliceAccount->connectionManager().connectDevice(bobDeviceId, "git://*", [&](std::shared_ptr<ChannelSocket> socket, const DeviceId&) { @@ -425,7 +427,7 @@ ConversationRepositoryTest::testFetch() // Clone repository auto id1 = repository->commitMessage("Commit 1"); auto cloned = ConversationRepository::cloneConversation(bobAccount->weak(), - aliceDeviceId, + aliceDeviceId.toString(), repository->id()); gs.stop(); bobAccount->removeGitSocket(aliceDeviceId, repository->id()); @@ -435,7 +437,7 @@ ConversationRepositoryTest::testFetch() auto id3 = repository->commitMessage("Commit 3"); // Open a new channel to simulate the fact that we are later - aliceAccount->connectionManager().connectDevice(DeviceId(bobDeviceId), + aliceAccount->connectionManager().connectDevice(bobDeviceId, "git://*", [&](std::shared_ptr<ChannelSocket> socket, const DeviceId&) { @@ -452,8 +454,8 @@ ConversationRepositoryTest::testFetch() bobAccount->addGitSocket(aliceDeviceId, repository->id(), channelSocket); GitServer gs2(aliceId, repository->id(), sendSocket); - CPPUNIT_ASSERT(cloned->fetch(aliceDeviceId)); - CPPUNIT_ASSERT(id3 == cloned->remoteHead(aliceDeviceId)); + CPPUNIT_ASSERT(cloned->fetch(aliceDeviceId.toString())); + CPPUNIT_ASSERT(id3 == cloned->remoteHead(aliceDeviceId.toString())); gs2.stop(); bobAccount->removeGitSocket(aliceDeviceId, repository->id()); @@ -493,14 +495,14 @@ ConversationRepositoryTest::addCommit(git_repository* repo, const std::string& branch, const std::string& commit_msg) { - auto deviceId = std::string(account->currentDeviceId()); + auto deviceId = DeviceId(std::string(account->currentDeviceId())); auto name = account->getDisplayName(); if (name.empty()) - name = deviceId; + name = deviceId.toString(); git_signature* sig_ptr = nullptr; // Sign commit's buffer - if (git_signature_new(&sig_ptr, name.c_str(), deviceId.c_str(), std::time(nullptr), 0) < 0) { + if (git_signature_new(&sig_ptr, name.c_str(), deviceId.to_c_str(), std::time(nullptr), 0) < 0) { JAMI_ERR("Unable to create a commit signature."); return {}; } @@ -674,7 +676,7 @@ void ConversationRepositoryTest::testDiff() { auto aliceAccount = Manager::instance().getAccount<JamiAccount>(aliceId); - auto aliceDeviceId = aliceAccount->currentDeviceId(); + auto aliceDeviceId = DeviceId(std::string(aliceAccount->currentDeviceId())); auto uri = aliceAccount->getUsername(); auto repository = ConversationRepository::createConversation(aliceAccount->weak()); @@ -688,7 +690,7 @@ ConversationRepositoryTest::testDiff() auto changedFiles = ConversationRepository::changedFiles(diff); CPPUNIT_ASSERT(!changedFiles.empty()); CPPUNIT_ASSERT(changedFiles[0] == "admins/" + uri + ".crt"); - CPPUNIT_ASSERT(changedFiles[1] == "devices/" + aliceDeviceId + ".crt"); + CPPUNIT_ASSERT(changedFiles[1] == "devices/" + aliceDeviceId.toString() + ".crt"); } void @@ -756,9 +758,9 @@ ConversationRepositoryTest::testCloneHugeRepo() { auto aliceAccount = Manager::instance().getAccount<JamiAccount>(aliceId); auto bobAccount = Manager::instance().getAccount<JamiAccount>(bobId); - auto aliceDeviceId = std::string(aliceAccount->currentDeviceId()); + auto aliceDeviceId = DeviceId(std::string(aliceAccount->currentDeviceId())); auto uri = aliceAccount->getUsername(); - auto bobDeviceId = std::string(bobAccount->currentDeviceId()); + auto bobDeviceId = DeviceId(std::string(bobAccount->currentDeviceId())); bobAccount->connectionManager().onICERequest([](const DeviceId&) { return true; }); aliceAccount->connectionManager().onICERequest([](const DeviceId&) { return true; }); @@ -801,7 +803,7 @@ DIR_SEPARATOR_STR + bobAccount->getAccountID() rcv.notify_one(); }); - aliceAccount->connectionManager().connectDevice(DeviceId(bobDeviceId), + aliceAccount->connectionManager().connectDevice(bobDeviceId, "git://*", [&](std::shared_ptr<ChannelSocket> socket, const DeviceId&) {