hi-secure 1.0.5 → 1.0.6
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/package.json +1 -1
- package/src/core/HiSecure.ts +12 -849
- package/src/core/useSecure.ts +0 -112
- package/src/index.ts +0 -16
- package/src/managers/ValidatorManager.ts +138 -138
- package/src/utils/normalizeOptions.ts +13 -12
package/src/core/useSecure.ts
CHANGED
|
@@ -1,63 +1,3 @@
|
|
|
1
|
-
// import { normalizeOptions } from "../utils/normalizeOptions.js";
|
|
2
|
-
// import { HiSecure } from "./HiSecure.js";
|
|
3
|
-
|
|
4
|
-
// export function useSecure(engine: HiSecure, input?: any) {
|
|
5
|
-
// if (!engine.isInitialized()) {
|
|
6
|
-
// throw new Error("HiSecure must be initialized before using .use()");
|
|
7
|
-
// }
|
|
8
|
-
|
|
9
|
-
// const options = normalizeOptions(input);
|
|
10
|
-
// const chain: any[] = [];
|
|
11
|
-
|
|
12
|
-
// // JSON
|
|
13
|
-
// if (options.json.enabled) {
|
|
14
|
-
// chain.push(engine.jsonManager.middleware(options.json.options));
|
|
15
|
-
// chain.push(engine.jsonManager.urlencoded());
|
|
16
|
-
// }
|
|
17
|
-
|
|
18
|
-
// // CORS
|
|
19
|
-
// if (options.cors.enabled) {
|
|
20
|
-
// chain.push(engine.corsManager.middleware(options.cors.options));
|
|
21
|
-
// }
|
|
22
|
-
|
|
23
|
-
// // Sanitize
|
|
24
|
-
// if (options.sanitize.enabled) {
|
|
25
|
-
// chain.push(engine.sanitizerManager.middleware());
|
|
26
|
-
// }
|
|
27
|
-
|
|
28
|
-
// // Validate
|
|
29
|
-
// if (options.validate.enabled && options.validate.schema) {
|
|
30
|
-
// chain.push(engine.validatorManager.validate(options.validate.schema));
|
|
31
|
-
// }
|
|
32
|
-
|
|
33
|
-
// // Rate Limit
|
|
34
|
-
// if (options.rateLimit.enabled) {
|
|
35
|
-
// chain.push(
|
|
36
|
-
// engine.rateLimitManager.middleware({
|
|
37
|
-
// mode: options.rateLimit.mode ?? undefined,
|
|
38
|
-
// options: options.rateLimit.options ?? undefined
|
|
39
|
-
// })
|
|
40
|
-
// );
|
|
41
|
-
// }
|
|
42
|
-
|
|
43
|
-
// // AUTH
|
|
44
|
-
// if (options.auth.enabled) {
|
|
45
|
-
// if (!engine.authManager) {
|
|
46
|
-
// throw new Error("AuthManager not initialized. Enable auth in config.");
|
|
47
|
-
// }
|
|
48
|
-
|
|
49
|
-
// chain.push(
|
|
50
|
-
// engine.authManager.protect({
|
|
51
|
-
// required: options.auth.required
|
|
52
|
-
// })
|
|
53
|
-
// );
|
|
54
|
-
// }
|
|
55
|
-
|
|
56
|
-
// return chain;
|
|
57
|
-
// }
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
1
|
// src/core/useSecure.ts - SIMPLER VERSION
|
|
62
2
|
// This is now optional since HiSecure class has fluent API
|
|
63
3
|
|
|
@@ -112,55 +52,3 @@ export function secureRoute(options?: SecureOptions) {
|
|
|
112
52
|
}
|
|
113
53
|
|
|
114
54
|
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
// import { HiSecure } from "./HiSecure.js";
|
|
118
|
-
// import { SecureOptions } from "./types/SecureOptions.js";
|
|
119
|
-
|
|
120
|
-
// export function secureRoute(options?: SecureOptions) {
|
|
121
|
-
// if (!options) return [];
|
|
122
|
-
|
|
123
|
-
// const chain: any[] = [];
|
|
124
|
-
|
|
125
|
-
// // 🔥 1. CORS
|
|
126
|
-
// if (options.cors !== undefined) {
|
|
127
|
-
// chain.push(
|
|
128
|
-
// HiSecure.cors(typeof options.cors === "object" ? options.cors : undefined)
|
|
129
|
-
// );
|
|
130
|
-
// }
|
|
131
|
-
|
|
132
|
-
// // 🔥 2. Rate Limiting (auto strict / relaxed detection)
|
|
133
|
-
// if (options.rateLimit !== undefined) {
|
|
134
|
-
// const rl = options.rateLimit;
|
|
135
|
-
// if (rl === "strict" || rl === "relaxed") {
|
|
136
|
-
// chain.push(HiSecure.rateLimit(rl));
|
|
137
|
-
// } else if (typeof rl === "object") {
|
|
138
|
-
// chain.push(HiSecure.rateLimit(rl));
|
|
139
|
-
// } else {
|
|
140
|
-
// chain.push(HiSecure.rateLimit("relaxed"));
|
|
141
|
-
// }
|
|
142
|
-
// }
|
|
143
|
-
|
|
144
|
-
// // 🔥 3. Sanitization
|
|
145
|
-
// if (options.sanitize !== undefined) {
|
|
146
|
-
// chain.push(
|
|
147
|
-
// HiSecure.sanitize(typeof options.sanitize === "object" ? options.sanitize : undefined)
|
|
148
|
-
// );
|
|
149
|
-
// }
|
|
150
|
-
|
|
151
|
-
// // 🔥 4. Validation — smart auto-detection
|
|
152
|
-
// if (options.validate) {
|
|
153
|
-
// chain.push(HiSecure.validate(options.validate));
|
|
154
|
-
// }
|
|
155
|
-
|
|
156
|
-
// // 🔥 5. Auth (roles included)
|
|
157
|
-
// if (options.auth) {
|
|
158
|
-
// chain.push(
|
|
159
|
-
// HiSecure.auth(
|
|
160
|
-
// typeof options.auth === "object" ? options.auth : undefined
|
|
161
|
-
// )
|
|
162
|
-
// );
|
|
163
|
-
// }
|
|
164
|
-
|
|
165
|
-
// return chain;
|
|
166
|
-
// }
|
package/src/index.ts
CHANGED
|
@@ -2,10 +2,8 @@
|
|
|
2
2
|
import { HiSecure } from "./core/HiSecure.js";
|
|
3
3
|
import { useSecure, secureRoute } from "./core/useSecure.js";
|
|
4
4
|
|
|
5
|
-
// Export the singleton instance for quick usage
|
|
6
5
|
const hiSecure = HiSecure.getInstance();
|
|
7
6
|
|
|
8
|
-
// Export everything
|
|
9
7
|
export {
|
|
10
8
|
HiSecure, // Class for advanced usage
|
|
11
9
|
hiSecure, // Singleton instance
|
|
@@ -13,21 +11,7 @@ export {
|
|
|
13
11
|
secureRoute // Route-level security helper
|
|
14
12
|
};
|
|
15
13
|
|
|
16
|
-
// Default export is the singleton instance
|
|
17
14
|
export default hiSecure;
|
|
18
15
|
|
|
19
16
|
|
|
20
17
|
|
|
21
|
-
|
|
22
|
-
// // src/index.ts
|
|
23
|
-
// import { HiSecure } from "./core/HiSecure.js";
|
|
24
|
-
// import { secureRoute } from "./core/useSecure.js"; // Only if kept
|
|
25
|
-
|
|
26
|
-
// // DON'T auto-init here
|
|
27
|
-
// export {
|
|
28
|
-
// HiSecure, // Class
|
|
29
|
-
// secureRoute // Optional sugar API
|
|
30
|
-
// };
|
|
31
|
-
|
|
32
|
-
// // Default export: class itself (NOT instance)
|
|
33
|
-
// export default HiSecure;
|
|
@@ -1,74 +1,74 @@
|
|
|
1
|
-
//
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
// interface ValidatorAdapter {
|
|
7
|
-
// validate: (schema?: any) => any;
|
|
8
|
-
// }
|
|
1
|
+
// src/managers/ValidatorManager.ts - COMPLETE FIXED
|
|
2
|
+
import { logger } from "../logging";
|
|
3
|
+
import { ValidationError } from "../core/errors/ValidationError.js";
|
|
4
|
+
import { HiSecureConfig } from "../core/types/HiSecureConfig.js"; // ✅ FIXED IMPORT
|
|
9
5
|
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
// private fallbackAdapter: ValidatorAdapter | null;
|
|
6
|
+
interface ValidatorAdapter {
|
|
7
|
+
validate: (schema?: any) => any;
|
|
8
|
+
}
|
|
14
9
|
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
10
|
+
export class ValidatorManager {
|
|
11
|
+
private config: HiSecureConfig["validation"];
|
|
12
|
+
private primaryAdapter: ValidatorAdapter;
|
|
13
|
+
private fallbackAdapter: ValidatorAdapter | null;
|
|
14
|
+
|
|
15
|
+
constructor(
|
|
16
|
+
config: HiSecureConfig["validation"],
|
|
17
|
+
primaryAdapter: ValidatorAdapter,
|
|
18
|
+
fallbackAdapter: ValidatorAdapter | null
|
|
19
|
+
) {
|
|
20
|
+
this.config = config;
|
|
21
|
+
this.primaryAdapter = primaryAdapter;
|
|
22
|
+
this.fallbackAdapter = fallbackAdapter;
|
|
23
|
+
}
|
|
24
24
|
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
//
|
|
28
|
-
|
|
25
|
+
validate(schema?: any) {
|
|
26
|
+
return (req: any, res: any, next: any) => {
|
|
27
|
+
// Execute primary adapter middleware
|
|
28
|
+
const primaryMiddleware = this.primaryAdapter.validate(schema);
|
|
29
29
|
|
|
30
|
-
//
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
30
|
+
// Run middleware and handle errors properly
|
|
31
|
+
primaryMiddleware(req, res, (err?: any) => {
|
|
32
|
+
if (!err) {
|
|
33
|
+
return next(); // Validation passed
|
|
34
|
+
}
|
|
35
35
|
|
|
36
|
-
//
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
36
|
+
// If error is a ValidationError, pass it through (don't fallback!)
|
|
37
|
+
if (err instanceof ValidationError) {
|
|
38
|
+
logger.warn("⚠ Validation failed", {
|
|
39
|
+
path: req.path,
|
|
40
|
+
method: req.method,
|
|
41
|
+
error: err.message
|
|
42
|
+
});
|
|
43
|
+
return next(err);
|
|
44
|
+
}
|
|
45
45
|
|
|
46
|
-
//
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
// if (!this.fallbackAdapter) {
|
|
54
|
-
// return next(new ValidationError("Validation system error"));
|
|
55
|
-
// }
|
|
46
|
+
// Only use fallback for ADAPTER errors, not validation errors
|
|
47
|
+
logger.warn("⚠ Primary validator adapter failed", {
|
|
48
|
+
error: err?.message,
|
|
49
|
+
path: req.path,
|
|
50
|
+
method: req.method
|
|
51
|
+
});
|
|
56
52
|
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
//
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
//
|
|
71
|
-
|
|
53
|
+
if (!this.fallbackAdapter) {
|
|
54
|
+
return next(new ValidationError("Validation system error"));
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
// Try fallback adapter
|
|
58
|
+
const fallbackMiddleware = this.fallbackAdapter.validate(schema);
|
|
59
|
+
fallbackMiddleware(req, res, (fallbackErr?: any) => {
|
|
60
|
+
if (fallbackErr) {
|
|
61
|
+
logger.error("❌ Fallback validator also failed", {
|
|
62
|
+
error: fallbackErr?.message
|
|
63
|
+
});
|
|
64
|
+
return next(new ValidationError("Validation system unavailable"));
|
|
65
|
+
}
|
|
66
|
+
next(); // Fallback validation passed
|
|
67
|
+
});
|
|
68
|
+
});
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
72
|
|
|
73
73
|
|
|
74
74
|
|
|
@@ -130,78 +130,78 @@
|
|
|
130
130
|
|
|
131
131
|
|
|
132
132
|
|
|
133
|
-
// src/managers/ValidatorManager.ts
|
|
134
|
-
import { logger } from "../logging";
|
|
135
|
-
import { ValidationError } from "../core/errors/ValidationError.js";
|
|
136
|
-
|
|
137
|
-
interface ValidatorAdapter {
|
|
138
|
-
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
export class ValidatorManager {
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
}
|
|
133
|
+
// // // src/managers/ValidatorManager.ts
|
|
134
|
+
// // import { logger } from "../logging";
|
|
135
|
+
// // import { ValidationError } from "../core/errors/ValidationError.js";
|
|
136
|
+
|
|
137
|
+
// // interface ValidatorAdapter {
|
|
138
|
+
// // validate: (schema?: any) => any;
|
|
139
|
+
// // }
|
|
140
|
+
|
|
141
|
+
// // export class ValidatorManager {
|
|
142
|
+
// // private zodAdapter: ValidatorAdapter;
|
|
143
|
+
// // private expressAdapter: ValidatorAdapter;
|
|
144
|
+
|
|
145
|
+
// // constructor(zodAdapter: ValidatorAdapter, expressAdapter: ValidatorAdapter) {
|
|
146
|
+
// // this.zodAdapter = zodAdapter;
|
|
147
|
+
// // this.expressAdapter = expressAdapter;
|
|
148
|
+
// // }
|
|
149
|
+
|
|
150
|
+
// // validate(schema?: any) {
|
|
151
|
+
// // // const isZod = schema && typeof schema.safeParse === "function";
|
|
152
|
+
// // const isZod =
|
|
153
|
+
// // schema &&
|
|
154
|
+
// // typeof schema === "object" &&
|
|
155
|
+
// // typeof schema._def === "object" &&
|
|
156
|
+
// // typeof schema.safeParse === "function";
|
|
157
|
+
|
|
158
|
+
// // const isExpressValidator = Array.isArray(schema);
|
|
159
|
+
|
|
160
|
+
// // return (req: any, res: any, next: any) => {
|
|
161
|
+
// // let middleware;
|
|
162
|
+
|
|
163
|
+
// // if (isZod) {
|
|
164
|
+
// // logger.debug("📌 Using Zod adapter");
|
|
165
|
+
// // middleware = this.zodAdapter.validate(schema);
|
|
166
|
+
// // }
|
|
167
|
+
// // else if (isExpressValidator) {
|
|
168
|
+
// // logger.debug("📌 Using express-validator adapter");
|
|
169
|
+
// // middleware = this.expressAdapter.validate(schema);
|
|
170
|
+
// // }
|
|
171
|
+
// // else {
|
|
172
|
+
// // return next(); // no schema found
|
|
173
|
+
// // }
|
|
174
|
+
|
|
175
|
+
// // // CASE 1 — express-validator returns ARRAY
|
|
176
|
+
// // if (Array.isArray(middleware)) {
|
|
177
|
+
// // let idx = 0;
|
|
178
|
+
|
|
179
|
+
// // const run = (err?: any) => {
|
|
180
|
+
// // if (err) return next(err);
|
|
181
|
+
|
|
182
|
+
// // const fn = middleware[idx++];
|
|
183
|
+
// // if (!fn) return next(); // done
|
|
184
|
+
|
|
185
|
+
// // try {
|
|
186
|
+
// // fn(req, res, run);
|
|
187
|
+
// // } catch (error: any) {
|
|
188
|
+
// // next(new ValidationError(error.message));
|
|
189
|
+
// // }
|
|
190
|
+
// // };
|
|
191
|
+
|
|
192
|
+
// // return run();
|
|
193
|
+
// // }
|
|
194
|
+
|
|
195
|
+
// // // CASE 2 — Zod returns SINGLE MIDDLEWARE
|
|
196
|
+
// // try {
|
|
197
|
+
// // middleware(req, res, (err?: any) => {
|
|
198
|
+
// // if (err) return next(err);
|
|
199
|
+
// // next();
|
|
200
|
+
// // });
|
|
201
|
+
// // } catch (err: any) {
|
|
202
|
+
// // next(new ValidationError(err.message));
|
|
203
|
+
// // }
|
|
204
|
+
// // };
|
|
205
|
+
// // }
|
|
206
|
+
// // }
|
|
207
207
|
|
|
@@ -218,21 +218,22 @@ function normalizeRateLimit(value: SecureOptions["rateLimit"]): NormalizedOption
|
|
|
218
218
|
}
|
|
219
219
|
|
|
220
220
|
function normalizeAuth(value: SecureOptions["auth"]): NormalizedOptions["auth"] {
|
|
221
|
-
// if (value === false) {
|
|
222
|
-
// return { enabled: false, required: false };
|
|
223
|
-
// }
|
|
224
221
|
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
222
|
+
if (value === false) {
|
|
223
|
+
return { enabled: false, required: false };
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
if (value === true || value === undefined) {
|
|
227
|
+
return { enabled: true, required: true };
|
|
228
|
+
}
|
|
228
229
|
|
|
229
230
|
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
}
|
|
233
|
-
if (value === true) {
|
|
234
|
-
|
|
235
|
-
}
|
|
231
|
+
// if (value === undefined) {
|
|
232
|
+
// return { enabled: false, required: false };
|
|
233
|
+
// }
|
|
234
|
+
// if (value === true) {
|
|
235
|
+
// return { enabled: true, required: true };
|
|
236
|
+
// }
|
|
236
237
|
|
|
237
238
|
|
|
238
239
|
const authOptions = value as AuthOptions;
|