From 36036578c645474aea30a6c869fff5a3f657d965 Mon Sep 17 00:00:00 2001 From: dmitry <dmitry.zyryanov@execution.su> Date: Wed, 24 Feb 2021 12:38:37 +0700 Subject: [PATCH 1/9] fix for undefined to string conversion --- common/Utils.js | 10 ++++++++++ portal/server/common/RequestResponseHelper.js | 3 ++- 2 files changed, 12 insertions(+), 1 deletion(-) create mode 100644 common/Utils.js diff --git a/common/Utils.js b/common/Utils.js new file mode 100644 index 0000000..6f62723 --- /dev/null +++ b/common/Utils.js @@ -0,0 +1,10 @@ +function JSONStringifyOrUndefined(x) { + return typeof x === 'undefined' + ? 'undefined' + : JSON.stringify(x); +} + + +module.exports = { + JSONStringifyOrUndefined, +}; diff --git a/portal/server/common/RequestResponseHelper.js b/portal/server/common/RequestResponseHelper.js index 2231d91..17fe817 100644 --- a/portal/server/common/RequestResponseHelper.js +++ b/portal/server/common/RequestResponseHelper.js @@ -1,5 +1,6 @@ const HttpStatusCodes = require('http-status-codes'); const ServerError = require('./errors/ServerError'); +const Utils = require('hrbot-common/Utils'); const DEFAULT_REQUEST_LOG_LEVEL = 'verbose'; @@ -60,7 +61,7 @@ class RequestResponseHelper { static writeResponseLog(logger, requestId, response, json, logLevel) { const { statusCode } = response; - const jsonStr = JSON.stringify(json); + const jsonStr = Utils.JSONStringifyOrUndefined(json); logger.log( logLevel || DEFAULT_RESPONSE_LOG_LEVEL, `RESPONSE (${requestId}) (statusCode = ${statusCode}; json = ${RequestResponseHelper._limitLogString(jsonStr, 1000)})`, -- GitLab From 4af4b9bea340019b3b102e23eec14ff7cf1fd27b Mon Sep 17 00:00:00 2001 From: dmitry <dmitry.zyryanov@execution.su> Date: Wed, 24 Feb 2021 12:45:23 +0700 Subject: [PATCH 2/9] fix for undefined to string conversion potential bug --- bot/index.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/bot/index.js b/bot/index.js index 5bd5aa6..4866a0b 100644 --- a/bot/index.js +++ b/bot/index.js @@ -2,6 +2,7 @@ const TelegramBot = require('node-telegram-bot-api'); const express = require('express'); const bodyParser = require('body-parser'); const { config, models, LoggersContainer } = require('hrbot-common'); +const Utils = require('hrbot-common/Utils'); const ServicesFacade = require('./ServicesFacade'); @@ -30,7 +31,7 @@ async function botSetWebHook(bot, botUrl) { logger.info('getWebHookInfo error %O', error); } if (!webHookResult) { - throw new Error(`Failed to set webhook, info=${JSON.stringify(webHookInfo)}`); + throw new Error(`Failed to set webhook, info=${Utils.JSONStringifyOrUndefined(webHookInfo)}`); } if (!webHookInfo) { throw new Error(`Failed to get webhook info, webhook result=${JSON.stringify(webHookResult)}`); -- GitLab From 6dedcc62b36a2ec77e8b9baa8c33bb78ba45aa12 Mon Sep 17 00:00:00 2001 From: dmitry <dmitry.zyryanov@execution.su> Date: Wed, 24 Feb 2021 12:46:03 +0700 Subject: [PATCH 3/9] logging code codestyle --- portal/server/common/RequestResponseHelper.js | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/portal/server/common/RequestResponseHelper.js b/portal/server/common/RequestResponseHelper.js index 17fe817..ac5620f 100644 --- a/portal/server/common/RequestResponseHelper.js +++ b/portal/server/common/RequestResponseHelper.js @@ -49,7 +49,10 @@ class RequestResponseHelper { const bodyAsString = JSON.stringify(body); logger.log( logLevel || DEFAULT_REQUEST_LOG_LEVEL, - `REQUEST (${requestId}) (method = "${method}"; URL = "${originalUrl}"; params = "${paramsAsString}"; body = ${RequestResponseHelper._limitLogString(bodyAsString, 1000)})`, + 'REQUEST (%d) method = "%s"; URL = "%s"; params = "%s"; body = %s', + requestId, method, originalUrl, + paramsAsString, + RequestResponseHelper._limitLogString(bodyAsString, 1000), ); } @@ -64,7 +67,10 @@ class RequestResponseHelper { const jsonStr = Utils.JSONStringifyOrUndefined(json); logger.log( logLevel || DEFAULT_RESPONSE_LOG_LEVEL, - `RESPONSE (${requestId}) (statusCode = ${statusCode}; json = ${RequestResponseHelper._limitLogString(jsonStr, 1000)})`, + 'RESPONSE (%d) statusCode = %d; json = %s', + requestId, + statusCode, + RequestResponseHelper._limitLogString(jsonStr, 1000), ); } -- GitLab From 17d580c442a6efa83b0421df5e59536fa3f16288 Mon Sep 17 00:00:00 2001 From: dmitry <dmitry.zyryanov@execution.su> Date: Wed, 24 Feb 2021 14:17:29 +0700 Subject: [PATCH 4/9] getting the user --- portal/server/common/RequestResponseHelper.js | 1 - portal/server/common/errors/NotFoundError.js | 13 ++++++ portal/server/controllers/BaseController.js | 40 +++++++++++++++++++ .../server/controllers/ControllersFacade.js | 4 ++ portal/server/controllers/UsersController.js | 24 +++++++++++ 5 files changed, 81 insertions(+), 1 deletion(-) create mode 100644 portal/server/common/errors/NotFoundError.js create mode 100644 portal/server/controllers/BaseController.js create mode 100644 portal/server/controllers/UsersController.js diff --git a/portal/server/common/RequestResponseHelper.js b/portal/server/common/RequestResponseHelper.js index ac5620f..d21a3e4 100644 --- a/portal/server/common/RequestResponseHelper.js +++ b/portal/server/common/RequestResponseHelper.js @@ -78,7 +78,6 @@ class RequestResponseHelper { const errorHttpStatusCode = error instanceof ServerError ? error.httpStatusCode : HttpStatusCodes.INTERNAL_SERVER_ERROR; - RequestResponseHelper.sendErrorAndStatusCode(response, error, errorHttpStatusCode); } } diff --git a/portal/server/common/errors/NotFoundError.js b/portal/server/common/errors/NotFoundError.js new file mode 100644 index 0000000..01f67fd --- /dev/null +++ b/portal/server/common/errors/NotFoundError.js @@ -0,0 +1,13 @@ +const HttpStatusCodes = require('http-status-codes'); +const ServerError = require('./ServerError'); + + +class NotFoundError extends ServerError { + constructor(message) { + super(message || 'Not found', HttpStatusCodes.NOT_FOUND); + this.name = 'NotFoundError'; + } +} + + +module.exports = NotFoundError; diff --git a/portal/server/controllers/BaseController.js b/portal/server/controllers/BaseController.js new file mode 100644 index 0000000..02487df --- /dev/null +++ b/portal/server/controllers/BaseController.js @@ -0,0 +1,40 @@ +const RequestResponseHelper = require('../common/RequestResponseHelper'); + + +class BaseController { + constructor(services, logger) { + this._services = services; + this._logger = logger; + } + + _sendOk(response) { + RequestResponseHelper.sendOk(response); + } + + _sendJson(response, data, statusCode) { + RequestResponseHelper.sendJson(response, data, statusCode); + } + + _sendError(response, error) { + RequestResponseHelper.sendError( + response, error, + ); + } + + _tryRouteHandler(routeHandler) { + return async (request, response) => { + try { + await routeHandler(request, response); + } catch (e) { + this._sendError(response, e); + } + }; + } + + _wrapHandler(method) { + return this._tryRouteHandler(method.bind(this)); + } +} + + +module.exports = BaseController; diff --git a/portal/server/controllers/ControllersFacade.js b/portal/server/controllers/ControllersFacade.js index 06ee36f..84ea8f1 100644 --- a/portal/server/controllers/ControllersFacade.js +++ b/portal/server/controllers/ControllersFacade.js @@ -1,16 +1,20 @@ const express = require('express'); const HttpStatusCodes = require('http-status-codes'); const RequestResponseHelper = require('../common/RequestResponseHelper'); +const UsersController = require('./UsersController'); class ControllersFacade { constructor(services, Logger) { this._logger = Logger.getLogger('ControllersFacade'); + this.usersController = new UsersController(services, Logger.getLogger('UsersController')); } createRouter() { const router = express(); + router.use('/users', this.usersController.createRouter()); + router.use(this._notFoundHandler.bind(this)); return router; diff --git a/portal/server/controllers/UsersController.js b/portal/server/controllers/UsersController.js new file mode 100644 index 0000000..ead90de --- /dev/null +++ b/portal/server/controllers/UsersController.js @@ -0,0 +1,24 @@ +const Express = require('express'); +const BaseController = require('./BaseController'); +const NotFoundError = require('../common/errors/NotFoundError'); + + +class UsersController extends BaseController { + async getUser(req, res) { + const userId = +req.params.userId; + const user = await this._services.usersService.getUserById(userId); + if (!user) { + throw new NotFoundError(); + } + this._sendJson(res, user); + } + + createRouter() { + const router = new Express(); + router.get('/:userId', this._wrapHandler(this.getUser)); + return router; + } +} + + +module.exports = UsersController; -- GitLab From 05d60037a0b7f2b3e37dce1b5779edb4383cf577 Mon Sep 17 00:00:00 2001 From: dmitry <dmitry.zyryanov@execution.su> Date: Wed, 24 Feb 2021 16:07:44 +0700 Subject: [PATCH 5/9] do not return internal server errors to the client by default --- portal/server/common/RequestResponseHelper.js | 23 ++++++++----------- portal/server/common/errors/NotFoundError.js | 4 ++-- portal/server/common/errors/ServerError.js | 4 ++-- .../requestResponseLoggerMiddleware.js | 3 +-- 4 files changed, 15 insertions(+), 19 deletions(-) diff --git a/portal/server/common/RequestResponseHelper.js b/portal/server/common/RequestResponseHelper.js index d21a3e4..9fffeb9 100644 --- a/portal/server/common/RequestResponseHelper.js +++ b/portal/server/common/RequestResponseHelper.js @@ -24,17 +24,6 @@ class RequestResponseHelper { response.end(); } - static sendErrorAndStatusCode(response, error, errorHttpStatusCode) { - const statusCode = errorHttpStatusCode || HttpStatusCodes.INTERNAL_SERVER_ERROR; - const errorMessage = (error && error.message) ? error.message : 'Unknown error'; - const errorObject = (error && error.errorObject) ? error.errorObject : {}; - - response.jsError = error; - response.status(statusCode); - response.json({ error: errorMessage, errorObject }); - response.end(); - } - static _limitLogString(str, maxLen) { return str.length > maxLen ? `${str.slice(0, maxLen)}[${maxLen}/${str.length} chars logged]` @@ -75,10 +64,18 @@ class RequestResponseHelper { } static sendError(response, error) { - const errorHttpStatusCode = error instanceof ServerError + const statusCode = error instanceof ServerError ? error.httpStatusCode : HttpStatusCodes.INTERNAL_SERVER_ERROR; - RequestResponseHelper.sendErrorAndStatusCode(response, error, errorHttpStatusCode); + const errorObject = error instanceof ServerError + ? error.errorObject + : {}; + response.jsError = error; + response.status(statusCode); + // response.json({ ...errorObject, _debug: error }); sending internal server error to the client + response.json(errorObject); + response.end(); + } } diff --git a/portal/server/common/errors/NotFoundError.js b/portal/server/common/errors/NotFoundError.js index 01f67fd..7e758d6 100644 --- a/portal/server/common/errors/NotFoundError.js +++ b/portal/server/common/errors/NotFoundError.js @@ -3,8 +3,8 @@ const ServerError = require('./ServerError'); class NotFoundError extends ServerError { - constructor(message) { - super(message || 'Not found', HttpStatusCodes.NOT_FOUND); + constructor(error, message) { + super(error, message || 'Not found', HttpStatusCodes.NOT_FOUND); this.name = 'NotFoundError'; } } diff --git a/portal/server/common/errors/ServerError.js b/portal/server/common/errors/ServerError.js index e4704b9..26d9051 100644 --- a/portal/server/common/errors/ServerError.js +++ b/portal/server/common/errors/ServerError.js @@ -2,8 +2,8 @@ const HttpStatusCodes = require('http-status-codes'); class ServerError extends Error { - constructor(message, httpStatusCode, errorObject = null) { - super(message || 'Unknown server error'); + constructor(errorObject = null, message, httpStatusCode) { + super(message || 'Server error'); this.name = 'ServerError'; this.httpStatusCode = httpStatusCode || HttpStatusCodes.INTERNAL_SERVER_ERROR; this.errorObject = errorObject; diff --git a/portal/server/middlewares/requestResponseLoggerMiddleware.js b/portal/server/middlewares/requestResponseLoggerMiddleware.js index 57cf5ec..040c84f 100644 --- a/portal/server/middlewares/requestResponseLoggerMiddleware.js +++ b/portal/server/middlewares/requestResponseLoggerMiddleware.js @@ -22,8 +22,7 @@ function requestResponseLoggerMiddleware(logger) { if (res.jsError.stack) { logger.debug(res.jsError.stack); } else { - logger.debug('Non-error object error:', res.jsError); - logger.debug(res.jsError); + logger.debug('No-stack object error: %O', res.jsError); } } oldEnd.apply(res, args); -- GitLab From 3c935065c45a038249ec95513248b0586f399650 Mon Sep 17 00:00:00 2001 From: dmitry <dmitry.zyryanov@execution.su> Date: Wed, 24 Feb 2021 16:58:12 +0700 Subject: [PATCH 6/9] logging error property renamed --- portal/server/common/RequestResponseHelper.js | 2 +- .../middlewares/requestResponseLoggerMiddleware.js | 9 +++++---- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/portal/server/common/RequestResponseHelper.js b/portal/server/common/RequestResponseHelper.js index 9fffeb9..e7cc053 100644 --- a/portal/server/common/RequestResponseHelper.js +++ b/portal/server/common/RequestResponseHelper.js @@ -70,7 +70,7 @@ class RequestResponseHelper { const errorObject = error instanceof ServerError ? error.errorObject : {}; - response.jsError = error; + response.loggingError = error; response.status(statusCode); // response.json({ ...errorObject, _debug: error }); sending internal server error to the client response.json(errorObject); diff --git a/portal/server/middlewares/requestResponseLoggerMiddleware.js b/portal/server/middlewares/requestResponseLoggerMiddleware.js index 040c84f..a7590b2 100644 --- a/portal/server/middlewares/requestResponseLoggerMiddleware.js +++ b/portal/server/middlewares/requestResponseLoggerMiddleware.js @@ -18,11 +18,12 @@ function requestResponseLoggerMiddleware(logger) { const { statusCode } = res; const isOk = statusCode >= 200 && statusCode < 300; RequestResponseHelper.writeResponseLog(logger, requestId, res, resJson, isOk ? 'verbose' : 'error'); - if (res.jsError) { - if (res.jsError.stack) { - logger.debug(res.jsError.stack); + const { loggingError } = res; + if (loggingError) { + if (loggingError.stack) { + logger.debug(loggingError.stack); } else { - logger.debug('No-stack object error: %O', res.jsError); + logger.debug('No-stack object error: %O', loggingError); } } oldEnd.apply(res, args); -- GitLab From 14f4f1ffa3ae748f1a3a73147b820fd68ad51f58 Mon Sep 17 00:00:00 2001 From: dmitry <dmitry.zyryanov@execution.su> Date: Wed, 24 Feb 2021 17:03:13 +0700 Subject: [PATCH 7/9] sending searchable request id with error --- portal/server/common/RequestResponseHelper.js | 7 +++++-- .../server/middlewares/requestResponseLoggerMiddleware.js | 3 +++ 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/portal/server/common/RequestResponseHelper.js b/portal/server/common/RequestResponseHelper.js index e7cc053..45df75e 100644 --- a/portal/server/common/RequestResponseHelper.js +++ b/portal/server/common/RequestResponseHelper.js @@ -72,8 +72,11 @@ class RequestResponseHelper { : {}; response.loggingError = error; response.status(statusCode); - // response.json({ ...errorObject, _debug: error }); sending internal server error to the client - response.json(errorObject); + response.json({ + ...errorObject, + _longId: response.loggingLongId, + // _debugError: error, // sending internal server error to the client + }); response.end(); } diff --git a/portal/server/middlewares/requestResponseLoggerMiddleware.js b/portal/server/middlewares/requestResponseLoggerMiddleware.js index a7590b2..afc9172 100644 --- a/portal/server/middlewares/requestResponseLoggerMiddleware.js +++ b/portal/server/middlewares/requestResponseLoggerMiddleware.js @@ -7,6 +7,9 @@ function requestResponseLoggerMiddleware(logger) { const oldJson = res.json; const requestId = RequestResponseHelper.generateIdAndWriteRequestLog(logger, req); + res.loggingRequestId = requestId; + res.loggingLongId = `${+new Date()}-${requestId}`; + let resJson; res.json = (...args) => { -- GitLab From 1b00849574acb2db9399eb90065d8c5ee32198d8 Mon Sep 17 00:00:00 2001 From: dmitry <dmitry.zyryanov@execution.su> Date: Wed, 24 Feb 2021 17:12:06 +0700 Subject: [PATCH 8/9] request/response logging moved to the logging middleware --- portal/server/common/RequestResponseHelper.js | 43 ---------------- .../requestResponseLoggerMiddleware.js | 49 ++++++++++++++++++- 2 files changed, 47 insertions(+), 45 deletions(-) diff --git a/portal/server/common/RequestResponseHelper.js b/portal/server/common/RequestResponseHelper.js index 45df75e..a7ef81e 100644 --- a/portal/server/common/RequestResponseHelper.js +++ b/portal/server/common/RequestResponseHelper.js @@ -1,18 +1,8 @@ const HttpStatusCodes = require('http-status-codes'); const ServerError = require('./errors/ServerError'); -const Utils = require('hrbot-common/Utils'); -const DEFAULT_REQUEST_LOG_LEVEL = 'verbose'; -const DEFAULT_RESPONSE_LOG_LEVEL = 'verbose'; - -let NEXT_REQUEST_ID = 1; - class RequestResponseHelper { - static _generateRequestId() { - return NEXT_REQUEST_ID++; - } - static sendOk(response) { response.status(HttpStatusCodes.OK); response.end(); @@ -30,39 +20,6 @@ class RequestResponseHelper { : str; } - static writeRequestLog(logger, requestId, request, logLevel) { - const { - method, originalUrl, params, body, - } = request; - const paramsAsString = JSON.stringify(params); - const bodyAsString = JSON.stringify(body); - logger.log( - logLevel || DEFAULT_REQUEST_LOG_LEVEL, - 'REQUEST (%d) method = "%s"; URL = "%s"; params = "%s"; body = %s', - requestId, method, originalUrl, - paramsAsString, - RequestResponseHelper._limitLogString(bodyAsString, 1000), - ); - } - - static generateIdAndWriteRequestLog(logger, request, logLevel) { - const requestId = RequestResponseHelper._generateRequestId(); - RequestResponseHelper.writeRequestLog(logger, requestId, request, logLevel); - return requestId; - } - - static writeResponseLog(logger, requestId, response, json, logLevel) { - const { statusCode } = response; - const jsonStr = Utils.JSONStringifyOrUndefined(json); - logger.log( - logLevel || DEFAULT_RESPONSE_LOG_LEVEL, - 'RESPONSE (%d) statusCode = %d; json = %s', - requestId, - statusCode, - RequestResponseHelper._limitLogString(jsonStr, 1000), - ); - } - static sendError(response, error) { const statusCode = error instanceof ServerError ? error.httpStatusCode diff --git a/portal/server/middlewares/requestResponseLoggerMiddleware.js b/portal/server/middlewares/requestResponseLoggerMiddleware.js index afc9172..d3c8b07 100644 --- a/portal/server/middlewares/requestResponseLoggerMiddleware.js +++ b/portal/server/middlewares/requestResponseLoggerMiddleware.js @@ -1,11 +1,56 @@ const RequestResponseHelper = require('../common/RequestResponseHelper'); +const Utils = require('hrbot-common/Utils'); + + +const DEFAULT_REQUEST_LOG_LEVEL = 'verbose'; +const DEFAULT_RESPONSE_LOG_LEVEL = 'verbose'; function requestResponseLoggerMiddleware(logger) { + + let NEXT_REQUEST_ID = 1; + + function generateRequestId() { + return NEXT_REQUEST_ID++; + } + + function writeRequestLog(logger, requestId, request, logLevel) { + const { + method, originalUrl, params, body, + } = request; + const paramsAsString = JSON.stringify(params); + const bodyAsString = JSON.stringify(body); + logger.log( + logLevel || DEFAULT_REQUEST_LOG_LEVEL, + 'REQUEST (%d) method = "%s"; URL = "%s"; params = "%s"; body = %s', + requestId, method, originalUrl, + paramsAsString, + RequestResponseHelper._limitLogString(bodyAsString, 1000), + ); + } + + function writeResponseLog(logger, requestId, response, json, logLevel) { + const { statusCode, loggingLongId } = response; + const jsonStr = Utils.JSONStringifyOrUndefined(json); + logger.log( + logLevel || DEFAULT_RESPONSE_LOG_LEVEL, + 'RESPONSE (%d) %s statusCode = %d; json = %s', + requestId, loggingLongId, + statusCode, + RequestResponseHelper._limitLogString(jsonStr, 1000), + ); + } + + function generateIdAndWriteRequestLog(logger, request, logLevel) { + const requestId = generateRequestId(); + writeRequestLog(logger, requestId, request, logLevel); + return requestId; + } + return (req, res, next) => { const oldEnd = res.end; const oldJson = res.json; - const requestId = RequestResponseHelper.generateIdAndWriteRequestLog(logger, req); + const requestId = generateIdAndWriteRequestLog(logger, req); res.loggingRequestId = requestId; res.loggingLongId = `${+new Date()}-${requestId}`; @@ -20,7 +65,7 @@ function requestResponseLoggerMiddleware(logger) { res.end = (...args) => { const { statusCode } = res; const isOk = statusCode >= 200 && statusCode < 300; - RequestResponseHelper.writeResponseLog(logger, requestId, res, resJson, isOk ? 'verbose' : 'error'); + writeResponseLog(logger, requestId, res, resJson, isOk ? 'verbose' : 'error'); const { loggingError } = res; if (loggingError) { if (loggingError.stack) { -- GitLab From 8a0a4df59765c03fb58b485cde5aac45e406add9 Mon Sep 17 00:00:00 2001 From: dmitry <dmitry.zyryanov@execution.su> Date: Wed, 24 Feb 2021 17:25:30 +0700 Subject: [PATCH 9/9] return only safe valuable values of user object --- common/services/UsersService.js | 1 + 1 file changed, 1 insertion(+) diff --git a/common/services/UsersService.js b/common/services/UsersService.js index 7f415d4..b98f814 100644 --- a/common/services/UsersService.js +++ b/common/services/UsersService.js @@ -16,6 +16,7 @@ class UsersService extends BaseService { async getUserById(userId) { this._logger.debug('getUserById %j', userId); return this._models.UserModel.query() + .select('id', 'company_id', 'phone') .where({ id: userId, deleted_at: null }) .first(); } -- GitLab