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,359 @@
1
+ // // // import { SanitizerError } from "../core/errors/SanitizerError";
2
+ // // // import { logger } from "../logging";
3
+
4
+ // // // interface SanitizerAdapter {
5
+ // // // sanitize: (value: string) => string;
6
+ // // // middleware?: () => any;
7
+ // // // }
8
+
9
+ // // // export class SanitizerManager {
10
+ // // // private primary: SanitizerAdapter;
11
+ // // // private fallback: SanitizerAdapter | null;
12
+
13
+ // // // constructor(primary: SanitizerAdapter, fallback: SanitizerAdapter | null = null) {
14
+ // // // this.primary = primary;
15
+ // // // this.fallback = fallback;
16
+ // // // }
17
+
18
+ // // // sanitize(value: string): string {
19
+ // // // try {
20
+ // // // return this.primary.sanitize(value);
21
+ // // // } catch (err: any) {
22
+ // // // logger.warn("⚠ Sanitizer primary adapter failed", { error: err?.message });
23
+
24
+ // // // if (!this.fallback) {
25
+ // // // throw new SanitizerError("Primary sanitizer failed, no fallback available.");
26
+ // // // }
27
+
28
+ // // // try {
29
+ // // // logger.info("📌 Using fallback sanitizer");
30
+ // // // return this.fallback.sanitize(value);
31
+ // // // } catch (fallbackErr: any) {
32
+ // // // logger.error("❌ Fallback sanitizer failed", {
33
+ // // // error: fallbackErr?.message
34
+ // // // });
35
+ // // // throw new SanitizerError("Both primary and fallback sanitizers failed.");
36
+ // // // }
37
+ // // // }
38
+ // // // }
39
+
40
+ // // // middleware() {
41
+ // // // return (req: any, _res: any, next: any) => {
42
+ // // // try {
43
+ // // // if (req.body && typeof req.body === "object") {
44
+ // // // for (const key of Object.keys(req.body)) {
45
+ // // // const value = req.body[key];
46
+
47
+ // // // if (typeof value === "string") {
48
+ // // // const clean = this.sanitize(value);
49
+
50
+ // // // logger.debug("🧼 Sanitized field", {
51
+ // // // field: key,
52
+ // // // before: value.slice(0, 80),
53
+ // // // after: clean.slice(0, 80),
54
+ // // // });
55
+
56
+ // // // req.body[key] = clean;
57
+ // // // }
58
+ // // // }
59
+ // // // }
60
+
61
+ // // // next();
62
+ // // // } catch (err: any) {
63
+ // // // logger.error("❌ Sanitizer middleware failed", { error: err?.message });
64
+ // // // next(new SanitizerError("Sanitizer middleware failure"));
65
+ // // // }
66
+ // // // };
67
+ // // // }
68
+ // // // }
69
+
70
+
71
+
72
+ // // // src/managers/SanitizerManager.ts
73
+ // // import { SanitizerError } from "../core/errors/SanitizerError.js";
74
+ // // import { logger } from "../logging";
75
+
76
+ // // interface SanitizerAdapter {
77
+ // // sanitize: (value: string, options?: any) => string;
78
+ // // }
79
+
80
+ // // export class SanitizerManager {
81
+ // // private primary: SanitizerAdapter;
82
+ // // private fallback: SanitizerAdapter | null;
83
+
84
+ // // constructor(primary: SanitizerAdapter, fallback: SanitizerAdapter | null = null) {
85
+ // // this.primary = primary;
86
+ // // this.fallback = fallback;
87
+ // // }
88
+
89
+ // // /**
90
+ // // * Sanitize a single value with optional dynamic options.
91
+ // // */
92
+ // // sanitize(value: string, options?: any): string {
93
+ // // try {
94
+ // // return this.primary.sanitize(value, options);
95
+
96
+ // // } catch (err: any) {
97
+ // // logger.warn("⚠ Primary sanitizer failed", { error: err?.message });
98
+
99
+ // // if (!this.fallback) {
100
+ // // throw new SanitizerError("Primary sanitizer failed and no fallback available.");
101
+ // // }
102
+
103
+ // // try {
104
+ // // logger.info("📌 Using fallback sanitizer");
105
+ // // return this.fallback.sanitize(value, options);
106
+
107
+ // // } catch (fallbackErr: any) {
108
+ // // logger.error("❌ Fallback sanitizer failed", {
109
+ // // error: fallbackErr?.message
110
+ // // });
111
+
112
+ // // throw new SanitizerError("Both primary and fallback sanitizers failed.");
113
+ // // }
114
+ // // }
115
+ // // }
116
+
117
+ // // /**
118
+ // // * Dynamic express middleware for sanitizing body.
119
+ // // * Options can override global config on each route.
120
+ // // */
121
+ // // middleware(options?: any) {
122
+ // // return (req: any, _res: any, next: any) => {
123
+ // // try {
124
+ // // if (req.body && typeof req.body === "object") {
125
+ // // for (const key of Object.keys(req.body)) {
126
+ // // const original = req.body[key];
127
+
128
+ // // if (typeof original === "string") {
129
+ // // const sanitized = this.sanitize(original, options);
130
+
131
+ // // logger.debug("🧼 Sanitized field", {
132
+ // // field: key,
133
+ // // before: original.slice(0, 80),
134
+ // // after: sanitized.slice(0, 80)
135
+ // // });
136
+
137
+ // // req.body[key] = sanitized;
138
+ // // }
139
+ // // }
140
+ // // }
141
+
142
+ // // next();
143
+
144
+ // // } catch (err: any) {
145
+ // // logger.error("❌ Sanitizer middleware failed", {
146
+ // // error: err?.message
147
+ // // });
148
+
149
+ // // next(new SanitizerError("Sanitizer middleware failure"));
150
+ // // }
151
+ // // };
152
+ // // }
153
+ // // }
154
+
155
+
156
+
157
+ // // src/managers/SanitizerManager.ts - FIXED
158
+ // import { SanitizerError } from "../core/errors/SanitizerError.js";
159
+ // import { logger } from "../logging";
160
+
161
+ // interface SanitizerAdapter {
162
+ // sanitize: (value: string, options?: any) => string;
163
+ // }
164
+
165
+ // export class SanitizerManager {
166
+ // private primary: SanitizerAdapter;
167
+ // private fallback: SanitizerAdapter | null;
168
+ // private useFallbackOnly: boolean = false;
169
+
170
+ // constructor(primary: SanitizerAdapter, fallback: SanitizerAdapter | null = null) {
171
+ // this.primary = primary;
172
+ // this.fallback = fallback;
173
+ // }
174
+
175
+ // /**
176
+ // * Sanitize a single value
177
+ // */
178
+ // sanitize(value: string, options?: any): string {
179
+ // // Don't process non-strings
180
+ // if (typeof value !== 'string') {
181
+ // return value;
182
+ // }
183
+
184
+ // // Use only one sanitizer, not both
185
+ // if (this.useFallbackOnly && this.fallback) {
186
+ // return this.fallback.sanitize(value, options);
187
+ // }
188
+
189
+ // try {
190
+ // return this.primary.sanitize(value, options);
191
+ // } catch (err: any) {
192
+ // logger.warn("⚠ Primary sanitizer failed", { error: err?.message });
193
+
194
+ // if (!this.fallback) {
195
+ // throw new SanitizerError("Primary sanitizer failed and no fallback available.");
196
+ // }
197
+
198
+ // logger.info("📌 Using fallback sanitizer");
199
+ // this.useFallbackOnly = true; // Use fallback for subsequent calls
200
+
201
+ // return this.fallback.sanitize(value, options);
202
+ // }
203
+ // }
204
+
205
+ // /**
206
+ // * Middleware that doesn't mutate original request
207
+ // */
208
+ // middleware(options?: any) {
209
+ // return (req: any, _res: any, next: any) => {
210
+ // try {
211
+ // // Create a sanitized copy of body instead of mutating
212
+ // if (req.body && typeof req.body === "object") {
213
+ // const originalBody = req.body;
214
+ // const sanitizedBody: any = Array.isArray(originalBody) ? [] : {};
215
+
216
+ // for (const key of Object.keys(originalBody)) {
217
+ // const value = originalBody[key];
218
+
219
+ // if (typeof value === "string") {
220
+ // sanitizedBody[key] = this.sanitize(value, options);
221
+ // } else if (Array.isArray(value)) {
222
+ // sanitizedBody[key] = value.map(item =>
223
+ // typeof item === "string" ? this.sanitize(item, options) : item
224
+ // );
225
+ // } else {
226
+ // sanitizedBody[key] = value;
227
+ // }
228
+ // }
229
+
230
+ // // Store sanitized version separately
231
+ // req.sanitizedBody = sanitizedBody;
232
+ // logger.debug("🧼 Request body sanitized", {
233
+ // originalKeys: Object.keys(originalBody),
234
+ // sanitizedKeys: Object.keys(sanitizedBody)
235
+ // });
236
+ // }
237
+
238
+ // next();
239
+ // } catch (err: any) {
240
+ // logger.error("❌ Sanitizer middleware failed", {
241
+ // error: err?.message
242
+ // });
243
+ // next(new SanitizerError("Sanitizer middleware failure"));
244
+ // }
245
+ // };
246
+ // }
247
+ // }
248
+
249
+
250
+
251
+ // src/managers/SanitizerManager.ts - COMPLETE FIXED
252
+ import { SanitizerError } from "../core/errors/SanitizerError.js";
253
+ import { logger } from "../logging";
254
+
255
+ interface SanitizerAdapter {
256
+ sanitize: (value: string, options?: any) => string;
257
+ }
258
+
259
+ export class SanitizerManager {
260
+ private primary: SanitizerAdapter;
261
+ private fallback: SanitizerAdapter | null;
262
+
263
+ constructor(primary: SanitizerAdapter, fallback: SanitizerAdapter | null = null) {
264
+ this.primary = primary;
265
+ this.fallback = fallback;
266
+ }
267
+
268
+ /**
269
+ * Sanitize a single value (public API)
270
+ */
271
+ sanitize(value: string, options?: any): string {
272
+ // Don't process non-strings
273
+ if (typeof value !== 'string') {
274
+ return value;
275
+ }
276
+
277
+ try {
278
+ return this.primary.sanitize(value, options);
279
+ } catch (err: any) {
280
+ logger.warn("⚠ Primary sanitizer failed", { error: err?.message });
281
+
282
+ if (!this.fallback) {
283
+ throw new SanitizerError("Primary sanitizer failed and no fallback available.");
284
+ }
285
+
286
+ logger.info("📌 Using fallback sanitizer");
287
+ return this.fallback.sanitize(value, options);
288
+ }
289
+ }
290
+
291
+ /**
292
+ * Middleware - Per-request fallback logic
293
+ */
294
+ middleware(options?: any) {
295
+ return (req: any, _res: any, next: any) => {
296
+ let fallbackTriggered = false;
297
+
298
+ // Helper function with per-request fallback logic
299
+ const safeSanitize = (value: string): string => {
300
+ if (fallbackTriggered && this.fallback) {
301
+ return this.fallback.sanitize(value, options);
302
+ }
303
+
304
+ try {
305
+ return this.primary.sanitize(value, options);
306
+ } catch (err: any) {
307
+ if (!this.fallback) {
308
+ throw err;
309
+ }
310
+
311
+ fallbackTriggered = true;
312
+ logger.warn("⚠ Switching to fallback sanitizer for this request");
313
+ return this.fallback.sanitize(value, options);
314
+ }
315
+ };
316
+
317
+ try {
318
+ // Create a sanitized copy of body instead of mutating
319
+ if (req.body && typeof req.body === "object") {
320
+ const originalBody = req.body;
321
+ const sanitizedBody: any = Array.isArray(originalBody) ? [] : {};
322
+
323
+ for (const key of Object.keys(originalBody)) {
324
+ const value = originalBody[key];
325
+
326
+ if (typeof value === "string") {
327
+ sanitizedBody[key] = safeSanitize(value);
328
+ } else if (Array.isArray(value)) {
329
+ sanitizedBody[key] = value.map(item =>
330
+ typeof item === "string" ? safeSanitize(item) : item
331
+ );
332
+ } else if (value && typeof value === "object") {
333
+ // Recursive sanitization for nested objects (optional)
334
+ sanitizedBody[key] = value; // Keep as-is for now
335
+ } else {
336
+ sanitizedBody[key] = value;
337
+ }
338
+ }
339
+
340
+ // Store sanitized version separately
341
+ req.sanitizedBody = sanitizedBody;
342
+
343
+ logger.debug("🧼 Request body sanitized", {
344
+ originalKeys: Object.keys(originalBody),
345
+ sanitizedKeys: Object.keys(sanitizedBody),
346
+ usedFallback: fallbackTriggered
347
+ });
348
+ }
349
+
350
+ next();
351
+ } catch (err: any) {
352
+ logger.error("❌ Sanitizer middleware failed", {
353
+ error: err?.message
354
+ });
355
+ next(new SanitizerError("Sanitizer middleware failure"));
356
+ }
357
+ };
358
+ }
359
+ }
@@ -0,0 +1,269 @@
1
+ // // // import { HiSecureConfig } from "../core/config";
2
+ // // // import { logger } from "../logging";
3
+ // // // import { ValidationError } from "../core/errors/ValidationError";
4
+
5
+ // // // export class ValidatorManager {
6
+ // // // private config: HiSecureConfig["validation"];
7
+ // // // private primaryAdapter: any;
8
+ // // // private fallbackAdapter: any;
9
+
10
+ // // // constructor(
11
+ // // // config: HiSecureConfig["validation"],
12
+ // // // primaryAdapter: any,
13
+ // // // fallbackAdapter: any
14
+ // // // ) {
15
+ // // // this.config = config;
16
+ // // // this.primaryAdapter = primaryAdapter;
17
+ // // // this.fallbackAdapter = fallbackAdapter;
18
+ // // // }
19
+
20
+ // // // /**
21
+ // // // * Validate request body using primary adapter (Zod/express-validator).
22
+ // // // * Fallback is only used if the adapter implementation itself throws.
23
+ // // // */
24
+ // // // validate(schema: any) {
25
+ // // // return (req: any, res: any, next: any) => {
26
+ // // // try {
27
+ // // // const middleware = this.primaryAdapter.validate(schema);
28
+ // // // return middleware(req, res, next);
29
+
30
+ // // // } catch (err: any) {
31
+ // // // logger.warn("⚠ Primary validator failed", {
32
+ // // // error: err?.message,
33
+ // // // path: req.path,
34
+ // // // method: req.method
35
+ // // // });
36
+
37
+ // // // if (!this.fallbackAdapter) {
38
+ // // // return next(new ValidationError("Validation failed."));
39
+ // // // }
40
+
41
+ // // // try {
42
+ // // // logger.info("📌 Using fallback validator");
43
+ // // // const fallbackMiddleware = this.fallbackAdapter.validate(schema);
44
+ // // // return fallbackMiddleware(req, res, next);
45
+
46
+ // // // } catch (fallbackErr: any) {
47
+ // // // logger.error("❌ Fallback validation also failed", {
48
+ // // // error: fallbackErr?.message
49
+ // // // });
50
+
51
+ // // // return next(new ValidationError("Both validators failed."));
52
+ // // // }
53
+ // // // }
54
+ // // // };
55
+ // // // }
56
+ // // // }
57
+
58
+
59
+
60
+ // // import { HiSecureConfig } from "../core/config.js";
61
+ // // import { logger } from "../logging";
62
+ // // import { ValidationError } from "../core/errors/ValidationError.js";
63
+
64
+ // // interface ValidatorAdapter {
65
+ // // validate: (schema?: any) => any;
66
+ // // }
67
+
68
+ // // export class ValidatorManager {
69
+ // // private config: HiSecureConfig["validation"];
70
+ // // private primaryAdapter: ValidatorAdapter;
71
+ // // private fallbackAdapter: ValidatorAdapter | null;
72
+
73
+ // // constructor(
74
+ // // config: HiSecureConfig["validation"],
75
+ // // primaryAdapter: ValidatorAdapter,
76
+ // // fallbackAdapter: ValidatorAdapter | null
77
+ // // ) {
78
+ // // this.config = config;
79
+ // // this.primaryAdapter = primaryAdapter;
80
+ // // this.fallbackAdapter = fallbackAdapter;
81
+ // // }
82
+
83
+ // // /**
84
+ // // * MAIN DYNAMIC VALIDATOR ENTRY
85
+ // // * schema = per-route schema
86
+ // // * If schema is undefined → use global schema
87
+ // // */
88
+ // // validate(schema?: any) {
89
+ // // return (req: any, res: any, next: any) => {
90
+ // // try {
91
+ // // const middleware = this.primaryAdapter.validate(schema);
92
+ // // return middleware(req, res, next);
93
+
94
+ // // } catch (err: any) {
95
+ // // logger.warn("⚠ Primary validator failed", {
96
+ // // error: err?.message,
97
+ // // path: req.path,
98
+ // // method: req.method
99
+ // // });
100
+
101
+ // // if (!this.fallbackAdapter) {
102
+ // // return next(new ValidationError("Validation failed"));
103
+ // // }
104
+
105
+ // // try {
106
+ // // logger.info("📌 Using fallback validator");
107
+ // // const fallbackMiddleware = this.fallbackAdapter.validate(schema);
108
+ // // return fallbackMiddleware(req, res, next);
109
+
110
+ // // } catch (fallbackErr: any) {
111
+ // // logger.error("❌ Fallback validator also failed", {
112
+ // // error: fallbackErr?.message
113
+ // // });
114
+
115
+ // // return next(new ValidationError("Both validators failed"));
116
+ // // }
117
+ // // }
118
+ // // };
119
+ // // }
120
+ // // }
121
+
122
+
123
+
124
+
125
+
126
+ // // src/managers/ValidatorManager.ts - FIXED
127
+ // import { logger } from "../logging";
128
+ // import { ValidationError } from "../core/errors/ValidationError.js";
129
+ // import { HiSecureConfig } from "../core/types/HiSecureConfig";
130
+
131
+ // interface ValidatorAdapter {
132
+ // validate: (schema?: any) => any;
133
+ // }
134
+
135
+ // export class ValidatorManager {
136
+ // private config: HiSecureConfig["validation"];
137
+ // private primaryAdapter: ValidatorAdapter;
138
+ // private fallbackAdapter: ValidatorAdapter | null;
139
+
140
+ // constructor(
141
+ // config: HiSecureConfig["validation"],
142
+ // primaryAdapter: ValidatorAdapter,
143
+ // fallbackAdapter: ValidatorAdapter | null
144
+ // ) {
145
+ // this.config = config;
146
+ // this.primaryAdapter = primaryAdapter;
147
+ // this.fallbackAdapter = fallbackAdapter;
148
+ // }
149
+
150
+ // validate(schema?: any) {
151
+ // return (req: any, res: any, next: any) => {
152
+ // // Execute primary adapter middleware
153
+ // const primaryMiddleware = this.primaryAdapter.validate(schema);
154
+
155
+ // // Run middleware and handle errors properly
156
+ // primaryMiddleware(req, res, (err?: any) => {
157
+ // if (!err) {
158
+ // return next(); // Validation passed
159
+ // }
160
+
161
+ // // If error is a ValidationError, pass it through (don't fallback!)
162
+ // if (err instanceof ValidationError) {
163
+ // logger.warn("⚠ Validation failed", {
164
+ // path: req.path,
165
+ // method: req.method,
166
+ // error: err.message
167
+ // });
168
+ // return next(err);
169
+ // }
170
+
171
+ // // Only use fallback for ADAPTER errors, not validation errors
172
+ // logger.warn("⚠ Primary validator adapter failed", {
173
+ // error: err?.message,
174
+ // path: req.path,
175
+ // method: req.method
176
+ // });
177
+
178
+ // if (!this.fallbackAdapter) {
179
+ // return next(new ValidationError("Validation system error"));
180
+ // }
181
+
182
+ // // Try fallback adapter
183
+ // const fallbackMiddleware = this.fallbackAdapter.validate(schema);
184
+ // fallbackMiddleware(req, res, (fallbackErr?: any) => {
185
+ // if (fallbackErr) {
186
+ // logger.error("❌ Fallback validator also failed", {
187
+ // error: fallbackErr?.message
188
+ // });
189
+ // return next(new ValidationError("Validation system unavailable"));
190
+ // }
191
+ // next(); // Fallback validation passed
192
+ // });
193
+ // });
194
+ // };
195
+ // }
196
+ // }
197
+
198
+
199
+ // src/managers/ValidatorManager.ts - COMPLETE FIXED
200
+ import { logger } from "../logging";
201
+ import { ValidationError } from "../core/errors/ValidationError.js";
202
+ import { HiSecureConfig } from "../core/types/HiSecureConfig.js"; // ✅ FIXED IMPORT
203
+
204
+ interface ValidatorAdapter {
205
+ validate: (schema?: any) => any;
206
+ }
207
+
208
+ export class ValidatorManager {
209
+ private config: HiSecureConfig["validation"];
210
+ private primaryAdapter: ValidatorAdapter;
211
+ private fallbackAdapter: ValidatorAdapter | null;
212
+
213
+ constructor(
214
+ config: HiSecureConfig["validation"],
215
+ primaryAdapter: ValidatorAdapter,
216
+ fallbackAdapter: ValidatorAdapter | null
217
+ ) {
218
+ this.config = config;
219
+ this.primaryAdapter = primaryAdapter;
220
+ this.fallbackAdapter = fallbackAdapter;
221
+ }
222
+
223
+ validate(schema?: any) {
224
+ return (req: any, res: any, next: any) => {
225
+ // Execute primary adapter middleware
226
+ const primaryMiddleware = this.primaryAdapter.validate(schema);
227
+
228
+ // Run middleware and handle errors properly
229
+ primaryMiddleware(req, res, (err?: any) => {
230
+ if (!err) {
231
+ return next(); // Validation passed
232
+ }
233
+
234
+ // If error is a ValidationError, pass it through (don't fallback!)
235
+ if (err instanceof ValidationError) {
236
+ logger.warn("⚠ Validation failed", {
237
+ path: req.path,
238
+ method: req.method,
239
+ error: err.message
240
+ });
241
+ return next(err);
242
+ }
243
+
244
+ // Only use fallback for ADAPTER errors, not validation errors
245
+ logger.warn("⚠ Primary validator adapter failed", {
246
+ error: err?.message,
247
+ path: req.path,
248
+ method: req.method
249
+ });
250
+
251
+ if (!this.fallbackAdapter) {
252
+ return next(new ValidationError("Validation system error"));
253
+ }
254
+
255
+ // Try fallback adapter
256
+ const fallbackMiddleware = this.fallbackAdapter.validate(schema);
257
+ fallbackMiddleware(req, res, (fallbackErr?: any) => {
258
+ if (fallbackErr) {
259
+ logger.error("❌ Fallback validator also failed", {
260
+ error: fallbackErr?.message
261
+ });
262
+ return next(new ValidationError("Validation system unavailable"));
263
+ }
264
+ next(); // Fallback validation passed
265
+ });
266
+ });
267
+ };
268
+ }
269
+ }