hi-secure 1.0.12 → 1.0.13
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.js +2 -2
- package/dist/adapters/ArgonAdapter.js.map +1 -1
- package/dist/adapters/BcryptAdapter.js +2 -2
- package/dist/adapters/BcryptAdapter.js.map +1 -1
- package/dist/adapters/ExpressRLAdapter.js +2 -2
- package/dist/adapters/ExpressRLAdapter.js.map +1 -1
- package/dist/adapters/ExpressValidatorAdapter.js +1 -1
- package/dist/adapters/ExpressValidatorAdapter.js.map +1 -1
- package/dist/adapters/GoogleAdapter.js +3 -3
- package/dist/adapters/GoogleAdapter.js.map +1 -1
- package/dist/adapters/JWTAdapter.js +2 -2
- package/dist/adapters/JWTAdapter.js.map +1 -1
- package/dist/adapters/RLFlexibleAdapter.js +2 -2
- package/dist/adapters/RLFlexibleAdapter.js.map +1 -1
- package/dist/adapters/SanitizeHtmlAdapter.js +3 -3
- package/dist/adapters/SanitizeHtmlAdapter.js.map +1 -1
- package/dist/adapters/XSSAdapter.js +3 -3
- package/dist/adapters/XSSAdapter.js.map +1 -1
- package/dist/adapters/ZodAdapter.js +1 -1
- package/dist/adapters/ZodAdapter.js.map +1 -1
- package/dist/core/HiSecure.d.ts.map +1 -1
- package/dist/core/HiSecure.js +9 -8
- package/dist/core/HiSecure.js.map +1 -1
- package/dist/core/config.d.ts.map +1 -1
- package/dist/core/config.js +0 -7
- package/dist/core/config.js.map +1 -1
- package/dist/core/constants.d.ts.map +1 -1
- package/dist/core/constants.js +0 -27
- package/dist/core/constants.js.map +1 -1
- package/dist/core/errors/AdapterError.js +1 -1
- package/dist/core/errors/AdapterError.js.map +1 -1
- package/dist/core/types/HiSecureConfig.d.ts.map +1 -1
- package/dist/core/types/HiSecureConfig.js.map +1 -1
- package/dist/core/types/SecureOptions.d.ts.map +1 -1
- package/dist/core/types/SecureOptions.js +0 -1
- package/dist/core/types/SecureOptions.js.map +1 -1
- package/dist/core/useSecure.d.ts.map +1 -1
- package/dist/core/useSecure.js +1 -1
- package/dist/core/useSecure.js.map +1 -1
- package/dist/managers/AuthManager.js +2 -2
- package/dist/managers/AuthManager.js.map +1 -1
- package/dist/managers/CorsManager.d.ts.map +1 -1
- package/dist/managers/CorsManager.js +2 -2
- package/dist/managers/CorsManager.js.map +1 -1
- package/dist/managers/HashManager.js +7 -7
- package/dist/managers/HashManager.js.map +1 -1
- package/dist/managers/JsonManager.js +4 -4
- package/dist/managers/JsonManager.js.map +1 -1
- package/dist/managers/RateLimitManager.js +5 -5
- package/dist/managers/RateLimitManager.js.map +1 -1
- package/dist/managers/SanitizerManager.js +5 -5
- package/dist/managers/SanitizerManager.js.map +1 -1
- package/dist/managers/ValidatorManager.js +2 -2
- package/dist/managers/ValidatorManager.js.map +1 -1
- package/dist/middlewares/errorHandler.js +3 -3
- package/dist/middlewares/errorHandler.js.map +1 -1
- package/package.json +1 -1
- package/src/adapters/ArgonAdapter.ts +2 -2
- package/src/adapters/BcryptAdapter.ts +2 -2
- package/src/adapters/ExpressRLAdapter.ts +2 -2
- package/src/adapters/ExpressValidatorAdapter.ts +1 -1
- package/src/adapters/GoogleAdapter.ts +3 -3
- package/src/adapters/JWTAdapter.ts +2 -2
- package/src/adapters/RLFlexibleAdapter.ts +2 -2
- package/src/adapters/SanitizeHtmlAdapter.ts +3 -3
- package/src/adapters/XSSAdapter.ts +3 -3
- package/src/adapters/ZodAdapter.ts +1 -1
- package/src/core/HiSecure.ts +10 -8
- package/src/core/config.ts +0 -105
- package/src/core/constants.ts +0 -33
- package/src/core/errors/AdapterError.ts +1 -1
- package/src/core/types/HiSecureConfig.ts +0 -1
- package/src/core/types/SecureOptions.ts +0 -27
- package/src/core/useSecure.ts +1 -3
- package/src/managers/AuthManager.ts +2 -2
- package/src/managers/CorsManager.ts +2 -2
- package/src/managers/HashManager.ts +7 -7
- package/src/managers/JsonManager.ts +4 -4
- package/src/managers/RateLimitManager.ts +5 -5
- package/src/managers/SanitizerManager.ts +5 -5
- package/src/managers/ValidatorManager.ts +2 -2
- package/src/middlewares/errorHandler.ts +3 -3
|
@@ -50,7 +50,7 @@ class RateLimitManager {
|
|
|
50
50
|
}
|
|
51
51
|
const attemptedOverrides = Object.keys(opts.options).filter(k => !allowedOverrides.includes(k) && k !== 'mode');
|
|
52
52
|
if (attemptedOverrides.length > 0) {
|
|
53
|
-
logging_1.logger.warn("
|
|
53
|
+
logging_1.logger.warn("Rate limit overrides ignored", {
|
|
54
54
|
preset: opts?.mode || 'default',
|
|
55
55
|
ignoredOptions: attemptedOverrides
|
|
56
56
|
});
|
|
@@ -63,7 +63,7 @@ class RateLimitManager {
|
|
|
63
63
|
finalOptions.legacyHeaders = false;
|
|
64
64
|
}
|
|
65
65
|
try {
|
|
66
|
-
logging_1.logger.info("
|
|
66
|
+
logging_1.logger.info("Applying rate limiting", {
|
|
67
67
|
mode: opts?.mode || 'default',
|
|
68
68
|
windowMs: finalOptions.windowMs,
|
|
69
69
|
max: finalOptions.max
|
|
@@ -71,18 +71,18 @@ class RateLimitManager {
|
|
|
71
71
|
return this.primaryAdapter.getMiddleware(finalOptions);
|
|
72
72
|
}
|
|
73
73
|
catch (err) {
|
|
74
|
-
logging_1.logger.warn("
|
|
74
|
+
logging_1.logger.warn("Primary rate limiter failed → fallback", {
|
|
75
75
|
error: err?.message
|
|
76
76
|
});
|
|
77
77
|
if (!this.fallbackAdapter) {
|
|
78
78
|
throw new AdapterError_js_1.AdapterError("Rate limiters failed; no fallback adapter.");
|
|
79
79
|
}
|
|
80
80
|
try {
|
|
81
|
-
logging_1.logger.info("
|
|
81
|
+
logging_1.logger.info("Using fallback rate limiter");
|
|
82
82
|
return this.fallbackAdapter.getMiddleware(finalOptions);
|
|
83
83
|
}
|
|
84
84
|
catch (fallbackErr) {
|
|
85
|
-
logging_1.logger.error("
|
|
85
|
+
logging_1.logger.error("Fallback limiter also failed", {
|
|
86
86
|
error: fallbackErr?.message
|
|
87
87
|
});
|
|
88
88
|
throw new AdapterError_js_1.AdapterError("Both primary and fallback limiters failed.");
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"RateLimitManager.js","sourceRoot":"","sources":["../../src/managers/RateLimitManager.ts"],"names":[],"mappings":";;;AACA,oEAA8D;AAC9D,wCAAoC;AAMpC,MAAa,gBAAgB;IAKzB,YACI,MAAqC,EACrC,cAAkC,EAClC,eAA0C;QAE1C,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;QACrB,IAAI,CAAC,cAAc,GAAG,cAAc,CAAC;QACrC,IAAI,CAAC,eAAe,GAAG,eAAe,CAAC;IAC3C,CAAC;IAED,UAAU,CAAC,IAA6D;QACpE,IAAI,YAAY,GAAQ,EAAE,CAAC;QAE3B,IAAI,IAAI,EAAE,IAAI,KAAK,QAAQ,EAAE,CAAC;YAC1B,YAAY,GAAG;gBACX,QAAQ,EAAE,KAAM;gBAChB,GAAG,EAAE,CAAC;gBACN,OAAO,EAAE,sCAAsC;aAClD,CAAC;QACN,CAAC;aAAM,IAAI,IAAI,EAAE,IAAI,KAAK,SAAS,EAAE,CAAC;YAClC,YAAY,GAAG;gBACX,QAAQ,EAAE,KAAM;gBAChB,GAAG,EAAE,GAAG;gBACR,OAAO,EAAE,sBAAsB;aAClC,CAAC;QACN,CAAC;aAAM,IAAI,IAAI,EAAE,IAAI,KAAK,KAAK,EAAE,CAAC;YAC9B,YAAY,GAAG;gBACX,QAAQ,EAAE,EAAE,GAAG,EAAE,GAAG,IAAI;gBACxB,GAAG,EAAE,GAAG;gBACR,OAAO,EAAE,0BAA0B;aACtC,CAAC;QACN,CAAC;aAAM,CAAC;YACJ,YAAY,GAAG;gBACX,QAAQ,EAAE,IAAI,CAAC,MAAM,CAAC,QAAQ;gBAC9B,GAAG,EAAE,IAAI,CAAC,MAAM,CAAC,WAAW;gBAC5B,OAAO,EAAE,IAAI,CAAC,MAAM,CAAC,OAAO;gBAC5B,eAAe,EAAE,IAAI;gBACrB,aAAa,EAAE,KAAK;aACvB,CAAC;QACN,CAAC;QAED,IAAI,IAAI,EAAE,OAAO,EAAE,CAAC;YAChB,MAAM,gBAAgB,GAAG,CAAC,SAAS,EAAE,oBAAoB,EAAE,iBAAiB,EAAE,eAAe,CAAC,CAAC;YAC/F,KAAK,MAAM,GAAG,IAAI,gBAAgB,EAAE,CAAC;gBACjC,IAAI,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,KAAK,SAAS,EAAE,CAAC;oBAClC,YAAY,CAAC,GAAG,CAAC,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;gBAC1C,CAAC;YACL,CAAC;YAED,MAAM,kBAAkB,GAAG,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,MAAM,CACvD,CAAC,CAAC,EAAE,CAAC,CAAC,gBAAgB,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,MAAM,CACrD,CAAC;YACF,IAAI,kBAAkB,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;gBAChC,gBAAM,CAAC,IAAI,CAAC,
|
|
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.js\";\r\nimport { AdapterError } from \"../core/errors/AdapterError.js\";\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\r\n middleware(opts?: { mode?: \"strict\" | \"relaxed\" | \"api\"; options?: any }) {\r\n let finalOptions: any = {};\r\n\r\n if (opts?.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 (opts?.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 (opts?.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 = ['message', 'skipFailedRequests', 'standardHeaders', 'legacyHeaders'];\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 if (attemptedOverrides.length > 0) {\r\n logger.warn(\"Rate limit overrides ignored\", {\r\n preset: opts?.mode || 'default',\r\n ignoredOptions: attemptedOverrides\r\n });\r\n }\r\n }\r\n\r\n if (finalOptions.standardHeaders === undefined) {\r\n finalOptions.standardHeaders = true;\r\n }\r\n if (finalOptions.legacyHeaders === undefined) {\r\n finalOptions.legacyHeaders = false;\r\n }\r\n\r\n try {\r\n logger.info(\"Applying rate limiting\", {\r\n mode: opts?.mode || 'default',\r\n windowMs: finalOptions.windowMs,\r\n max: finalOptions.max\r\n });\r\n \r\n return this.primaryAdapter.getMiddleware(finalOptions);\r\n } catch (err: any) {\r\n logger.warn(\"Primary rate limiter failed → fallback\", {\r\n error: err?.message\r\n });\r\n\r\n if (!this.fallbackAdapter) {\r\n throw new AdapterError(\"Rate limiters failed; no fallback adapter.\");\r\n }\r\n\r\n try {\r\n logger.info(\"Using fallback rate limiter\");\r\n return this.fallbackAdapter.getMiddleware(finalOptions);\r\n } catch (fallbackErr: any) {\r\n logger.error(\"Fallback limiter also failed\", {\r\n error: fallbackErr?.message\r\n });\r\n throw new AdapterError(\"Both primary and fallback limiters failed.\");\r\n }\r\n }\r\n }\r\n}"]}
|
|
@@ -16,11 +16,11 @@ class SanitizerManager {
|
|
|
16
16
|
return this.primary.sanitize(value, options);
|
|
17
17
|
}
|
|
18
18
|
catch (err) {
|
|
19
|
-
logging_1.logger.warn("
|
|
19
|
+
logging_1.logger.warn("Primary sanitizer failed", { error: err?.message });
|
|
20
20
|
if (!this.fallback) {
|
|
21
21
|
throw new SanitizerError_js_1.SanitizerError("Primary sanitizer failed and no fallback available.");
|
|
22
22
|
}
|
|
23
|
-
logging_1.logger.info("
|
|
23
|
+
logging_1.logger.info("Using fallback sanitizer");
|
|
24
24
|
return this.fallback.sanitize(value, options);
|
|
25
25
|
}
|
|
26
26
|
}
|
|
@@ -39,7 +39,7 @@ class SanitizerManager {
|
|
|
39
39
|
throw err;
|
|
40
40
|
}
|
|
41
41
|
fallbackTriggered = true;
|
|
42
|
-
logging_1.logger.warn("
|
|
42
|
+
logging_1.logger.warn("Switching to fallback sanitizer for this request");
|
|
43
43
|
return this.fallback.sanitize(value, options);
|
|
44
44
|
}
|
|
45
45
|
};
|
|
@@ -63,7 +63,7 @@ class SanitizerManager {
|
|
|
63
63
|
}
|
|
64
64
|
}
|
|
65
65
|
req.sanitizedBody = sanitizedBody;
|
|
66
|
-
logging_1.logger.debug("
|
|
66
|
+
logging_1.logger.debug("Request body sanitized", {
|
|
67
67
|
originalKeys: Object.keys(originalBody),
|
|
68
68
|
sanitizedKeys: Object.keys(sanitizedBody),
|
|
69
69
|
usedFallback: fallbackTriggered
|
|
@@ -72,7 +72,7 @@ class SanitizerManager {
|
|
|
72
72
|
next();
|
|
73
73
|
}
|
|
74
74
|
catch (err) {
|
|
75
|
-
logging_1.logger.error("
|
|
75
|
+
logging_1.logger.error("Sanitizer middleware failed", {
|
|
76
76
|
error: err?.message
|
|
77
77
|
});
|
|
78
78
|
next(new SanitizerError_js_1.SanitizerError("Sanitizer middleware failure"));
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SanitizerManager.js","sourceRoot":"","sources":["../../src/managers/SanitizerManager.ts"],"names":[],"mappings":";;;AAAA,wEAAkE;AAClE,wCAAoC;AAMpC,MAAa,gBAAgB;IAIzB,YAAY,OAAyB,EAAE,WAAoC,IAAI;QAC3E,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC;QACvB,IAAI,CAAC,QAAQ,GAAG,QAAQ,CAAC;IAC7B,CAAC;IAED,QAAQ,CAAC,KAAa,EAAE,OAAa;QAEjC,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,
|
|
1
|
+
{"version":3,"file":"SanitizerManager.js","sourceRoot":"","sources":["../../src/managers/SanitizerManager.ts"],"names":[],"mappings":";;;AAAA,wEAAkE;AAClE,wCAAoC;AAMpC,MAAa,gBAAgB;IAIzB,YAAY,OAAyB,EAAE,WAAoC,IAAI;QAC3E,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC;QACvB,IAAI,CAAC,QAAQ,GAAG,QAAQ,CAAC;IAC7B,CAAC;IAED,QAAQ,CAAC,KAAa,EAAE,OAAa;QAEjC,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,EAAE,KAAK,EAAE,GAAG,EAAE,OAAO,EAAE,CAAC,CAAC;YAEjE,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,CAAC;gBACjB,MAAM,IAAI,kCAAc,CAAC,qDAAqD,CAAC,CAAC;YACpF,CAAC;YAED,gBAAM,CAAC,IAAI,CAAC,0BAA0B,CAAC,CAAC;YACxC,OAAO,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAC,CAAC;QAClD,CAAC;IACL,CAAC;IAGD,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;oBACzB,gBAAM,CAAC,IAAI,CAAC,kDAAkD,CAAC,CAAC;oBAChE,OAAO,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAC,CAAC;gBAClD,CAAC;YACL,CAAC,CAAC;YAEF,IAAI,CAAC;gBAED,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,CAAC,CAAC,CAAC,YAAY,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CACvD,CAAC;wBACN,CAAC;6BAAM,IAAI,KAAK,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;4BAC5C,aAAa,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC;wBAC/B,CAAC;6BAAM,CAAC;4BACJ,aAAa,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC;wBAC/B,CAAC;oBACL,CAAC;oBAED,GAAG,CAAC,aAAa,GAAG,aAAa,CAAC;oBAElC,gBAAM,CAAC,KAAK,CAAC,wBAAwB,EAAE;wBACnC,YAAY,EAAE,MAAM,CAAC,IAAI,CAAC,YAAY,CAAC;wBACvC,aAAa,EAAE,MAAM,CAAC,IAAI,CAAC,aAAa,CAAC;wBACzC,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,GAAG,EAAE,OAAO;iBACtB,CAAC,CAAC;gBACH,IAAI,CAAC,IAAI,kCAAc,CAAC,8BAA8B,CAAC,CAAC,CAAC;YAC7D,CAAC;QACL,CAAC,CAAC;IACN,CAAC;CACJ;AA5FD,4CA4FC","sourcesContent":["import { SanitizerError } from \"../core/errors/SanitizerError.js\";\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\r\n sanitize(value: string, options?: any): string {\r\n \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\", { error: err?.message });\r\n\r\n if (!this.fallback) {\r\n throw new SanitizerError(\"Primary sanitizer failed and no fallback available.\");\r\n }\r\n\r\n logger.info(\"Using fallback sanitizer\");\r\n return this.fallback.sanitize(value, options);\r\n }\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 logger.warn(\"Switching to fallback sanitizer for this request\");\r\n return this.fallback.sanitize(value, options);\r\n }\r\n };\r\n\r\n try {\r\n \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\" ? safeSanitize(item) : item\r\n );\r\n } else if (value && typeof value === \"object\") {\r\n sanitizedBody[key] = value; \r\n } else {\r\n sanitizedBody[key] = value;\r\n }\r\n }\r\n \r\n req.sanitizedBody = sanitizedBody;\r\n \r\n logger.debug(\"Request body sanitized\", {\r\n originalKeys: Object.keys(originalBody),\r\n sanitizedKeys: Object.keys(sanitizedBody),\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 error: err?.message\r\n });\r\n next(new SanitizerError(\"Sanitizer middleware failure\"));\r\n }\r\n };\r\n }\r\n}"]}
|
|
@@ -17,11 +17,11 @@ class ValidatorManager {
|
|
|
17
17
|
return (req, res, next) => {
|
|
18
18
|
let middleware;
|
|
19
19
|
if (isZod) {
|
|
20
|
-
logging_1.logger.debug("
|
|
20
|
+
logging_1.logger.debug("Using Zod adapter");
|
|
21
21
|
middleware = this.zodAdapter.validate(schema);
|
|
22
22
|
}
|
|
23
23
|
else if (isExpressValidator) {
|
|
24
|
-
logging_1.logger.debug("
|
|
24
|
+
logging_1.logger.debug(" Using express-validator adapter");
|
|
25
25
|
middleware = this.expressAdapter.validate(schema);
|
|
26
26
|
}
|
|
27
27
|
else {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ValidatorManager.js","sourceRoot":"","sources":["../../src/managers/ValidatorManager.ts"],"names":[],"mappings":";;;AAAA,wCAAoC;AACpC,0EAAoE;AAMpE,MAAa,gBAAgB;IAIzB,YAAY,UAA4B,EAAE,cAAgC;QACtE,IAAI,CAAC,UAAU,GAAG,UAAU,CAAC;QAC7B,IAAI,CAAC,cAAc,GAAG,cAAc,CAAC;IACzC,CAAC;IAED,QAAQ,CAAC,MAAY;QACjB,MAAM,KAAK,GACf,MAAM;YACN,OAAO,MAAM,KAAK,QAAQ;YAC1B,OAAO,MAAM,CAAC,IAAI,KAAK,QAAQ;YAC/B,OAAO,MAAM,CAAC,SAAS,KAAK,UAAU,CAAC;QAEnC,MAAM,kBAAkB,GAAG,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;QAEjD,OAAO,CAAC,GAAQ,EAAE,GAAQ,EAAE,IAAS,EAAE,EAAE;YACrC,IAAI,UAAU,CAAC;YAEf,IAAI,KAAK,EAAE,CAAC;gBACR,gBAAM,CAAC,KAAK,CAAC,
|
|
1
|
+
{"version":3,"file":"ValidatorManager.js","sourceRoot":"","sources":["../../src/managers/ValidatorManager.ts"],"names":[],"mappings":";;;AAAA,wCAAoC;AACpC,0EAAoE;AAMpE,MAAa,gBAAgB;IAIzB,YAAY,UAA4B,EAAE,cAAgC;QACtE,IAAI,CAAC,UAAU,GAAG,UAAU,CAAC;QAC7B,IAAI,CAAC,cAAc,GAAG,cAAc,CAAC;IACzC,CAAC;IAED,QAAQ,CAAC,MAAY;QACjB,MAAM,KAAK,GACf,MAAM;YACN,OAAO,MAAM,KAAK,QAAQ;YAC1B,OAAO,MAAM,CAAC,IAAI,KAAK,QAAQ;YAC/B,OAAO,MAAM,CAAC,SAAS,KAAK,UAAU,CAAC;QAEnC,MAAM,kBAAkB,GAAG,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;QAEjD,OAAO,CAAC,GAAQ,EAAE,GAAQ,EAAE,IAAS,EAAE,EAAE;YACrC,IAAI,UAAU,CAAC;YAEf,IAAI,KAAK,EAAE,CAAC;gBACR,gBAAM,CAAC,KAAK,CAAC,mBAAmB,CAAC,CAAC;gBAClC,UAAU,GAAG,IAAI,CAAC,UAAU,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;YAClD,CAAC;iBACI,IAAI,kBAAkB,EAAE,CAAC;gBAC1B,gBAAM,CAAC,KAAK,CAAC,kCAAkC,CAAC,CAAC;gBACjD,UAAU,GAAG,IAAI,CAAC,cAAc,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;YACtD,CAAC;iBACI,CAAC;gBACF,OAAO,IAAI,EAAE,CAAC;YAClB,CAAC;YAED,2CAA2C;YAC3C,IAAI,KAAK,CAAC,OAAO,CAAC,UAAU,CAAC,EAAE,CAAC;gBAC5B,IAAI,GAAG,GAAG,CAAC,CAAC;gBAEZ,MAAM,GAAG,GAAG,CAAC,GAAS,EAAE,EAAE;oBACtB,IAAI,GAAG;wBAAE,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC;oBAE1B,MAAM,EAAE,GAAG,UAAU,CAAC,GAAG,EAAE,CAAC,CAAC;oBAC7B,IAAI,CAAC,EAAE;wBAAE,OAAO,IAAI,EAAE,CAAC,CAAC,OAAO;oBAE/B,IAAI,CAAC;wBACD,EAAE,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,CAAC,CAAC;oBACtB,CAAC;oBAAC,OAAO,KAAU,EAAE,CAAC;wBAClB,IAAI,CAAC,IAAI,oCAAe,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC;oBAC7C,CAAC;gBACL,CAAC,CAAC;gBAEF,OAAO,GAAG,EAAE,CAAC;YACjB,CAAC;YAED,yCAAyC;YACzC,IAAI,CAAC;gBACD,UAAU,CAAC,GAAG,EAAE,GAAG,EAAE,CAAC,GAAS,EAAE,EAAE;oBAC/B,IAAI,GAAG;wBAAE,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC;oBAC1B,IAAI,EAAE,CAAC;gBACX,CAAC,CAAC,CAAC;YACP,CAAC;YAAC,OAAO,GAAQ,EAAE,CAAC;gBAChB,IAAI,CAAC,IAAI,oCAAe,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC;YAC3C,CAAC;QACL,CAAC,CAAC;IACN,CAAC;CACJ;AAhED,4CAgEC","sourcesContent":["import { logger } from \"../logging\";\r\nimport { ValidationError } from \"../core/errors/ValidationError.js\";\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\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\r\n if (isZod) {\r\n logger.debug(\"Using Zod adapter\");\r\n middleware = this.zodAdapter.validate(schema);\r\n } \r\n else if (isExpressValidator) {\r\n logger.debug(\" Using express-validator adapter\");\r\n middleware = this.expressAdapter.validate(schema);\r\n } \r\n else {\r\n return next(); \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(); // done\r\n\r\n try {\r\n fn(req, res, run);\r\n } catch (error: any) {\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 next(new ValidationError(err.message));\r\n }\r\n };\r\n }\r\n}\r\n\r\n"]}
|
|
@@ -14,7 +14,7 @@ function errorHandler(err, req, res, _next) {
|
|
|
14
14
|
const stack = err instanceof Error && err.stack
|
|
15
15
|
? err.stack.split("\n").slice(0, 2).join(" | ")
|
|
16
16
|
: undefined;
|
|
17
|
-
logging_1.logger.error("
|
|
17
|
+
logging_1.logger.error("HiSecure Error", {
|
|
18
18
|
type: err?.name || "UnknownError",
|
|
19
19
|
message,
|
|
20
20
|
status: err?.status,
|
|
@@ -49,7 +49,7 @@ function errorHandler(err, req, res, _next) {
|
|
|
49
49
|
message,
|
|
50
50
|
});
|
|
51
51
|
}
|
|
52
|
-
// 4. Adapter Errors
|
|
52
|
+
// 4. Adapter Errors - hashing, rate-limit, sanitizer, validator
|
|
53
53
|
if (err instanceof AdapterError_js_1.AdapterError) {
|
|
54
54
|
return res.status(500).json({
|
|
55
55
|
success: false,
|
|
@@ -65,7 +65,7 @@ function errorHandler(err, req, res, _next) {
|
|
|
65
65
|
message,
|
|
66
66
|
});
|
|
67
67
|
}
|
|
68
|
-
// 6. Fallback
|
|
68
|
+
// 6. Fallback - Unexpected
|
|
69
69
|
return res.status(500).json({
|
|
70
70
|
success: false,
|
|
71
71
|
error: "INTERNAL_SERVER_ERROR",
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"errorHandler.js","sourceRoot":"","sources":["../../src/middlewares/errorHandler.ts"],"names":[],"mappings":";;AASA,oCAgFC;AAxFD,wCAAoC;AAEpC,oEAA8D;AAC9D,0EAAoE;AACpE,wEAAkE;AAClE,sEAAgE;AAChE,8DAAwD;AAExD,SAAgB,YAAY,CACxB,GAAQ,EACR,GAAY,EACZ,GAAa,EACb,KAAmB;IAEnB,MAAM,OAAO,GACT,OAAO,GAAG,KAAK,QAAQ;QACnB,CAAC,CAAC,GAAG;QACL,CAAC,CAAC,GAAG,EAAE,OAAO,IAAI,eAAe,CAAC;IAE1C,MAAM,KAAK,GACP,GAAG,YAAY,KAAK,IAAI,GAAG,CAAC,KAAK;QAC7B,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC;QAC/C,CAAC,CAAC,SAAS,CAAC;IAGpB,gBAAM,CAAC,KAAK,CAAC,
|
|
1
|
+
{"version":3,"file":"errorHandler.js","sourceRoot":"","sources":["../../src/middlewares/errorHandler.ts"],"names":[],"mappings":";;AASA,oCAgFC;AAxFD,wCAAoC;AAEpC,oEAA8D;AAC9D,0EAAoE;AACpE,wEAAkE;AAClE,sEAAgE;AAChE,8DAAwD;AAExD,SAAgB,YAAY,CACxB,GAAQ,EACR,GAAY,EACZ,GAAa,EACb,KAAmB;IAEnB,MAAM,OAAO,GACT,OAAO,GAAG,KAAK,QAAQ;QACnB,CAAC,CAAC,GAAG;QACL,CAAC,CAAC,GAAG,EAAE,OAAO,IAAI,eAAe,CAAC;IAE1C,MAAM,KAAK,GACP,GAAG,YAAY,KAAK,IAAI,GAAG,CAAC,KAAK;QAC7B,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC;QAC/C,CAAC,CAAC,SAAS,CAAC;IAGpB,gBAAM,CAAC,KAAK,CAAC,gBAAgB,EAAE;QAC3B,IAAI,EAAE,GAAG,EAAE,IAAI,IAAI,cAAc;QACjC,OAAO;QACP,MAAM,EAAE,GAAG,EAAE,MAAM;QACnB,IAAI,EAAE,GAAG,EAAE,IAAI;QACf,IAAI,EAAE,GAAG,CAAC,IAAI;QACd,MAAM,EAAE,GAAG,CAAC,MAAM;QAClB,KAAK;QACL,GAAG,EAAE,GAAG;KACX,CAAC,CAAC;IAEH,kCAAkC;IAClC,IAAI,GAAG,YAAY,wBAAS,EAAE,CAAC;QAC3B,OAAO,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC;YAC/B,OAAO,EAAE,KAAK;YACd,KAAK,EAAE,GAAG,CAAC,IAAI;YACf,OAAO,EAAE,GAAG,CAAC,OAAO;YACpB,OAAO,EAAE,GAAG,CAAC,OAAO,IAAI,SAAS;SACpC,CAAC,CAAC;IACP,CAAC;IAED,uBAAuB;IACvB,IAAI,GAAG,YAAY,oCAAe,EAAE,CAAC;QACjC,OAAO,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC;YACxB,OAAO,EAAE,KAAK;YACd,KAAK,EAAE,kBAAkB;YACzB,OAAO;SACV,CAAC,CAAC;IACP,CAAC;IAED,sBAAsB;IACtB,IAAI,GAAG,YAAY,kCAAc,EAAE,CAAC;QAChC,OAAO,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC;YACxB,OAAO,EAAE,KAAK;YACd,KAAK,EAAE,iBAAiB;YACxB,OAAO;SACV,CAAC,CAAC;IACP,CAAC;IAED,gEAAgE;IAChE,IAAI,GAAG,YAAY,8BAAY,EAAE,CAAC;QAC9B,OAAO,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC;YACxB,OAAO,EAAE,KAAK;YACd,KAAK,EAAE,eAAe;YACtB,OAAO;SACV,CAAC,CAAC;IACP,CAAC;IAED,uDAAuD;IACvD,IAAI,GAAG,YAAY,gCAAa,EAAE,CAAC;QAC/B,OAAO,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC;YACxB,OAAO,EAAE,KAAK;YACd,KAAK,EAAE,gBAAgB;YACvB,OAAO;SACV,CAAC,CAAC;IACP,CAAC;IAED,2BAA2B;IAC3B,OAAO,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC;QACxB,OAAO,EAAE,KAAK;QACd,KAAK,EAAE,uBAAuB;QAC9B,OAAO,EAAE,2CAA2C;KACvD,CAAC,CAAC;AACP,CAAC","sourcesContent":["import { Request, Response, NextFunction } from \"express\";\r\nimport { logger } from \"../logging\";\r\n\r\nimport { AdapterError } from \"../core/errors/AdapterError.js\";\r\nimport { ValidationError } from \"../core/errors/ValidationError.js\";\r\nimport { SanitizerError } from \"../core/errors/SanitizerError.js\";\r\nimport { SecurityError } from \"../core/errors/SecurityError.js\";\r\nimport { HttpError } from \"../core/errors/HttpError.js\";\r\n\r\nexport function errorHandler(\r\n err: any,\r\n req: Request,\r\n res: Response,\r\n _next: NextFunction\r\n) {\r\n const message =\r\n typeof err === \"string\"\r\n ? err\r\n : err?.message || \"Unknown error\";\r\n\r\n const stack =\r\n err instanceof Error && err.stack\r\n ? err.stack.split(\"\\n\").slice(0, 2).join(\" | \")\r\n : undefined;\r\n\r\n \r\n logger.error(\"HiSecure Error\", {\r\n type: err?.name || \"UnknownError\",\r\n message,\r\n status: err?.status,\r\n code: err?.code,\r\n path: req.path,\r\n method: req.method,\r\n stack,\r\n raw: err,\r\n });\r\n\r\n // 1. HttpError (developer thrown)\r\n if (err instanceof HttpError) {\r\n return res.status(err.status).json({\r\n success: false,\r\n error: err.code,\r\n message: err.message,\r\n details: err.details || undefined,\r\n });\r\n }\r\n\r\n // 2. Validation Errors\r\n if (err instanceof ValidationError) {\r\n return res.status(400).json({\r\n success: false,\r\n error: \"VALIDATION_ERROR\",\r\n message,\r\n });\r\n }\r\n\r\n // 3. Sanitizer Errors\r\n if (err instanceof SanitizerError) {\r\n return res.status(400).json({\r\n success: false,\r\n error: \"SANITIZER_ERROR\",\r\n message,\r\n });\r\n }\r\n\r\n // 4. Adapter Errors - hashing, rate-limit, sanitizer, validator\r\n if (err instanceof AdapterError) {\r\n return res.status(500).json({\r\n success: false,\r\n error: \"ADAPTER_ERROR\",\r\n message,\r\n });\r\n }\r\n\r\n // 5. Security Errors (internal library security logic)\r\n if (err instanceof SecurityError) {\r\n return res.status(500).json({\r\n success: false,\r\n error: \"SECURITY_ERROR\",\r\n message,\r\n });\r\n }\r\n\r\n // 6. Fallback - Unexpected\r\n return res.status(500).json({\r\n success: false,\r\n error: \"INTERNAL_SERVER_ERROR\",\r\n message: \"An unexpected error occurred in HiSecure.\",\r\n });\r\n}\r\n"]}
|
package/package.json
CHANGED
|
@@ -17,7 +17,7 @@ export class ArgonAdapter {
|
|
|
17
17
|
? await argon2.hash(value, this.options)
|
|
18
18
|
: await argon2.hash(value);
|
|
19
19
|
} catch (err: any) {
|
|
20
|
-
logger.error("
|
|
20
|
+
logger.error("Argon2 hashing failed", {
|
|
21
21
|
error: err?.message || err
|
|
22
22
|
});
|
|
23
23
|
throw new AdapterError("Argon2 hashing failed.");
|
|
@@ -32,7 +32,7 @@ export class ArgonAdapter {
|
|
|
32
32
|
|
|
33
33
|
return await argon2.verify(hashed, value);
|
|
34
34
|
} catch (err: any) {
|
|
35
|
-
logger.error("
|
|
35
|
+
logger.error("Argon2 verify failed", {
|
|
36
36
|
error: err?.message || err
|
|
37
37
|
});
|
|
38
38
|
throw new AdapterError("Argon2 verify failed.");
|
|
@@ -13,7 +13,7 @@ export class BcryptAdapter {
|
|
|
13
13
|
|
|
14
14
|
return await bcrypt.hash(value, this.saltRounds);
|
|
15
15
|
} catch (err: any) {
|
|
16
|
-
logger.error("
|
|
16
|
+
logger.error("Bcrypt hashing failed", {
|
|
17
17
|
error: err?.message || err,
|
|
18
18
|
saltRounds: this.saltRounds
|
|
19
19
|
});
|
|
@@ -34,7 +34,7 @@ export class BcryptAdapter {
|
|
|
34
34
|
|
|
35
35
|
return await bcrypt.compare(value, hashed);
|
|
36
36
|
} catch (err: any) {
|
|
37
|
-
logger.error("
|
|
37
|
+
logger.error("Bcrypt verify failed", {
|
|
38
38
|
error: err?.message || err
|
|
39
39
|
});
|
|
40
40
|
|
|
@@ -28,7 +28,7 @@ export class ExpressRLAdapter {
|
|
|
28
28
|
|
|
29
29
|
const limiter = rateLimit(finalOptions);
|
|
30
30
|
|
|
31
|
-
logger.debug("
|
|
31
|
+
logger.debug("Express rate limiter configured", {
|
|
32
32
|
windowMs: finalOptions.windowMs,
|
|
33
33
|
max: finalOptions.max
|
|
34
34
|
});
|
|
@@ -36,7 +36,7 @@ export class ExpressRLAdapter {
|
|
|
36
36
|
return limiter;
|
|
37
37
|
|
|
38
38
|
} catch (err: any) {
|
|
39
|
-
logger.error("
|
|
39
|
+
logger.error("ExpressRLAdapter: failed to create limiter", {
|
|
40
40
|
error: err?.message || err
|
|
41
41
|
});
|
|
42
42
|
throw new AdapterError("Express rate limiter creation failed.");
|
|
@@ -35,7 +35,7 @@ export class GoogleAdapter {
|
|
|
35
35
|
idToken
|
|
36
36
|
};
|
|
37
37
|
|
|
38
|
-
//
|
|
38
|
+
// audience only if clientId is provided and not empty
|
|
39
39
|
if (this.clientId && this.clientId.trim().length > 0) {
|
|
40
40
|
options.audience = this.clientId;
|
|
41
41
|
}
|
|
@@ -48,7 +48,7 @@ export class GoogleAdapter {
|
|
|
48
48
|
throw new AdapterError("Invalid Google ID token payload.");
|
|
49
49
|
}
|
|
50
50
|
|
|
51
|
-
//
|
|
51
|
+
// result object
|
|
52
52
|
const result: GoogleTokenPayload = {
|
|
53
53
|
sub: payload.sub,
|
|
54
54
|
email: payload.email || '',
|
|
@@ -57,7 +57,7 @@ export class GoogleAdapter {
|
|
|
57
57
|
picture: payload.picture
|
|
58
58
|
};
|
|
59
59
|
|
|
60
|
-
//
|
|
60
|
+
// remaining properties from payload
|
|
61
61
|
const { sub, email, email_verified, name, picture, ...rest } = payload;
|
|
62
62
|
Object.assign(result, rest);
|
|
63
63
|
|
|
@@ -33,8 +33,8 @@ export class JWTAdapter {
|
|
|
33
33
|
}
|
|
34
34
|
|
|
35
35
|
if (options.secret.length < 32) {
|
|
36
|
-
logger.warn("
|
|
37
|
-
// logError("
|
|
36
|
+
logger.warn("JWT secret shorter than 32 chars. Consider using stronger secret.");
|
|
37
|
+
// logError("JWT secret is too short (minimum 32 characters recommended)");
|
|
38
38
|
}
|
|
39
39
|
|
|
40
40
|
this.secret = options.secret;
|
|
@@ -37,7 +37,7 @@ export class RLFlexibleAdapter {
|
|
|
37
37
|
} catch (err: any) {
|
|
38
38
|
const rlErr = err as RateLimiterRes;
|
|
39
39
|
|
|
40
|
-
logger.warn("
|
|
40
|
+
logger.warn("RLFlexibleAdapter: rate limit exceeded", {
|
|
41
41
|
ip,
|
|
42
42
|
path: req.path,
|
|
43
43
|
method: req.method,
|
|
@@ -56,7 +56,7 @@ export class RLFlexibleAdapter {
|
|
|
56
56
|
};
|
|
57
57
|
|
|
58
58
|
} catch (err: any) {
|
|
59
|
-
logger.error("
|
|
59
|
+
logger.error("RLFlexibleAdapter: failed to initialize limiter", {
|
|
60
60
|
error: err?.message || err
|
|
61
61
|
});
|
|
62
62
|
throw new AdapterError("RateLimiterFlexible creation failed.");
|
|
@@ -17,7 +17,7 @@ export class SanitizeHtmlAdapter {
|
|
|
17
17
|
return typeof clean === "string" ? clean : String(clean);
|
|
18
18
|
|
|
19
19
|
} catch (err: any) {
|
|
20
|
-
logger.error("
|
|
20
|
+
logger.error("sanitize-html failed", {
|
|
21
21
|
error: err?.message || err,
|
|
22
22
|
preview: typeof input === "string" ? input.slice(0, 100) : undefined
|
|
23
23
|
});
|
|
@@ -61,14 +61,14 @@ export class SanitizeHtmlAdapter {
|
|
|
61
61
|
if (req.body) {
|
|
62
62
|
req.body = this.deepSanitize(req.body, dynamicOptions);
|
|
63
63
|
|
|
64
|
-
logger.debug("
|
|
64
|
+
logger.debug("sanitize-html applied", {
|
|
65
65
|
keys: Object.keys(req.body)
|
|
66
66
|
});
|
|
67
67
|
}
|
|
68
68
|
next();
|
|
69
69
|
|
|
70
70
|
} catch (err: any) {
|
|
71
|
-
logger.error("
|
|
71
|
+
logger.error("sanitize-html middleware failed", {
|
|
72
72
|
error: err?.message || err
|
|
73
73
|
});
|
|
74
74
|
next(err);
|
|
@@ -60,7 +60,7 @@ export class XSSAdapter {
|
|
|
60
60
|
return customFilter.process(input);
|
|
61
61
|
|
|
62
62
|
} catch (err: any) {
|
|
63
|
-
logger.error("
|
|
63
|
+
logger.error("XSS sanitizer failed", {
|
|
64
64
|
error: err?.message,
|
|
65
65
|
preview: input?.slice?.(0, 80)
|
|
66
66
|
});
|
|
@@ -98,7 +98,7 @@ export class XSSAdapter {
|
|
|
98
98
|
|
|
99
99
|
req.sanitizedBody = sanitizedBody;
|
|
100
100
|
|
|
101
|
-
logger.debug("
|
|
101
|
+
logger.debug("XSS sanitizer applied", {
|
|
102
102
|
originalKeys: Object.keys(originalBody),
|
|
103
103
|
sanitizedKeys: Object.keys(sanitizedBody)
|
|
104
104
|
});
|
|
@@ -106,7 +106,7 @@ export class XSSAdapter {
|
|
|
106
106
|
|
|
107
107
|
next();
|
|
108
108
|
} catch (err: any) {
|
|
109
|
-
logger.error("
|
|
109
|
+
logger.error("XSS middleware failed", {
|
|
110
110
|
error: err?.message || err
|
|
111
111
|
});
|
|
112
112
|
next(err);
|
package/src/core/HiSecure.ts
CHANGED
|
@@ -76,17 +76,18 @@ export class HiSecure {
|
|
|
76
76
|
|
|
77
77
|
init(): void {
|
|
78
78
|
if (this.initialized) {
|
|
79
|
-
logger.warn("
|
|
79
|
+
logger.warn(" HiSecure already initialized");
|
|
80
80
|
return;
|
|
81
81
|
}
|
|
82
82
|
|
|
83
|
-
logger.info(
|
|
83
|
+
logger.info(` ${LIB_NAME} v${LIB_VERSION} initializing...`);
|
|
84
84
|
|
|
85
85
|
this.setupAdapters();
|
|
86
86
|
this.setupManagers();
|
|
87
87
|
this.setupDynamicManagers();
|
|
88
88
|
|
|
89
89
|
deepFreeze(this.config);
|
|
90
|
+
// deep Freeze - for now we remove from manager it needs to manage the adapters
|
|
90
91
|
// deepFreeze(this.hashManager);
|
|
91
92
|
// deepFreeze(this.rateLimitManager);
|
|
92
93
|
// deepFreeze(this.validatorManager);
|
|
@@ -96,7 +97,7 @@ export class HiSecure {
|
|
|
96
97
|
// if (this.authManager) deepFreeze(this.authManager);
|
|
97
98
|
|
|
98
99
|
this.initialized = true;
|
|
99
|
-
logger.info("
|
|
100
|
+
logger.info("HiSecure initialized successfully");
|
|
100
101
|
}
|
|
101
102
|
|
|
102
103
|
isInitialized(): boolean {
|
|
@@ -148,7 +149,7 @@ export class HiSecure {
|
|
|
148
149
|
return chain;
|
|
149
150
|
}
|
|
150
151
|
|
|
151
|
-
// UTILITY METHODS
|
|
152
|
+
// UTILITY METHODS - For direct use
|
|
152
153
|
|
|
153
154
|
static async hash(password: string): Promise<string> {
|
|
154
155
|
const instance = this.getInstance();
|
|
@@ -214,7 +215,7 @@ export class HiSecure {
|
|
|
214
215
|
// Internal Methods
|
|
215
216
|
|
|
216
217
|
private setupAdapters(): void {
|
|
217
|
-
logger.info("
|
|
218
|
+
logger.info(" Setting up adapters...");
|
|
218
219
|
|
|
219
220
|
// Hashing
|
|
220
221
|
this.hashingPrimary = this.config.hashing.primary === "argon2"
|
|
@@ -233,7 +234,8 @@ export class HiSecure {
|
|
|
233
234
|
|
|
234
235
|
|
|
235
236
|
|
|
236
|
-
|
|
237
|
+
|
|
238
|
+
// // Validation - we handle this in d/f way for now
|
|
237
239
|
// this.validatorPrimary = this.config.validation.mode === "zod"
|
|
238
240
|
// ? new ZodAdapter()
|
|
239
241
|
// : new ExpressValidatorAdapter();
|
|
@@ -246,7 +248,7 @@ export class HiSecure {
|
|
|
246
248
|
this.sanitizerPrimary = new SanitizeHtmlAdapter(this.config.sanitizer);
|
|
247
249
|
this.sanitizerFallback = new XSSAdapter(this.config.sanitizer);
|
|
248
250
|
|
|
249
|
-
logger.info("
|
|
251
|
+
logger.info("Adapters ready");
|
|
250
252
|
}
|
|
251
253
|
|
|
252
254
|
private setupManagers(): void {
|
|
@@ -341,7 +343,7 @@ export class HiSecure {
|
|
|
341
343
|
chain.push(this.authManager.protect(authOpts));
|
|
342
344
|
}
|
|
343
345
|
|
|
344
|
-
// Error handler
|
|
346
|
+
// Error handler - at last usage
|
|
345
347
|
chain.push(errorHandler);
|
|
346
348
|
|
|
347
349
|
return chain;
|
package/src/core/config.ts
CHANGED
|
@@ -1,108 +1,3 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
// export interface HiSecureConfig {
|
|
4
|
-
// enableHelmet: boolean;
|
|
5
|
-
// enableHPP: boolean;
|
|
6
|
-
// enableCORS: boolean;
|
|
7
|
-
// enableSanitizer: boolean;
|
|
8
|
-
// enableRateLimiter: boolean;
|
|
9
|
-
// enableValidation: boolean;
|
|
10
|
-
|
|
11
|
-
// hashing: {
|
|
12
|
-
// primary: "argon2" | "bcrypt";
|
|
13
|
-
// fallback: "bcrypt" | null;
|
|
14
|
-
// saltRounds: number;
|
|
15
|
-
// };
|
|
16
|
-
|
|
17
|
-
// rateLimiter: {
|
|
18
|
-
// windowMs: number;
|
|
19
|
-
// maxRequests: number;
|
|
20
|
-
// message: string;
|
|
21
|
-
// useAdaptiveMode: boolean;
|
|
22
|
-
// };
|
|
23
|
-
|
|
24
|
-
// validation: {
|
|
25
|
-
// mode: "zod" | "express-validator";
|
|
26
|
-
// fallback: "express-validator" | null;
|
|
27
|
-
// };
|
|
28
|
-
|
|
29
|
-
// sanitizer: {
|
|
30
|
-
// allowedTags: string[];
|
|
31
|
-
// allowedAttributes: Record<string, string[]>;
|
|
32
|
-
// };
|
|
33
|
-
|
|
34
|
-
// logging: {
|
|
35
|
-
// enabled: boolean;
|
|
36
|
-
// level: "info" | "warn" | "error" | "debug";
|
|
37
|
-
// };
|
|
38
|
-
|
|
39
|
-
// /** 🔥 ADD THIS */
|
|
40
|
-
// auth: {
|
|
41
|
-
// enabled: boolean;
|
|
42
|
-
// jwtExpiresIn: string | number | undefined;
|
|
43
|
-
// };
|
|
44
|
-
|
|
45
|
-
// /** 🔥 optional configs for dynamic JSON/CORS */
|
|
46
|
-
// json?: any;
|
|
47
|
-
// urlencoded?: any;
|
|
48
|
-
// cors?: any;
|
|
49
|
-
// }
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
// export const defaultConfig: HiSecureConfig = {
|
|
55
|
-
// enableHelmet: true,
|
|
56
|
-
// enableHPP: true,
|
|
57
|
-
// enableCORS: true,
|
|
58
|
-
// enableSanitizer: true,
|
|
59
|
-
// enableRateLimiter: true,
|
|
60
|
-
// enableValidation: true,
|
|
61
|
-
|
|
62
|
-
// hashing: {
|
|
63
|
-
// primary: "argon2",
|
|
64
|
-
// fallback: "bcrypt",
|
|
65
|
-
// saltRounds: 10,
|
|
66
|
-
// },
|
|
67
|
-
|
|
68
|
-
// rateLimiter: {
|
|
69
|
-
// windowMs: 15 * 60 * 1000,
|
|
70
|
-
// maxRequests: 100,
|
|
71
|
-
// message: "Too many requests, please try again later.",
|
|
72
|
-
// useAdaptiveMode: false,
|
|
73
|
-
// },
|
|
74
|
-
|
|
75
|
-
// validation: {
|
|
76
|
-
// mode: "zod",
|
|
77
|
-
// fallback: "express-validator",
|
|
78
|
-
// },
|
|
79
|
-
|
|
80
|
-
// sanitizer: {
|
|
81
|
-
// allowedTags: ["b", "i", "em", "strong", "a"],
|
|
82
|
-
// allowedAttributes: { a: ["href"] },
|
|
83
|
-
// },
|
|
84
|
-
|
|
85
|
-
// logging: {
|
|
86
|
-
// enabled: true,
|
|
87
|
-
// level: "info",
|
|
88
|
-
// },
|
|
89
|
-
|
|
90
|
-
// /** 🔥 NEW AUTH CONFIG */
|
|
91
|
-
// auth: {
|
|
92
|
-
// enabled: false, // user enables manually
|
|
93
|
-
// jwtExpiresIn: "1d", // default value
|
|
94
|
-
// },
|
|
95
|
-
|
|
96
|
-
// /** Optional parser configs */
|
|
97
|
-
// json: {},
|
|
98
|
-
// urlencoded: { extended: true },
|
|
99
|
-
// cors: {},
|
|
100
|
-
// };
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
// src/core/config.ts
|
|
106
1
|
import { HiSecureConfig } from "./types/HiSecureConfig";
|
|
107
2
|
|
|
108
3
|
export const defaultConfig: HiSecureConfig = {
|