X-Git-Url: https://git.squeep.com/?p=squeep-logger-json-console;a=blobdiff_plain;f=lib%2Fjson-replacers.js;fp=lib%2Fjson-replacers.js;h=2160ad8635af71f9aed3fbd169c02cd17df71849;hp=0000000000000000000000000000000000000000;hb=229dafe0003708b9fad190b4c0fc68136efd4f8c;hpb=21506cf49b1d239d780b377651554dc868639477 diff --git a/lib/json-replacers.js b/lib/json-replacers.js new file mode 100644 index 0000000..2160ad8 --- /dev/null +++ b/lib/json-replacers.js @@ -0,0 +1,136 @@ +'use strict'; + +/** + * Here are some replacers for rendering peculiar entities as JSON suitable for logging. + */ + +const http = require('http'); + +/** + * @typedef {Object} ReplacerResult + * @property {Boolean} replaced + * @property {*} value + */ + + +/** + * template for replacers + * @param {String} _key + * @param {*} value + * @returns {ReplacerResult} + */ +/* istanbul ignore next */ +function _replacer(_key, value) { + let replaced = false; + + if (undefined) { // eslint-disable-line no-constant-condition + replaced = true; + + const newValue = Object.assign({}, value); + + value = newValue; + } + return { replaced, value }; +} + + +/** + * Convert any Error to a plain Object. + * @param {String} _key + * @param {*} value + * @returns {ReplacerResult} + */ +function replacerError(_key, value) { + let replaced = false; + if (value instanceof Error) { + replaced = true; + const newValue = {}; + Object.getOwnPropertyNames(value).forEach((propertyName) => newValue[propertyName] = value[propertyName]); // eslint-disable-line security/detect-object-injection + value = newValue; + } + return { replaced, value }; +} + + +/** + * Convert any BigInt type to a String. + * @param {String} _key + * @param {*} value + * @returns {ReplacerResult} + */ +function replacerBigInt(_key, value) { + let replaced = false; + if (typeof value === 'bigint') { + replaced = true; + value = value.toString(); + } + return { replaced, value }; +} + + +/** + * Convert any IncomingMessage to a subset Object. + * Also sanitizes any Authorization header. We do this here rather than + * in sanitization stage so that we do not have to rely on a set path to + * this object. + * @param {String} _key + * @param {*} value + * @returns {ReplacerResult} + */ +function replacerHttpIncomingMessage(_key, value) { + let replaced = false; + if (value instanceof http.IncomingMessage) { + replaced = true; + const newValue = {}; + [ + 'method', + 'url', + 'httpVersion', + 'headers', + 'trailers', + ].forEach((property) => newValue[property] = value[property]); // eslint-disable-line security/detect-object-injection + + if (newValue.headers && 'authorization' in newValue.headers) { + const authHeader = newValue.headers.authorization; + const spaceIndex = authHeader.indexOf(' '); + // This blurs entire auth string if no space found, because -1 from indexOf. + const blurredAuthHeader = authHeader.slice(0, spaceIndex + 1) + '*'.repeat(authHeader.length - (spaceIndex + 1)); + // New headers object, as we change it. + newValue.headers = Object.assign({}, newValue.headers, { + authorization: blurredAuthHeader, + }); + } + value = newValue; + } + return { replaced, value }; +} + + +/** + * Convert any ServerResponse or OutgoingMessage to a subset Object. + * @param {String} _key + * @param {*} value + * @returns {ReplacerResult} + */ +function replacerHttpServerResponse(_key, value) { + let replaced = false; + if (value instanceof http.OutgoingMessage || value instanceof http.ServerResponse) { + replaced = true; + const newValue = {}; + [ + 'statusCode', + 'statusMessage', + ].forEach((property) => newValue[property] = value[property]); // eslint-disable-line security/detect-object-injection + newValue.headers = value.getHeaders(); + value = newValue; + } + return { replaced, value }; +} + + +module.exports = { + replacerBigInt, + replacerError, + replacerHttpIncomingMessage, + replacerHttpServerResponse, +};