hi-secure 1.0.0

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.
Files changed (210) hide show
  1. package/dist/adapters/ArgonAdapter.d.ts +8 -0
  2. package/dist/adapters/ArgonAdapter.d.ts.map +1 -0
  3. package/dist/adapters/ArgonAdapter.js +45 -0
  4. package/dist/adapters/ArgonAdapter.js.map +1 -0
  5. package/dist/adapters/BcryptAdapter.d.ts +7 -0
  6. package/dist/adapters/BcryptAdapter.d.ts.map +1 -0
  7. package/dist/adapters/BcryptAdapter.js +48 -0
  8. package/dist/adapters/BcryptAdapter.js.map +1 -0
  9. package/dist/adapters/DomPurifyAdapter.d.ts +13 -0
  10. package/dist/adapters/DomPurifyAdapter.d.ts.map +1 -0
  11. package/dist/adapters/DomPurifyAdapter.js +61 -0
  12. package/dist/adapters/DomPurifyAdapter.js.map +1 -0
  13. package/dist/adapters/ExpressRLAdapter.d.ts +13 -0
  14. package/dist/adapters/ExpressRLAdapter.d.ts.map +1 -0
  15. package/dist/adapters/ExpressRLAdapter.js +68 -0
  16. package/dist/adapters/ExpressRLAdapter.js.map +1 -0
  17. package/dist/adapters/ExpressValidatorAdapter.d.ts +6 -0
  18. package/dist/adapters/ExpressValidatorAdapter.d.ts.map +1 -0
  19. package/dist/adapters/ExpressValidatorAdapter.js +78 -0
  20. package/dist/adapters/ExpressValidatorAdapter.js.map +1 -0
  21. package/dist/adapters/GoggleAdapter.d.ts +15 -0
  22. package/dist/adapters/GoggleAdapter.d.ts.map +1 -0
  23. package/dist/adapters/GoggleAdapter.js +91 -0
  24. package/dist/adapters/GoggleAdapter.js.map +1 -0
  25. package/dist/adapters/GoogleAdapter.d.ts +15 -0
  26. package/dist/adapters/GoogleAdapter.d.ts.map +1 -0
  27. package/dist/adapters/GoogleAdapter.js +159 -0
  28. package/dist/adapters/GoogleAdapter.js.map +1 -0
  29. package/dist/adapters/JWTAdapter.d.ts +28 -0
  30. package/dist/adapters/JWTAdapter.d.ts.map +1 -0
  31. package/dist/adapters/JWTAdapter.js +276 -0
  32. package/dist/adapters/JWTAdapter.js.map +1 -0
  33. package/dist/adapters/RLFlexibleAdapter.d.ts +11 -0
  34. package/dist/adapters/RLFlexibleAdapter.d.ts.map +1 -0
  35. package/dist/adapters/RLFlexibleAdapter.js +115 -0
  36. package/dist/adapters/RLFlexibleAdapter.js.map +1 -0
  37. package/dist/adapters/SanitizeHtmlAdapter.d.ts +12 -0
  38. package/dist/adapters/SanitizeHtmlAdapter.d.ts.map +1 -0
  39. package/dist/adapters/SanitizeHtmlAdapter.js +141 -0
  40. package/dist/adapters/SanitizeHtmlAdapter.js.map +1 -0
  41. package/dist/adapters/XSSAdapter.d.ts +33 -0
  42. package/dist/adapters/XSSAdapter.d.ts.map +1 -0
  43. package/dist/adapters/XSSAdapter.js +127 -0
  44. package/dist/adapters/XSSAdapter.js.map +1 -0
  45. package/dist/adapters/ZodAdapter.d.ts +7 -0
  46. package/dist/adapters/ZodAdapter.d.ts.map +1 -0
  47. package/dist/adapters/ZodAdapter.js +39 -0
  48. package/dist/adapters/ZodAdapter.js.map +1 -0
  49. package/dist/core/HiSecure.d.ts +62 -0
  50. package/dist/core/HiSecure.d.ts.map +1 -0
  51. package/dist/core/HiSecure.js +273 -0
  52. package/dist/core/HiSecure.js.map +1 -0
  53. package/dist/core/config.d.ts +3 -0
  54. package/dist/core/config.d.ts.map +1 -0
  55. package/dist/core/config.js +53 -0
  56. package/dist/core/config.js.map +1 -0
  57. package/dist/core/constants.d.ts +37 -0
  58. package/dist/core/constants.d.ts.map +1 -0
  59. package/dist/core/constants.js +67 -0
  60. package/dist/core/constants.js.map +1 -0
  61. package/dist/core/errors/AdapterError.d.ts +5 -0
  62. package/dist/core/errors/AdapterError.d.ts.map +1 -0
  63. package/dist/core/errors/AdapterError.js +15 -0
  64. package/dist/core/errors/AdapterError.js.map +1 -0
  65. package/dist/core/errors/HttpErrror.d.ts +17 -0
  66. package/dist/core/errors/HttpErrror.d.ts.map +1 -0
  67. package/dist/core/errors/HttpErrror.js +36 -0
  68. package/dist/core/errors/HttpErrror.js.map +1 -0
  69. package/dist/core/errors/SanitizerError.d.ts +5 -0
  70. package/dist/core/errors/SanitizerError.d.ts.map +1 -0
  71. package/dist/core/errors/SanitizerError.js +14 -0
  72. package/dist/core/errors/SanitizerError.js.map +1 -0
  73. package/dist/core/errors/SecurityError.d.ts +5 -0
  74. package/dist/core/errors/SecurityError.d.ts.map +1 -0
  75. package/dist/core/errors/SecurityError.js +14 -0
  76. package/dist/core/errors/SecurityError.js.map +1 -0
  77. package/dist/core/errors/ValidationError.d.ts +5 -0
  78. package/dist/core/errors/ValidationError.d.ts.map +1 -0
  79. package/dist/core/errors/ValidationError.js +14 -0
  80. package/dist/core/errors/ValidationError.js.map +1 -0
  81. package/dist/core/types/HiSecureConfig.d.ts +47 -0
  82. package/dist/core/types/HiSecureConfig.d.ts.map +1 -0
  83. package/dist/core/types/HiSecureConfig.js +3 -0
  84. package/dist/core/types/HiSecureConfig.js.map +1 -0
  85. package/dist/core/types/SecureOptions.d.ts +30 -0
  86. package/dist/core/types/SecureOptions.d.ts.map +1 -0
  87. package/dist/core/types/SecureOptions.js +4 -0
  88. package/dist/core/types/SecureOptions.js.map +1 -0
  89. package/dist/core/useSecure.d.ts +10 -0
  90. package/dist/core/useSecure.d.ts.map +1 -0
  91. package/dist/core/useSecure.js +85 -0
  92. package/dist/core/useSecure.js.map +1 -0
  93. package/dist/examples/e1.d.ts +1 -0
  94. package/dist/examples/e1.d.ts.map +1 -0
  95. package/dist/examples/e1.js +3 -0
  96. package/dist/examples/e1.js.map +1 -0
  97. package/dist/index.d.ts +9 -0
  98. package/dist/index.d.ts.map +1 -0
  99. package/dist/index.js +15 -0
  100. package/dist/index.js.map +1 -0
  101. package/dist/logging/index.d.ts +3 -0
  102. package/dist/logging/index.d.ts.map +1 -0
  103. package/dist/logging/index.js +19 -0
  104. package/dist/logging/index.js.map +1 -0
  105. package/dist/logging/morganSetup.d.ts +2 -0
  106. package/dist/logging/morganSetup.d.ts.map +1 -0
  107. package/dist/logging/morganSetup.js +9 -0
  108. package/dist/logging/morganSetup.js.map +1 -0
  109. package/dist/logging/winstonSetup.d.ts +6 -0
  110. package/dist/logging/winstonSetup.d.ts.map +1 -0
  111. package/dist/logging/winstonSetup.js +22 -0
  112. package/dist/logging/winstonSetup.js.map +1 -0
  113. package/dist/managers/AuthManager.d.ts +23 -0
  114. package/dist/managers/AuthManager.d.ts.map +1 -0
  115. package/dist/managers/AuthManager.js +190 -0
  116. package/dist/managers/AuthManager.js.map +1 -0
  117. package/dist/managers/CorsManager.d.ts +9 -0
  118. package/dist/managers/CorsManager.d.ts.map +1 -0
  119. package/dist/managers/CorsManager.js +55 -0
  120. package/dist/managers/CorsManager.js.map +1 -0
  121. package/dist/managers/HashManager.d.ts +22 -0
  122. package/dist/managers/HashManager.d.ts.map +1 -0
  123. package/dist/managers/HashManager.js +319 -0
  124. package/dist/managers/HashManager.js.map +1 -0
  125. package/dist/managers/JsonManager.d.ts +6 -0
  126. package/dist/managers/JsonManager.d.ts.map +1 -0
  127. package/dist/managers/JsonManager.js +142 -0
  128. package/dist/managers/JsonManager.js.map +1 -0
  129. package/dist/managers/RateLimitManager.d.ts +16 -0
  130. package/dist/managers/RateLimitManager.d.ts.map +1 -0
  131. package/dist/managers/RateLimitManager.js +108 -0
  132. package/dist/managers/RateLimitManager.js.map +1 -0
  133. package/dist/managers/SanitizerManager.d.ts +18 -0
  134. package/dist/managers/SanitizerManager.d.ts.map +1 -0
  135. package/dist/managers/SanitizerManager.js +296 -0
  136. package/dist/managers/SanitizerManager.js.map +1 -0
  137. package/dist/managers/ValidatorManager.d.ts +13 -0
  138. package/dist/managers/ValidatorManager.d.ts.map +1 -0
  139. package/dist/managers/ValidatorManager.js +218 -0
  140. package/dist/managers/ValidatorManager.js.map +1 -0
  141. package/dist/middlewares/errorHandler.d.ts +3 -0
  142. package/dist/middlewares/errorHandler.d.ts.map +1 -0
  143. package/dist/middlewares/errorHandler.js +94 -0
  144. package/dist/middlewares/errorHandler.js.map +1 -0
  145. package/dist/middlewares/index.d.ts +3 -0
  146. package/dist/middlewares/index.d.ts.map +1 -0
  147. package/dist/middlewares/index.js +19 -0
  148. package/dist/middlewares/index.js.map +1 -0
  149. package/dist/middlewares/requestLogger.d.ts +2 -0
  150. package/dist/middlewares/requestLogger.d.ts.map +1 -0
  151. package/dist/middlewares/requestLogger.js +8 -0
  152. package/dist/middlewares/requestLogger.js.map +1 -0
  153. package/dist/test/t1.d.ts +1 -0
  154. package/dist/test/t1.d.ts.map +1 -0
  155. package/dist/test/t1.js +3 -0
  156. package/dist/test/t1.js.map +1 -0
  157. package/dist/utils/deepFreeze.d.ts +2 -0
  158. package/dist/utils/deepFreeze.d.ts.map +1 -0
  159. package/dist/utils/deepFreeze.js +69 -0
  160. package/dist/utils/deepFreeze.js.map +1 -0
  161. package/dist/utils/deepMerge.d.ts +5 -0
  162. package/dist/utils/deepMerge.d.ts.map +1 -0
  163. package/dist/utils/deepMerge.js +68 -0
  164. package/dist/utils/deepMerge.js.map +1 -0
  165. package/dist/utils/normalizeOptions.d.ts +38 -0
  166. package/dist/utils/normalizeOptions.d.ts.map +1 -0
  167. package/dist/utils/normalizeOptions.js +119 -0
  168. package/dist/utils/normalizeOptions.js.map +1 -0
  169. package/package.json +50 -0
  170. package/src/adapters/ArgonAdapter.ts +41 -0
  171. package/src/adapters/BcryptAdapter.ts +49 -0
  172. package/src/adapters/ExpressRLAdapter.ts +84 -0
  173. package/src/adapters/ExpressValidatorAdapter.ts +99 -0
  174. package/src/adapters/GoogleAdapter.ts +206 -0
  175. package/src/adapters/JWTAdapter.ts +346 -0
  176. package/src/adapters/RLFlexibleAdapter.ts +139 -0
  177. package/src/adapters/SanitizeHtmlAdapter.ts +162 -0
  178. package/src/adapters/XSSAdapter.ts +153 -0
  179. package/src/adapters/ZodAdapter.ts +91 -0
  180. package/src/core/HiSecure.ts +955 -0
  181. package/src/core/config.ts +156 -0
  182. package/src/core/constants.ts +73 -0
  183. package/src/core/errors/AdapterError.ts +14 -0
  184. package/src/core/errors/HttpErrror.ts +46 -0
  185. package/src/core/errors/SanitizerError.ts +13 -0
  186. package/src/core/errors/SecurityError.ts +13 -0
  187. package/src/core/errors/ValidationError.ts +13 -0
  188. package/src/core/types/HiSecureConfig.ts +62 -0
  189. package/src/core/types/SecureOptions.ts +61 -0
  190. package/src/core/useSecure.ts +111 -0
  191. package/src/examples/e1.ts +1 -0
  192. package/src/index.ts +17 -0
  193. package/src/logging/index.ts +2 -0
  194. package/src/logging/morganSetup.ts +3 -0
  195. package/src/logging/winstonSetup.ts +17 -0
  196. package/src/managers/AuthManager.ts +237 -0
  197. package/src/managers/CorsManager.ts +58 -0
  198. package/src/managers/HashManager.ts +390 -0
  199. package/src/managers/JsonManager.ts +149 -0
  200. package/src/managers/RateLimitManager.ts +368 -0
  201. package/src/managers/SanitizerManager.ts +359 -0
  202. package/src/managers/ValidatorManager.ts +269 -0
  203. package/src/middlewares/errorHandler.ts +265 -0
  204. package/src/middlewares/index.ts +2 -0
  205. package/src/middlewares/requestLogger.ts +5 -0
  206. package/src/test/t1.ts +1 -0
  207. package/src/utils/deepFreeze.ts +76 -0
  208. package/src/utils/deepMerge.ts +87 -0
  209. package/src/utils/normalizeOptions.ts +265 -0
  210. package/tsconfig.json +30 -0
@@ -0,0 +1,115 @@
1
+ "use strict";
2
+ // import { RateLimiterMemory, RateLimiterRes } from "rate-limiter-flexible";
3
+ // import { logger } from "../logging";
4
+ // import { AdapterError } from "../core/errors/AdapterError";
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ 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
+ const rate_limiter_flexible_1 = require("rate-limiter-flexible");
55
+ const index_js_1 = require("../logging/index.js");
56
+ const AdapterError_js_1 = require("../core/errors/AdapterError.js");
57
+ class RLFlexibleAdapter {
58
+ getMiddleware(options = {}) {
59
+ try {
60
+ const defaultOptions = {
61
+ points: 100,
62
+ duration: 60,
63
+ message: "Too many requests, slow down.",
64
+ blockDuration: 0
65
+ };
66
+ const finalOptions = { ...defaultOptions, ...options };
67
+ const limiter = new rate_limiter_flexible_1.RateLimiterMemory({
68
+ points: finalOptions.points,
69
+ duration: finalOptions.duration,
70
+ blockDuration: finalOptions.blockDuration
71
+ });
72
+ return async (req, res, next) => {
73
+ // Better IP extraction
74
+ const ip = this.extractIP(req);
75
+ try {
76
+ await limiter.consume(ip);
77
+ next();
78
+ }
79
+ catch (err) {
80
+ const rlErr = err;
81
+ index_js_1.logger.warn("⚠ RLFlexibleAdapter: rate limit exceeded", {
82
+ ip,
83
+ path: req.path,
84
+ method: req.method,
85
+ retryAfter: rlErr.msBeforeNext
86
+ });
87
+ res.setHeader('Retry-After', Math.ceil(rlErr.msBeforeNext / 1000));
88
+ return res.status(429).json({
89
+ success: false,
90
+ error: "RATE_LIMIT_EXCEEDED",
91
+ retryAfter: Math.ceil(rlErr.msBeforeNext / 1000),
92
+ message: finalOptions.message
93
+ });
94
+ }
95
+ };
96
+ }
97
+ catch (err) {
98
+ index_js_1.logger.error("❌ RLFlexibleAdapter: failed to initialize limiter", {
99
+ error: err?.message || err
100
+ });
101
+ throw new AdapterError_js_1.AdapterError("RateLimiterFlexible creation failed.");
102
+ }
103
+ }
104
+ extractIP(req) {
105
+ // Order of priority for IP extraction
106
+ return (req.headers['x-real-ip'] ||
107
+ req.headers['x-forwarded-for']?.split(',')[0]?.trim() ||
108
+ req.ip ||
109
+ req.connection?.remoteAddress ||
110
+ req.socket?.remoteAddress ||
111
+ 'unknown');
112
+ }
113
+ }
114
+ exports.RLFlexibleAdapter = RLFlexibleAdapter;
115
+ //# sourceMappingURL=RLFlexibleAdapter.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"RLFlexibleAdapter.js","sourceRoot":"","sources":["../../src/adapters/RLFlexibleAdapter.ts"],"names":[],"mappings":"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","sourcesContent":["\r\n// import { RateLimiterMemory, RateLimiterRes } from \"rate-limiter-flexible\";\r\n// import { logger } from \"../logging\";\r\n// import { AdapterError } from \"../core/errors/AdapterError\";\r\n\r\n// export class RLFlexibleAdapter {\r\n\r\n// /**\r\n// * Create middleware dynamically using options.\r\n// */\r\n// getMiddleware(options: {\r\n// points?: number;\r\n// duration?: number; // seconds\r\n// message?: any;\r\n// } = {}) {\r\n\r\n// try {\r\n// const limiter = new RateLimiterMemory({\r\n// points: options.points ?? 100,\r\n// duration: options.duration ?? 60,\r\n// });\r\n\r\n// return async (req: any, res: any, next: any) => {\r\n// const ip = req.ip ||\r\n// req.headers[\"x-forwarded-for\"] ||\r\n// req.connection?.remoteAddress ||\r\n// \"unknown\";\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// 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: options.message ?? \"Too many requests, slow down.\"\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\r\n\r\n\r\n// src/adapters/RLFlexibleAdapter.ts - IMPROVED\r\nimport { 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; // seconds\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 // Better IP extraction\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 // Order of priority for IP extraction\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}"]}
@@ -0,0 +1,12 @@
1
+ import sanitizeHtml from "sanitize-html";
2
+ export declare class SanitizeHtmlAdapter {
3
+ private globalOptions;
4
+ constructor(options?: sanitizeHtml.IOptions);
5
+ sanitize(input: string, dynamicOptions?: any): string;
6
+ /**
7
+ * Deep sanitize with recursion protection
8
+ */
9
+ private deepSanitize;
10
+ middleware(dynamicOptions?: any): (req: any, _res: any, next: any) => void;
11
+ }
12
+ //# sourceMappingURL=SanitizeHtmlAdapter.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SanitizeHtmlAdapter.d.ts","sourceRoot":"","sources":["../../src/adapters/SanitizeHtmlAdapter.ts"],"names":[],"mappings":"AAkFA,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;IAiBrD;;OAEG;IACH,OAAO,CAAC,YAAY;IA4BpB,UAAU,CAAC,cAAc,CAAC,EAAE,GAAG,IACnB,KAAK,GAAG,EAAE,MAAM,GAAG,EAAE,MAAM,GAAG;CAmB7C"}
@@ -0,0 +1,141 @@
1
+ "use strict";
2
+ // import sanitizeHtml from "sanitize-html";
3
+ // import { AdapterError } from "../core/errors/AdapterError";
4
+ // import { logger } from "../logging";
5
+ var __importDefault = (this && this.__importDefault) || function (mod) {
6
+ return (mod && mod.__esModule) ? mod : { "default": mod };
7
+ };
8
+ Object.defineProperty(exports, "__esModule", { value: true });
9
+ 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
+ const sanitize_html_1 = __importDefault(require("sanitize-html"));
74
+ const AdapterError_js_1 = require("../core/errors/AdapterError.js");
75
+ const index_js_1 = require("../logging/index.js");
76
+ class SanitizeHtmlAdapter {
77
+ constructor(options = {}) {
78
+ this.globalOptions = options;
79
+ }
80
+ sanitize(input, dynamicOptions) {
81
+ try {
82
+ const opts = { ...this.globalOptions, ...(dynamicOptions || {}) };
83
+ const clean = (0, sanitize_html_1.default)(input, opts);
84
+ return typeof clean === "string" ? clean : String(clean);
85
+ }
86
+ catch (err) {
87
+ index_js_1.logger.error("❌ sanitize-html failed", {
88
+ error: err?.message || err,
89
+ preview: typeof input === "string" ? input.slice(0, 100) : undefined
90
+ });
91
+ throw new AdapterError_js_1.AdapterError("sanitize-html adapter failed.");
92
+ }
93
+ }
94
+ /**
95
+ * Deep sanitize with recursion protection
96
+ */
97
+ deepSanitize(obj, dynamicOptions, visited = new WeakSet()) {
98
+ // Handle circular references
99
+ if (obj && typeof obj === "object") {
100
+ if (visited.has(obj)) {
101
+ return obj; // Circular reference detected
102
+ }
103
+ visited.add(obj);
104
+ }
105
+ if (typeof obj === "string") {
106
+ return this.sanitize(obj, dynamicOptions);
107
+ }
108
+ if (Array.isArray(obj)) {
109
+ return obj.map((item) => this.deepSanitize(item, dynamicOptions, visited));
110
+ }
111
+ if (obj && typeof obj === "object") {
112
+ const result = {};
113
+ for (const key of Object.keys(obj)) {
114
+ result[key] = this.deepSanitize(obj[key], dynamicOptions, visited);
115
+ }
116
+ return result;
117
+ }
118
+ return obj;
119
+ }
120
+ middleware(dynamicOptions) {
121
+ return (req, _res, next) => {
122
+ try {
123
+ if (req.body) {
124
+ req.body = this.deepSanitize(req.body, dynamicOptions);
125
+ index_js_1.logger.debug("🧼 sanitize-html applied", {
126
+ keys: Object.keys(req.body)
127
+ });
128
+ }
129
+ next();
130
+ }
131
+ catch (err) {
132
+ index_js_1.logger.error("❌ sanitize-html middleware failed", {
133
+ error: err?.message || err
134
+ });
135
+ next(err);
136
+ }
137
+ };
138
+ }
139
+ }
140
+ exports.SanitizeHtmlAdapter = SanitizeHtmlAdapter;
141
+ //# sourceMappingURL=SanitizeHtmlAdapter.js.map
@@ -0,0 +1 @@
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\n// import { AdapterError } from \"../core/errors/AdapterError\";\r\n// import { logger } from \"../logging\";\r\n\r\n// export 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// /**\r\n// * Sanitize a string with merged global + dynamic options\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\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// /**\r\n// * Deep sanitize nested objects, arrays, strings\r\n// */\r\n// private deepSanitize(obj: any, dynamicOptions?: any): any {\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));\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);\r\n// }\r\n// return result;\r\n// }\r\n\r\n// return obj;\r\n// }\r\n\r\n// /**\r\n// * Middleware wrapper with dynamic per-route options\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// }\r\n\r\n\r\n// src/adapters/SanitizeHtmlAdapter.ts - FIXED\r\nimport 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 /**\r\n * Deep sanitize with recursion protection\r\n */\r\n private deepSanitize(obj: any, dynamicOptions?: any, visited = new WeakSet()): any {\r\n // Handle circular references\r\n if (obj && typeof obj === \"object\") {\r\n if (visited.has(obj)) {\r\n return obj; // Circular reference detected\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}"]}
@@ -0,0 +1,33 @@
1
+ import { whiteList } from 'xss';
2
+ export interface XSSOptions {
3
+ whiteList?: typeof whiteList;
4
+ stripIgnoreTag?: boolean;
5
+ stripIgnoreTagBody?: string[];
6
+ allowCommentTag?: boolean;
7
+ css?: boolean | {
8
+ [key: string]: boolean;
9
+ };
10
+ onTag?: (tag: string, html: string, options: any) => string;
11
+ onTagAttr?: (tag: string, name: string, value: string, isWhiteAttr: boolean) => string;
12
+ onIgnoreTag?: (tag: string, html: string, options: any) => string;
13
+ [key: string]: any;
14
+ }
15
+ export declare class XSSAdapter {
16
+ private globalOptions;
17
+ private defaultFilter;
18
+ constructor(options?: XSSOptions);
19
+ /**
20
+ * Sanitize a string with global + dynamic merged options
21
+ */
22
+ sanitize(input: string, dynamicOptions?: XSSOptions): string;
23
+ /**
24
+ * Middleware wrapper WITH dynamic options
25
+ * Doesn't mutate original request - creates sanitized copy
26
+ */
27
+ middleware(dynamicOptions?: XSSOptions): (req: any, _res: any, next: any) => void;
28
+ /**
29
+ * Deep sanitize nested objects/arrays
30
+ */
31
+ private deepSanitize;
32
+ }
33
+ //# sourceMappingURL=XSSAdapter.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"XSSAdapter.d.ts","sourceRoot":"","sources":["../../src/adapters/XSSAdapter.ts"],"names":[],"mappings":"AACA,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;IAuBpC;;OAEG;IACH,QAAQ,CAAC,KAAK,EAAE,MAAM,EAAE,cAAc,CAAC,EAAE,UAAU,GAAG,MAAM;IA0B5D;;;OAGG;IACH,UAAU,CAAC,cAAc,CAAC,EAAE,UAAU,IAC1B,KAAK,GAAG,EAAE,MAAM,GAAG,EAAE,MAAM,GAAG;IA4C1C;;OAEG;IACH,OAAO,CAAC,YAAY;CA2BvB"}
@@ -0,0 +1,127 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.XSSAdapter = void 0;
4
+ // src/adapters/XSSAdapter.ts - NEW FILE
5
+ const xss_1 = require("xss");
6
+ const AdapterError_js_1 = require("../core/errors/AdapterError.js");
7
+ const index_js_1 = require("../logging/index.js");
8
+ class XSSAdapter {
9
+ constructor(options = {}) {
10
+ this.globalOptions = options;
11
+ // Default safe configuration
12
+ const defaultOptions = {
13
+ whiteList: (0, xss_1.getDefaultWhiteList)(),
14
+ stripIgnoreTag: true, // Remove non-whitelisted tags completely
15
+ stripIgnoreTagBody: ['script', 'style', 'iframe', 'object', 'embed'],
16
+ allowCommentTag: false,
17
+ css: false, // Disable CSS by default
18
+ onTag: (tag, html, options) => {
19
+ // Add noopener/noreferrer to links for security
20
+ if (tag === 'a') {
21
+ return html.replace(/<a /i, '<a target="_blank" rel="noopener noreferrer" ');
22
+ }
23
+ return html;
24
+ }
25
+ };
26
+ const finalOptions = { ...defaultOptions, ...options };
27
+ this.defaultFilter = new xss_1.FilterXSS(finalOptions);
28
+ }
29
+ /**
30
+ * Sanitize a string with global + dynamic merged options
31
+ */
32
+ sanitize(input, dynamicOptions) {
33
+ try {
34
+ if (typeof input !== "string") {
35
+ return input;
36
+ }
37
+ // If no dynamic options, use default filter
38
+ if (!dynamicOptions || Object.keys(dynamicOptions).length === 0) {
39
+ return this.defaultFilter.process(input);
40
+ }
41
+ // Merge options for this specific call
42
+ const mergedOptions = { ...this.globalOptions, ...dynamicOptions };
43
+ const customFilter = new xss_1.FilterXSS(mergedOptions);
44
+ return customFilter.process(input);
45
+ }
46
+ catch (err) {
47
+ index_js_1.logger.error("❌ XSS sanitizer failed", {
48
+ error: err?.message,
49
+ preview: input?.slice?.(0, 80)
50
+ });
51
+ throw new AdapterError_js_1.AdapterError("XSS sanitizer failed.");
52
+ }
53
+ }
54
+ /**
55
+ * Middleware wrapper WITH dynamic options
56
+ * Doesn't mutate original request - creates sanitized copy
57
+ */
58
+ middleware(dynamicOptions) {
59
+ return (req, _res, next) => {
60
+ try {
61
+ if (req.body && typeof req.body === "object") {
62
+ const originalBody = req.body;
63
+ const sanitizedBody = Array.isArray(originalBody) ? [] : {};
64
+ for (const key of Object.keys(originalBody)) {
65
+ const val = originalBody[key];
66
+ if (typeof val === "string") {
67
+ sanitizedBody[key] = this.sanitize(val, dynamicOptions);
68
+ }
69
+ else if (Array.isArray(val)) {
70
+ sanitizedBody[key] = val.map((v) => typeof v === "string"
71
+ ? this.sanitize(v, dynamicOptions)
72
+ : v);
73
+ }
74
+ else if (val && typeof val === "object") {
75
+ // Handle nested objects (simple recursion)
76
+ sanitizedBody[key] = this.deepSanitize(val, dynamicOptions);
77
+ }
78
+ else {
79
+ sanitizedBody[key] = val;
80
+ }
81
+ }
82
+ // Store sanitized version separately
83
+ req.sanitizedBody = sanitizedBody;
84
+ index_js_1.logger.debug("🛡️ XSS sanitizer applied", {
85
+ originalKeys: Object.keys(originalBody),
86
+ sanitizedKeys: Object.keys(sanitizedBody)
87
+ });
88
+ }
89
+ next();
90
+ }
91
+ catch (err) {
92
+ index_js_1.logger.error("❌ XSS middleware failed", {
93
+ error: err?.message || err
94
+ });
95
+ next(err);
96
+ }
97
+ };
98
+ }
99
+ /**
100
+ * Deep sanitize nested objects/arrays
101
+ */
102
+ deepSanitize(obj, options, visited = new WeakSet()) {
103
+ // Handle circular references
104
+ if (obj && typeof obj === "object") {
105
+ if (visited.has(obj)) {
106
+ return obj;
107
+ }
108
+ visited.add(obj);
109
+ }
110
+ if (typeof obj === "string") {
111
+ return this.sanitize(obj, options);
112
+ }
113
+ if (Array.isArray(obj)) {
114
+ return obj.map(item => this.deepSanitize(item, options, visited));
115
+ }
116
+ if (obj && typeof obj === "object") {
117
+ const result = {};
118
+ for (const key of Object.keys(obj)) {
119
+ result[key] = this.deepSanitize(obj[key], options, visited);
120
+ }
121
+ return result;
122
+ }
123
+ return obj;
124
+ }
125
+ }
126
+ exports.XSSAdapter = XSSAdapter;
127
+ //# sourceMappingURL=XSSAdapter.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"XSSAdapter.js","sourceRoot":"","sources":["../../src/adapters/XSSAdapter.ts"],"names":[],"mappings":"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","sourcesContent":["// src/adapters/XSSAdapter.ts - NEW FILE\r\nimport { 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, // Remove non-whitelisted tags completely\r\n stripIgnoreTagBody: ['script', 'style', 'iframe', 'object', 'embed'],\r\n allowCommentTag: false,\r\n css: false, // Disable CSS by default\r\n onTag: (tag, html, options) => {\r\n // Add noopener/noreferrer to links for security\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 a string with global + dynamic merged options\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 // If no dynamic options, use default filter\r\n if (!dynamicOptions || Object.keys(dynamicOptions).length === 0) {\r\n return this.defaultFilter.process(input);\r\n }\r\n\r\n // Merge options for this specific call\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 wrapper WITH dynamic options\r\n * Doesn't mutate original request - creates sanitized copy\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 // Handle nested objects (simple recursion)\r\n sanitizedBody[key] = this.deepSanitize(val, dynamicOptions);\r\n } else {\r\n sanitizedBody[key] = val;\r\n }\r\n }\r\n \r\n // Store sanitized version separately\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 * Deep sanitize nested objects/arrays\r\n */\r\n private deepSanitize(obj: any, options?: XSSOptions, visited = new WeakSet()): any {\r\n // Handle circular references\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}"]}
@@ -0,0 +1,7 @@
1
+ import { ZodSchema } from "zod";
2
+ export declare class ZodAdapter {
3
+ private globalSchema?;
4
+ constructor(globalSchema?: ZodSchema);
5
+ validate(dynamicSchema?: ZodSchema): (req: any, res: any, next: any) => any;
6
+ }
7
+ //# sourceMappingURL=ZodAdapter.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ZodAdapter.d.ts","sourceRoot":"","sources":["../../src/adapters/ZodAdapter.ts"],"names":[],"mappings":"AAiDA,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"}
@@ -0,0 +1,39 @@
1
+ "use strict";
2
+ // import { ZodSchema, ZodError } from "zod";
3
+ // import { ValidationError } from "../core/errors/ValidationError";
4
+ // import { logger } from "../logging";
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.ZodAdapter = void 0;
7
+ const ValidationError_js_1 = require("../core/errors/ValidationError.js"); // ✅ Add .js
8
+ const index_js_1 = require("../logging/index.js");
9
+ class ZodAdapter {
10
+ constructor(globalSchema) {
11
+ this.globalSchema = globalSchema;
12
+ }
13
+ validate(dynamicSchema) {
14
+ return (req, res, next) => {
15
+ const schema = dynamicSchema || this.globalSchema;
16
+ if (!schema)
17
+ return next();
18
+ const result = schema.safeParse(req.body);
19
+ if (result.success)
20
+ return next();
21
+ const zodErr = result.error;
22
+ const issues = zodErr.issues.map(issue => ({
23
+ message: issue.message,
24
+ path: issue.path.join("."),
25
+ code: issue.code
26
+ }));
27
+ index_js_1.logger.warn("⚠ Zod validation failed", {
28
+ path: req.path,
29
+ method: req.method,
30
+ issues,
31
+ preview: JSON.stringify(req.body).slice(0, 200)
32
+ });
33
+ return next(new ValidationError_js_1.ValidationError("Validation failed.", issues) // ✅ Pass issues
34
+ );
35
+ };
36
+ }
37
+ }
38
+ exports.ZodAdapter = ZodAdapter;
39
+ //# sourceMappingURL=ZodAdapter.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ZodAdapter.js","sourceRoot":"","sources":["../../src/adapters/ZodAdapter.ts"],"names":[],"mappings":";AAAA,6CAA6C;AAC7C,oEAAoE;AACpE,uCAAuC;;;AAgDvC,0EAAoE,CAAC,YAAY;AACjF,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,CAAC,gBAAgB;aAC5E,CAAC;QACN,CAAC,CAAC;IACN,CAAC;CACJ;AArCD,gCAqCC","sourcesContent":["// import { ZodSchema, ZodError } from \"zod\";\r\n// import { ValidationError } from \"../core/errors/ValidationError\";\r\n// import { logger } from \"../logging\";\r\n\r\n// export class ZodAdapter {\r\n// private globalSchema?: ZodSchema;\r\n\r\n// constructor(globalSchema?: ZodSchema) {\r\n// this.globalSchema = globalSchema as any;\r\n// }\r\n\r\n// /**\r\n// * Validate with global + dynamic schema (dynamic overrides global)\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(); // no validation for this route\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(issues[0]?.message || \"Validation failed.\")\r\n// );\r\n// };\r\n// }\r\n// }\r\n\r\n\r\n\r\n// src/adapters/ZodAdapter.ts - FIXED\r\nimport { ZodSchema, ZodError } from \"zod\";\r\nimport { ValidationError } from \"../core/errors/ValidationError.js\"; // ✅ Add .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) // ✅ Pass issues\r\n );\r\n };\r\n }\r\n}"]}
@@ -0,0 +1,62 @@
1
+ import { HiSecureConfig } from "./types/HiSecureConfig.js";
2
+ import { HashManager } from "../managers/HashManager.js";
3
+ import { RateLimitManager } from "../managers/RateLimitManager.js";
4
+ import { ValidatorManager } from "../managers/ValidatorManager.js";
5
+ import { SanitizerManager } from "../managers/SanitizerManager.js";
6
+ import { JsonManager } from "../managers/JsonManager.js";
7
+ import { CorsManager } from "../managers/CorsManager.js";
8
+ import { AuthManager } from "../managers/AuthManager.js";
9
+ import { SecureOptions, ValidationSchema } from "./types/SecureOptions.js";
10
+ export declare class HiSecure {
11
+ private static instance;
12
+ private config;
13
+ private initialized;
14
+ hashManager: HashManager;
15
+ rateLimitManager: RateLimitManager;
16
+ validatorManager: ValidatorManager;
17
+ sanitizerManager: SanitizerManager;
18
+ jsonManager: JsonManager;
19
+ corsManager: CorsManager;
20
+ authManager?: AuthManager;
21
+ private hashingPrimary;
22
+ private hashingFallback;
23
+ private rateLimiterPrimary;
24
+ private rateLimiterFallback;
25
+ private validatorPrimary;
26
+ private validatorFallback;
27
+ private sanitizerPrimary;
28
+ private sanitizerFallback;
29
+ private constructor();
30
+ static getInstance(config?: Partial<HiSecureConfig>): HiSecure;
31
+ static resetInstance(): void;
32
+ init(): void;
33
+ isInitialized(): boolean;
34
+ static auth(options?: {
35
+ required?: boolean;
36
+ roles?: string[];
37
+ }): (req: import("express").Request, res: import("express").Response, next: import("express").NextFunction) => void;
38
+ static validate(schema: ValidationSchema): (req: any, res: any, next: any) => void;
39
+ static sanitize(options?: any): (req: any, _res: any, next: any) => void;
40
+ static rateLimit(preset: "strict" | "relaxed" | "api" | object): any;
41
+ static cors(options?: any): (req: import("cors").CorsRequest, res: {
42
+ statusCode?: number | undefined;
43
+ setHeader(key: string, value: string): any;
44
+ end(): any;
45
+ }, next: (err?: any) => any) => void;
46
+ static json(options?: any): import("connect").NextHandleFunction[];
47
+ static hash(password: string): Promise<string>;
48
+ static verify(password: string, hash: string): Promise<boolean>;
49
+ static jwt: {
50
+ sign: (payload: object, options?: any) => string;
51
+ verify: (token: string) => string | import("jsonwebtoken").Jwt | import("jsonwebtoken").JwtPayload;
52
+ google: {
53
+ verifyIdToken: (idToken: string) => Promise<import("../adapters/GoogleAdapter.js").GoogleTokenPayload>;
54
+ };
55
+ };
56
+ static middleware(options?: SecureOptions | "api" | "strict" | "public"): any[];
57
+ private setupAdapters;
58
+ private setupManagers;
59
+ private setupDynamicManagers;
60
+ private createMiddlewareChain;
61
+ }
62
+ //# sourceMappingURL=HiSecure.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"HiSecure.d.ts","sourceRoot":"","sources":["../../src/core/HiSecure.ts"],"names":[],"mappings":"AAslBA,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,EAAoB,MAAM,0BAA0B,CAAC;AAE7F,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;IAC/B,OAAO,CAAC,gBAAgB,CAAM;IAC9B,OAAO,CAAC,iBAAiB,CAAM;IAG/B,OAAO;IAQP,MAAM,CAAC,WAAW,CAAC,MAAM,CAAC,EAAE,OAAO,CAAC,cAAc,CAAC,GAAG,QAAQ;IAQ9D,MAAM,CAAC,aAAa,IAAI,IAAI;IAI5B,IAAI,IAAI,IAAI;IA0BZ,aAAa,IAAI,OAAO;IAQxB,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;kBA7sBsB,CAAC;;;iBAGjB,CAAC;IA8sBhC,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,GAAG;WAYZ,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;IAMF,MAAM,CAAC,UAAU,CAAC,OAAO,CAAC,EAAE,aAAa,GAAG,KAAK,GAAG,QAAQ,GAAG,QAAQ;IAwBvE,OAAO,CAAC,aAAa;IAiCrB,OAAO,CAAC,aAAa;IAyBrB,OAAO,CAAC,oBAAoB;IAoB5B,OAAO,CAAC,qBAAqB;CAmDhC"}