From 5b22fac214a9a4e8a2b9fa51d0086aaf73b759c2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Toma=C5=BE=20Vajngerl?= Date: Thu, 22 Nov 2018 15:12:32 +0100 Subject: [PATCH] Upload document to Vereign MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Save document to a input format (either PDF, ODT, DOCX) and send the document to Vereign using WOPI protocol. Change-Id: If9a7d88e91d07c7f1f831c01793f0f73d7a98131 Reviewed-on: https://gerrit.libreoffice.org/63839 Reviewed-by: Tomaž Vajngerl Tested-by: Tomaž Vajngerl --- kit/ChildSession.cpp | 145 ++++++++++++++++++++++++++++++- kit/ChildSession.hpp | 1 + loleaflet/js/toolbar.js | 1 + loleaflet/src/control/Signing.js | 28 ++++++ wsd/ClientSession.cpp | 3 +- 5 files changed, 176 insertions(+), 2 deletions(-) diff --git a/kit/ChildSession.cpp b/kit/ChildSession.cpp index 2af6b76c2..e5c758789 100644 --- a/kit/ChildSession.cpp +++ b/kit/ChildSession.cpp @@ -21,12 +21,19 @@ #include #include #include +#include #include #include #include +#include +#include +#include +#include +#include #include #include +#include #include "KitHelper.hpp" #include #include @@ -263,7 +270,8 @@ bool ChildSession::_handleInput(const char *buffer, int length) tokens[0] == "userinactive" || tokens[0] == "windowcommand" || tokens[0] == "asksignaturestatus" || - tokens[0] == "signdocument"); + tokens[0] == "signdocument" || + tokens[0] == "uploadsigneddocument"); if (tokens[0] == "clientzoom") { @@ -357,6 +365,10 @@ bool ChildSession::_handleInput(const char *buffer, int length) { askSignatureStatus(buffer, length, tokens); } + else if (tokens[0] == "uploadsigneddocument") + { + return uploadSignedDocument(buffer, length, tokens); + } else { assert(false && "Unknown command token."); @@ -366,6 +378,137 @@ bool ChildSession::_handleInput(const char *buffer, int length) return true; } +// add to common / tools +size_t getFileSize(const std::string& filename) +{ + return std::ifstream(filename, std::ifstream::ate | std::ifstream::binary).tellg(); +} + +std::string getMimeFromFileType(const std::string & fileType) +{ + if (fileType == "pdf") + return "application/pdf"; + else if (fileType == "odt") + return "application/vnd.oasis.opendocument.text"; + else if (fileType == "docx") + return "application/vnd.openxmlformats-officedocument.wordprocessingml.document"; + + return std::string(); +} + +bool ChildSession::uploadSignedDocument(const char* buffer, int length, const std::vector& /*tokens*/) +{ + std::string filename; + std::string wopiUrl; + std::string token; + std::string filetype; + + { // parse JSON + const std::string firstLine = getFirstLine(buffer, length); + + const char* data = buffer + firstLine.size() + 1; + const int size = length - firstLine.size() - 1; + std::string json(data, size); + + Poco::JSON::Parser parser; + Poco::JSON::Object::Ptr root = parser.parse(json).extract(); + + filename = JsonUtil::getJSONValue(root, "filename"); + wopiUrl = JsonUtil::getJSONValue(root, "wopiUrl"); + token = JsonUtil::getJSONValue(root, "token"); + filetype = JsonUtil::getJSONValue(root, "type"); + } + + if (filetype.empty() || filename.empty() || wopiUrl.empty() || token.empty()) + { + sendTextFrame("error: cmd=uploadsigneddocument kind=syntax"); + return false; + } + + std::string mimetype = getMimeFromFileType(filetype); + if (mimetype.empty()) + { + sendTextFrame("error: cmd=uploadsigneddocument kind=syntax"); + return false; + } + const std::string tmpDir = FileUtil::createRandomDir(JAILED_DOCUMENT_ROOT); + const Poco::Path filenameParam(filename); + const std::string url = JAILED_DOCUMENT_ROOT + tmpDir + "/" + filenameParam.getFileName(); + + { + std::unique_lock lock(_docManager.getDocumentMutex()); + + getLOKitDocument()->saveAs(url.c_str(), + filetype.empty() ? nullptr : filetype.c_str(), + nullptr); + } + + Authorization authorization(Authorization::Type::Token, token); + Poco::URI uriObject(wopiUrl + "/" + filename + "/contents"); + + authorization.authorizeURI(uriObject); + + try + { + Poco::Net::initializeSSL(); + Poco::Net::Context::Params sslClientParams; + sslClientParams.verificationMode = Poco::Net::Context::VERIFY_NONE; + Poco::SharedPtr consoleClientHandler = new Poco::Net::KeyConsoleHandler(false); + Poco::SharedPtr invalidClientCertHandler = new Poco::Net::AcceptCertificateHandler(false); + Poco::Net::Context::Ptr sslClientContext = new Poco::Net::Context(Poco::Net::Context::CLIENT_USE, sslClientParams); + Poco::Net::SSLManager::instance().initializeClient(consoleClientHandler, invalidClientCertHandler, sslClientContext); + + std::unique_ptr psession; + psession.reset(new Poco::Net::HTTPSClientSession( + uriObject.getHost(), + uriObject.getPort(), + Poco::Net::SSLManager::instance().defaultClientContext())); + + Poco::Net::HTTPRequest request(Poco::Net::HTTPRequest::HTTP_POST, uriObject.getPathAndQuery(), Poco::Net::HTTPMessage::HTTP_1_1); + request.set("User-Agent", WOPI_AGENT_STRING); + authorization.authorizeRequest(request); + + request.set("X-WOPI-Override", "PUT"); + + const size_t filesize = getFileSize(url); + + request.setContentType(mimetype); + request.setContentLength(filesize); + + std::ostream& httpOutputStream = psession->sendRequest(request); + + std::ifstream inputFileStream(url); + Poco::StreamCopier::copyStream(inputFileStream, httpOutputStream); + + Poco::Net::HTTPResponse response; + std::istream& responseStream = psession->receiveResponse(response); + + std::ostringstream outputStringStream; + Poco::StreamCopier::copyStream(responseStream, outputStringStream); + std::string responseString = outputStringStream.str(); + + if (response.getStatus() != Poco::Net::HTTPResponse::HTTP_OK && + response.getStatus() != Poco::Net::HTTPResponse::HTTP_CREATED) + { + LOG_ERR("Upload signed document HTTP Response Error: " << response.getStatus() << ' ' << response.getReason()); + + sendTextFrame("error: cmd=uploadsigneddocument kind=httpresponse"); + + return false; + } + } + catch (const Poco::Exception& pocoException) + { + LOG_ERR("Upload signed document Exception: " + pocoException.displayText()); + + sendTextFrame("error: cmd=uploadsigneddocument kind=failure"); + + return false; + } + + return true; +} + bool ChildSession::loadDocument(const char * /*buffer*/, int /*length*/, const std::vector& tokens) { int part = -1; diff --git a/kit/ChildSession.hpp b/kit/ChildSession.hpp index 7b38ec904..c9b0d1f42 100644 --- a/kit/ChildSession.hpp +++ b/kit/ChildSession.hpp @@ -263,6 +263,7 @@ private: bool sendWindowCommand(const char* buffer, int length, const std::vector& tokens); bool signDocumentContent(const char* buffer, int length, const std::vector& tokens); bool askSignatureStatus(const char* buffer, int length, const std::vector& tokens); + bool uploadSignedDocument(const char* buffer, int length, const std::vector& tokens); void rememberEventsForInactiveUser(const int type, const std::string& payload); diff --git a/loleaflet/js/toolbar.js b/loleaflet/js/toolbar.js index 145d14e5e..89d5c92ce 100644 --- a/loleaflet/js/toolbar.js +++ b/loleaflet/js/toolbar.js @@ -954,6 +954,7 @@ function initNormalToolbar(toolItems) { {type: 'html', id: 'left'}, {type: 'html', id: 'logo', html: '

Vereign

'}, {type: 'button', id: 'sign', caption: 'Sign', img: '', hint: _('Sign document')}, + {type: 'button', id: 'upload', caption: 'Upload', img: '', hint: _('Upload document')}, {type: 'break' }, {type: 'html', id: 'identity-label', html: 'Identity:'}, {type: 'html', id: 'identity', html: 'N/A'}, diff --git a/loleaflet/src/control/Signing.js b/loleaflet/src/control/Signing.js index af890a434..f34590bd0 100644 --- a/loleaflet/src/control/Signing.js +++ b/loleaflet/src/control/Signing.js @@ -86,11 +86,13 @@ function adjustUIState() { w2ui['document-signing-bar'].show('passport'); w2ui['document-signing-bar'].show('current-passport'); w2ui['document-signing-bar'].show('sign'); + w2ui['document-signing-bar'].show('upload'); } else { w2ui['document-signing-bar'].show('passport'); w2ui['document-signing-bar'].hide('current-passport'); w2ui['document-signing-bar'].hide('sign'); + w2ui['document-signing-bar'].hide('upload'); } } else { @@ -103,6 +105,7 @@ function adjustUIState() { w2ui['document-signing-bar'].hide('identity-label'); w2ui['document-signing-bar'].hide('identity'); w2ui['document-signing-bar'].hide('sign'); + w2ui['document-signing-bar'].hide('upload'); w2ui['document-signing-bar'].hide('passport'); w2ui['document-signing-bar'].hide('current-passport'); } @@ -244,6 +247,31 @@ L.Map.include({ } } }, + uploadToVereign: function() { + if (library == null) { + return; + } + var map = this; + var filename = 'fileId'; // need to read the filename + + library.getPassports(filename).then(function(result) { + if (isSuccess(result)) { + var resultArray = result.data; + for (var i = 0; i < resultArray.length; i++) { + if (currentPassport.uuid == resultArray[i].PassportUUID) { + var jsonRequest = { + filename: filename, + wopiUrl: vereignURL + '/wopi/files', + token: resultArray[i].AccessToken, + type: 'pdf' + }; + var blob = new Blob(['uploadsigneddocument\n', JSON.stringify(jsonRequest)]); + map._socket.sendMessage(blob); + } + } + } + }); + }, signingLogout: function() { if (library) { library.logout().then(function(result) { diff --git a/wsd/ClientSession.cpp b/wsd/ClientSession.cpp index 7d4b0b438..4dcc03c75 100644 --- a/wsd/ClientSession.cpp +++ b/wsd/ClientSession.cpp @@ -173,7 +173,8 @@ bool ClientSession::_handleInput(const char *buffer, int length) tokens[0] != "paintwindow" && tokens[0] != "windowcommand" && tokens[0] != "signdocument" && - tokens[0] != "asksignaturestatus") + tokens[0] != "asksignaturestatus" && + tokens[0] != "uploadsigneddocument") { sendTextFrame("error: cmd=" + tokens[0] + " kind=unknown"); return false;