@riocrypto/common-server 1.0.2711 → 1.0.2712
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
|
@@ -21,9 +21,9 @@ function buildAxiosWithLogging() {
|
|
|
21
21
|
"csrf",
|
|
22
22
|
];
|
|
23
23
|
function maskHeaderValue(value) {
|
|
24
|
-
return value.length >
|
|
25
|
-
? "*".repeat(
|
|
26
|
-
:
|
|
24
|
+
return value.length > 2
|
|
25
|
+
? "*".repeat(12) + value.slice(-2)
|
|
26
|
+
: "************";
|
|
27
27
|
}
|
|
28
28
|
// Masking function - masks any header containing a sensitive substring
|
|
29
29
|
function maskHeaders(headers) {
|
|
@@ -2,10 +2,18 @@ import { Logger } from "winston";
|
|
|
2
2
|
declare class LoggerService {
|
|
3
3
|
private logger;
|
|
4
4
|
constructor();
|
|
5
|
+
private sensitiveSubstrings;
|
|
6
|
+
private isSensitiveKey;
|
|
5
7
|
private maskValue;
|
|
8
|
+
private deepMaskSensitiveKeys;
|
|
6
9
|
private maskSensitiveData;
|
|
7
10
|
private requestMethodFilter;
|
|
8
11
|
private handleCustomErrorFormat;
|
|
12
|
+
private sanitizeArg;
|
|
13
|
+
private sensitiveStringPatterns;
|
|
14
|
+
private maskSensitiveString;
|
|
15
|
+
private setupConsoleMasking;
|
|
16
|
+
private setupStreamMasking;
|
|
9
17
|
getLogger(): Logger;
|
|
10
18
|
initLogger(): Promise<void>;
|
|
11
19
|
}
|
package/build/services/logger.js
CHANGED
|
@@ -8,33 +8,43 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
8
8
|
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
9
|
});
|
|
10
10
|
};
|
|
11
|
+
var __rest = (this && this.__rest) || function (s, e) {
|
|
12
|
+
var t = {};
|
|
13
|
+
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
|
|
14
|
+
t[p] = s[p];
|
|
15
|
+
if (s != null && typeof Object.getOwnPropertySymbols === "function")
|
|
16
|
+
for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
|
|
17
|
+
if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
|
|
18
|
+
t[p[i]] = s[p[i]];
|
|
19
|
+
}
|
|
20
|
+
return t;
|
|
21
|
+
};
|
|
11
22
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
23
|
const common_1 = require("@riocrypto/common");
|
|
13
24
|
const winston_1 = require("winston");
|
|
14
25
|
class LoggerService {
|
|
15
26
|
constructor() {
|
|
27
|
+
this.sensitiveSubstrings = [
|
|
28
|
+
"key",
|
|
29
|
+
"token",
|
|
30
|
+
"secret",
|
|
31
|
+
"auth",
|
|
32
|
+
"sign",
|
|
33
|
+
"password",
|
|
34
|
+
"private",
|
|
35
|
+
"credential",
|
|
36
|
+
"passphrase",
|
|
37
|
+
"csrf",
|
|
38
|
+
];
|
|
16
39
|
this.maskSensitiveData = (0, winston_1.format)((info) => {
|
|
17
40
|
var _a, _b, _c, _d, _e;
|
|
18
41
|
// Mask sensitive headers
|
|
19
42
|
if ((_b = (_a = info.meta) === null || _a === void 0 ? void 0 : _a.req) === null || _b === void 0 ? void 0 : _b.headers) {
|
|
20
43
|
// Use optional chaining
|
|
21
44
|
const headers = info.meta.req.headers;
|
|
22
|
-
const sensitiveSubstrings = [
|
|
23
|
-
"key",
|
|
24
|
-
"token",
|
|
25
|
-
"secret",
|
|
26
|
-
"auth",
|
|
27
|
-
"sign",
|
|
28
|
-
"password",
|
|
29
|
-
"private",
|
|
30
|
-
"credential",
|
|
31
|
-
"passphrase",
|
|
32
|
-
"csrf",
|
|
33
|
-
];
|
|
34
45
|
// Mask any header containing a sensitive substring
|
|
35
46
|
Object.keys(headers).forEach((headerKey) => {
|
|
36
|
-
|
|
37
|
-
if (sensitiveSubstrings.some((sub) => lower.includes(sub))) {
|
|
47
|
+
if (this.isSensitiveKey(headerKey)) {
|
|
38
48
|
headers[headerKey] = this.maskValue(String(headers[headerKey]));
|
|
39
49
|
}
|
|
40
50
|
});
|
|
@@ -152,22 +162,131 @@ class LoggerService {
|
|
|
152
162
|
if (typeof info.message === "object") {
|
|
153
163
|
info.message = error.message;
|
|
154
164
|
}
|
|
165
|
+
// Deep mask the error object to catch SDK errors with embedded configs/headers
|
|
155
166
|
if ((_c = info.meta) === null || _c === void 0 ? void 0 : _c.err) {
|
|
156
|
-
|
|
157
|
-
delete info.meta.err;
|
|
167
|
+
info.meta.err = this.deepMaskSensitiveKeys(info.meta.err);
|
|
158
168
|
}
|
|
159
169
|
}
|
|
170
|
+
// Deep mask the entire meta object to catch any remaining sensitive data
|
|
171
|
+
if (info.meta) {
|
|
172
|
+
const _d = info.meta, { req, res } = _d, rest = __rest(_d, ["req", "res"]);
|
|
173
|
+
// req/res are already handled above, deep mask everything else (error objects, SDK responses, etc.)
|
|
174
|
+
const masked = this.deepMaskSensitiveKeys(rest);
|
|
175
|
+
info.meta = Object.assign(Object.assign({}, info.meta), masked);
|
|
176
|
+
}
|
|
160
177
|
return info;
|
|
161
178
|
});
|
|
179
|
+
// Pre-compiled regex patterns for string masking
|
|
180
|
+
this.sensitiveStringPatterns = [
|
|
181
|
+
// Quoted keys: "Authorization":"value" or "api-key": "value"
|
|
182
|
+
new RegExp(`("(?:[^"]*(?:${this.sensitiveSubstrings.join("|")})[^"]*)"\\s*[:=]\\s*"?)([^",}\\s]+)`, "gi"),
|
|
183
|
+
// Unquoted keys: Authorization: value, apiKey=value, api_key: value
|
|
184
|
+
new RegExp(`((?:^|[\\s,;{])(?:[\\w-]*(?:${this.sensitiveSubstrings.join("|")})[\\w-]*)\\s*[:=]\\s*"?)([^",}\\s;]+)`, "gi"),
|
|
185
|
+
// Bearer tokens: Bearer <token>
|
|
186
|
+
/(\bBearer\s+)([^\s,;"]+)/gi,
|
|
187
|
+
];
|
|
162
188
|
this.logger = null;
|
|
189
|
+
this.setupConsoleMasking();
|
|
190
|
+
this.setupStreamMasking();
|
|
191
|
+
}
|
|
192
|
+
isSensitiveKey(key) {
|
|
193
|
+
const lower = key.toLowerCase();
|
|
194
|
+
return this.sensitiveSubstrings.some((sub) => lower.includes(sub));
|
|
163
195
|
}
|
|
164
196
|
maskValue(value, showLastFour = false) {
|
|
165
197
|
if (showLastFour) {
|
|
166
|
-
return value.length > 4 ? "*".repeat(12) + value.slice(-4) :
|
|
198
|
+
return value.length > 4 ? "*".repeat(12) + value.slice(-4) : "************";
|
|
199
|
+
}
|
|
200
|
+
return value.length > 2 ? "*".repeat(12) + value.slice(-2) : "************";
|
|
201
|
+
}
|
|
202
|
+
deepMaskSensitiveKeys(obj, seen = new WeakSet()) {
|
|
203
|
+
if (obj === null || obj === undefined)
|
|
204
|
+
return obj;
|
|
205
|
+
if (typeof obj !== "object")
|
|
206
|
+
return obj;
|
|
207
|
+
if (seen.has(obj))
|
|
208
|
+
return "[Circular]";
|
|
209
|
+
seen.add(obj);
|
|
210
|
+
if (Array.isArray(obj)) {
|
|
211
|
+
return obj.map((item) => this.deepMaskSensitiveKeys(item, seen));
|
|
167
212
|
}
|
|
168
|
-
|
|
169
|
-
|
|
213
|
+
const result = {};
|
|
214
|
+
for (const key of Object.keys(obj)) {
|
|
215
|
+
const value = obj[key];
|
|
216
|
+
if (this.isSensitiveKey(key) && typeof value === "string") {
|
|
217
|
+
result[key] = this.maskValue(value);
|
|
218
|
+
}
|
|
219
|
+
else if (typeof value === "object" && value !== null) {
|
|
220
|
+
result[key] = this.deepMaskSensitiveKeys(value, seen);
|
|
221
|
+
}
|
|
222
|
+
else {
|
|
223
|
+
result[key] = value;
|
|
224
|
+
}
|
|
170
225
|
}
|
|
226
|
+
return result;
|
|
227
|
+
}
|
|
228
|
+
sanitizeArg(arg) {
|
|
229
|
+
if (arg === null || arg === undefined)
|
|
230
|
+
return arg;
|
|
231
|
+
if (typeof arg === "string") {
|
|
232
|
+
return this.maskSensitiveString(arg);
|
|
233
|
+
}
|
|
234
|
+
if (arg instanceof Error) {
|
|
235
|
+
const masked = this.deepMaskSensitiveKeys(Object.assign(Object.assign({}, arg), { message: arg.message, stack: arg.stack }));
|
|
236
|
+
const sanitizedError = new Error(this.maskSensitiveString(masked.message));
|
|
237
|
+
sanitizedError.stack = this.maskSensitiveString(masked.stack || "");
|
|
238
|
+
Object.assign(sanitizedError, masked);
|
|
239
|
+
return sanitizedError;
|
|
240
|
+
}
|
|
241
|
+
if (typeof arg === "object") {
|
|
242
|
+
return this.deepMaskSensitiveKeys(arg);
|
|
243
|
+
}
|
|
244
|
+
return arg;
|
|
245
|
+
}
|
|
246
|
+
maskSensitiveString(str) {
|
|
247
|
+
let result = str;
|
|
248
|
+
for (const pattern of this.sensitiveStringPatterns) {
|
|
249
|
+
pattern.lastIndex = 0;
|
|
250
|
+
result = result.replace(pattern, (_match, prefix, value) => {
|
|
251
|
+
if (value.length > 2) {
|
|
252
|
+
return `${prefix}************${value.slice(-2)}`;
|
|
253
|
+
}
|
|
254
|
+
return `${prefix}************`;
|
|
255
|
+
});
|
|
256
|
+
}
|
|
257
|
+
return result;
|
|
258
|
+
}
|
|
259
|
+
setupConsoleMasking() {
|
|
260
|
+
const originalConsole = {
|
|
261
|
+
log: console.log.bind(console),
|
|
262
|
+
error: console.error.bind(console),
|
|
263
|
+
warn: console.warn.bind(console),
|
|
264
|
+
info: console.info.bind(console),
|
|
265
|
+
};
|
|
266
|
+
const sanitize = (...args) => args.map((arg) => this.sanitizeArg(arg));
|
|
267
|
+
console.log = (...args) => originalConsole.log(...sanitize(...args));
|
|
268
|
+
console.error = (...args) => originalConsole.error(...sanitize(...args));
|
|
269
|
+
console.warn = (...args) => originalConsole.warn(...sanitize(...args));
|
|
270
|
+
console.info = (...args) => originalConsole.info(...sanitize(...args));
|
|
271
|
+
}
|
|
272
|
+
setupStreamMasking() {
|
|
273
|
+
const originalStdoutWrite = process.stdout.write.bind(process.stdout);
|
|
274
|
+
const originalStderrWrite = process.stderr.write.bind(process.stderr);
|
|
275
|
+
const maskChunk = (chunk) => {
|
|
276
|
+
if (typeof chunk === "string") {
|
|
277
|
+
return this.maskSensitiveString(chunk);
|
|
278
|
+
}
|
|
279
|
+
if (Buffer.isBuffer(chunk)) {
|
|
280
|
+
return Buffer.from(this.maskSensitiveString(chunk.toString("utf8")));
|
|
281
|
+
}
|
|
282
|
+
return chunk;
|
|
283
|
+
};
|
|
284
|
+
process.stdout.write = (chunk, ...args) => {
|
|
285
|
+
return originalStdoutWrite(maskChunk(chunk), ...args);
|
|
286
|
+
};
|
|
287
|
+
process.stderr.write = (chunk, ...args) => {
|
|
288
|
+
return originalStderrWrite(maskChunk(chunk), ...args);
|
|
289
|
+
};
|
|
171
290
|
}
|
|
172
291
|
getLogger() {
|
|
173
292
|
if (!this.logger) {
|