hi-secure 1.0.7 → 1.0.10
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 +1 -1
- package/dist/adapters/ArgonAdapter.js.map +1 -1
- package/dist/adapters/ExpressRLAdapter.d.ts.map +1 -1
- package/dist/adapters/ExpressRLAdapter.js +1 -2
- package/dist/adapters/ExpressRLAdapter.js.map +1 -1
- package/dist/adapters/ExpressValidatorAdapter.d.ts.map +1 -1
- package/dist/adapters/ExpressValidatorAdapter.js +1 -39
- package/dist/adapters/ExpressValidatorAdapter.js.map +1 -1
- package/dist/adapters/GoogleAdapter.d.ts.map +1 -1
- package/dist/adapters/GoogleAdapter.js +0 -101
- package/dist/adapters/GoogleAdapter.js.map +1 -1
- package/dist/adapters/JWTAdapter.d.ts.map +1 -1
- package/dist/adapters/JWTAdapter.js +3 -210
- package/dist/adapters/JWTAdapter.js.map +1 -1
- package/dist/adapters/RLFlexibleAdapter.d.ts.map +1 -1
- package/dist/adapters/RLFlexibleAdapter.js +0 -52
- package/dist/adapters/RLFlexibleAdapter.js.map +1 -1
- package/dist/adapters/SanitizeHtmlAdapter.d.ts +0 -3
- package/dist/adapters/SanitizeHtmlAdapter.d.ts.map +1 -1
- package/dist/adapters/SanitizeHtmlAdapter.js +2 -71
- package/dist/adapters/SanitizeHtmlAdapter.js.map +1 -1
- package/dist/adapters/XSSAdapter.d.ts +0 -10
- package/dist/adapters/XSSAdapter.d.ts.map +1 -1
- package/dist/adapters/XSSAdapter.js +2 -19
- package/dist/adapters/XSSAdapter.js.map +1 -1
- package/dist/adapters/ZodAdapter.d.ts.map +1 -1
- package/dist/adapters/ZodAdapter.js +2 -6
- package/dist/adapters/ZodAdapter.js.map +1 -1
- package/dist/core/HiSecure.d.ts +0 -2
- package/dist/core/HiSecure.d.ts.map +1 -1
- package/dist/core/HiSecure.js +8 -20
- package/dist/core/HiSecure.js.map +1 -1
- package/dist/core/useSecure.d.ts +0 -3
- package/dist/core/useSecure.d.ts.map +1 -1
- package/dist/core/useSecure.js +1 -5
- package/dist/core/useSecure.js.map +1 -1
- package/dist/index.d.ts +1 -4
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +0 -1
- package/dist/index.js.map +1 -1
- package/dist/managers/AuthManager.d.ts.map +1 -1
- package/dist/managers/AuthManager.js +1 -89
- package/dist/managers/AuthManager.js.map +1 -1
- package/dist/managers/CorsManager.d.ts.map +1 -1
- package/dist/managers/CorsManager.js +1 -19
- package/dist/managers/CorsManager.js.map +1 -1
- package/dist/managers/HashManager.d.ts.map +1 -1
- package/dist/managers/HashManager.js +0 -243
- package/dist/managers/HashManager.js.map +1 -1
- package/dist/managers/JsonManager.d.ts.map +1 -1
- package/dist/managers/JsonManager.js +1 -77
- package/dist/managers/JsonManager.js.map +1 -1
- package/dist/managers/RateLimitManager.d.ts.map +1 -1
- package/dist/managers/RateLimitManager.js +3 -17
- package/dist/managers/RateLimitManager.js.map +1 -1
- package/dist/managers/SanitizerManager.d.ts +0 -6
- package/dist/managers/SanitizerManager.d.ts.map +1 -1
- package/dist/managers/SanitizerManager.js +1 -213
- package/dist/managers/SanitizerManager.js.map +1 -1
- package/dist/managers/ValidatorManager.d.ts.map +1 -1
- package/dist/managers/ValidatorManager.js +1 -109
- package/dist/managers/ValidatorManager.js.map +1 -1
- package/dist/middlewares/errorHandler.d.ts.map +1 -1
- package/dist/middlewares/errorHandler.js +0 -19
- package/dist/middlewares/errorHandler.js.map +1 -1
- package/dist/utils/deepFreeze.d.ts.map +1 -1
- package/dist/utils/deepFreeze.js +0 -25
- package/dist/utils/deepFreeze.js.map +1 -1
- package/dist/utils/deepMerge.d.ts.map +1 -1
- package/dist/utils/deepMerge.js +0 -26
- package/dist/utils/deepMerge.js.map +1 -1
- package/dist/utils/normalizeOptions.d.ts +1 -3
- package/dist/utils/normalizeOptions.d.ts.map +1 -1
- package/dist/utils/normalizeOptions.js +8 -9
- package/dist/utils/normalizeOptions.js.map +1 -1
- package/package.json +1 -1
- package/src/adapters/ArgonAdapter.ts +1 -1
- package/src/adapters/ExpressRLAdapter.ts +1 -2
- package/src/adapters/ExpressValidatorAdapter.ts +1 -54
- package/src/adapters/GoogleAdapter.ts +0 -129
- package/src/adapters/JWTAdapter.ts +5 -259
- package/src/adapters/RLFlexibleAdapter.ts +2 -65
- package/src/adapters/SanitizeHtmlAdapter.ts +3 -87
- package/src/adapters/XSSAdapter.ts +11 -19
- package/src/adapters/ZodAdapter.ts +2 -51
- package/src/core/HiSecure.ts +13 -24
- package/src/core/useSecure.ts +5 -7
- package/src/index.ts +4 -5
- package/src/managers/AuthManager.ts +5 -109
- package/src/managers/CorsManager.ts +1 -25
- package/src/managers/HashManager.ts +0 -286
- package/src/managers/JsonManager.ts +1 -91
- package/src/managers/RateLimitManager.ts +3 -262
- package/src/managers/SanitizerManager.ts +4 -263
- package/src/managers/ValidatorManager.ts +1 -135
- package/src/middlewares/errorHandler.ts +1 -176
- package/src/utils/deepFreeze.ts +0 -32
- package/src/utils/deepMerge.ts +0 -35
- package/src/utils/normalizeOptions.ts +16 -133
- package/src/examples/e1.ts +0 -1
- package/src/test/t1.ts +0 -1
|
@@ -1,56 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
// import { RateLimiterMemory, RateLimiterRes } from "rate-limiter-flexible";
|
|
3
|
-
// import { logger } from "../logging";
|
|
4
|
-
// import { AdapterError } from "../core/errors/AdapterError";
|
|
5
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
3
|
exports.RLFlexibleAdapter = void 0;
|
|
7
|
-
// export class RLFlexibleAdapter {
|
|
8
|
-
// /**
|
|
9
|
-
// * Create middleware dynamically using options.
|
|
10
|
-
// */
|
|
11
|
-
// getMiddleware(options: {
|
|
12
|
-
// points?: number;
|
|
13
|
-
// duration?: number; // seconds
|
|
14
|
-
// message?: any;
|
|
15
|
-
// } = {}) {
|
|
16
|
-
// try {
|
|
17
|
-
// const limiter = new RateLimiterMemory({
|
|
18
|
-
// points: options.points ?? 100,
|
|
19
|
-
// duration: options.duration ?? 60,
|
|
20
|
-
// });
|
|
21
|
-
// return async (req: any, res: any, next: any) => {
|
|
22
|
-
// const ip = req.ip ||
|
|
23
|
-
// req.headers["x-forwarded-for"] ||
|
|
24
|
-
// req.connection?.remoteAddress ||
|
|
25
|
-
// "unknown";
|
|
26
|
-
// try {
|
|
27
|
-
// await limiter.consume(ip);
|
|
28
|
-
// next();
|
|
29
|
-
// } catch (err: any) {
|
|
30
|
-
// const rlErr = err as RateLimiterRes;
|
|
31
|
-
// logger.warn("⚠ RLFlexibleAdapter: rate limit exceeded", {
|
|
32
|
-
// ip,
|
|
33
|
-
// path: req.path,
|
|
34
|
-
// method: req.method,
|
|
35
|
-
// retryAfter: rlErr.msBeforeNext
|
|
36
|
-
// });
|
|
37
|
-
// return res.status(429).json({
|
|
38
|
-
// success: false,
|
|
39
|
-
// error: "RATE_LIMIT_EXCEEDED",
|
|
40
|
-
// retryAfter: Math.ceil(rlErr.msBeforeNext / 1000),
|
|
41
|
-
// message: options.message ?? "Too many requests, slow down."
|
|
42
|
-
// });
|
|
43
|
-
// }
|
|
44
|
-
// };
|
|
45
|
-
// } catch (err: any) {
|
|
46
|
-
// logger.error("❌ RLFlexibleAdapter: failed to initialize limiter", {
|
|
47
|
-
// error: err?.message || err
|
|
48
|
-
// });
|
|
49
|
-
// throw new AdapterError("RateLimiterFlexible creation failed.");
|
|
50
|
-
// }
|
|
51
|
-
// }
|
|
52
|
-
// }
|
|
53
|
-
// src/adapters/RLFlexibleAdapter.ts - IMPROVED
|
|
54
4
|
const rate_limiter_flexible_1 = require("rate-limiter-flexible");
|
|
55
5
|
const index_js_1 = require("../logging/index.js");
|
|
56
6
|
const AdapterError_js_1 = require("../core/errors/AdapterError.js");
|
|
@@ -70,7 +20,6 @@ class RLFlexibleAdapter {
|
|
|
70
20
|
blockDuration: finalOptions.blockDuration
|
|
71
21
|
});
|
|
72
22
|
return async (req, res, next) => {
|
|
73
|
-
// Better IP extraction
|
|
74
23
|
const ip = this.extractIP(req);
|
|
75
24
|
try {
|
|
76
25
|
await limiter.consume(ip);
|
|
@@ -102,7 +51,6 @@ class RLFlexibleAdapter {
|
|
|
102
51
|
}
|
|
103
52
|
}
|
|
104
53
|
extractIP(req) {
|
|
105
|
-
// Order of priority for IP extraction
|
|
106
54
|
return (req.headers['x-real-ip'] ||
|
|
107
55
|
req.headers['x-forwarded-for']?.split(',')[0]?.trim() ||
|
|
108
56
|
req.ip ||
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"RLFlexibleAdapter.js","sourceRoot":"","sources":["../../src/adapters/RLFlexibleAdapter.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"RLFlexibleAdapter.js","sourceRoot":"","sources":["../../src/adapters/RLFlexibleAdapter.ts"],"names":[],"mappings":";;;AAAA,iEAA0E;AAC1E,kDAA6C;AAC7C,oEAA8D;AAS9D,MAAa,iBAAiB;IAC1B,aAAa,CAAC,UAAqB,EAAE;QACjC,IAAI,CAAC;YACD,MAAM,cAAc,GAAG;gBACnB,MAAM,EAAE,GAAG;gBACX,QAAQ,EAAE,EAAE;gBACZ,OAAO,EAAE,+BAA+B;gBACxC,aAAa,EAAE,CAAC;aACnB,CAAC;YAEF,MAAM,YAAY,GAAG,EAAE,GAAG,cAAc,EAAE,GAAG,OAAO,EAAE,CAAC;YAEvD,MAAM,OAAO,GAAG,IAAI,yCAAiB,CAAC;gBAClC,MAAM,EAAE,YAAY,CAAC,MAAM;gBAC3B,QAAQ,EAAE,YAAY,CAAC,QAAQ;gBAC/B,aAAa,EAAE,YAAY,CAAC,aAAa;aAC5C,CAAC,CAAC;YAEH,OAAO,KAAK,EAAE,GAAQ,EAAE,GAAQ,EAAE,IAAS,EAAE,EAAE;gBAE3C,MAAM,EAAE,GAAG,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC;gBAE/B,IAAI,CAAC;oBACD,MAAM,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;oBAC1B,IAAI,EAAE,CAAC;gBACX,CAAC;gBAAC,OAAO,GAAQ,EAAE,CAAC;oBAChB,MAAM,KAAK,GAAG,GAAqB,CAAC;oBAEpC,iBAAM,CAAC,IAAI,CAAC,0CAA0C,EAAE;wBACpD,EAAE;wBACF,IAAI,EAAE,GAAG,CAAC,IAAI;wBACd,MAAM,EAAE,GAAG,CAAC,MAAM;wBAClB,UAAU,EAAE,KAAK,CAAC,YAAY;qBACjC,CAAC,CAAC;oBAEH,GAAG,CAAC,SAAS,CAAC,aAAa,EAAE,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,YAAY,GAAG,IAAI,CAAC,CAAC,CAAC;oBAEnE,OAAO,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC;wBACxB,OAAO,EAAE,KAAK;wBACd,KAAK,EAAE,qBAAqB;wBAC5B,UAAU,EAAE,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,YAAY,GAAG,IAAI,CAAC;wBAChD,OAAO,EAAE,YAAY,CAAC,OAAO;qBAChC,CAAC,CAAC;gBACP,CAAC;YACL,CAAC,CAAC;QAEN,CAAC;QAAC,OAAO,GAAQ,EAAE,CAAC;YAChB,iBAAM,CAAC,KAAK,CAAC,mDAAmD,EAAE;gBAC9D,KAAK,EAAE,GAAG,EAAE,OAAO,IAAI,GAAG;aAC7B,CAAC,CAAC;YACH,MAAM,IAAI,8BAAY,CAAC,sCAAsC,CAAC,CAAC;QACnE,CAAC;IACL,CAAC;IAEO,SAAS,CAAC,GAAQ;QACtB,OAAO,CACH,GAAG,CAAC,OAAO,CAAC,WAAW,CAAC;YACxB,GAAG,CAAC,OAAO,CAAC,iBAAiB,CAAC,EAAE,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE;YACrD,GAAG,CAAC,EAAE;YACN,GAAG,CAAC,UAAU,EAAE,aAAa;YAC7B,GAAG,CAAC,MAAM,EAAE,aAAa;YACzB,SAAS,CACZ,CAAC;IACN,CAAC;CACJ;AAhED,8CAgEC","sourcesContent":["import { RateLimiterMemory, RateLimiterRes } from \"rate-limiter-flexible\";\r\nimport { logger } from \"../logging/index.js\";\r\nimport { AdapterError } from \"../core/errors/AdapterError.js\";\r\n\r\nexport interface RLOptions {\r\n points?: number;\r\n duration?: number; \r\n message?: any;\r\n blockDuration?: number;\r\n}\r\n\r\nexport class RLFlexibleAdapter {\r\n getMiddleware(options: RLOptions = {}) {\r\n try {\r\n const defaultOptions = {\r\n points: 100,\r\n duration: 60,\r\n message: \"Too many requests, slow down.\",\r\n blockDuration: 0\r\n };\r\n\r\n const finalOptions = { ...defaultOptions, ...options };\r\n\r\n const limiter = new RateLimiterMemory({\r\n points: finalOptions.points,\r\n duration: finalOptions.duration,\r\n blockDuration: finalOptions.blockDuration\r\n });\r\n\r\n return async (req: any, res: any, next: any) => {\r\n \r\n const ip = this.extractIP(req);\r\n\r\n try {\r\n await limiter.consume(ip);\r\n next();\r\n } catch (err: any) {\r\n const rlErr = err as RateLimiterRes;\r\n\r\n logger.warn(\"⚠ RLFlexibleAdapter: rate limit exceeded\", {\r\n ip,\r\n path: req.path,\r\n method: req.method,\r\n retryAfter: rlErr.msBeforeNext\r\n });\r\n\r\n res.setHeader('Retry-After', Math.ceil(rlErr.msBeforeNext / 1000));\r\n \r\n return res.status(429).json({\r\n success: false,\r\n error: \"RATE_LIMIT_EXCEEDED\",\r\n retryAfter: Math.ceil(rlErr.msBeforeNext / 1000),\r\n message: finalOptions.message\r\n });\r\n }\r\n };\r\n\r\n } catch (err: any) {\r\n logger.error(\"❌ RLFlexibleAdapter: failed to initialize limiter\", {\r\n error: err?.message || err\r\n });\r\n throw new AdapterError(\"RateLimiterFlexible creation failed.\");\r\n }\r\n }\r\n\r\n private extractIP(req: any): string {\r\n return (\r\n req.headers['x-real-ip'] ||\r\n req.headers['x-forwarded-for']?.split(',')[0]?.trim() ||\r\n req.ip ||\r\n req.connection?.remoteAddress ||\r\n req.socket?.remoteAddress ||\r\n 'unknown'\r\n );\r\n }\r\n}"]}
|
|
@@ -3,9 +3,6 @@ export declare class SanitizeHtmlAdapter {
|
|
|
3
3
|
private globalOptions;
|
|
4
4
|
constructor(options?: sanitizeHtml.IOptions);
|
|
5
5
|
sanitize(input: string, dynamicOptions?: any): string;
|
|
6
|
-
/**
|
|
7
|
-
* Deep sanitize with recursion protection
|
|
8
|
-
*/
|
|
9
6
|
private deepSanitize;
|
|
10
7
|
middleware(dynamicOptions?: any): (req: any, _res: any, next: any) => void;
|
|
11
8
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SanitizeHtmlAdapter.d.ts","sourceRoot":"","sources":["../../src/adapters/SanitizeHtmlAdapter.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"SanitizeHtmlAdapter.d.ts","sourceRoot":"","sources":["../../src/adapters/SanitizeHtmlAdapter.ts"],"names":[],"mappings":"AAAA,OAAO,YAAY,MAAM,eAAe,CAAC;AAIzC,qBAAa,mBAAmB;IAC5B,OAAO,CAAC,aAAa,CAAwB;gBAEjC,OAAO,GAAE,YAAY,CAAC,QAAa;IAI/C,QAAQ,CAAC,KAAK,EAAE,MAAM,EAAE,cAAc,CAAC,EAAE,GAAG,GAAG,MAAM;IAkBrD,OAAO,CAAC,YAAY;IA4BpB,UAAU,CAAC,cAAc,CAAC,EAAE,GAAG,IACnB,KAAK,GAAG,EAAE,MAAM,GAAG,EAAE,MAAM,GAAG;CAmB7C"}
|
|
@@ -1,75 +1,9 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
// import sanitizeHtml from "sanitize-html";
|
|
3
|
-
// import { AdapterError } from "../core/errors/AdapterError";
|
|
4
|
-
// import { logger } from "../logging";
|
|
5
2
|
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
6
3
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
7
4
|
};
|
|
8
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
9
6
|
exports.SanitizeHtmlAdapter = void 0;
|
|
10
|
-
// export class SanitizeHtmlAdapter {
|
|
11
|
-
// private globalOptions: sanitizeHtml.IOptions;
|
|
12
|
-
// constructor(options: sanitizeHtml.IOptions = {}) {
|
|
13
|
-
// this.globalOptions = options;
|
|
14
|
-
// }
|
|
15
|
-
// /**
|
|
16
|
-
// * Sanitize a string with merged global + dynamic options
|
|
17
|
-
// */
|
|
18
|
-
// sanitize(input: string, dynamicOptions?: any): string {
|
|
19
|
-
// try {
|
|
20
|
-
// const opts = { ...this.globalOptions, ...(dynamicOptions || {}) };
|
|
21
|
-
// const clean = sanitizeHtml(input, opts);
|
|
22
|
-
// return typeof clean === "string" ? clean : String(clean);
|
|
23
|
-
// } catch (err: any) {
|
|
24
|
-
// logger.error("❌ sanitize-html failed", {
|
|
25
|
-
// error: err?.message || err,
|
|
26
|
-
// preview: typeof input === "string" ? input.slice(0, 100) : undefined
|
|
27
|
-
// });
|
|
28
|
-
// throw new AdapterError("sanitize-html adapter failed.");
|
|
29
|
-
// }
|
|
30
|
-
// }
|
|
31
|
-
// /**
|
|
32
|
-
// * Deep sanitize nested objects, arrays, strings
|
|
33
|
-
// */
|
|
34
|
-
// private deepSanitize(obj: any, dynamicOptions?: any): any {
|
|
35
|
-
// if (typeof obj === "string") {
|
|
36
|
-
// return this.sanitize(obj, dynamicOptions);
|
|
37
|
-
// }
|
|
38
|
-
// if (Array.isArray(obj)) {
|
|
39
|
-
// return obj.map((item) => this.deepSanitize(item, dynamicOptions));
|
|
40
|
-
// }
|
|
41
|
-
// if (obj && typeof obj === "object") {
|
|
42
|
-
// const result: any = {};
|
|
43
|
-
// for (const key of Object.keys(obj)) {
|
|
44
|
-
// result[key] = this.deepSanitize(obj[key], dynamicOptions);
|
|
45
|
-
// }
|
|
46
|
-
// return result;
|
|
47
|
-
// }
|
|
48
|
-
// return obj;
|
|
49
|
-
// }
|
|
50
|
-
// /**
|
|
51
|
-
// * Middleware wrapper with dynamic per-route options
|
|
52
|
-
// */
|
|
53
|
-
// middleware(dynamicOptions?: any) {
|
|
54
|
-
// return (req: any, _res: any, next: any) => {
|
|
55
|
-
// try {
|
|
56
|
-
// if (req.body) {
|
|
57
|
-
// req.body = this.deepSanitize(req.body, dynamicOptions);
|
|
58
|
-
// logger.debug("🧼 sanitize-html applied", {
|
|
59
|
-
// keys: Object.keys(req.body)
|
|
60
|
-
// });
|
|
61
|
-
// }
|
|
62
|
-
// next();
|
|
63
|
-
// } catch (err: any) {
|
|
64
|
-
// logger.error("❌ sanitize-html middleware failed", {
|
|
65
|
-
// error: err?.message || err
|
|
66
|
-
// });
|
|
67
|
-
// next(err);
|
|
68
|
-
// }
|
|
69
|
-
// };
|
|
70
|
-
// }
|
|
71
|
-
// }
|
|
72
|
-
// src/adapters/SanitizeHtmlAdapter.ts - FIXED
|
|
73
7
|
const sanitize_html_1 = __importDefault(require("sanitize-html"));
|
|
74
8
|
const AdapterError_js_1 = require("../core/errors/AdapterError.js");
|
|
75
9
|
const index_js_1 = require("../logging/index.js");
|
|
@@ -91,14 +25,11 @@ class SanitizeHtmlAdapter {
|
|
|
91
25
|
throw new AdapterError_js_1.AdapterError("sanitize-html adapter failed.");
|
|
92
26
|
}
|
|
93
27
|
}
|
|
94
|
-
|
|
95
|
-
* Deep sanitize with recursion protection
|
|
96
|
-
*/
|
|
28
|
+
// Deep Sanitization - Recursively
|
|
97
29
|
deepSanitize(obj, dynamicOptions, visited = new WeakSet()) {
|
|
98
|
-
// Handle circular references
|
|
99
30
|
if (obj && typeof obj === "object") {
|
|
100
31
|
if (visited.has(obj)) {
|
|
101
|
-
return obj;
|
|
32
|
+
return obj;
|
|
102
33
|
}
|
|
103
34
|
visited.add(obj);
|
|
104
35
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SanitizeHtmlAdapter.js","sourceRoot":"","sources":["../../src/adapters/SanitizeHtmlAdapter.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"SanitizeHtmlAdapter.js","sourceRoot":"","sources":["../../src/adapters/SanitizeHtmlAdapter.ts"],"names":[],"mappings":"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","sourcesContent":["import sanitizeHtml from \"sanitize-html\";\r\nimport { AdapterError } from \"../core/errors/AdapterError.js\";\r\nimport { logger } from \"../logging/index.js\";\r\n\r\nexport class SanitizeHtmlAdapter {\r\n private globalOptions: sanitizeHtml.IOptions;\r\n\r\n constructor(options: sanitizeHtml.IOptions = {}) {\r\n this.globalOptions = options;\r\n }\r\n\r\n sanitize(input: string, dynamicOptions?: any): string {\r\n try {\r\n const opts = { ...this.globalOptions, ...(dynamicOptions || {}) };\r\n\r\n const clean = sanitizeHtml(input, opts);\r\n return typeof clean === \"string\" ? clean : String(clean);\r\n\r\n } catch (err: any) {\r\n logger.error(\"❌ sanitize-html failed\", {\r\n error: err?.message || err,\r\n preview: typeof input === \"string\" ? input.slice(0, 100) : undefined\r\n });\r\n\r\n throw new AdapterError(\"sanitize-html adapter failed.\");\r\n }\r\n }\r\n\r\n // Deep Sanitization - Recursively \r\n private deepSanitize(obj: any, dynamicOptions?: any, visited = new WeakSet()): any {\r\n \r\n if (obj && typeof obj === \"object\") {\r\n if (visited.has(obj)) {\r\n return obj; \r\n }\r\n visited.add(obj);\r\n }\r\n\r\n if (typeof obj === \"string\") {\r\n return this.sanitize(obj, dynamicOptions);\r\n }\r\n\r\n if (Array.isArray(obj)) {\r\n return obj.map((item) => this.deepSanitize(item, dynamicOptions, visited));\r\n }\r\n\r\n if (obj && typeof obj === \"object\") {\r\n const result: any = {};\r\n for (const key of Object.keys(obj)) {\r\n result[key] = this.deepSanitize(obj[key], dynamicOptions, visited);\r\n }\r\n return result;\r\n }\r\n\r\n return obj;\r\n }\r\n\r\n middleware(dynamicOptions?: any) {\r\n return (req: any, _res: any, next: any) => {\r\n try {\r\n if (req.body) {\r\n req.body = this.deepSanitize(req.body, dynamicOptions);\r\n\r\n logger.debug(\"🧼 sanitize-html applied\", {\r\n keys: Object.keys(req.body)\r\n });\r\n }\r\n next();\r\n\r\n } catch (err: any) {\r\n logger.error(\"❌ sanitize-html middleware failed\", {\r\n error: err?.message || err\r\n });\r\n next(err);\r\n }\r\n };\r\n }\r\n}"]}
|
|
@@ -16,18 +16,8 @@ export declare class XSSAdapter {
|
|
|
16
16
|
private globalOptions;
|
|
17
17
|
private defaultFilter;
|
|
18
18
|
constructor(options?: XSSOptions);
|
|
19
|
-
/**
|
|
20
|
-
* Sanitize a string with global + dynamic merged options
|
|
21
|
-
*/
|
|
22
19
|
sanitize(input: string, dynamicOptions?: XSSOptions): string;
|
|
23
|
-
/**
|
|
24
|
-
* Middleware wrapper WITH dynamic options
|
|
25
|
-
* Doesn't mutate original request - creates sanitized copy
|
|
26
|
-
*/
|
|
27
20
|
middleware(dynamicOptions?: XSSOptions): (req: any, _res: any, next: any) => void;
|
|
28
|
-
/**
|
|
29
|
-
* Deep sanitize nested objects/arrays
|
|
30
|
-
*/
|
|
31
21
|
private deepSanitize;
|
|
32
22
|
}
|
|
33
23
|
//# sourceMappingURL=XSSAdapter.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"XSSAdapter.d.ts","sourceRoot":"","sources":["../../src/adapters/XSSAdapter.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"XSSAdapter.d.ts","sourceRoot":"","sources":["../../src/adapters/XSSAdapter.ts"],"names":[],"mappings":"AAAA,OAAO,EAAkC,SAAS,EAAE,MAAM,KAAK,CAAC;AAIhE,MAAM,WAAW,UAAU;IACvB,SAAS,CAAC,EAAE,OAAO,SAAS,CAAC;IAC7B,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,kBAAkB,CAAC,EAAE,MAAM,EAAE,CAAC;IAC9B,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,GAAG,CAAC,EAAE,OAAO,GAAG;QAAE,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAA;KAAE,CAAC;IAC3C,KAAK,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,GAAG,KAAK,MAAM,CAAC;IAC5D,SAAS,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,WAAW,EAAE,OAAO,KAAK,MAAM,CAAC;IACvF,WAAW,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,GAAG,KAAK,MAAM,CAAC;IAClE,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,CAAC;CACtB;AAED,qBAAa,UAAU;IACnB,OAAO,CAAC,aAAa,CAAa;IAClC,OAAO,CAAC,aAAa,CAAY;gBAErB,OAAO,GAAE,UAAe;IAwBpC,QAAQ,CAAC,KAAK,EAAE,MAAM,EAAE,cAAc,CAAC,EAAE,UAAU,GAAG,MAAM;IA2B5D,UAAU,CAAC,cAAc,CAAC,EAAE,UAAU,IAC1B,KAAK,GAAG,EAAE,MAAM,GAAG,EAAE,MAAM,GAAG;IA6C1C,OAAO,CAAC,YAAY;CA2BvB"}
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.XSSAdapter = void 0;
|
|
4
|
-
// src/adapters/XSSAdapter.ts - NEW FILE
|
|
5
4
|
const xss_1 = require("xss");
|
|
6
5
|
const AdapterError_js_1 = require("../core/errors/AdapterError.js");
|
|
7
6
|
const index_js_1 = require("../logging/index.js");
|
|
@@ -11,12 +10,11 @@ class XSSAdapter {
|
|
|
11
10
|
// Default safe configuration
|
|
12
11
|
const defaultOptions = {
|
|
13
12
|
whiteList: (0, xss_1.getDefaultWhiteList)(),
|
|
14
|
-
stripIgnoreTag: true,
|
|
13
|
+
stripIgnoreTag: true,
|
|
15
14
|
stripIgnoreTagBody: ['script', 'style', 'iframe', 'object', 'embed'],
|
|
16
15
|
allowCommentTag: false,
|
|
17
|
-
css: false,
|
|
16
|
+
css: false,
|
|
18
17
|
onTag: (tag, html, options) => {
|
|
19
|
-
// Add noopener/noreferrer to links for security
|
|
20
18
|
if (tag === 'a') {
|
|
21
19
|
return html.replace(/<a /i, '<a target="_blank" rel="noopener noreferrer" ');
|
|
22
20
|
}
|
|
@@ -26,19 +24,14 @@ class XSSAdapter {
|
|
|
26
24
|
const finalOptions = { ...defaultOptions, ...options };
|
|
27
25
|
this.defaultFilter = new xss_1.FilterXSS(finalOptions);
|
|
28
26
|
}
|
|
29
|
-
/**
|
|
30
|
-
* Sanitize a string with global + dynamic merged options
|
|
31
|
-
*/
|
|
32
27
|
sanitize(input, dynamicOptions) {
|
|
33
28
|
try {
|
|
34
29
|
if (typeof input !== "string") {
|
|
35
30
|
return input;
|
|
36
31
|
}
|
|
37
|
-
// If no dynamic options, use default filter
|
|
38
32
|
if (!dynamicOptions || Object.keys(dynamicOptions).length === 0) {
|
|
39
33
|
return this.defaultFilter.process(input);
|
|
40
34
|
}
|
|
41
|
-
// Merge options for this specific call
|
|
42
35
|
const mergedOptions = { ...this.globalOptions, ...dynamicOptions };
|
|
43
36
|
const customFilter = new xss_1.FilterXSS(mergedOptions);
|
|
44
37
|
return customFilter.process(input);
|
|
@@ -51,10 +44,6 @@ class XSSAdapter {
|
|
|
51
44
|
throw new AdapterError_js_1.AdapterError("XSS sanitizer failed.");
|
|
52
45
|
}
|
|
53
46
|
}
|
|
54
|
-
/**
|
|
55
|
-
* Middleware wrapper WITH dynamic options
|
|
56
|
-
* Doesn't mutate original request - creates sanitized copy
|
|
57
|
-
*/
|
|
58
47
|
middleware(dynamicOptions) {
|
|
59
48
|
return (req, _res, next) => {
|
|
60
49
|
try {
|
|
@@ -72,14 +61,12 @@ class XSSAdapter {
|
|
|
72
61
|
: v);
|
|
73
62
|
}
|
|
74
63
|
else if (val && typeof val === "object") {
|
|
75
|
-
// Handle nested objects (simple recursion)
|
|
76
64
|
sanitizedBody[key] = this.deepSanitize(val, dynamicOptions);
|
|
77
65
|
}
|
|
78
66
|
else {
|
|
79
67
|
sanitizedBody[key] = val;
|
|
80
68
|
}
|
|
81
69
|
}
|
|
82
|
-
// Store sanitized version separately
|
|
83
70
|
req.sanitizedBody = sanitizedBody;
|
|
84
71
|
index_js_1.logger.debug("🛡️ XSS sanitizer applied", {
|
|
85
72
|
originalKeys: Object.keys(originalBody),
|
|
@@ -96,11 +83,7 @@ class XSSAdapter {
|
|
|
96
83
|
}
|
|
97
84
|
};
|
|
98
85
|
}
|
|
99
|
-
/**
|
|
100
|
-
* Deep sanitize nested objects/arrays
|
|
101
|
-
*/
|
|
102
86
|
deepSanitize(obj, options, visited = new WeakSet()) {
|
|
103
|
-
// Handle circular references
|
|
104
87
|
if (obj && typeof obj === "object") {
|
|
105
88
|
if (visited.has(obj)) {
|
|
106
89
|
return obj;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"XSSAdapter.js","sourceRoot":"","sources":["../../src/adapters/XSSAdapter.ts"],"names":[],"mappings":";;;AAAA,
|
|
1
|
+
{"version":3,"file":"XSSAdapter.js","sourceRoot":"","sources":["../../src/adapters/XSSAdapter.ts"],"names":[],"mappings":"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","sourcesContent":["import { FilterXSS, getDefaultWhiteList, whiteList } from 'xss';\r\nimport { AdapterError } from \"../core/errors/AdapterError.js\";\r\nimport { logger } from \"../logging/index.js\";\r\n\r\nexport interface XSSOptions {\r\n whiteList?: typeof whiteList;\r\n stripIgnoreTag?: boolean;\r\n stripIgnoreTagBody?: string[];\r\n allowCommentTag?: boolean;\r\n css?: boolean | { [key: string]: boolean };\r\n onTag?: (tag: string, html: string, options: any) => string;\r\n onTagAttr?: (tag: string, name: string, value: string, isWhiteAttr: boolean) => string;\r\n onIgnoreTag?: (tag: string, html: string, options: any) => string;\r\n [key: string]: any;\r\n}\r\n\r\nexport class XSSAdapter {\r\n private globalOptions: XSSOptions;\r\n private defaultFilter: FilterXSS;\r\n\r\n constructor(options: XSSOptions = {}) {\r\n this.globalOptions = options;\r\n \r\n // Default safe configuration\r\n const defaultOptions: XSSOptions = {\r\n whiteList: getDefaultWhiteList(),\r\n stripIgnoreTag: true, \r\n stripIgnoreTagBody: ['script', 'style', 'iframe', 'object', 'embed'],\r\n allowCommentTag: false,\r\n css: false, \r\n onTag: (tag, html, options) => {\r\n \r\n if (tag === 'a') {\r\n return html.replace(/<a /i, '<a target=\"_blank\" rel=\"noopener noreferrer\" ');\r\n }\r\n return html;\r\n }\r\n };\r\n\r\n const finalOptions = { ...defaultOptions, ...options };\r\n this.defaultFilter = new FilterXSS(finalOptions);\r\n }\r\n\r\n \r\n sanitize(input: string, dynamicOptions?: XSSOptions): string {\r\n try {\r\n if (typeof input !== \"string\") {\r\n return input as any;\r\n }\r\n\r\n \r\n if (!dynamicOptions || Object.keys(dynamicOptions).length === 0) {\r\n return this.defaultFilter.process(input);\r\n }\r\n\r\n \r\n const mergedOptions = { ...this.globalOptions, ...dynamicOptions };\r\n const customFilter = new FilterXSS(mergedOptions);\r\n \r\n return customFilter.process(input);\r\n\r\n } catch (err: any) {\r\n logger.error(\"❌ XSS sanitizer failed\", {\r\n error: err?.message,\r\n preview: input?.slice?.(0, 80)\r\n });\r\n throw new AdapterError(\"XSS sanitizer failed.\");\r\n }\r\n }\r\n\r\n \r\n middleware(dynamicOptions?: XSSOptions) {\r\n return (req: any, _res: any, next: any) => {\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 val = originalBody[key];\r\n\r\n if (typeof val === \"string\") {\r\n sanitizedBody[key] = this.sanitize(val, dynamicOptions);\r\n } else if (Array.isArray(val)) {\r\n sanitizedBody[key] = val.map((v) =>\r\n typeof v === \"string\"\r\n ? this.sanitize(v, dynamicOptions)\r\n : v\r\n );\r\n } else if (val && typeof val === \"object\") {\r\n \r\n sanitizedBody[key] = this.deepSanitize(val, dynamicOptions);\r\n } else {\r\n sanitizedBody[key] = val;\r\n }\r\n }\r\n \r\n \r\n req.sanitizedBody = sanitizedBody;\r\n \r\n logger.debug(\"🛡️ XSS sanitizer applied\", {\r\n originalKeys: Object.keys(originalBody),\r\n sanitizedKeys: Object.keys(sanitizedBody)\r\n });\r\n }\r\n\r\n next();\r\n } catch (err: any) {\r\n logger.error(\"❌ XSS middleware failed\", {\r\n error: err?.message || err\r\n });\r\n next(err);\r\n }\r\n };\r\n }\r\n\r\n \r\n private deepSanitize(obj: any, options?: XSSOptions, visited = new WeakSet()): any {\r\n \r\n if (obj && typeof obj === \"object\") {\r\n if (visited.has(obj)) {\r\n return obj;\r\n }\r\n visited.add(obj);\r\n }\r\n\r\n if (typeof obj === \"string\") {\r\n return this.sanitize(obj, options);\r\n }\r\n\r\n if (Array.isArray(obj)) {\r\n return obj.map(item => this.deepSanitize(item, options, visited));\r\n }\r\n\r\n if (obj && typeof obj === \"object\") {\r\n const result: any = {};\r\n for (const key of Object.keys(obj)) {\r\n result[key] = this.deepSanitize(obj[key], options, visited);\r\n }\r\n return result;\r\n }\r\n\r\n return obj;\r\n }\r\n}"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ZodAdapter.d.ts","sourceRoot":"","sources":["../../src/adapters/ZodAdapter.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"ZodAdapter.d.ts","sourceRoot":"","sources":["../../src/adapters/ZodAdapter.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAY,MAAM,KAAK,CAAC;AAI1C,qBAAa,UAAU;IACnB,OAAO,CAAC,YAAY,CAAC,CAAY;gBAErB,YAAY,CAAC,EAAE,SAAS;IAIpC,QAAQ,CAAC,aAAa,CAAC,EAAE,SAAS,IACtB,KAAK,GAAG,EAAE,KAAK,GAAG,EAAE,MAAM,GAAG;CA6B5C"}
|
|
@@ -1,10 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
// import { ZodSchema, ZodError } from "zod";
|
|
3
|
-
// import { ValidationError } from "../core/errors/ValidationError";
|
|
4
|
-
// import { logger } from "../logging";
|
|
5
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
3
|
exports.ZodAdapter = void 0;
|
|
7
|
-
const ValidationError_js_1 = require("../core/errors/ValidationError.js");
|
|
4
|
+
const ValidationError_js_1 = require("../core/errors/ValidationError.js");
|
|
8
5
|
const index_js_1 = require("../logging/index.js");
|
|
9
6
|
class ZodAdapter {
|
|
10
7
|
constructor(globalSchema) {
|
|
@@ -30,8 +27,7 @@ class ZodAdapter {
|
|
|
30
27
|
issues,
|
|
31
28
|
preview: JSON.stringify(req.body).slice(0, 200)
|
|
32
29
|
});
|
|
33
|
-
return next(new ValidationError_js_1.ValidationError("Validation failed.", issues)
|
|
34
|
-
);
|
|
30
|
+
return next(new ValidationError_js_1.ValidationError("Validation failed.", issues));
|
|
35
31
|
};
|
|
36
32
|
}
|
|
37
33
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ZodAdapter.js","sourceRoot":"","sources":["../../src/adapters/ZodAdapter.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"ZodAdapter.js","sourceRoot":"","sources":["../../src/adapters/ZodAdapter.ts"],"names":[],"mappings":";;;AACA,0EAAoE;AACpE,kDAA6C;AAE7C,MAAa,UAAU;IAGnB,YAAY,YAAwB;QAChC,IAAI,CAAC,YAAY,GAAG,YAAY,CAAC;IACrC,CAAC;IAED,QAAQ,CAAC,aAAyB;QAC9B,OAAO,CAAC,GAAQ,EAAE,GAAQ,EAAE,IAAS,EAAE,EAAE;YACrC,MAAM,MAAM,GAAG,aAAa,IAAI,IAAI,CAAC,YAAY,CAAC;YAElD,IAAI,CAAC,MAAM;gBAAE,OAAO,IAAI,EAAE,CAAC;YAE3B,MAAM,MAAM,GAAG,MAAM,CAAC,SAAS,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;YAE1C,IAAI,MAAM,CAAC,OAAO;gBAAE,OAAO,IAAI,EAAE,CAAC;YAElC,MAAM,MAAM,GAAa,MAAM,CAAC,KAAK,CAAC;YAEtC,MAAM,MAAM,GAAG,MAAM,CAAC,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;gBACvC,OAAO,EAAE,KAAK,CAAC,OAAO;gBACtB,IAAI,EAAE,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC;gBAC1B,IAAI,EAAE,KAAK,CAAC,IAAI;aACnB,CAAC,CAAC,CAAC;YAEJ,iBAAM,CAAC,IAAI,CAAC,yBAAyB,EAAE;gBACnC,IAAI,EAAE,GAAG,CAAC,IAAI;gBACd,MAAM,EAAE,GAAG,CAAC,MAAM;gBAClB,MAAM;gBACN,OAAO,EAAE,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC;aAClD,CAAC,CAAC;YAEH,OAAO,IAAI,CACP,IAAI,oCAAe,CAAC,oBAAoB,EAAE,MAAa,CAAC,CAC3D,CAAC;QACN,CAAC,CAAC;IACN,CAAC;CACJ;AArCD,gCAqCC","sourcesContent":["import { ZodSchema, ZodError } from \"zod\";\r\nimport { ValidationError } from \"../core/errors/ValidationError.js\"; \r\nimport { logger } from \"../logging/index.js\";\r\n\r\nexport class ZodAdapter {\r\n private globalSchema?: ZodSchema;\r\n\r\n constructor(globalSchema?: ZodSchema) {\r\n this.globalSchema = globalSchema;\r\n }\r\n\r\n validate(dynamicSchema?: ZodSchema) {\r\n return (req: any, res: any, next: any) => {\r\n const schema = dynamicSchema || this.globalSchema;\r\n\r\n if (!schema) return next();\r\n\r\n const result = schema.safeParse(req.body);\r\n\r\n if (result.success) return next();\r\n\r\n const zodErr: ZodError = result.error;\r\n\r\n const issues = zodErr.issues.map(issue => ({\r\n message: issue.message,\r\n path: issue.path.join(\".\"),\r\n code: issue.code\r\n }));\r\n\r\n logger.warn(\"⚠ Zod validation failed\", {\r\n path: req.path,\r\n method: req.method,\r\n issues,\r\n preview: JSON.stringify(req.body).slice(0, 200)\r\n });\r\n\r\n return next(\r\n new ValidationError(\"Validation failed.\", issues as any) \r\n );\r\n };\r\n }\r\n}"]}
|
package/dist/core/HiSecure.d.ts
CHANGED
|
@@ -22,8 +22,6 @@ export declare class HiSecure {
|
|
|
22
22
|
private hashingFallback;
|
|
23
23
|
private rateLimiterPrimary;
|
|
24
24
|
private rateLimiterFallback;
|
|
25
|
-
private validatorPrimary;
|
|
26
|
-
private validatorFallback;
|
|
27
25
|
private sanitizerPrimary;
|
|
28
26
|
private sanitizerFallback;
|
|
29
27
|
private constructor();
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"HiSecure.d.ts","sourceRoot":"","sources":["../../src/core/HiSecure.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"HiSecure.d.ts","sourceRoot":"","sources":["../../src/core/HiSecure.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAC;AAkB3D,OAAO,EAAE,WAAW,EAAE,MAAM,4BAA4B,CAAC;AACzD,OAAO,EAAE,gBAAgB,EAAE,MAAM,iCAAiC,CAAC;AACnE,OAAO,EAAE,gBAAgB,EAAE,MAAM,iCAAiC,CAAC;AACnE,OAAO,EAAE,gBAAgB,EAAE,MAAM,iCAAiC,CAAC;AACnE,OAAO,EAAE,WAAW,EAAE,MAAM,4BAA4B,CAAC;AACzD,OAAO,EAAE,WAAW,EAAE,MAAM,4BAA4B,CAAC;AACzD,OAAO,EAAE,WAAW,EAAE,MAAM,4BAA4B,CAAC;AASzD,OAAO,EAAE,aAAa,EAAE,gBAAgB,EAAC,MAAM,0BAA0B,CAAC;AAE1E,qBAAa,QAAQ;IACjB,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAyB;IAChD,OAAO,CAAC,MAAM,CAAiB;IAC/B,OAAO,CAAC,WAAW,CAAS;IAGrB,WAAW,EAAG,WAAW,CAAC;IAC1B,gBAAgB,EAAG,gBAAgB,CAAC;IACpC,gBAAgB,EAAG,gBAAgB,CAAC;IACpC,gBAAgB,EAAG,gBAAgB,CAAC;IACpC,WAAW,EAAG,WAAW,CAAC;IAC1B,WAAW,EAAG,WAAW,CAAC;IAC1B,WAAW,CAAC,EAAE,WAAW,CAAC;IAGjC,OAAO,CAAC,cAAc,CAAM;IAC5B,OAAO,CAAC,eAAe,CAAM;IAC7B,OAAO,CAAC,kBAAkB,CAAM;IAChC,OAAO,CAAC,mBAAmB,CAAM;IACjC,OAAO,CAAC,gBAAgB,CAAM;IAC9B,OAAO,CAAC,iBAAiB,CAAM;IAG/B,OAAO;IAMP,MAAM,CAAC,WAAW,CAAC,MAAM,CAAC,EAAE,OAAO,CAAC,cAAc,CAAC,GAAG,QAAQ;IAQ9D,MAAM,CAAC,aAAa,IAAI,IAAI;IAI5B,IAAI,IAAI,IAAI;IAyBZ,aAAa,IAAI,OAAO;IAMxB,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE;QAAE,QAAQ,CAAC,EAAE,OAAO,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,EAAE,CAAA;KAAE;IAQ9D,MAAM,CAAC,QAAQ,CAAC,MAAM,EAAE,gBAAgB;IAIxC,MAAM,CAAC,QAAQ,CAAC,OAAO,CAAC,EAAE,GAAG;IAI7B,MAAM,CAAC,SAAS,CAAC,MAAM,EAAE,QAAQ,GAAG,SAAS,GAAG,KAAK,GAAG,MAAM;IAe9D,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,GAAG;kBA7GJ,CAAC;;;iBAID,CAAC;IA6GtB,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,GAAG;WAUZ,IAAI,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;WAMvC,MAAM,CAAC,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAIrE,MAAM,CAAC,GAAG;wBACU,MAAM,YAAY,GAAG;wBAQrB,MAAM;;qCASO,MAAM;;MAQrC;IAIF,MAAM,CAAC,UAAU,CAAC,OAAO,CAAC,EAAE,aAAa,GAAG,KAAK,GAAG,QAAQ,GAAG,QAAQ;IAuBvE,OAAO,CAAC,aAAa;IAoCrB,OAAO,CAAC,aAAa;IA2BrB,OAAO,CAAC,oBAAoB;IAmB5B,OAAO,CAAC,qBAAqB;CAmDhC"}
|
package/dist/core/HiSecure.js
CHANGED
|
@@ -37,9 +37,7 @@ class HiSecure {
|
|
|
37
37
|
this.initialized = false;
|
|
38
38
|
this.config = (0, deepMerge_js_1.deepMerge)(config_js_1.defaultConfig, userConfig);
|
|
39
39
|
}
|
|
40
|
-
// =====================================================
|
|
41
40
|
// SINGLETON & INITIALIZATION
|
|
42
|
-
// =====================================================
|
|
43
41
|
static getInstance(config) {
|
|
44
42
|
if (!HiSecure.instance) {
|
|
45
43
|
HiSecure.instance = new HiSecure(config);
|
|
@@ -59,7 +57,6 @@ class HiSecure {
|
|
|
59
57
|
this.setupAdapters();
|
|
60
58
|
this.setupManagers();
|
|
61
59
|
this.setupDynamicManagers();
|
|
62
|
-
// Make everything immutable
|
|
63
60
|
(0, deepFreeze_js_1.deepFreeze)(this.config);
|
|
64
61
|
// deepFreeze(this.hashManager);
|
|
65
62
|
// deepFreeze(this.rateLimitManager);
|
|
@@ -74,9 +71,7 @@ class HiSecure {
|
|
|
74
71
|
isInitialized() {
|
|
75
72
|
return this.initialized;
|
|
76
73
|
}
|
|
77
|
-
// =====================================================
|
|
78
74
|
// FLUENT API METHODS (Route-level security)
|
|
79
|
-
// =====================================================
|
|
80
75
|
static auth(options) {
|
|
81
76
|
const instance = this.getInstance();
|
|
82
77
|
if (!instance.authManager) {
|
|
@@ -112,9 +107,7 @@ class HiSecure {
|
|
|
112
107
|
chain.push(instance.jsonManager.urlencoded());
|
|
113
108
|
return chain;
|
|
114
109
|
}
|
|
115
|
-
// =====================================================
|
|
116
110
|
// UTILITY METHODS (Direct usage)
|
|
117
|
-
// =====================================================
|
|
118
111
|
static async hash(password) {
|
|
119
112
|
const instance = this.getInstance();
|
|
120
113
|
const result = await instance.hashManager.hash(password, { allowFallback: true });
|
|
@@ -123,9 +116,7 @@ class HiSecure {
|
|
|
123
116
|
static async verify(password, hash) {
|
|
124
117
|
return this.getInstance().hashManager.verify(password, hash);
|
|
125
118
|
}
|
|
126
|
-
// =====================================================
|
|
127
119
|
// GLOBAL MIDDLEWARE (app.use())
|
|
128
|
-
// =====================================================
|
|
129
120
|
static middleware(options) {
|
|
130
121
|
const instance = this.getInstance();
|
|
131
122
|
// Handle preset strings
|
|
@@ -143,9 +134,7 @@ class HiSecure {
|
|
|
143
134
|
}
|
|
144
135
|
return instance.createMiddlewareChain(options || {});
|
|
145
136
|
}
|
|
146
|
-
//
|
|
147
|
-
// INTERNAL METHODS
|
|
148
|
-
// =====================================================
|
|
137
|
+
// Internal Methods
|
|
149
138
|
setupAdapters() {
|
|
150
139
|
index_js_1.logger.info("🧩 Setting up adapters...");
|
|
151
140
|
// Hashing
|
|
@@ -160,13 +149,13 @@ class HiSecure {
|
|
|
160
149
|
? new RLFlexibleAdapter_js_1.RLFlexibleAdapter()
|
|
161
150
|
: new ExpressRLAdapter_js_1.ExpressRLAdapter();
|
|
162
151
|
this.rateLimiterFallback = new ExpressRLAdapter_js_1.ExpressRLAdapter();
|
|
163
|
-
// Validation
|
|
164
|
-
this.validatorPrimary = this.config.validation.mode === "zod"
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
this.validatorFallback = this.config.validation.fallback === "express-validator"
|
|
168
|
-
|
|
169
|
-
|
|
152
|
+
// // Validation
|
|
153
|
+
// this.validatorPrimary = this.config.validation.mode === "zod"
|
|
154
|
+
// ? new ZodAdapter()
|
|
155
|
+
// : new ExpressValidatorAdapter();
|
|
156
|
+
// this.validatorFallback = this.config.validation.fallback === "express-validator"
|
|
157
|
+
// ? new ExpressValidatorAdapter()
|
|
158
|
+
// : null;
|
|
170
159
|
// Sanitization
|
|
171
160
|
this.sanitizerPrimary = new SanitizeHtmlAdapter_js_1.SanitizeHtmlAdapter(this.config.sanitizer);
|
|
172
161
|
this.sanitizerFallback = new XSSAdapter_js_1.XSSAdapter(this.config.sanitizer);
|
|
@@ -195,7 +184,6 @@ class HiSecure {
|
|
|
195
184
|
jwtSecret,
|
|
196
185
|
jwtExpiresIn: this.config.auth.jwtExpiresIn,
|
|
197
186
|
googleClientId: process.env.GOOGLE_CLIENT_ID || this.config.auth.googleClientId
|
|
198
|
-
// Removed algorithm - handled in AuthManager
|
|
199
187
|
});
|
|
200
188
|
}
|
|
201
189
|
}
|