[Libreoffice-commits] online.git: Branch 'distro/collabora/collabora-online-3' - 49 commits - common/JsonUtil.hpp common/Log.cpp common/Log.hpp common/Protocol.hpp common/Seccomp.cpp common/Seccomp.hpp common/Session.cpp common/Session.hpp common/Util.cpp common/Util.hpp configure.ac kit/ChildSession.cpp kit/ChildSession.hpp kit/ForKit.cpp kit/Kit.cpp kit/KitHelper.hpp kit/Kit.hpp loleaflet/dist loleaflet/src loolwsd.xml.in Makefile.am net/Socket.cpp net/Socket.hpp net/WebSocketHandler.hpp test/TileCacheTests.cpp test/WhiteBoxTests.cpp wsd/AdminModel.cpp wsd/ClientSession.cpp wsd/DocumentBroker.cpp wsd/DocumentBroker.hpp wsd/LOOLWSD.cpp wsd/LOOLWSD.hpp wsd/Storage.cpp wsd/Storage.hpp wsd/TileCache.cpp wsd/TileCache.hpp
Libreoffice Gerrit user
logerrit at kemper.freedesktop.org
Fri Aug 17 09:57:29 UTC 2018
Makefile.am | 2
common/JsonUtil.hpp | 146 +++++++++++++++
common/Log.cpp | 47 ++--
common/Log.hpp | 142 ++++++++++++--
common/Protocol.hpp | 42 ----
common/Seccomp.cpp | 8
common/Seccomp.hpp | 3
common/Session.cpp | 73 ++++---
common/Session.hpp | 16 +
common/Util.cpp | 125 +++++++++++--
common/Util.hpp | 139 +++++++++++++-
configure.ac | 32 +++
kit/ChildSession.cpp | 41 ++--
kit/ChildSession.hpp | 4
kit/ForKit.cpp | 35 +++
kit/Kit.cpp | 148 +++++++++++----
kit/Kit.hpp | 6
kit/KitHelper.hpp | 2
loleaflet/dist/framed.doc.html | 85 ++++++++
loleaflet/src/core/Socket.js | 11 -
loolwsd.xml.in | 4
net/Socket.cpp | 17 +
net/Socket.hpp | 22 ++
net/WebSocketHandler.hpp | 2
test/TileCacheTests.cpp | 2
test/WhiteBoxTests.cpp | 221 ++++++++++++++++++++++
wsd/AdminModel.cpp | 5
wsd/ClientSession.cpp | 16 -
wsd/DocumentBroker.cpp | 90 +++++----
wsd/DocumentBroker.hpp | 4
wsd/LOOLWSD.cpp | 190 +++++++++++++------
wsd/LOOLWSD.hpp | 16 +
wsd/Storage.cpp | 394 ++++++++++++++++++++---------------------
wsd/Storage.hpp | 24 +-
wsd/TileCache.cpp | 21 +-
wsd/TileCache.hpp | 4
36 files changed, 1616 insertions(+), 523 deletions(-)
New commits:
commit 17d1fdda7a0c29df12c43b956418c83b59bfe0da
Author: Jan Holesovsky <kendy at collabora.com>
AuthorDate: Wed Jul 18 16:18:03 2018 +0200
Commit: Jan Holesovsky <kendy at collabora.com>
CommitDate: Fri Aug 17 11:52:06 2018 +0200
wsd: safer string splitting
Change-Id: I88b82a3754c4f5e280f00be8e27614c3fe49eff8
Reviewed-on: https://gerrit.libreoffice.org/57644
Reviewed-by: Ashod Nakashian <ashnakash at gmail.com>
Tested-by: Ashod Nakashian <ashnakash at gmail.com>
diff --git a/common/Util.hpp b/common/Util.hpp
index ada42d093..43269e8d7 100644
--- a/common/Util.hpp
+++ b/common/Util.hpp
@@ -346,7 +346,13 @@ namespace Util
std::pair<std::string, std::string> split(const char* s, const int length, const char delimeter = ' ', bool removeDelim = true)
{
const auto size = getDelimiterPosition(s, length, delimeter);
- return std::make_pair(std::string(s, size), std::string(s+size+removeDelim));
+
+ std::string after;
+ int after_pos = size + (removeDelim? 1: 0);
+ if (after_pos < length)
+ after = std::string(s + after_pos, length - after_pos);
+
+ return std::make_pair(std::string(s, size), after);
}
/// Split a string in two at the delimeter, removing it.
@@ -361,7 +367,13 @@ namespace Util
std::pair<std::string, std::string> splitLast(const char* s, const int length, const char delimeter = ' ', bool removeDelim = true)
{
const auto size = getLastDelimiterPosition(s, length, delimeter);
- return std::make_pair(std::string(s, size), std::string(s+size+removeDelim));
+
+ std::string after;
+ int after_pos = size + (removeDelim? 1: 0);
+ if (after_pos < length)
+ after = std::string(s + after_pos, length - after_pos);
+
+ return std::make_pair(std::string(s, size), after);
}
/// Split a string in two at the delimeter, removing it.
commit 6ee2f90d4a448717bf73c4e4e4186b74b3ce6558
Author: Ashod Nakashian <ashod.nakashian at collabora.co.uk>
AuthorDate: Thu Jul 19 01:27:46 2018 -0400
Commit: Jan Holesovsky <kendy at collabora.com>
CommitDate: Fri Aug 17 11:48:37 2018 +0200
leaflet: update IE11 connection limit message
Change-Id: I7299867873fb00cf2a500f17a559106f52c8ba6f
Reviewed-on: https://gerrit.libreoffice.org/57709
Reviewed-by: Jan Holesovsky <kendy at collabora.com>
Tested-by: Jan Holesovsky <kendy at collabora.com>
diff --git a/loleaflet/src/core/Socket.js b/loleaflet/src/core/Socket.js
index c394402b4..27095b9ad 100644
--- a/loleaflet/src/core/Socket.js
+++ b/loleaflet/src/core/Socket.js
@@ -44,7 +44,7 @@ L.Socket = L.Class.extend({
var msgHint = '';
var isIE11 = !!window.MSInputMethodContext && !!document.documentMode; // https://stackoverflow.com/questions/21825157/internet-explorer-11-detection
if (isIE11)
- msgHint = 'IE11 has limitation on the maximum number of WebSockets open to a single domain. Please consult this page on how to change this limit: https://docs.microsoft.com/en-us/previous-versions/windows/internet-explorer/ie-developer/general-info/ee330736(v=vs.85)#websocket-maximum-server-connections';
+ msgHint = 'IE11 has reached its maximum number of connections. Please see this document to increase this limit if needed: https://docs.microsoft.com/en-us/previous-versions/windows/internet-explorer/ie-developer/general-info/ee330736(v=vs.85)#websocket-maximum-server-connections';
this._map.fire('error', {msg: _('Oops, there is a problem connecting to LibreOffice Online : ').replace('LibreOffice Online', (typeof brandProductName !== 'undefined' ? brandProductName : 'LibreOffice Online')) + e + msgHint, cmd: 'socket', kind: 'failed', id: 3});
return;
commit 39d14348d51964530acebc650204b7b18fa87d5a
Author: Ashod Nakashian <ashod.nakashian at collabora.co.uk>
AuthorDate: Wed Jun 6 22:53:15 2018 -0400
Commit: Jan Holesovsky <kendy at collabora.com>
CommitDate: Fri Aug 17 07:54:19 2018 +0200
wsd: support polling on client thread
Previously SocketPoll expected to be
running its own thread for polling.
This is unnecessary when we have a
spare thread (e.g. main) that can
(and should, for efficiency) be used
for polling rather than starting
dedicated thread.
Not starting the SocketPoll's thread
and calling SocketPoll::poll() directly
worked, the warning logs on each activity
notwithstanding.
The warnings aren't just noisy, they are
a performance drain as well, and signal
that something is wrong. The new code
now makes the API cleaner and avoids
unnecessary warning logs, while being
faster.
Change-Id: Ibf9a223c59dae6522a5fc2e5d84a8ef191b577b1
(cherry picked from commit a835bce3b352f565d06533dcacddb5b1927dc5b1)
diff --git a/kit/Kit.cpp b/kit/Kit.cpp
index 74e12f2c9..362f7bf2a 100644
--- a/kit/Kit.cpp
+++ b/kit/Kit.cpp
@@ -2337,6 +2337,7 @@ void lokit_main(const std::string& childRoot,
}
SocketPoll mainKit("kit");
+ mainKit.runOnClientThread(); // We will do the polling on this thread.
mainKit.insertNewWebSocketSync(uri, std::make_shared<KitWebSocketHandler>("child_ws_" + pid, loKit, jailId, mainKit));
LOG_INF("New kit client websocket inserted.");
diff --git a/net/Socket.cpp b/net/Socket.cpp
index 7ba09b830..b78900276 100644
--- a/net/Socket.cpp
+++ b/net/Socket.cpp
@@ -60,6 +60,7 @@ SocketPoll::SocketPoll(const std::string& threadName)
_stop(false),
_threadStarted(false),
_threadFinished(false),
+ _runOnClientThread(false),
_owner(std::this_thread::get_id())
{
// Create the wakeup fd.
@@ -92,14 +93,17 @@ SocketPoll::~SocketPoll()
_wakeup[1] = -1;
}
-void SocketPoll::startThread()
+bool SocketPoll::startThread()
{
+ assert(!_runOnClientThread);
+
if (!_threadStarted)
{
_threadStarted = true;
try
{
_thread = std::thread(&SocketPoll::pollingThreadEntry, this);
+ return true;
}
catch (const std::exception& exc)
{
@@ -107,6 +111,8 @@ void SocketPoll::startThread()
_threadStarted = false;
}
}
+
+ return false;
}
void SocketPoll::joinThread()
diff --git a/net/Socket.hpp b/net/Socket.hpp
index a3c194d83..421222302 100644
--- a/net/Socket.hpp
+++ b/net/Socket.hpp
@@ -390,7 +390,7 @@ public:
}
}
- bool isAlive() const { return _threadStarted && !_threadFinished; }
+ bool isAlive() const { return (_threadStarted && !_threadFinished) || _runOnClientThread; }
/// Check if we should continue polling
virtual bool continuePolling()
@@ -611,11 +611,28 @@ public:
const std::string& name() const { return _name; }
/// Start the polling thread (if desired)
- void startThread();
+ /// Mutually exclusive with runOnClientThread().
+ bool startThread();
/// Stop and join the polling thread before returning (if active)
void joinThread();
+ /// Called to prevent starting own poll thread
+ /// when polling is done on the client's thread.
+ /// Mutually exclusive with startThread().
+ bool runOnClientThread()
+ {
+ assert(!_threadStarted);
+
+ if (!_threadStarted)
+ {
+ _runOnClientThread = true;
+ return true;
+ }
+
+ return false;
+ }
+
private:
/// Initialize the poll fds array with the right events
void setupPollFds(std::chrono::steady_clock::time_point now,
@@ -697,6 +714,7 @@ protected:
std::thread _thread;
std::atomic<bool> _threadStarted;
std::atomic<bool> _threadFinished;
+ std::atomic<bool> _runOnClientThread;
std::thread::id _owner;
};
commit dbc0fc6da413c271db66cf8b9d01f5d4ad46c504
Author: Ashod Nakashian <ashod.nakashian at collabora.co.uk>
AuthorDate: Sun Jul 29 22:58:42 2018 -0400
Commit: Jan Holesovsky <kendy at collabora.com>
CommitDate: Fri Aug 17 07:54:19 2018 +0200
wsd: make loolmount before setcap on it
Change-Id: Ide93a347513d85d0c6349f364b3a28127e3d2882
diff --git a/Makefile.am b/Makefile.am
index 36db3d47e..ab5bd12aa 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -323,7 +323,7 @@ clang-tidy:
# capabilities won't survive packaging anyway. Instead, handle it when
# installing the RPM or Debian package.
-all-local: loolforkit @JAILS_PATH@ $(SYSTEM_STAMP)
+all-local: loolforkit loolmount @JAILS_PATH@ $(SYSTEM_STAMP)
@if test "$$BUILDING_FROM_RPMBUILD" != yes; then \
sudo @SETCAP@ cap_fowner,cap_mknod,cap_sys_chroot=ep loolforkit; \
sudo @SETCAP@ cap_sys_admin=ep loolmount; \
commit 02076bdb9128ffe7c26d8bcf420b659ec1d68280
Author: Ashod Nakashian <ashod.nakashian at collabora.co.uk>
AuthorDate: Wed Aug 1 22:25:38 2018 -0400
Commit: Jan Holesovsky <kendy at collabora.com>
CommitDate: Fri Aug 17 07:54:19 2018 +0200
wsd: warn when allow_logging_pii forces trace with anonymization
Also move anonymization initialization after logging is initialized.
Change-Id: I5c3753f0b11ae9c3376235e22af204eb3a57f5c8
diff --git a/wsd/LOOLWSD.cpp b/wsd/LOOLWSD.cpp
index 8074152c4..bce86d95a 100644
--- a/wsd/LOOLWSD.cpp
+++ b/wsd/LOOLWSD.cpp
@@ -775,39 +775,6 @@ void LOOLWSD::initialize(Application& self)
setenv("LOOL_LOGCOLOR", "1", true);
}
- // Get anonymization settings.
-#if LOOLWSD_ANONYMIZE_USERNAMES
- AnonymizeUsernames = true;
-#else
- AnonymizeUsernames = getConfigValue<bool>(conf, "logging.anonymize.usernames", false);
-#endif
- if (AnonymizeUsernames)
- setenv("LOOL_ANONYMIZE_USERNAMES", AnonymizeUsernames ? "1" : "0", true);
-
-#if LOOLWSD_ANONYMIZE_FILENAMES
- AnonymizeFilenames = true;
-#else
- AnonymizeFilenames = getConfigValue<bool>(conf, "logging.anonymize.filenames", false);
-#endif
- if (AnonymizeFilenames)
- setenv("LOOL_ANONYMIZE_FILENAMES", AnonymizeFilenames ? "1" : "0", true);
-
- if (AnonymizeFilenames || AnonymizeUsernames)
- {
- if (LogLevel == "trace" && !getConfigValue<bool>(conf, "logging.anonymize.allow_logging_pii", false))
- {
- const char failure[] = "Anonymization and trace-level logging are incompatible. "
- "Please reduce logging level to debug or lower in loolwsd.xml to prevent leaking sensitive user data.";
- LOG_FTL(failure);
- std::cerr << '\n' << failure << std::endl;
-#if ENABLE_DEBUG
- std::cerr << "\nIf you have used 'make run', edit loolwsd.xml and make sure you have removed '--o:logging.level=trace' from the command line in Makefile.am.\n" << std::endl;
-#endif
- Log::shutdown();
- _exit(Application::EXIT_SOFTWARE);
- }
- }
-
const auto logToFile = getConfigValue<bool>(conf, "logging.file[@enable]", false);
std::map<std::string, std::string> logProperties;
for (std::size_t i = 0; ; ++i)
@@ -846,6 +813,45 @@ void LOOLWSD::initialize(Application& self)
LOG_INF("Setting log-level to [trace] and delaying setting to configured [" << LogLevel << "] until after WSD initialization.");
}
+ // Get anonymization settings.
+#if LOOLWSD_ANONYMIZE_USERNAMES
+ AnonymizeUsernames = true;
+#else
+ AnonymizeUsernames = getConfigValue<bool>(conf, "logging.anonymize.usernames", false);
+#endif
+ if (AnonymizeUsernames)
+ setenv("LOOL_ANONYMIZE_USERNAMES", AnonymizeUsernames ? "1" : "0", true);
+
+#if LOOLWSD_ANONYMIZE_FILENAMES
+ AnonymizeFilenames = true;
+#else
+ AnonymizeFilenames = getConfigValue<bool>(conf, "logging.anonymize.filenames", false);
+#endif
+ if (AnonymizeFilenames)
+ setenv("LOOL_ANONYMIZE_FILENAMES", AnonymizeFilenames ? "1" : "0", true);
+
+ if ((AnonymizeFilenames || AnonymizeUsernames) && LogLevel == "trace")
+ {
+ if (getConfigValue<bool>(conf, "logging.anonymize.allow_logging_pii", false))
+ {
+ LOG_WRN("Enabling trace logging while anonymization is enabled due to logging.anonymize.allow_logging_pii setting. "
+ "This will leak personally identifiable information!");
+ }
+ else
+ {
+ static const char failure[] = "Anonymization and trace-level logging are incompatible. "
+ "Please reduce logging level to debug or lower in loolwsd.xml to prevent leaking sensitive user data.";
+ LOG_FTL(failure);
+ std::cerr << '\n' << failure << std::endl;
+#if ENABLE_DEBUG
+ std::cerr << "\nIf you have used 'make run', edit loolwsd.xml and make sure you have removed "
+ "'--o:logging.level=trace' from the command line in Makefile.am.\n" << std::endl;
+#endif
+ Log::shutdown();
+ _exit(Application::EXIT_SOFTWARE);
+ }
+ }
+
{
std::string proto = getConfigValue<std::string>(conf, "net.proto", "");
if (!Poco::icompare(proto, "ipv4"))
commit 9a35fcd269877f3b42bb34c0d1b3bd6e98450d7d
Author: Ashod Nakashian <ashod.nakashian at collabora.co.uk>
AuthorDate: Wed Aug 1 22:04:33 2018 -0400
Commit: Jan Holesovsky <kendy at collabora.com>
CommitDate: Fri Aug 17 07:54:19 2018 +0200
wsd: minor cleanup of CheckFileInfo logging
Change-Id: I45a7d281a640cbadfd42f1411f53946ae0142653
diff --git a/wsd/Storage.cpp b/wsd/Storage.cpp
index 5c9d6643b..f43f5d20d 100644
--- a/wsd/Storage.cpp
+++ b/wsd/Storage.cpp
@@ -470,6 +470,11 @@ std::unique_ptr<WopiStorage::WOPIFileInfo> WopiStorage::getWOPIFileInfo(const Au
Poco::JSON::Object::Ptr object;
if (JsonUtil::parseJSON(wopiResponse, object))
{
+ if (LOOLWSD::AnonymizeFilenames || LOOLWSD::AnonymizeUsernames)
+ LOG_DBG("WOPI::CheckFileInfo (" << callDuration.count() * 1000. << " ms): anonymizing...");
+ else
+ LOG_DBG("WOPI::CheckFileInfo (" << callDuration.count() * 1000. << " ms): " << wopiResponse);
+
JsonUtil::findJSONValue(object, "BaseFileName", filename);
JsonUtil::findJSONValue(object, "OwnerId", ownerId);
JsonUtil::findJSONValue(object, "UserId", userId);
@@ -517,10 +522,9 @@ std::unique_ptr<WopiStorage::WOPIFileInfo> WopiStorage::getWOPIFileInfo(const Au
object->remove("UserId");
object->remove("UserFriendlyName");
}
- }
- // Log either an original or anonymized version, depending on anonymization flags.
- LOG_DBG("WOPI::CheckFileInfo (" << callDuration.count() * 1000. << " ms): " << wopiResponse);
+ LOG_DBG("WOPI::CheckFileInfo (" << callDuration.count() * 1000. << " ms): " << wopiResponse);
+ }
JsonUtil::findJSONValue(object, "Size", size);
JsonUtil::findJSONValue(object, "UserExtraInfo", userExtraInfo);
@@ -548,10 +552,12 @@ std::unique_ptr<WopiStorage::WOPIFileInfo> WopiStorage::getWOPIFileInfo(const Au
else
{
if (LOOLWSD::AnonymizeFilenames || LOOLWSD::AnonymizeUsernames)
- LOG_ERR("WOPI::CheckFileInfo failed or no valid JSON payload returned. Access denied.");
- else
- LOG_ERR("WOPI::CheckFileInfo failed or no valid JSON payload returned. Access denied. "
- "Original response: [" << wopiResponse << "].");
+ wopiResponse = "obfuscated";
+
+ LOG_ERR("WOPI::CheckFileInfo (" << callDuration.count() * 1000. <<
+ " ms) failed or no valid JSON payload returned. Access denied. "
+ "Original response: [" << wopiResponse << "].");
+
throw UnauthorizedRequestException("Access denied. WOPI::CheckFileInfo failed on: " + uriAnonym);
}
commit 7b48be5a9dde4fcec01b8804559ffa4f9c19d53c
Author: Ashod Nakashian <ashod.nakashian at collabora.co.uk>
AuthorDate: Wed Aug 1 22:03:53 2018 -0400
Commit: Jan Holesovsky <kendy at collabora.com>
CommitDate: Fri Aug 17 07:54:19 2018 +0200
wsd: don't warn on missing json
Change-Id: I28086152fbf9fc82ddead1a2feb80f21ffdcd208
diff --git a/common/JsonUtil.hpp b/common/JsonUtil.hpp
index fe63a469b..54cf99978 100644
--- a/common/JsonUtil.hpp
+++ b/common/JsonUtil.hpp
@@ -106,7 +106,7 @@ bool findJSONValue(Poco::JSON::Object::Ptr &object, const std::string& key, T& v
// Check each property name against given key
// and warn for mis-spells with tolerance of 2.
- for (const std::string& userInput: propertyNames)
+ for (const std::string& userInput : propertyNames)
{
if (key != userInput)
{
@@ -134,7 +134,7 @@ bool findJSONValue(Poco::JSON::Object::Ptr &object, const std::string& key, T& v
return true;
}
- LOG_WRN("Missing JSON property [" << key << "]");
+ LOG_INF("Missing JSON property [" << key << "] will default to [" << value << "].");
return false;
}
diff --git a/wsd/Storage.cpp b/wsd/Storage.cpp
index 72ca99edd..5c9d6643b 100644
--- a/wsd/Storage.cpp
+++ b/wsd/Storage.cpp
@@ -369,10 +369,13 @@ Poco::Timestamp iso8601ToTimestamp(const std::string& iso8601Time, const std::st
Poco::Timestamp timestamp = Poco::Timestamp::fromEpochTime(0);
try
{
- int timeZoneDifferential;
- Poco::DateTime dateTime;
- Poco::DateTimeParser::parse(Poco::DateTimeFormat::ISO8601_FRAC_FORMAT, iso8601Time, dateTime, timeZoneDifferential);
- timestamp = dateTime.timestamp();
+ if (!iso8601Time.empty())
+ {
+ int timeZoneDifferential;
+ Poco::DateTime dateTime;
+ Poco::DateTimeParser::parse(Poco::DateTimeFormat::ISO8601_FRAC_FORMAT, iso8601Time, dateTime, timeZoneDifferential);
+ timestamp = dateTime.timestamp();
+ }
}
catch (const Poco::SyntaxException& exc)
{
commit b7f5809a792e2a0b816d3cfd96511cdd93582d15
Author: Ashod Nakashian <ashod.nakashian at collabora.co.uk>
AuthorDate: Sat Jul 21 15:58:35 2018 -0400
Commit: Jan Holesovsky <kendy at collabora.com>
CommitDate: Fri Aug 17 07:54:19 2018 +0200
wsd: fixed remaining anonymization issues
Change-Id: I756ccd4b810fdc4dd62a83c1704c59c6a947e615
diff --git a/kit/ChildSession.cpp b/kit/ChildSession.cpp
index a7a1349ff..f63e2643e 100644
--- a/kit/ChildSession.cpp
+++ b/kit/ChildSession.cpp
@@ -650,7 +650,7 @@ bool ChildSession::downloadAs(const char* /*buffer*/, int /*length*/, const std:
}
// Obfuscate the new name.
- Util::mapAnonymized(name, _docManager.getObfuscatedFileId());
+ Util::mapAnonymized(Util::getFilenameFromURL(name), _docManager.getObfuscatedFileId());
getTokenString(tokens[3], "format", format);
@@ -1130,8 +1130,6 @@ bool ChildSession::saveAs(const char* /*buffer*/, int /*length*/, const std::vec
return false;
}
- const std::string urlAnonym = anonymizeUrl(url);
-
// if the url is a 'wopi:///something/blah.odt', then save to a temporary
Poco::URI wopiURL(url);
if (wopiURL.getScheme() == "wopi")
@@ -1161,16 +1159,20 @@ bool ChildSession::saveAs(const char* /*buffer*/, int /*length*/, const std::vec
}
}
+
bool success = false;
{
std::unique_lock<std::mutex> lock(_docManager.getDocumentMutex());
- getLOKitDocument()->setView(_viewId);
-
- LOG_DBG("Calling LOK's saveAs with: '" << urlAnonym << "', '" <<
+ // We don't have the FileId at this point, just a new filename to save-as.
+ // So here the filename will be obfuscated with some hashing, which later will
+ // get a proper FileId that we will use going forward.
+ LOG_DBG("Calling LOK's saveAs with: '" << anonymizeUrl(wopiFilename) << "', '" <<
(format.size() == 0 ? "(nullptr)" : format.c_str()) << "', '" <<
(filterOptions.size() == 0 ? "(nullptr)" : filterOptions.c_str()) << "'.");
+ getLOKitDocument()->setView(_viewId);
+
success = getLOKitDocument()->saveAs(url.c_str(),
format.empty() ? nullptr : format.c_str(),
filterOptions.empty() ? nullptr : filterOptions.c_str());
diff --git a/wsd/DocumentBroker.cpp b/wsd/DocumentBroker.cpp
index 74ee429fd..0fe8e1878 100644
--- a/wsd/DocumentBroker.cpp
+++ b/wsd/DocumentBroker.cpp
@@ -670,7 +670,7 @@ bool DocumentBroker::load(const std::shared_ptr<ClientSession>& session, const s
std::string localPathEncoded;
Poco::URI::encode(localPath, "#", localPathEncoded);
_uriJailed = Poco::URI(Poco::URI("file://"), localPathEncoded).toString();
- _uriJailedAnonym = Poco::URI(Poco::URI("file://"), LOOLWSD::anonymizeUrl(localPathEncoded)).toString();
+ _uriJailedAnonym = Poco::URI(Poco::URI("file://"), LOOLWSD::anonymizeUrl(localPath)).toString();
_filename = fileInfo._filename;
@@ -772,6 +772,14 @@ bool DocumentBroker::saveToStorageInternal(const std::string& sessionId,
const Authorization auth = it->second->getAuthorization();
const std::string uri = isSaveAs ? saveAsPath : it->second->getPublicUri().toString();
+
+ // Map the FileId from the docKey to the new filename to anonymize the new filename as the FileId.
+ const std::string newFilename = Util::getFilenameFromURL(uri);
+ const std::string fileId = Util::getFilenameFromURL(_docKey);
+ if (LOOLWSD::AnonymizeFilenames)
+ LOG_DBG("New filename [" << LOOLWSD::anonymizeUrl(newFilename) << "] will be known by its fileId [" << fileId << "]");
+
+ Util::mapAnonymized(newFilename, fileId);
const std::string uriAnonym = LOOLWSD::anonymizeUrl(uri);
// If the file timestamp hasn't changed, skip saving.
diff --git a/wsd/Storage.cpp b/wsd/Storage.cpp
index cea27b758..72ca99edd 100644
--- a/wsd/Storage.cpp
+++ b/wsd/Storage.cpp
@@ -740,16 +740,21 @@ StorageBase::SaveResult WopiStorage::saveLocalFileToStorage(const Authorization&
{
// Anonymize the filename
std::string url;
- JsonUtil::findJSONValue(object, "Url", url);
- std::string decodedUrl;
- Poco::URI::decode(url, decodedUrl);
- const std::string obfuscatedFileId = Util::getFilenameFromURL(decodedUrl);
-
std::string filename;
- JsonUtil::findJSONValue(object, "Name", filename);
- const std::string filenameOnly = Util::getFilenameFromURL(filename);
- Util::mapAnonymized(filenameOnly, obfuscatedFileId);
- object->set("Name", LOOLWSD::anonymizeUrl(filename));
+ if (JsonUtil::findJSONValue(object, "Url", url) &&
+ JsonUtil::findJSONValue(object, "Name", filename))
+ {
+ // Get the FileId form the URL, which we use as the anonymized filename.
+ std::string decodedUrl;
+ Poco::URI::decode(url, decodedUrl);
+ const std::string obfuscatedFileId = Util::getFilenameFromURL(decodedUrl);
+ Util::mapAnonymized(obfuscatedFileId, obfuscatedFileId); // Identity, to avoid re-anonymizing.
+
+ const std::string filenameOnly = Util::getFilenameFromURL(filename);
+ Util::mapAnonymized(filenameOnly, obfuscatedFileId);
+ object->set("Name", LOOLWSD::anonymizeUrl(filename));
+ }
+
// Stringify to log.
std::ostringstream ossResponse;
object->stringify(ossResponse);
commit 7cadf9da49c2b804f30f1e8c2d2998c768b9d365
Author: Ashod Nakashian <ashod.nakashian at collabora.co.uk>
AuthorDate: Thu Jul 19 01:22:07 2018 -0400
Commit: Jan Holesovsky <kendy at collabora.com>
CommitDate: Fri Aug 17 07:54:19 2018 +0200
wsd: don't anonymize 'contents' URI
Change-Id: Ia66729453a1f7db6105a0332de0f8bad3835f3f5
Reviewed-on: https://gerrit.libreoffice.org/57707
Reviewed-by: Jan Holesovsky <kendy at collabora.com>
Tested-by: Jan Holesovsky <kendy at collabora.com>
diff --git a/wsd/LOOLWSD.cpp b/wsd/LOOLWSD.cpp
index d5524ad89..8074152c4 100644
--- a/wsd/LOOLWSD.cpp
+++ b/wsd/LOOLWSD.cpp
@@ -2802,6 +2802,9 @@ int LOOLWSD::innerMain()
Log::logger().setLevel(LogLevel);
}
+ // URI with /contents are public and we don't need to anonymize them.
+ Util::mapAnonymized("contents", "contents");
+
// Start the server.
srv.start(ClientPortNumber);
commit f64e0fba92ad80776572255951b2e0d76bc76e73
Author: Ashod Nakashian <ashod.nakashian at collabora.co.uk>
AuthorDate: Wed Jul 18 10:30:22 2018 -0400
Commit: Jan Holesovsky <kendy at collabora.com>
CommitDate: Fri Aug 17 07:54:19 2018 +0200
wsd: more string split tests
Change-Id: Idd6e99954b11238eaf64e11e7969d0aee1612557
Reviewed-on: https://gerrit.libreoffice.org/57648
Reviewed-by: Ashod Nakashian <ashnakash at gmail.com>
Tested-by: Ashod Nakashian <ashnakash at gmail.com>
diff --git a/test/WhiteBoxTests.cpp b/test/WhiteBoxTests.cpp
index c6ad64217..820959287 100644
--- a/test/WhiteBoxTests.cpp
+++ b/test/WhiteBoxTests.cpp
@@ -183,6 +183,28 @@ void WhiteBoxTests::testSplitting()
CPPUNIT_ASSERT_EQUAL(std::string("a"), first);
CPPUNIT_ASSERT_EQUAL(std::string(""), second);
+
+ // Split first, remove delim.
+ std::tie(first, second) = Util::split(std::string("a."), '.', true);
+ CPPUNIT_ASSERT_EQUAL(std::string("a"), first);
+ CPPUNIT_ASSERT_EQUAL(std::string(""), second);
+
+ // Split first, keep delim.
+ std::tie(first, second) = Util::split(std::string("a."), '.', false);
+ CPPUNIT_ASSERT_EQUAL(std::string("a"), first);
+ CPPUNIT_ASSERT_EQUAL(std::string("."), second);
+
+ // Split first, remove delim.
+ std::tie(first, second) = Util::splitLast(std::string("a."), '.', true);
+ CPPUNIT_ASSERT_EQUAL(std::string("a"), first);
+ CPPUNIT_ASSERT_EQUAL(std::string(""), second);
+
+ // Split first, keep delim.
+ std::tie(first, second) = Util::splitLast(std::string("a."), '.', false);
+ CPPUNIT_ASSERT_EQUAL(std::string("a"), first);
+ CPPUNIT_ASSERT_EQUAL(std::string("."), second);
+
+
// Split first, remove delim.
std::tie(first, second) = Util::split(std::string("aa.bb"), '.', true);
CPPUNIT_ASSERT_EQUAL(std::string("aa"), first);
commit 78248a542c9ca31bf9ad4cad9b55d78690384395
Author: Ashod Nakashian <ashod.nakashian at collabora.co.uk>
AuthorDate: Tue Jul 17 02:01:05 2018 -0400
Commit: Jan Holesovsky <kendy at collabora.com>
CommitDate: Fri Aug 17 07:54:19 2018 +0200
wsd: anonymization improvements and unittests
Also support anonymization of downloadas documents
and renaming of documents.
Change-Id: I81a80e6290217659987d73f625e5f0fb81cb7ef2
Reviewed-on: https://gerrit.libreoffice.org/57541
Reviewed-by: Jan Holesovsky <kendy at collabora.com>
Tested-by: Jan Holesovsky <kendy at collabora.com>
diff --git a/common/Util.cpp b/common/Util.cpp
index 788757e1c..cfd636d4b 100644
--- a/common/Util.cpp
+++ b/common/Util.cpp
@@ -544,6 +544,42 @@ namespace Util
return true;
}
+ /// Split a string in two at the delimeter and give the delimiter to the first.
+ static
+ std::pair<std::string, std::string> splitLast2(const char* s, const int length, const char delimeter = ' ')
+ {
+ if (s != nullptr && length > 0)
+ {
+ const int pos = getLastDelimiterPosition(s, length, delimeter);
+ if (pos < length)
+ return std::make_pair(std::string(s, pos + 1), std::string(s + pos + 1));
+ }
+
+ // Not found; return in first.
+ return std::make_pair(std::string(s, length), std::string());
+ }
+
+ std::tuple<std::string, std::string, std::string, std::string> splitUrl(const std::string& url)
+ {
+ // In case we have a URL that has parameters.
+ std::string base;
+ std::string params;
+ std::tie(base, params) = Util::split(url, '?', false);
+
+ std::string filename;
+ std::tie(base, filename) = Util::splitLast2(base.c_str(), base.size(), '/');
+ if (filename.empty())
+ {
+ // If no '/', then it's only filename.
+ std::swap(base, filename);
+ }
+
+ std::string ext;
+ std::tie(filename, ext) = Util::splitLast(filename, '.', false);
+
+ return std::make_tuple(base, filename, ext, params);
+ }
+
static std::map<std::string, std::string> AnonymizedStrings;
static std::atomic<unsigned> AnonymizationSalt(0);
static std::mutex AnonymizedMutex;
@@ -586,45 +622,25 @@ namespace Util
return res;
}
- static std::string anonymizeFilename(const std::string& filename)
+ std::string getFilenameFromURL(const std::string& url)
{
- // Preserve the extension.
- std::string basename;
+ std::string base;
+ std::string filename;
std::string ext;
- const std::size_t mid = filename.find_last_of('.');
- if (mid != std::string::npos)
- {
- basename = filename.substr(0, mid);
- ext = filename.substr(mid);
- }
- else
- basename = filename;
-
- return Util::anonymize(basename) + ext;
- }
-
- std::string getFilenameFromPath(const std::string& path)
- {
- const std::size_t mid = path.find_last_of('/');
- if (mid != std::string::npos)
- return path.substr(mid + 1);
-
- // No path, treat as filename only.
- return path;
+ std::string params;
+ std::tie(base, filename, ext, params) = Util::splitUrl(url);
+ return filename;
}
std::string anonymizeUrl(const std::string& url)
{
- const std::size_t mid = url.find_last_of('/');
- if (mid != std::string::npos)
- {
- const std::string path = url.substr(0, mid + 1);
- const std::string filename = url.substr(mid + 1);
- return path + Util::anonymizeFilename(filename);
- }
+ std::string base;
+ std::string filename;
+ std::string ext;
+ std::string params;
+ std::tie(base, filename, ext, params) = Util::splitUrl(url);
- // No path, treat as filename only.
- return Util::anonymizeFilename(url);
+ return base + Util::anonymize(filename) + ext + params;
}
}
diff --git a/common/Util.hpp b/common/Util.hpp
index 253776330..ada42d093 100644
--- a/common/Util.hpp
+++ b/common/Util.hpp
@@ -310,6 +310,18 @@ namespace Util
return false;
}
+ inline size_t getLastDelimiterPosition(const char* message, const int length, const char delim)
+ {
+ if (message && length > 0)
+ {
+ const char *founddelim = static_cast<const char *>(memrchr(message, delim, length));
+ const auto size = (founddelim == nullptr ? length : founddelim - message);
+ return size;
+ }
+
+ return 0;
+ }
+
inline size_t getDelimiterPosition(const char* message, const int length, const char delim)
{
if (message && length > 0)
@@ -331,19 +343,38 @@ namespace Util
/// Split a string in two at the delimeter, removing it.
inline
- std::pair<std::string, std::string> split(const char* s, const int length, const char delimeter = ' ')
+ std::pair<std::string, std::string> split(const char* s, const int length, const char delimeter = ' ', bool removeDelim = true)
{
const auto size = getDelimiterPosition(s, length, delimeter);
- return std::make_pair(std::string(s, size), std::string(s+size+1));
+ return std::make_pair(std::string(s, size), std::string(s+size+removeDelim));
}
/// Split a string in two at the delimeter, removing it.
inline
- std::pair<std::string, std::string> split(const std::string& s, const char delimeter = ' ')
+ std::pair<std::string, std::string> split(const std::string& s, const char delimeter = ' ', bool removeDelim = true)
{
- return split(s.c_str(), s.size(), delimeter);
+ return split(s.c_str(), s.size(), delimeter, removeDelim);
}
+ /// Split a string in two at the delimeter.
+ inline
+ std::pair<std::string, std::string> splitLast(const char* s, const int length, const char delimeter = ' ', bool removeDelim = true)
+ {
+ const auto size = getLastDelimiterPosition(s, length, delimeter);
+ return std::make_pair(std::string(s, size), std::string(s+size+removeDelim));
+ }
+
+ /// Split a string in two at the delimeter, removing it.
+ inline
+ std::pair<std::string, std::string> splitLast(const std::string& s, const char delimeter = ' ', bool removeDelim = true)
+ {
+ return splitLast(s.c_str(), s.size(), delimeter, removeDelim);
+ }
+
+ /// Splits a URL into path (with protocol), filename, extension, parameters.
+ /// All components are optional, depending on what the URL represents (can be a unix path).
+ std::tuple<std::string, std::string, std::string, std::string> splitUrl(const std::string& url);
+
/// Check for the URI scheme validity.
/// For now just a basic sanity check, can be extended if necessary.
bool isValidURIScheme(const std::string& scheme);
@@ -363,8 +394,8 @@ namespace Util
/// Anonymize the basename of filenames only, preserving the path and extension.
std::string anonymizeUrl(const std::string& url);
- /// Extract and return the filename given a path (i.e. the token after last '/').
- std::string getFilenameFromPath(const std::string& path);
+ /// Extract and return the filename given a url or path.
+ std::string getFilenameFromURL(const std::string& url);
/// Given one or more patterns to allow, and one or more to deny,
/// the match member will return true if, and only if, the subject
diff --git a/kit/ChildSession.cpp b/kit/ChildSession.cpp
index b273c86f0..a7a1349ff 100644
--- a/kit/ChildSession.cpp
+++ b/kit/ChildSession.cpp
@@ -649,6 +649,9 @@ bool ChildSession::downloadAs(const char* /*buffer*/, int /*length*/, const std:
return false;
}
+ // Obfuscate the new name.
+ Util::mapAnonymized(name, _docManager.getObfuscatedFileId());
+
getTokenString(tokens[3], "format", format);
if (getTokenString(tokens[4], "options", filterOptions))
diff --git a/kit/ChildSession.hpp b/kit/ChildSession.hpp
index c0813a047..c32e797ba 100644
--- a/kit/ChildSession.hpp
+++ b/kit/ChildSession.hpp
@@ -70,6 +70,8 @@ public:
/// setting a view followed by a tile render, etc.
virtual std::mutex& getDocumentMutex() = 0;
+ virtual std::string getObfuscatedFileId() = 0;
+
virtual std::shared_ptr<TileQueue>& getTileQueue() = 0;
virtual bool sendFrame(const char* buffer, int length, WSOpCode opCode = WSOpCode::Text) = 0;
diff --git a/kit/Kit.cpp b/kit/Kit.cpp
index 171b01449..74e12f2c9 100644
--- a/kit/Kit.cpp
+++ b/kit/Kit.cpp
@@ -109,7 +109,6 @@ static LokHookFunction2* initFunction = nullptr;
static bool AnonymizeFilenames = false;
static bool AnonymizeUsernames = false;
static std::string ObfuscatedFileId;
-static std::string ObfuscatedUserId;
#endif
#if ENABLE_DEBUG
@@ -712,6 +711,7 @@ public:
_docKey(docKey),
_docId(docId),
_url(url),
+ _obfuscatedFileId(Util::getFilenameFromURL(docKey)),
_tileQueue(std::move(tileQueue)),
_socketPoll(socketPoll),
_websocketHandler(websocketHandler),
@@ -1911,6 +1911,11 @@ private:
return _documentMutex;
}
+ std::string getObfuscatedFileId() override
+ {
+ return _obfuscatedFileId;
+ }
+
private:
std::shared_ptr<lok::Office> _loKit;
const std::string _jailId;
@@ -1919,6 +1924,7 @@ private:
/// Short numerical ID. Unique during the lifetime of WSD.
const std::string _docId;
const std::string _url;
+ const std::string _obfuscatedFileId;
std::string _jailedUrl;
std::string _renderOpts;
@@ -2005,7 +2011,7 @@ protected:
const std::string& sessionId = tokens[1];
const std::string& docKey = tokens[2];
const std::string& docId = tokens[3];
- const std::string fileId = Util::getFilenameFromPath(docKey);
+ const std::string fileId = Util::getFilenameFromURL(docKey);
Util::mapAnonymized(fileId, fileId); // Identity mapping, since fileId is already obfuscated
std::string url;
diff --git a/test/WhiteBoxTests.cpp b/test/WhiteBoxTests.cpp
index 3250b17ad..c6ad64217 100644
--- a/test/WhiteBoxTests.cpp
+++ b/test/WhiteBoxTests.cpp
@@ -27,6 +27,7 @@ class WhiteBoxTests : public CPPUNIT_NS::TestFixture
CPPUNIT_TEST_SUITE(WhiteBoxTests);
CPPUNIT_TEST(testLOOLProtocolFunctions);
+ CPPUNIT_TEST(testSplitting);
CPPUNIT_TEST(testMessageAbbreviation);
CPPUNIT_TEST(testTokenizer);
CPPUNIT_TEST(testReplace);
@@ -36,10 +37,12 @@ class WhiteBoxTests : public CPPUNIT_NS::TestFixture
CPPUNIT_TEST(testRectanglesIntersect);
CPPUNIT_TEST(testAuthorization);
CPPUNIT_TEST(testJson);
+ CPPUNIT_TEST(testAnonymization);
CPPUNIT_TEST_SUITE_END();
void testLOOLProtocolFunctions();
+ void testSplitting();
void testMessageAbbreviation();
void testTokenizer();
void testReplace();
@@ -49,6 +52,7 @@ class WhiteBoxTests : public CPPUNIT_NS::TestFixture
void testRectanglesIntersect();
void testAuthorization();
void testJson();
+ void testAnonymization();
};
void WhiteBoxTests::testLOOLProtocolFunctions()
@@ -142,6 +146,115 @@ void WhiteBoxTests::testLOOLProtocolFunctions()
CPPUNIT_ASSERT_EQUAL(std::string(""), Util::trim(s));
}
+void WhiteBoxTests::testSplitting()
+{
+ CPPUNIT_ASSERT_EQUAL(std::string(), Util::getDelimitedInitialSubstring(nullptr, 5, '\n'));
+ CPPUNIT_ASSERT_EQUAL(std::string(), Util::getDelimitedInitialSubstring(nullptr, -1, '\n'));
+ CPPUNIT_ASSERT_EQUAL(std::string(), Util::getDelimitedInitialSubstring("abc", 0, '\n'));
+ CPPUNIT_ASSERT_EQUAL(std::string(), Util::getDelimitedInitialSubstring("abc", -1, '\n'));
+ CPPUNIT_ASSERT_EQUAL(std::string("ab"), Util::getDelimitedInitialSubstring("abc", 2, '\n'));
+
+ std::string first;
+ std::string second;
+
+ std::tie(first, second) = Util::split(std::string(""), '.', true);
+ std::tie(first, second) = Util::split(std::string(""), '.', false);
+
+ std::tie(first, second) = Util::splitLast(std::string(""), '.', true);
+ std::tie(first, second) = Util::splitLast(std::string(""), '.', false);
+
+ // Split first, remove delim.
+ std::tie(first, second) = Util::split(std::string("a"), '.', true);
+ CPPUNIT_ASSERT_EQUAL(std::string("a"), first);
+ CPPUNIT_ASSERT_EQUAL(std::string(""), second);
+
+ // Split first, keep delim.
+ std::tie(first, second) = Util::split(std::string("a"), '.', false);
+ CPPUNIT_ASSERT_EQUAL(std::string("a"), first);
+ CPPUNIT_ASSERT_EQUAL(std::string(""), second);
+
+ // Split first, remove delim.
+ std::tie(first, second) = Util::splitLast(std::string("a"), '.', true);
+ CPPUNIT_ASSERT_EQUAL(std::string("a"), first);
+ CPPUNIT_ASSERT_EQUAL(std::string(""), second);
+
+ // Split first, keep delim.
+ std::tie(first, second) = Util::splitLast(std::string("a"), '.', false);
+ CPPUNIT_ASSERT_EQUAL(std::string("a"), first);
+ CPPUNIT_ASSERT_EQUAL(std::string(""), second);
+
+ // Split first, remove delim.
+ std::tie(first, second) = Util::split(std::string("aa.bb"), '.', true);
+ CPPUNIT_ASSERT_EQUAL(std::string("aa"), first);
+ CPPUNIT_ASSERT_EQUAL(std::string("bb"), second);
+
+ // Split first, keep delim.
+ std::tie(first, second) = Util::split(std::string("aa.bb"), '.', false);
+ CPPUNIT_ASSERT_EQUAL(std::string("aa"), first);
+ CPPUNIT_ASSERT_EQUAL(std::string(".bb"), second);
+
+ CPPUNIT_ASSERT_EQUAL(5UL, Util::getLastDelimiterPosition("aa.bb.cc", 8, '.'));
+
+ // Split last, remove delim.
+ std::tie(first, second) = Util::splitLast(std::string("aa.bb.cc"), '.', true);
+ CPPUNIT_ASSERT_EQUAL(std::string("aa.bb"), first);
+ CPPUNIT_ASSERT_EQUAL(std::string("cc"), second);
+
+ // Split last, keep delim.
+ std::tie(first, second) = Util::splitLast(std::string("aa.bb.cc"), '.', false);
+ CPPUNIT_ASSERT_EQUAL(std::string("aa.bb"), first);
+ CPPUNIT_ASSERT_EQUAL(std::string(".cc"), second);
+
+ // Split last, remove delim.
+ std::tie(first, second) = Util::splitLast(std::string("/owncloud/index.php/apps/richdocuments/wopi/files/13_ocgdpzbkm39u"), '/', true);
+ CPPUNIT_ASSERT_EQUAL(std::string("/owncloud/index.php/apps/richdocuments/wopi/files"), first);
+ CPPUNIT_ASSERT_EQUAL(std::string("13_ocgdpzbkm39u"), second);
+
+ // Split last, keep delim.
+ std::tie(first, second) = Util::splitLast(std::string("/owncloud/index.php/apps/richdocuments/wopi/files/13_ocgdpzbkm39u"), '/', false);
+ CPPUNIT_ASSERT_EQUAL(std::string("/owncloud/index.php/apps/richdocuments/wopi/files"), first);
+ CPPUNIT_ASSERT_EQUAL(std::string("/13_ocgdpzbkm39u"), second);
+
+ std::string third;
+ std::string fourth;
+
+ std::tie(first, second, third, fourth) = Util::splitUrl("filename");
+ CPPUNIT_ASSERT_EQUAL(std::string(""), first);
+ CPPUNIT_ASSERT_EQUAL(std::string("filename"), second);
+ CPPUNIT_ASSERT_EQUAL(std::string(""), third);
+ CPPUNIT_ASSERT_EQUAL(std::string(""), fourth);
+
+ std::tie(first, second, third, fourth) = Util::splitUrl("filename.ext");
+ CPPUNIT_ASSERT_EQUAL(std::string(""), first);
+ CPPUNIT_ASSERT_EQUAL(std::string("filename"), second);
+ CPPUNIT_ASSERT_EQUAL(std::string(".ext"), third);
+ CPPUNIT_ASSERT_EQUAL(std::string(""), fourth);
+
+ std::tie(first, second, third, fourth) = Util::splitUrl("/path/to/filename");
+ CPPUNIT_ASSERT_EQUAL(std::string("/path/to/"), first);
+ CPPUNIT_ASSERT_EQUAL(std::string("filename"), second);
+ CPPUNIT_ASSERT_EQUAL(std::string(""), third);
+ CPPUNIT_ASSERT_EQUAL(std::string(""), fourth);
+
+ std::tie(first, second, third, fourth) = Util::splitUrl("http://domain.com/path/filename");
+ CPPUNIT_ASSERT_EQUAL(std::string("http://domain.com/path/"), first);
+ CPPUNIT_ASSERT_EQUAL(std::string("filename"), second);
+ CPPUNIT_ASSERT_EQUAL(std::string(""), third);
+ CPPUNIT_ASSERT_EQUAL(std::string(""), fourth);
+
+ std::tie(first, second, third, fourth) = Util::splitUrl("http://domain.com/path/filename.ext");
+ CPPUNIT_ASSERT_EQUAL(std::string("http://domain.com/path/"), first);
+ CPPUNIT_ASSERT_EQUAL(std::string("filename"), second);
+ CPPUNIT_ASSERT_EQUAL(std::string(".ext"), third);
+ CPPUNIT_ASSERT_EQUAL(std::string(""), fourth);
+
+ std::tie(first, second, third, fourth) = Util::splitUrl("http://domain.com/path/filename.ext?params=3&command=5");
+ CPPUNIT_ASSERT_EQUAL(std::string("http://domain.com/path/"), first);
+ CPPUNIT_ASSERT_EQUAL(std::string("filename"), second);
+ CPPUNIT_ASSERT_EQUAL(std::string(".ext"), third);
+ CPPUNIT_ASSERT_EQUAL(std::string("?params=3&command=5"), fourth);
+}
+
void WhiteBoxTests::testMessageAbbreviation()
{
CPPUNIT_ASSERT_EQUAL(std::string(), Util::getDelimitedInitialSubstring(nullptr, 5, '\n'));
@@ -387,6 +500,11 @@ public:
return _mutex;
}
+ std::string getObfuscatedFileId() override
+ {
+ return std::string();
+ }
+
std::shared_ptr<TileQueue>& getTileQueue() override
{
return _tileQueue;
@@ -505,6 +623,40 @@ void WhiteBoxTests::testJson()
CPPUNIT_ASSERT_EQUAL(std::string("user at user.com"), sValue);
}
+void WhiteBoxTests::testAnonymization()
+{
+ static const std::string name = "some name with space";
+ CPPUNIT_ASSERT_EQUAL(std::string("#0#77d#"), Util::anonymizeUrl(name));
+ Util::mapAnonymized(name, name);
+ CPPUNIT_ASSERT_EQUAL(name, Util::anonymizeUrl(name));
+
+ static const std::string filename = "filename.ext";
+ CPPUNIT_ASSERT_EQUAL(std::string("#1#341#.ext"), Util::anonymizeUrl(filename));
+ Util::mapAnonymized("filename", "filename");
+ CPPUNIT_ASSERT_EQUAL(name, Util::anonymizeUrl(name));
+
+ static const std::string filenameTestx = "testx (6).odt";
+ CPPUNIT_ASSERT_EQUAL(std::string("#2#2df#.odt"), Util::anonymizeUrl(filenameTestx));
+ Util::mapAnonymized("testx (6)", "testx (6)");
+ CPPUNIT_ASSERT_EQUAL(filenameTestx, Util::anonymizeUrl(filenameTestx));
+
+ static const std::string path = "/path/to/filename.ext";
+ CPPUNIT_ASSERT_EQUAL(path, Util::anonymizeUrl(path));
+
+ static const std::string plainUrl = "http://localhost/owncloud/index.php/apps/richdocuments/wopi/files/736_ocgdpzbkm39u?access_token=Hn0zttjbwkvGWb5BHbDa5ArgTykJAyBl&access_token_ttl=0&permission=edit";
+ const std::string urlAnonymized = Util::replace(plainUrl, "736_ocgdpzbkm39u", "#3#5a1#");
+ CPPUNIT_ASSERT_EQUAL(urlAnonymized, Util::anonymizeUrl(plainUrl));
+ Util::mapAnonymized("736_ocgdpzbkm39u", "736_ocgdpzbkm39u");
+ CPPUNIT_ASSERT_EQUAL(plainUrl, Util::anonymizeUrl(plainUrl));
+
+ static const std::string fileUrl = "http://localhost/owncloud/index.php/apps/richdocuments/wopi/files/736_ocgdpzbkm39u/secret.odt?access_token=Hn0zttjbwkvGWb5BHbDa5ArgTykJAyBl&access_token_ttl=0&permission=edit";
+ const std::string urlAnonymized2 = Util::replace(fileUrl, "secret", "#4#286#");
+ CPPUNIT_ASSERT_EQUAL(urlAnonymized2, Util::anonymizeUrl(fileUrl));
+ Util::mapAnonymized("secret", "736_ocgdpzbkm39u");
+ const std::string urlAnonymized3 = Util::replace(fileUrl, "secret", "736_ocgdpzbkm39u");
+ CPPUNIT_ASSERT_EQUAL(urlAnonymized3, Util::anonymizeUrl(fileUrl));
+}
+
CPPUNIT_TEST_SUITE_REGISTRATION(WhiteBoxTests);
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/wsd/DocumentBroker.cpp b/wsd/DocumentBroker.cpp
index 0c2db18e6..74ee429fd 100644
--- a/wsd/DocumentBroker.cpp
+++ b/wsd/DocumentBroker.cpp
@@ -514,10 +514,13 @@ bool DocumentBroker::load(const std::shared_ptr<ClientSession>& session, const s
std::ostringstream ossWopiInfo;
wopiInfo->stringify(ossWopiInfo);
+ const std::string wopiInfoString = ossWopiInfo.str();
+ LOG_TRC("Sending wopi info to client: " << wopiInfoString);
+
// Contains PostMessageOrigin property which is necessary to post messages to parent
// frame. Important to send this message immediately and not enqueue it so that in case
// document load fails, loleaflet is able to tell its parent frame via PostMessage API.
- session->sendMessage("wopi: " + ossWopiInfo.str());
+ session->sendMessage("wopi: " + wopiInfoString);
// Mark the session as 'Document owner' if WOPI hosts supports it
if (userId == _storage->getFileInfo()._ownerId)
diff --git a/wsd/LOOLWSD.cpp b/wsd/LOOLWSD.cpp
index e88e5ea9a..d5524ad89 100644
--- a/wsd/LOOLWSD.cpp
+++ b/wsd/LOOLWSD.cpp
@@ -1848,7 +1848,9 @@ private:
else if (reqPathTokens.count() > 2 && reqPathTokens[0] == "lool" && reqPathTokens[2] == "ws" &&
request.find("Upgrade") != request.end() && Poco::icompare(request["Upgrade"], "websocket") == 0)
{
- handleClientWsUpgrade(request, reqPathTokens[1], disposition);
+ std::string decodedUri;
+ Poco::URI::decode(reqPathTokens[1], decodedUri);
+ handleClientWsUpgrade(request, decodedUri, disposition);
}
else
{
@@ -2281,6 +2283,14 @@ private:
#endif
}
+ LOG_INF("URL [" << url << "].");
+ const auto uriPublic = DocumentBroker::sanitizeURI(url);
+ LOG_INF("URI [" << uriPublic.getPath() << "].");
+ const auto docKey = DocumentBroker::getDocKey(uriPublic);
+ LOG_INF("DocKey [" << docKey << "].");
+ const std::string fileId = Util::getFilenameFromURL(docKey);
+ Util::mapAnonymized(fileId, fileId); // Identity mapping, since fileId is already obfuscated
+
LOG_INF("Starting GET request handler for session [" << _id << "] on url [" << LOOLWSD::anonymizeUrl(url) << "].");
// Indicate to the client that document broker is searching.
@@ -2288,10 +2298,6 @@ private:
LOG_TRC("Sending to Client [" << status << "].");
ws.sendMessage(status);
- const auto uriPublic = DocumentBroker::sanitizeURI(url);
- const auto docKey = DocumentBroker::getDocKey(uriPublic);
- const std::string fileId = Util::getFilenameFromPath(docKey);
- Util::mapAnonymized(fileId, fileId); // Identity mapping, since fileId is already obfuscated
LOG_INF("Sanitized URI [" << LOOLWSD::anonymizeUrl(url) << "] to [" << LOOLWSD::anonymizeUrl(uriPublic.toString()) <<
"] and mapped to docKey [" << docKey << "] for session [" << _id << "].");
diff --git a/wsd/Storage.cpp b/wsd/Storage.cpp
index 2004b5467..cea27b758 100644
--- a/wsd/Storage.cpp
+++ b/wsd/Storage.cpp
@@ -33,6 +33,7 @@
#include <Poco/Net/SSLManager.h>
#include <Poco/StreamCopier.h>
#include <Poco/Timestamp.h>
+#include <Poco/URI.h>
// For residual Poco SSL usage.
#include <Poco/Net/AcceptCertificateHandler.h>
@@ -474,7 +475,7 @@ std::unique_ptr<WopiStorage::WOPIFileInfo> WopiStorage::getWOPIFileInfo(const Au
// Anonymize key values.
if (LOOLWSD::AnonymizeFilenames || LOOLWSD::AnonymizeUsernames)
{
- Util::mapAnonymized(filename, Util::getFilenameFromPath(_uri.toString()));
+ Util::mapAnonymized(Util::getFilenameFromURL(filename), Util::getFilenameFromURL(_uri.toString()));
JsonUtil::findJSONValue(object, "ObfuscatedUserId", obfuscatedUserId, false);
if (!obfuscatedUserId.empty())
@@ -738,9 +739,17 @@ StorageBase::SaveResult WopiStorage::saveLocalFileToStorage(const Authorization&
if (JsonUtil::parseJSON(responseString, object))
{
// Anonymize the filename
+ std::string url;
+ JsonUtil::findJSONValue(object, "Url", url);
+ std::string decodedUrl;
+ Poco::URI::decode(url, decodedUrl);
+ const std::string obfuscatedFileId = Util::getFilenameFromURL(decodedUrl);
+
std::string filename;
JsonUtil::findJSONValue(object, "Name", filename);
- object->set("Name", LOOLWSD::anonymizeUsername(filename));
+ const std::string filenameOnly = Util::getFilenameFromURL(filename);
+ Util::mapAnonymized(filenameOnly, obfuscatedFileId);
+ object->set("Name", LOOLWSD::anonymizeUrl(filename));
// Stringify to log.
std::ostringstream ossResponse;
object->stringify(ossResponse);
commit ad7964393eadb68873b820e0a620fb40f1e1b06a
Author: Ashod Nakashian <ashod.nakashian at collabora.co.uk>
AuthorDate: Mon Jul 16 21:42:17 2018 -0400
Commit: Jan Holesovsky <kendy at collabora.com>
CommitDate: Fri Aug 17 07:54:19 2018 +0200
wsd: flush logs before existing
This is important for when we abort with some explanation.
Often said explanation doesn't show up anywhere to be useful.
Also, issue fatal logs for abnormal exist and use SFL to log errno.
Change-Id: Ic67064ef40ef6e93d26e5847ecd32bdd49c3cc8b
Reviewed-on: https://gerrit.libreoffice.org/57540
Reviewed-by: Jan Holesovsky <kendy at collabora.com>
Tested-by: Jan Holesovsky <kendy at collabora.com>
diff --git a/common/Log.cpp b/common/Log.cpp
index 1d4d36d39..236e4bea6 100644
--- a/common/Log.cpp
+++ b/common/Log.cpp
@@ -16,6 +16,7 @@
#include <cstring>
#include <ctime>
#include <iomanip>
+#include <iostream>
#include <sstream>
#include <string>
@@ -175,6 +176,17 @@ namespace Log
{
return Poco::Logger::get(Source.inited ? Source.name : std::string());
}
+
+ void shutdown()
+ {
+ logger().shutdown();
+
+ // Flush
+ std::flush(std::cout);
+ fflush(stdout);
+ std::flush(std::cerr);
+ fflush(stderr);
+ }
}
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/common/Log.hpp b/common/Log.hpp
index e630c5678..fbafeeadc 100644
--- a/common/Log.hpp
+++ b/common/Log.hpp
@@ -30,13 +30,19 @@ inline std::ostream& operator<< (std::ostream& os, const Poco::Timestamp& ts)
namespace Log
{
+ /// Initialize the logging system.
void initialize(const std::string& name,
const std::string& logLevel,
const bool withColor,
const bool logToFile,
std::map<std::string, std::string> config);
+
+ /// Returns the underlying logging system.
Poco::Logger& logger();
+ /// Shutdown and release the logging system.
+ void shutdown();
+
char* prefix(char* buffer, std::size_t len, const char* level);
inline bool traceEnabled() { return logger().trace(); }
@@ -192,7 +198,6 @@ namespace Log
do \
{ \
LOG << "| " << __FILE__ << ':' << __LINE__; \
- LOG.flush(); \
} while (false)
#define LOG_BODY_(LOG, PRIO, LVL, X) \
diff --git a/common/Seccomp.cpp b/common/Seccomp.cpp
index af7fb0d36..95cd33def 100644
--- a/common/Seccomp.cpp
+++ b/common/Seccomp.cpp
@@ -74,6 +74,7 @@ static void handleSysSignal(int /* signal */,
SigUtil::dumpBacktrace();
+ Log::shutdown();
_exit(1);
}
diff --git a/common/Util.cpp b/common/Util.cpp
index 4b57d429a..788757e1c 100644
--- a/common/Util.cpp
+++ b/common/Util.cpp
@@ -220,6 +220,7 @@ namespace Util
int ret = execvp(params[0], ¶ms[0]);
if (ret < 0)
std::cerr << "Failed to exec command '" << cmd << "' with error '" << strerror(errno) << "'\n";
+ Log::shutdown();
_exit(42);
}
// else spawning process still
diff --git a/kit/ForKit.cpp b/kit/ForKit.cpp
index 2548a1c61..7dcf1da5d 100644
--- a/kit/ForKit.cpp
+++ b/kit/ForKit.cpp
@@ -531,7 +531,11 @@ int main(int argc, char** argv)
// Initialize LoKit
if (!globalPreinit(loTemplate))
+ {
+ LOG_FTL("Failed to preinit lokit.");
+ Log::shutdown();
std::_Exit(Application::EXIT_SOFTWARE);
+ }
LOG_INF("Preinit stage OK.");
@@ -542,6 +546,7 @@ int main(int argc, char** argv)
if (forKitPid < 0)
{
LOG_FTL("Failed to create a kit process.");
+ Log::shutdown();
std::_Exit(Application::EXIT_SOFTWARE);
}
@@ -578,6 +583,7 @@ int main(int argc, char** argv)
#endif
LOG_INF("ForKit process finished.");
+ Log::shutdown();
std::_Exit(returnValue);
}
#endif
diff --git a/kit/Kit.cpp b/kit/Kit.cpp
index 514c0b5d6..171b01449 100644
--- a/kit/Kit.cpp
+++ b/kit/Kit.cpp
@@ -194,8 +194,9 @@ namespace
}
catch (const std::exception& exc)
{
- LOG_ERR("Copying of '" << fpath << "' to " << newPath.toString() <<
+ LOG_FTL("Copying of '" << fpath << "' to " << newPath.toString() <<
" failed: " << exc.what() << ". Exiting.");
+ Log::shutdown();
std::_Exit(Application::EXIT_SOFTWARE);
}
}
@@ -267,7 +268,8 @@ namespace
caps = cap_get_proc();
if (caps == nullptr)
{
- LOG_SYS("cap_get_proc() failed.");
+ LOG_SFL("cap_get_proc() failed.");
+ Log::shutdown();
std::_Exit(1);
}
@@ -278,13 +280,15 @@ namespace
if (cap_set_flag(caps, CAP_EFFECTIVE, sizeof(cap_list)/sizeof(cap_list[0]), cap_list, CAP_CLEAR) == -1 ||
cap_set_flag(caps, CAP_PERMITTED, sizeof(cap_list)/sizeof(cap_list[0]), cap_list, CAP_CLEAR) == -1)
{
- LOG_SYS("cap_set_flag() failed.");
+ LOG_SFL("cap_set_flag() failed.");
+ Log::shutdown();
std::_Exit(1);
}
if (cap_set_proc(caps) == -1)
{
- LOG_SYS("cap_set_proc() failed.");
+ LOG_SFL("cap_set_proc() failed.");
+ Log::shutdown();
std::_Exit(1);
}
@@ -827,7 +831,8 @@ public:
num_sessions = _sessions.size();
if (num_sessions == 0)
{
- LOG_INF("Document [" << anonymizeUrl(_url) << "] has no more views, exiting bluntly.");
+ LOG_FTL("Document [" << anonymizeUrl(_url) << "] has no more views, exiting bluntly.");
+ Log::shutdown();
std::_Exit(Application::EXIT_OK);
}
}
@@ -1307,6 +1312,7 @@ private:
if (_sessions.empty())
{
LOG_INF("Document [" << anonymizeUrl(_url) << "] has no more views, exiting bluntly.");
+ Log::shutdown();
std::_Exit(Application::EXIT_OK);
}
@@ -2207,13 +2213,15 @@ void lokit_main(const std::string& childRoot,
LOG_INF("chroot(\"" << jailPath.toString() << "\")");
if (chroot(jailPath.toString().c_str()) == -1)
{
- LOG_SYS("chroot(\"" << jailPath.toString() << "\") failed.");
+ LOG_SFL("chroot(\"" << jailPath.toString() << "\") failed.");
+ Log::shutdown();
std::_Exit(Application::EXIT_SOFTWARE);
}
if (chdir("/") == -1)
{
- LOG_SYS("chdir(\"/\") in jail failed.");
+ LOG_SFL("chdir(\"/\") in jail failed.");
+ Log::shutdown();
std::_Exit(Application::EXIT_SOFTWARE);
}
@@ -2255,6 +2263,7 @@ void lokit_main(const std::string& childRoot,
if (!loKit)
{
LOG_FTL("LibreOfficeKit initialization failed. Exiting.");
+ Log::shutdown();
std::_Exit(Application::EXIT_SOFTWARE);
}
}
@@ -2264,7 +2273,8 @@ void lokit_main(const std::string& childRoot,
{
if (!noSeccomp)
{
- LOG_ERR("LibreOfficeKit seccomp security lockdown failed. Exiting.");
+ LOG_FTL("LibreOfficeKit seccomp security lockdown failed. Exiting.");
+ Log::shutdown();
std::_Exit(Application::EXIT_SOFTWARE);
}
@@ -2353,6 +2363,7 @@ void lokit_main(const std::string& childRoot,
// Trap the signal handler, if invoked,
// to prevent exiting.
LOG_INF("Process finished.");
+ Log::shutdown();
std::unique_lock<std::mutex> lock(SigHandlerTrap);
std::_Exit(Application::EXIT_OK);
}
diff --git a/wsd/LOOLWSD.cpp b/wsd/LOOLWSD.cpp
index b6df73ebf..e88e5ea9a 100644
--- a/wsd/LOOLWSD.cpp
+++ b/wsd/LOOLWSD.cpp
@@ -803,6 +803,7 @@ void LOOLWSD::initialize(Application& self)
#if ENABLE_DEBUG
std::cerr << "\nIf you have used 'make run', edit loolwsd.xml and make sure you have removed '--o:logging.level=trace' from the command line in Makefile.am.\n" << std::endl;
#endif
+ Log::shutdown();
_exit(Application::EXIT_SOFTWARE);
}
}
@@ -2635,6 +2636,7 @@ private:
{
LOG_FTL("Failed to listen on Prisoner port (" <<
MasterPortNumber << '-' << port << "). Exiting.");
+ Log::shutdown();
_exit(Application::EXIT_SOFTWARE);
}
commit fb2671c4145edd4d4e359f0dcf5cc84835487cd4
Author: Ashod Nakashian <ashod.nakashian at collabora.co.uk>
AuthorDate: Fri Jul 13 00:18:30 2018 -0400
Commit: Jan Holesovsky <kendy at collabora.com>
CommitDate: Fri Aug 17 07:54:19 2018 +0200
wsd: move string utilities into Util
Change-Id: Idc578dff4e8ee5e48c1b7780d3feb2d21c6a9b13
Reviewed-on: https://gerrit.libreoffice.org/57539
Reviewed-by: Jan Holesovsky <kendy at collabora.com>
Tested-by: Jan Holesovsky <kendy at collabora.com>
diff --git a/common/Protocol.hpp b/common/Protocol.hpp
index 1e2158a91..fd39423bc 100644
--- a/common/Protocol.hpp
+++ b/common/Protocol.hpp
@@ -21,6 +21,8 @@
#include <Poco/Net/WebSocket.h>
+#include <Util.hpp>
+
#define LOK_USE_UNSTABLE_API
#include <LibreOfficeKit/LibreOfficeKitEnums.h>
@@ -144,45 +146,11 @@ namespace LOOLProtocol
return getTokenInteger(tokenize(message), name, value);
}
- inline size_t getDelimiterPosition(const char* message, const int length, const char delim)
- {
- if (message && length > 0)
- {
- const char *founddelim = static_cast<const char *>(std::memchr(message, delim, length));
- const auto size = (founddelim == nullptr ? length : founddelim - message);
- return size;
- }
-
- return 0;
- }
-
- inline
- std::string getDelimitedInitialSubstring(const char *message, const int length, const char delim)
- {
- const auto size = getDelimiterPosition(message, length, delim);
- return std::string(message, size);
- }
-
- /// Split a string in two at the delimeter, removing it.
- inline
- std::pair<std::string, std::string> split(const char* s, const int length, const char delimeter = ' ')
- {
- const auto size = getDelimiterPosition(s, length, delimeter);
- return std::make_pair(std::string(s, size), std::string(s+size+1));
- }
-
- /// Split a string in two at the delimeter, removing it.
- inline
- std::pair<std::string, std::string> split(const std::string& s, const char delimeter = ' ')
- {
- return split(s.c_str(), s.size(), delimeter);
- }
-
/// Returns the first token of a message.
inline
std::string getFirstToken(const char *message, const int length, const char delim = ' ')
{
- return getDelimitedInitialSubstring(message, length, delim);
+ return Util::getDelimitedInitialSubstring(message, length, delim);
}
template <typename T>
@@ -246,7 +214,7 @@ namespace LOOLProtocol
inline
std::string getFirstLine(const char *message, const int length)
{
- return getDelimitedInitialSubstring(message, length, '\n');
+ return Util::getDelimitedInitialSubstring(message, length, '\n');
}
/// Returns the first line of any data which payload char*.
@@ -282,7 +250,7 @@ namespace LOOLProtocol
inline std::string getAbbreviatedMessage(const std::string& message)
{
- const auto pos = getDelimiterPosition(message.data(), std::min(message.size(), 500UL), '\n');
+ const auto pos = Util::getDelimiterPosition(message.data(), std::min(message.size(), 501UL), '\n');
// If first line is less than the length (minus newline), add ellipsis.
if (pos < static_cast<std::string::size_type>(message.size()) - 1)
diff --git a/common/Util.hpp b/common/Util.hpp
index cca318e20..253776330 100644
--- a/common/Util.hpp
+++ b/common/Util.hpp
@@ -310,6 +310,40 @@ namespace Util
return false;
}
+ inline size_t getDelimiterPosition(const char* message, const int length, const char delim)
+ {
+ if (message && length > 0)
+ {
+ const char *founddelim = static_cast<const char *>(std::memchr(message, delim, length));
+ const auto size = (founddelim == nullptr ? length : founddelim - message);
+ return size;
+ }
+
+ return 0;
+ }
+
+ inline
+ std::string getDelimitedInitialSubstring(const char *message, const int length, const char delim)
+ {
+ const auto size = getDelimiterPosition(message, length, delim);
+ return std::string(message, size);
+ }
+
+ /// Split a string in two at the delimeter, removing it.
+ inline
+ std::pair<std::string, std::string> split(const char* s, const int length, const char delimeter = ' ')
+ {
+ const auto size = getDelimiterPosition(s, length, delimeter);
+ return std::make_pair(std::string(s, size), std::string(s+size+1));
+ }
+
+ /// Split a string in two at the delimeter, removing it.
+ inline
+ std::pair<std::string, std::string> split(const std::string& s, const char delimeter = ' ')
+ {
+ return split(s.c_str(), s.size(), delimeter);
+ }
+
/// Check for the URI scheme validity.
/// For now just a basic sanity check, can be extended if necessary.
bool isValidURIScheme(const std::string& scheme);
diff --git a/kit/ForKit.cpp b/kit/ForKit.cpp
index d77c01c30..2548a1c61 100644
--- a/kit/ForKit.cpp
+++ b/kit/ForKit.cpp
@@ -453,7 +453,7 @@ int main(int argc, char** argv)
std::vector<std::string> tokens = LOOLProtocol::tokenize(rlimits, ';');
for (const std::string& cmdLimit : tokens)
{
- const auto pair = LOOLProtocol::split(cmdLimit, ':');
+ const auto pair = Util::split(cmdLimit, ':');
std::vector<std::string> tokensLimit = { "setconfig", pair.first, pair.second };
if (!Rlimit::handleSetrlimitCommand(tokensLimit))
{
diff --git a/test/WhiteBoxTests.cpp b/test/WhiteBoxTests.cpp
index b5ae27663..3250b17ad 100644
--- a/test/WhiteBoxTests.cpp
+++ b/test/WhiteBoxTests.cpp
@@ -144,11 +144,11 @@ void WhiteBoxTests::testLOOLProtocolFunctions()
void WhiteBoxTests::testMessageAbbreviation()
{
- CPPUNIT_ASSERT_EQUAL(std::string(), LOOLProtocol::getDelimitedInitialSubstring(nullptr, 5, '\n'));
- CPPUNIT_ASSERT_EQUAL(std::string(), LOOLProtocol::getDelimitedInitialSubstring(nullptr, -1, '\n'));
- CPPUNIT_ASSERT_EQUAL(std::string(), LOOLProtocol::getDelimitedInitialSubstring("abc", 0, '\n'));
- CPPUNIT_ASSERT_EQUAL(std::string(), LOOLProtocol::getDelimitedInitialSubstring("abc", -1, '\n'));
- CPPUNIT_ASSERT_EQUAL(std::string("ab"), LOOLProtocol::getDelimitedInitialSubstring("abc", 2, '\n'));
+ CPPUNIT_ASSERT_EQUAL(std::string(), Util::getDelimitedInitialSubstring(nullptr, 5, '\n'));
+ CPPUNIT_ASSERT_EQUAL(std::string(), Util::getDelimitedInitialSubstring(nullptr, -1, '\n'));
+ CPPUNIT_ASSERT_EQUAL(std::string(), Util::getDelimitedInitialSubstring("abc", 0, '\n'));
+ CPPUNIT_ASSERT_EQUAL(std::string(), Util::getDelimitedInitialSubstring("abc", -1, '\n'));
+ CPPUNIT_ASSERT_EQUAL(std::string("ab"), Util::getDelimitedInitialSubstring("abc", 2, '\n'));
CPPUNIT_ASSERT_EQUAL(std::string(), LOOLProtocol::getAbbreviatedMessage(nullptr, 5));
CPPUNIT_ASSERT_EQUAL(std::string(), LOOLProtocol::getAbbreviatedMessage(nullptr, -1));
diff --git a/wsd/ClientSession.cpp b/wsd/ClientSession.cpp
index d690c5905..f5573c06c 100644
--- a/wsd/ClientSession.cpp
+++ b/wsd/ClientSession.cpp
@@ -855,7 +855,7 @@ bool ClientSession::handleKitToClientMessage(const char* buffer, const int lengt
else
{
// Set the initial settings per the user's request.
- const std::pair<std::string, std::string> unoStatePair = LOOLProtocol::split(tokens[1], '=');
+ const std::pair<std::string, std::string> unoStatePair = Util::split(tokens[1], '=');
if (!docBroker->isInitialSettingSet(unoStatePair.first))
{
commit e17f6b9e7aabf66db43874a7852fa5d23a0b9100
Author: Ashod Nakashian <ashod.nakashian at collabora.co.uk>
AuthorDate: Thu Jul 19 01:27:46 2018 -0400
Commit: Jan Holesovsky <kendy at collabora.com>
CommitDate: Fri Aug 17 07:54:19 2018 +0200
leaflet: update IE11 connection limit message
Change-Id: I7299867873fb00cf2a500f17a559106f52c8ba6f
Reviewed-on: https://gerrit.libreoffice.org/57709
Reviewed-by: Jan Holesovsky <kendy at collabora.com>
Tested-by: Jan Holesovsky <kendy at collabora.com>
diff --git a/loleaflet/src/core/Socket.js b/loleaflet/src/core/Socket.js
index f24599774..c394402b4 100644
--- a/loleaflet/src/core/Socket.js
+++ b/loleaflet/src/core/Socket.js
@@ -39,9 +39,14 @@ L.Socket = L.Class.extend({
}
this.socket = new WebSocket(websocketURI);
} catch (e) {
- this._map.fire('error', {msg: _('Oops, there is a problem connecting to LibreOffice Online : ').replace('LibreOffice Online', (typeof brandProductName !== 'undefined' ? brandProductName : 'LibreOffice Online')) + _('Cannot create websocket, please restart your browser.'), cmd: 'socket', kind: 'failed', id: 3});
- console.log('Failed to create websocket: ' + websocketURI);
- console.log('Due to an exception: ' + e);
+ // On IE 11 there is a limiation on the number of WebSockets open to a single domain (6 by default and can go to 128).
+ // Detect this and hint the user.
+ var msgHint = '';
+ var isIE11 = !!window.MSInputMethodContext && !!document.documentMode; // https://stackoverflow.com/questions/21825157/internet-explorer-11-detection
+ if (isIE11)
+ msgHint = 'IE11 has limitation on the maximum number of WebSockets open to a single domain. Please consult this page on how to change this limit: https://docs.microsoft.com/en-us/previous-versions/windows/internet-explorer/ie-developer/general-info/ee330736(v=vs.85)#websocket-maximum-server-connections';
+
+ this._map.fire('error', {msg: _('Oops, there is a problem connecting to LibreOffice Online : ').replace('LibreOffice Online', (typeof brandProductName !== 'undefined' ? brandProductName : 'LibreOffice Online')) + e + msgHint, cmd: 'socket', kind: 'failed', id: 3});
return;
}
commit 84245aa61e89cda6a9075a7059b5a7d839389719
Author: Ashod Nakashian <ashod.nakashian at collabora.co.uk>
AuthorDate: Thu Jul 12 18:00:33 2018 -0400
Commit: Jan Holesovsky <kendy at collabora.com>
CommitDate: Fri Aug 17 07:54:19 2018 +0200
wsd: prevent anonymization to empty strings
Change-Id: Ib4f90db5d39e7bf2e2f0b6566b1927363e6afcec
Reviewed-on: https://gerrit.libreoffice.org/57377
Reviewed-by: Jan Holesovsky <kendy at collabora.com>
Tested-by: Jan Holesovsky <kendy at collabora.com>
diff --git a/common/Util.cpp b/common/Util.cpp
index b481d9e88..4b57d429a 100644
--- a/common/Util.cpp
+++ b/common/Util.cpp
@@ -549,6 +549,9 @@ namespace Util
void mapAnonymized(const std::string& plain, const std::string& anonymized)
{
+ if (plain.empty() || anonymized.empty())
+ return;
+
LOG_TRC("Anonymizing [" << plain << "] -> [" << anonymized << "].");
std::unique_lock<std::mutex> lock(AnonymizedMutex);
@@ -563,7 +566,10 @@ namespace Util
const auto it = AnonymizedStrings.find(text);
if (it != AnonymizedStrings.end())
+ {
+ LOG_TRC("Found anonymized [" << text << "] -> [" << it->second << "].");
return it->second;
+ }
}
// We just need something irreversible, short, and
diff --git a/wsd/ClientSession.cpp b/wsd/ClientSession.cpp
index 6f3e262b0..d690c5905 100644
--- a/wsd/ClientSession.cpp
+++ b/wsd/ClientSession.cpp
@@ -402,12 +402,12 @@ bool ClientSession::loadDocument(const char* /*buffer*/, int /*length*/,
std::string encodedUserId;
Poco::URI::encode(_userId, "", encodedUserId);
oss << " authorid=" << encodedUserId;
- oss << " xauthorid=" << LOOLWSD::anonymizeUsername(encodedUserId);
+ oss << " xauthorid=" << LOOLWSD::anonymizeUsername(_userId);
std::string encodedUserName;
Poco::URI::encode(_userName, "", encodedUserName);
oss << " author=" << encodedUserName;
- oss << " xauthor=" << LOOLWSD::anonymizeUsername(encodedUserName);
+ oss << " xauthor=" << LOOLWSD::anonymizeUsername(_userName);
}
if (!_userExtraInfo.empty())
commit 5e3568ff1029da948f05d1c0e0c56c6d0706690e
Author: Ashod Nakashian <ashod.nakashian at collabora.co.uk>
AuthorDate: Tue Jul 10 23:09:27 2018 -0400
Commit: Jan Holesovsky <kendy at collabora.com>
CommitDate: Fri Aug 17 07:54:19 2018 +0200
wsd: anonymize filename by using the WOPI file ID
Change-Id: I869cae3846c8630b192246bc68cc90e70c50d1fd
Reviewed-on: https://gerrit.libreoffice.org/57254
Reviewed-by: Jan Holesovsky <kendy at collabora.com>
Tested-by: Jan Holesovsky <kendy at collabora.com>
diff --git a/common/Session.cpp b/common/Session.cpp
index dc538ca89..7e174e2e3 100644
--- a/common/Session.cpp
+++ b/common/Session.cpp
@@ -163,6 +163,10 @@ void Session::parseDocOptions(const std::vector<std::string>& tokens, int& part,
}
}
+ Util::mapAnonymized(_userId, _userIdAnonym);
+ Util::mapAnonymized(_userName, _userNameAnonym);
+ Util::mapAnonymized(_jailedFilePath, _jailedFilePathAnonym);
+
if (tokens.size() > offset)
{
if (getTokenString(tokens[offset], "options", _docOptions))
diff --git a/common/Util.cpp b/common/Util.cpp
index 30fbc20fe..b481d9e88 100644
--- a/common/Util.cpp
+++ b/common/Util.cpp
@@ -545,12 +545,26 @@ namespace Util
static std::map<std::string, std::string> AnonymizedStrings;
static std::atomic<unsigned> AnonymizationSalt(0);
+ static std::mutex AnonymizedMutex;
+
+ void mapAnonymized(const std::string& plain, const std::string& anonymized)
+ {
+ LOG_TRC("Anonymizing [" << plain << "] -> [" << anonymized << "].");
+
+ std::unique_lock<std::mutex> lock(AnonymizedMutex);
+
+ AnonymizedStrings[plain] = anonymized;
+ }
std::string anonymize(const std::string& text)
{
- const auto it = AnonymizedStrings.find(text);
- if (it != AnonymizedStrings.end())
- return it->second;
+ {
+ std::unique_lock<std::mutex> lock(AnonymizedMutex);
+
+ const auto it = AnonymizedStrings.find(text);
+ if (it != AnonymizedStrings.end())
+ return it->second;
+ }
// We just need something irreversible, short, and
// quite simple.
@@ -561,7 +575,7 @@ namespace Util
// Generate the anonymized string. The '#' is to hint that it's anonymized.
// Prepend with salt to make it unique, in case we get collisions (which we will, eventually).
const std::string res = '#' + Util::encodeId(AnonymizationSalt++, 0) + '#' + Util::encodeId(hash, 0) + '#';
- AnonymizedStrings[text] = res;
+ mapAnonymized(text, res);
return res;
}
@@ -582,6 +596,16 @@ namespace Util
return Util::anonymize(basename) + ext;
}
+ std::string getFilenameFromPath(const std::string& path)
+ {
+ const std::size_t mid = path.find_last_of('/');
+ if (mid != std::string::npos)
+ return path.substr(mid + 1);
+
+ // No path, treat as filename only.
+ return path;
+ }
+
std::string anonymizeUrl(const std::string& url)
{
const std::size_t mid = url.find_last_of('/');
diff --git a/common/Util.hpp b/common/Util.hpp
index 2e919e1b9..cca318e20 100644
--- a/common/Util.hpp
+++ b/common/Util.hpp
@@ -322,9 +322,16 @@ namespace Util
/// Called on strings to be logged or exposed.
std::string anonymize(const std::string& text);
+ /// 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);
+
/// Anonymize the basename of filenames only, preserving the path and extension.
std::string anonymizeUrl(const std::string& url);
+ /// Extract and return the filename given a path (i.e. the token after last '/').
+ std::string getFilenameFromPath(const std::string& path);
+
/// Given one or more patterns to allow, and one or more to deny,
/// the match member will return true if, and only if, the subject
/// matches the allowed list, but not the deny.
diff --git a/kit/Kit.cpp b/kit/Kit.cpp
index 3213f61a7..514c0b5d6 100644
--- a/kit/Kit.cpp
+++ b/kit/Kit.cpp
@@ -108,6 +108,7 @@ static LokHookFunction2* initFunction = nullptr;
#ifndef BUILDING_TESTS
static bool AnonymizeFilenames = false;
static bool AnonymizeUsernames = false;
+static std::string ObfuscatedFileId;
static std::string ObfuscatedUserId;
#endif
@@ -1998,6 +1999,8 @@ protected:
const std::string& sessionId = tokens[1];
const std::string& docKey = tokens[2];
const std::string& docId = tokens[3];
+ const std::string fileId = Util::getFilenameFromPath(docKey);
+ Util::mapAnonymized(fileId, fileId); // Identity mapping, since fileId is already obfuscated
std::string url;
URI::decode(docKey, url);
diff --git a/wsd/DocumentBroker.cpp b/wsd/DocumentBroker.cpp
index ebd89fd54..0c2db18e6 100644
--- a/wsd/DocumentBroker.cpp
+++ b/wsd/DocumentBroker.cpp
@@ -468,7 +468,6 @@ bool DocumentBroker::load(const std::shared_ptr<ClientSession>& session, const s
{
std::unique_ptr<WopiStorage::WOPIFileInfo> wopifileinfo = wopiStorage->getWOPIFileInfo(session->getAuthorization());
userId = wopifileinfo->_userId;
- LOOLWSD::ObfuscatedUserId = wopifileinfo->_obfuscatedUserId;
username = wopifileinfo->_username;
userExtraInfo = wopifileinfo->_userExtraInfo;
watermarkText = wopifileinfo->_watermarkText;
@@ -1054,7 +1053,7 @@ size_t DocumentBroker::addSessionInternal(const std::shared_ptr<ClientSession>&
const auto id = session->getId();
// Request a new session from the child kit.
- const std::string aMessage = "session " + id + ' ' + _docKey + ' ' + _docId + ' ' + LOOLWSD::ObfuscatedUserId;
+ const std::string aMessage = "session " + id + ' ' + _docKey + ' ' + _docId;
_childProcess->sendTextFrame(aMessage);
// Tell the admin console about this new doc
@@ -1762,7 +1761,7 @@ void DocumentBroker::dumpState(std::ostream& os)
uint64_t sent, recv;
getIOStats(sent, recv);
- os << " Broker: " << _filename << " pid: " << getPid();
+ os << " Broker: " << LOOLWSD::anonymizeUrl(_filename) << " pid: " << getPid();
if (_markToDestroy)
os << " *** Marked to destroy ***";
else
@@ -1775,9 +1774,9 @@ void DocumentBroker::dumpState(std::ostream& os)
os << "\n recv: " << recv;
os << "\n modified?: " << _isModified;
os << "\n jail id: " << _jailId;
- os << "\n filename: " << _filename;
+ os << "\n filename: " << LOOLWSD::anonymizeUrl(_filename);
os << "\n public uri: " << _uriPublic.toString();
- os << "\n jailed uri: " << _uriJailed;
+ os << "\n jailed uri: " << LOOLWSD::anonymizeUrl(_uriJailed);
os << "\n doc key: " << _docKey;
os << "\n doc id: " << _docId;
os << "\n num sessions: " << _sessions.size();
diff --git a/wsd/LOOLWSD.cpp b/wsd/LOOLWSD.cpp
index fa12da514..b6df73ebf 100644
--- a/wsd/LOOLWSD.cpp
+++ b/wsd/LOOLWSD.cpp
@@ -603,7 +603,6 @@ std::string LOOLWSD::ConfigDir = LOOLWSD_CONFIGDIR "/conf.d";
std::string LOOLWSD::LogLevel = "trace";
bool LOOLWSD::AnonymizeFilenames = false;
bool LOOLWSD::AnonymizeUsernames = false;
-std::string LOOLWSD::ObfuscatedUserId;
Util::RuntimeConstant<bool> LOOLWSD::SSLEnabled;
Util::RuntimeConstant<bool> LOOLWSD::SSLTermination;
std::set<std::string> LOOLWSD::EditFileExtensions;
@@ -2290,6 +2289,8 @@ private:
const auto uriPublic = DocumentBroker::sanitizeURI(url);
const auto docKey = DocumentBroker::getDocKey(uriPublic);
+ const std::string fileId = Util::getFilenameFromPath(docKey);
+ Util::mapAnonymized(fileId, fileId); // Identity mapping, since fileId is already obfuscated
LOG_INF("Sanitized URI [" << LOOLWSD::anonymizeUrl(url) << "] to [" << LOOLWSD::anonymizeUrl(uriPublic.toString()) <<
"] and mapped to docKey [" << docKey << "] for session [" << _id << "].");
diff --git a/wsd/LOOLWSD.hpp b/wsd/LOOLWSD.hpp
index d3c026375..536f8d051 100644
--- a/wsd/LOOLWSD.hpp
+++ b/wsd/LOOLWSD.hpp
@@ -61,7 +61,6 @@ public:
static std::string LogLevel;
static bool AnonymizeFilenames;
static bool AnonymizeUsernames;
- static std::string ObfuscatedUserId;
static std::atomic<unsigned> NumConnections;
static bool TileCachePersistent;
static std::unique_ptr<TraceFileWriter> TraceDumper;
@@ -155,10 +154,7 @@ public:
/// Will use the Obfuscated User ID if one is provied via WOPI.
static std::string anonymizeUsername(const std::string& username)
{
- if (AnonymizeUsernames)
- return !ObfuscatedUserId.empty() ? ObfuscatedUserId : Util::anonymize(username);
-
- return username;
+ return AnonymizeUsernames ? Util::anonymize(username) : username;
}
protected:
diff --git a/wsd/Storage.cpp b/wsd/Storage.cpp
index f26f04c4e..2004b5467 100644
--- a/wsd/Storage.cpp
+++ b/wsd/Storage.cpp
@@ -474,7 +474,15 @@ std::unique_ptr<WopiStorage::WOPIFileInfo> WopiStorage::getWOPIFileInfo(const Au
// Anonymize key values.
if (LOOLWSD::AnonymizeFilenames || LOOLWSD::AnonymizeUsernames)
{
+ Util::mapAnonymized(filename, Util::getFilenameFromPath(_uri.toString()));
+
JsonUtil::findJSONValue(object, "ObfuscatedUserId", obfuscatedUserId, false);
+ if (!obfuscatedUserId.empty())
+ {
+ Util::mapAnonymized(ownerId, obfuscatedUserId);
+ Util::mapAnonymized(userId, obfuscatedUserId);
+ Util::mapAnonymized(userName, obfuscatedUserId);
+ }
// Set anonymized version of the above fields before logging.
// Note: anonymization caches the result, so we don't need to store here.
commit 62dadb8aaa5cf9ba8cbbe0bc7f84dfc1076104c1
Author: Ashod Nakashian <ashod.nakashian at collabora.co.uk>
AuthorDate: Sun Jul 8 22:50:09 2018 -0400
Commit: Jan Holesovsky <kendy at collabora.com>
CommitDate: Fri Aug 17 07:54:19 2018 +0200
wsd: use obfascated user id when provided by WOPI
Change-Id: I69a17dff0e5e6b27e4538d9fe9019e4d1eebb16f
Reviewed-on: https://gerrit.libreoffice.org/57171
Reviewed-by: Jan Holesovsky <kendy at collabora.com>
Tested-by: Jan Holesovsky <kendy at collabora.com>
diff --git a/kit/Kit.cpp b/kit/Kit.cpp
index 0b1c92adc..3213f61a7 100644
--- a/kit/Kit.cpp
+++ b/kit/Kit.cpp
@@ -108,6 +108,7 @@ static LokHookFunction2* initFunction = nullptr;
#ifndef BUILDING_TESTS
static bool AnonymizeFilenames = false;
static bool AnonymizeUsernames = false;
+static std::string ObfuscatedUserId;
#endif
#if ENABLE_DEBUG
diff --git a/wsd/DocumentBroker.cpp b/wsd/DocumentBroker.cpp
index 36debc7df..ebd89fd54 100644
--- a/wsd/DocumentBroker.cpp
+++ b/wsd/DocumentBroker.cpp
@@ -459,7 +459,7 @@ bool DocumentBroker::load(const std::shared_ptr<ClientSession>& session, const s
assert(_storage != nullptr);
// Call the storage specific fileinfo functions
- std::string userid, username;
+ std::string userId, username;
std::string userExtraInfo;
std::string watermarkText;
std::chrono::duration<double> getInfoCallDuration(0);
@@ -467,7 +467,8 @@ bool DocumentBroker::load(const std::shared_ptr<ClientSession>& session, const s
if (wopiStorage != nullptr)
{
std::unique_ptr<WopiStorage::WOPIFileInfo> wopifileinfo = wopiStorage->getWOPIFileInfo(session->getAuthorization());
- userid = wopifileinfo->_userid;
+ userId = wopifileinfo->_userId;
+ LOOLWSD::ObfuscatedUserId = wopifileinfo->_obfuscatedUserId;
username = wopifileinfo->_username;
userExtraInfo = wopifileinfo->_userExtraInfo;
watermarkText = wopifileinfo->_watermarkText;
@@ -520,7 +521,7 @@ bool DocumentBroker::load(const std::shared_ptr<ClientSession>& session, const s
session->sendMessage("wopi: " + ossWopiInfo.str());
// Mark the session as 'Document owner' if WOPI hosts supports it
- if (userid == _storage->getFileInfo()._ownerId)
+ if (userId == _storage->getFileInfo()._ownerId)
{
LOG_DBG("Session [" << sessionId << "] is the document owner");
session->setDocumentOwner(true);
@@ -537,7 +538,7 @@ bool DocumentBroker::load(const std::shared_ptr<ClientSession>& session, const s
if (localStorage != nullptr)
{
std::unique_ptr<LocalStorage::LocalFileInfo> localfileinfo = localStorage->getLocalFileInfo();
- userid = localfileinfo->_userid;
+ userId = localfileinfo->_userId;
username = localfileinfo->_username;
if (LOOLWSD::IsViewFileExtension(localStorage->getFileExtension()))
@@ -548,14 +549,16 @@ bool DocumentBroker::load(const std::shared_ptr<ClientSession>& session, const s
}
}
+
#if ENABLE_SUPPORT_KEY
if (!LOOLWSD::OverrideWatermark.empty())
watermarkText = LOOLWSD::OverrideWatermark;
#endif
LOG_DBG("Setting username [" << LOOLWSD::anonymizeUsername(username) << "] and userId [" <<
- LOOLWSD::anonymizeUsername(userid) << "] for session [" << sessionId << "]");
- session->setUserId(userid);
+ LOOLWSD::anonymizeUsername(userId) << "] for session [" << sessionId << "]");
+
+ session->setUserId(userId);
session->setUserName(username);
session->setUserExtraInfo(userExtraInfo);
session->setWatermarkText(watermarkText);
@@ -1051,7 +1054,7 @@ size_t DocumentBroker::addSessionInternal(const std::shared_ptr<ClientSession>&
const auto id = session->getId();
// Request a new session from the child kit.
- const std::string aMessage = "session " + id + ' ' + _docKey + ' ' + _docId;
+ const std::string aMessage = "session " + id + ' ' + _docKey + ' ' + _docId + ' ' + LOOLWSD::ObfuscatedUserId;
_childProcess->sendTextFrame(aMessage);
// Tell the admin console about this new doc
diff --git a/wsd/LOOLWSD.cpp b/wsd/LOOLWSD.cpp
index cb92ae278..fa12da514 100644
--- a/wsd/LOOLWSD.cpp
+++ b/wsd/LOOLWSD.cpp
@@ -603,6 +603,7 @@ std::string LOOLWSD::ConfigDir = LOOLWSD_CONFIGDIR "/conf.d";
std::string LOOLWSD::LogLevel = "trace";
bool LOOLWSD::AnonymizeFilenames = false;
bool LOOLWSD::AnonymizeUsernames = false;
+std::string LOOLWSD::ObfuscatedUserId;
Util::RuntimeConstant<bool> LOOLWSD::SSLEnabled;
Util::RuntimeConstant<bool> LOOLWSD::SSLTermination;
std::set<std::string> LOOLWSD::EditFileExtensions;
@@ -781,14 +782,16 @@ void LOOLWSD::initialize(Application& self)
#else
AnonymizeUsernames = getConfigValue<bool>(conf, "logging.anonymize.usernames", false);
#endif
- setenv("LOOL_ANONYMIZE_USERNAMES", AnonymizeUsernames ? "1" : "0", true);
+ if (AnonymizeUsernames)
+ setenv("LOOL_ANONYMIZE_USERNAMES", AnonymizeUsernames ? "1" : "0", true);
#if LOOLWSD_ANONYMIZE_FILENAMES
AnonymizeFilenames = true;
#else
AnonymizeFilenames = getConfigValue<bool>(conf, "logging.anonymize.filenames", false);
#endif
- setenv("LOOL_ANONYMIZE_FILENAMES", AnonymizeFilenames ? "1" : "0", true);
+ if (AnonymizeFilenames)
+ setenv("LOOL_ANONYMIZE_FILENAMES", AnonymizeFilenames ? "1" : "0", true);
if (AnonymizeFilenames || AnonymizeUsernames)
{
diff --git a/wsd/LOOLWSD.hpp b/wsd/LOOLWSD.hpp
index 85dd87a10..d3c026375 100644
--- a/wsd/LOOLWSD.hpp
+++ b/wsd/LOOLWSD.hpp
@@ -61,6 +61,7 @@ public:
static std::string LogLevel;
static bool AnonymizeFilenames;
static bool AnonymizeUsernames;
+ static std::string ObfuscatedUserId;
static std::atomic<unsigned> NumConnections;
static bool TileCachePersistent;
static std::unique_ptr<TraceFileWriter> TraceDumper;
@@ -150,10 +151,14 @@ public:
return AnonymizeFilenames ? Util::anonymizeUrl(url) : url;
}
- /// Anonymize usernames.
+ /// Anonymize user names and IDs.
+ /// Will use the Obfuscated User ID if one is provied via WOPI.
static std::string anonymizeUsername(const std::string& username)
{
- return AnonymizeUsernames ? Util::anonymize(username) : username;
+ if (AnonymizeUsernames)
+ return !ObfuscatedUserId.empty() ? ObfuscatedUserId : Util::anonymize(username);
+
+ return username;
}
protected:
diff --git a/wsd/Storage.cpp b/wsd/Storage.cpp
index ca4cfa64a..f26f04c4e 100644
--- a/wsd/Storage.cpp
+++ b/wsd/Storage.cpp
@@ -409,7 +409,6 @@ std::unique_ptr<WopiStorage::WOPIFileInfo> WopiStorage::getWOPIFileInfo(const Au
Poco::Net::HTTPResponse response;
std::istream& rs = psession->receiveResponse(response);
-
callDuration = (std::chrono::steady_clock::now() - startTime);
auto logger = Log::trace();
@@ -445,6 +444,7 @@ std::unique_ptr<WopiStorage::WOPIFileInfo> WopiStorage::getWOPIFileInfo(const Au
std::string ownerId;
std::string userId;
std::string userName;
+ std::string obfuscatedUserId;
std::string userExtraInfo;
std::string watermarkText;
bool canWrite = false;
@@ -474,12 +474,15 @@ std::unique_ptr<WopiStorage::WOPIFileInfo> WopiStorage::getWOPIFileInfo(const Au
// Anonymize key values.
if (LOOLWSD::AnonymizeFilenames || LOOLWSD::AnonymizeUsernames)
{
+ JsonUtil::findJSONValue(object, "ObfuscatedUserId", obfuscatedUserId, false);
+
// Set anonymized version of the above fields before logging.
// Note: anonymization caches the result, so we don't need to store here.
if (LOOLWSD::AnonymizeFilenames)
object->set("BaseFileName", LOOLWSD::anonymizeUrl(filename));
- if (LOOLWSD::AnonymizeUsernames)
+ // If obfuscatedUserId is provided, then don't log the originals and use it.
+ if (LOOLWSD::AnonymizeUsernames && obfuscatedUserId.empty())
{
object->set("OwnerId", LOOLWSD::anonymizeUsername(ownerId));
object->set("UserId", LOOLWSD::anonymizeUsername(userId));
@@ -491,6 +494,8 @@ std::unique_ptr<WopiStorage::WOPIFileInfo> WopiStorage::getWOPIFileInfo(const Au
wopiResponse = oss.str();
// Remove them for performance reasons; they aren't needed anymore.
+ object->remove("ObfuscatedUserId");
+
if (LOOLWSD::AnonymizeFilenames)
object->remove("BaseFileName");
@@ -542,7 +547,7 @@ std::unique_ptr<WopiStorage::WOPIFileInfo> WopiStorage::getWOPIFileInfo(const Au
_fileInfo = FileInfo({filename, ownerId, modifiedTime, size});
return std::unique_ptr<WopiStorage::WOPIFileInfo>(new WOPIFileInfo(
- {userId, userName, userExtraInfo, watermarkText, canWrite,
+ {userId, obfuscatedUserId, userName, userExtraInfo, watermarkText, canWrite,
postMessageOrigin, hidePrintOption, hideSaveOption, hideExportOption,
enableOwnerTermination, disablePrint, disableExport, disableCopy,
disableInactiveMessages, userCanNotWriteRelative,
@@ -612,7 +617,7 @@ std::string WopiStorage::loadStorageFileToLocal(const Authorization& auth)
return Poco::Path(_jailPath, _fileInfo._filename).toString();
}
}
- catch(const Poco::Exception& pexc)
+ catch (const Poco::Exception& pexc)
{
LOG_ERR("Cannot load document from WOPI storage uri [" + uriAnonym + "]. Error: " <<
pexc.displayText() << (pexc.nested() ? " (" + pexc.nested()->displayText() + ")" : ""));
@@ -796,7 +801,7 @@ StorageBase::SaveResult WopiStorage::saveLocalFileToStorage(const Authorization&
}
}
}
- catch(const Poco::Exception& pexc)
+ catch (const Poco::Exception& pexc)
{
LOG_ERR("Cannot save file to WOPI storage uri [" << uriAnonym << "]. Error: " <<
pexc.displayText() << (pexc.nested() ? " (" + pexc.nested()->displayText() + ")" : ""));
diff --git a/wsd/Storage.hpp b/wsd/Storage.hpp
index c23ed7352..1e9544c2e 100644
--- a/wsd/Storage.hpp
+++ b/wsd/Storage.hpp
@@ -218,14 +218,14 @@ public:
class LocalFileInfo
{
public:
- LocalFileInfo(const std::string& userid,
+ LocalFileInfo(const std::string& userId,
const std::string& username)
- : _userid(userid),
+ : _userId(userId),
_username(username)
{
}
- std::string _userid;
+ std::string _userId;
std::string _username;
};
@@ -269,6 +269,7 @@ public:
};
WOPIFileInfo(const std::string& userid,
+ const std::string& obfuscatedUserId,
const std::string& username,
const std::string& userExtraInfo,
const std::string& watermarkText,
@@ -287,7 +288,8 @@ public:
const TriState disableChangeTrackingRecord,
const TriState hideChangeTrackingControls,
const std::chrono::duration<double> callDuration)
- : _userid(userid),
+ : _userId(userid),
+ _obfuscatedUserId(obfuscatedUserId),
_username(username),
_watermarkText(watermarkText),
_userCanWrite(userCanWrite),
@@ -310,7 +312,9 @@ public:
}
/// User id of the user accessing the file
- std::string _userid;
+ std::string _userId;
+ /// Obfuscated User id used for logging the UserId.
+ std::string _obfuscatedUserId;
/// Display Name of user accessing the file
std::string _username;
/// Extra info per user, typically mail and other links, as json.
commit 829b4722817b89445701a378ffa6b597b906bb7d
Author: Ashod Nakashian <ashod.nakashian at collabora.co.uk>
AuthorDate: Thu Jun 28 00:47:20 2018 -0400
Commit: Jan Holesovsky <kendy at collabora.com>
CommitDate: Fri Aug 17 07:54:19 2018 +0200
wsd: allow tracing with anonymization
Useful for troubleshooting and other non-prod setups.
To enable, add a subnode under logging/anonymize in
loolwsd.xml called allow_logging_pii with a boolean
value of true:
<logging>
<anonymize>
<allow_logging_pii>true</allow_logging_pii>
</anonymize>
</logging>
Change-Id: If74acaac0ea442ee5a7860453182180663a5108b
Reviewed-on: https://gerrit.libreoffice.org/56568
Reviewed-by: Jan Holesovsky <kendy at collabora.com>
Tested-by: Jan Holesovsky <kendy at collabora.com>
diff --git a/common/Log.hpp b/common/Log.hpp
index 152fea1b4..e630c5678 100644
--- a/common/Log.hpp
+++ b/common/Log.hpp
@@ -10,6 +10,8 @@
#ifndef INCLUDED_LOG_HPP
#define INCLUDED_LOG_HPP
+#include "config.h"
+
#include <functional>
#include <sstream>
#include <string>
diff --git a/wsd/LOOLWSD.cpp b/wsd/LOOLWSD.cpp
index 734ec53e6..cb92ae278 100644
--- a/wsd/LOOLWSD.cpp
+++ b/wsd/LOOLWSD.cpp
@@ -792,7 +792,7 @@ void LOOLWSD::initialize(Application& self)
if (AnonymizeFilenames || AnonymizeUsernames)
{
- if (LogLevel == "trace")
+ if (LogLevel == "trace" && !getConfigValue<bool>(conf, "logging.anonymize.allow_logging_pii", false))
{
const char failure[] = "Anonymization and trace-level logging are incompatible. "
"Please reduce logging level to debug or lower in loolwsd.xml to prevent leaking sensitive user data.";
@@ -807,7 +807,7 @@ void LOOLWSD::initialize(Application& self)
const auto logToFile = getConfigValue<bool>(conf, "logging.file[@enable]", false);
std::map<std::string, std::string> logProperties;
- for (size_t i = 0; ; ++i)
+ for (std::size_t i = 0; ; ++i)
{
const std::string confPath = "logging.file.property[" + std::to_string(i) + "]";
const auto confName = config().getString(confPath + "[@name]", "");
commit 13f3b7848f9cd77dc7a1e82f0fba656dbd503b4c
Author: Ashod Nakashian <ashod.nakashian at collabora.co.uk>
AuthorDate: Sat Jun 23 19:52:27 2018 -0400
Commit: Jan Holesovsky <kendy at collabora.com>
CommitDate: Fri Aug 17 07:54:19 2018 +0200
configure: support disabling anonymization
And inform the user of the anonymization level.
Change-Id: I95cf832d5c4103744207214ffbf4e85d177ff190
Reviewed-on: https://gerrit.libreoffice.org/56567
Reviewed-by: Jan Holesovsky <kendy at collabora.com>
Tested-by: Jan Holesovsky <kendy at collabora.com>
diff --git a/configure.ac b/configure.ac
index 7dc9e0e48..ef4dcf901 100644
--- a/configure.ac
+++ b/configure.ac
@@ -138,6 +138,7 @@ LOOLWSD_ANONYMIZE_FILENAMES=false
LOOLWSD_ANONYMIZE_USERNAMES=false
LOLEAFLET_LOGGING="false"
debug_msg="secure mode: product build"
+anonym_msg=""
if test "$enable_debug" = "yes"; then
AC_DEFINE([ENABLE_DEBUG],1,[Whether to compile in some extra debugging support code and disable some security pieces])
ENABLE_DEBUG=true
@@ -161,18 +162,24 @@ if test -n "$with_logfile" ; then
fi
AC_SUBST(LOOLWSD_LOGFILE)
-if test -n "$enable_anonymize_filenames" ; then
+if test "$enable_anonymize_filenames" = "yes" ; then
LOOLWSD_ANONYMIZE_FILENAMES=true
+ anonym_msg="filenames anonymized; "
fi
AC_DEFINE_UNQUOTED([LOOLWSD_ANONYMIZE_FILENAMES],[$LOOLWSD_ANONYMIZE_FILENAMES],[Enable permanent filenames anonymization in logs])
AC_SUBST(LOOLWSD_ANONYMIZE_FILENAMES)
-if test -n "$enable_anonymize_usernames" ; then
+if test "$enable_anonymize_usernames" = "yes" ; then
LOOLWSD_ANONYMIZE_USERNAMES=true
+ anonym_msg="${anonym_msg}usernames anonymized; "
fi
AC_DEFINE_UNQUOTED([LOOLWSD_ANONYMIZE_USERNAMES],[$LOOLWSD_ANONYMIZE_USERNAMES],[Enable permanent usernames anonymization in logs])
AC_SUBST(LOOLWSD_ANONYMIZE_USERNAMES)
+if "x$anonym_msg" = "x"; then
+ anonym_msg="no anonymization of usernames or filenames"
+fi
+
MAX_CONNECTIONS=20
AS_IF([test -n "$with_max_connections" && test "$with_max_connections" -gt "0"],
[MAX_CONNECTIONS="$with_max_connections"])
@@ -452,6 +459,7 @@ Configuration:
LO integration tests ${lo_msg}
SSL support $ssl_msg
Debug & low security $debug_msg
+ Anonymization $anonym_msg
\$ make # to compile"
if test -n "$with_lo_path"; then
diff --git a/wsd/LOOLWSD.cpp b/wsd/LOOLWSD.cpp
index e80dffb2c..734ec53e6 100644
--- a/wsd/LOOLWSD.cpp
+++ b/wsd/LOOLWSD.cpp
@@ -776,14 +776,14 @@ void LOOLWSD::initialize(Application& self)
}
// Get anonymization settings.
-#ifdef LOOLWSD_ANONYMIZE_USERNAMES
+#if LOOLWSD_ANONYMIZE_USERNAMES
AnonymizeUsernames = true;
#else
AnonymizeUsernames = getConfigValue<bool>(conf, "logging.anonymize.usernames", false);
#endif
setenv("LOOL_ANONYMIZE_USERNAMES", AnonymizeUsernames ? "1" : "0", true);
-#ifdef LOOLWSD_ANONYMIZE_FILENAMES
+#if LOOLWSD_ANONYMIZE_FILENAMES
AnonymizeFilenames = true;
#else
AnonymizeFilenames = getConfigValue<bool>(conf, "logging.anonymize.filenames", false);
commit 8844d238f1c7a0bd71f6ddd3b59f4ea18bf3bdbb
Author: Ashod Nakashian <ashod.nakashian at collabora.co.uk>
AuthorDate: Tue Jun 19 07:21:22 2018 -0400
Commit: Jan Holesovsky <kendy at collabora.com>
CommitDate: Fri Aug 17 07:54:19 2018 +0200
wsd: force anonymization when enabled with configure
This prevents disabling from loolwsd.xml when
the flags to anonymize are baked in at compile time.
Change-Id: If38ad3815bc9f18ed51b6626fc8c03528e7b8327
Reviewed-on: https://gerrit.libreoffice.org/56089
Reviewed-by: Ashod Nakashian <ashnakash at gmail.com>
... etc. - the rest is truncated
More information about the Libreoffice-commits
mailing list