From 0d7e506bea1fe7603e0c5eb1e599781d68083f9c Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?S=C3=A9bastien=20Blin?=
 <sebastien.blin@savoirfairelinux.com>
Date: Wed, 21 Jun 2023 09:46:40 -0400
Subject: [PATCH] data_transfer: remove invalid file if larger than requested

Else, we will result in a forever downloading file

Change-Id: If25dc48e5fffaea04c82c2a0c9e7b00933ac58ec
---
 src/data_transfer.cpp                       |   4 +
 test/unitTest/fileTransfer/fileTransfer.cpp | 119 +++++++++++++++-----
 2 files changed, 95 insertions(+), 28 deletions(-)

diff --git a/src/data_transfer.cpp b/src/data_transfer.cpp
index d7565c7115..62de434d0c 100644
--- a/src/data_transfer.cpp
+++ b/src/data_transfer.cpp
@@ -217,6 +217,10 @@ IncomingFile::process()
                 correct = true;
             } else {
                 JAMI_WARN() << "Invalid sha3sum detected, unfinished file: " << shared->info_.path;
+                if (shared->info_.totalSize != 0 && shared->info_.totalSize < shared->info_.bytesProgress) {
+                    JAMI_WARN() << "Remove file, larger file than announced for " << shared->info_.path;
+                    fileutils::remove(shared->info_.path, true);
+                }
             }
         }
         if (shared->isUserCancelled_)
diff --git a/test/unitTest/fileTransfer/fileTransfer.cpp b/test/unitTest/fileTransfer/fileTransfer.cpp
index e8cd6c1500..95ed291f78 100644
--- a/test/unitTest/fileTransfer/fileTransfer.cpp
+++ b/test/unitTest/fileTransfer/fileTransfer.cpp
@@ -67,6 +67,10 @@ public:
     std::string recvPath {std::filesystem::current_path() / "RECV"};
     std::string recv2Path {std::filesystem::current_path() / "RECV2"};
 
+    std::mutex mtx;
+    std::unique_lock<std::mutex> lk {mtx};
+    std::condition_variable cv;
+
 private:
     void testConversationFileTransfer();
     void testFileTransferInConversation();
@@ -78,6 +82,7 @@ private:
     void testCancelOutTransfer();
     void testTransferInfo();
     void testRemoveHardLink();
+    void testTooLarge();
 
     CPPUNIT_TEST_SUITE(FileTransferTest);
     CPPUNIT_TEST(testConversationFileTransfer);
@@ -89,6 +94,7 @@ private:
     CPPUNIT_TEST(testCancelInTransfer);
     CPPUNIT_TEST(testTransferInfo);
     CPPUNIT_TEST(testRemoveHardLink);
+    CPPUNIT_TEST(testTooLarge);
     CPPUNIT_TEST_SUITE_END();
 };
 
@@ -144,9 +150,6 @@ FileTransferTest::testConversationFileTransfer()
     wait_for_announcement_of(carlaId);
 
     std::map<std::string, std::shared_ptr<libjami::CallbackWrapperBase>> confHandlers;
-    std::mutex mtx;
-    std::unique_lock<std::mutex> lk {mtx};
-    std::condition_variable cv;
     auto requestReceived = 0;
     auto conversationReady = 0;
     auto memberJoined = 0;
@@ -248,9 +251,6 @@ FileTransferTest::testFileTransferInConversation()
     auto aliceUri = aliceAccount->getUsername();
     auto convId = libjami::startConversation(aliceId);
 
-    std::mutex mtx;
-    std::unique_lock<std::mutex> lk {mtx};
-    std::condition_variable cv;
     std::map<std::string, std::shared_ptr<libjami::CallbackWrapperBase>> confHandlers;
     bool requestReceived = false;
     bool conversationReady = false;
@@ -339,9 +339,6 @@ FileTransferTest::testVcfFileTransferInConversation()
     auto aliceUri = aliceAccount->getUsername();
     auto convId = libjami::startConversation(aliceId);
 
-    std::mutex mtx;
-    std::unique_lock<std::mutex> lk {mtx};
-    std::condition_variable cv;
     std::map<std::string, std::shared_ptr<libjami::CallbackWrapperBase>> confHandlers;
     bool requestReceived = false;
     bool conversationReady = false;
@@ -430,9 +427,6 @@ FileTransferTest::testBadSha3sumOut()
     auto aliceUri = aliceAccount->getUsername();
     auto convId = libjami::startConversation(aliceId);
 
-    std::mutex mtx;
-    std::unique_lock<std::mutex> lk {mtx};
-    std::condition_variable cv;
     std::map<std::string, std::shared_ptr<libjami::CallbackWrapperBase>> confHandlers;
     bool requestReceived = false;
     bool conversationReady = false;
@@ -537,9 +531,6 @@ FileTransferTest::testBadSha3sumIn()
     auto aliceUri = aliceAccount->getUsername();
     auto convId = libjami::startConversation(aliceId);
 
-    std::mutex mtx;
-    std::unique_lock<std::mutex> lk {mtx};
-    std::condition_variable cv;
     std::map<std::string, std::shared_ptr<libjami::CallbackWrapperBase>> confHandlers;
     bool requestReceived = false;
     bool conversationReady = false;
@@ -649,9 +640,6 @@ FileTransferTest::testAskToMultipleParticipants()
     auto carlaUri = carlaAccount->getUsername();
     auto convId = libjami::startConversation(aliceId);
 
-    std::mutex mtx;
-    std::unique_lock<std::mutex> lk {mtx};
-    std::condition_variable cv;
     std::map<std::string, std::shared_ptr<libjami::CallbackWrapperBase>> confHandlers;
     bool requestReceived = false;
     bool conversationReady = false;
@@ -765,9 +753,6 @@ FileTransferTest::testCancelInTransfer()
     auto aliceUri = aliceAccount->getUsername();
     auto convId = libjami::startConversation(aliceId);
 
-    std::mutex mtx;
-    std::unique_lock<std::mutex> lk {mtx};
-    std::condition_variable cv;
     std::map<std::string, std::shared_ptr<libjami::CallbackWrapperBase>> confHandlers;
     bool requestReceived = false;
     bool conversationReady = false;
@@ -861,9 +846,6 @@ FileTransferTest::testTransferInfo()
     auto aliceUri = aliceAccount->getUsername();
     auto convId = libjami::startConversation(aliceId);
 
-    std::mutex mtx;
-    std::unique_lock<std::mutex> lk {mtx};
-    std::condition_variable cv;
     std::map<std::string, std::shared_ptr<libjami::CallbackWrapperBase>> confHandlers;
     bool requestReceived = false;
     bool conversationReady = false;
@@ -971,10 +953,7 @@ FileTransferTest::testRemoveHardLink()
     wait_for_announcement_of(carlaId);
 
     std::map<std::string, std::shared_ptr<libjami::CallbackWrapperBase>> confHandlers;
-    std::mutex mtx;
-    std::unique_lock<std::mutex> lk {mtx};
-    std::condition_variable cv;
-    auto messageReceived = false;
+    bool messageReceived = false;
     confHandlers.insert(libjami::exportable_callback<libjami::ConversationSignal::MessageReceived>(
         [&](const std::string& /*accountId*/,
             const std::string& /* conversationId */,
@@ -1020,6 +999,90 @@ FileTransferTest::testRemoveHardLink()
     libjami::unregisterSignalHandlers();
 }
 
+void
+FileTransferTest::testTooLarge()
+{
+    auto aliceAccount = Manager::instance().getAccount<JamiAccount>(aliceId);
+    auto bobAccount = Manager::instance().getAccount<JamiAccount>(bobId);
+    auto bobUri = bobAccount->getUsername();
+
+    auto convId = libjami::startConversation(aliceId);
+
+    std::map<std::string, std::shared_ptr<libjami::CallbackWrapperBase>> confHandlers;
+    bool memberJoined = false;
+    std::string tidBob, iidBob;
+    confHandlers.insert(libjami::exportable_callback<libjami::ConversationSignal::MessageReceived>(
+        [&](const std::string& accountId,
+            const std::string& /* conversationId */,
+            std::map<std::string, std::string> message) {
+            if (message["type"] == "application/data-transfer+json") {
+                if (accountId == bobId) {
+                    tidBob = message["fileId"];
+                    iidBob = message["id"];
+                }
+            } else if (accountId == aliceId && message["type"] == "member"
+                       && message["action"] == "join") {
+                memberJoined = true;
+            }
+            cv.notify_one();
+        }));
+    auto requestReceived = false;
+    confHandlers.insert(
+        libjami::exportable_callback<libjami::ConversationSignal::ConversationRequestReceived>(
+            [&](const std::string& /*accountId*/,
+                const std::string& /* conversationId */,
+                std::map<std::string, std::string> /*metadatas*/) {
+                requestReceived = true;
+                cv.notify_one();
+            }));
+    auto conversationReady = false;
+    confHandlers.insert(libjami::exportable_callback<libjami::ConversationSignal::ConversationReady>(
+        [&](const std::string& /*accountId*/, const std::string& /* conversationId */) {
+            conversationReady = true;
+            cv.notify_one();
+        }));
+    bool cancelled = false;
+    confHandlers.insert(libjami::exportable_callback<libjami::DataTransferSignal::DataTransferEvent>(
+        [&](const std::string& accountId,
+            const std::string& conversationId,
+            const std::string&,
+            const std::string& fileId,
+            int code) {
+            if (conversationId == convId && code == static_cast<int>(libjami::DataTransferEventCode::closed_by_host))
+                cancelled = true;
+            cv.notify_one();
+        }));
+    libjami::registerSignalHandlers(confHandlers);
+
+    libjami::addConversationMember(aliceId, convId, bobUri);
+    cv.wait_for(lk, 60s, [&]() { return requestReceived; });
+
+    conversationReady = false;
+    libjami::acceptConversationRequest(bobId, convId);
+    cv.wait_for(lk, 30s, [&]() { return conversationReady && memberJoined; });
+
+    // Send file
+    std::ofstream sendFile(sendPath);
+    CPPUNIT_ASSERT(sendFile.is_open());
+    sendFile << std::string(64000, 'A');
+    sendFile.close();
+
+    libjami::sendFile(aliceId, convId, sendPath, "SEND", "");
+    CPPUNIT_ASSERT(cv.wait_for(lk, 45s, [&]() { return !tidBob.empty(); }));
+
+    // Add some data for the reception. This will break the final shasum
+    std::ofstream recvFile(recvPath);
+    CPPUNIT_ASSERT(recvFile.is_open());
+    recvFile << std::string(1000, 'B');
+    recvFile.close();
+    libjami::downloadFile(bobId, convId, iidBob, tidBob, recvPath);
+
+    CPPUNIT_ASSERT(cv.wait_for(lk, 20s, [&]() { return cancelled; }));
+    CPPUNIT_ASSERT(!fileutils::isFile(recvPath));
+
+    libjami::unregisterSignalHandlers();
+}
+
 } // namespace test
 } // namespace jami
 
-- 
GitLab