[Libreoffice-commits] online.git: fuzzer/ClientSession.cpp loleaflet/src Makefile.am wsd/ClientSession.cpp wsd/ClientSession.hpp wsd/DocumentBroker.cpp wsd/DocumentBroker.hpp wsd/FileServer.cpp wsd/LOOLWSD.cpp wsd/ProxyProtocol.cpp wsd/ServerURL.hpp

Michael Meeks (via logerrit) logerrit at kemper.freedesktop.org
Wed May 6 21:12:33 UTC 2020


 Makefile.am                    |    1 
 fuzzer/ClientSession.cpp       |    4 -
 loleaflet/src/map/Clipboard.js |   14 +++---
 wsd/ClientSession.cpp          |   13 +++---
 wsd/ClientSession.hpp          |    7 +--
 wsd/DocumentBroker.cpp         |    7 +--
 wsd/DocumentBroker.hpp         |    5 +-
 wsd/FileServer.cpp             |   54 +-------------------------
 wsd/LOOLWSD.cpp                |   18 ++------
 wsd/ProxyProtocol.cpp          |    4 -
 wsd/ServerURL.hpp              |   84 +++++++++++++++++++++++++++++++++++++++++
 11 files changed, 124 insertions(+), 87 deletions(-)

New commits:
commit 18c4301a1f26e5630b24db532a532baafb6cd57f
Author:     Michael Meeks <michael.meeks at collabora.com>
AuthorDate: Wed May 6 17:02:51 2020 +0100
Commit:     Michael Meeks <michael.meeks at collabora.com>
CommitDate: Wed May 6 23:12:12 2020 +0200

    Proxy: re-factor proxy handling into ServerURL and cleanup copy/paste.
    
    Also adds ServiceRoot handling for clipboard.
    
    Change-Id: I7bc6591130fcc7d693e59ab8561fb9e99f4e93d5
    Reviewed-on: https://gerrit.libreoffice.org/c/online/+/93578
    Tested-by: Michael Meeks <michael.meeks at collabora.com>
    Reviewed-by: Michael Meeks <michael.meeks at collabora.com>

diff --git a/Makefile.am b/Makefile.am
index 42e338913..1b5beb47c 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -225,6 +225,7 @@ wsd_headers = wsd/Admin.hpp \
               wsd/ProofKey.hpp \
               wsd/QueueHandler.hpp \
               wsd/SenderQueue.hpp \
+              wsd/ServerURL.hpp \
               wsd/Storage.hpp \
               wsd/TileCache.hpp \
               wsd/TileDesc.hpp \
diff --git a/fuzzer/ClientSession.cpp b/fuzzer/ClientSession.cpp
index 844fa0c80..a9a6ad657 100644
--- a/fuzzer/ClientSession.cpp
+++ b/fuzzer/ClientSession.cpp
@@ -21,9 +21,9 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size)
     std::shared_ptr<ProtocolHandlerInterface> ws;
     std::string id;
     bool isReadOnly = false;
-    const std::string hostNoTrust;
+    const ServerURL serverURL("", "");
     auto session
-        = std::make_shared<ClientSession>(ws, id, docBroker, uriPublic, isReadOnly, hostNoTrust);
+        = std::make_shared<ClientSession>(ws, id, docBroker, uriPublic, isReadOnly, serverURL);
 
     std::string input(reinterpret_cast<const char*>(data), size);
     std::stringstream ss(input);
diff --git a/loleaflet/src/map/Clipboard.js b/loleaflet/src/map/Clipboard.js
index 700369d29..c7b604083 100644
--- a/loleaflet/src/map/Clipboard.js
+++ b/loleaflet/src/map/Clipboard.js
@@ -99,6 +99,10 @@ L.Clipboard = L.Class.extend({
 			'&Tag=' + this._accessKey[idx];
 	},
 
+	getMetaURL: function(idx) {
+		return this.getMetaBase() + this.getMetaPath(idx);
+	},
+
 	// Returns the marker used to identify stub messages.
 	_getHtmlStubMarker: function() {
 		return '<title>Stub HTML Message</title>';
@@ -111,7 +115,7 @@ L.Clipboard = L.Class.extend({
 
 	// wrap some content with our stub magic
 	_originWrapBody: function(body, isStub) {
-		var encodedOrigin = encodeURIComponent(this.getMetaPath());
+		var encodedOrigin = encodeURIComponent(this.getMetaURL());
 		var text =  '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">\n' +
 		            '<html>\n' +
 		            '  <head>\n';
@@ -340,8 +344,7 @@ L.Clipboard = L.Class.extend({
 		if (meta !== '')
 		{
 			console.log('Transfer between servers\n\t"' + meta + '" vs. \n\t"' + id + '"');
-			var destination = this.getMetaBase() + this.getMetaPath();
-			this._dataTransferDownloadAndPasteAsync(meta, destination, htmlText);
+			this._dataTransferDownloadAndPasteAsync(meta, this.getMetaURL(), htmlText);
 			return;
 		}
 
@@ -397,8 +400,7 @@ L.Clipboard = L.Class.extend({
 			formData.append('file', content);
 
 			var that = this;
-			var destination = this.getMetaBase() + this.getMetaPath();
-			this._doAsyncDownload('POST', destination, formData,
+			this._doAsyncDownload('POST', this.getMetaURL(), formData,
 							function() {
 								console.log('Posted ' + content.size + ' bytes successfully');
 								if (usePasteKeyEvent) {
@@ -439,7 +441,7 @@ L.Clipboard = L.Class.extend({
 				text = this._getStubHtml();
 				this._onDownloadOnLargeCopyPaste();
 				this._downloadProgress.setURI( // richer, bigger HTML ...
-					this.getMetaBase() + this.getMetaPath() + '&MimeType=text/html');
+					this.getMetaURL() + '&MimeType=text/html');
 			}
 		} else if (this._selectionType === null) {
 			console.log('Copy/Cut with no selection!');
diff --git a/wsd/ClientSession.cpp b/wsd/ClientSession.cpp
index c4c6ec7cb..c28961fb6 100644
--- a/wsd/ClientSession.cpp
+++ b/wsd/ClientSession.cpp
@@ -44,7 +44,7 @@ ClientSession::ClientSession(
     const std::shared_ptr<DocumentBroker>& docBroker,
     const Poco::URI& uriPublic,
     const bool readOnly,
-    const std::string& hostNoTrust) :
+    const ServerURL &serverURL) :
     Session(ws, "ToClient-" + id, id, readOnly),
     _docBroker(docBroker),
     _uriPublic(uriPublic),
@@ -58,7 +58,7 @@ ClientSession::ClientSession(
     _tileWidthTwips(0),
     _tileHeightTwips(0),
     _kitViewId(-1),
-    _hostNoTrust(hostNoTrust),
+    _serverURL(serverURL),
     _isTextDocument(false)
 {
     const size_t curConnections = ++LOOLWSD::NumConnections;
@@ -207,12 +207,11 @@ std::string ClientSession::getClipboardURI(bool encode)
     std::string encodeChars = ",/?:@&=+$#"; // match JS encodeURIComponent
     Poco::URI::encode(wopiSrc.toString(), encodeChars, encodedFrom);
 
-    std::string proto = (LOOLWSD::isSSLEnabled() || LOOLWSD::isSSLTermination()) ? "https://" : "http://";
-    std::string meta = proto + _hostNoTrust +
+    std::string meta = _serverURL.getSubURLForEndpoint(
         "/lool/clipboard?WOPISrc=" + encodedFrom +
         "&ServerId=" + LOOLWSD::HostIdentifier +
         "&ViewId=" + std::to_string(getKitViewId()) +
-        "&Tag=" + _clipboardKeys[0];
+        "&Tag=" + _clipboardKeys[0]);
 
     if (!encode)
         return meta;
@@ -1030,6 +1029,7 @@ void ClientSession::writeQueuedMessages()
     LOG_TRC(getName() << " ClientSession: performed write.");
 }
 
+// NB. also see loleaflet/src/map/Clipboard.js that does this in JS for stubs.
 void ClientSession::postProcessCopyPayload(std::shared_ptr<Message> payload)
 {
     // Insert our meta origin if we can
@@ -1043,6 +1043,7 @@ void ClientSession::postProcessCopyPayload(std::shared_ptr<Message> payload)
             if (pos != std::string::npos) // assume text/html
             {
                 const std::string meta = getClipboardURI();
+                LOG_TRC("Inject clipboard meta origin of '" << meta << "'");
                 const std::string origin = "<meta name=\"origin\" content=\"" + meta + "\"/>\n";
                 data.insert(data.begin() + pos, origin.begin(), origin.end());
                 return true;
@@ -1719,7 +1720,7 @@ void ClientSession::dumpState(std::ostream& os)
        << "\n\t\ttile size Pixel: " << _tileWidthPixel << "x" << _tileHeightPixel
        << "\n\t\ttile size Twips: " << _tileWidthTwips << "x" << _tileHeightTwips
        << "\n\t\tkit ViewId: " << _kitViewId
-       << "\n\t\thost (un-trusted): " << _hostNoTrust
+       << "\n\t\tour URL (un-trusted): " << _serverURL.getSubURLForEndpoint("")
        << "\n\t\tisTextDocument: " << _isTextDocument
        << "\n\t\tclipboardKeys[0]: " << _clipboardKeys[0]
        << "\n\t\tclipboardKeys[1]: " << _clipboardKeys[1]
diff --git a/wsd/ClientSession.hpp b/wsd/ClientSession.hpp
index f2bd63adc..a99832560 100644
--- a/wsd/ClientSession.hpp
+++ b/wsd/ClientSession.hpp
@@ -13,6 +13,7 @@
 #include "Storage.hpp"
 #include "MessageQueue.hpp"
 #include "SenderQueue.hpp"
+#include "ServerURL.hpp"
 #include "DocumentBroker.hpp"
 #include <Poco/URI.h>
 #include <Rectangle.hpp>
@@ -33,7 +34,7 @@ public:
                   const std::shared_ptr<DocumentBroker>& docBroker,
                   const Poco::URI& uriPublic,
                   const bool isReadOnly,
-                  const std::string& hostNoTrust);
+                  const ServerURL &serverURL);
     void construct();
     virtual ~ClientSession();
 
@@ -260,8 +261,8 @@ private:
     /// The integer id of the view in the Kit process
     int _kitViewId;
 
-    /// Un-trusted hostname of our service from the client
-    const std::string _hostNoTrust;
+    /// How to find our service from the client.
+    const ServerURL _serverURL;
 
     /// Client is using a text document?
     bool _isTextDocument;
diff --git a/wsd/DocumentBroker.cpp b/wsd/DocumentBroker.cpp
index a81864506..1cbfcac13 100644
--- a/wsd/DocumentBroker.cpp
+++ b/wsd/DocumentBroker.cpp
@@ -1526,7 +1526,7 @@ std::shared_ptr<ClientSession> DocumentBroker::createNewClientSession(
     const std::string& id,
     const Poco::URI& uriPublic,
     const bool isReadOnly,
-    const std::string& hostNoTrust)
+    const ServerURL &serverURL)
 {
     try
     {
@@ -1541,7 +1541,7 @@ std::shared_ptr<ClientSession> DocumentBroker::createNewClientSession(
         // In case of WOPI, if this session is not set as readonly, it might be set so
         // later after making a call to WOPI host which tells us the permission on files
         // (UserCanWrite param).
-        auto session = std::make_shared<ClientSession>(ws, id, shared_from_this(), uriPublic, isReadOnly, hostNoTrust);
+        auto session = std::make_shared<ClientSession>(ws, id, shared_from_this(), uriPublic, isReadOnly, serverURL);
         session->construct();
 
         return session;
@@ -2269,7 +2269,8 @@ bool ConvertToBroker::startConversion(SocketDisposition &disposition, const std:
     const bool isReadOnly = true;
     // FIXME: associate this with moveSocket (?)
     std::shared_ptr<ProtocolHandlerInterface> nullPtr;
-    _clientSession = std::make_shared<ClientSession>(nullPtr, id, docBroker, getPublicUri(), isReadOnly, "nocliphost");
+    ServerURL serverURL;
+    _clientSession = std::make_shared<ClientSession>(nullPtr, id, docBroker, getPublicUri(), isReadOnly, serverURL);
     _clientSession->construct();
 
     if (!_clientSession)
diff --git a/wsd/DocumentBroker.hpp b/wsd/DocumentBroker.hpp
index f8c2ccea2..f086ddea6 100644
--- a/wsd/DocumentBroker.hpp
+++ b/wsd/DocumentBroker.hpp
@@ -97,6 +97,7 @@ private:
     int _smapsFD;
 };
 
+class ServerURL;
 class ClientSession;
 
 /// DocumentBroker is responsible for setting up a document in jail and brokering loading it from
@@ -153,7 +154,7 @@ public:
         const std::string& id,
         const Poco::URI& uriPublic,
         const bool isReadOnly,
-        const std::string& hostNoTrust);
+        const ServerURL &serverURL);
 
     /// Find or create a new client session for the PHP proxy
     void handleProxyRequest(
@@ -161,7 +162,7 @@ public:
         const std::string& id,
         const Poco::URI& uriPublic,
         const bool isReadOnly,
-        const std::string& hostNoTrust,
+        const ServerURL &serverURL,
         const std::shared_ptr<StreamSocket> &socket,
         bool isWaiting);
 
diff --git a/wsd/FileServer.cpp b/wsd/FileServer.cpp
index 888509591..8809a582a 100644
--- a/wsd/FileServer.cpp
+++ b/wsd/FileServer.cpp
@@ -43,6 +43,7 @@
 #include <Crypto.hpp>
 #include "FileServer.hpp"
 #include "LOOLWSD.hpp"
+#include "ServerURL.hpp"
 #include <Log.hpp>
 #include <Protocol.hpp>
 #include <Util.hpp>
@@ -641,61 +642,12 @@ constexpr char BRANDING_UNSUPPORTED[] = "branding-unsupported";
 #endif
 
 namespace {
-    /// Very simple splitting of proxy URLs without fear of escaping or validation.
-    class ProxyURL {
-        std::string _schemeAuthority;
-        std::string _pathPlus;
-    public:
-        ProxyURL(const HTTPRequest &request)
-        {
-            // The user can override the ServerRoot with a new prefix.
-            if (_pathPlus.size() <= 0)
-                _pathPlus = LOOLWSD::ServiceRoot;
-
-            if (_schemeAuthority.size() <= 0)
-            {
-                bool ssl = (LOOLWSD::isSSLEnabled() || LOOLWSD::isSSLTermination());
-                std::string serverName = LOOLWSD::ServerName.empty() ? request.getHost() : LOOLWSD::ServerName;
-                _schemeAuthority = (ssl ? "wss://" : "ws://") + serverName;
-            }
-
-            // A well formed ProxyPrefix will override it.
-            std::string url = request.get("ProxyPrefix", "");
-            if (url.size() <= 0)
-                return;
-
-            size_t pos = url.find("://");
-            if (pos != std::string::npos) {
-                pos = url.find("/", pos + 3);
-                if (pos != std::string::npos)
-                {
-                    _schemeAuthority = url.substr(0, pos);
-                    _pathPlus = url.substr(pos);
-                    return;
-                }
-                else
-                    LOG_ERR("Unusual proxy prefix '" << url << "'");
-            } else
-                LOG_ERR("No http[s]:// in unusual proxy prefix '" << url << "'");
-
-        }
-
-        std::string getResponseRoot() const
-        {
-            return _pathPlus;
-        }
-
-        std::string getWebSocketUrl() const
-        {
-            return _schemeAuthority;
-        }
-    };
 }
 
 void FileServerRequestHandler::preprocessFile(const HTTPRequest& request, Poco::MemoryInputStream& message,
                                               const std::shared_ptr<StreamSocket>& socket)
 {
-    ProxyURL cnxDetails(request);
+    ServerURL cnxDetails(request);
 
     const Poco::URI::QueryParameters params = Poco::URI(request.getURI()).getQueryParameters();
 
@@ -963,7 +915,7 @@ void FileServerRequestHandler::preprocessAdminFile(const HTTPRequest& request,co
     if (!FileServerRequestHandler::isAdminLoggedIn(request, response))
         throw Poco::Net::NotAuthenticatedException("Invalid admin login");
 
-    ProxyURL cnxDetails(request);
+    ServerURL cnxDetails(request);
     std::string responseRoot = cnxDetails.getResponseRoot();
 
     static const std::string scriptJS("<script src=\"%s/loleaflet/" LOOLWSD_VERSION_HASH "/%s.js\"></script>");
diff --git a/wsd/LOOLWSD.cpp b/wsd/LOOLWSD.cpp
index 3b770cf03..18d8469ef 100644
--- a/wsd/LOOLWSD.cpp
+++ b/wsd/LOOLWSD.cpp
@@ -2956,7 +2956,7 @@ private:
             }
         }
 
-        const std::string hostNoTrust = (LOOLWSD::ServerName.empty() ? request.getHost() : LOOLWSD::ServerName);
+        ServerURL serverURL(request);
 
         LOG_INF("URL [" << LOOLWSD::anonymizeUrl(url) << "] is " << (isReadOnly ? "readonly" : "writable") << ".");
         (void)request; (void)message; (void)disposition;
@@ -2973,7 +2973,7 @@ private:
         {
             // need to move into the DocumentBroker context before doing session lookup / creation etc.
             std::string id = _id;
-            disposition.setMove([docBroker, id, uriPublic, isReadOnly, hostNoTrust, sessionId, isWaiting]
+            disposition.setMove([docBroker, id, uriPublic, isReadOnly, serverURL, sessionId, isWaiting]
                                 (const std::shared_ptr<Socket> &moveSocket)
                 {
                     LOG_TRC("Setting up docbroker thread for " << docBroker->getDocKey());
@@ -2983,7 +2983,7 @@ private:
                     // We no longer own this socket.
                     moveSocket->setThreadOwner(std::thread::id());
 
-                    docBroker->addCallback([docBroker, id, uriPublic, isReadOnly, hostNoTrust,
+                    docBroker->addCallback([docBroker, id, uriPublic, isReadOnly, serverURL,
                                             sessionId, moveSocket, isWaiting]()
                         {
                             // Now inside the document broker thread ...
@@ -2994,7 +2994,7 @@ private:
                             {
                                 docBroker->handleProxyRequest(
                                     sessionId, id, uriPublic, isReadOnly,
-                                    hostNoTrust, streamSocket, isWaiting);
+                                    serverURL, streamSocket, isWaiting);
                                 return;
                             }
                             catch (const UnauthorizedRequestException& exc)
@@ -3084,15 +3084,9 @@ private:
                 DocumentBroker::ChildType::Interactive, url, docKey, _id, uriPublic);
             if (docBroker)
             {
-#if MOBILEAPP
-                const std::string hostNoTrust;
-#else
-                // We can send this back to whomever sent it to us though.
-                const std::string hostNoTrust = (LOOLWSD::ServerName.empty() ? request.getHost() : LOOLWSD::ServerName);
-#endif
-
+                ServerURL serverURL(request);
                 std::shared_ptr<ClientSession> clientSession =
-                    docBroker->createNewClientSession(ws, _id, uriPublic, isReadOnly, hostNoTrust);
+                    docBroker->createNewClientSession(ws, _id, uriPublic, isReadOnly, serverURL);
                 if (clientSession)
                 {
                     // Transfer the client socket to the DocumentBroker when we get back to the poll:
diff --git a/wsd/ProxyProtocol.cpp b/wsd/ProxyProtocol.cpp
index 973d9f3c5..f11d7d942 100644
--- a/wsd/ProxyProtocol.cpp
+++ b/wsd/ProxyProtocol.cpp
@@ -24,7 +24,7 @@ void DocumentBroker::handleProxyRequest(
     const std::string& id,
     const Poco::URI& uriPublic,
     const bool isReadOnly,
-    const std::string& hostNoTrust,
+    const ServerURL &serverURL,
     const std::shared_ptr<StreamSocket> &socket,
     bool isWaiting)
 {
@@ -34,7 +34,7 @@ void DocumentBroker::handleProxyRequest(
         LOG_TRC("proxy: Create session for " << _docKey);
         clientSession = createNewClientSession(
                 std::make_shared<ProxyProtocolHandler>(),
-                id, uriPublic, isReadOnly, hostNoTrust);
+                id, uriPublic, isReadOnly, serverURL);
         addSession(clientSession);
         LOOLWSD::checkDiskSpaceAndWarnClients(true);
         LOOLWSD::checkSessionLimitsAndWarnClients();
diff --git a/wsd/ServerURL.hpp b/wsd/ServerURL.hpp
new file mode 100644
index 000000000..3e96fff98
--- /dev/null
+++ b/wsd/ServerURL.hpp
@@ -0,0 +1,84 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#pragma once
+
+#include <string>
+#include <Poco/Net/HTTPRequest.h>
+#include "LOOLWSD.hpp"
+
+/** This class helps us to build a URL that will reliably point back
+ * at our service. It does very simple splitting of proxy U
+ * and handles the proxy prefix feature.
+ */
+class ServerURL
+{
+    std::string _schemeProtocol;
+    std::string _schemeAuthority;
+    std::string _pathPlus;
+public:
+    ServerURL(const Poco::Net::HTTPRequest &request)
+    {
+        init(request.getHost(), request.get("ProxyPrefix", ""));
+    }
+
+    explicit ServerURL()
+    {
+        init("nohostname", "");
+    }
+
+    void init(const std::string &host, const std::string &proxyPrefix)
+    {
+        // The user can override the ServerRoot with a new prefix.
+        _pathPlus = LOOLWSD::ServiceRoot;
+
+        bool ssl = (LOOLWSD::isSSLEnabled() || LOOLWSD::isSSLTermination());
+        std::string serverName = LOOLWSD::ServerName.empty() ? host : LOOLWSD::ServerName;
+        _schemeProtocol = (ssl ? "wss://" : "ws://");
+        _schemeAuthority = serverName;
+
+        // A well formed ProxyPrefix will override it.
+        std::string url = proxyPrefix;
+        if (url.size() <= 0)
+            return;
+
+        size_t pos = url.find("://");
+        if (pos != std::string::npos) {
+            pos += 3;
+            auto hostEndPos = url.find("/", pos);
+            if (hostEndPos != std::string::npos)
+            {
+                _schemeProtocol = url.substr(0, pos);
+                _schemeAuthority = url.substr(pos, hostEndPos - pos);
+                _pathPlus = url.substr(hostEndPos);
+                return;
+            }
+            else
+                LOG_ERR("Unusual proxy prefix '" << url << "'");
+        } else
+            LOG_ERR("No http[s]:// in unusual proxy prefix '" << url << "'");
+    }
+
+    std::string getResponseRoot() const
+    {
+        return _pathPlus;
+    }
+
+    std::string getWebSocketUrl() const
+    {
+        return _schemeProtocol + _schemeAuthority;
+    }
+
+    std::string getSubURLForEndpoint(const std::string &path) const
+    {
+        return _schemeProtocol + _schemeAuthority + _pathPlus + path;
+    }
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */


More information about the Libreoffice-commits mailing list