3.0.2
[squeep-logger-json-console] / lib / json-replacers.js
1 'use strict';
2
3 /**
4 * Here are some replacers for rendering peculiar entities as JSON suitable for logging.
5 */
6
7 const http = require('http');
8
9 /**
10 * @typedef {Object} ReplacerResult
11 * @property {Boolean} replaced
12 * @property {*} value
13 */
14
15
16 /**
17 * template for replacers
18 * @param {String} _key
19 * @param {*} value
20 * @returns {ReplacerResult}
21 */
22 /* istanbul ignore next */
23 function _replacer(_key, value) {
24 let replaced = false;
25
26 if (undefined) { // eslint-disable-line no-constant-condition
27 replaced = true;
28
29 const newValue = Object.assign({}, value);
30
31 value = newValue;
32 }
33 return { replaced, value };
34 }
35
36
37 /**
38 * Convert any Error to a plain Object.
39 * @param {String} _key
40 * @param {*} value
41 * @returns {ReplacerResult}
42 */
43 function replacerError(_key, value) {
44 let replaced = false;
45 if (value instanceof Error) {
46 replaced = true;
47 const newValue = {};
48 Object.getOwnPropertyNames(value).forEach((propertyName) => newValue[propertyName] = value[propertyName]); // eslint-disable-line security/detect-object-injection
49 value = newValue;
50 }
51 return { replaced, value };
52 }
53
54
55 /**
56 * Convert any BigInt type to a String.
57 * @param {String} _key
58 * @param {*} value
59 * @returns {ReplacerResult}
60 */
61 function replacerBigInt(_key, value) {
62 let replaced = false;
63 if (typeof value === 'bigint') {
64 replaced = true;
65 value = value.toString();
66 }
67 return { replaced, value };
68 }
69
70
71 /**
72 * Convert any IncomingMessage to a subset Object.
73 * Also sanitizes any Authorization header. We do this here rather than
74 * in sanitization stage so that we do not have to rely on a set path to
75 * this object.
76 * @param {String} _key
77 * @param {*} value
78 * @returns {ReplacerResult}
79 */
80 function replacerHttpIncomingMessage(_key, value) {
81 let replaced = false;
82 if (value instanceof http.IncomingMessage) {
83 replaced = true;
84 const newValue = {};
85 [
86 'method',
87 'url',
88 'httpVersion',
89 'headers',
90 'trailers',
91 ].forEach((property) => newValue[property] = value[property]); // eslint-disable-line security/detect-object-injection
92
93 if (newValue.headers && 'authorization' in newValue.headers) {
94 const authHeader = newValue.headers.authorization;
95 const spaceIndex = authHeader.indexOf(' ');
96 // This blurs entire auth string if no space found, because -1 from indexOf.
97 const blurredAuthHeader = authHeader.slice(0, spaceIndex + 1) + '*'.repeat(authHeader.length - (spaceIndex + 1));
98 // New headers object, as we change it.
99 newValue.headers = Object.assign({}, newValue.headers, {
100 authorization: blurredAuthHeader,
101 });
102 }
103 value = newValue;
104 }
105 return { replaced, value };
106 }
107
108
109 /**
110 * Convert any ServerResponse or OutgoingMessage to a subset Object.
111 * @param {String} _key
112 * @param {*} value
113 * @returns {ReplacerResult}
114 */
115 function replacerHttpServerResponse(_key, value) {
116 let replaced = false;
117 if (value instanceof http.OutgoingMessage || value instanceof http.ServerResponse) {
118 replaced = true;
119 const newValue = {};
120 [
121 'statusCode',
122 'statusMessage',
123 ].forEach((property) => newValue[property] = value[property]); // eslint-disable-line security/detect-object-injection
124 newValue.headers = value.getHeaders();
125 value = newValue;
126 }
127 return { replaced, value };
128 }
129
130
131 module.exports = {
132 replacerBigInt,
133 replacerError,
134 replacerHttpIncomingMessage,
135 replacerHttpServerResponse,
136 };