@riocrypto/common-server 1.0.2275 → 1.0.2277
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.
- package/build/helpers/sanitize-bank-account-doc.d.ts +1 -0
- package/build/helpers/sanitize-crypto-address-doc.d.ts +1 -0
- package/build/helpers/sanitize-order-doc.d.ts +1 -0
- package/build/helpers/sanitize-user-doc.d.ts +1 -0
- package/build/index.d.ts +2 -0
- package/build/index.js +2 -0
- package/build/middlewares/dynamic-rate-limiter.d.ts +10 -0
- package/build/middlewares/dynamic-rate-limiter.js +148 -0
- package/build/models/admin-webauthn-credential.d.ts +1 -0
- package/build/models/custom-rate-limit.d.ts +24 -0
- package/build/models/custom-rate-limit.js +63 -0
- package/build/models/webauthn-credential.d.ts +1 -0
- package/build/services/logger.js +38 -23
- package/package.json +2 -1
|
@@ -47,6 +47,7 @@
|
|
|
47
47
|
/// <reference types="mongoose/types/virtuals" />
|
|
48
48
|
/// <reference types="mongoose" />
|
|
49
49
|
/// <reference types="mongoose/types/inferschematype" />
|
|
50
|
+
/// <reference types="mongoose/types/inferrawdoctype" />
|
|
50
51
|
/// <reference types="mongoose/types/inferschematype" />
|
|
51
52
|
/// <reference types="mongoose/types/inferrawdoctype" />
|
|
52
53
|
import { BankAccountDoc } from "@riocrypto/common-server";
|
|
@@ -47,6 +47,7 @@
|
|
|
47
47
|
/// <reference types="mongoose/types/virtuals" />
|
|
48
48
|
/// <reference types="mongoose" />
|
|
49
49
|
/// <reference types="mongoose/types/inferschematype" />
|
|
50
|
+
/// <reference types="mongoose/types/inferrawdoctype" />
|
|
50
51
|
/// <reference types="mongoose/types/inferschematype" />
|
|
51
52
|
/// <reference types="mongoose/types/inferrawdoctype" />
|
|
52
53
|
import { CryptoAddressDoc } from "@riocrypto/common-server";
|
|
@@ -47,6 +47,7 @@
|
|
|
47
47
|
/// <reference types="mongoose/types/virtuals" />
|
|
48
48
|
/// <reference types="mongoose" />
|
|
49
49
|
/// <reference types="mongoose/types/inferschematype" />
|
|
50
|
+
/// <reference types="mongoose/types/inferrawdoctype" />
|
|
50
51
|
/// <reference types="mongoose/types/inferschematype" />
|
|
51
52
|
/// <reference types="mongoose/types/inferrawdoctype" />
|
|
52
53
|
import { OrderDoc } from "@riocrypto/common-server";
|
|
@@ -47,6 +47,7 @@
|
|
|
47
47
|
/// <reference types="mongoose/types/virtuals" />
|
|
48
48
|
/// <reference types="mongoose" />
|
|
49
49
|
/// <reference types="mongoose/types/inferschematype" />
|
|
50
|
+
/// <reference types="mongoose/types/inferrawdoctype" />
|
|
50
51
|
/// <reference types="mongoose/types/inferschematype" />
|
|
51
52
|
/// <reference types="mongoose/types/inferrawdoctype" />
|
|
52
53
|
import { UserDoc } from "@riocrypto/common-server";
|
package/build/index.d.ts
CHANGED
|
@@ -7,6 +7,7 @@ export * from "./middlewares/set-trace";
|
|
|
7
7
|
export * from "./middlewares/require-min-role";
|
|
8
8
|
export * from "./middlewares/require-min-admin-role";
|
|
9
9
|
export * from "./middlewares/verify-csrf-token";
|
|
10
|
+
export * from "./middlewares/dynamic-rate-limiter";
|
|
10
11
|
export * from "./services/apiKey";
|
|
11
12
|
export * from "./services/password";
|
|
12
13
|
export * from "./services/logger";
|
|
@@ -91,6 +92,7 @@ export * from "./models/STP-settings";
|
|
|
91
92
|
export * from "./models/dashboard-push-notification-subscription";
|
|
92
93
|
export * from "./models/webauthn-credential";
|
|
93
94
|
export * from "./models/admin-webauthn-credential";
|
|
95
|
+
export * from "./models/custom-rate-limit";
|
|
94
96
|
export * from "./clients/axios-with-logging";
|
|
95
97
|
export * from "./clients/slack-client";
|
|
96
98
|
export * from "./clients/fireblocks-client";
|
package/build/index.js
CHANGED
|
@@ -23,6 +23,7 @@ __exportStar(require("./middlewares/set-trace"), exports);
|
|
|
23
23
|
__exportStar(require("./middlewares/require-min-role"), exports);
|
|
24
24
|
__exportStar(require("./middlewares/require-min-admin-role"), exports);
|
|
25
25
|
__exportStar(require("./middlewares/verify-csrf-token"), exports);
|
|
26
|
+
__exportStar(require("./middlewares/dynamic-rate-limiter"), exports);
|
|
26
27
|
__exportStar(require("./services/apiKey"), exports);
|
|
27
28
|
__exportStar(require("./services/password"), exports);
|
|
28
29
|
__exportStar(require("./services/logger"), exports);
|
|
@@ -107,6 +108,7 @@ __exportStar(require("./models/STP-settings"), exports);
|
|
|
107
108
|
__exportStar(require("./models/dashboard-push-notification-subscription"), exports);
|
|
108
109
|
__exportStar(require("./models/webauthn-credential"), exports);
|
|
109
110
|
__exportStar(require("./models/admin-webauthn-credential"), exports);
|
|
111
|
+
__exportStar(require("./models/custom-rate-limit"), exports);
|
|
110
112
|
__exportStar(require("./clients/axios-with-logging"), exports);
|
|
111
113
|
__exportStar(require("./clients/slack-client"), exports);
|
|
112
114
|
__exportStar(require("./clients/fireblocks-client"), exports);
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { Request, Response, NextFunction } from "express";
|
|
2
|
+
import { Options as RateLimitOptions } from "express-rate-limit";
|
|
3
|
+
import { Mongoose } from "mongoose";
|
|
4
|
+
export interface DynamicRateLimiterOptions extends Partial<RateLimitOptions> {
|
|
5
|
+
windowMs: number;
|
|
6
|
+
max: number;
|
|
7
|
+
mongooseConnection: Mongoose;
|
|
8
|
+
cacheTtlMs?: number;
|
|
9
|
+
}
|
|
10
|
+
export declare function createDynamicRateLimiter(options: DynamicRateLimiterOptions): (req: Request, res: Response, next: NextFunction) => Promise<void>;
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
+
});
|
|
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
|
+
};
|
|
22
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
23
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
24
|
+
};
|
|
25
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
26
|
+
exports.createDynamicRateLimiter = void 0;
|
|
27
|
+
const express_rate_limit_1 = __importDefault(require("express-rate-limit"));
|
|
28
|
+
// Removed path-to-regexp import
|
|
29
|
+
// Adjust the import path according to your project structure
|
|
30
|
+
const custom_rate_limit_1 = require("../models/custom-rate-limit");
|
|
31
|
+
// Cache for rate limiter instances
|
|
32
|
+
const limiterInstanceCache = new Map();
|
|
33
|
+
// Cache for compiled RegExp objects from path strings
|
|
34
|
+
// Key: regex string pattern, Value: compiled RegExp object
|
|
35
|
+
const regexCache = new Map();
|
|
36
|
+
// In-memory cache for custom IP rules
|
|
37
|
+
let customIpRulesCache = new Map();
|
|
38
|
+
let lastCacheRefreshTime = 0;
|
|
39
|
+
const DEFAULT_CACHE_TTL_MS = 5 * 60 * 1000; // 5 minutes
|
|
40
|
+
function refreshCustomIpRulesCache(CustomRateLimit, filePathForLog) {
|
|
41
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
42
|
+
try {
|
|
43
|
+
const allRules = yield CustomRateLimit.find({}).lean();
|
|
44
|
+
const newCache = new Map();
|
|
45
|
+
allRules.forEach((rule) => {
|
|
46
|
+
if (rule.ipAddress) {
|
|
47
|
+
// Pre-compile and cache regexes when rules are loaded/refreshed
|
|
48
|
+
if (rule.routes && Array.isArray(rule.routes)) {
|
|
49
|
+
rule.routes.forEach((routeRule) => {
|
|
50
|
+
// Use any temporarily if lean typing is tricky
|
|
51
|
+
if (typeof routeRule.path === "string" &&
|
|
52
|
+
!regexCache.has(routeRule.path)) {
|
|
53
|
+
try {
|
|
54
|
+
regexCache.set(routeRule.path, new RegExp(routeRule.path));
|
|
55
|
+
}
|
|
56
|
+
catch (e) {
|
|
57
|
+
console.error(`[DynamicRateLimiter Refresh] Failed to compile regex: '${routeRule.path}' for IP ${rule.ipAddress}. Skipping rule path. Error:`, e);
|
|
58
|
+
// Optionally mark the rule path as invalid or handle differently
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
newCache.set(rule.ipAddress, rule);
|
|
64
|
+
}
|
|
65
|
+
});
|
|
66
|
+
customIpRulesCache = newCache;
|
|
67
|
+
lastCacheRefreshTime = Date.now();
|
|
68
|
+
}
|
|
69
|
+
catch (error) {
|
|
70
|
+
console.error(`[DynamicRateLimiter ${filePathForLog}] Error refreshing custom IP rules cache:`, error);
|
|
71
|
+
}
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
function createDynamicRateLimiter(options) {
|
|
75
|
+
const { windowMs: defaultWindowMs, // Rename for clarity
|
|
76
|
+
max: defaultMax, // Rename for clarity
|
|
77
|
+
mongooseConnection, cacheTtlMs = DEFAULT_CACHE_TTL_MS,
|
|
78
|
+
// Capture other express-rate-limit options passed in
|
|
79
|
+
message, standardHeaders, legacyHeaders, skip, requestPropertyName } = options,
|
|
80
|
+
// Add any other valid RateLimitOptions you might pass
|
|
81
|
+
otherRateLimitOptions = __rest(options, ["windowMs", "max", "mongooseConnection", "cacheTtlMs", "message", "standardHeaders", "legacyHeaders", "skip", "requestPropertyName"]) // Use a specific variable if you know exactly what else you pass
|
|
82
|
+
;
|
|
83
|
+
if (!mongooseConnection) {
|
|
84
|
+
throw new Error("[DynamicRateLimiter] Mongoose connection is required.");
|
|
85
|
+
}
|
|
86
|
+
const CustomRateLimit = (0, custom_rate_limit_1.buildCustomRateLimit)(mongooseConnection);
|
|
87
|
+
refreshCustomIpRulesCache(CustomRateLimit, "initialization");
|
|
88
|
+
return (req, res, next) => __awaiter(this, void 0, void 0, function* () {
|
|
89
|
+
try {
|
|
90
|
+
// Refresh cache if stale
|
|
91
|
+
if (Date.now() - lastCacheRefreshTime > cacheTtlMs ||
|
|
92
|
+
(customIpRulesCache.size === 0 && lastCacheRefreshTime === 0)) {
|
|
93
|
+
yield refreshCustomIpRulesCache(CustomRateLimit, req.path);
|
|
94
|
+
}
|
|
95
|
+
const clientIp = req.ip;
|
|
96
|
+
let currentLimit = defaultMax; // Use destructured default
|
|
97
|
+
let currentWindowMs = defaultWindowMs; // Use destructured default
|
|
98
|
+
let ruleIdentifier = "default";
|
|
99
|
+
let customRule;
|
|
100
|
+
if (clientIp) {
|
|
101
|
+
customRule = customIpRulesCache.get(clientIp);
|
|
102
|
+
}
|
|
103
|
+
if (customRule) {
|
|
104
|
+
// Check if routes array exists and is not empty
|
|
105
|
+
const appliesToCurrentRoute = !customRule.routes || // Should not happen if default is []
|
|
106
|
+
customRule.routes.length === 0 || // Empty array means apply custom limit to ALL requests for this IP
|
|
107
|
+
customRule.routes.some((rule) => {
|
|
108
|
+
// Check HTTP Method first (faster check)
|
|
109
|
+
const methodMatch = rule.action === "*" || rule.action === req.method.toUpperCase();
|
|
110
|
+
if (!methodMatch) {
|
|
111
|
+
return false;
|
|
112
|
+
}
|
|
113
|
+
// Get the compiled regex from cache
|
|
114
|
+
const regex = regexCache.get(rule.path);
|
|
115
|
+
if (!regex) {
|
|
116
|
+
// Regex failed compilation during refresh, skip this rule path
|
|
117
|
+
// Error was already logged during refreshCustomIpRulesCache
|
|
118
|
+
return false;
|
|
119
|
+
}
|
|
120
|
+
// Test the path against the regex
|
|
121
|
+
return regex.test(req.path);
|
|
122
|
+
});
|
|
123
|
+
if (appliesToCurrentRoute) {
|
|
124
|
+
currentLimit = customRule.limit;
|
|
125
|
+
currentWindowMs = customRule.windowMs;
|
|
126
|
+
ruleIdentifier = `custom_ip:${clientIp}`;
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
// Get/create limiter instance using currentLimit, currentWindowMs, ruleIdentifier
|
|
130
|
+
const limiterCacheKey = `${currentLimit}-${currentWindowMs}-${ruleIdentifier}`;
|
|
131
|
+
let selectedLimiter = limiterInstanceCache.get(limiterCacheKey);
|
|
132
|
+
if (!selectedLimiter) {
|
|
133
|
+
selectedLimiter = (0, express_rate_limit_1.default)(Object.assign({ windowMs: currentWindowMs, max: currentLimit, keyGenerator: (request) => {
|
|
134
|
+
return request.ip || "unknown_ip_for_rate_limit";
|
|
135
|
+
},
|
|
136
|
+
// Pass through other specified options
|
|
137
|
+
message: message, standardHeaders: standardHeaders, legacyHeaders: legacyHeaders, skip: skip, requestPropertyName: requestPropertyName }, otherRateLimitOptions));
|
|
138
|
+
limiterInstanceCache.set(limiterCacheKey, selectedLimiter);
|
|
139
|
+
}
|
|
140
|
+
return selectedLimiter(req, res, next);
|
|
141
|
+
}
|
|
142
|
+
catch (error) {
|
|
143
|
+
console.error(`[DynamicRateLimiter ${req.path}] Error in rate limiting middleware (IP: ${req.ip}):`, error);
|
|
144
|
+
next();
|
|
145
|
+
}
|
|
146
|
+
});
|
|
147
|
+
}
|
|
148
|
+
exports.createDynamicRateLimiter = createDynamicRateLimiter;
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import mongoose from "mongoose";
|
|
2
|
+
interface RouteRule {
|
|
3
|
+
path: string;
|
|
4
|
+
action: string;
|
|
5
|
+
}
|
|
6
|
+
interface CustomRateLimitAttrs {
|
|
7
|
+
createdAt?: Date;
|
|
8
|
+
ipAddress: string;
|
|
9
|
+
limit: number;
|
|
10
|
+
windowMs: number;
|
|
11
|
+
routes: RouteRule[];
|
|
12
|
+
}
|
|
13
|
+
interface CustomRateLimitDoc extends mongoose.Document {
|
|
14
|
+
createdAt: Date;
|
|
15
|
+
ipAddress: string;
|
|
16
|
+
limit: number;
|
|
17
|
+
windowMs: number;
|
|
18
|
+
routes: RouteRule[];
|
|
19
|
+
}
|
|
20
|
+
interface CustomRateLimitModel extends mongoose.Model<CustomRateLimitDoc> {
|
|
21
|
+
build(attrs: CustomRateLimitAttrs): CustomRateLimitDoc;
|
|
22
|
+
}
|
|
23
|
+
declare const buildCustomRateLimit: (mongoose: typeof mongoose) => CustomRateLimitModel;
|
|
24
|
+
export { buildCustomRateLimit, CustomRateLimitDoc, CustomRateLimitAttrs, RouteRule, };
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.buildCustomRateLimit = void 0;
|
|
4
|
+
const buildCustomRateLimit = (mongoose) => {
|
|
5
|
+
// if model is already defined, return it
|
|
6
|
+
if (mongoose.models.CustomRateLimit) {
|
|
7
|
+
return mongoose.model("CustomRateLimit");
|
|
8
|
+
}
|
|
9
|
+
// Define the schema for the nested RouteRule object
|
|
10
|
+
const RouteRuleSchema = new mongoose.Schema({
|
|
11
|
+
path: {
|
|
12
|
+
type: String,
|
|
13
|
+
required: [true, "Path (regex string) is required for a route rule"],
|
|
14
|
+
},
|
|
15
|
+
action: {
|
|
16
|
+
type: String,
|
|
17
|
+
required: [true, "Action (HTTP method) is required for a route rule"],
|
|
18
|
+
uppercase: true, // Store methods consistently (e.g., 'GET')
|
|
19
|
+
// Optional: Add enum validation if you want to restrict methods
|
|
20
|
+
// enum: ['GET', 'POST', 'PUT', 'PATCH', 'DELETE', '*'] // Example enum
|
|
21
|
+
},
|
|
22
|
+
}, { _id: false }); // Don't create separate IDs for subdocuments
|
|
23
|
+
const CustomRateLimitSchema = new mongoose.Schema({
|
|
24
|
+
createdAt: {
|
|
25
|
+
type: mongoose.Schema.Types.Date,
|
|
26
|
+
default: Date.now, // Add default value for createdAt
|
|
27
|
+
},
|
|
28
|
+
ipAddress: {
|
|
29
|
+
type: String,
|
|
30
|
+
required: true,
|
|
31
|
+
},
|
|
32
|
+
limit: {
|
|
33
|
+
type: Number,
|
|
34
|
+
required: true,
|
|
35
|
+
},
|
|
36
|
+
windowMs: {
|
|
37
|
+
type: Number,
|
|
38
|
+
required: true,
|
|
39
|
+
},
|
|
40
|
+
routes: {
|
|
41
|
+
type: [RouteRuleSchema],
|
|
42
|
+
required: true,
|
|
43
|
+
// Default to empty array, meaning applies to all routes/methods if not specified
|
|
44
|
+
default: [],
|
|
45
|
+
},
|
|
46
|
+
}, {
|
|
47
|
+
toJSON: {
|
|
48
|
+
transform(doc, ret) {
|
|
49
|
+
ret.id = ret._id;
|
|
50
|
+
delete ret._id;
|
|
51
|
+
delete ret.__v;
|
|
52
|
+
},
|
|
53
|
+
},
|
|
54
|
+
});
|
|
55
|
+
CustomRateLimitSchema.statics.build = (attrs) => {
|
|
56
|
+
var _a;
|
|
57
|
+
// Ensure default createdAt is handled if not provided
|
|
58
|
+
return new CustomRateLimit(Object.assign(Object.assign({}, attrs), { createdAt: (_a = attrs.createdAt) !== null && _a !== void 0 ? _a : new Date() }));
|
|
59
|
+
};
|
|
60
|
+
const CustomRateLimit = mongoose.model("CustomRateLimit", CustomRateLimitSchema);
|
|
61
|
+
return CustomRateLimit;
|
|
62
|
+
};
|
|
63
|
+
exports.buildCustomRateLimit = buildCustomRateLimit;
|
package/build/services/logger.js
CHANGED
|
@@ -14,8 +14,10 @@ const winston_1 = require("winston");
|
|
|
14
14
|
class LoggerService {
|
|
15
15
|
constructor() {
|
|
16
16
|
this.maskSensitiveData = (0, winston_1.format)((info) => {
|
|
17
|
+
var _a, _b, _c, _d, _e;
|
|
17
18
|
// Mask sensitive headers
|
|
18
|
-
if (info.meta
|
|
19
|
+
if ((_b = (_a = info.meta) === null || _a === void 0 ? void 0 : _a.req) === null || _b === void 0 ? void 0 : _b.headers) {
|
|
20
|
+
// Use optional chaining
|
|
19
21
|
const headers = info.meta.req.headers;
|
|
20
22
|
const headerKeysToMask = [
|
|
21
23
|
"x-api-key",
|
|
@@ -24,7 +26,8 @@ class LoggerService {
|
|
|
24
26
|
];
|
|
25
27
|
headerKeysToMask.forEach((key) => {
|
|
26
28
|
if (headers[key]) {
|
|
27
|
-
|
|
29
|
+
// Type assertion might be needed if headers[key] is not strictly string
|
|
30
|
+
headers[key] = this.maskValue(String(headers[key]));
|
|
28
31
|
}
|
|
29
32
|
});
|
|
30
33
|
// Mask cookies specifically
|
|
@@ -38,22 +41,26 @@ class LoggerService {
|
|
|
38
41
|
key === "refreshToken" ||
|
|
39
42
|
key === "adminRefreshToken" ||
|
|
40
43
|
key === "phoneVerifiedJWT") {
|
|
41
|
-
return `${key}=${this.maskValue(value, true)}`;
|
|
44
|
+
return `${key}=${this.maskValue(value, true)}`;
|
|
42
45
|
}
|
|
43
|
-
return cookie;
|
|
46
|
+
return cookie;
|
|
44
47
|
})
|
|
45
48
|
.join("; ");
|
|
46
49
|
}
|
|
47
50
|
}
|
|
48
51
|
// Mask sensitive request body fields
|
|
49
|
-
if (info.meta
|
|
52
|
+
if (((_d = (_c = info.meta) === null || _c === void 0 ? void 0 : _c.req) === null || _d === void 0 ? void 0 : _d.body) &&
|
|
53
|
+
typeof info.meta.req.body === "object" &&
|
|
54
|
+
info.meta.req.body !== null) {
|
|
55
|
+
const requestBody = info.meta.req.body; // Type assertion
|
|
50
56
|
const requestBodyFieldsToMaskWithLastFour = [
|
|
51
57
|
"accountNumber",
|
|
52
58
|
"routingNumber",
|
|
53
59
|
];
|
|
54
60
|
requestBodyFieldsToMaskWithLastFour.forEach((field) => {
|
|
55
|
-
if (
|
|
56
|
-
|
|
61
|
+
if (requestBody.hasOwnProperty(field) &&
|
|
62
|
+
typeof requestBody[field] === "string") {
|
|
63
|
+
requestBody[field] = this.maskValue(requestBody[field], true);
|
|
57
64
|
}
|
|
58
65
|
});
|
|
59
66
|
const requestBodyFieldsToMaskWithoutLastFour = [
|
|
@@ -64,26 +71,34 @@ class LoggerService {
|
|
|
64
71
|
"authenticatorCode",
|
|
65
72
|
];
|
|
66
73
|
requestBodyFieldsToMaskWithoutLastFour.forEach((field) => {
|
|
67
|
-
if (
|
|
68
|
-
|
|
74
|
+
if (requestBody.hasOwnProperty(field) &&
|
|
75
|
+
typeof requestBody[field] === "string") {
|
|
76
|
+
requestBody[field] = this.maskValue(requestBody[field]);
|
|
69
77
|
}
|
|
70
78
|
});
|
|
71
79
|
}
|
|
72
80
|
// Mask sensitive response body fields
|
|
73
|
-
|
|
81
|
+
const resAsAny = (_e = info.meta) === null || _e === void 0 ? void 0 : _e.res;
|
|
82
|
+
if ((resAsAny === null || resAsAny === void 0 ? void 0 : resAsAny.body) &&
|
|
83
|
+
typeof resAsAny.body === "object" &&
|
|
84
|
+
resAsAny.body !== null) {
|
|
85
|
+
const responseBody = resAsAny.body; // Keep this assertion for object access
|
|
74
86
|
const responseBodyFieldsToMask = ["secret", "value"];
|
|
75
87
|
responseBodyFieldsToMask.forEach((field) => {
|
|
76
|
-
if (
|
|
77
|
-
|
|
88
|
+
if (responseBody.hasOwnProperty(field) &&
|
|
89
|
+
typeof responseBody[field] === "string") {
|
|
90
|
+
responseBody[field] = this.maskValue(responseBody[field]);
|
|
78
91
|
}
|
|
79
92
|
});
|
|
80
93
|
}
|
|
81
94
|
return info;
|
|
82
95
|
});
|
|
83
96
|
this.requestMethodFilter = (0, winston_1.format)((info) => {
|
|
97
|
+
var _a, _b;
|
|
84
98
|
const allowedMethods = ["POST", "PATCH", "DELETE"];
|
|
85
99
|
// Only apply filter if req.method is defined
|
|
86
|
-
if (info.meta
|
|
100
|
+
if ((_b = (_a = info.meta) === null || _a === void 0 ? void 0 : _a.req) === null || _b === void 0 ? void 0 : _b.method) {
|
|
101
|
+
// Use optional chaining
|
|
87
102
|
if (allowedMethods.includes(info.meta.req.method)) {
|
|
88
103
|
return info;
|
|
89
104
|
}
|
|
@@ -96,41 +111,41 @@ class LoggerService {
|
|
|
96
111
|
});
|
|
97
112
|
// Custom format to handle CustomError serialization
|
|
98
113
|
this.handleCustomErrorFormat = (0, winston_1.format)((info) => {
|
|
114
|
+
var _a, _b, _c;
|
|
99
115
|
let error;
|
|
100
116
|
// express-winston errorLogger often puts the error in info.message or info.meta.err
|
|
101
117
|
if (info.message instanceof Error) {
|
|
102
118
|
error = info.message;
|
|
103
119
|
}
|
|
104
|
-
else if (info.meta
|
|
120
|
+
else if (((_a = info.meta) === null || _a === void 0 ? void 0 : _a.err) instanceof Error) {
|
|
121
|
+
// Use optional chaining
|
|
105
122
|
error = info.meta.err;
|
|
106
123
|
}
|
|
107
124
|
else if (info.level === "error" &&
|
|
108
125
|
info.message &&
|
|
109
126
|
typeof info.message === "object" &&
|
|
110
|
-
info.message.stack
|
|
111
|
-
|
|
127
|
+
info.message.stack // Type assertion to check for stack
|
|
128
|
+
) {
|
|
112
129
|
error = info.message;
|
|
113
130
|
}
|
|
114
131
|
if (error instanceof common_1.CustomError) {
|
|
115
|
-
// Replace the error object/message with serialized details
|
|
116
|
-
// Log serialized errors under 'errorDetails' and keep original message if it's just a string
|
|
117
132
|
info.errorDetails = error.serializeErrors();
|
|
118
133
|
if (typeof info.message === "object") {
|
|
119
|
-
info.message = error.message;
|
|
134
|
+
info.message = error.message;
|
|
120
135
|
}
|
|
121
|
-
|
|
122
|
-
|
|
136
|
+
if ((_b = info.meta) === null || _b === void 0 ? void 0 : _b.err) {
|
|
137
|
+
// Use optional chaining
|
|
123
138
|
delete info.meta.err;
|
|
124
139
|
}
|
|
125
140
|
}
|
|
126
141
|
else if (error) {
|
|
127
|
-
// For generic errors, ensure the stack is included if available
|
|
128
142
|
info.errorMessage = error.message;
|
|
129
143
|
info.errorStack = error.stack;
|
|
130
144
|
if (typeof info.message === "object") {
|
|
131
145
|
info.message = error.message;
|
|
132
146
|
}
|
|
133
|
-
if (info.meta
|
|
147
|
+
if ((_c = info.meta) === null || _c === void 0 ? void 0 : _c.err) {
|
|
148
|
+
// Use optional chaining
|
|
134
149
|
delete info.meta.err;
|
|
135
150
|
}
|
|
136
151
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@riocrypto/common-server",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.2277",
|
|
4
4
|
"description": "",
|
|
5
5
|
"main": "./build/index.js",
|
|
6
6
|
"types": "./build/index.d.ts",
|
|
@@ -34,6 +34,7 @@
|
|
|
34
34
|
"crypto-js": "^4.2.0",
|
|
35
35
|
"csurf": "^1.11.0",
|
|
36
36
|
"express": "^4.21.1",
|
|
37
|
+
"express-rate-limit": "^7.5.0",
|
|
37
38
|
"express-validator": "^6.14.2",
|
|
38
39
|
"fireblocks-sdk": "^5.13.0",
|
|
39
40
|
"googleapis": "^135.1.0",
|