Makefile.am | 4
common/Anonymizer.hpp | 101 +++++++++++++
common/FileUtil.cpp | 13 -
common/Session.cpp | 17 +-
common/Unit.hpp | 7
common/Util.cpp | 74 ---------
common/Util.hpp | 15 --
kit/ChildSession.cpp | 14 -
kit/Kit.cpp | 17 +-
kit/KitWebSocket.cpp | 5
test/KitPidHelpers.cpp | 11 -
test/UnitWOPI.cpp | 1
test/WhiteBoxTests.cpp | 47 +++---
tools/Config.cpp | 12 -
wsd/Admin.cpp | 1
wsd/AdminModel.cpp | 1
wsd/Auth.cpp | 1
wsd/COOLWSD.cpp | 4
wsd/COOLWSD.hpp | 205 ---------------------------
wsd/ClientRequestDispatcher.cpp | 4
wsd/DocumentBroker.cpp | 7
wsd/DocumentBroker.hpp | 86 -----------
wsd/Process.hpp | 297 ++++++++++++++++++++++++++++++++++++++++
wsd/ProofKey.cpp | 1
wsd/RequestVettingStation.cpp | 7
wsd/SpecialBrokers.cpp | 10 -
wsd/Storage.hpp | 5
wsd/wopi/WopiProxy.cpp | 7
wsd/wopi/WopiStorage.cpp | 20 +-
29 files changed, 528 insertions(+), 466 deletions(-)
New commits:
commit fc2c44198812060095d016000906e9d926af1735
Author: Ashod Nakashian <
ashod.n...@collabora.co.uk>
AuthorDate: Sun Oct 27 14:04:28 2024 -0400
Commit: Ashod Nakashian <
As...@users.noreply.github.com>
CommitDate: Wed Nov 20 08:03:33 2024 -0500
wsd: move anonymization implementation to own home
This is non-functional refactoring. It will
be followed by some improvements.
Change-Id: Icada6372e684e3ca8fcac7d2f8350ec2804d23da
Signed-off-by: Ashod Nakashian <
ashod.n...@collabora.co.uk>
diff --git a/Makefile.am b/Makefile.am
index 237c35891c..b796db211e 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -360,7 +360,8 @@ wsd_headers = wsd/Admin.hpp \
wsd/wopi/WopiProxy.hpp \
wsd/wopi/WopiStorage.hpp
-shared_headers = common/Common.hpp \
+shared_headers = common/Anonymizer.hpp \
+ common/Common.hpp \
common/CharacterConverter.hpp \
common/Clipboard.hpp \
common/Crypto.hpp \
diff --git a/common/Anonymizer.hpp b/common/Anonymizer.hpp
new file mode 100644
index 0000000000..d02cf4eadd
--- /dev/null
+++ b/common/Anonymizer.hpp
@@ -0,0 +1,101 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */
+/*
+ * Copyright the Collabora Online contributors.
+ *
+ * SPDX-License-Identifier: MPL-2.0
+ *
+ * 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 <common/Log.hpp>
+#include <common/Util.hpp>
+
+#include <atomic>
+#include <mutex>
+#include <string>
+#include <unordered_map>
+
+extern std::unordered_map<std::string, std::string> AnonymizedStrings;
+extern std::mutex AnonymizedMutex;
+
+/// Responsible for annonymizing names and URLs.
+/// The anonymized version is always the same for
+/// a given value, provided the salt is identical.
+class Anonymizer
+{
+public:
+ /// Sets the anonymized version of a given plain-text string.
+ /// After this, 'anonymize(plain)' will return 'anonymized'.
+ static void mapAnonymized(const std::string& plain, const std::string& anonymized)
+ {
+ if (plain.empty() || anonymized.empty())
+ return;
+
+ if (plain != anonymized)
+ LOG_TRC("Anonymizing [" << plain << "] -> [" << anonymized << "].");
+
+ std::unique_lock<std::mutex> lock(AnonymizedMutex);
+
+ AnonymizedStrings[plain] = anonymized;
+ }
+
+ /// Anonymize a sensitive string to avoid leaking it.
+ /// Called on strings to be logged or exposed.
+ static std::string anonymize(const std::string& text, const std::uint64_t nAnonymizationSalt)
+ {
+ {
+ std::unique_lock<std::mutex> lock(AnonymizedMutex);
+
+ const auto it = AnonymizedStrings.find(text);
+ if (it != AnonymizedStrings.end())
+ {
+ if (text != it->second)
+ LOG_TRC("Found anonymized [" << text << "] -> [" << it->second << "].");
+ return it->second;
+ }
+ }
+
+ // Modified 64-bit FNV-1a to add salting.
+ // For the algorithm and the magic numbers, see
http://isthe.com/chongo/tech/comp/fnv/
+ std::uint64_t hash = 0xCBF29CE484222325LL;
+ hash ^= nAnonymizationSalt;
+ hash *= 0x100000001b3ULL;
+ for (const char c : text)
+ {
+ hash ^= static_cast<std::uint64_t>(c);
+ hash *= 0x100000001b3ULL;
+ }
+
+ hash ^= nAnonymizationSalt;
+ hash *= 0x100000001b3ULL;
+
+ // Generate the anonymized string. The '#' is to hint that it's anonymized.
+ // Prepend with count to make it unique within a single process instance,
+ // in case we get collisions (which we will, eventually). N.B.: Identical
+ // strings likely to have different prefixes when logged in WSD process vs. Kit.
+ static std::atomic<unsigned> AnonymizationCounter(0);
+ std::string res =
+ '#' + Util::encodeId(AnonymizationCounter++, 0) + '#' + Util::encodeId(hash, 0) + '#';
+ mapAnonymized(text, res);
+ return res;
+ }
+
+ /// Clears the shared state of mapAnonymized() / anonymize().
+ static void clearAnonymized() { AnonymizedStrings.clear(); }
+
+ /// Anonymize the basename of filenames only, preserving the path and extension.
+ static std::string anonymizeUrl(const std::string& url, const std::uint64_t nAnonymizationSalt)
+ {
+ std::string base;
+ std::string filename;
+ std::string ext;
+ std::string params;
+ std::tie(base, filename, ext, params) = Util::splitUrl(url);
+
+ return base + anonymize(filename, nAnonymizationSalt) + ext + params;
+ }
+};
diff --git a/common/FileUtil.cpp b/common/FileUtil.cpp
index af3e12c537..abe2e7208c 100644
--- a/common/FileUtil.cpp
+++ b/common/FileUtil.cpp
@@ -13,6 +13,11 @@
#include "FileUtil.hpp"
+#include <common/Anonymizer.hpp>
+#include <common/Log.hpp>
+#include <common/Unit.hpp>
+#include <common/Util.hpp>
+
#include <dirent.h>
#include <exception>
#include <ftw.h>
@@ -43,10 +48,6 @@
#include <Poco/File.h>
#include <Poco/Path.h>
-#include "Log.hpp"
-#include "Util.hpp"
-#include "Unit.hpp"
-
namespace FileUtil
{
std::string createRandomDir(const std::string& path)
@@ -621,14 +622,14 @@ namespace FileUtil
/// Anonymize the basename of filenames, preserving the path and extension.
std::string anonymizeUrl(const std::string& url)
{
- return AnonymizeUserData ? Util::anonymizeUrl(url, AnonymizationSalt) : url;
+ return AnonymizeUserData ? Anonymizer::anonymizeUrl(url, AnonymizationSalt) : url;
}
/// Anonymize user names and IDs.
/// Will use the Obfuscated User ID if one is provided via WOPI.
std::string anonymizeUsername(const std::string& username)
{
- return AnonymizeUserData ? Util::anonymize(username, AnonymizationSalt) : username;
+ return AnonymizeUserData ? Anonymizer::anonymize(username, AnonymizationSalt) : username;
}
std::string extractFileExtension(const std::string& path)
diff --git a/common/Session.cpp b/common/Session.cpp
index 03175d39fe..253a42f822 100644
--- a/common/Session.cpp
+++ b/common/Session.cpp
@@ -13,16 +13,17 @@
#include "Session.hpp"
+#include <common/Anonymizer.hpp>
+#include <common/Log.hpp>
+#include <common/Protocol.hpp>
+#include <common/Uri.hpp>
+#include <common/Util.hpp>
+
#include <Poco/Exception.h>
#include <Poco/Path.h>
#include <Poco/String.h>
#include <Poco/URI.h>
-#include <common/Uri.hpp>
-#include "Protocol.hpp"
-#include "Log.hpp"
-#include "Util.hpp"
-
using namespace COOLProtocol;
using Poco::Exception;
@@ -240,9 +241,9 @@ void Session::parseDocOptions(const StringVector& tokens, int& part, std::string
}
}
- Util::mapAnonymized(_userId, _userIdAnonym);
- Util::mapAnonymized(_userName, _userNameAnonym);
- Util::mapAnonymized(_jailedFilePath, _jailedFilePathAnonym);
+ Anonymizer::mapAnonymized(_userId, _userIdAnonym);
+ Anonymizer::mapAnonymized(_userName, _userNameAnonym);
+ Anonymizer::mapAnonymized(_jailedFilePath, _jailedFilePathAnonym);
if (tokens.size() > offset)
{
diff --git a/common/Util.cpp b/common/Util.cpp
index 469652943d..22f59c8544 100644
--- a/common/Util.cpp
+++ b/common/Util.cpp
@@ -80,6 +80,9 @@
#include "Protocol.hpp"
#include "TraceEvent.hpp"
+std::unordered_map<std::string, std::string> AnonymizedStrings;
+std::mutex AnonymizedMutex;
+
namespace Util
{
namespace rng
@@ -481,77 +484,6 @@ namespace Util
return std::make_tuple(base, filename, ext, params);
}
- static std::unordered_map<std::string, std::string> AnonymizedStrings;
- static std::atomic<unsigned> AnonymizationCounter(0);
- static std::mutex AnonymizedMutex;
-
- void mapAnonymized(const std::string& plain, const std::string& anonymized)
- {
- if (plain.empty() || anonymized.empty())
- return;
-
- if (Log::traceEnabled() && plain != anonymized)
- LOG_TRC("Anonymizing [" << plain << "] -> [" << anonymized << "].");
-
- std::unique_lock<std::mutex> lock(AnonymizedMutex);
-
- AnonymizedStrings[plain] = anonymized;
- }
-
- std::string anonymize(const std::string& text, const std::uint64_t nAnonymizationSalt)
- {
- {
- std::unique_lock<std::mutex> lock(AnonymizedMutex);
-
- const auto it = AnonymizedStrings.find(text);
- if (it != AnonymizedStrings.end())
- {
- if (Log::traceEnabled() && text != it->second)
- LOG_TRC("Found anonymized [" << text << "] -> [" << it->second << "].");
- return it->second;
- }
- }
-
- // Modified 64-bit FNV-1a to add salting.
- // For the algorithm and the magic numbers, see
http://isthe.com/chongo/tech/comp/fnv/
- std::uint64_t hash = 0xCBF29CE484222325LL;
- hash ^= nAnonymizationSalt;
- hash *= 0x100000001b3ULL;
- for (const char c : text)
- {
- hash ^= static_cast<std::uint64_t>(c);
- hash *= 0x100000001b3ULL;
- }
-
- hash ^= nAnonymizationSalt;
- hash *= 0x100000001b3ULL;
-
- // Generate the anonymized string. The '#' is to hint that it's anonymized.
- // Prepend with count to make it unique within a single process instance,
- // in case we get collisions (which we will, eventually). N.B.: Identical
- // strings likely to have different prefixes when logged in WSD process vs. Kit.
- std::string res
- = '#' + Util::encodeId(AnonymizationCounter++, 0) + '#' + Util::encodeId(hash, 0) + '#';
- mapAnonymized(text, res);
- return res;
- }
-
- void clearAnonymized()
- {
- AnonymizedStrings.clear();
- }
-
- std::string anonymizeUrl(const std::string& url, const std::uint64_t nAnonymizationSalt)
- {
- std::string base;
- std::string filename;
- std::string ext;
- std::string params;
- std::tie(base, filename, ext, params) = Util::splitUrl(url);
-
- return base + Util::anonymize(filename, nAnonymizationSalt) + ext + params;
- }
-
std::string getTimeNow(const char* format)
{
char time_now[64];
diff --git a/common/Util.hpp b/common/Util.hpp
index
6785312466..5f9dc7d9ed 100644
--- a/common/Util.hpp
+++ b/common/Util.hpp
@@ -1163,20 +1163,6 @@ int main(int argc, char**argv)
/// either for a URL or for a file path
std::string cleanupFilename(const std::string &filename);
- /// Anonymize a sensitive string to avoid leaking it.
- /// Called on strings to be logged or exposed.
- std::string anonymize(const std::string& text, const std::uint64_t nAnonymizationSalt);
-
- /// Sets the anonymized version of a given plain-text string.
- /// After this, 'anonymize(plain)' will return 'anonymized'.
- void mapAnonymized(const std::string& plain, const std::string& anonymized);
-
- /// Clears the shared state of mapAnonymized() / anonymize().
- void clearAnonymized();
-
- /// Anonymize the basename of filenames only, preserving the path and extension.
- std::string anonymizeUrl(const std::string& url, const std::uint64_t nAnonymizationSalt);
-
/// Return true if the subject matches in given set. It uses regex
/// Mainly used to match WOPI hosts patterns
bool matchRegex(const std::set<std::string>& set, const std::string& subject);
diff --git a/kit/ChildSession.cpp b/kit/ChildSession.cpp
index dd929343fc..7196300e9c 100644
--- a/kit/ChildSession.cpp
+++ b/kit/ChildSession.cpp
@@ -11,16 +11,17 @@
#include <config.h>
-#include "Kit.hpp"
#include "ChildSession.hpp"
-#include "MobileApp.hpp"
-#include "COOLWSD.hpp"
+
+#include <common/Anonymizer.hpp>
+#include <common/Log.hpp>
+#include <common/Unit.hpp>
+#include <common/Util.hpp>
#include <climits>
#include <fstream>
#include <memory>
#include <sstream>
-#include <regex>
#define LOK_USE_UNSTABLE_API
#include <LibreOfficeKit/LibreOfficeKitEnums.h>
@@ -49,10 +50,7 @@
#include <common/SpookyV2.h>
#include <common/Uri.hpp>
#include "KitHelper.hpp"
-#include <Log.hpp>
#include <Png.hpp>
-#include <Util.hpp>
-#include <Unit.hpp>
#include <Clipboard.hpp>
#include <string>
#include <CommandControl.hpp>
@@ -1281,7 +1279,7 @@ bool ChildSession::downloadAs(const StringVector& tokens)
}
// Obfuscate the new name.
- Util::mapAnonymized(Uri::getFilenameFromURL(name), _docManager->getObfuscatedFileId());
+ Anonymizer::mapAnonymized(Uri::getFilenameFromURL(name), _docManager->getObfuscatedFileId());
getTokenString(tokens[3], "format", format);
diff --git a/kit/Kit.cpp b/kit/Kit.cpp
index df0819ece7..39367b2872 100644
--- a/kit/Kit.cpp
+++ b/kit/Kit.cpp
@@ -15,6 +15,8 @@
#include <config.h>
+#include <common/Anonymizer.hpp>
+
#include <csignal>
#include <dlfcn.h>
#include <limits>
@@ -1972,7 +1974,7 @@ std::shared_ptr<lok::Document> Document::load(const std::shared_ptr<ChildSession
_isDocPasswordProtected = false;
const char *pURL = uri.c_str();
- LOG_DBG("Calling lokit::documentLoad(" << FileUtil::anonymizeUrl(pURL) << ", \"" << options << "\").");
+ LOG_DBG("Calling lokit::documentLoad(" << anonymizeUrl(pURL) << ", \"" << options << "\")");
const auto start = std::chrono::steady_clock::now();
_loKitDocument.reset(_loKit->documentLoad(pURL, options.c_str()));
#ifdef __ANDROID__
@@ -1980,8 +1982,7 @@ std::shared_ptr<lok::Document> Document::load(const std::shared_ptr<ChildSession
#endif
const auto duration = std::chrono::steady_clock::now() - start;
const auto elapsed = std::chrono::duration_cast<std::chrono::milliseconds>(duration);
- LOG_DBG("Returned lokit::documentLoad(" << FileUtil::anonymizeUrl(pURL) << ") in "
- << elapsed);
+ LOG_DBG("Returned lokit::documentLoad(" << anonymizeUrl(pURL) << ") in " << elapsed);
#ifdef IOS
DocumentData::get(_mobileAppDocId).loKitDocument = _loKitDocument.get();
#endif
@@ -3815,7 +3816,7 @@ TileWireId getCurrentWireId(bool increment)
std::string anonymizeUrl(const std::string& url)
{
#ifndef BUILDING_TESTS
- return AnonymizeUserData ? Util::anonymizeUrl(url, AnonymizationSalt) : url;
+ return AnonymizeUserData ? Anonymizer::anonymizeUrl(url, AnonymizationSalt) : url;
#else
return url;
#endif
@@ -3967,7 +3968,7 @@ bool globalPreinit(const std::string &loTemplate)
std::string anonymizeUsername(const std::string& username)
{
#ifndef BUILDING_TESTS
- return AnonymizeUserData ? Util::anonymize(username, AnonymizationSalt) : username;
+ return AnonymizeUserData ? Anonymizer::anonymize(username, AnonymizationSalt) : username;
#else
return username;
#endif
diff --git a/kit/KitWebSocket.cpp b/kit/KitWebSocket.cpp
index 17989944ae..c67cc33d15 100644
--- a/kit/KitWebSocket.cpp
+++ b/kit/KitWebSocket.cpp
@@ -21,13 +21,13 @@
#include <sys/wait.h>
#include <sys/types.h>
+#include <common/Anonymizer.hpp>
#include <common/Seccomp.hpp>
#include <common/JsonUtil.hpp>
#include <common/TraceEvent.hpp>
#include <common/Uri.hpp>
#include "Kit.hpp"
-#include "KitQueue.hpp"
#include "ChildSession.hpp"
#include "KitWebSocket.hpp"
@@ -68,7 +68,8 @@ void KitWebSocketHandler::handleMessage(const std::vector<char>& data)
_docKey = tokens[2];
const std::string& docId = tokens[3];
const std::string fileId = Uri::getFilenameFromURL(_docKey);
- Util::mapAnonymized(fileId, fileId); // Identity mapping, since fileId is already obfuscated
+ Anonymizer::mapAnonymized(fileId,
+ fileId); // Identity mapping, since fileId is already obfuscated
const std::string url = Uri::decode(_docKey);
#ifndef IOS
diff --git a/test/WhiteBoxTests.cpp b/test/WhiteBoxTests.cpp
index 7d8e5d87b9..081a820312 100644
--- a/test/WhiteBoxTests.cpp
+++ b/test/WhiteBoxTests.cpp
@@ -15,6 +15,7 @@
#include <cppunit/TestAssert.h>
#include <cstddef>
+#include <common/Anonymizer.hpp>
#include <Auth.hpp>
#include <ChildSession.hpp>
#include <Common.hpp>
@@ -724,52 +725,54 @@ void WhiteBoxTests::testAnonymization()
std::uint64_t nAnonymizationSalt = 1111111111182589933;
LOK_ASSERT_EQUAL(std::string("#0#5e45aef91248a8aa#"),
- Util::anonymizeUrl(name, nAnonymizationSalt));
+ Anonymizer::anonymizeUrl(name, nAnonymizationSalt));
LOK_ASSERT_EQUAL(std::string("#1#8f8d95bd2a202d00#.odt"),
- Util::anonymizeUrl(filenameTestx, nAnonymizationSalt));
+ Anonymizer::anonymizeUrl(filenameTestx, nAnonymizationSalt));
LOK_ASSERT_EQUAL(std::string("/path/to/#2#5c872b2d82ecc8a0#.ext"),
- Util::anonymizeUrl(path, nAnonymizationSalt));
+ Anonymizer::anonymizeUrl(path, nAnonymizationSalt));
LOK_ASSERT_EQUAL(
std::string("
http://localhost/owncloud/index.php/apps/richdocuments/wopi/files/"
"#3#22c6f0caad277666#?access_token=Hn0zttjbwkvGWb5BHbDa5ArgTykJAyBl&access_"
"token_ttl=0&permission=edit"),
- Util::anonymizeUrl(plainUrl, nAnonymizationSalt));
+ Anonymizer::anonymizeUrl(plainUrl, nAnonymizationSalt));
LOK_ASSERT_EQUAL(
std::string("
http://localhost/owncloud/index.php/apps/richdocuments/wopi/files/"
"736_ocgdpzbkm39u/"
"#4#294f0dfb18f6a80b#.odt?access_token=Hn0zttjbwkvGWb5BHbDa5ArgTykJAyBl&access_"
"token_ttl=0&permission=edit"),
- Util::anonymizeUrl(fileUrl, nAnonymizationSalt));
+ Anonymizer::anonymizeUrl(fileUrl, nAnonymizationSalt));
nAnonymizationSalt = 0;
- LOK_ASSERT_EQUAL(std::string("#0#5e45aef91248a8aa#"), Util::anonymizeUrl(name, nAnonymizationSalt));
- Util::mapAnonymized(name, name);
- LOK_ASSERT_EQUAL(name, Util::anonymizeUrl(name, nAnonymizationSalt));
+ LOK_ASSERT_EQUAL(std::string("#0#5e45aef91248a8aa#"),
+ Anonymizer::anonymizeUrl(name, nAnonymizationSalt));
+ Anonymizer::mapAnonymized(name, name);
+ LOK_ASSERT_EQUAL(name, Anonymizer::anonymizeUrl(name, nAnonymizationSalt));
LOK_ASSERT_EQUAL(std::string("#2#5c872b2d82ecc8a0#.ext"),
- Util::anonymizeUrl(filename, nAnonymizationSalt));
- Util::mapAnonymized("filename", "filename"); // Identity map of the filename without extension.
- LOK_ASSERT_EQUAL(filename, Util::anonymizeUrl(filename, nAnonymizationSalt));
+ Anonymizer::anonymizeUrl(filename, nAnonymizationSalt));
+ Anonymizer::mapAnonymized("filename",
+ "filename"); // Identity map of the filename without extension.
+ LOK_ASSERT_EQUAL(filename, Anonymizer::anonymizeUrl(filename, nAnonymizationSalt));
LOK_ASSERT_EQUAL(std::string("#1#8f8d95bd2a202d00#.odt"),
- Util::anonymizeUrl(filenameTestx, nAnonymizationSalt));
- Util::mapAnonymized("testx (6)",
- "testx (6)"); // Identity map of the filename without extension.
- LOK_ASSERT_EQUAL(filenameTestx, Util::anonymizeUrl(filenameTestx, nAnonymizationSalt));
+ Anonymizer::anonymizeUrl(filenameTestx, nAnonymizationSalt));
+ Anonymizer::mapAnonymized("testx (6)",
+ "testx (6)"); // Identity map of the filename without extension.
+ LOK_ASSERT_EQUAL(filenameTestx, Anonymizer::anonymizeUrl(filenameTestx, nAnonymizationSalt));
- LOK_ASSERT_EQUAL(path, Util::anonymizeUrl(path, nAnonymizationSalt));
+ LOK_ASSERT_EQUAL(path, Anonymizer::anonymizeUrl(path, nAnonymizationSalt));
const std::string urlAnonymized = Util::replace(plainUrl, "736_ocgdpzbkm39u", "#3#22c6f0caad277666#");
- LOK_ASSERT_EQUAL(urlAnonymized, Util::anonymizeUrl(plainUrl, nAnonymizationSalt));
- Util::mapAnonymized("736_ocgdpzbkm39u", "736_ocgdpzbkm39u");
- LOK_ASSERT_EQUAL(plainUrl, Util::anonymizeUrl(plainUrl, nAnonymizationSalt));
+ LOK_ASSERT_EQUAL(urlAnonymized, Anonymizer::anonymizeUrl(plainUrl, nAnonymizationSalt));
+ Anonymizer::mapAnonymized("736_ocgdpzbkm39u", "736_ocgdpzbkm39u");
+ LOK_ASSERT_EQUAL(plainUrl, Anonymizer::anonymizeUrl(plainUrl, nAnonymizationSalt));
const std::string urlAnonymized2 = Util::replace(fileUrl, "secret", "#4#294f0dfb18f6a80b#");
- LOK_ASSERT_EQUAL(urlAnonymized2, Util::anonymizeUrl(fileUrl, nAnonymizationSalt));
- Util::mapAnonymized("secret", "736_ocgdpzbkm39u");
+ LOK_ASSERT_EQUAL(urlAnonymized2, Anonymizer::anonymizeUrl(fileUrl, nAnonymizationSalt));
+ Anonymizer::mapAnonymized("secret", "736_ocgdpzbkm39u");
const std::string urlAnonymized3 = Util::replace(fileUrl, "secret", "736_ocgdpzbkm39u");
- LOK_ASSERT_EQUAL(urlAnonymized3, Util::anonymizeUrl(fileUrl, nAnonymizationSalt));
+ LOK_ASSERT_EQUAL(urlAnonymized3, Anonymizer::anonymizeUrl(fileUrl, nAnonymizationSalt));
}
void WhiteBoxTests::testIso8601Time()
diff --git a/tools/Config.cpp b/tools/Config.cpp
index c8e4d9c009..76da0031b0 100644
--- a/tools/Config.cpp
+++ b/tools/Config.cpp
@@ -11,6 +11,11 @@
#include <config.h>
+#include <common/Anonymizer.hpp>
+#include <common/ConfigUtil.hpp>
+#include <common/Crypto.hpp>
+#include <common/Util.hpp>
+
#include <iostream>
#include <iomanip>
#include <pwd.h>
@@ -33,10 +38,6 @@
#include <Poco/Util/OptionSet.h>
#include <Poco/Util/XMLConfiguration.h>
-#include <common/ConfigUtil.hpp>
-#include <Util.hpp>
-#include <Crypto.hpp>
-
using Poco::Util::Application;
using Poco::Util::HelpFormatter;
using Poco::Util::Option;
@@ -422,7 +423,8 @@ int Config::main(const std::vector<std::string>& args)
for (std::size_t i = 1; i < args.size(); ++i)
{
- std::cout << '[' << args[i] << "]: " << Util::anonymizeUrl(args[i], AnonymizationSalt) << std::endl;
+ std::cout << '[' << args[i]
+ << "]: " << Anonymizer::anonymizeUrl(args[i], AnonymizationSalt) << std::endl;
}
}
else if (args[0] == "migrateconfig")
diff --git a/wsd/COOLWSD.cpp b/wsd/COOLWSD.cpp
index 8622c5b215..93dae733e0 100644
--- a/wsd/COOLWSD.cpp
+++ b/wsd/COOLWSD.cpp
@@ -93,6 +93,7 @@
#include <Poco/Util/ServerApplication.h>
#include <Poco/Util/XMLConfiguration.h>
+#include <common/Anonymizer.hpp>
#include <ClientRequestDispatcher.hpp>
#include <Common.hpp>
#include <Clipboard.hpp>
@@ -3693,7 +3694,7 @@ int COOLWSD::innerMain()
#endif
// URI with /contents are public and we don't need to anonymize them.
- Util::mapAnonymized("contents", "contents");
+ Anonymizer::mapAnonymized("contents", "contents");
// Start the server.
Server->start();
diff --git a/wsd/ClientRequestDispatcher.cpp b/wsd/ClientRequestDispatcher.cpp
index 2896076af1..ae572a624a 100644
--- a/wsd/ClientRequestDispatcher.cpp
+++ b/wsd/ClientRequestDispatcher.cpp
@@ -15,6 +15,7 @@
#include "CommandControl.hpp"
#endif
+#include <common/Anonymizer.hpp>
#include <Admin.hpp>
#include <COOLWSD.hpp>
#include <ClientSession.hpp>
@@ -1819,7 +1820,8 @@ bool ClientRequestDispatcher::handleClientProxyRequest(const Poco::Net::HTTPRequ
auto uriPublic = RequestDetails::sanitizeURI(url);
const auto docKey = RequestDetails::getDocKey(uriPublic);
const std::string fileId = Uri::getFilenameFromURL(docKey);
- Util::mapAnonymized(fileId, fileId); // Identity mapping, since fileId is already obfuscated
+ Anonymizer::mapAnonymized(fileId,
+ fileId); // Identity mapping, since fileId is already obfuscated
LOG_INF("Starting Proxy request handler for session [" << _id << "] on url ["
<< COOLWSD::anonymizeUrl(url) << "].");
diff --git a/wsd/DocumentBroker.cpp b/wsd/DocumentBroker.cpp
index f20d9f974f..26cb2a4083 100644
--- a/wsd/DocumentBroker.cpp
+++ b/wsd/DocumentBroker.cpp
@@ -13,6 +13,8 @@
#include "DocumentBroker.hpp"
+#include <common/Anonymizer.hpp>
+
#include <atomic>
#include <cassert>
#include <chrono>
@@ -2133,7 +2135,7 @@ void DocumentBroker::uploadToStorageInternal(const std::shared_ptr<ClientSession
LOG_DBG("New filename [" << COOLWSD::anonymizeUrl(newFilename)
<< "] will be known by its fileId [" << fileId << ']');
- Util::mapAnonymized(newFilename, fileId);
+ Anonymizer::mapAnonymized(newFilename, fileId);
}
if (!_storage)
diff --git a/wsd/RequestVettingStation.cpp b/wsd/RequestVettingStation.cpp
index 2c8f7c4149..56c9bd14b0 100644
--- a/wsd/RequestVettingStation.cpp
+++ b/wsd/RequestVettingStation.cpp
@@ -13,6 +13,7 @@
#include <RequestVettingStation.hpp>
+#include <common/Anonymizer.hpp>
#include <COOLWSD.hpp>
#include <RequestDetails.hpp>
#include <TraceEvent.hpp>
@@ -63,7 +64,8 @@ void RequestVettingStation::handleRequest(const std::string& id)
const auto uriPublic = RequestDetails::sanitizeURI(url);
const auto docKey = RequestDetails::getDocKey(uriPublic);
const std::string fileId = Uri::getFilenameFromURL(docKey);
- Util::mapAnonymized(fileId, fileId); // Identity mapping, since fileId is already obfuscated
+ Anonymizer::mapAnonymized(fileId,
+ fileId); // Identity mapping, since fileId is already obfuscated
// Check if readonly session is required.
const bool isReadOnly = Uri::hasReadonlyPermission(uriPublic.toString());
@@ -156,7 +158,8 @@ void RequestVettingStation::handleRequest(const std::string& id,
const auto uriPublic = RequestDetails::sanitizeURI(url);
const auto docKey = RequestDetails::getDocKey(uriPublic);
const std::string fileId = Uri::getFilenameFromURL(docKey);
- Util::mapAnonymized(fileId, fileId); // Identity mapping, since fileId is already obfuscated
+ Anonymizer::mapAnonymized(fileId,
+ fileId); // Identity mapping, since fileId is already obfuscated
// Check if readonly session is required.
const bool isReadOnly = Uri::hasReadonlyPermission(uriPublic.toString());
diff --git a/wsd/wopi/WopiProxy.cpp b/wsd/wopi/WopiProxy.cpp
index 6e87d9a627..53b0fd3064 100644
--- a/wsd/wopi/WopiProxy.cpp
+++ b/wsd/wopi/WopiProxy.cpp
@@ -13,6 +13,7 @@
#include "WopiProxy.hpp"
+#include <common/Anonymizer.hpp>
#include "FileUtil.hpp"
#include "HttpHelper.hpp"
#include "HttpRequest.hpp"
@@ -38,7 +39,8 @@ void WopiProxy::handleRequest([[maybe_unused]] const std::shared_ptr<Terminating
const auto uriPublic = RequestDetails::sanitizeURI(url);
const auto docKey = RequestDetails::getDocKey(uriPublic);
const std::string fileId = Uri::getFilenameFromURL(docKey);
- Util::mapAnonymized(fileId, fileId); // Identity mapping, since fileId is already obfuscated
+ Anonymizer::mapAnonymized(fileId,
+ fileId); // Identity mapping, since fileId is already obfuscated
LOG_INF("Starting GET request handler for session [" << _id << "] on url ["
<< COOLWSD::anonymizeUrl(url) << "].");
@@ -146,7 +148,7 @@ void WopiProxy::checkFileInfo(const std::shared_ptr<TerminatingPoll>& poll, cons
std::move(lastModifiedTime) });
// if (COOLWSD::AnonymizeUserData)
- // Util::mapAnonymized(Uri::getFilenameFromURL(filename),
+ // Anonymizer::mapAnonymized(Uri::getFilenameFromURL(filename),
// Uri::getFilenameFromURL(getUri().toString()));
auto wopiInfo = std::make_unique<WopiStorage::WOPIFileInfo>(fileInfo, object, uri);
diff --git a/wsd/wopi/WopiStorage.cpp b/wsd/wopi/WopiStorage.cpp
index 61195383c6..fd461d1c7b 100644
--- a/wsd/wopi/WopiStorage.cpp
+++ b/wsd/wopi/WopiStorage.cpp
@@ -12,7 +12,6 @@
#include <config.h>
#include "WopiStorage.hpp"
-#include "wopi/StorageConnectionManager.hpp"
#include <Auth.hpp>
#include <CommandControl.hpp>
@@ -25,10 +24,12 @@
#include <ProofKey.hpp>
#include <Unit.hpp>
#include <Util.hpp>
+#include <common/Anonymizer.hpp>
#include <common/FileUtil.hpp>
#include <common/JsonUtil.hpp>
#include <common/TraceEvent.hpp>
#include <common/Uri.hpp>
+#include <wopi/StorageConnectionManager.hpp>
#include <Poco/Exception.h>
#include <Poco/Net/AcceptCertificateHandler.h>
@@ -169,8 +170,8 @@ void WopiStorage::handleWOPIFileInfo(const WOPIFileInfo& wopiFileInfo, LockConte
setFileInfo(wopiFileInfo);
if (COOLWSD::AnonymizeUserData)
- Util::mapAnonymized(Uri::getFilenameFromURL(wopiFileInfo.getFilename()),
- Uri::getFilenameFromURL(getUri().toString()));
+ Anonymizer::mapAnonymized(Uri::getFilenameFromURL(wopiFileInfo.getFilename()),
+ Uri::getFilenameFromURL(getUri().toString()));
if (wopiFileInfo.getSupportsLocks())
lockCtx.initSupportsLocks();
@@ -211,9 +212,9 @@ WopiStorage::WOPIFileInfo::WOPIFileInfo(const FileInfo& fileInfo, Poco::JSON::Ob
JsonUtil::findJSONValue(object, "ObfuscatedUserId", _obfuscatedUserId);
if (!_obfuscatedUserId.empty())
{
- Util::mapAnonymized(getOwnerId(), _obfuscatedUserId);
- Util::mapAnonymized(_userId, _obfuscatedUserId);
- Util::mapAnonymized(_username, _obfuscatedUserId);
+ Anonymizer::mapAnonymized(getOwnerId(), _obfuscatedUserId);
+ Anonymizer::mapAnonymized(_userId, _obfuscatedUserId);
+ Anonymizer::mapAnonymized(_username, _obfuscatedUserId);
}
// Set anonymized version of the above fields before logging.
@@ -963,11 +964,12 @@ WopiStorage::handleUploadToStorageResponse(const WopiUploadDetails& details,
// Get the FileId form the URL, which we use as the anonymized filename.
const std::string decodedUrl = Uri::decode(url);
const std::string obfuscatedFileId = Uri::getFilenameFromURL(decodedUrl);
- Util::mapAnonymized(obfuscatedFileId,
- obfuscatedFileId); // Identity, to avoid re-anonymizing.
+ Anonymizer::mapAnonymized(
+ obfuscatedFileId,
+ obfuscatedFileId); // Identity, to avoid re-anonymizing.
const std::string filenameOnly = Uri::getFilenameFromURL(filename);
- Util::mapAnonymized(filenameOnly, obfuscatedFileId);
+ Anonymizer::mapAnonymized(filenameOnly, obfuscatedFileId);
object->set("Name", COOLWSD::anonymizeUrl(filename));
}
commit 12d6409af160ac9cea50ac93f166dff4ba2c610e
Author: Ashod Nakashian <
ashod.n...@collabora.co.uk>
AuthorDate: Sat Oct 26 10:50:03 2024 -0400
Commit: Ashod Nakashian <
As...@users.noreply.github.com>
CommitDate: Wed Nov 20 08:03:33 2024 -0500
wsd: header cleanup
Change-Id: I9278a77eff33173dfa6328eabd0313685f24d166
Signed-off-by: Ashod Nakashian <
ashod.n...@collabora.co.uk>
diff --git a/common/Unit.hpp b/common/Unit.hpp
index 4bac605c6c..d7f1d7f041 100644
--- a/common/Unit.hpp
+++ b/common/Unit.hpp
@@ -7,6 +7,10 @@
#pragma once
+#include <common/StateEnum.hpp>
+#include <common/Util.hpp>
+#include <net/Socket.hpp>
+
#include <cassert>
#include <chrono>
#include <map>
@@ -14,9 +18,6 @@
#include <string>
#include <vector>
-#include <common/StateEnum.hpp>
-#include "Util.hpp"
-#include "net/Socket.hpp"
#include <Poco/Exception.h>
#include <test/testlog.hpp>
diff --git a/common/Util.hpp b/common/Util.hpp
index 9f224d0e16..6785312466 100644
--- a/common/Util.hpp
+++ b/common/Util.hpp
@@ -22,7 +22,6 @@
#include <atomic>
#include <limits>
#include <mutex>
-#include <ratio>
#include <set>
#include <sstream>
#include <string>
diff --git a/test/KitPidHelpers.cpp b/test/KitPidHelpers.cpp
index fa5767d81e..e924c28dac 100644
--- a/test/KitPidHelpers.cpp
+++ b/test/KitPidHelpers.cpp
@@ -10,6 +10,12 @@
*/
#include "KitPidHelpers.hpp"
+#include <wsd/COOLWSD.hpp>
+
+#include <lokassert.hpp>
+#include <testlog.hpp>
+
+#include <csignal>
#include <set>
#include <chrono>
#include <iostream>
@@ -17,11 +23,6 @@
#include <thread>
#include <string>
-#include <wsd/COOLWSD.hpp>
-
-#include <lokassert.hpp>
-#include <testlog.hpp>
-
std::string getPidList(const std::set<pid_t>& pids);
std::set<pid_t> helpers::getKitPids() { return COOLWSD::getKitPids(); }
diff --git a/wsd/Admin.cpp b/wsd/Admin.cpp
index
7727411601..850ecf208f 100644
--- a/wsd/Admin.cpp
+++ b/wsd/Admin.cpp
@@ -12,6 +12,7 @@
#include <config.h>
#include <chrono>
+#include <csignal>
#include <iomanip>
#include <sstream>
#include <string>
diff --git a/wsd/AdminModel.cpp b/wsd/AdminModel.cpp
index e592a4bcaf..eef6807012 100644
--- a/wsd/AdminModel.cpp
+++ b/wsd/AdminModel.cpp
@@ -16,6 +16,7 @@
#include <chrono>
#include <cmath>
+#include <csignal>
#include <memory>
#include <set>
#include <sstream>
diff --git a/wsd/COOLWSD.hpp b/wsd/COOLWSD.hpp
index 9ece3e7993..bd2a6d3855 100644
--- a/wsd/COOLWSD.hpp
+++ b/wsd/COOLWSD.hpp
@@ -13,8 +13,8 @@
#include <common/ConfigUtil.hpp>
#include <common/FileUtil.hpp>
+#include <common/Unit.hpp>
#include <common/Util.hpp>
-#include <net/WebSocketHandler.hpp>
#include <algorithm>
#include <atomic>
@@ -25,9 +25,6 @@
#include <unordered_map>
#include <unordered_set>
#include <string>
-#include <utility>
-
-#include <signal.h>
#include <Poco/Path.h>
#include <Poco/Util/AbstractConfiguration.h>
@@ -37,10 +34,12 @@
class WSProcess;
class ForKitProcess;
class ChildProcess;
-class TraceFileWriter;
-class DocumentBroker;
class ClipboardCache;
+class DocumentBroker;
class FileServerRequestHandler;
+class ForKitProcess;
+class SocketPoll;
+class TraceFileWriter;
std::shared_ptr<ChildProcess> getNewChild_Blocks(SocketPoll &destPoll, unsigned mobileAppDocId);
diff --git a/wsd/Process.hpp b/wsd/Process.hpp
index 3755e93c24..2b94b162ed 100644
--- a/wsd/Process.hpp
+++ b/wsd/Process.hpp
@@ -15,6 +15,7 @@
#include <atomic>
#include <chrono>
+#include <csignal>
#include <string>
class ChildProcess;
diff --git a/wsd/Storage.hpp b/wsd/Storage.hpp
index 14e2bcebaf..29f7f565e8 100644
--- a/wsd/Storage.hpp
+++ b/wsd/Storage.hpp
@@ -13,10 +13,11 @@
#pragma once
-#include "COOLWSD.hpp"
-#include "Log.hpp"
#include <common/Authorization.hpp>
+#include <common/Common.hpp>
#include <common/ConfigUtil.hpp>
+#include <common/Log.hpp>
+#include <wsd/COOLWSD.hpp>
#include <Poco/URI.h>
diff --git a/wsd/wopi/WopiProxy.cpp b/wsd/wopi/WopiProxy.cpp
index 597c1a4f9c..6e87d9a627 100644
--- a/wsd/wopi/WopiProxy.cpp
+++ b/wsd/wopi/WopiProxy.cpp
@@ -16,6 +16,7 @@
#include "FileUtil.hpp"
#include "HttpHelper.hpp"
#include "HttpRequest.hpp"
+#include "Protocol.hpp"
#include <COOLWSD.hpp>
#include <Exceptions.hpp>
#include <Log.hpp>
commit ccda768b8c45e82e1a448847c0dd3fb94005fadd
Author: Ashod Nakashian <
ashod.n...@collabora.co.uk>
AuthorDate: Sat Oct 26 09:10:46 2024 -0400
Commit: Ashod Nakashian <
As...@users.noreply.github.com>
CommitDate: Wed Nov 20 08:03:33 2024 -0500
wsd: move process wrappers into their own home
Change-Id: Ida1bf54e0121420ce0cbcceb34bb7f332acfa14a
Signed-off-by: Ashod Nakashian <
ashod.n...@collabora.co.uk>
diff --git a/Makefile.am b/Makefile.am
index 78d0415cb3..237c35891c 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -338,6 +338,7 @@ wsd_headers = wsd/Admin.hpp \
wsd/Exceptions.hpp \
wsd/FileServer.hpp \
wsd/HostUtil.hpp \
+ wsd/Process.hpp \
wsd/ProofKey.hpp \
wsd/ProxyProtocol.hpp \
wsd/ProxyRequestHandler.hpp \
diff --git a/test/UnitWOPI.cpp b/test/UnitWOPI.cpp
index e7ed46dd51..339dd33220 100644
--- a/test/UnitWOPI.cpp
+++ b/test/UnitWOPI.cpp
@@ -17,6 +17,7 @@
#include <WopiTestServer.hpp>
#include <wsd/DocumentBroker.hpp>
+#include <wsd/Process.hpp>
#include <Poco/Net/HTTPRequest.h>
diff --git a/wsd/COOLWSD.cpp b/wsd/COOLWSD.cpp
index 741837dbb9..8622c5b215 100644
--- a/wsd/COOLWSD.cpp
+++ b/wsd/COOLWSD.cpp
@@ -99,6 +99,7 @@
#include <Crypto.hpp>
#include <DelaySocket.hpp>
#include <wsd/DocumentBroker.hpp>
+#include <wsd/Process.hpp>
#include <common/JsonUtil.hpp>
#include <common/FileUtil.hpp>
#include <common/JailUtil.hpp>
diff --git a/wsd/COOLWSD.hpp b/wsd/COOLWSD.hpp
index 7217500293..9ece3e7993 100644
--- a/wsd/COOLWSD.hpp
+++ b/wsd/COOLWSD.hpp
@@ -34,6 +34,8 @@
#include <Poco/Util/OptionSet.h>
#include <Poco/Util/ServerApplication.h>
+class WSProcess;
+class ForKitProcess;
class ChildProcess;
class TraceFileWriter;
class DocumentBroker;
@@ -42,198 +44,6 @@ class FileServerRequestHandler;
std::shared_ptr<ChildProcess> getNewChild_Blocks(SocketPoll &destPoll, unsigned mobileAppDocId);
-// A WSProcess object in the WSD process represents a descendant process, either the direct child
-// process ForKit or a grandchild Kit process, with which the WSD process communicates through a
-// WebSocket.
-class WSProcess
-{
-public:
- /// @param pid is the process ID.
- /// @param socket is the underlying Socket to the process.
- WSProcess(const std::string& name,
- const pid_t pid,
- const std::shared_ptr<StreamSocket>& socket,
- std::shared_ptr<WebSocketHandler> handler) :
-
- _name(name),
- _pid(pid),
- _ws(std::move(handler)),
- _socket(socket)
- {
- LOG_INF(_name << " ctor [" << _pid << "].");
- }
-
- WSProcess(WSProcess&& other) = delete;
-
- const WSProcess& operator=(WSProcess&& other) = delete;
-
- virtual ~WSProcess()
- {
- LOG_DBG('~' << _name << " dtor [" << _pid << "].");
-
- if (_pid <= 0)
- return;
-
- terminate();
-
- // No need for the socket anymore.
- _ws.reset();
- _socket.reset();
- }
-
- /// Let the child close a nice way.
- void close()
- {
- if (_pid < 0)
- return;
-
- try
- {
- LOG_DBG("Closing ChildProcess [" << _pid << "].");
-
- requestTermination();
-
- // Shutdown the socket.
- if (_ws)
- _ws->shutdown();
- }
- catch (const std::exception& ex)
- {
- LOG_ERR("Error while closing child process: " << ex.what());
- }
-
- _pid = -1; // Detach from child.
- }
-
- /// Request graceful termination.
- void requestTermination()
- {
- // Request the child to exit
- if (isAlive())
- {
- LOG_DBG("Stopping ChildProcess [" << _pid << "] by sending 'exit' command");
- sendTextFrame("exit", /*flush=*/true);
- }
- }
-
- /// Kill or abandon the child.
- void terminate()
- {
- if (_pid < 0)
- return;
-
-#if !MOBILEAPP
- if (::kill(_pid, 0) == 0)
- {
- LOG_INF("Killing child [" << _pid << "].");
-#if CODE_COVERAGE || VALGRIND_COOLFORKIT
- constexpr auto signal = SIGTERM;
-#else
- constexpr auto signal = SIGKILL;
-#endif
- if (!SigUtil::killChild(_pid, signal))
- {
- LOG_ERR("Cannot terminate lokit [" << _pid << "]. Abandoning.");
- }
- }
-#else
- // What to do? Throw some unique exception that the outermost call in the thread catches and
- // exits from the thread?
-#endif
- _pid = -1;
- }
-
- pid_t getPid() const { return _pid; }
-
- /// Send a text payload to the child-process WS.
- bool sendTextFrame(const std::string& data, bool flush = false)
- {
- return sendFrame(data, false, flush);
- }
-
- /// Send a payload to the child-process WS.
- bool sendFrame(const std::string& data, bool binary = false, bool flush = false)
- {
- try
- {
- if (_ws)
- {
- LOG_TRC("Send to " << _name << " message: ["
- << COOLProtocol::getAbbreviatedMessage(data) << ']');
- _ws->sendMessage(data.c_str(), data.size(),
- (binary ? WSOpCode::Binary : WSOpCode::Text), flush);
- return true;
- }
- }
- catch (const std::exception& exc)
- {
- LOG_ERR("Failed to send " << _name << " [" << _pid << "] data [" <<
- COOLProtocol::getAbbreviatedMessage(data) << "] due to: " << exc.what());
- throw;
- }
-
- LOG_WRN("No socket to " << _name << " to send [" << COOLProtocol::getAbbreviatedMessage(data) << ']');
- return false;
- }
-
- /// Check whether this child is alive and socket not in error.
- /// Note: zombies will show as alive, and sockets have waiting
- /// time after the other end-point closes. So this isn't accurate.
- virtual bool isAlive() const
- {
-#if !MOBILEAPP
- try
- {
- return _pid > 1 && _ws && ::kill(_pid, 0) == 0;
- }
- catch (const std::exception&)
- {
- }
-
- return false;
-#else
- return _pid > 1;
-#endif
- }
-
-protected:
- std::shared_ptr<WebSocketHandler> getWSHandler() const { return _ws; }
- std::shared_ptr<StreamSocket> getSocket() const { return _socket.lock(); };
-
-private:
- std::string _name;
- std::atomic<pid_t> _pid; ///< The process-id, which can be access from different threads.
- std::shared_ptr<WebSocketHandler> _ws; // FIXME: should be weak ? ...
- std::weak_ptr<StreamSocket> _socket;
-};
-
-#if !MOBILEAPP
-
-class ForKitProcWSHandler final : public WebSocketHandler
-{
-public:
- template <typename T>
- ForKitProcWSHandler(const std::weak_ptr<StreamSocket>& socket, const T& request)
- : WebSocketHandler(socket.lock(), request)
- {
- }
-
- virtual void handleMessage(const std::vector<char>& data) override;
-};
-
-class ForKitProcess final : public WSProcess
-{
-public:
- template <typename T>
- ForKitProcess(int pid, std::shared_ptr<StreamSocket>& socket, const T& request)
- : WSProcess("ForKit", pid, socket, std::make_shared<ForKitProcWSHandler>(socket, request))
- {
- socket->setHandler(getWSHandler());
- }
-};
-
-#endif
-
/// The Server class which is responsible for all
/// external interactions.
class COOLWSD final : public Poco::Util::ServerApplication,
diff --git a/wsd/DocumentBroker.cpp b/wsd/DocumentBroker.cpp
index be10e0b8af..f20d9f974f 100644
--- a/wsd/DocumentBroker.cpp
+++ b/wsd/DocumentBroker.cpp
@@ -54,6 +54,7 @@
#include <common/FileUtil.hpp>
#include <common/Uri.hpp>
#include <CommandControl.hpp>
+#include <wsd/Process.hpp>
#if !MOBILEAPP
#include <wopi/CheckFileInfo.hpp>
@@ -227,6 +228,8 @@ DocumentBroker::DocumentBroker(ChildType type, const std::string& uri, const Poc
}
}
+pid_t DocumentBroker::getPid() const { return _childProcess ? _childProcess->getPid() : 0; }
+
void DocumentBroker::setupPriorities()
{
if constexpr (Util::isMobileApp())
diff --git a/wsd/DocumentBroker.hpp b/wsd/DocumentBroker.hpp
index 59a54422fc..53c9c00ae8 100644
--- a/wsd/DocumentBroker.hpp
+++ b/wsd/DocumentBroker.hpp
@@ -82,88 +82,6 @@ private:
ChildProcess* _childProcess;
};
-/// A ChildProcess object represents a Kit process that hosts a document and manipulates the
-/// document using the LibreOfficeKit API. It isn't actually a child of the WSD process, but a
-/// grandchild. The comments loosely talk about "child" anyway.
-
-class ChildProcess final : public WSProcess
-{
-public:
- /// @param pid is the process ID of the child.
- /// @param socket is the underlying Socket to the child.
- template <typename T>
- ChildProcess(const pid_t pid, const std::string& jailId,
- const std::shared_ptr<StreamSocket>& socket, const T& request)
- : WSProcess("ChildProcess", pid, socket,
- std::make_shared<WebSocketHandler>(socket, request))
- , _jailId(jailId)
- , _smapsFD(-1)
- {
- int urpFromKitFD = socket->getIncomingFD(SharedFDType::URPFromKit);
- int urpToKitFD = socket->getIncomingFD(SharedFDType::URPToKit);
- if (urpFromKitFD != -1 && urpToKitFD != -1)
- {
- std::chrono::steady_clock::time_point now = std::chrono::steady_clock::now();
- _urpFromKit = StreamSocket::create<StreamSocket>(
- std::string(), urpFromKitFD, Socket::Type::Unix,
- false, HostType::Other, std::make_shared<UrpHandler>(this),
- StreamSocket::ReadType::NormalRead, now);
- _urpToKit = StreamSocket::create<StreamSocket>(
- std::string(), urpToKitFD, Socket::Type::Unix,
- false, HostType::Other, std::make_shared<UrpHandler>(this),
- StreamSocket::ReadType::NormalRead, now);
- }
- }
-
- ChildProcess(ChildProcess&& other) = delete;
-
- bool sendUrpMessage(const std::string& message)
- {
- if (!_urpToKit)
- return false;
- if (message.size() < 4)
- {
- LOG_ERR("URP Message too short");
- return false;
- }
- _urpToKit->send(message.data() + 4, message.size() - 4);
- return true;
- }
-
- virtual ~ChildProcess()
- {
- if (_urpFromKit)
- _urpFromKit->shutdown();
- if (_urpToKit)
- _urpToKit->shutdown();
- if (_smapsFD != -1)
- {
- ::close(_smapsFD);
- _smapsFD = -1;
- }
- }
-
- const ChildProcess& operator=(ChildProcess&& other) = delete;
-
- void setDocumentBroker(const std::shared_ptr<DocumentBroker>& docBroker);
- std::shared_ptr<DocumentBroker> getDocumentBroker() const { return _docBroker.lock(); }
- const std::string& getJailId() const { return _jailId; }
- void setSMapsFD(int smapsFD) { _smapsFD = smapsFD;}
- int getSMapsFD(){ return _smapsFD; }
-
- void moveSocketFromTo(const std::shared_ptr<SocketPoll> &from, SocketPoll &to)
- {
- to.takeSocket(from, getSocket());
- }
-
-private:
- const std::string _jailId;
- std::weak_ptr<DocumentBroker> _docBroker;
- std::shared_ptr<StreamSocket> _urpFromKit;
- std::shared_ptr<StreamSocket> _urpToKit;
- int _smapsFD;
-};
-
class RequestDetails;
class ClientSession;
@@ -532,8 +450,8 @@ public:
/// Flag that we have been disconnected from the Kit and request unloading.
void disconnectedFromKit(bool unexpected);
- /// Get the PID of the associated child process
- pid_t getPid() const { return _childProcess ? _childProcess->getPid() : 0; }
+ /// Get the PID of the associated child process.
+ pid_t getPid() const;
/// Update the last activity time to now.
/// Best to be inlined as it's called frequently.
diff --git a/wsd/Process.hpp b/wsd/Process.hpp
new file mode 100644
index 0000000000..3755e93c24
--- /dev/null
+++ b/wsd/Process.hpp
@@ -0,0 +1,296 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */
+/*
+ * Copyright the Collabora Online contributors.
+ *
+ * SPDX-License-Identifier: MPL-2.0
+ *
+ * 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 <net/WebSocketHandler.hpp>
+
+#include <atomic>
+#include <chrono>
+#include <string>
+
+class ChildProcess;
+class DocumentBroker;
+
+// A WSProcess object in the WSD process represents a descendant process, either the direct child
+// process ForKit or a grandchild Kit process, with which the WSD process communicates through a
+// WebSocket.
+class WSProcess
+{
+public:
+ /// @param pid is the process ID.
+ /// @param socket is the underlying Socket to the process.
+ WSProcess(const std::string& name, const pid_t pid, const std::shared_ptr<StreamSocket>& socket,
+ std::shared_ptr<WebSocketHandler> handler)
+ :
+
+ _name(name)
+ , _pid(pid)
+ , _ws(std::move(handler))
+ , _socket(socket)
+ {
+ LOG_INF(_name << " ctor [" << _pid << "].");
+ }
+
+ WSProcess(WSProcess&& other) = delete;
+
+ const WSProcess& operator=(WSProcess&& other) = delete;
+
+ virtual ~WSProcess()
+ {
+ LOG_DBG('~' << _name << " dtor [" << _pid << "].");
+
+ if (_pid <= 0)
+ return;
+
+ terminate();
+
+ // No need for the socket anymore.
+ _ws.reset();
+ _socket.reset();
+ }
+
+ /// Let the child close a nice way.
+ void close()
+ {
+ if (_pid < 0)
+ return;
+
+ try
+ {
+ LOG_DBG("Closing ChildProcess [" << _pid << "].");
+
+ requestTermination();
+
+ // Shutdown the socket.
+ if (_ws)
+ _ws->shutdown();
+ }
+ catch (const std::exception& ex)
+ {
+ LOG_ERR("Error while closing child process: " << ex.what());
+ }
+
+ _pid = -1; // Detach from child.
+ }
+
+ /// Request graceful termination.
+ void requestTermination()
+ {
+ // Request the child to exit
+ if (isAlive())
+ {
+ LOG_DBG("Stopping ChildProcess [" << _pid << "] by sending 'exit' command");
+ sendTextFrame("exit", /*flush=*/true);
+ }
+ }
+
+ /// Kill or abandon the child.
+ void terminate()
+ {
+ if (_pid < 0)
+ return;
+
+#if !MOBILEAPP
+ if (::kill(_pid, 0) == 0)
+ {
+ LOG_INF("Killing child [" << _pid << "].");
+#if CODE_COVERAGE || VALGRIND_COOLFORKIT
+ constexpr auto signal = SIGTERM;
+#else
+ constexpr auto signal = SIGKILL;
+#endif
+ if (!SigUtil::killChild(_pid, signal))
+ {
+ LOG_ERR("Cannot terminate lokit [" << _pid << "]. Abandoning.");
+ }
+ }
+#else
+ // What to do? Throw some unique exception that the outermost call in the thread catches and
+ // exits from the thread?
+#endif
+ _pid = -1;
+ }
+
+ pid_t getPid() const { return _pid; }
+
+ /// Send a text payload to the child-process WS.
+ bool sendTextFrame(const std::string& data, bool flush = false)
+ {
+ return sendFrame(data, false, flush);
+ }
+
+ /// Send a payload to the child-process WS.
+ bool sendFrame(const std::string& data, bool binary = false, bool flush = false)
+ {
+ try
+ {
+ if (_ws)
+ {
+ LOG_TRC("Send to " << _name << " message: ["
+ << COOLProtocol::getAbbreviatedMessage(data) << ']');
+ _ws->sendMessage(data.c_str(), data.size(),
+ (binary ? WSOpCode::Binary : WSOpCode::Text), flush);
+ return true;
+ }
+ }
+ catch (const std::exception& exc)
+ {
+ LOG_ERR("Failed to send " << _name << " [" << _pid << "] data ["
+ << COOLProtocol::getAbbreviatedMessage(data)
+ << "] due to: " << exc.what());
+ throw;
+ }
+
+ LOG_WRN("No socket to " << _name << " to send ["
+ << COOLProtocol::getAbbreviatedMessage(data) << ']');
+ return false;
+ }
+
+ /// Check whether this child is alive and socket not in error.
+ /// Note: zombies will show as alive, and sockets have waiting
+ /// time after the other end-point closes. So this isn't accurate.
+ virtual bool isAlive() const
+ {
+#if !MOBILEAPP
+ try
+ {
+ return _pid > 1 && _ws && ::kill(_pid, 0) == 0;
+ }
+ catch (const std::exception&)
+ {
+ }
+
+ return false;
+#else
+ return _pid > 1;
+#endif
+ }
+
+protected:
+ std::shared_ptr<WebSocketHandler> getWSHandler() const { return _ws; }
+ std::shared_ptr<StreamSocket> getSocket() const { return _socket.lock(); };
+
+private:
+ std::string _name;
+ std::atomic<pid_t> _pid; ///< The process-id, which can be access from different threads.
+ std::shared_ptr<WebSocketHandler> _ws; // FIXME: should be weak ? ...
+ std::weak_ptr<StreamSocket> _socket;
+};
+
+/// A ChildProcess object represents a Kit process that hosts a document and manipulates the
+/// document using the LibreOfficeKit API. It isn't actually a child of the WSD process, but a
+/// grandchild. The comments loosely talk about "child" anyway.
+
+class ChildProcess final : public WSProcess
+{
+public:
+ /// @param pid is the process ID of the child.
+ /// @param socket is the underlying Socket to the child.
+ template <typename T>
+ ChildProcess(const pid_t pid, const std::string& jailId,
+ const std::shared_ptr<StreamSocket>& socket, const T& request)
+ : WSProcess("ChildProcess", pid, socket,
+ std::make_shared<WebSocketHandler>(socket, request))
+ , _jailId(jailId)
+ , _smapsFD(-1)
+ {
+ int urpFromKitFD = socket->getIncomingFD(SharedFDType::URPFromKit);
+ int urpToKitFD = socket->getIncomingFD(SharedFDType::URPToKit);
+ if (urpFromKitFD != -1 && urpToKitFD != -1)
+ {
+ std::chrono::steady_clock::time_point now = std::chrono::steady_clock::now();
+ _urpFromKit = StreamSocket::create<StreamSocket>(
+ std::string(), urpFromKitFD, Socket::Type::Unix, false, HostType::Other,
+ std::make_shared<UrpHandler>(this), StreamSocket::ReadType::NormalRead, now);
+ _urpToKit = StreamSocket::create<StreamSocket>(
+ std::string(), urpToKitFD, Socket::Type::Unix, false, HostType::Other,
+ std::make_shared<UrpHandler>(this), StreamSocket::ReadType::NormalRead, now);
+ }
+ }
+
+ ChildProcess(ChildProcess&& other) = delete;
+
+ bool sendUrpMessage(const std::string& message)
+ {
+ if (!_urpToKit)
+ return false;
+ if (message.size() < 4)
+ {
+ LOG_ERR("URP Message too short");
+ return false;
+ }
+ _urpToKit->send(message.data() + 4, message.size() - 4);
+ return true;
+ }
+
+ virtual ~ChildProcess()
+ {
+ if (_urpFromKit)
+ _urpFromKit->shutdown();
+ if (_urpToKit)
+ _urpToKit->shutdown();
+ if (_smapsFD != -1)
+ {
+ ::close(_smapsFD);
+ _smapsFD = -1;
+ }
+ }
+
+ const ChildProcess& operator=(ChildProcess&& other) = delete;
+
+ void setDocumentBroker(const std::shared_ptr<DocumentBroker>& docBroker);
+ std::shared_ptr<DocumentBroker> getDocumentBroker() const { return _docBroker.lock(); }
+ const std::string& getJailId() const { return _jailId; }
+ void setSMapsFD(int smapsFD) { _smapsFD = smapsFD; }
+ int getSMapsFD() { return _smapsFD; }
+
+ void moveSocketFromTo(const std::shared_ptr<SocketPoll>& from, SocketPoll& to)
+ {
+ to.takeSocket(from, getSocket());
+ }
+
+private:
+ const std::string _jailId;
+ std::weak_ptr<DocumentBroker> _docBroker;
+ std::shared_ptr<StreamSocket> _urpFromKit;
+ std::shared_ptr<StreamSocket> _urpToKit;
+ int _smapsFD;
+};
+
+#if !MOBILEAPP
+
+class ForKitProcWSHandler final : public WebSocketHandler
+{
+public:
+ template <typename T>
+ ForKitProcWSHandler(const std::weak_ptr<StreamSocket>& socket, const T& request)
+ : WebSocketHandler(socket.lock(), request)
+ {
+ }
+
+ virtual void handleMessage(const std::vector<char>& data) override;
+};
+
+class ForKitProcess final : public WSProcess
+{
+public:
+ template <typename T>
+ ForKitProcess(int pid, std::shared_ptr<StreamSocket>& socket, const T& request)
+ : WSProcess("ForKit", pid, socket, std::make_shared<ForKitProcWSHandler>(socket, request))
+ {
+ socket->setHandler(getWSHandler());
+ }
+};
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
commit b3f74806fe53a307c4ef393d5e72f7e330221be6
Author: Ashod Nakashian <
ashod.n...@collabora.co.uk>
AuthorDate: Fri Oct 25 04:35:59 2024 -0400
Commit: Ashod Nakashian <
As...@users.noreply.github.com>
CommitDate: Wed Nov 20 08:03:33 2024 -0500
wsd: include cleanup
Change-Id: I1d20764bc80a8debb8d0ba51eb5ce658ee8b5484
Signed-off-by: Ashod Nakashian <
ashod.n...@collabora.co.uk>
diff --git a/kit/Kit.cpp b/kit/Kit.cpp
index 47ae8b3c9e..df0819ece7 100644
--- a/kit/Kit.cpp
+++ b/kit/Kit.cpp
@@ -76,10 +76,8 @@
#include <UserMessages.hpp>
#include <Util.hpp>
#include <JsonUtil.hpp>
-#include "Watermark.hpp"
#include "RenderTiles.hpp"
#include "KitWebSocket.hpp"
-#include "SetupKitEnvironment.hpp"
#include <common/ConfigUtil.hpp>
#include <common/TraceEvent.hpp>
#include <common/Watchdog.hpp>
@@ -94,6 +92,9 @@
#if MOBILEAPP
#include "COOLWSD.hpp"
+#ifndef IOS
+#include "SetupKitEnvironment.hpp"
+#endif
#endif
#ifdef IOS
@@ -107,7 +108,6 @@ using Poco::Exception;
using Poco::File;
using Poco::JSON::Object;
using Poco::JSON::Parser;
-using Poco::URI;
#ifndef BUILDING_TESTS
using Poco::Path;
diff --git a/wsd/Auth.cpp b/wsd/Auth.cpp
index 48386f70f2..2579e9cebd 100644
--- a/wsd/Auth.cpp
+++ b/wsd/Auth.cpp
@@ -28,7 +28,6 @@
#include <Poco/Net/NetException.h>
#include <Poco/URI.h>
-#include "COOLWSD.hpp"
#include <JsonUtil.hpp>
#include <Log.hpp>
#include <Protocol.hpp>
diff --git a/wsd/ProofKey.cpp b/wsd/ProofKey.cpp
index f977beb0c0..a38c5bfa17 100644
--- a/wsd/ProofKey.cpp
+++ b/wsd/ProofKey.cpp
@@ -12,7 +12,6 @@
#include <config.h>
#include "ProofKey.hpp"
-#include "COOLWSD.hpp"
#include <algorithm>
#include <cassert>
diff --git a/wsd/SpecialBrokers.cpp b/wsd/SpecialBrokers.cpp
index 33476af4f7..a0891bd548 100644
--- a/wsd/SpecialBrokers.cpp
+++ b/wsd/SpecialBrokers.cpp
@@ -17,12 +17,8 @@
#include <cassert>
#include <chrono>
#include <ctime>
-#include <ios>
-#include <fstream>
#include <memory>
-#include <stdexcept>
#include <string>
-#include <sstream>
#include <Poco/DigestStream.h>
#include <Poco/Exception.h>
@@ -31,19 +27,13 @@
#include <Poco/StreamCopier.h>
#include <Poco/URI.h>
-#include "Admin.hpp"
#include "Authorization.hpp"
#include "ClientSession.hpp"
#include "Common.hpp"
-#include "Exceptions.hpp"
#include "COOLWSD.hpp"
#include "FileServer.hpp"
#include "Socket.hpp"
-#include "Storage.hpp"
#include "TileCache.hpp"
-#include "TraceEvent.hpp"
-#include "ProxyProtocol.hpp"
-#include "Util.hpp"
#include "QuarantineUtil.hpp"
#include <common/JsonUtil.hpp>
#include <common/Log.hpp>