From 5f13f8436b4bb9c6b714c3b2c15ac4bb34b320b6 Mon Sep 17 00:00:00 2001 From: Guillaume Roguez <guillaume.roguez@savoirfairelinux.com> Date: Tue, 23 Jan 2018 13:39:04 -0500 Subject: [PATCH] datatransfer: provide account/peer information MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fill AccountId and Peer field of outgoing and incoming data transfers. Change-Id: I772e9c4560fb63c30e33c341cd296cacd6a45df6 Reviewed-by: Anthony Léonard <anthony.leonard@savoirfairelinux.com> --- src/data_transfer.cpp | 90 ++++++++++++++++++++------------------- src/data_transfer.h | 4 +- src/ftp_server.cpp | 9 +++- src/ftp_server.h | 4 +- src/ringdht/p2p.cpp | 36 +++++++++++++--- src/ringdht/ringaccount.h | 15 ++++--- 6 files changed, 98 insertions(+), 60 deletions(-) diff --git a/src/data_transfer.cpp b/src/data_transfer.cpp index 9735f787b5..17f5e491af 100644 --- a/src/data_transfer.cpp +++ b/src/data_transfer.cpp @@ -104,7 +104,7 @@ DataTransfer::emit(DRing::DataTransferEventCode code) const class FileTransfer final : public DataTransfer { public: - FileTransfer(DRing::DataTransferId id, const std::string&, const std::string&); + FileTransfer(DRing::DataTransferId tid, const DRing::DataTransferInfo& info); bool start() override; @@ -121,18 +121,15 @@ private: const std::string peerUri_; }; -FileTransfer::FileTransfer(DRing::DataTransferId id, - const std::string& file_path, - const std::string& display_name) - : DataTransfer(id) +FileTransfer::FileTransfer(DRing::DataTransferId tid, const DRing::DataTransferInfo& info) + : DataTransfer(tid) { - input_.open(file_path, std::ios::binary); + input_.open(info.path, std::ios::binary); if (!input_) throw std::runtime_error("input file open failed"); + info_ = info; info_.isOutgoing = true; - info_.displayName = display_name; - info_.path = file_path; // File size? input_.seekg(0, std::ios_base::end); @@ -205,7 +202,7 @@ FileTransfer::read(std::vector<uint8_t>& buf) const class IncomingFileTransfer final : public DataTransfer { public: - IncomingFileTransfer(DRing::DataTransferId, const std::string&, std::size_t, std::size_t, + IncomingFileTransfer(DRing::DataTransferId, const DRing::DataTransferInfo&, std::atomic<std::size_t>&); bool start() override; @@ -225,21 +222,16 @@ private: std::promise<void> filenamePromise_; }; -IncomingFileTransfer::IncomingFileTransfer(DRing::DataTransferId id, - const std::string& display_name, - std::size_t total_size, - std::size_t offset, +IncomingFileTransfer::IncomingFileTransfer(DRing::DataTransferId tid, + const DRing::DataTransferInfo& info, std::atomic<std::size_t>& progress_storage) - : DataTransfer(id) + : DataTransfer(tid) , progressStorage_ {progress_storage} { - RING_WARN() << "[FTP] incoming transfert of " << total_size << " byte(s): " << display_name; - (void)offset; + RING_WARN() << "[FTP] incoming transfert of " << info.totalSize << " byte(s): " << info.displayName; + info_ = info; info_.isOutgoing = false; - info_.displayName = display_name; - info_.totalSize = total_size; - // TODO: use offset? emit(DRing::DataTransferEventCode::created); } @@ -257,7 +249,7 @@ IncomingFileTransfer::requestFilename() { emit(DRing::DataTransferEventCode::wait_host_acceptance); -#if 1 +#if 0 // Now wait for DataTransferFacade::acceptFileTransfer() call filenamePromise_.get_future().wait(); return info_.path; @@ -305,11 +297,8 @@ public: mutable std::mutex mapMutex_; std::unordered_map<DRing::DataTransferId, std::shared_ptr<DataTransfer>> map_; - std::shared_ptr<DataTransfer> createFileTransfer(const std::string& file_path, - const std::string& display_name); - std::shared_ptr<IncomingFileTransfer> createIncomingFileTransfer(const std::string& display_name, - std::size_t total_size, - std::size_t offset, + std::shared_ptr<DataTransfer> createFileTransfer(const DRing::DataTransferInfo& info); + std::shared_ptr<IncomingFileTransfer> createIncomingFileTransfer(const DRing::DataTransferInfo& info, std::atomic<std::size_t>& progress_storage); std::shared_ptr<DataTransfer> getTransfer(const DRing::DataTransferId& id); @@ -336,27 +325,23 @@ DataTransferFacade::Impl::getTransfer(const DRing::DataTransferId& id) } std::shared_ptr<DataTransfer> -DataTransferFacade::Impl::createFileTransfer(const std::string& file_path, - const std::string& display_name) +DataTransferFacade::Impl::createFileTransfer(const DRing::DataTransferInfo& info) { - auto id = generateUID(); - auto transfer = std::make_shared<FileTransfer>(id, file_path, display_name); + auto tid = generateUID(); + auto transfer = std::make_shared<FileTransfer>(tid, info); std::lock_guard<std::mutex> lk {mapMutex_}; - map_.emplace(id, transfer); + map_.emplace(tid, transfer); return transfer; } std::shared_ptr<IncomingFileTransfer> -DataTransferFacade::Impl::createIncomingFileTransfer(const std::string& display_name, - std::size_t total_size, - std::size_t offset, +DataTransferFacade::Impl::createIncomingFileTransfer(const DRing::DataTransferInfo& info, std::atomic<std::size_t>& progress_storage) { - auto id = generateUID(); - auto transfer = std::make_shared<IncomingFileTransfer>(id, display_name, total_size, offset, - progress_storage); + auto tid = generateUID(); + auto transfer = std::make_shared<IncomingFileTransfer>(tid, info, progress_storage); std::lock_guard<std::mutex> lk {mapMutex_}; - map_.emplace(id, transfer); + map_.emplace(tid, transfer); return transfer; } @@ -406,18 +391,25 @@ DataTransferFacade::sendFile(const std::string& account_id, const std::string& p if (!fileutils::isFile(file_path)) throw std::invalid_argument("invalid input file"); - auto transfer = pimpl_->createFileTransfer(file_path, display_name); - auto id = transfer->getId(); + DRing::DataTransferInfo info; + info.accountId = account_id; + info.peer = peer_uri; + info.displayName = display_name; + info.path = file_path; + // remaining fields are overwritten + + auto transfer = pimpl_->createFileTransfer(info); + auto tid = transfer->getId(); // IMPLEMENTATION NOTE: requestPeerConnection() may call the given callback a multiple time. // This happen when multiple agents handle communications of the given peer for the given account. // Example: Ring account supports multi-devices, each can answer to the request. account->requestPeerConnection( peer_uri, - [this, id] (PeerConnection* connection) { - pimpl_->onConnectionRequestReply(id, connection); + [this, tid] (PeerConnection* connection) { + pimpl_->onConnectionRequestReply(tid, connection); }); - return id; + return tid; } void @@ -459,12 +451,22 @@ DataTransferFacade::info(const DRing::DataTransferId& id) const } std::string -DataTransferFacade::onIncomingFileRequest(const std::string& display_name, +DataTransferFacade::onIncomingFileRequest(const std::string& account_id, + const std::string& peer_uri, + const std::string& display_name, std::size_t total_size, std::size_t offset, std::atomic<std::size_t>& progress_storage) { - auto transfer = pimpl_->createIncomingFileTransfer(display_name, total_size, offset, progress_storage); + DRing::DataTransferInfo info; + info.accountId = account_id; + info.peer = peer_uri; + info.displayName = display_name; + info.totalSize = total_size; + info.bytesProgress = offset; + // remaining fields are overwritten + + auto transfer = pimpl_->createIncomingFileTransfer(info, progress_storage); auto filename = transfer->requestFilename(); if (!filename.empty()) transfer->start(); // TODO: bad place, call only if file can be open diff --git a/src/data_transfer.h b/src/data_transfer.h index 4c9a47a503..56d9b1fe78 100644 --- a/src/data_transfer.h +++ b/src/data_transfer.h @@ -70,7 +70,9 @@ public: /// Create an IncomingFileTransfer object. /// \return a filename to open where incoming data will be written or an empty string /// in case of refusal. - std::string onIncomingFileRequest(const std::string& display_name, std::size_t total_size, + std::string onIncomingFileRequest(const std::string& account_id, + const std::string& peer_uri, + const std::string& display_name, std::size_t total_size, std::size_t offset, std::atomic<std::size_t>& progress_storage); diff --git a/src/ftp_server.cpp b/src/ftp_server.cpp index 7d9ee8bba3..d1e52a7478 100644 --- a/src/ftp_server.cpp +++ b/src/ftp_server.cpp @@ -35,8 +35,11 @@ namespace ring { //============================================================================== -FtpServer::FtpServer() +FtpServer::FtpServer(const std::string& account_id, + const std::string& peer_uri) : Stream() + , accountId_ {account_id} + , peerUri_ {peer_uri} {} DRing::DataTransferId @@ -56,7 +59,9 @@ bool FtpServer::startNewFile() { // Request filename from client (WARNING: synchrone call!) - auto filename = Manager::instance().dataTransfers->onIncomingFileRequest(displayName_, + auto filename = Manager::instance().dataTransfers->onIncomingFileRequest(accountId_, + peerUri_, + displayName_, fileSize_, 0 /* TODO: offset */, rx_); diff --git a/src/ftp_server.h b/src/ftp_server.h index 6313544a90..0f0244dfdb 100644 --- a/src/ftp_server.h +++ b/src/ftp_server.h @@ -33,7 +33,7 @@ namespace ring { class FtpServer final : public Stream { public: - FtpServer(); + FtpServer(const std::string& account_id, const std::string& peer_uri); bool write(const std::vector<uint8_t>& buffer) override; DRing::DataTransferId getId() const override; @@ -51,6 +51,8 @@ private: READ_DATA, }; + const std::string accountId_; + const std::string peerUri_; std::ofstream out_; std::size_t fileSize_ {0}; std::atomic<std::size_t> rx_ {0}; diff --git a/src/ringdht/p2p.cpp b/src/ringdht/p2p.cpp index 95ab147cab..735d59847b 100644 --- a/src/ringdht/p2p.cpp +++ b/src/ringdht/p2p.cpp @@ -203,6 +203,7 @@ public: private: std::unique_ptr<ConnectedTurnTransport> turn_ep_; std::unique_ptr<TurnTransport> turn_; + std::map<std::shared_ptr<dht::crypto::Certificate>, dht::InfoHash> certMap_; dht::crypto::TrustList trustedPeers_; protected: @@ -213,7 +214,8 @@ private: void onTurnPeerConnection(const IpAddr&); void onTurnPeerDisconnection(const IpAddr&); void onRequestMsg(PeerConnectionMsg&&); - void onTrustedRequestMsg(PeerConnectionMsg&&, const std::shared_ptr<dht::crypto::Certificate>&); + void onTrustedRequestMsg(PeerConnectionMsg&&, const std::shared_ptr<dht::crypto::Certificate>&, + const dht::InfoHash&); void onResponseMsg(PeerConnectionMsg&&); void onAddDevice(const dht::InfoHash&, const std::shared_ptr<dht::crypto::Certificate>&, @@ -401,8 +403,26 @@ DhtPeerConnector::Impl::onTurnPeerConnection(const IpAddr& peer_addr) auto tls_ep = std::make_unique<TlsTurnEndpoint>(*turn_ep, account.identity(), account.dhParams(), trustedPeers_); tls_ep->connect(); // block until TLS negotiated (throw in case of error) + + // Find who is connected by using connection certificate + dht::InfoHash peer_h; + auto& connected_cert = tls_ep->peerCertificate(); + for (const auto& item : certMap_) { + if (item.first->getPacked() == connected_cert.getPacked()) { + peer_h = item.second; + break; + } + } + + // Not found? Considering this case as an attack! + if (!peer_h) { + RING_WARN() << "[CNX] unknown certificate from ip " << peer_addr.toString(true, true); + return; + } + + RING_DBG() << account << "[CNX] Accepted TLS-TURN connection from RingID " << peer_h; auto connection = std::make_unique<PeerConnection>(account, peer_addr.toString(), std::move(tls_ep)); - connection->attachOutputStream(std::make_shared<FtpServer>()); + connection->attachOutputStream(std::make_shared<FtpServer>(account.getAccountID(), peer_h.toString())); servers_.emplace(peer_addr, std::move(connection)); // note: operating this way let endpoint to be deleted safely in case of exceptions @@ -428,18 +448,24 @@ DhtPeerConnector::Impl::onRequestMsg(PeerConnectionMsg&& request) account.findCertificate( request.from, [this, request=std::move(request)] (const std::shared_ptr<dht::crypto::Certificate>& cert) mutable { - /* TODO: certificate trusted? */ - onTrustedRequestMsg(std::move(request), cert); + dht::InfoHash peer_h; + if (account.foundPeerDevice(cert, peer_h)) + onTrustedRequestMsg(std::move(request), cert, peer_h); + else + RING_WARN() << account << "[CNX] rejected untrusted connection request from " + << request.from; }); } void DhtPeerConnector::Impl::onTrustedRequestMsg(PeerConnectionMsg&& request, - const std::shared_ptr<dht::crypto::Certificate>& cert) + const std::shared_ptr<dht::crypto::Certificate>& cert, + const dht::InfoHash& peer_h) { turnConnect(); // start a TURN client connection on first pass, next ones just add new peer cnx handlers // Save peer certificate for later TLS session (MUST BE DONE BEFORE TURN PEER AUTHORIZATION) + certMap_.insert(std::make_pair(cert, peer_h)); trustedPeers_.add(*cert); for (auto& ip: request.addresses) { diff --git a/src/ringdht/ringaccount.h b/src/ringdht/ringaccount.h index 951a9be3f8..c3a5c3a84f 100644 --- a/src/ringdht/ringaccount.h +++ b/src/ringdht/ringaccount.h @@ -341,6 +341,14 @@ class RingAccount : public SIPAccountBase { std::function<void(const std::shared_ptr<RingAccount>&, const dht::InfoHash&)> op, std::function<void(bool)> end = {}); + + /** + * Inform that a potential peer device have been found. + * Returns true only if the device certificate is a valid Ring device certificate. + * In that case (true is returned) the account_id parameter is set to the peer account ID. + */ + static bool foundPeerDevice(const std::shared_ptr<dht::crypto::Certificate>& crt, dht::InfoHash& account_id); + private: NON_COPYABLE(RingAccount); @@ -417,13 +425,6 @@ class RingAccount : public SIPAccountBase { */ bool foundAccountDevice(const std::shared_ptr<dht::crypto::Certificate>& crt, const std::string& name = {}, const time_point& last_sync = time_point::min()); - /** - * Inform that a potential peer device have been found. - * Returns true only if the device certificate is a valid Ring device certificate. - * In that case (true is returned) the account_id parameter is set to the peer account ID. - */ - static bool foundPeerDevice(const std::shared_ptr<dht::crypto::Certificate>& crt, dht::InfoHash& account_id); - /** * For a call with (from_device, from_account), check the peer certificate chain (cert_list, cert_num) * with session check status. -- GitLab