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 <ke...@collabora.com>
AuthorDate: Wed Jul 18 16:18:03 2018 +0200
Commit:     Jan Holesovsky <ke...@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 <ashnak...@gmail.com>
    Tested-by: Ashod Nakashian <ashnak...@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.nakash...@collabora.co.uk>
AuthorDate: Thu Jul 19 01:27:46 2018 -0400
Commit:     Jan Holesovsky <ke...@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 <ke...@collabora.com>
    Tested-by: Jan Holesovsky <ke...@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.nakash...@collabora.co.uk>
AuthorDate: Wed Jun 6 22:53:15 2018 -0400
Commit:     Jan Holesovsky <ke...@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.nakash...@collabora.co.uk>
AuthorDate: Sun Jul 29 22:58:42 2018 -0400
Commit:     Jan Holesovsky <ke...@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.nakash...@collabora.co.uk>
AuthorDate: Wed Aug 1 22:25:38 2018 -0400
Commit:     Jan Holesovsky <ke...@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.nakash...@collabora.co.uk>
AuthorDate: Wed Aug 1 22:04:33 2018 -0400
Commit:     Jan Holesovsky <ke...@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.nakash...@collabora.co.uk>
AuthorDate: Wed Aug 1 22:03:53 2018 -0400
Commit:     Jan Holesovsky <ke...@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.nakash...@collabora.co.uk>
AuthorDate: Sat Jul 21 15:58:35 2018 -0400
Commit:     Jan Holesovsky <ke...@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.nakash...@collabora.co.uk>
AuthorDate: Thu Jul 19 01:22:07 2018 -0400
Commit:     Jan Holesovsky <ke...@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 <ke...@collabora.com>
    Tested-by: Jan Holesovsky <ke...@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.nakash...@collabora.co.uk>
AuthorDate: Wed Jul 18 10:30:22 2018 -0400
Commit:     Jan Holesovsky <ke...@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 <ashnak...@gmail.com>
    Tested-by: Ashod Nakashian <ashnak...@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.nakash...@collabora.co.uk>
AuthorDate: Tue Jul 17 02:01:05 2018 -0400
Commit:     Jan Holesovsky <ke...@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 <ke...@collabora.com>
    Tested-by: Jan Holesovsky <ke...@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("u...@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.nakash...@collabora.co.uk>
AuthorDate: Mon Jul 16 21:42:17 2018 -0400
Commit:     Jan Holesovsky <ke...@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 <ke...@collabora.com>
    Tested-by: Jan Holesovsky <ke...@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], &params[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.nakash...@collabora.co.uk>
AuthorDate: Fri Jul 13 00:18:30 2018 -0400
Commit:     Jan Holesovsky <ke...@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 <ke...@collabora.com>
    Tested-by: Jan Holesovsky <ke...@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.nakash...@collabora.co.uk>
AuthorDate: Thu Jul 19 01:27:46 2018 -0400
Commit:     Jan Holesovsky <ke...@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 <ke...@collabora.com>
    Tested-by: Jan Holesovsky <ke...@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.nakash...@collabora.co.uk>
AuthorDate: Thu Jul 12 18:00:33 2018 -0400
Commit:     Jan Holesovsky <ke...@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 <ke...@collabora.com>
    Tested-by: Jan Holesovsky <ke...@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.nakash...@collabora.co.uk>
AuthorDate: Tue Jul 10 23:09:27 2018 -0400
Commit:     Jan Holesovsky <ke...@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 <ke...@collabora.com>
    Tested-by: Jan Holesovsky <ke...@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.nakash...@collabora.co.uk>
AuthorDate: Sun Jul 8 22:50:09 2018 -0400
Commit:     Jan Holesovsky <ke...@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 <ke...@collabora.com>
    Tested-by: Jan Holesovsky <ke...@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.nakash...@collabora.co.uk>
AuthorDate: Thu Jun 28 00:47:20 2018 -0400
Commit:     Jan Holesovsky <ke...@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 <ke...@collabora.com>
    Tested-by: Jan Holesovsky <ke...@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.nakash...@collabora.co.uk>
AuthorDate: Sat Jun 23 19:52:27 2018 -0400
Commit:     Jan Holesovsky <ke...@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 <ke...@collabora.com>
    Tested-by: Jan Holesovsky <ke...@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.nakash...@collabora.co.uk>
AuthorDate: Tue Jun 19 07:21:22 2018 -0400
Commit:     Jan Holesovsky <ke...@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 <ashnak...@gmail.com>

... etc. - the rest is truncated
_______________________________________________
Libreoffice-commits mailing list
libreoffice-comm...@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/libreoffice-commits

Reply via email to