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 <[email protected]> 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 <[email protected]> Tested-by: Ashod Nakashian <[email protected]> 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; _______________________________________________ Libreoffice-commits mailing list [email protected] https://lists.freedesktop.org/mailman/listinfo/libreoffice-commits
