diff --git a/web/documentserver-example/nodejs/app.js b/web/documentserver-example/nodejs/app.js index f386c875..e95fec7b 100644 --- a/web/documentserver-example/nodejs/app.js +++ b/web/documentserver-example/nodejs/app.js @@ -30,6 +30,7 @@ const bodyParser = require("body-parser"); const fileSystem = require("fs"); const formidable = require("formidable"); const syncRequest = require("sync-request"); +const jwt = require('jsonwebtoken'); const config = require('config'); const configServer = config.get('server'); const docManager = require("./helpers/docManager"); @@ -38,6 +39,10 @@ const fileUtility = require("./helpers/fileUtility"); const siteUrl = configServer.get('siteUrl'); const fileChoiceUrl = configServer.has('fileChoiceUrl') ? configServer.get('fileChoiceUrl') : ""; const plugins = config.get('plugins'); +const cfgSignatureEnable = configServer.get('token.enable'); +const cfgSignatureUseForRequest = configServer.get('token.useforrequest'); +const cfgSignatureSecretExpiresIn = configServer.get('token.expiresIn'); +const cfgSignatureSecret = configServer.get('token.secret'); process.env.NODE_TLS_REJECT_UNAUTHORIZED = "0"; @@ -395,6 +400,29 @@ app.post("/track", function (req, res) { }); }; + //checkjwt + if (cfgSignatureEnable && cfgSignatureUseForRequest) { + var checkJwtHeaderRes = documentService.checkJwtHeader(req); + if (checkJwtHeaderRes) { + if (checkJwtHeaderRes.payload) { + body = checkJwtHeaderRes.payload; + } + if (checkJwtHeaderRes.query) { + if (checkJwtHeaderRes.query.useraddress) { + userAddress = checkJwtHeaderRes.query.useraddress; + } + if (checkJwtHeaderRes.query.filename) { + fileName = fileUtility.getFileName(checkJwtHeaderRes.query.filename); + } + } + processTrack(res, body, fileName, userAddress); + } else { + res.write("{\"error\":1}"); + res.end(); + } + return; + } + if (req.body.hasOwnProperty("status")) { processTrack(res, req.body, fileName, userAddress); } else { @@ -479,6 +507,7 @@ app.get("/editor", function (req, res) { type: type, documentType: fileUtility.getFileType(fileName), key: key, + token: "", callbackUrl: docManager.getCallback(fileName), isEdit: canEdit && mode != "review", mode: canEdit && mode != "view" ? "edit" : "view", @@ -498,7 +527,18 @@ app.get("/editor", function (req, res) { } }; - res.render("editor", argss); + if (cfgSignatureEnable) { + app.render('config', argss, function(err, html){ + if (err) { + console.log(err); + } else { + argss.editor.token = jwt.sign(JSON.parse("{"+html+"}"), cfgSignatureSecret, {expiresIn: cfgSignatureSecretExpiresIn}); + } + res.render("editor", argss); + }); + } else { + res.render("editor", argss); + } } catch (ex) { console.log(ex); diff --git a/web/documentserver-example/nodejs/config/default.json b/web/documentserver-example/nodejs/config/default.json index b4457b37..9ad98e10 100644 --- a/web/documentserver-example/nodejs/config/default.json +++ b/web/documentserver-example/nodejs/config/default.json @@ -30,7 +30,16 @@ "name": "/public", "path": "public" } - ] + ], + "token": { + "enable": true, + "useforrequest": true, + "algorithmRequest": "HS256", + "authorizationHeader": "Authorization", + "authorizationHeaderPrefix": "Bearer ", + "secret": "secret", + "expiresIn": "5m" + } }, "plugins": { "url": "", diff --git a/web/documentserver-example/nodejs/helpers/documentService.js b/web/documentserver-example/nodejs/helpers/documentService.js index 40d97682..b309edc7 100644 --- a/web/documentserver-example/nodejs/helpers/documentService.js +++ b/web/documentserver-example/nodejs/helpers/documentService.js @@ -24,12 +24,22 @@ */ var path = require("path"); +var urlModule = require("url"); var urllib = require("urllib"); var xml2js = require("xml2js"); +var jwt = require("jsonwebtoken"); +var jwa = require("jwa"); var fileUtility = require("./fileUtility"); var guidManager = require("./guidManager"); var configServer = require('config').get('server'); var siteUrl = configServer.get('siteUrl'); +var cfgSignatureEnable = configServer.get('token.enable'); +var cfgSignatureUseForRequest = configServer.get('token.useforrequest'); +var cfgSignatureAuthorizationHeader = configServer.get('token.authorizationHeader'); +var cfgSignatureAuthorizationHeaderPrefix = configServer.get('token.authorizationHeaderPrefix'); +var cfgSignatureSecretExpiresIn = configServer.get('token.expiresIn'); +var cfgSignatureSecret = configServer.get('token.secret'); +var cfgSignatureSecretAlgorithmRequest = configServer.get('token.algorithmRequest'); var documentService = {}; @@ -64,12 +74,19 @@ documentService.getConvertedUri = function (documentUri, fromExtension, toExtens key: documentRevisionId }; - urllib.request(siteUrl + configServer.get('converterUrl'), + var uri = siteUrl + configServer.get('converterUrl'); + var headers = { + 'Content-Type': 'application/json' + }; + + if (cfgSignatureEnable && cfgSignatureUseForRequest) { + headers[cfgSignatureAuthorizationHeader] = cfgSignatureAuthorizationHeaderPrefix + this.fillJwtByUrl(uri, params); + } + + urllib.request(uri, { method: "POST", - headers: { - 'Content-Type': 'application/json' - }, + headers: headers, data: params }, callback); @@ -79,15 +96,22 @@ documentService.getExternalUri = function (fileStream, contentLength, contentTyp documentRevisionId = documentService.generateRevisionId(documentRevisionId); var urlTostorage = siteUrl + configServer.get('storageUrl') + "?key=" + documentRevisionId; + var headers = { + "Content-Type": contentType == null ? "application/octet-stream" : contentType, + "Content-Length": contentLength.toString(), + "charset": "utf-8" + }; + + if (cfgSignatureEnable && cfgSignatureUseForRequest) { + const hmac = jwa(cfgSignatureSecretAlgorithmRequest); + var payloadhash = hmac.sign(fileStream, cfgSignatureSecret); + headers[cfgSignatureAuthorizationHeader] = cfgSignatureAuthorizationHeaderPrefix + this.fillJwtByUrl(urlTostorage, undefined, undefined, payloadhash); + } urllib.request(urlTostorage, { method: "POST", - headers: { - "Content-Type": contentType == null ? "application/octet-stream" : contentType, - "Content-Length": contentLength.toString(), - "charset": "utf-8" - }, + headers: headers, data: fileStream }, function (err, data) { @@ -116,10 +140,10 @@ documentService.processConvertServiceResponceError = function (errorCode) { switch (errorCode) { case -20: - errorMessage = errorMessageTemplate + "vkey deciphering error"; + errorMessage = errorMessageTemplate + "Error encrypt signature"; break; case -8: - errorMessage = errorMessageTemplate + "Error document VKey"; + errorMessage = errorMessageTemplate + "Error document signature"; break; case -7: errorMessage = errorMessageTemplate + "Error document request"; @@ -207,15 +231,43 @@ documentService.commandRequest = function (method, documentRevisionId, callback) key: documentRevisionId }; - urllib.request(siteUrl + configServer.get('commandUrl'), + var uri = siteUrl + configServer.get('commandUrl'); + var headers = { + 'Content-Type': 'application/json' + }; + if (cfgSignatureEnable && cfgSignatureUseForRequest) { + headers[cfgSignatureAuthorizationHeader] = cfgSignatureAuthorizationHeaderPrefix + this.fillJwtByUrl(uri, params); + } + + urllib.request(uri, { method: "POST", - headers: { - 'Content-Type': 'application/json' - }, + headers: headers, data: params }, callback); }; +documentService.checkJwtHeader = function (req) { + var decoded = null; + var authorization = req.get(cfgSignatureAuthorizationHeader); + if (authorization && authorization.startsWith(cfgSignatureAuthorizationHeaderPrefix)) { + var token = authorization.substring(cfgSignatureAuthorizationHeaderPrefix.length); + try { + decoded = jwt.verify(token, cfgSignatureSecret); + } catch (err) { + console.log('checkJwtHeader error: name = ' + err.name + ' message = ' + err.message + ' token = ' + token) + } + } + return decoded; +} + +documentService.fillJwtByUrl = function (uri, opt_dataObject, opt_iss, opt_payloadhash) { + var parseObject = urlModule.parse(uri, true); + var payload = {query: parseObject.query, payload: opt_dataObject, payloadhash: opt_payloadhash}; + + var options = {algorithm: cfgSignatureSecretAlgorithmRequest, expiresIn: cfgSignatureSecretExpiresIn, issuer: opt_iss}; + return jwt.sign(payload, cfgSignatureSecret, options); +} + module.exports = documentService; diff --git a/web/documentserver-example/nodejs/package.json b/web/documentserver-example/nodejs/package.json index 6dc837a5..d5279a6d 100644 --- a/web/documentserver-example/nodejs/package.json +++ b/web/documentserver-example/nodejs/package.json @@ -20,6 +20,8 @@ "ejs": "~2.5.1", "express": "^4.14.1", "formidable": "^1.1.1", + "jsonwebtoken": "^7.1.9", + "jwa": "^1.1.4", "log4js": "^0.6.38", "serve-favicon": "~2.3.0", "sync-request": "^4.0.1", diff --git a/web/documentserver-example/nodejs/views/config.ejs b/web/documentserver-example/nodejs/views/config.ejs index 4fd59d93..e52d61e8 100644 --- a/web/documentserver-example/nodejs/views/config.ejs +++ b/web/documentserver-example/nodejs/views/config.ejs @@ -2,6 +2,7 @@ "height": "100%", "type": "<%= editor.type %>", "documentType": "<%= editor.documentType %>", +"token": "<%= editor.token %>", "document": { "title": "<%= file.name %>", "url": "<%= file.uri %>",