@riocrypto/common-server 1.0.2711 → 1.0.2713

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,7 @@ function buildAxiosWithLogging() {
21
21
  "csrf",
22
22
  ];
23
23
  function maskHeaderValue(value) {
24
- return value.length > 4
25
- ? "*".repeat(value.length - 4) + value.slice(-4)
26
- : value;
24
+ return value.length > 2 ? "*".repeat(12) + value.slice(-2) : "************";
27
25
  }
28
26
  // Masking function - masks any header containing a sensitive substring
29
27
  function maskHeaders(headers) {
package/build/index.d.ts CHANGED
@@ -117,6 +117,7 @@ export * from "./models/compliance-bot-chat";
117
117
  export * from "./models/compliance-bot-rule";
118
118
  export * from "./models/compliance-bot-rule-result";
119
119
  export * from "./models/static-bank-payment-reference";
120
+ export * from "./models/indicative-quote-page";
120
121
  export * from "./clients/axios-with-logging";
121
122
  export * from "./clients/slack-client";
122
123
  export * from "./clients/fireblocks-client";
package/build/index.js CHANGED
@@ -133,6 +133,7 @@ __exportStar(require("./models/compliance-bot-chat"), exports);
133
133
  __exportStar(require("./models/compliance-bot-rule"), exports);
134
134
  __exportStar(require("./models/compliance-bot-rule-result"), exports);
135
135
  __exportStar(require("./models/static-bank-payment-reference"), exports);
136
+ __exportStar(require("./models/indicative-quote-page"), exports);
136
137
  __exportStar(require("./clients/axios-with-logging"), exports);
137
138
  __exportStar(require("./clients/slack-client"), exports);
138
139
  __exportStar(require("./clients/fireblocks-client"), exports);
@@ -0,0 +1,24 @@
1
+ import { IndicativeQuotePageQuoteConfig } from "@riocrypto/common";
2
+ import { Mongoose, Model, Document } from "mongoose";
3
+ interface IndicativeQuotePageAttrs {
4
+ userId: string;
5
+ quotes: IndicativeQuotePageQuoteConfig[];
6
+ allowedIPs: string[];
7
+ createdBy: string;
8
+ createdAt: Date;
9
+ updatedAt: Date;
10
+ }
11
+ interface IndicativeQuotePageModel extends Model<IndicativeQuotePageDoc> {
12
+ build(attrs: IndicativeQuotePageAttrs): IndicativeQuotePageDoc;
13
+ }
14
+ interface IndicativeQuotePageDoc extends Document {
15
+ _id: string;
16
+ userId: string;
17
+ quotes: IndicativeQuotePageQuoteConfig[];
18
+ allowedIPs: string[];
19
+ createdBy: string;
20
+ createdAt: Date;
21
+ updatedAt: Date;
22
+ }
23
+ declare const buildIndicativeQuotePage: (mongoose: Mongoose) => IndicativeQuotePageModel;
24
+ export { buildIndicativeQuotePage, IndicativeQuotePageDoc, IndicativeQuotePageAttrs };
@@ -0,0 +1,77 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.buildIndicativeQuotePage = void 0;
4
+ const common_1 = require("@riocrypto/common");
5
+ const buildIndicativeQuotePage = (mongoose) => {
6
+ if (mongoose.models.PublicQuotePage) {
7
+ return mongoose.model("PublicQuotePage");
8
+ }
9
+ const QuoteConfigSchema = new mongoose.Schema({
10
+ side: {
11
+ type: String,
12
+ required: true,
13
+ enum: Object.values(common_1.Side),
14
+ },
15
+ crypto: {
16
+ type: String,
17
+ required: true,
18
+ enum: Object.values(common_1.Crypto),
19
+ },
20
+ fiat: {
21
+ type: String,
22
+ required: true,
23
+ enum: Object.values(common_1.Fiat),
24
+ },
25
+ country: {
26
+ type: String,
27
+ required: true,
28
+ enum: Object.values(common_1.Country),
29
+ },
30
+ amountFiat: {
31
+ type: Number,
32
+ },
33
+ amountCrypto: {
34
+ type: Number,
35
+ },
36
+ }, { _id: false });
37
+ const IndicativeQuotePageSchema = new mongoose.Schema({
38
+ userId: {
39
+ type: String,
40
+ required: true,
41
+ },
42
+ quotes: {
43
+ type: [QuoteConfigSchema],
44
+ required: true,
45
+ },
46
+ allowedIPs: {
47
+ type: [String],
48
+ required: true,
49
+ },
50
+ createdBy: {
51
+ type: String,
52
+ required: true,
53
+ },
54
+ createdAt: {
55
+ type: Date,
56
+ required: true,
57
+ },
58
+ updatedAt: {
59
+ type: Date,
60
+ required: true,
61
+ },
62
+ }, {
63
+ toJSON: {
64
+ transform(doc, ret) {
65
+ ret.id = ret._id.valueOf();
66
+ delete ret._id;
67
+ delete ret.__v;
68
+ },
69
+ },
70
+ });
71
+ IndicativeQuotePageSchema.statics.build = (attrs) => {
72
+ return new IndicativeQuotePage(attrs);
73
+ };
74
+ const IndicativeQuotePage = mongoose.model("PublicQuotePage", IndicativeQuotePageSchema);
75
+ return IndicativeQuotePage;
76
+ };
77
+ exports.buildIndicativeQuotePage = buildIndicativeQuotePage;
@@ -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
  }
@@ -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
- const lower = headerKey.toLowerCase();
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
- // Use optional chaining
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) : value;
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
- else {
169
- return "************";
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) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@riocrypto/common-server",
3
- "version": "1.0.2711",
3
+ "version": "1.0.2713",
4
4
  "description": "",
5
5
  "main": "./build/index.js",
6
6
  "types": "./build/index.d.ts",
@@ -28,7 +28,7 @@
28
28
  "@google-cloud/secret-manager": "^5.3.0",
29
29
  "@google-cloud/storage": "^6.9.5",
30
30
  "@hyperdx/node-opentelemetry": "^0.7.0",
31
- "@riocrypto/common": "^1.0.2510",
31
+ "@riocrypto/common": "^1.0.2511",
32
32
  "@types/express": "^4.17.13",
33
33
  "axios": "^1.7.4",
34
34
  "crypto-js": "^4.2.0",