hi-secure 1.0.15 → 1.0.17
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/dist/adapters/ArgonAdapter.d.ts +1 -1
- package/dist/adapters/ArgonAdapter.d.ts.map +1 -1
- package/dist/adapters/ArgonAdapter.js +7 -5
- package/dist/adapters/ArgonAdapter.js.map +1 -1
- package/dist/adapters/BcryptAdapter.d.ts.map +1 -1
- package/dist/adapters/BcryptAdapter.js +7 -3
- package/dist/adapters/BcryptAdapter.js.map +1 -1
- package/dist/adapters/ExpressRLAdapter.d.ts.map +1 -1
- package/dist/adapters/ExpressRLAdapter.js +10 -6
- package/dist/adapters/ExpressRLAdapter.js.map +1 -1
- package/dist/adapters/ExpressValidatorAdapter.d.ts.map +1 -1
- package/dist/adapters/ExpressValidatorAdapter.js +14 -10
- package/dist/adapters/ExpressValidatorAdapter.js.map +1 -1
- package/dist/adapters/GoogleAdapter.d.ts.map +1 -1
- package/dist/adapters/GoogleAdapter.js +19 -16
- package/dist/adapters/GoogleAdapter.js.map +1 -1
- package/dist/adapters/JWTAdapter.d.ts.map +1 -1
- package/dist/adapters/JWTAdapter.js +25 -15
- package/dist/adapters/JWTAdapter.js.map +1 -1
- package/dist/adapters/RLFlexibleAdapter.d.ts.map +1 -1
- package/dist/adapters/RLFlexibleAdapter.js +23 -12
- package/dist/adapters/RLFlexibleAdapter.js.map +1 -1
- package/dist/adapters/SanitizeHtmlAdapter.d.ts.map +1 -1
- package/dist/adapters/SanitizeHtmlAdapter.js +17 -13
- package/dist/adapters/SanitizeHtmlAdapter.js.map +1 -1
- package/dist/adapters/XSSAdapter.d.ts +1 -1
- package/dist/adapters/XSSAdapter.d.ts.map +1 -1
- package/dist/adapters/XSSAdapter.js +21 -20
- package/dist/adapters/XSSAdapter.js.map +1 -1
- package/dist/adapters/ZodAdapter.d.ts +1 -1
- package/dist/adapters/ZodAdapter.d.ts.map +1 -1
- package/dist/adapters/ZodAdapter.js +10 -8
- package/dist/adapters/ZodAdapter.js.map +1 -1
- package/dist/core/HiSecure.d.ts +3 -4
- package/dist/core/HiSecure.d.ts.map +1 -1
- package/dist/core/HiSecure.js +91 -120
- package/dist/core/HiSecure.js.map +1 -1
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +8 -1
- package/dist/index.js.map +1 -1
- package/dist/logging/morganSetup.d.ts.map +1 -1
- package/dist/logging/morganSetup.js +8 -1
- package/dist/logging/morganSetup.js.map +1 -1
- package/dist/logging/winstonSetup.d.ts.map +1 -1
- package/dist/logging/winstonSetup.js +17 -3
- package/dist/logging/winstonSetup.js.map +1 -1
- package/dist/managers/AuthManager.d.ts +2 -2
- package/dist/managers/AuthManager.d.ts.map +1 -1
- package/dist/managers/AuthManager.js +59 -31
- package/dist/managers/AuthManager.js.map +1 -1
- package/dist/managers/CorsManager.d.ts.map +1 -1
- package/dist/managers/CorsManager.js +18 -11
- package/dist/managers/CorsManager.js.map +1 -1
- package/dist/managers/HashManager.d.ts +1 -1
- package/dist/managers/HashManager.d.ts.map +1 -1
- package/dist/managers/HashManager.js +35 -17
- package/dist/managers/HashManager.js.map +1 -1
- package/dist/managers/JsonManager.d.ts +1 -1
- package/dist/managers/JsonManager.d.ts.map +1 -1
- package/dist/managers/JsonManager.js +44 -16
- package/dist/managers/JsonManager.js.map +1 -1
- package/dist/managers/RateLimitManager.d.ts +1 -1
- package/dist/managers/RateLimitManager.d.ts.map +1 -1
- package/dist/managers/RateLimitManager.js +43 -22
- package/dist/managers/RateLimitManager.js.map +1 -1
- package/dist/managers/SanitizerManager.d.ts.map +1 -1
- package/dist/managers/SanitizerManager.js +32 -15
- package/dist/managers/SanitizerManager.js.map +1 -1
- package/dist/managers/ValidatorManager.d.ts.map +1 -1
- package/dist/managers/ValidatorManager.js +31 -7
- package/dist/managers/ValidatorManager.js.map +1 -1
- package/package.json +2 -6
- package/readme.md +3 -6
- package/src/adapters/ArgonAdapter.ts +10 -6
- package/src/adapters/BcryptAdapter.ts +7 -8
- package/src/adapters/ExpressRLAdapter.ts +14 -9
- package/src/adapters/ExpressValidatorAdapter.ts +17 -11
- package/src/adapters/GoogleAdapter.ts +24 -21
- package/src/adapters/JWTAdapter.ts +33 -21
- package/src/adapters/RLFlexibleAdapter.ts +31 -16
- package/src/adapters/SanitizeHtmlAdapter.ts +28 -18
- package/src/adapters/XSSAdapter.ts +33 -38
- package/src/adapters/ZodAdapter.ts +10 -10
- package/src/core/HiSecure.ts +127 -161
- package/src/index.ts +4 -0
- package/src/logging/morganSetup.ts +11 -1
- package/src/logging/winstonSetup.ts +35 -8
- package/src/managers/AuthManager.ts +64 -34
- package/src/managers/CorsManager.ts +23 -16
- package/src/managers/HashManager.ts +48 -19
- package/src/managers/JsonManager.ts +57 -15
- package/src/managers/RateLimitManager.ts +61 -29
- package/src/managers/SanitizerManager.ts +47 -25
- package/src/managers/ValidatorManager.ts +40 -15
|
@@ -1,31 +1,37 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.RateLimitManager = void 0;
|
|
4
|
-
const
|
|
4
|
+
const AdapterError_1 = require("../core/errors/AdapterError");
|
|
5
5
|
const logging_1 = require("../logging");
|
|
6
6
|
class RateLimitManager {
|
|
7
7
|
constructor(config, primaryAdapter, fallbackAdapter) {
|
|
8
8
|
this.config = config;
|
|
9
9
|
this.primaryAdapter = primaryAdapter;
|
|
10
10
|
this.fallbackAdapter = fallbackAdapter;
|
|
11
|
+
logging_1.logger.info("RateLimitManager initialized", {
|
|
12
|
+
layer: "rate-limit-manager",
|
|
13
|
+
primaryConfigured: true,
|
|
14
|
+
fallbackConfigured: !!fallbackAdapter
|
|
15
|
+
});
|
|
11
16
|
}
|
|
12
17
|
middleware(opts) {
|
|
13
18
|
let finalOptions = {};
|
|
14
|
-
|
|
19
|
+
const mode = opts?.mode || "default";
|
|
20
|
+
if (mode === "strict") {
|
|
15
21
|
finalOptions = {
|
|
16
22
|
windowMs: 10000,
|
|
17
23
|
max: 5,
|
|
18
24
|
message: "Too many requests, please slow down."
|
|
19
25
|
};
|
|
20
26
|
}
|
|
21
|
-
else if (
|
|
27
|
+
else if (mode === "relaxed") {
|
|
22
28
|
finalOptions = {
|
|
23
29
|
windowMs: 60000,
|
|
24
30
|
max: 100,
|
|
25
31
|
message: "Rate limit exceeded."
|
|
26
32
|
};
|
|
27
33
|
}
|
|
28
|
-
else if (
|
|
34
|
+
else if (mode === "api") {
|
|
29
35
|
finalOptions = {
|
|
30
36
|
windowMs: 15 * 60 * 1000,
|
|
31
37
|
max: 100,
|
|
@@ -42,50 +48,65 @@ class RateLimitManager {
|
|
|
42
48
|
};
|
|
43
49
|
}
|
|
44
50
|
if (opts?.options) {
|
|
45
|
-
const allowedOverrides = [
|
|
51
|
+
const allowedOverrides = [
|
|
52
|
+
"message",
|
|
53
|
+
"skipFailedRequests",
|
|
54
|
+
"standardHeaders",
|
|
55
|
+
"legacyHeaders"
|
|
56
|
+
];
|
|
46
57
|
for (const key of allowedOverrides) {
|
|
47
58
|
if (opts.options[key] !== undefined) {
|
|
48
59
|
finalOptions[key] = opts.options[key];
|
|
49
60
|
}
|
|
50
61
|
}
|
|
51
|
-
const attemptedOverrides = Object.keys(opts.options).filter(k => !allowedOverrides.includes(k) && k !==
|
|
62
|
+
const attemptedOverrides = Object.keys(opts.options).filter(k => !allowedOverrides.includes(k) && k !== "mode");
|
|
52
63
|
if (attemptedOverrides.length > 0) {
|
|
53
64
|
logging_1.logger.warn("Rate limit overrides ignored", {
|
|
54
|
-
|
|
65
|
+
layer: "rate-limit-manager",
|
|
66
|
+
operation: "configure",
|
|
67
|
+
mode,
|
|
55
68
|
ignoredOptions: attemptedOverrides
|
|
56
69
|
});
|
|
57
70
|
}
|
|
58
71
|
}
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
}
|
|
62
|
-
if (finalOptions.legacyHeaders === undefined) {
|
|
63
|
-
finalOptions.legacyHeaders = false;
|
|
64
|
-
}
|
|
72
|
+
finalOptions.standardHeaders ?? (finalOptions.standardHeaders = true);
|
|
73
|
+
finalOptions.legacyHeaders ?? (finalOptions.legacyHeaders = false);
|
|
65
74
|
try {
|
|
66
|
-
logging_1.logger.info("
|
|
67
|
-
|
|
75
|
+
logging_1.logger.info("Rate limiting applied", {
|
|
76
|
+
layer: "rate-limit-manager",
|
|
77
|
+
operation: "apply",
|
|
78
|
+
mode,
|
|
68
79
|
windowMs: finalOptions.windowMs,
|
|
69
80
|
max: finalOptions.max
|
|
70
81
|
});
|
|
71
82
|
return this.primaryAdapter.getMiddleware(finalOptions);
|
|
72
83
|
}
|
|
73
84
|
catch (err) {
|
|
74
|
-
logging_1.logger.warn("Primary rate limiter failed
|
|
75
|
-
|
|
85
|
+
logging_1.logger.warn("Primary rate limiter failed", {
|
|
86
|
+
layer: "rate-limit-manager",
|
|
87
|
+
operation: "apply",
|
|
88
|
+
mode,
|
|
89
|
+
reason: err?.message
|
|
76
90
|
});
|
|
77
91
|
if (!this.fallbackAdapter) {
|
|
78
|
-
throw new
|
|
92
|
+
throw new AdapterError_1.AdapterError("Rate limiters failed; no fallback adapter configured.");
|
|
79
93
|
}
|
|
80
94
|
try {
|
|
81
|
-
logging_1.logger.
|
|
95
|
+
logging_1.logger.warn("Using fallback rate limiter", {
|
|
96
|
+
layer: "rate-limit-manager",
|
|
97
|
+
operation: "fallback",
|
|
98
|
+
mode
|
|
99
|
+
});
|
|
82
100
|
return this.fallbackAdapter.getMiddleware(finalOptions);
|
|
83
101
|
}
|
|
84
102
|
catch (fallbackErr) {
|
|
85
|
-
logging_1.logger.error("Fallback limiter
|
|
86
|
-
|
|
103
|
+
logging_1.logger.error("Fallback rate limiter failed", {
|
|
104
|
+
layer: "rate-limit-manager",
|
|
105
|
+
operation: "fallback",
|
|
106
|
+
mode,
|
|
107
|
+
reason: fallbackErr?.message
|
|
87
108
|
});
|
|
88
|
-
throw new
|
|
109
|
+
throw new AdapterError_1.AdapterError("Both primary and fallback rate limiters failed.");
|
|
89
110
|
}
|
|
90
111
|
}
|
|
91
112
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"RateLimitManager.js","sourceRoot":"","sources":["../../src/managers/RateLimitManager.ts"],"names":[],"mappings":";;;AACA,
|
|
1
|
+
{"version":3,"file":"RateLimitManager.js","sourceRoot":"","sources":["../../src/managers/RateLimitManager.ts"],"names":[],"mappings":"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","sourcesContent":["import { HiSecureConfig } from \"../core/types/HiSecureConfig\";\r\nimport { AdapterError } from \"../core/errors/AdapterError\";\r\nimport { logger } from \"../logging\";\r\n\r\ninterface RateLimiterAdapter {\r\n getMiddleware: (options?: any) => any;\r\n}\r\n\r\nexport class RateLimitManager {\r\n private config: HiSecureConfig[\"rateLimiter\"];\r\n private primaryAdapter: RateLimiterAdapter;\r\n private fallbackAdapter: RateLimiterAdapter | null;\r\n\r\n constructor(\r\n config: HiSecureConfig[\"rateLimiter\"],\r\n primaryAdapter: RateLimiterAdapter,\r\n fallbackAdapter: RateLimiterAdapter | null\r\n ) {\r\n this.config = config;\r\n this.primaryAdapter = primaryAdapter;\r\n this.fallbackAdapter = fallbackAdapter;\r\n\r\n logger.info(\"RateLimitManager initialized\", {\r\n layer: \"rate-limit-manager\",\r\n primaryConfigured: true,\r\n fallbackConfigured: !!fallbackAdapter\r\n });\r\n }\r\n\r\n middleware(opts?: { mode?: \"strict\" | \"relaxed\" | \"api\"; options?: any }) {\r\n let finalOptions: any = {};\r\n const mode = opts?.mode || \"default\";\r\n\r\n if (mode === \"strict\") {\r\n finalOptions = {\r\n windowMs: 10_000,\r\n max: 5,\r\n message: \"Too many requests, please slow down.\"\r\n };\r\n } else if (mode === \"relaxed\") {\r\n finalOptions = {\r\n windowMs: 60_000,\r\n max: 100,\r\n message: \"Rate limit exceeded.\"\r\n };\r\n } else if (mode === \"api\") {\r\n finalOptions = {\r\n windowMs: 15 * 60 * 1000,\r\n max: 100,\r\n message: \"API rate limit exceeded.\"\r\n };\r\n } else {\r\n finalOptions = {\r\n windowMs: this.config.windowMs,\r\n max: this.config.maxRequests,\r\n message: this.config.message,\r\n standardHeaders: true,\r\n legacyHeaders: false\r\n };\r\n }\r\n\r\n if (opts?.options) {\r\n const allowedOverrides = [\r\n \"message\",\r\n \"skipFailedRequests\",\r\n \"standardHeaders\",\r\n \"legacyHeaders\"\r\n ];\r\n\r\n for (const key of allowedOverrides) {\r\n if (opts.options[key] !== undefined) {\r\n finalOptions[key] = opts.options[key];\r\n }\r\n }\r\n\r\n const attemptedOverrides = Object.keys(opts.options).filter(\r\n k => !allowedOverrides.includes(k) && k !== \"mode\"\r\n );\r\n\r\n if (attemptedOverrides.length > 0) {\r\n logger.warn(\"Rate limit overrides ignored\", {\r\n layer: \"rate-limit-manager\",\r\n operation: \"configure\",\r\n mode,\r\n ignoredOptions: attemptedOverrides\r\n });\r\n }\r\n }\r\n\r\n finalOptions.standardHeaders ??= true;\r\n finalOptions.legacyHeaders ??= false;\r\n\r\n try {\r\n logger.info(\"Rate limiting applied\", {\r\n layer: \"rate-limit-manager\",\r\n operation: \"apply\",\r\n mode,\r\n windowMs: finalOptions.windowMs,\r\n max: finalOptions.max\r\n });\r\n\r\n return this.primaryAdapter.getMiddleware(finalOptions);\r\n\r\n } catch (err: any) {\r\n logger.warn(\"Primary rate limiter failed\", {\r\n layer: \"rate-limit-manager\",\r\n operation: \"apply\",\r\n mode,\r\n reason: err?.message\r\n });\r\n\r\n if (!this.fallbackAdapter) {\r\n throw new AdapterError(\r\n \"Rate limiters failed; no fallback adapter configured.\"\r\n );\r\n }\r\n\r\n try {\r\n logger.warn(\"Using fallback rate limiter\", {\r\n layer: \"rate-limit-manager\",\r\n operation: \"fallback\",\r\n mode\r\n });\r\n\r\n return this.fallbackAdapter.getMiddleware(finalOptions);\r\n\r\n } catch (fallbackErr: any) {\r\n logger.error(\"Fallback rate limiter failed\", {\r\n layer: \"rate-limit-manager\",\r\n operation: \"fallback\",\r\n mode,\r\n reason: fallbackErr?.message\r\n });\r\n\r\n throw new AdapterError(\r\n \"Both primary and fallback rate limiters failed.\"\r\n );\r\n }\r\n }\r\n }\r\n}\r\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SanitizerManager.d.ts","sourceRoot":"","sources":["../../src/managers/SanitizerManager.ts"],"names":[],"mappings":"AAGA,UAAU,gBAAgB;IACtB,QAAQ,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,GAAG,KAAK,MAAM,CAAC;CACtD;AAED,qBAAa,gBAAgB;IACzB,OAAO,CAAC,OAAO,CAAmB;IAClC,OAAO,CAAC,QAAQ,CAA0B;gBAE9B,OAAO,EAAE,gBAAgB,EAAE,QAAQ,GAAE,gBAAgB,GAAG,IAAW;
|
|
1
|
+
{"version":3,"file":"SanitizerManager.d.ts","sourceRoot":"","sources":["../../src/managers/SanitizerManager.ts"],"names":[],"mappings":"AAGA,UAAU,gBAAgB;IACtB,QAAQ,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,GAAG,KAAK,MAAM,CAAC;CACtD;AAED,qBAAa,gBAAgB;IACzB,OAAO,CAAC,OAAO,CAAmB;IAClC,OAAO,CAAC,QAAQ,CAA0B;gBAE9B,OAAO,EAAE,gBAAgB,EAAE,QAAQ,GAAE,gBAAgB,GAAG,IAAW;IAU/E,QAAQ,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,GAAG,GAAG,MAAM;IA6B9C,UAAU,CAAC,OAAO,CAAC,EAAE,GAAG,IACZ,KAAK,GAAG,EAAE,MAAM,GAAG,EAAE,MAAM,GAAG;CAsE7C"}
|
|
@@ -1,26 +1,37 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.SanitizerManager = void 0;
|
|
4
|
-
const
|
|
4
|
+
const SanitizerError_1 = require("../core/errors/SanitizerError");
|
|
5
5
|
const logging_1 = require("../logging");
|
|
6
6
|
class SanitizerManager {
|
|
7
7
|
constructor(primary, fallback = null) {
|
|
8
8
|
this.primary = primary;
|
|
9
9
|
this.fallback = fallback;
|
|
10
|
+
logging_1.logger.info("SanitizerManager initialized", {
|
|
11
|
+
layer: "sanitizer-manager",
|
|
12
|
+
fallbackEnabled: !!fallback
|
|
13
|
+
});
|
|
10
14
|
}
|
|
11
15
|
sanitize(value, options) {
|
|
12
|
-
if (typeof value !==
|
|
16
|
+
if (typeof value !== "string") {
|
|
13
17
|
return value;
|
|
14
18
|
}
|
|
15
19
|
try {
|
|
16
20
|
return this.primary.sanitize(value, options);
|
|
17
21
|
}
|
|
18
22
|
catch (err) {
|
|
19
|
-
logging_1.logger.warn("Primary sanitizer failed", {
|
|
23
|
+
logging_1.logger.warn("Primary sanitizer failed", {
|
|
24
|
+
layer: "sanitizer-manager",
|
|
25
|
+
operation: "sanitize",
|
|
26
|
+
reason: err?.message
|
|
27
|
+
});
|
|
20
28
|
if (!this.fallback) {
|
|
21
|
-
throw new
|
|
29
|
+
throw new SanitizerError_1.SanitizerError("Primary sanitizer failed and no fallback available.");
|
|
22
30
|
}
|
|
23
|
-
logging_1.logger.
|
|
31
|
+
logging_1.logger.warn("Sanitizer fallback used", {
|
|
32
|
+
layer: "sanitizer-manager",
|
|
33
|
+
operation: "sanitize"
|
|
34
|
+
});
|
|
24
35
|
return this.fallback.sanitize(value, options);
|
|
25
36
|
}
|
|
26
37
|
}
|
|
@@ -39,7 +50,10 @@ class SanitizerManager {
|
|
|
39
50
|
throw err;
|
|
40
51
|
}
|
|
41
52
|
fallbackTriggered = true;
|
|
42
|
-
logging_1.logger.warn("Switching to fallback sanitizer for
|
|
53
|
+
logging_1.logger.warn("Switching to fallback sanitizer for request", {
|
|
54
|
+
layer: "sanitizer-manager",
|
|
55
|
+
operation: "middleware"
|
|
56
|
+
});
|
|
43
57
|
return this.fallback.sanitize(value, options);
|
|
44
58
|
}
|
|
45
59
|
};
|
|
@@ -53,19 +67,20 @@ class SanitizerManager {
|
|
|
53
67
|
sanitizedBody[key] = safeSanitize(value);
|
|
54
68
|
}
|
|
55
69
|
else if (Array.isArray(value)) {
|
|
56
|
-
sanitizedBody[key] = value.map(item => typeof item === "string"
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
sanitizedBody[key] = value;
|
|
70
|
+
sanitizedBody[key] = value.map(item => typeof item === "string"
|
|
71
|
+
? safeSanitize(item)
|
|
72
|
+
: item);
|
|
60
73
|
}
|
|
61
74
|
else {
|
|
62
75
|
sanitizedBody[key] = value;
|
|
63
76
|
}
|
|
64
77
|
}
|
|
65
78
|
req.sanitizedBody = sanitizedBody;
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
79
|
+
// ✅ visible + safe info
|
|
80
|
+
logging_1.logger.info("Request body sanitized", {
|
|
81
|
+
layer: "sanitizer-manager",
|
|
82
|
+
operation: "middleware",
|
|
83
|
+
fieldCount: Object.keys(sanitizedBody).length,
|
|
69
84
|
usedFallback: fallbackTriggered
|
|
70
85
|
});
|
|
71
86
|
}
|
|
@@ -73,9 +88,11 @@ class SanitizerManager {
|
|
|
73
88
|
}
|
|
74
89
|
catch (err) {
|
|
75
90
|
logging_1.logger.error("Sanitizer middleware failed", {
|
|
76
|
-
|
|
91
|
+
layer: "sanitizer-manager",
|
|
92
|
+
operation: "middleware",
|
|
93
|
+
reason: err?.message
|
|
77
94
|
});
|
|
78
|
-
next(new
|
|
95
|
+
next(new SanitizerError_1.SanitizerError("Sanitizer middleware failure"));
|
|
79
96
|
}
|
|
80
97
|
};
|
|
81
98
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SanitizerManager.js","sourceRoot":"","sources":["../../src/managers/SanitizerManager.ts"],"names":[],"mappings":";;;AAAA,
|
|
1
|
+
{"version":3,"file":"SanitizerManager.js","sourceRoot":"","sources":["../../src/managers/SanitizerManager.ts"],"names":[],"mappings":";;;AAAA,kEAA+D;AAC/D,wCAAoC;AAMpC,MAAa,gBAAgB;IAIzB,YAAY,OAAyB,EAAE,WAAoC,IAAI;QAC3E,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC;QACvB,IAAI,CAAC,QAAQ,GAAG,QAAQ,CAAC;QAEzB,gBAAM,CAAC,IAAI,CAAC,8BAA8B,EAAE;YACxC,KAAK,EAAE,mBAAmB;YAC1B,eAAe,EAAE,CAAC,CAAC,QAAQ;SAC9B,CAAC,CAAC;IACP,CAAC;IAED,QAAQ,CAAC,KAAa,EAAE,OAAa;QACjC,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;YAC5B,OAAO,KAAK,CAAC;QACjB,CAAC;QAED,IAAI,CAAC;YACD,OAAO,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAC,CAAC;QACjD,CAAC;QAAC,OAAO,GAAQ,EAAE,CAAC;YAChB,gBAAM,CAAC,IAAI,CAAC,0BAA0B,EAAE;gBACpC,KAAK,EAAE,mBAAmB;gBAC1B,SAAS,EAAE,UAAU;gBACrB,MAAM,EAAE,GAAG,EAAE,OAAO;aACvB,CAAC,CAAC;YAEH,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,CAAC;gBACjB,MAAM,IAAI,+BAAc,CACpB,qDAAqD,CACxD,CAAC;YACN,CAAC;YAED,gBAAM,CAAC,IAAI,CAAC,yBAAyB,EAAE;gBACnC,KAAK,EAAE,mBAAmB;gBAC1B,SAAS,EAAE,UAAU;aACxB,CAAC,CAAC;YAEH,OAAO,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAC,CAAC;QAClD,CAAC;IACL,CAAC;IAED,UAAU,CAAC,OAAa;QACpB,OAAO,CAAC,GAAQ,EAAE,IAAS,EAAE,IAAS,EAAE,EAAE;YACtC,IAAI,iBAAiB,GAAG,KAAK,CAAC;YAE9B,MAAM,YAAY,GAAG,CAAC,KAAa,EAAU,EAAE;gBAC3C,IAAI,iBAAiB,IAAI,IAAI,CAAC,QAAQ,EAAE,CAAC;oBACrC,OAAO,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAC,CAAC;gBAClD,CAAC;gBAED,IAAI,CAAC;oBACD,OAAO,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAC,CAAC;gBACjD,CAAC;gBAAC,OAAO,GAAQ,EAAE,CAAC;oBAChB,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,CAAC;wBACjB,MAAM,GAAG,CAAC;oBACd,CAAC;oBAED,iBAAiB,GAAG,IAAI,CAAC;oBAEzB,gBAAM,CAAC,IAAI,CAAC,6CAA6C,EAAE;wBACvD,KAAK,EAAE,mBAAmB;wBAC1B,SAAS,EAAE,YAAY;qBAC1B,CAAC,CAAC;oBAEH,OAAO,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAC,CAAC;gBAClD,CAAC;YACL,CAAC,CAAC;YAEF,IAAI,CAAC;gBACD,IAAI,GAAG,CAAC,IAAI,IAAI,OAAO,GAAG,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;oBAC3C,MAAM,YAAY,GAAG,GAAG,CAAC,IAAI,CAAC;oBAC9B,MAAM,aAAa,GAAQ,KAAK,CAAC,OAAO,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;oBAEjE,KAAK,MAAM,GAAG,IAAI,MAAM,CAAC,IAAI,CAAC,YAAY,CAAC,EAAE,CAAC;wBAC1C,MAAM,KAAK,GAAG,YAAY,CAAC,GAAG,CAAC,CAAC;wBAEhC,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;4BAC5B,aAAa,CAAC,GAAG,CAAC,GAAG,YAAY,CAAC,KAAK,CAAC,CAAC;wBAC7C,CAAC;6BAAM,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;4BAC9B,aAAa,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAClC,OAAO,IAAI,KAAK,QAAQ;gCACpB,CAAC,CAAC,YAAY,CAAC,IAAI,CAAC;gCACpB,CAAC,CAAC,IAAI,CACb,CAAC;wBACN,CAAC;6BAAM,CAAC;4BACJ,aAAa,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC;wBAC/B,CAAC;oBACL,CAAC;oBAED,GAAG,CAAC,aAAa,GAAG,aAAa,CAAC;oBAElC,wBAAwB;oBACxB,gBAAM,CAAC,IAAI,CAAC,wBAAwB,EAAE;wBAClC,KAAK,EAAE,mBAAmB;wBAC1B,SAAS,EAAE,YAAY;wBACvB,UAAU,EAAE,MAAM,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC,MAAM;wBAC7C,YAAY,EAAE,iBAAiB;qBAClC,CAAC,CAAC;gBACP,CAAC;gBAED,IAAI,EAAE,CAAC;YACX,CAAC;YAAC,OAAO,GAAQ,EAAE,CAAC;gBAChB,gBAAM,CAAC,KAAK,CAAC,6BAA6B,EAAE;oBACxC,KAAK,EAAE,mBAAmB;oBAC1B,SAAS,EAAE,YAAY;oBACvB,MAAM,EAAE,GAAG,EAAE,OAAO;iBACvB,CAAC,CAAC;gBAEH,IAAI,CAAC,IAAI,+BAAc,CAAC,8BAA8B,CAAC,CAAC,CAAC;YAC7D,CAAC;QACL,CAAC,CAAC;IACN,CAAC;CACJ;AAlHD,4CAkHC","sourcesContent":["import { SanitizerError } from \"../core/errors/SanitizerError\";\r\nimport { logger } from \"../logging\";\r\n\r\ninterface SanitizerAdapter {\r\n sanitize: (value: string, options?: any) => string;\r\n}\r\n\r\nexport class SanitizerManager {\r\n private primary: SanitizerAdapter;\r\n private fallback: SanitizerAdapter | null;\r\n\r\n constructor(primary: SanitizerAdapter, fallback: SanitizerAdapter | null = null) {\r\n this.primary = primary;\r\n this.fallback = fallback;\r\n\r\n logger.info(\"SanitizerManager initialized\", {\r\n layer: \"sanitizer-manager\",\r\n fallbackEnabled: !!fallback\r\n });\r\n }\r\n\r\n sanitize(value: string, options?: any): string {\r\n if (typeof value !== \"string\") {\r\n return value;\r\n }\r\n\r\n try {\r\n return this.primary.sanitize(value, options);\r\n } catch (err: any) {\r\n logger.warn(\"Primary sanitizer failed\", {\r\n layer: \"sanitizer-manager\",\r\n operation: \"sanitize\",\r\n reason: err?.message\r\n });\r\n\r\n if (!this.fallback) {\r\n throw new SanitizerError(\r\n \"Primary sanitizer failed and no fallback available.\"\r\n );\r\n }\r\n\r\n logger.warn(\"Sanitizer fallback used\", {\r\n layer: \"sanitizer-manager\",\r\n operation: \"sanitize\"\r\n });\r\n\r\n return this.fallback.sanitize(value, options);\r\n }\r\n }\r\n\r\n middleware(options?: any) {\r\n return (req: any, _res: any, next: any) => {\r\n let fallbackTriggered = false;\r\n\r\n const safeSanitize = (value: string): string => {\r\n if (fallbackTriggered && this.fallback) {\r\n return this.fallback.sanitize(value, options);\r\n }\r\n\r\n try {\r\n return this.primary.sanitize(value, options);\r\n } catch (err: any) {\r\n if (!this.fallback) {\r\n throw err;\r\n }\r\n\r\n fallbackTriggered = true;\r\n\r\n logger.warn(\"Switching to fallback sanitizer for request\", {\r\n layer: \"sanitizer-manager\",\r\n operation: \"middleware\"\r\n });\r\n\r\n return this.fallback.sanitize(value, options);\r\n }\r\n };\r\n\r\n try {\r\n if (req.body && typeof req.body === \"object\") {\r\n const originalBody = req.body;\r\n const sanitizedBody: any = Array.isArray(originalBody) ? [] : {};\r\n\r\n for (const key of Object.keys(originalBody)) {\r\n const value = originalBody[key];\r\n\r\n if (typeof value === \"string\") {\r\n sanitizedBody[key] = safeSanitize(value);\r\n } else if (Array.isArray(value)) {\r\n sanitizedBody[key] = value.map(item =>\r\n typeof item === \"string\"\r\n ? safeSanitize(item)\r\n : item\r\n );\r\n } else {\r\n sanitizedBody[key] = value;\r\n }\r\n }\r\n\r\n req.sanitizedBody = sanitizedBody;\r\n\r\n // ✅ visible + safe info\r\n logger.info(\"Request body sanitized\", {\r\n layer: \"sanitizer-manager\",\r\n operation: \"middleware\",\r\n fieldCount: Object.keys(sanitizedBody).length,\r\n usedFallback: fallbackTriggered\r\n });\r\n }\r\n\r\n next();\r\n } catch (err: any) {\r\n logger.error(\"Sanitizer middleware failed\", {\r\n layer: \"sanitizer-manager\",\r\n operation: \"middleware\",\r\n reason: err?.message\r\n });\r\n\r\n next(new SanitizerError(\"Sanitizer middleware failure\"));\r\n }\r\n };\r\n }\r\n}\r\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ValidatorManager.d.ts","sourceRoot":"","sources":["../../src/managers/ValidatorManager.ts"],"names":[],"mappings":"AAGA,UAAU,gBAAgB;IACtB,QAAQ,EAAE,CAAC,MAAM,CAAC,EAAE,GAAG,KAAK,GAAG,CAAC;CACnC;AAED,qBAAa,gBAAgB;IACzB,OAAO,CAAC,UAAU,CAAmB;IACrC,OAAO,CAAC,cAAc,CAAmB;gBAE7B,UAAU,EAAE,gBAAgB,EAAE,cAAc,EAAE,gBAAgB;
|
|
1
|
+
{"version":3,"file":"ValidatorManager.d.ts","sourceRoot":"","sources":["../../src/managers/ValidatorManager.ts"],"names":[],"mappings":"AAGA,UAAU,gBAAgB;IACtB,QAAQ,EAAE,CAAC,MAAM,CAAC,EAAE,GAAG,KAAK,GAAG,CAAC;CACnC;AAED,qBAAa,gBAAgB;IACzB,OAAO,CAAC,UAAU,CAAmB;IACrC,OAAO,CAAC,cAAc,CAAmB;gBAE7B,UAAU,EAAE,gBAAgB,EAAE,cAAc,EAAE,gBAAgB;IAU1E,QAAQ,CAAC,MAAM,CAAC,EAAE,GAAG,IAST,KAAK,GAAG,EAAE,KAAK,GAAG,EAAE,MAAM,GAAG;CAmE5C"}
|
|
@@ -2,11 +2,15 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.ValidatorManager = void 0;
|
|
4
4
|
const logging_1 = require("../logging");
|
|
5
|
-
const
|
|
5
|
+
const ValidationError_1 = require("../core/errors/ValidationError");
|
|
6
6
|
class ValidatorManager {
|
|
7
7
|
constructor(zodAdapter, expressAdapter) {
|
|
8
8
|
this.zodAdapter = zodAdapter;
|
|
9
9
|
this.expressAdapter = expressAdapter;
|
|
10
|
+
logging_1.logger.info("ValidatorManager initialized", {
|
|
11
|
+
layer: "validator-manager",
|
|
12
|
+
adapters: ["zod", "express-validator"]
|
|
13
|
+
});
|
|
10
14
|
}
|
|
11
15
|
validate(schema) {
|
|
12
16
|
const isZod = schema &&
|
|
@@ -16,17 +20,25 @@ class ValidatorManager {
|
|
|
16
20
|
const isExpressValidator = Array.isArray(schema);
|
|
17
21
|
return (req, res, next) => {
|
|
18
22
|
let middleware;
|
|
23
|
+
let adapterUsed = "none";
|
|
19
24
|
if (isZod) {
|
|
20
|
-
|
|
25
|
+
adapterUsed = "zod";
|
|
21
26
|
middleware = this.zodAdapter.validate(schema);
|
|
22
27
|
}
|
|
23
28
|
else if (isExpressValidator) {
|
|
24
|
-
|
|
29
|
+
adapterUsed = "express-validator";
|
|
25
30
|
middleware = this.expressAdapter.validate(schema);
|
|
26
31
|
}
|
|
27
32
|
else {
|
|
28
33
|
return next();
|
|
29
34
|
}
|
|
35
|
+
logging_1.logger.info("Validation adapter selected", {
|
|
36
|
+
layer: "validator-manager",
|
|
37
|
+
operation: "select",
|
|
38
|
+
adapter: adapterUsed,
|
|
39
|
+
path: req.path,
|
|
40
|
+
method: req.method
|
|
41
|
+
});
|
|
30
42
|
// CASE 1 — express-validator returns ARRAY
|
|
31
43
|
if (Array.isArray(middleware)) {
|
|
32
44
|
let idx = 0;
|
|
@@ -35,17 +47,23 @@ class ValidatorManager {
|
|
|
35
47
|
return next(err);
|
|
36
48
|
const fn = middleware[idx++];
|
|
37
49
|
if (!fn)
|
|
38
|
-
return next();
|
|
50
|
+
return next();
|
|
39
51
|
try {
|
|
40
52
|
fn(req, res, run);
|
|
41
53
|
}
|
|
42
54
|
catch (error) {
|
|
43
|
-
|
|
55
|
+
logging_1.logger.error("Validation middleware execution failed", {
|
|
56
|
+
layer: "validator-manager",
|
|
57
|
+
operation: "execute",
|
|
58
|
+
adapter: adapterUsed,
|
|
59
|
+
reason: error?.message
|
|
60
|
+
});
|
|
61
|
+
next(new ValidationError_1.ValidationError(error.message));
|
|
44
62
|
}
|
|
45
63
|
};
|
|
46
64
|
return run();
|
|
47
65
|
}
|
|
48
|
-
// CASE 2 — Zod returns SINGLE
|
|
66
|
+
// CASE 2 — Zod returns SINGLE middleware
|
|
49
67
|
try {
|
|
50
68
|
middleware(req, res, (err) => {
|
|
51
69
|
if (err)
|
|
@@ -54,7 +72,13 @@ class ValidatorManager {
|
|
|
54
72
|
});
|
|
55
73
|
}
|
|
56
74
|
catch (err) {
|
|
57
|
-
|
|
75
|
+
logging_1.logger.error("Validation middleware execution failed", {
|
|
76
|
+
layer: "validator-manager",
|
|
77
|
+
operation: "execute",
|
|
78
|
+
adapter: adapterUsed,
|
|
79
|
+
reason: err?.message
|
|
80
|
+
});
|
|
81
|
+
next(new ValidationError_1.ValidationError(err.message));
|
|
58
82
|
}
|
|
59
83
|
};
|
|
60
84
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ValidatorManager.js","sourceRoot":"","sources":["../../src/managers/ValidatorManager.ts"],"names":[],"mappings":";;;AAAA,wCAAoC;AACpC,
|
|
1
|
+
{"version":3,"file":"ValidatorManager.js","sourceRoot":"","sources":["../../src/managers/ValidatorManager.ts"],"names":[],"mappings":"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","sourcesContent":["import { logger } from \"../logging\";\r\nimport { ValidationError } from \"../core/errors/ValidationError\";\r\n\r\ninterface ValidatorAdapter {\r\n validate: (schema?: any) => any;\r\n}\r\n\r\nexport class ValidatorManager {\r\n private zodAdapter: ValidatorAdapter;\r\n private expressAdapter: ValidatorAdapter;\r\n\r\n constructor(zodAdapter: ValidatorAdapter, expressAdapter: ValidatorAdapter) {\r\n this.zodAdapter = zodAdapter;\r\n this.expressAdapter = expressAdapter;\r\n\r\n logger.info(\"ValidatorManager initialized\", {\r\n layer: \"validator-manager\",\r\n adapters: [\"zod\", \"express-validator\"]\r\n });\r\n }\r\n\r\n validate(schema?: any) {\r\n const isZod =\r\n schema &&\r\n typeof schema === \"object\" &&\r\n typeof schema._def === \"object\" &&\r\n typeof schema.safeParse === \"function\";\r\n\r\n const isExpressValidator = Array.isArray(schema);\r\n\r\n return (req: any, res: any, next: any) => {\r\n let middleware;\r\n let adapterUsed: \"zod\" | \"express-validator\" | \"none\" = \"none\";\r\n\r\n if (isZod) {\r\n adapterUsed = \"zod\";\r\n middleware = this.zodAdapter.validate(schema);\r\n } else if (isExpressValidator) {\r\n adapterUsed = \"express-validator\";\r\n middleware = this.expressAdapter.validate(schema);\r\n } else {\r\n return next();\r\n }\r\n\r\n logger.info(\"Validation adapter selected\", {\r\n layer: \"validator-manager\",\r\n operation: \"select\",\r\n adapter: adapterUsed,\r\n path: req.path,\r\n method: req.method\r\n });\r\n\r\n // CASE 1 — express-validator returns ARRAY\r\n if (Array.isArray(middleware)) {\r\n let idx = 0;\r\n\r\n const run = (err?: any) => {\r\n if (err) return next(err);\r\n\r\n const fn = middleware[idx++];\r\n if (!fn) return next();\r\n\r\n try {\r\n fn(req, res, run);\r\n } catch (error: any) {\r\n logger.error(\"Validation middleware execution failed\", {\r\n layer: \"validator-manager\",\r\n operation: \"execute\",\r\n adapter: adapterUsed,\r\n reason: error?.message\r\n });\r\n\r\n next(new ValidationError(error.message));\r\n }\r\n };\r\n\r\n return run();\r\n }\r\n\r\n // CASE 2 — Zod returns SINGLE middleware\r\n try {\r\n middleware(req, res, (err?: any) => {\r\n if (err) return next(err);\r\n next();\r\n });\r\n } catch (err: any) {\r\n logger.error(\"Validation middleware execution failed\", {\r\n layer: \"validator-manager\",\r\n operation: \"execute\",\r\n adapter: adapterUsed,\r\n reason: err?.message\r\n });\r\n\r\n next(new ValidationError(err.message));\r\n }\r\n };\r\n }\r\n}\r\n"]}
|
package/package.json
CHANGED
|
@@ -1,14 +1,10 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "hi-secure",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.17",
|
|
4
4
|
"description": "Unified security layer for Express.js: authentication, validation, sanitization, rate limiting and CORS",
|
|
5
|
+
"license": "MIT",
|
|
5
6
|
"main": "dist/index.js",
|
|
6
7
|
"types": "dist/index.d.ts",
|
|
7
|
-
"repository": {
|
|
8
|
-
"type": "git",
|
|
9
|
-
"url": "https://github.com/100NikhilBro/hi-secure.git"
|
|
10
|
-
},
|
|
11
|
-
"homepage": "https://github.com/100NikhilBro/hi-secure#readme",
|
|
12
8
|
"keywords": [
|
|
13
9
|
"express",
|
|
14
10
|
"security",
|
package/readme.md
CHANGED
|
@@ -97,7 +97,7 @@ Managing these separately leads to duplicated logic, configuration drift and sub
|
|
|
97
97
|
|
|
98
98
|
<tr>
|
|
99
99
|
<td>Logging</td>
|
|
100
|
-
<td>
|
|
100
|
+
<td>Better</td>
|
|
101
101
|
<td>Structured internal logs</td>
|
|
102
102
|
</tr>
|
|
103
103
|
</table>
|
|
@@ -324,7 +324,7 @@ Choose the style based on complexity and ownership.
|
|
|
324
324
|
|
|
325
325
|
<h4>express-validator (Rule-Based, Inline)</h4>
|
|
326
326
|
|
|
327
|
-
<pre><code>import { body } from "
|
|
327
|
+
<pre><code>import { HiSecure , body } from "hi-secure";
|
|
328
328
|
|
|
329
329
|
router.post(
|
|
330
330
|
"/register",
|
|
@@ -346,7 +346,7 @@ router.post(
|
|
|
346
346
|
|
|
347
347
|
<h4>Zod (Schema-Based, Reusable)</h4>
|
|
348
348
|
|
|
349
|
-
<pre><code>import { z } from "
|
|
349
|
+
<pre><code>import { HiSecure , z } from "hi-secure";
|
|
350
350
|
|
|
351
351
|
const registerSchema = z.object({
|
|
352
352
|
email: z.string().email(),
|
|
@@ -455,9 +455,6 @@ HiSecure.getInstance({
|
|
|
455
455
|
|
|
456
456
|
<hr/>
|
|
457
457
|
|
|
458
|
-
<h2>Final Authentication Setup</h2>
|
|
459
|
-
|
|
460
|
-
<hr/>
|
|
461
458
|
|
|
462
459
|
<h2>🔐 Final Authentication Setup</h2>
|
|
463
460
|
|
|
@@ -3,12 +3,10 @@ import { AdapterError } from "../core/errors/AdapterError";
|
|
|
3
3
|
import { logger } from "../logging";
|
|
4
4
|
|
|
5
5
|
export class ArgonAdapter {
|
|
6
|
-
private options
|
|
6
|
+
private options?: argon2.Options;
|
|
7
7
|
|
|
8
8
|
constructor(options?: argon2.Options) {
|
|
9
|
-
|
|
10
|
-
this.options = options;
|
|
11
|
-
}
|
|
9
|
+
this.options = options;
|
|
12
10
|
}
|
|
13
11
|
|
|
14
12
|
async hash(value: string): Promise<string> {
|
|
@@ -18,8 +16,11 @@ export class ArgonAdapter {
|
|
|
18
16
|
: await argon2.hash(value);
|
|
19
17
|
} catch (err: any) {
|
|
20
18
|
logger.error("Argon2 hashing failed", {
|
|
21
|
-
|
|
19
|
+
adapter: "argon2",
|
|
20
|
+
operation: "hash",
|
|
21
|
+
reason: err?.message
|
|
22
22
|
});
|
|
23
|
+
|
|
23
24
|
throw new AdapterError("Argon2 hashing failed.");
|
|
24
25
|
}
|
|
25
26
|
}
|
|
@@ -33,8 +34,11 @@ export class ArgonAdapter {
|
|
|
33
34
|
return await argon2.verify(hashed, value);
|
|
34
35
|
} catch (err: any) {
|
|
35
36
|
logger.error("Argon2 verify failed", {
|
|
36
|
-
|
|
37
|
+
adapter: "argon2",
|
|
38
|
+
operation: "verify",
|
|
39
|
+
reason: err?.message
|
|
37
40
|
});
|
|
41
|
+
|
|
38
42
|
throw new AdapterError("Argon2 verify failed.");
|
|
39
43
|
}
|
|
40
44
|
}
|
|
@@ -14,8 +14,10 @@ export class BcryptAdapter {
|
|
|
14
14
|
return await bcrypt.hash(value, this.saltRounds);
|
|
15
15
|
} catch (err: any) {
|
|
16
16
|
logger.error("Bcrypt hashing failed", {
|
|
17
|
-
|
|
18
|
-
|
|
17
|
+
adapter: "bcrypt",
|
|
18
|
+
operation: "hash",
|
|
19
|
+
saltRounds: this.saltRounds,
|
|
20
|
+
reason: err?.message
|
|
19
21
|
});
|
|
20
22
|
|
|
21
23
|
throw new AdapterError("Bcrypt hashing failed.");
|
|
@@ -35,15 +37,12 @@ export class BcryptAdapter {
|
|
|
35
37
|
return await bcrypt.compare(value, hashed);
|
|
36
38
|
} catch (err: any) {
|
|
37
39
|
logger.error("Bcrypt verify failed", {
|
|
38
|
-
|
|
40
|
+
adapter: "bcrypt",
|
|
41
|
+
operation: "verify",
|
|
42
|
+
reason: err?.message
|
|
39
43
|
});
|
|
40
44
|
|
|
41
45
|
throw new AdapterError("Bcrypt verify failed.");
|
|
42
46
|
}
|
|
43
47
|
}
|
|
44
48
|
}
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import rateLimit from "express-rate-limit";
|
|
2
|
-
import { logger } from "../logging
|
|
3
|
-
import { AdapterError } from "../core/errors/AdapterError
|
|
2
|
+
import { logger } from "../logging";
|
|
3
|
+
import { AdapterError } from "../core/errors/AdapterError";
|
|
4
4
|
|
|
5
5
|
export interface RateLimitOptions {
|
|
6
6
|
windowMs?: number;
|
|
@@ -16,7 +16,7 @@ export class ExpressRLAdapter {
|
|
|
16
16
|
getMiddleware(options: RateLimitOptions = {}) {
|
|
17
17
|
try {
|
|
18
18
|
const defaultOptions = {
|
|
19
|
-
windowMs: 15 * 60 * 1000,
|
|
19
|
+
windowMs: 15 * 60 * 1000,
|
|
20
20
|
max: 100,
|
|
21
21
|
message: { error: "Too many requests" },
|
|
22
22
|
standardHeaders: true,
|
|
@@ -25,21 +25,26 @@ export class ExpressRLAdapter {
|
|
|
25
25
|
};
|
|
26
26
|
|
|
27
27
|
const finalOptions = { ...defaultOptions, ...options };
|
|
28
|
-
|
|
28
|
+
|
|
29
29
|
const limiter = rateLimit(finalOptions);
|
|
30
|
+
|
|
30
31
|
|
|
31
|
-
logger.
|
|
32
|
+
logger.info("Express rate limiter configured", {
|
|
33
|
+
adapter: "express-rate-limit",
|
|
34
|
+
operation: "configure",
|
|
32
35
|
windowMs: finalOptions.windowMs,
|
|
33
36
|
max: finalOptions.max
|
|
34
37
|
});
|
|
35
38
|
|
|
36
39
|
return limiter;
|
|
37
|
-
|
|
38
40
|
} catch (err: any) {
|
|
39
|
-
logger.error("
|
|
40
|
-
|
|
41
|
+
logger.error("Express rate limiter setup failed", {
|
|
42
|
+
adapter: "express-rate-limit",
|
|
43
|
+
operation: "configure",
|
|
44
|
+
reason: err?.message
|
|
41
45
|
});
|
|
46
|
+
|
|
42
47
|
throw new AdapterError("Express rate limiter creation failed.");
|
|
43
48
|
}
|
|
44
49
|
}
|
|
45
|
-
}
|
|
50
|
+
}
|