loolwsd/ChildProcessSession.cpp | 48 ------------------- loolwsd/ChildProcessSession.hpp | 4 - loolwsd/LOOLKit.cpp | 100 ++++++++++++++++++++++++++++++++++++++-- loolwsd/LOOLSession.hpp | 8 --- 4 files changed, 100 insertions(+), 60 deletions(-)
New commits: commit b71ebb8dfcead80197a482c2e8619dd3e3d768f3 Author: Pranav Kant <pran...@collabora.co.uk> Date: Mon Feb 8 01:23:45 2016 +0530 loolwsd: Ask for password for multiple views also This is possible by moving all the password handling logic to Document container class. When a user opens a password protected document the first time, it saves all possible data such as password, password type etc. Upon opening the same document again, password is matched with the cached password saved in the document container class before allowing the new view access to this document. Change-Id: Id1f2b6e06de806564bf865e83fed51b01c9a0fbc Reviewed-on: https://gerrit.libreoffice.org/22208 Reviewed-by: Ashod Nakashian <ashnak...@gmail.com> Tested-by: Ashod Nakashian <ashnak...@gmail.com> diff --git a/loolwsd/ChildProcessSession.cpp b/loolwsd/ChildProcessSession.cpp index a2e737f..5bfd320 100644 --- a/loolwsd/ChildProcessSession.cpp +++ b/loolwsd/ChildProcessSession.cpp @@ -309,7 +309,7 @@ ChildProcessSession::ChildProcessSession(const std::string& id, LibreOfficeKit* loKit, LibreOfficeKitDocument * loKitDocument, const std::string& jailId, - std::function<LibreOfficeKitDocument*(const std::string&, const std::string&)> onLoad, + std::function<LibreOfficeKitDocument*(const std::string&, const std::string&, const std::string&, bool)> onLoad, std::function<void(const std::string&)> onUnload) : LOOLSession(id, Kind::ToMaster, ws), _loKit(loKit), @@ -415,21 +415,6 @@ bool ChildProcessSession::_handleInput(const char *buffer, int length) } _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 (!_isDocLoaded) @@ -584,7 +569,7 @@ bool ChildProcessSession::loadDocument(const char * /*buffer*/, int /*length*/, assert(!_docURL.empty()); assert(!_jailedFilePath.empty()); - _loKitDocument = _onLoad(getId(), _jailedFilePath); + _loKitDocument = _onLoad(getId(), _jailedFilePath, _docPassword, _isDocPasswordProvided); if (!_loKitDocument) return false; @@ -611,11 +596,6 @@ 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; @@ -1330,30 +1310,6 @@ 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 259dccb..1187a63 100644 --- a/loolwsd/ChildProcessSession.hpp +++ b/loolwsd/ChildProcessSession.hpp @@ -64,7 +64,7 @@ public: LibreOfficeKit *loKit, LibreOfficeKitDocument * loKitDocument, const std::string& jailId, - std::function<LibreOfficeKitDocument*(const std::string&, const std::string&)> onLoad, + std::function<LibreOfficeKitDocument*(const std::string&, const std::string&, const std::string&, bool)> onLoad, std::function<void(const std::string&)> onUnload); virtual ~ChildProcessSession(); @@ -131,7 +131,7 @@ private: /// View ID, returned by createView() or 0 by default. int _viewId; int _clientPart; - std::function<LibreOfficeKitDocument*(const std::string&, const std::string&)> _onLoad; + std::function<LibreOfficeKitDocument*(const std::string&, const std::string&, const std::string&, bool)> _onLoad; std::function<void(const std::string&)> _onUnload; /// Statistics and activity tracking. Statistics _stats; diff --git a/loolwsd/LOOLKit.cpp b/loolwsd/LOOLKit.cpp index 703e30b..c8355a6 100644 --- a/loolwsd/LOOLKit.cpp +++ b/loolwsd/LOOLKit.cpp @@ -310,6 +310,11 @@ private: class Document { public: + /// 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 }; + Document(LibreOfficeKit *loKit, const std::string& jailId, const std::string& url) @@ -318,6 +323,11 @@ public: _jailId(jailId), _url(url), _loKitDocument(nullptr), + _docPassword(""), + _isDocPasswordProvided(false), + _isDocLoaded(false), + _isDocPasswordProtected(false), + _docPasswordType(PasswordType::ToView), _clientViews(0) { Log::info("Document ctor for url [" + _url + "] on child [" + _jailId + @@ -407,8 +417,8 @@ public: ws->setReceiveTimeout(0); auto session = std::make_shared<ChildProcessSession>(sessionId, ws, _loKit, _loKitDocument, _jailId, - [this](const std::string& id, const std::string& uri) { return onLoad(id, uri); }, - [this](const std::string& id) { onUnload(id); }); + [this](const std::string& id, const std::string& uri, const std::string& docPassword, bool isDocPasswordProvided) { return onLoad(id, uri, docPassword, isDocPasswordProvided); }, + [this](const std::string& id) { onUnload(id); }); // child -> 0, sessionId -> 1, PID -> 2 std::string hello("child " + sessionId + " " + std::to_string(Process::id())); session->sendTextFrame(hello); @@ -471,6 +481,30 @@ public: return !hasConnections(); } + /// Set Document password for given URL + void setDocumentPassword(int nPasswordType) + { + if (_isDocPasswordProtected && _isDocPasswordProvided) + { + // it means this is the second attempt with the wrong password; abort the load operation + _loKit->pClass->setDocumentPassword(_loKit, _jailedUrl.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, _jailedUrl.c_str(), _docPassword.c_str()); + else + _loKit->pClass->setDocumentPassword(_loKit, _jailedUrl.c_str(), nullptr); + } + + private: static std::string KitCallbackTypeToString (const int nType) @@ -523,7 +557,7 @@ private: break; case LOK_CALLBACK_DOCUMENT_PASSWORD: case LOK_CALLBACK_DOCUMENT_PASSWORD_TO_MODIFY: - session->setDocumentPassword(nType); + self->setDocumentPassword(nType); break; } } @@ -563,7 +597,7 @@ private: } /// Load a document (or view) and register callbacks. - LibreOfficeKitDocument* onLoad(const std::string& sessionId, const std::string& uri) + LibreOfficeKitDocument* onLoad(const std::string& sessionId, const std::string& uri, const std::string& docPassword, bool isDocPasswordProvided) { Log::info("Session " + sessionId + " is loading. " + std::to_string(_clientViews) + " views loaded."); const unsigned intSessionId = Util::decodeId(sessionId); @@ -577,6 +611,8 @@ private: return nullptr; } + auto session = it->second->getSession(); + if (_loKitDocument == nullptr) { // This is the first time we are loading the document @@ -592,9 +628,31 @@ private: // documentLoad will trigger callback, which needs to take the lock. lock.unlock(); + // Save the provided password with us and the jailed url + _isDocPasswordProvided = isDocPasswordProvided; + _docPassword = docPassword; + _jailedUrl = uri; + _isDocPasswordProtected = false; if ((_loKitDocument = _loKit->pClass->documentLoad(_loKit, uri.c_str())) == nullptr) { Log::error("Failed to load: " + uri + ", error: " + _loKit->pClass->getError(_loKit)); + + // Checking if wrong password or no password was reason for failure. + if (_isDocPasswordProtected) + { + if (!_isDocPasswordProvided) + { + std::string passwordFrame = "passwordrequired:"; + if (_docPasswordType == PasswordType::ToView) + passwordFrame += "to-view"; + else if (_docPasswordType == PasswordType::ToModify) + passwordFrame += "to-modify"; + session->sendTextFrame("error: cmd=load kind=" + passwordFrame); + } + else + session->sendTextFrame("error: cmd=load kind=wrongpassword"); + } + return nullptr; } @@ -617,6 +675,28 @@ private: _loKitDocument->pClass->registerCallback(_loKitDocument, DocumentCallback, this); } } + else + { + // Check if this document requires password + if (_isDocPasswordProtected) + { + if (!isDocPasswordProvided) + { + std::string passwordFrame = "passwordrequired:"; + if (_docPasswordType == PasswordType::ToView) + passwordFrame += "to-view"; + else if (_docPasswordType == PasswordType::ToModify) + passwordFrame += "to-modify"; + session->sendTextFrame("error: cmd=load kind=" + passwordFrame); + return nullptr; + } + else if (docPassword != _docPassword) + { + session->sendTextFrame("error: cmd=load kind=wrongpassword"); + return nullptr; + } + } + } ++_clientViews; return _loKitDocument; @@ -655,9 +735,21 @@ private: LibreOfficeKit *_loKit; const std::string _jailId; const std::string _url; + std::string _jailedUrl; LibreOfficeKitDocument *_loKitDocument; + // Document password provided + std::string _docPassword; + // Whether password was provided or not + bool _isDocPasswordProvided; + // Whether documet has been opened successfully + bool _isDocLoaded; + // Whether document is password protected + bool _isDocPasswordProtected; + // Whether password is required to view the document, or modify it + PasswordType _docPasswordType; + std::recursive_mutex _mutex; std::map<unsigned, std::shared_ptr<Connection>> _connections; std::atomic<unsigned> _clientViews; diff --git a/loolwsd/LOOLSession.hpp b/loolwsd/LOOLSession.hpp index 9bc7f85..6b57a96 100644 --- a/loolwsd/LOOLSession.hpp +++ b/loolwsd/LOOLSession.hpp @@ -41,11 +41,6 @@ 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; } @@ -120,9 +115,6 @@ protected: // 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; _______________________________________________ Libreoffice-commits mailing list libreoffice-comm...@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/libreoffice-commits