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