diff --git a/src/data_transfer.cpp b/src/data_transfer.cpp index 4d0371a7e5980ce00c9b45709044fae7e209f0fd..8b75209978b7fa6e92b88fa2d90988241e548040 100644 --- a/src/data_transfer.cpp +++ b/src/data_transfer.cpp @@ -203,21 +203,16 @@ IncomingFile::process() auto shared = w.lock(); if (!shared) return; - auto isEOF = shared->info_.bytesProgress == shared->info_.totalSize; - if (shared->stream_ && shared->stream_.is_open()) { - isEOF |= shared->stream_.eof(); - shared->stream_.close(); - } - auto correct = isEOF && shared->sha3Sum_.empty(); - if (!correct && !shared->sha3Sum_.empty()) { + auto correct = shared->sha3Sum_.empty(); + if (!correct) { // Verify shaSum auto sha3Sum = fileutils::sha3File(shared->info_.path); - if (shared->sha3Sum_ == sha3Sum) { - JAMI_INFO() << "New file received: " << shared->info_.path; - correct = true; - } else if (isEOF || shared->isUserCancelled_) { + if (shared->isUserCancelled_) { JAMI_WARN() << "Remove file, invalid sha3sum detected for " << shared->info_.path; fileutils::remove(shared->info_.path, true); + } else if (shared->sha3Sum_ == sha3Sum) { + JAMI_INFO() << "New file received: " << shared->info_.path; + correct = true; } else { JAMI_WARN() << "Invalid sha3sum detected, unfinished file: " << shared->info_.path; } @@ -486,12 +481,17 @@ TransferManager::path(const std::string& fileId) const } void -TransferManager::onIncomingProfile(const std::shared_ptr<ChannelSocket>& channel) +TransferManager::onIncomingProfile(const std::shared_ptr<ChannelSocket>& channel, const std::string& sha3Sum) { if (!channel) return; auto name = channel->name(); + auto sep = name.find_last_of('?'); + std::string arguments; + if (sep != std::string::npos) + name = name.substr(0, sep); + auto lastSep = name.find_last_of('/'); auto fileId = name.substr(lastSep + 1); @@ -521,7 +521,7 @@ TransferManager::onIncomingProfile(const std::shared_ptr<ChannelSocket>& channel fileutils::recursive_mkdir(recvDir); info.path = fmt::format("{:s}{:s}_{:s}_{}", recvDir, deviceId, uri, tid); - auto ifile = std::make_shared<IncomingFile>(std::move(channel), info, "profile.vcf", ""); + auto ifile = std::make_shared<IncomingFile>(std::move(channel), info, "profile.vcf", "", sha3Sum); auto res = pimpl_->vcards_.emplace(idx, std::move(ifile)); if (res.second) { res.first->second->onFinished([w = weak(), diff --git a/src/data_transfer.h b/src/data_transfer.h index ffb84d360fd939767b498dc627634f4f01839ed8..89fc10a07433922f212c5e24152f94c47dd7ec15 100644 --- a/src/data_transfer.h +++ b/src/data_transfer.h @@ -195,7 +195,7 @@ public: */ std::vector<WaitingRequest> waitingRequests() const; bool isWaiting(const std::string& fileId) const; - void onIncomingProfile(const std::shared_ptr<ChannelSocket>& channel); + void onIncomingProfile(const std::shared_ptr<ChannelSocket>& channel, const std::string& sha3Sum = ""); /** * @param contactId contact's id diff --git a/src/jamidht/jamiaccount.cpp b/src/jamidht/jamiaccount.cpp index 11ff5685891f1788da88505cc0cb5b87ba6e54d8..0a90cdba6929f09145da9db4495d715d854db9d0 100644 --- a/src/jamidht/jamiaccount.cpp +++ b/src/jamidht/jamiaccount.cpp @@ -3678,13 +3678,16 @@ JamiAccount::requestSIPConnection(const std::string& peerId, void JamiAccount::sendProfile(const std::string& convId, const std::string& peerUri, const std::string& deviceId) { + if (not fileutils::isFile(fmt::format("{}/profile.vcf", idPath_))) + return; + auto currentSha3 = fileutils::sha3File(fmt::format("{}/profile.vcf", idPath_)); // VCard sync for peerUri - if (not needToSendProfile(peerUri, deviceId)) { + if (not needToSendProfile(peerUri, deviceId, currentSha3)) { JAMI_DEBUG("Peer {} already got an up-to-date vcard", peerUri); return; } // We need a new channel - transferFile(convId, profilePath(), deviceId, "profile.vcf", "", 0, 0, std::move([accId = getAccountID(), peerUri, deviceId]() { + transferFile(convId, profilePath(), deviceId, "profile.vcf", "", 0, 0, currentSha3, std::move([accId = getAccountID(), peerUri, deviceId]() { // Mark the VCard as sent auto sendDir = fmt::format("{}/{}/vcard/{}", fileutils::get_cache_dir(), @@ -3700,9 +3703,8 @@ JamiAccount::sendProfile(const std::string& convId, const std::string& peerUri, } bool -JamiAccount::needToSendProfile(const std::string& peerUri, const std::string& deviceId) +JamiAccount::needToSendProfile(const std::string& peerUri, const std::string& deviceId, const std::string& sha3Sum) { - auto currentSha3 = fileutils::sha3File(fmt::format("{}/profile.vcf", idPath_)); std::string previousSha3 {}; auto vCardPath = fmt::format("{}/vcard", cachePath_); auto sha3Path = fmt::format("{}/sha3", vCardPath); @@ -3710,14 +3712,14 @@ JamiAccount::needToSendProfile(const std::string& peerUri, const std::string& de try { previousSha3 = fileutils::loadTextFile(sha3Path); } catch (...) { - fileutils::saveFile(sha3Path, {currentSha3.begin(), currentSha3.end()}, 0600); + fileutils::saveFile(sha3Path, {sha3Sum.begin(), sha3Sum.end()}, 0600); return true; } - if (currentSha3 != previousSha3) { + if (sha3Sum != previousSha3) { // Incorrect sha3 stored. Update it fileutils::removeAll(vCardPath, true); fileutils::check_dir(vCardPath.c_str(), 0700); - fileutils::saveFile(sha3Path, {currentSha3.begin(), currentSha3.end()}, 0600); + fileutils::saveFile(sha3Path, {sha3Sum.begin(), sha3Sum.end()}, 0600); return true; } fileutils::recursive_mkdir(fmt::format("{}/{}/", vCardPath, peerUri)); @@ -4000,14 +4002,19 @@ JamiAccount::transferFile(const std::string& conversationId, const std::string& interactionId, size_t start, size_t end, + const std::string& sha3Sum, std::function<void()> onFinished) { - auto channelName = conversationId.empty() ? fmt::format("{}profile.vcf", DATA_TRANSFER_URI) + auto fid = fileId; + if (fid == "profile.vcf") { + fid = fmt::format("profile.vcf?sha3={}", sha3Sum); + } + auto channelName = conversationId.empty() ? fmt::format("{}profile.vcf?sha3={}", DATA_TRANSFER_URI, sha3Sum) : fmt::format("{}{}/{}/{}", DATA_TRANSFER_URI, conversationId, currentDeviceId(), - fileId); + fid); std::lock_guard<std::mutex> lkCM(connManagerMtx_); if (!connectionManager_) return; diff --git a/src/jamidht/jamiaccount.h b/src/jamidht/jamiaccount.h index d3dda1f04a92bb90bd55ccc6cf88d4bb5d7be3ce..f1a5aa1d085b8a8d5c2e8f8dea5e78b7d6c01f7c 100644 --- a/src/jamidht/jamiaccount.h +++ b/src/jamidht/jamiaccount.h @@ -520,6 +520,7 @@ public: const std::string& interactionId, size_t start = 0, size_t end = 0, + const std::string& sha3Sum = "", std::function<void()> onFinished = {}); void askForFileChannel(const std::string& conversationId, @@ -547,9 +548,10 @@ public: * Check (via the cache) if we need to send our profile to a specific device * @param peerUri Uri that will receive the profile * @param deviceId Device that will receive the profile + * @param sha3Sum SHA3 hash of the profile */ // Note: when swarm will be merged, this can be moved in transferManager - bool needToSendProfile(const std::string& peerUri, const std::string& deviceId); + bool needToSendProfile(const std::string& peerUri, const std::string& deviceId, const std::string& sha3Sum); /** * Send Profile via cached SIP connection * @param convId Conversation's identifier (can be empty for self profile on sync) diff --git a/src/jamidht/transfer_channel_handler.cpp b/src/jamidht/transfer_channel_handler.cpp index e9c905fd2fd3c6ea9ca19e2ae1a0f2d0807d54a3..7eca025f3d626e8340b31981332bde4b25845cf0 100644 --- a/src/jamidht/transfer_channel_handler.cpp +++ b/src/jamidht/transfer_channel_handler.cpp @@ -54,11 +54,14 @@ TransferChannelHandler::onRequest(const std::shared_ptr<dht::crypto::Certificate auto uri = cert->issuer->getId().toString(); // Else, check if it's a profile or file in a conversation. auto idstr = name.substr(16); + // Remove arguments for now + auto sep = idstr.find_last_of('?'); + idstr = idstr.substr(0, sep); if (idstr == "profile.vcf") { // If it's our profile from another device return uri == acc->getUsername(); } - auto sep = idstr.find('/'); + sep = idstr.find('/'); auto lastSep = idstr.find_last_of('/'); auto conversationId = idstr.substr(0, sep); auto fileHost = idstr.substr(sep + 1, lastSep - sep - 1); @@ -66,11 +69,6 @@ TransferChannelHandler::onRequest(const std::shared_ptr<dht::crypto::Certificate if (fileHost == acc->currentDeviceId()) return false; - sep = fileId.find_last_of('?'); - if (sep != std::string::npos) { - fileId = fileId.substr(0, sep); - } - // Check if peer is member of the conversation if (fileId == fmt::format("{}.vcf", acc->getUsername()) || fileId == "profile.vcf") { // Or a member from the conversation @@ -98,9 +96,33 @@ TransferChannelHandler::onReady(const std::shared_ptr<dht::crypto::Certificate>& return; auto idstr = name.substr(16); + // Parse arguments + auto sep = idstr.find_last_of('?'); + std::string arguments; + if (sep != std::string::npos) { + arguments = idstr.substr(sep + 1); + idstr = idstr.substr(0, sep); + } + + auto start = 0u, end = 0u; + std::string sha3Sum; + for (const auto arg : split_string(arguments, '&')) { + auto keyVal = split_string(arg, '='); + if (keyVal.size() == 2) { + if (keyVal[0] == "start") { + start = to_int<unsigned>(keyVal[1]); + } else if (keyVal[0] == "end") { + end = to_int<unsigned>(keyVal[1]); + } else if (keyVal[0] == "sha3") { + sha3Sum = keyVal[1]; + } + } + } + + // Check if profile if (idstr == "profile.vcf") { if (!channel->isInitiator()) { - acc->dataTransfer()->onIncomingProfile(channel); + acc->dataTransfer()->onIncomingProfile(channel, sha3Sum); } else { // If it's a profile from sync std::string path = fmt::format("{}/profile.vcf", idPath_); @@ -124,13 +146,6 @@ TransferChannelHandler::onReady(const std::shared_ptr<dht::crypto::Certificate>& if (channel->isInitiator()) return; - auto sep = fileId.find_last_of('?'); - std::string arguments; - if (sep != std::string::npos) { - arguments = fileId.substr(sep + 1); - fileId = fileId.substr(0, sep); - } - // Profile for a member in the conversation if (fileId == fmt::format("{}.vcf", acc->getUsername())) { std::string path = fmt::format("{}/profile.vcf", idPath_); @@ -141,7 +156,7 @@ TransferChannelHandler::onReady(const std::shared_ptr<dht::crypto::Certificate>& acc->dataTransfer()->transferFile(channel, fileId, "", path); return; } else if (fileId == "profile.vcf") { - acc->dataTransfer()->onIncomingProfile(channel); + acc->dataTransfer()->onIncomingProfile(channel, sha3Sum); return; } // Check if it's a file in a conversation @@ -153,18 +168,6 @@ TransferChannelHandler::onReady(const std::shared_ptr<dht::crypto::Certificate>& } auto interactionId = fileId.substr(0, sep); std::string path = dt->path(fileId); - auto start = 0u, end = 0u; - for (const auto arg : split_string(arguments, '&')) { - auto keyVal = split_string(arg, '='); - if (keyVal.size() == 2) { - if (keyVal[0] == "start") { - start = to_int<unsigned>(keyVal[1]); - } else if (keyVal[0] == "end") { - end = to_int<unsigned>(keyVal[1]); - } - } - } - dt->transferFile(channel, fileId, interactionId, path, start, end); }