diff options
Diffstat (limited to 'wsd')
-rw-r--r-- | wsd/DocumentBroker.cpp | 4 | ||||
-rw-r--r-- | wsd/LOOLWSD.cpp | 14 | ||||
-rw-r--r-- | wsd/LOOLWSD.hpp | 5 | ||||
-rw-r--r-- | wsd/QuarantineUtil.cpp | 150 | ||||
-rw-r--r-- | wsd/QuarantineUtil.hpp | 27 |
5 files changed, 198 insertions, 2 deletions
diff --git a/wsd/DocumentBroker.cpp b/wsd/DocumentBroker.cpp index 42d9f08c5c..ac2489cb80 100644 --- a/wsd/DocumentBroker.cpp +++ b/wsd/DocumentBroker.cpp @@ -34,6 +34,7 @@ #include "TileCache.hpp" #include "ProxyProtocol.hpp" #include "Util.hpp" +#include "QuarantineUtil.hpp" #include <common/Log.hpp> #include <common/Message.hpp> #include <common/Clipboard.hpp> @@ -1136,6 +1137,9 @@ void DocumentBroker::handleSaveResponse(const std::string& sessionId, bool succe // DocBroker will have to decide to upload or skip. const std::string oldName = _storage->getRootFilePathToUpload(); const std::string newName = _storage->getRootFilePathUploading(); + + Quarantine::quarantineFile(this, _storage->getFileInfo().getFilename() + TO_UPLOAD_SUFFIX); + if (rename(oldName.c_str(), newName.c_str()) < 0) { // It's not an error if there was no file to rename, when the document isn't modified. diff --git a/wsd/LOOLWSD.cpp b/wsd/LOOLWSD.cpp index 597b857714..632ad3f6ad 100644 --- a/wsd/LOOLWSD.cpp +++ b/wsd/LOOLWSD.cpp @@ -887,6 +887,8 @@ static std::string UnitTestLibrary; unsigned int LOOLWSD::NumPreSpawnedChildren = 0; std::unique_ptr<TraceFileWriter> LOOLWSD::TraceDumper; +std::unordered_map<std::string, std::vector<std::string>> LOOLWSD::QuarantineMap; +std::string LOOLWSD::QuarantinePath; #if !MOBILEAPP std::unique_ptr<ClipboardCache> LOOLWSD::SavedClipboards; #endif @@ -1125,7 +1127,9 @@ void LOOLWSD::innerInitialize(Application& self) #ifdef ENABLE_FEATURE_RESTRICTION { "restricted_commands", "" }, #endif - { "user_interface.mode", USER_INTERFACE_MODE } + { "user_interface.mode", USER_INTERFACE_MODE }, + {"quarantine_files.limit_dir_size_mb", "250"}, + {"quarantine_files.max_versions_to_maintain", "2"} }; // Set default values, in case they are missing from the config file. @@ -1453,6 +1457,14 @@ void LOOLWSD::innerInitialize(Application& self) FileServerRoot = getPathFromConfig("file_server_root_path"); LOG_DBG("FileServerRoot after config: " << FileServerRoot); + //creating quarantine directory + QuarantinePath = FileServerRoot + "quarantine/"; + Poco::File p(QuarantinePath); + p.createDirectories(); + LOG_INF("Created quarantine directory " + p.path()); + + Quarantine::createQuarantineMap(); + WelcomeFilesRoot = getPathFromConfig("welcome.path"); if (!getConfigValue<bool>(conf, "welcome.enable", true)) WelcomeFilesRoot = ""; diff --git a/wsd/LOOLWSD.hpp b/wsd/LOOLWSD.hpp index 50c82e5f05..5a14e39bd8 100644 --- a/wsd/LOOLWSD.hpp +++ b/wsd/LOOLWSD.hpp @@ -13,6 +13,7 @@ #include <cstdio> #include <map> #include <set> +#include <unordered_map> #include <unordered_set> #include <string> #include <utility> @@ -28,7 +29,7 @@ #include "FileUtil.hpp" #include "RequestDetails.hpp" #include "WebSocketHandler.hpp" - +#include "QuarantineUtil.hpp" class ChildProcess; class TraceFileWriter; class DocumentBroker; @@ -263,6 +264,8 @@ public: static bool IsProxyPrefixEnabled; static std::atomic<unsigned> NumConnections; static std::unique_ptr<TraceFileWriter> TraceDumper; + static std::unordered_map<std::string, std::vector<std::string>> QuarantineMap; + static std::string QuarantinePath; #if !MOBILEAPP static std::unique_ptr<ClipboardCache> SavedClipboards; #endif diff --git a/wsd/QuarantineUtil.cpp b/wsd/QuarantineUtil.cpp new file mode 100644 index 0000000000..6a286a5a67 --- /dev/null +++ b/wsd/QuarantineUtil.cpp @@ -0,0 +1,150 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */ +/* + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#include "QuarantineUtil.hpp" + +#include <Poco/Path.h> +#include <Poco/URI.h> +#include "ClientSession.hpp" +#include "LOOLWSD.hpp" +#include "DocumentBroker.hpp" + +#include <common/Common.hpp> +#include <common/StringVector.hpp> +#include <common/Log.hpp> + +namespace Quarantine +{ + void createQuarantineMap() + { + std::vector<std::string> files; + Poco::File(LOOLWSD::QuarantinePath).list(files); + LOOLWSD::QuarantineMap.clear(); + + std::vector<StringToken> tokens; + std::string decoded; + + std::sort(files.begin(), files.end()); + for (auto file : files) + { + + Util::tokenize(file.c_str(), file.size(), '_', tokens); + Poco::URI::decode(file.substr(tokens[2]._index), decoded); + LOOLWSD::QuarantineMap[decoded].emplace_back(LOOLWSD::QuarantinePath + file); + + tokens.clear(); + decoded.clear(); + } + } + + void removeQuarantine() + { + FileUtil::removeFile(LOOLWSD::QuarantinePath, true); + } + + // returns quarentine directory size in bytes + // files with hardlink count of more than 1 is not counted + // because they are originally stored in jails + std::size_t quarantineSize() + { + std::vector<std::string> files; + Poco::File(LOOLWSD::QuarantinePath).list(files); + std::size_t size = 0; + for (auto file : files) + { + FileUtil::Stat f(LOOLWSD::QuarantinePath + file); + + if (f.hardLinkCount() == 1) + size += f.size(); + } + return size; + } + + void makeQuarantineSpace() + { + std::size_t sizeLimit = LOOLWSD::getConfigValue<std::size_t>("quarantine_files.limit_dir_size_mb", 0)*1024*1024; + + if(sizeLimit == 0) + return; + + std::vector<std::string> files; + Poco::File(LOOLWSD::QuarantinePath).list(files); + + std::sort(files.begin(), files.end()); + + std::size_t currentSize = quarantineSize(); + std::size_t index = 0; + while (currentSize >= sizeLimit && !files.empty()) + { + FileUtil::Stat file(LOOLWSD::QuarantinePath + files[index]); + if(file.hardLinkCount() != 1) + { + index++; + continue; + } + currentSize -= file.size(); + FileUtil::removeFile(LOOLWSD::QuarantinePath + files[index], true); + files.erase(files.begin()); + } + } + + void clearOldQuarantineVersions(std::string Wopiscr) + { + std::size_t maxVersionCount = LOOLWSD::getConfigValue<std::size_t>("quarantine_files.max_versions_to_maintain", 2); + std::string decoded; + Poco::URI::decode(Wopiscr, decoded); + while (LOOLWSD::QuarantineMap[decoded].size() > maxVersionCount) + { + FileUtil::removeFile(LOOLWSD::QuarantineMap[decoded][0]); + LOOLWSD::QuarantineMap[decoded].erase(LOOLWSD::QuarantineMap[decoded].begin()); + } + + } + + bool quarantineFile(DocumentBroker* docBroker, std::string docName) + { + //return if directory size limit is 0 + std::size_t sizeLimit = LOOLWSD::getConfigValue<std::size_t>("quarantine_files.limit_dir_size_mb", 0); + + if (sizeLimit == 0) + return false; + + std::string docKey; + Poco::URI::encode(docBroker->getDocKey(), "?#/", docKey); + + const auto timeNow = std::chrono::system_clock::now(); + const std::string ts = std::to_string(std::chrono::duration_cast<std::chrono::seconds>(timeNow.time_since_epoch()).count()); + + std::string sourcefilePath = LOOLWSD::ChildRoot + "tmp/lool-" + docBroker->getJailId() + "/user/docs/" + docBroker->getJailId() + "/" + docName; + + std::string linkedFileName = ts + "_" + std::to_string(docBroker->getPid()) + "_" + docKey; + std::string linkedFilePath = LOOLWSD::QuarantinePath + linkedFileName; + + FileUtil::Stat fileStat(linkedFilePath); + + makeQuarantineSpace(); + + int result_link = link(sourcefilePath.c_str(),linkedFilePath.c_str()); + + if(result_link == 0) + { + LOOLWSD::QuarantineMap[docBroker->getDocKey()].emplace_back(linkedFilePath); + clearOldQuarantineVersions(docKey); + makeQuarantineSpace(); + + LOG_INF("Quarantined " + sourcefilePath + " to " + linkedFilePath); + return true; + } + else + { + LOG_ERR("Quarantining of file " + sourcefilePath + " filed"); + return false; + } + + return false; + } +}
\ No newline at end of file diff --git a/wsd/QuarantineUtil.hpp b/wsd/QuarantineUtil.hpp new file mode 100644 index 0000000000..1fb629c549 --- /dev/null +++ b/wsd/QuarantineUtil.hpp @@ -0,0 +1,27 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */ +/* + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#pragma once + +#include <config.h> +#include <string> + +class DocumentBroker; +namespace Quarantine +{ + void createQuarantineMap(); + + void removeQuarantine(); + + std::size_t quarantineSize(); + + void makeQuarantineSpace(); + + void clearOldQuarantineVersions(std::string Wopiscr); + + bool quarantineFile(DocumentBroker* docBroker, std::string docName); +} |