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.
- package/dist/adapters/ArgonAdapter.d.ts +8 -0
- package/dist/adapters/ArgonAdapter.d.ts.map +1 -0
- package/dist/adapters/ArgonAdapter.js +45 -0
- package/dist/adapters/ArgonAdapter.js.map +1 -0
- package/dist/adapters/BcryptAdapter.d.ts +7 -0
- package/dist/adapters/BcryptAdapter.d.ts.map +1 -0
- package/dist/adapters/BcryptAdapter.js +48 -0
- package/dist/adapters/BcryptAdapter.js.map +1 -0
- package/dist/adapters/DomPurifyAdapter.d.ts +13 -0
- package/dist/adapters/DomPurifyAdapter.d.ts.map +1 -0
- package/dist/adapters/DomPurifyAdapter.js +61 -0
- package/dist/adapters/DomPurifyAdapter.js.map +1 -0
- package/dist/adapters/ExpressRLAdapter.d.ts +13 -0
- package/dist/adapters/ExpressRLAdapter.d.ts.map +1 -0
- package/dist/adapters/ExpressRLAdapter.js +68 -0
- package/dist/adapters/ExpressRLAdapter.js.map +1 -0
- package/dist/adapters/ExpressValidatorAdapter.d.ts +6 -0
- package/dist/adapters/ExpressValidatorAdapter.d.ts.map +1 -0
- package/dist/adapters/ExpressValidatorAdapter.js +78 -0
- package/dist/adapters/ExpressValidatorAdapter.js.map +1 -0
- package/dist/adapters/GoggleAdapter.d.ts +15 -0
- package/dist/adapters/GoggleAdapter.d.ts.map +1 -0
- package/dist/adapters/GoggleAdapter.js +91 -0
- package/dist/adapters/GoggleAdapter.js.map +1 -0
- package/dist/adapters/GoogleAdapter.d.ts +15 -0
- package/dist/adapters/GoogleAdapter.d.ts.map +1 -0
- package/dist/adapters/GoogleAdapter.js +159 -0
- package/dist/adapters/GoogleAdapter.js.map +1 -0
- package/dist/adapters/JWTAdapter.d.ts +28 -0
- package/dist/adapters/JWTAdapter.d.ts.map +1 -0
- package/dist/adapters/JWTAdapter.js +276 -0
- package/dist/adapters/JWTAdapter.js.map +1 -0
- package/dist/adapters/RLFlexibleAdapter.d.ts +11 -0
- package/dist/adapters/RLFlexibleAdapter.d.ts.map +1 -0
- package/dist/adapters/RLFlexibleAdapter.js +115 -0
- package/dist/adapters/RLFlexibleAdapter.js.map +1 -0
- package/dist/adapters/SanitizeHtmlAdapter.d.ts +12 -0
- package/dist/adapters/SanitizeHtmlAdapter.d.ts.map +1 -0
- package/dist/adapters/SanitizeHtmlAdapter.js +141 -0
- package/dist/adapters/SanitizeHtmlAdapter.js.map +1 -0
- package/dist/adapters/XSSAdapter.d.ts +33 -0
- package/dist/adapters/XSSAdapter.d.ts.map +1 -0
- package/dist/adapters/XSSAdapter.js +127 -0
- package/dist/adapters/XSSAdapter.js.map +1 -0
- package/dist/adapters/ZodAdapter.d.ts +7 -0
- package/dist/adapters/ZodAdapter.d.ts.map +1 -0
- package/dist/adapters/ZodAdapter.js +39 -0
- package/dist/adapters/ZodAdapter.js.map +1 -0
- package/dist/core/HiSecure.d.ts +62 -0
- package/dist/core/HiSecure.d.ts.map +1 -0
- package/dist/core/HiSecure.js +273 -0
- package/dist/core/HiSecure.js.map +1 -0
- package/dist/core/config.d.ts +3 -0
- package/dist/core/config.d.ts.map +1 -0
- package/dist/core/config.js +53 -0
- package/dist/core/config.js.map +1 -0
- package/dist/core/constants.d.ts +37 -0
- package/dist/core/constants.d.ts.map +1 -0
- package/dist/core/constants.js +67 -0
- package/dist/core/constants.js.map +1 -0
- package/dist/core/errors/AdapterError.d.ts +5 -0
- package/dist/core/errors/AdapterError.d.ts.map +1 -0
- package/dist/core/errors/AdapterError.js +15 -0
- package/dist/core/errors/AdapterError.js.map +1 -0
- package/dist/core/errors/HttpErrror.d.ts +17 -0
- package/dist/core/errors/HttpErrror.d.ts.map +1 -0
- package/dist/core/errors/HttpErrror.js +36 -0
- package/dist/core/errors/HttpErrror.js.map +1 -0
- package/dist/core/errors/SanitizerError.d.ts +5 -0
- package/dist/core/errors/SanitizerError.d.ts.map +1 -0
- package/dist/core/errors/SanitizerError.js +14 -0
- package/dist/core/errors/SanitizerError.js.map +1 -0
- package/dist/core/errors/SecurityError.d.ts +5 -0
- package/dist/core/errors/SecurityError.d.ts.map +1 -0
- package/dist/core/errors/SecurityError.js +14 -0
- package/dist/core/errors/SecurityError.js.map +1 -0
- package/dist/core/errors/ValidationError.d.ts +5 -0
- package/dist/core/errors/ValidationError.d.ts.map +1 -0
- package/dist/core/errors/ValidationError.js +14 -0
- package/dist/core/errors/ValidationError.js.map +1 -0
- package/dist/core/types/HiSecureConfig.d.ts +47 -0
- package/dist/core/types/HiSecureConfig.d.ts.map +1 -0
- package/dist/core/types/HiSecureConfig.js +3 -0
- package/dist/core/types/HiSecureConfig.js.map +1 -0
- package/dist/core/types/SecureOptions.d.ts +30 -0
- package/dist/core/types/SecureOptions.d.ts.map +1 -0
- package/dist/core/types/SecureOptions.js +4 -0
- package/dist/core/types/SecureOptions.js.map +1 -0
- package/dist/core/useSecure.d.ts +10 -0
- package/dist/core/useSecure.d.ts.map +1 -0
- package/dist/core/useSecure.js +85 -0
- package/dist/core/useSecure.js.map +1 -0
- package/dist/examples/e1.d.ts +1 -0
- package/dist/examples/e1.d.ts.map +1 -0
- package/dist/examples/e1.js +3 -0
- package/dist/examples/e1.js.map +1 -0
- package/dist/index.d.ts +9 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +15 -0
- package/dist/index.js.map +1 -0
- package/dist/logging/index.d.ts +3 -0
- package/dist/logging/index.d.ts.map +1 -0
- package/dist/logging/index.js +19 -0
- package/dist/logging/index.js.map +1 -0
- package/dist/logging/morganSetup.d.ts +2 -0
- package/dist/logging/morganSetup.d.ts.map +1 -0
- package/dist/logging/morganSetup.js +9 -0
- package/dist/logging/morganSetup.js.map +1 -0
- package/dist/logging/winstonSetup.d.ts +6 -0
- package/dist/logging/winstonSetup.d.ts.map +1 -0
- package/dist/logging/winstonSetup.js +22 -0
- package/dist/logging/winstonSetup.js.map +1 -0
- package/dist/managers/AuthManager.d.ts +23 -0
- package/dist/managers/AuthManager.d.ts.map +1 -0
- package/dist/managers/AuthManager.js +190 -0
- package/dist/managers/AuthManager.js.map +1 -0
- package/dist/managers/CorsManager.d.ts +9 -0
- package/dist/managers/CorsManager.d.ts.map +1 -0
- package/dist/managers/CorsManager.js +55 -0
- package/dist/managers/CorsManager.js.map +1 -0
- package/dist/managers/HashManager.d.ts +22 -0
- package/dist/managers/HashManager.d.ts.map +1 -0
- package/dist/managers/HashManager.js +319 -0
- package/dist/managers/HashManager.js.map +1 -0
- package/dist/managers/JsonManager.d.ts +6 -0
- package/dist/managers/JsonManager.d.ts.map +1 -0
- package/dist/managers/JsonManager.js +142 -0
- package/dist/managers/JsonManager.js.map +1 -0
- package/dist/managers/RateLimitManager.d.ts +16 -0
- package/dist/managers/RateLimitManager.d.ts.map +1 -0
- package/dist/managers/RateLimitManager.js +108 -0
- package/dist/managers/RateLimitManager.js.map +1 -0
- package/dist/managers/SanitizerManager.d.ts +18 -0
- package/dist/managers/SanitizerManager.d.ts.map +1 -0
- package/dist/managers/SanitizerManager.js +296 -0
- package/dist/managers/SanitizerManager.js.map +1 -0
- package/dist/managers/ValidatorManager.d.ts +13 -0
- package/dist/managers/ValidatorManager.d.ts.map +1 -0
- package/dist/managers/ValidatorManager.js +218 -0
- package/dist/managers/ValidatorManager.js.map +1 -0
- package/dist/middlewares/errorHandler.d.ts +3 -0
- package/dist/middlewares/errorHandler.d.ts.map +1 -0
- package/dist/middlewares/errorHandler.js +94 -0
- package/dist/middlewares/errorHandler.js.map +1 -0
- package/dist/middlewares/index.d.ts +3 -0
- package/dist/middlewares/index.d.ts.map +1 -0
- package/dist/middlewares/index.js +19 -0
- package/dist/middlewares/index.js.map +1 -0
- package/dist/middlewares/requestLogger.d.ts +2 -0
- package/dist/middlewares/requestLogger.d.ts.map +1 -0
- package/dist/middlewares/requestLogger.js +8 -0
- package/dist/middlewares/requestLogger.js.map +1 -0
- package/dist/test/t1.d.ts +1 -0
- package/dist/test/t1.d.ts.map +1 -0
- package/dist/test/t1.js +3 -0
- package/dist/test/t1.js.map +1 -0
- package/dist/utils/deepFreeze.d.ts +2 -0
- package/dist/utils/deepFreeze.d.ts.map +1 -0
- package/dist/utils/deepFreeze.js +69 -0
- package/dist/utils/deepFreeze.js.map +1 -0
- package/dist/utils/deepMerge.d.ts +5 -0
- package/dist/utils/deepMerge.d.ts.map +1 -0
- package/dist/utils/deepMerge.js +68 -0
- package/dist/utils/deepMerge.js.map +1 -0
- package/dist/utils/normalizeOptions.d.ts +38 -0
- package/dist/utils/normalizeOptions.d.ts.map +1 -0
- package/dist/utils/normalizeOptions.js +119 -0
- package/dist/utils/normalizeOptions.js.map +1 -0
- package/package.json +50 -0
- package/src/adapters/ArgonAdapter.ts +41 -0
- package/src/adapters/BcryptAdapter.ts +49 -0
- package/src/adapters/ExpressRLAdapter.ts +84 -0
- package/src/adapters/ExpressValidatorAdapter.ts +99 -0
- package/src/adapters/GoogleAdapter.ts +206 -0
- package/src/adapters/JWTAdapter.ts +346 -0
- package/src/adapters/RLFlexibleAdapter.ts +139 -0
- package/src/adapters/SanitizeHtmlAdapter.ts +162 -0
- package/src/adapters/XSSAdapter.ts +153 -0
- package/src/adapters/ZodAdapter.ts +91 -0
- package/src/core/HiSecure.ts +955 -0
- package/src/core/config.ts +156 -0
- package/src/core/constants.ts +73 -0
- package/src/core/errors/AdapterError.ts +14 -0
- package/src/core/errors/HttpErrror.ts +46 -0
- package/src/core/errors/SanitizerError.ts +13 -0
- package/src/core/errors/SecurityError.ts +13 -0
- package/src/core/errors/ValidationError.ts +13 -0
- package/src/core/types/HiSecureConfig.ts +62 -0
- package/src/core/types/SecureOptions.ts +61 -0
- package/src/core/useSecure.ts +111 -0
- package/src/examples/e1.ts +1 -0
- package/src/index.ts +17 -0
- package/src/logging/index.ts +2 -0
- package/src/logging/morganSetup.ts +3 -0
- package/src/logging/winstonSetup.ts +17 -0
- package/src/managers/AuthManager.ts +237 -0
- package/src/managers/CorsManager.ts +58 -0
- package/src/managers/HashManager.ts +390 -0
- package/src/managers/JsonManager.ts +149 -0
- package/src/managers/RateLimitManager.ts +368 -0
- package/src/managers/SanitizerManager.ts +359 -0
- package/src/managers/ValidatorManager.ts +269 -0
- package/src/middlewares/errorHandler.ts +265 -0
- package/src/middlewares/index.ts +2 -0
- package/src/middlewares/requestLogger.ts +5 -0
- package/src/test/t1.ts +1 -0
- package/src/utils/deepFreeze.ts +76 -0
- package/src/utils/deepMerge.ts +87 -0
- package/src/utils/normalizeOptions.ts +265 -0
- package/tsconfig.json +30 -0
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
// // import express from "express";
|
|
2
|
+
// // import { logger } from "../logging";
|
|
3
|
+
// // import { AdapterError } from "../core/errors/AdapterError";
|
|
4
|
+
|
|
5
|
+
// // export class JsonManager {
|
|
6
|
+
|
|
7
|
+
// // /**
|
|
8
|
+
// // * JSON parser middleware — global + dynamic override
|
|
9
|
+
// // */
|
|
10
|
+
// // middleware(options?: any) {
|
|
11
|
+
// // try {
|
|
12
|
+
// // const opts = options || {};
|
|
13
|
+
// // return express.json(opts);
|
|
14
|
+
// // } catch (err: any) {
|
|
15
|
+
// // logger.error("❌ JSON Manager: failed to create JSON parser", {
|
|
16
|
+
// // error: err?.message || err
|
|
17
|
+
// // });
|
|
18
|
+
// // throw new AdapterError("JSON parser initialization failed.");
|
|
19
|
+
// // }
|
|
20
|
+
// // }
|
|
21
|
+
|
|
22
|
+
// // /**
|
|
23
|
+
// // * URL-encoded parser — same global + dynamic style
|
|
24
|
+
// // */
|
|
25
|
+
// // urlencoded(options?: any) {
|
|
26
|
+
// // try {
|
|
27
|
+
// // const opts = options || { extended: true };
|
|
28
|
+
// // return express.urlencoded(opts);
|
|
29
|
+
// // } catch (err: any) {
|
|
30
|
+
// // logger.error("❌ JSON Manager: failed to create urlencoded parser", {
|
|
31
|
+
// // error: err?.message || err
|
|
32
|
+
// // });
|
|
33
|
+
// // throw new AdapterError("URL-encoded parser initialization failed.");
|
|
34
|
+
// // }
|
|
35
|
+
// // }
|
|
36
|
+
// // }
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
// import express from "express";
|
|
41
|
+
// import qs from "qs";
|
|
42
|
+
// import { logger } from "../logging";
|
|
43
|
+
// import { AdapterError } from "../core/errors/AdapterError.js";
|
|
44
|
+
|
|
45
|
+
// export class JsonManager {
|
|
46
|
+
|
|
47
|
+
// // JSON parser
|
|
48
|
+
// middleware(options?: any) {
|
|
49
|
+
// try {
|
|
50
|
+
// return express.json(options || {});
|
|
51
|
+
// } catch (err: any) {
|
|
52
|
+
// logger.error("❌ JSON Manager: failed to create JSON parser");
|
|
53
|
+
// throw new AdapterError("JSON parser initialization failed.");
|
|
54
|
+
// }
|
|
55
|
+
// }
|
|
56
|
+
|
|
57
|
+
// // URL-encoded parser
|
|
58
|
+
// urlencoded(options?: any) {
|
|
59
|
+
// try {
|
|
60
|
+
// const opts = options || { extended: true };
|
|
61
|
+
// return express.urlencoded(opts);
|
|
62
|
+
// } catch (err: any) {
|
|
63
|
+
// logger.error("❌ URL-encoded parser failed");
|
|
64
|
+
// throw new AdapterError("URL-encoded parser initialization failed.");
|
|
65
|
+
// }
|
|
66
|
+
// }
|
|
67
|
+
|
|
68
|
+
// // NEW: Query-string parser
|
|
69
|
+
// queryParser() {
|
|
70
|
+
// return (req: any, res: any, next: any) => {
|
|
71
|
+
// try {
|
|
72
|
+
// req.query = qs.parse(req.url.split("?")[1] || "");
|
|
73
|
+
// } catch (err: any) {
|
|
74
|
+
// logger.error("❌ Failed to parse query", { error: err?.message });
|
|
75
|
+
// throw new AdapterError("Query parsing failed.");
|
|
76
|
+
// }
|
|
77
|
+
// next();
|
|
78
|
+
// };
|
|
79
|
+
// }
|
|
80
|
+
// }
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
// src/managers/JsonManager.ts - FIXED
|
|
86
|
+
import express from "express";
|
|
87
|
+
import qs from "qs";
|
|
88
|
+
import { logger } from "../logging";
|
|
89
|
+
import { AdapterError } from "../core/errors/AdapterError.js";
|
|
90
|
+
|
|
91
|
+
export class JsonManager {
|
|
92
|
+
// JSON parser
|
|
93
|
+
middleware(options?: any) {
|
|
94
|
+
try {
|
|
95
|
+
const defaultOptions = {
|
|
96
|
+
limit: '1mb',
|
|
97
|
+
inflate: true,
|
|
98
|
+
strict: true
|
|
99
|
+
};
|
|
100
|
+
return express.json({ ...defaultOptions, ...(options || {}) });
|
|
101
|
+
} catch (err: any) {
|
|
102
|
+
logger.error("❌ JSON Manager: failed to create JSON parser");
|
|
103
|
+
throw new AdapterError("JSON parser initialization failed.");
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
// URL-encoded parser
|
|
108
|
+
urlencoded(options?: any) {
|
|
109
|
+
try {
|
|
110
|
+
const defaultOptions = {
|
|
111
|
+
extended: true,
|
|
112
|
+
limit: '1mb',
|
|
113
|
+
parameterLimit: 1000
|
|
114
|
+
};
|
|
115
|
+
const opts = { ...defaultOptions, ...(options || {}) };
|
|
116
|
+
return express.urlencoded(opts);
|
|
117
|
+
} catch (err: any) {
|
|
118
|
+
logger.error("❌ URL-encoded parser failed");
|
|
119
|
+
throw new AdapterError("URL-encoded parser initialization failed.");
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
// Query-string parser (doesn't override Express's query)
|
|
124
|
+
queryParser(options?: any) {
|
|
125
|
+
return (req: any, res: any, next: any) => {
|
|
126
|
+
try {
|
|
127
|
+
// Only parse if not already parsed by Express
|
|
128
|
+
if (!req.parsedQuery && req.url.includes('?')) {
|
|
129
|
+
const queryString = req.url.split("?")[1] || "";
|
|
130
|
+
const parsed = qs.parse(queryString, {
|
|
131
|
+
depth: 5, // Prevent deep nesting attacks
|
|
132
|
+
parameterLimit: 100,
|
|
133
|
+
...options
|
|
134
|
+
});
|
|
135
|
+
|
|
136
|
+
// Store separately, don't override req.query
|
|
137
|
+
req.parsedQuery = parsed;
|
|
138
|
+
logger.debug("🔍 Query parsed", {
|
|
139
|
+
keys: Object.keys(parsed)
|
|
140
|
+
});
|
|
141
|
+
}
|
|
142
|
+
next();
|
|
143
|
+
} catch (err: any) {
|
|
144
|
+
logger.error("❌ Failed to parse query", { error: err?.message });
|
|
145
|
+
next(new AdapterError("Query parsing failed."));
|
|
146
|
+
}
|
|
147
|
+
};
|
|
148
|
+
}
|
|
149
|
+
}
|
|
@@ -0,0 +1,368 @@
|
|
|
1
|
+
|
|
2
|
+
|
|
3
|
+
// // // src/managers/RateLimitManager.ts - COMPLETE FIXED
|
|
4
|
+
// // import { HiSecureConfig } from "../core/types/HiSecureConfig.js";
|
|
5
|
+
// // import { AdapterError } from "../core/errors/AdapterError.js";
|
|
6
|
+
// // import { logger } from "../logging";
|
|
7
|
+
|
|
8
|
+
// // interface RateLimiterAdapter {
|
|
9
|
+
// // getMiddleware: (options?: any) => any;
|
|
10
|
+
// // }
|
|
11
|
+
|
|
12
|
+
// // export class RateLimitManager {
|
|
13
|
+
// // private config: HiSecureConfig["rateLimiter"];
|
|
14
|
+
// // private primaryAdapter: RateLimiterAdapter;
|
|
15
|
+
// // private fallbackAdapter: RateLimiterAdapter | null;
|
|
16
|
+
|
|
17
|
+
// // constructor(
|
|
18
|
+
// // config: HiSecureConfig["rateLimiter"],
|
|
19
|
+
// // primaryAdapter: RateLimiterAdapter,
|
|
20
|
+
// // fallbackAdapter: RateLimiterAdapter | null
|
|
21
|
+
// // ) {
|
|
22
|
+
// // this.config = config;
|
|
23
|
+
// // this.primaryAdapter = primaryAdapter;
|
|
24
|
+
// // this.fallbackAdapter = fallbackAdapter;
|
|
25
|
+
// // }
|
|
26
|
+
|
|
27
|
+
// // middleware(opts?: { mode?: "strict" | "relaxed" | "api"; options?: any }) {
|
|
28
|
+
// // let finalOptions: any = {};
|
|
29
|
+
|
|
30
|
+
// // // Handle presets (user cannot override these)
|
|
31
|
+
// // if (opts?.mode === "strict") {
|
|
32
|
+
// // finalOptions = {
|
|
33
|
+
// // windowMs: 10_000,
|
|
34
|
+
// // max: 5,
|
|
35
|
+
// // points: 5,
|
|
36
|
+
// // duration: 10,
|
|
37
|
+
// // message: "Too many requests, please slow down."
|
|
38
|
+
// // };
|
|
39
|
+
// // } else if (opts?.mode === "relaxed") {
|
|
40
|
+
// // finalOptions = {
|
|
41
|
+
// // windowMs: 60_000,
|
|
42
|
+
// // max: 100,
|
|
43
|
+
// // points: 100,
|
|
44
|
+
// // duration: 60,
|
|
45
|
+
// // message: "Rate limit exceeded."
|
|
46
|
+
// // };
|
|
47
|
+
// // } else if (opts?.mode === "api") {
|
|
48
|
+
// // finalOptions = {
|
|
49
|
+
// // windowMs: 15 * 60 * 1000, // 15 minutes
|
|
50
|
+
// // max: 100,
|
|
51
|
+
// // points: 100,
|
|
52
|
+
// // duration: 900,
|
|
53
|
+
// // message: "API rate limit exceeded."
|
|
54
|
+
// // };
|
|
55
|
+
// // } else {
|
|
56
|
+
// // // Use defaults
|
|
57
|
+
// // finalOptions = {
|
|
58
|
+
// // windowMs: this.config.windowMs,
|
|
59
|
+
// // max: this.config.maxRequests,
|
|
60
|
+
// // duration: this.config.windowMs / 1000,
|
|
61
|
+
// // points: this.config.maxRequests,
|
|
62
|
+
// // message: this.config.message
|
|
63
|
+
// // };
|
|
64
|
+
// // }
|
|
65
|
+
|
|
66
|
+
// // // Apply custom options WITHOUT overriding preset values
|
|
67
|
+
// // if (opts?.options) {
|
|
68
|
+
// // // Only allow specific overrides, not preset overrides
|
|
69
|
+
// // const allowedOverrides = ['message', 'skipFailedRequests', 'standardHeaders'];
|
|
70
|
+
// // for (const key of allowedOverrides) {
|
|
71
|
+
// // if (opts.options[key] !== undefined) {
|
|
72
|
+
// // finalOptions[key] = opts.options[key];
|
|
73
|
+
// // }
|
|
74
|
+
// // }
|
|
75
|
+
|
|
76
|
+
// // // Log if user tried to override preset
|
|
77
|
+
// // const attemptedOverrides = Object.keys(opts.options).filter(
|
|
78
|
+
// // k => !allowedOverrides.includes(k) && k !== 'mode'
|
|
79
|
+
// // );
|
|
80
|
+
// // if (attemptedOverrides.length > 0) {
|
|
81
|
+
// // logger.warn("⚠ Rate limit overrides ignored", { // ✅ FIXED: Better message
|
|
82
|
+
// // preset: opts?.mode || 'default', // ✅ FIXED: Handle undefined
|
|
83
|
+
// // ignoredOptions: attemptedOverrides
|
|
84
|
+
// // });
|
|
85
|
+
// // }
|
|
86
|
+
// // }
|
|
87
|
+
|
|
88
|
+
// // // Try primary adapter
|
|
89
|
+
// // try {
|
|
90
|
+
// // logger.info("📌 Applying rate limiting", {
|
|
91
|
+
// // mode: opts?.mode || 'default',
|
|
92
|
+
// // windowMs: finalOptions.windowMs,
|
|
93
|
+
// // max: finalOptions.max
|
|
94
|
+
// // });
|
|
95
|
+
|
|
96
|
+
// // return this.primaryAdapter.getMiddleware(finalOptions);
|
|
97
|
+
// // } catch (err: any) {
|
|
98
|
+
// // logger.warn("⚠ Primary rate limiter failed → fallback", {
|
|
99
|
+
// // error: err?.message
|
|
100
|
+
// // });
|
|
101
|
+
|
|
102
|
+
// // if (!this.fallbackAdapter) {
|
|
103
|
+
// // throw new AdapterError("Rate limiters failed; no fallback adapter.");
|
|
104
|
+
// // }
|
|
105
|
+
|
|
106
|
+
// // try {
|
|
107
|
+
// // logger.info("📌 Using fallback rate limiter");
|
|
108
|
+
// // return this.fallbackAdapter.getMiddleware(finalOptions);
|
|
109
|
+
// // } catch (fallbackErr: any) {
|
|
110
|
+
// // logger.error("❌ Fallback limiter also failed", {
|
|
111
|
+
// // error: fallbackErr?.message
|
|
112
|
+
// // });
|
|
113
|
+
// // throw new AdapterError("Both primary and fallback limiters failed.");
|
|
114
|
+
// // }
|
|
115
|
+
// // }
|
|
116
|
+
// // }
|
|
117
|
+
// // }
|
|
118
|
+
|
|
119
|
+
|
|
120
|
+
|
|
121
|
+
// // src/managers/RateLimitManager.ts - FIXED
|
|
122
|
+
// import { HiSecureConfig } from "../core/types/HiSecureConfig.js";
|
|
123
|
+
// import { AdapterError } from "../core/errors/AdapterError.js";
|
|
124
|
+
// import { logger } from "../logging";
|
|
125
|
+
|
|
126
|
+
// interface RateLimiterAdapter {
|
|
127
|
+
// getMiddleware: (options?: any) => any;
|
|
128
|
+
// }
|
|
129
|
+
|
|
130
|
+
// export class RateLimitManager {
|
|
131
|
+
// private config: HiSecureConfig["rateLimiter"];
|
|
132
|
+
// private primaryAdapter: RateLimiterAdapter;
|
|
133
|
+
// private fallbackAdapter: RateLimiterAdapter | null;
|
|
134
|
+
|
|
135
|
+
// constructor(
|
|
136
|
+
// config: HiSecureConfig["rateLimiter"],
|
|
137
|
+
// primaryAdapter: RateLimiterAdapter,
|
|
138
|
+
// fallbackAdapter: RateLimiterAdapter | null
|
|
139
|
+
// ) {
|
|
140
|
+
// this.config = config;
|
|
141
|
+
// this.primaryAdapter = primaryAdapter;
|
|
142
|
+
// this.fallbackAdapter = fallbackAdapter;
|
|
143
|
+
// }
|
|
144
|
+
|
|
145
|
+
// middleware(opts?: { mode?: "strict" | "relaxed" | "api"; options?: any }) {
|
|
146
|
+
// let finalOptions: any = {};
|
|
147
|
+
|
|
148
|
+
// // Handle presets (user cannot override these)
|
|
149
|
+
// if (opts?.mode === "strict") {
|
|
150
|
+
// finalOptions = {
|
|
151
|
+
// windowMs: 10_000,
|
|
152
|
+
// max: 5,
|
|
153
|
+
// points: 5,
|
|
154
|
+
// // ❌ REMOVED: duration: 10,
|
|
155
|
+
// message: "Too many requests, please slow down."
|
|
156
|
+
// };
|
|
157
|
+
// } else if (opts?.mode === "relaxed") {
|
|
158
|
+
// finalOptions = {
|
|
159
|
+
// windowMs: 60_000,
|
|
160
|
+
// max: 100,
|
|
161
|
+
// points: 100,
|
|
162
|
+
// // ❌ REMOVED: duration: 60,
|
|
163
|
+
// message: "Rate limit exceeded."
|
|
164
|
+
// };
|
|
165
|
+
// } else if (opts?.mode === "api") {
|
|
166
|
+
// finalOptions = {
|
|
167
|
+
// windowMs: 15 * 60 * 1000, // 15 minutes
|
|
168
|
+
// max: 100,
|
|
169
|
+
// points: 100,
|
|
170
|
+
// // ❌ REMOVED: duration: 900,
|
|
171
|
+
// message: "API rate limit exceeded."
|
|
172
|
+
// };
|
|
173
|
+
// } else {
|
|
174
|
+
// // Use defaults
|
|
175
|
+
// finalOptions = {
|
|
176
|
+
// windowMs: this.config.windowMs,
|
|
177
|
+
// max: this.config.maxRequests,
|
|
178
|
+
// // ❌ REMOVED: duration: this.config.windowMs / 1000,
|
|
179
|
+
// points: this.config.maxRequests,
|
|
180
|
+
// message: this.config.message,
|
|
181
|
+
// standardHeaders: true, // ✅ ADD
|
|
182
|
+
// legacyHeaders: false // ✅ ADD
|
|
183
|
+
// };
|
|
184
|
+
// }
|
|
185
|
+
|
|
186
|
+
// // Apply custom options WITHOUT overriding preset values
|
|
187
|
+
// if (opts?.options) {
|
|
188
|
+
// // Only allow specific overrides, not preset overrides
|
|
189
|
+
// const allowedOverrides = ['message', 'skipFailedRequests', 'standardHeaders', 'legacyHeaders'];
|
|
190
|
+
// for (const key of allowedOverrides) {
|
|
191
|
+
// if (opts.options[key] !== undefined) {
|
|
192
|
+
// finalOptions[key] = opts.options[key];
|
|
193
|
+
// }
|
|
194
|
+
// }
|
|
195
|
+
|
|
196
|
+
// // Log if user tried to override preset
|
|
197
|
+
// const attemptedOverrides = Object.keys(opts.options).filter(
|
|
198
|
+
// k => !allowedOverrides.includes(k) && k !== 'mode'
|
|
199
|
+
// );
|
|
200
|
+
// if (attemptedOverrides.length > 0) {
|
|
201
|
+
// logger.warn("⚠ Rate limit overrides ignored", {
|
|
202
|
+
// preset: opts?.mode || 'default',
|
|
203
|
+
// ignoredOptions: attemptedOverrides
|
|
204
|
+
// });
|
|
205
|
+
// }
|
|
206
|
+
// }
|
|
207
|
+
|
|
208
|
+
// // Add v8+ options if not present
|
|
209
|
+
// if (finalOptions.standardHeaders === undefined) {
|
|
210
|
+
// finalOptions.standardHeaders = true;
|
|
211
|
+
// }
|
|
212
|
+
// if (finalOptions.legacyHeaders === undefined) {
|
|
213
|
+
// finalOptions.legacyHeaders = false;
|
|
214
|
+
// }
|
|
215
|
+
|
|
216
|
+
// // Try primary adapter
|
|
217
|
+
// try {
|
|
218
|
+
// logger.info("📌 Applying rate limiting", {
|
|
219
|
+
// mode: opts?.mode || 'default',
|
|
220
|
+
// windowMs: finalOptions.windowMs,
|
|
221
|
+
// max: finalOptions.max
|
|
222
|
+
// });
|
|
223
|
+
|
|
224
|
+
// return this.primaryAdapter.getMiddleware(finalOptions);
|
|
225
|
+
// } catch (err: any) {
|
|
226
|
+
// logger.warn("⚠ Primary rate limiter failed → fallback", {
|
|
227
|
+
// error: err?.message
|
|
228
|
+
// });
|
|
229
|
+
|
|
230
|
+
// if (!this.fallbackAdapter) {
|
|
231
|
+
// throw new AdapterError("Rate limiters failed; no fallback adapter.");
|
|
232
|
+
// }
|
|
233
|
+
|
|
234
|
+
// try {
|
|
235
|
+
// logger.info("📌 Using fallback rate limiter");
|
|
236
|
+
// return this.fallbackAdapter.getMiddleware(finalOptions);
|
|
237
|
+
// } catch (fallbackErr: any) {
|
|
238
|
+
// logger.error("❌ Fallback limiter also failed", {
|
|
239
|
+
// error: fallbackErr?.message
|
|
240
|
+
// });
|
|
241
|
+
// throw new AdapterError("Both primary and fallback limiters failed.");
|
|
242
|
+
// }
|
|
243
|
+
// }
|
|
244
|
+
// }
|
|
245
|
+
// }
|
|
246
|
+
|
|
247
|
+
|
|
248
|
+
|
|
249
|
+
// src/managers/RateLimitManager.ts - COMPLETELY FIXED
|
|
250
|
+
import { HiSecureConfig } from "../core/types/HiSecureConfig.js";
|
|
251
|
+
import { AdapterError } from "../core/errors/AdapterError.js";
|
|
252
|
+
import { logger } from "../logging";
|
|
253
|
+
|
|
254
|
+
interface RateLimiterAdapter {
|
|
255
|
+
getMiddleware: (options?: any) => any;
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
export class RateLimitManager {
|
|
259
|
+
private config: HiSecureConfig["rateLimiter"];
|
|
260
|
+
private primaryAdapter: RateLimiterAdapter;
|
|
261
|
+
private fallbackAdapter: RateLimiterAdapter | null;
|
|
262
|
+
|
|
263
|
+
constructor(
|
|
264
|
+
config: HiSecureConfig["rateLimiter"],
|
|
265
|
+
primaryAdapter: RateLimiterAdapter,
|
|
266
|
+
fallbackAdapter: RateLimiterAdapter | null
|
|
267
|
+
) {
|
|
268
|
+
this.config = config;
|
|
269
|
+
this.primaryAdapter = primaryAdapter;
|
|
270
|
+
this.fallbackAdapter = fallbackAdapter;
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
middleware(opts?: { mode?: "strict" | "relaxed" | "api"; options?: any }) {
|
|
274
|
+
let finalOptions: any = {};
|
|
275
|
+
|
|
276
|
+
// Handle presets (user cannot override these)
|
|
277
|
+
if (opts?.mode === "strict") {
|
|
278
|
+
finalOptions = {
|
|
279
|
+
windowMs: 10_000,
|
|
280
|
+
max: 5,
|
|
281
|
+
// ❌ REMOVED: points: 5,
|
|
282
|
+
message: "Too many requests, please slow down."
|
|
283
|
+
};
|
|
284
|
+
} else if (opts?.mode === "relaxed") {
|
|
285
|
+
finalOptions = {
|
|
286
|
+
windowMs: 60_000,
|
|
287
|
+
max: 100,
|
|
288
|
+
// ❌ REMOVED: points: 100,
|
|
289
|
+
message: "Rate limit exceeded."
|
|
290
|
+
};
|
|
291
|
+
} else if (opts?.mode === "api") {
|
|
292
|
+
finalOptions = {
|
|
293
|
+
windowMs: 15 * 60 * 1000, // 15 minutes
|
|
294
|
+
max: 100,
|
|
295
|
+
// ❌ REMOVED: points: 100,
|
|
296
|
+
message: "API rate limit exceeded."
|
|
297
|
+
};
|
|
298
|
+
} else {
|
|
299
|
+
// Use defaults
|
|
300
|
+
finalOptions = {
|
|
301
|
+
windowMs: this.config.windowMs,
|
|
302
|
+
max: this.config.maxRequests,
|
|
303
|
+
message: this.config.message,
|
|
304
|
+
standardHeaders: true, // ✅ ADD
|
|
305
|
+
legacyHeaders: false // ✅ ADD
|
|
306
|
+
};
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
// Apply custom options WITHOUT overriding preset values
|
|
310
|
+
if (opts?.options) {
|
|
311
|
+
// Only allow specific overrides, not preset overrides
|
|
312
|
+
const allowedOverrides = ['message', 'skipFailedRequests', 'standardHeaders', 'legacyHeaders'];
|
|
313
|
+
for (const key of allowedOverrides) {
|
|
314
|
+
if (opts.options[key] !== undefined) {
|
|
315
|
+
finalOptions[key] = opts.options[key];
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
// Log if user tried to override preset
|
|
320
|
+
const attemptedOverrides = Object.keys(opts.options).filter(
|
|
321
|
+
k => !allowedOverrides.includes(k) && k !== 'mode'
|
|
322
|
+
);
|
|
323
|
+
if (attemptedOverrides.length > 0) {
|
|
324
|
+
logger.warn("⚠ Rate limit overrides ignored", {
|
|
325
|
+
preset: opts?.mode || 'default',
|
|
326
|
+
ignoredOptions: attemptedOverrides
|
|
327
|
+
});
|
|
328
|
+
}
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
// Add v8+ options if not present
|
|
332
|
+
if (finalOptions.standardHeaders === undefined) {
|
|
333
|
+
finalOptions.standardHeaders = true;
|
|
334
|
+
}
|
|
335
|
+
if (finalOptions.legacyHeaders === undefined) {
|
|
336
|
+
finalOptions.legacyHeaders = false;
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
// Try primary adapter
|
|
340
|
+
try {
|
|
341
|
+
logger.info("📌 Applying rate limiting", {
|
|
342
|
+
mode: opts?.mode || 'default',
|
|
343
|
+
windowMs: finalOptions.windowMs,
|
|
344
|
+
max: finalOptions.max
|
|
345
|
+
});
|
|
346
|
+
|
|
347
|
+
return this.primaryAdapter.getMiddleware(finalOptions);
|
|
348
|
+
} catch (err: any) {
|
|
349
|
+
logger.warn("⚠ Primary rate limiter failed → fallback", {
|
|
350
|
+
error: err?.message
|
|
351
|
+
});
|
|
352
|
+
|
|
353
|
+
if (!this.fallbackAdapter) {
|
|
354
|
+
throw new AdapterError("Rate limiters failed; no fallback adapter.");
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
try {
|
|
358
|
+
logger.info("📌 Using fallback rate limiter");
|
|
359
|
+
return this.fallbackAdapter.getMiddleware(finalOptions);
|
|
360
|
+
} catch (fallbackErr: any) {
|
|
361
|
+
logger.error("❌ Fallback limiter also failed", {
|
|
362
|
+
error: fallbackErr?.message
|
|
363
|
+
});
|
|
364
|
+
throw new AdapterError("Both primary and fallback limiters failed.");
|
|
365
|
+
}
|
|
366
|
+
}
|
|
367
|
+
}
|
|
368
|
+
}
|