[Libreoffice-commits] online.git: loolwsd/ChildProcessSession.cpp loolwsd/ChildProcessSession.hpp loolwsd/LOOLKit.cpp loolwsd/LOOLSession.cpp loolwsd/LOOLSession.hpp loolwsd/MasterProcessSession.cpp

Pranav Kant pranavk at collabora.co.uk
Fri Feb 19 21:50:05 UTC 2016


 loolwsd/ChildProcessSession.cpp  |   63 +++++++++++++++++++++++++++++++++++----
 loolwsd/ChildProcessSession.hpp  |    4 ++
 loolwsd/LOOLKit.cpp              |    5 +++
 loolwsd/LOOLSession.cpp          |   10 ++++++
 loolwsd/LOOLSession.hpp          |   20 ++++++++++++
 loolwsd/MasterProcessSession.cpp |   30 +++++++++++++++++-
 6 files changed, 126 insertions(+), 6 deletions(-)

New commits:
commit 3667bef9a6759181ac90b31e63633c75bf5bed72
Author: Pranav Kant <pranavk at collabora.co.uk>
Date:   Thu Feb 4 23:05:26 2016 +0530

    loolwsd: Handle password protected documents
    
    Change-Id: Iceb5bb598ef1517bf640994c27bad4ca36bd72c1
    Reviewed-on: https://gerrit.libreoffice.org/21894
    Reviewed-by: Ashod Nakashian <ashnakash at gmail.com>
    Tested-by: Ashod Nakashian <ashnakash at gmail.com>

diff --git a/loolwsd/ChildProcessSession.cpp b/loolwsd/ChildProcessSession.cpp
index dfef7b7..5fd53ee 100644
--- a/loolwsd/ChildProcessSession.cpp
+++ b/loolwsd/ChildProcessSession.cpp
@@ -118,6 +118,10 @@ public:
             return std::string("LOK_CALLBACK_SET_PART");
         case LOK_CALLBACK_PARTS_COUNT_CHANGED:
             return std::string("LOK_CALLBACK_PARTS_COUNT_CHANGED");
+        case LOK_CALLBACK_DOCUMENT_PASSWORD:
+            return std::string("LOK_CALLBACK_DOCUMENT_PASSWORD");
+        case LOK_CALLBACK_DOCUMENT_PASSWORD_TO_MODIFY:
+            return std::string("LOK_CALLBACK_DOCUMENT_PASSWORD_TO_MODIFY");
         }
         return std::to_string(nType);
     }
@@ -245,8 +249,8 @@ public:
             _session.sendTextFrame("unocommandresult: " + rPayload);
             break;
         case LOK_CALLBACK_DOCUMENT_PASSWORD:
-            break;
         case LOK_CALLBACK_DOCUMENT_PASSWORD_TO_MODIFY:
+            _session.setDocumentPassword(nType);
             break;
         case LOK_CALLBACK_ERROR:
             {
@@ -321,12 +325,13 @@ std::recursive_mutex ChildProcessSession::Mutex;
 
 ChildProcessSession::ChildProcessSession(const std::string& id,
                                          std::shared_ptr<Poco::Net::WebSocket> ws,
-                                         LibreOfficeKit* /*loKit*/,
+                                         LibreOfficeKit* loKit,
                                          LibreOfficeKitDocument * loKitDocument,
                                          const std::string& jailId,
                                          std::function<LibreOfficeKitDocument*(const std::string&, const std::string&)> onLoad,
                                          std::function<void(const std::string&)> onUnload) :
     LOOLSession(id, Kind::ToMaster, ws),
+    _loKit(loKit),
     _loKitDocument(loKitDocument),
     _multiView(getenv("LOK_VIEW_CALLBACK")),
     _jailId(jailId),
@@ -422,15 +427,31 @@ bool ChildProcessSession::_handleInput(const char *buffer, int length)
     }
     else if (tokens[0] == "load")
     {
-        if (_docURL != "")
+        if (_isDocLoaded)
         {
             sendTextFrame("error: cmd=load kind=docalreadyloaded");
             return false;
         }
 
-        return loadDocument(buffer, length, tokens);
+        _isDocLoaded = loadDocument(buffer, length, tokens);
+        if (!_isDocLoaded && _isDocPasswordProtected)
+        {
+            if (!_isDocPasswordProvided)
+            {
+                std::string passwordFrame = "passwordrequired:";
+                if (_docPasswordType == PasswordType::ToView)
+                    passwordFrame += "to-view";
+                else if (_docPasswordType == PasswordType::ToModify)
+                    passwordFrame += "to-modify";
+                sendTextFrame("error: cmd=load kind=" + passwordFrame);
+            }
+            else
+                sendTextFrame("error: cmd=load kind=wrongpassword");
+        }
+
+        return _isDocLoaded;
     }
-    else if (_docURL == "")
+    else if (!_isDocLoaded)
     {
         sendTextFrame("error: cmd=" + tokens[0] + " kind=nodocloaded");
         return false;
@@ -584,6 +605,9 @@ bool ChildProcessSession::loadDocument(const char * /*buffer*/, int /*length*/,
 
     _loKitDocument = _onLoad(getId(), _jailedFilePath);
 
+    if (!_loKitDocument)
+        return false;
+
     std::unique_lock<std::recursive_mutex> lock(Mutex);
 
     if (_multiView)
@@ -606,6 +630,11 @@ bool ChildProcessSession::loadDocument(const char * /*buffer*/, int /*length*/,
         _loKitDocument->pClass->setPart(_loKitDocument, part);
     }
 
+    // 'statusindicatorfinish:' is used to let clients, and parent process know of successfull document load
+    // Usually, 'statusindicatorfinish:' is already sent when the load document operation finishes,
+    // but in case of multiple sessions accessing the same document, it won't be sent.
+    sendTextFrame("statusindicatorfinish:");
+
     // Respond by the document status, which has no arguments.
     if (!getStatus(nullptr, 0))
         return false;
@@ -1320,6 +1349,30 @@ bool ChildProcessSession::setPage(const char* /*buffer*/, int /*length*/, String
     return true;
 }
 
+void ChildProcessSession::setDocumentPassword(const int nPasswordType)
+{
+
+    if (_isDocPasswordProtected && _isDocPasswordProvided)
+    {
+        // it means this is the second attempt with the wrong password; abort load operation
+        _loKit->pClass->setDocumentPassword(_loKit, _jailedFilePath.c_str(), nullptr);
+        return;
+    }
+
+    // One thing for sure, this is a password protected document
+    _isDocPasswordProtected = true;
+
+    if (nPasswordType == LOK_CALLBACK_DOCUMENT_PASSWORD)
+        _docPasswordType = PasswordType::ToView;
+    else if (nPasswordType == LOK_CALLBACK_DOCUMENT_PASSWORD_TO_MODIFY)
+        _docPasswordType = PasswordType::ToModify;
+
+    if (_isDocPasswordProvided)
+        _loKit->pClass->setDocumentPassword(_loKit, _jailedFilePath.c_str(), _docPassword.c_str());
+    else
+        _loKit->pClass->setDocumentPassword(_loKit, _jailedFilePath.c_str(), nullptr);
+}
+
 void ChildProcessSession::loKitCallback(const int nType, const char *pPayload)
 {
     auto pNotif = new CallbackNotification(nType, pPayload ? pPayload : "(nil)");
diff --git a/loolwsd/ChildProcessSession.hpp b/loolwsd/ChildProcessSession.hpp
index 3e7c957..259dccb 100644
--- a/loolwsd/ChildProcessSession.hpp
+++ b/loolwsd/ChildProcessSession.hpp
@@ -14,6 +14,7 @@
 
 #define LOK_USE_UNSTABLE_API
 #include <LibreOfficeKit/LibreOfficeKit.h>
+#include <LibreOfficeKit/LibreOfficeKitEnums.h>
 
 #include <Poco/Thread.h>
 #include <Poco/NotificationQueue.h>
@@ -89,6 +90,8 @@ public:
     const Statistics& getStatistics() const { return _stats; }
     bool isInactive() const { return _stats.getInactivityMS() >= InactivityThresholdMS; }
 
+    void setDocumentPassword(const int nPasswordType);
+
  protected:
     virtual bool loadDocument(const char *buffer, int length, Poco::StringTokenizer& tokens) override;
 
@@ -120,6 +123,7 @@ private:
     virtual bool _handleInput(const char *buffer, int length) override;
 
 private:
+    LibreOfficeKit *_loKit;
     LibreOfficeKitDocument *_loKitDocument;
     std::string _docType;
     const bool _multiView;
diff --git a/loolwsd/LOOLKit.cpp b/loolwsd/LOOLKit.cpp
index 3895609..9c55ff3 100644
--- a/loolwsd/LOOLKit.cpp
+++ b/loolwsd/LOOLKit.cpp
@@ -44,6 +44,7 @@
 
 #define LOK_USE_UNSTABLE_API
 #include <LibreOfficeKit/LibreOfficeKitInit.h>
+#include <LibreOfficeKit/LibreOfficeKitEnums.h>
 
 #include "Common.hpp"
 #include "QueueHandler.hpp"
@@ -518,7 +519,11 @@ private:
             Log::info("Loading new document from URI: [" + uri + "] for session [" + sessionId + "].");
 
             if ( LIBREOFFICEKIT_HAS(_loKit, registerCallback))
+            {
                 _loKit->pClass->registerCallback(_loKit, DocumentCallback, this);
+                _loKit->pClass->setOptionalFeatures(_loKit, LOK_FEATURE_DOCUMENT_PASSWORD |
+                                                    LOK_FEATURE_DOCUMENT_PASSWORD_TO_MODIFY);
+            }
 
             // documentLoad will trigger callback, which needs to take the lock.
             lock.unlock();
diff --git a/loolwsd/LOOLSession.cpp b/loolwsd/LOOLSession.cpp
index 9a59292..65eb0ea 100644
--- a/loolwsd/LOOLSession.cpp
+++ b/loolwsd/LOOLSession.cpp
@@ -87,6 +87,10 @@ LOOLSession::LOOLSession(const std::string& id, const Kind kind,
     _kindString(kind == Kind::ToClient ? "ToClient" :
                 kind == Kind::ToMaster ? "ToMaster" : "ToPrisoner"),
     _ws(ws),
+    _docPassword(""),
+    _isDocPasswordProvided(false),
+    _isDocLoaded(false),
+    _isDocPasswordProtected(false),
     _bShutdown(false),
     _disconnected(false)
 {
@@ -171,6 +175,12 @@ void LOOLSession::parseDocOptions(const StringTokenizer& tokens, int& part, std:
             timestamp = tokens[i].substr(strlen("timestamp="));
             ++offset;
         }
+        else if (tokens[i].find("password=") == 0)
+        {
+            _docPassword = tokens[i].substr(strlen("password="));
+            _isDocPasswordProvided = true;
+            ++offset;
+        }
     }
 
     if (tokens.count() > offset)
diff --git a/loolwsd/LOOLSession.hpp b/loolwsd/LOOLSession.hpp
index 62769e2..9bc7f85 100644
--- a/loolwsd/LOOLSession.hpp
+++ b/loolwsd/LOOLSession.hpp
@@ -41,6 +41,11 @@ public:
     /// 3) Ditto, in the jailed loolwsd process
     enum class Kind { ToClient, ToPrisoner, ToMaster };
 
+    /// We have two types of password protected documents
+    /// 1) Documents which require password to view
+    /// 2) Document which require password to modify
+    enum class PasswordType { ToView, ToModify };
+
     const std::string& getId() const { return _id; }
     const std::string& getName() const { return _name; }
     bool isDisconnected() const { return _disconnected; }
@@ -103,6 +108,21 @@ protected:
     // The Jailed document path.
     std::string _jailedFilePath;
 
+    // Password provided, if any, to open the document
+    std::string _docPassword;
+
+    // If password is provided or not
+    bool _isDocPasswordProvided;
+
+    // Whether document has been opened succesfuly
+    bool _isDocLoaded;
+
+    // Whether document is password protected
+    bool _isDocPasswordProtected;
+
+    // Whether password is required to view the document, or modify it
+    PasswordType _docPasswordType;
+
     /// Document options: a JSON string, containing options (rendering, also possibly load in the future).
     std::string _docOptions;
 
diff --git a/loolwsd/MasterProcessSession.cpp b/loolwsd/MasterProcessSession.cpp
index de04450..d9b4f33 100644
--- a/loolwsd/MasterProcessSession.cpp
+++ b/loolwsd/MasterProcessSession.cpp
@@ -125,6 +125,31 @@ bool MasterProcessSession::_handleInput(const char *buffer, int length)
 
         if (_kind == Kind::ToPrisoner)
         {
+            if (tokens[0] == "error:")
+            {
+                std::string errorCommand;
+                std::string errorKind;
+                if (getTokenString(tokens[1], "cmd", errorCommand) &&
+                    getTokenString(tokens[2], "kind", errorKind) )
+                {
+                    if (errorCommand == "load")
+                    {
+                        if (errorKind == "passwordrequired:to-view" ||
+                            errorKind == "passwordrequired:to-modify" ||
+                            errorKind == "wrongpassword")
+                        {
+                            _isDocPasswordProtected = true;
+                            // Reset docURL so that client can send another load request with password
+                            peer->_docURL = "";
+                            // disconnect 'ToPrisoner' after letting client know that password is required
+                            forwardToPeer(buffer, length);
+                            LOOLSession::disconnect();
+                            return false;
+                        }
+                    }
+                }
+            }
+
             if (tokens[0] == "curpart:" &&
                 tokens.count() == 2 &&
                 getTokenInteger(tokens[1], "part", _curPart))
@@ -157,7 +182,7 @@ bool MasterProcessSession::_handleInput(const char *buffer, int length)
             }
         }
 
-        if (_kind == Kind::ToPrisoner && peer && peer->_tileCache)
+        if (_kind == Kind::ToPrisoner && peer && peer->_tileCache && !_isDocPasswordProtected)
         {
             if (tokens[0] == "tile:")
             {
@@ -789,6 +814,9 @@ void MasterProcessSession::dispatchChild()
     if (_loadPart >= 0)
         oss << " part=" + std::to_string(_loadPart);
 
+    if (_isDocPasswordProvided)
+        oss << " password=" << _docPassword;
+
     if (!_docOptions.empty())
         oss << " options=" << _docOptions;
 


More information about the Libreoffice-commits mailing list