hi-secure 1.0.16 → 1.0.18
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.map +1 -1
- package/dist/adapters/ArgonAdapter.js +0 -36
- package/dist/adapters/ArgonAdapter.js.map +1 -1
- package/dist/adapters/BcryptAdapter.d.ts.map +1 -1
- package/dist/adapters/BcryptAdapter.js +0 -36
- package/dist/adapters/BcryptAdapter.js.map +1 -1
- package/dist/adapters/ExpressRLAdapter.d.ts.map +1 -1
- package/dist/adapters/ExpressRLAdapter.js +0 -38
- package/dist/adapters/ExpressRLAdapter.js.map +1 -1
- package/dist/adapters/ExpressValidatorAdapter.d.ts.map +1 -1
- package/dist/adapters/ExpressValidatorAdapter.js +0 -36
- package/dist/adapters/ExpressValidatorAdapter.js.map +1 -1
- package/dist/adapters/GoogleAdapter.d.ts.map +1 -1
- package/dist/adapters/GoogleAdapter.js +0 -63
- package/dist/adapters/GoogleAdapter.js.map +1 -1
- package/dist/adapters/JWTAdapter.d.ts.map +1 -1
- package/dist/adapters/JWTAdapter.js +0 -79
- package/dist/adapters/JWTAdapter.js.map +1 -1
- package/dist/adapters/RLFlexibleAdapter.d.ts.map +1 -1
- package/dist/adapters/RLFlexibleAdapter.js +0 -64
- package/dist/adapters/RLFlexibleAdapter.js.map +1 -1
- package/dist/adapters/SanitizeHtmlAdapter.d.ts.map +1 -1
- package/dist/adapters/SanitizeHtmlAdapter.js +0 -64
- package/dist/adapters/SanitizeHtmlAdapter.js.map +1 -1
- package/dist/adapters/XSSAdapter.d.ts.map +1 -1
- package/dist/adapters/XSSAdapter.js +0 -116
- package/dist/adapters/XSSAdapter.js.map +1 -1
- package/dist/adapters/ZodAdapter.d.ts.map +1 -1
- package/dist/adapters/ZodAdapter.js +0 -3
- package/dist/adapters/ZodAdapter.js.map +1 -1
- package/dist/core/HiSecure.d.ts.map +1 -1
- package/dist/core/HiSecure.js +0 -16
- package/dist/core/HiSecure.js.map +1 -1
- package/dist/logging/index.d.ts.map +1 -1
- package/dist/logging/index.js +0 -2
- package/dist/logging/index.js.map +1 -1
- package/dist/logging/morganSetup.d.ts.map +1 -1
- package/dist/logging/morganSetup.js +0 -14
- package/dist/logging/morganSetup.js.map +1 -1
- package/dist/logging/winstonSetup.d.ts.map +1 -1
- package/dist/logging/winstonSetup.js +2 -46
- package/dist/logging/winstonSetup.js.map +1 -1
- package/dist/managers/AuthManager.d.ts.map +1 -1
- package/dist/managers/AuthManager.js +0 -108
- package/dist/managers/AuthManager.js.map +1 -1
- package/dist/managers/CorsManager.d.ts.map +1 -1
- package/dist/managers/CorsManager.js +0 -28
- package/dist/managers/CorsManager.js.map +1 -1
- package/dist/managers/HashManager.d.ts.map +1 -1
- package/dist/managers/HashManager.js +0 -92
- package/dist/managers/HashManager.js.map +1 -1
- package/dist/managers/JsonManager.d.ts.map +1 -1
- package/dist/managers/JsonManager.js +0 -55
- package/dist/managers/JsonManager.js.map +1 -1
- package/dist/managers/RateLimitManager.d.ts.map +1 -1
- package/dist/managers/RateLimitManager.js +0 -3
- package/dist/managers/RateLimitManager.js.map +1 -1
- package/dist/managers/SanitizerManager.d.ts.map +1 -1
- package/dist/managers/SanitizerManager.js +0 -80
- package/dist/managers/SanitizerManager.js.map +1 -1
- package/dist/managers/ValidatorManager.d.ts.map +1 -1
- package/dist/managers/ValidatorManager.js +0 -59
- package/dist/managers/ValidatorManager.js.map +1 -1
- package/package.json +1 -1
- package/src/adapters/ArgonAdapter.ts +0 -45
- package/src/adapters/BcryptAdapter.ts +0 -49
- package/src/adapters/ExpressRLAdapter.ts +0 -48
- package/src/adapters/ExpressValidatorAdapter.ts +0 -50
- package/src/adapters/GoogleAdapter.ts +0 -82
- package/src/adapters/JWTAdapter.ts +0 -96
- package/src/adapters/RLFlexibleAdapter.ts +0 -82
- package/src/adapters/SanitizeHtmlAdapter.ts +1 -84
- package/src/adapters/XSSAdapter.ts +1 -150
- package/src/adapters/ZodAdapter.ts +0 -46
- package/src/core/HiSecure.ts +1 -369
- package/src/logging/index.ts +0 -6
- package/src/logging/morganSetup.ts +0 -25
- package/src/logging/winstonSetup.ts +2 -64
- package/src/managers/AuthManager.ts +0 -141
- package/src/managers/CorsManager.ts +0 -40
- package/src/managers/HashManager.ts +0 -108
- package/src/managers/JsonManager.ts +0 -62
- package/src/managers/RateLimitManager.ts +0 -113
- package/src/managers/SanitizerManager.ts +0 -103
- package/src/managers/ValidatorManager.ts +0 -75
|
@@ -1,70 +1,8 @@
|
|
|
1
|
-
// // import winston from "winston";
|
|
2
|
-
|
|
3
|
-
// // export const logger = winston.createLogger({
|
|
4
|
-
// // level: "info",
|
|
5
|
-
// // format: winston.format.combine(
|
|
6
|
-
// // winston.format.timestamp(),
|
|
7
|
-
// // winston.format.json()
|
|
8
|
-
// // ),
|
|
9
|
-
// // transports: [
|
|
10
|
-
// // new winston.transports.Console()
|
|
11
|
-
// // ]
|
|
12
|
-
// // });
|
|
13
|
-
|
|
14
|
-
// // // Shortcut helpers
|
|
15
|
-
// // export const logInfo = (msg: string, meta: any = {}) => logger.info(msg, meta);
|
|
16
|
-
// // export const logWarn = (msg: string, meta: any = {}) => logger.warn(msg, meta);
|
|
17
|
-
// // export const logError = (msg: string, meta: any = {}) => logger.error(msg, meta);
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
// import winston from "winston";
|
|
23
|
-
|
|
24
|
-
// const { combine, timestamp, printf, colorize, errors } = winston.format;
|
|
25
|
-
|
|
26
|
-
// const logFormat = printf(({ level, message, timestamp, ...meta }) => {
|
|
27
|
-
// const metaString =
|
|
28
|
-
// Object.keys(meta).length > 0 ? ` | ${JSON.stringify(meta)}` : "";
|
|
29
|
-
|
|
30
|
-
// return `${timestamp} ${level}: ${message}${metaString}`;
|
|
31
|
-
// });
|
|
32
|
-
|
|
33
|
-
// export const logger = winston.createLogger({
|
|
34
|
-
// level: "info",
|
|
35
|
-
// format: combine(
|
|
36
|
-
// errors({ stack: true }),
|
|
37
|
-
// timestamp({ format: "HH:mm:ss" })
|
|
38
|
-
// ),
|
|
39
|
-
// transports: [
|
|
40
|
-
// new winston.transports.Console({
|
|
41
|
-
// format: combine(
|
|
42
|
-
// colorize({ all: true }),
|
|
43
|
-
// logFormat
|
|
44
|
-
// )
|
|
45
|
-
// })
|
|
46
|
-
// ]
|
|
47
|
-
// });
|
|
48
|
-
|
|
49
|
-
// // Shortcut helpers
|
|
50
|
-
// export const logInfo = (msg: string, meta: any = {}) =>
|
|
51
|
-
// logger.info(msg, meta);
|
|
52
|
-
|
|
53
|
-
// export const logWarn = (msg: string, meta: any = {}) =>
|
|
54
|
-
// logger.warn(msg, meta);
|
|
55
|
-
|
|
56
|
-
// export const logError = (msg: string, meta: any = {}) =>
|
|
57
|
-
// logger.error(msg, meta);
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
1
|
import winston from "winston";
|
|
64
2
|
|
|
65
3
|
const { combine, timestamp, printf, colorize, errors } = winston.format;
|
|
66
4
|
|
|
67
|
-
//
|
|
5
|
+
//colors added
|
|
68
6
|
winston.addColors({
|
|
69
7
|
error: "red",
|
|
70
8
|
warn: "yellow",
|
|
@@ -80,7 +18,7 @@ const logFormat = printf(({ level, message, timestamp, ...meta }) => {
|
|
|
80
18
|
});
|
|
81
19
|
|
|
82
20
|
export const logger = winston.createLogger({
|
|
83
|
-
level: "http",
|
|
21
|
+
level: "http",
|
|
84
22
|
format: combine(
|
|
85
23
|
errors({ stack: true }),
|
|
86
24
|
timestamp({ format: "HH:mm:ss" })
|
|
@@ -1,144 +1,3 @@
|
|
|
1
|
-
// import { JWTAdapter } from "../adapters/JWTAdapter.js";
|
|
2
|
-
// import { GoogleAdapter } from "../adapters/GoogleAdapter.js";
|
|
3
|
-
// import { AdapterError } from "../core/errors/AdapterError.js";
|
|
4
|
-
// import { HttpError } from "../core/errors/HttpError.js";
|
|
5
|
-
// import { Request, Response, NextFunction } from "express";
|
|
6
|
-
// import { logger } from "../logging";
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
// export interface AuthOptions {
|
|
10
|
-
// jwtSecret: string;
|
|
11
|
-
// jwtExpiresIn?: string | number;
|
|
12
|
-
// googleClientId?: string;
|
|
13
|
-
// }
|
|
14
|
-
|
|
15
|
-
// export interface ProtectOptions {
|
|
16
|
-
// required?: boolean;
|
|
17
|
-
// roles?: string[];
|
|
18
|
-
// }
|
|
19
|
-
|
|
20
|
-
// export class AuthManager {
|
|
21
|
-
// private jwtAdapter: JWTAdapter;
|
|
22
|
-
// private googleAdapter?: GoogleAdapter;
|
|
23
|
-
|
|
24
|
-
// constructor(opts: AuthOptions) {
|
|
25
|
-
// if (!opts.jwtSecret) {
|
|
26
|
-
// throw new AdapterError("jwtSecret required in AuthOptions");
|
|
27
|
-
// }
|
|
28
|
-
|
|
29
|
-
// if (opts.jwtSecret.length < 32) {
|
|
30
|
-
// logger.warn(" JWT secret is less than 32 characters - consider using a stronger secret");
|
|
31
|
-
// }
|
|
32
|
-
|
|
33
|
-
// logger.info("AuthManager initialized");
|
|
34
|
-
|
|
35
|
-
// this.jwtAdapter = new JWTAdapter({
|
|
36
|
-
// secret: opts.jwtSecret,
|
|
37
|
-
// expiresIn: opts.jwtExpiresIn ?? "1d",
|
|
38
|
-
// });
|
|
39
|
-
|
|
40
|
-
// if (opts.googleClientId) {
|
|
41
|
-
// this.googleAdapter = new GoogleAdapter(opts.googleClientId);
|
|
42
|
-
// logger.info("GoogleAdapter enabled");
|
|
43
|
-
// }
|
|
44
|
-
// }
|
|
45
|
-
|
|
46
|
-
// sign(payload: object, options?: { expiresIn?: string | number, jti?: string }) {
|
|
47
|
-
// logger.info("JWT Sign called");
|
|
48
|
-
// return this.jwtAdapter.sign(payload, options);
|
|
49
|
-
// }
|
|
50
|
-
|
|
51
|
-
// verify(token: string) {
|
|
52
|
-
// logger.info("JWT Verify called");
|
|
53
|
-
// return this.jwtAdapter.verify(token);
|
|
54
|
-
// }
|
|
55
|
-
|
|
56
|
-
// async verifyGoogleIdToken(idToken: string) {
|
|
57
|
-
// if (!this.googleAdapter) {
|
|
58
|
-
// throw new AdapterError("GoogleAdapter not configured.");
|
|
59
|
-
// }
|
|
60
|
-
|
|
61
|
-
// logger.info("Google ID Token verify called");
|
|
62
|
-
|
|
63
|
-
// try {
|
|
64
|
-
// return await this.googleAdapter.verifyIdToken(idToken);
|
|
65
|
-
// } catch (err: any) {
|
|
66
|
-
// logger.error("Google ID Token verification failed", { error: err?.message });
|
|
67
|
-
// throw HttpError.Unauthorized("Invalid Google ID token");
|
|
68
|
-
// }
|
|
69
|
-
// }
|
|
70
|
-
|
|
71
|
-
// protect(options?: ProtectOptions) {
|
|
72
|
-
// const required = options?.required ?? true;
|
|
73
|
-
// const roles = options?.roles;
|
|
74
|
-
|
|
75
|
-
// return (req: Request, res: Response, next: NextFunction) => {
|
|
76
|
-
// const header = req.headers["authorization"];
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
// if (!required && !header) {
|
|
80
|
-
// return next();
|
|
81
|
-
// }
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
// if (!header) {
|
|
85
|
-
// logger.warn("Missing Authorization header", {
|
|
86
|
-
// path: req.path,
|
|
87
|
-
// method: req.method
|
|
88
|
-
// });
|
|
89
|
-
// return next(HttpError.Unauthorized("Missing Authorization header"));
|
|
90
|
-
// }
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
// const [type, token] = String(header).split(" ");
|
|
94
|
-
// if (type !== "Bearer" || !token) {
|
|
95
|
-
// logger.warn("Invalid Authorization header", {
|
|
96
|
-
// path: req.path,
|
|
97
|
-
// method: req.method
|
|
98
|
-
// });
|
|
99
|
-
// return next(HttpError.Unauthorized("Invalid Authorization header"));
|
|
100
|
-
// }
|
|
101
|
-
|
|
102
|
-
// try {
|
|
103
|
-
|
|
104
|
-
// // Verify JWT
|
|
105
|
-
// const decoded = this.verify(token);
|
|
106
|
-
|
|
107
|
-
// // Attach to request
|
|
108
|
-
// (req as any).auth = decoded;
|
|
109
|
-
// (req as any).user = decoded;
|
|
110
|
-
|
|
111
|
-
// // Role-based authorization - role added Middleware
|
|
112
|
-
// if (roles && roles.length > 0) {
|
|
113
|
-
// const userRole = (decoded as any).role || (decoded as any).roles?.[0];
|
|
114
|
-
// if (!userRole || !roles.includes(userRole)) {
|
|
115
|
-
// logger.warn("Insufficient permissions", {
|
|
116
|
-
// path: req.path,
|
|
117
|
-
// requiredRoles: roles,
|
|
118
|
-
// userRole
|
|
119
|
-
// });
|
|
120
|
-
// return next(HttpError.Forbidden("Insufficient permissions"));
|
|
121
|
-
// }
|
|
122
|
-
// }
|
|
123
|
-
|
|
124
|
-
// return next();
|
|
125
|
-
// } catch (err: any) {
|
|
126
|
-
// logger.error("JWT verify failed", {
|
|
127
|
-
// error: err?.message,
|
|
128
|
-
// path: req.path,
|
|
129
|
-
// method: req.method
|
|
130
|
-
// });
|
|
131
|
-
// return next(HttpError.Unauthorized("Invalid or expired token"));
|
|
132
|
-
// }
|
|
133
|
-
// };
|
|
134
|
-
// }
|
|
135
|
-
// }
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
1
|
import { JWTAdapter } from "../adapters/JWTAdapter";
|
|
143
2
|
import { GoogleAdapter } from "../adapters/GoogleAdapter";
|
|
144
3
|
import { AdapterError } from "../core/errors/AdapterError";
|
|
@@ -1,43 +1,3 @@
|
|
|
1
|
-
// import cors from "cors";
|
|
2
|
-
// import { logger } from "../logging";
|
|
3
|
-
// import { AdapterError } from "../core/errors/AdapterError.js";
|
|
4
|
-
|
|
5
|
-
// export class CorsManager {
|
|
6
|
-
|
|
7
|
-
// middleware(options?: any) {
|
|
8
|
-
// try {
|
|
9
|
-
// const defaultOptions = {
|
|
10
|
-
// origin: '*',
|
|
11
|
-
// methods: ['GET', 'POST', 'PUT', 'DELETE', 'PATCH', 'OPTIONS'],
|
|
12
|
-
// allowedHeaders: ['Content-Type', 'Authorization'],
|
|
13
|
-
// credentials: false,
|
|
14
|
-
// maxAge: 86400
|
|
15
|
-
// };
|
|
16
|
-
|
|
17
|
-
// const finalOptions = options ? { ...defaultOptions, ...options } : defaultOptions;
|
|
18
|
-
|
|
19
|
-
// logger.debug("CORS configured", {
|
|
20
|
-
// origin: finalOptions.origin,
|
|
21
|
-
// methods: finalOptions.methods
|
|
22
|
-
// });
|
|
23
|
-
|
|
24
|
-
// return cors(finalOptions);
|
|
25
|
-
|
|
26
|
-
// } catch (err: any) {
|
|
27
|
-
// logger.error(" CORS Manager: failed to create CORS middleware", {
|
|
28
|
-
// error: err?.message || err,
|
|
29
|
-
// options
|
|
30
|
-
// });
|
|
31
|
-
// throw new AdapterError("CORS middleware initialization failed.");
|
|
32
|
-
// }
|
|
33
|
-
// }
|
|
34
|
-
// }
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
1
|
import cors from "cors";
|
|
42
2
|
import { logger } from "../logging";
|
|
43
3
|
import { AdapterError } from "../core/errors/AdapterError";
|
|
@@ -1,111 +1,3 @@
|
|
|
1
|
-
// import { AdapterError } from "../core/errors/AdapterError.js";
|
|
2
|
-
// import { HiSecureConfig } from "../core/types/HiSecureConfig.js";
|
|
3
|
-
// import { logger } from "../logging";
|
|
4
|
-
|
|
5
|
-
// interface HashAdapter {
|
|
6
|
-
// hash(value: string): Promise<string>;
|
|
7
|
-
// verify(value: string, hashed: string): Promise<boolean>;
|
|
8
|
-
// }
|
|
9
|
-
|
|
10
|
-
// export interface HashResult {
|
|
11
|
-
// hash: string;
|
|
12
|
-
// algorithm: string;
|
|
13
|
-
// usedFallback: boolean;
|
|
14
|
-
// }
|
|
15
|
-
|
|
16
|
-
// export class HashManager {
|
|
17
|
-
// private config: HiSecureConfig["hashing"];
|
|
18
|
-
// private primaryAdapter: HashAdapter;
|
|
19
|
-
// private fallbackAdapter: HashAdapter | null;
|
|
20
|
-
|
|
21
|
-
// constructor(
|
|
22
|
-
// config: HiSecureConfig["hashing"],
|
|
23
|
-
// primaryAdapter: HashAdapter,
|
|
24
|
-
// fallbackAdapter: HashAdapter | null
|
|
25
|
-
// ) {
|
|
26
|
-
// this.config = config;
|
|
27
|
-
// this.primaryAdapter = primaryAdapter;
|
|
28
|
-
// this.fallbackAdapter = fallbackAdapter;
|
|
29
|
-
// }
|
|
30
|
-
|
|
31
|
-
// async hash(value: string, options?: { allowFallback?: boolean }): Promise<HashResult> {
|
|
32
|
-
// try {
|
|
33
|
-
// const hash = await this.primaryAdapter.hash(value);
|
|
34
|
-
// return {
|
|
35
|
-
// hash,
|
|
36
|
-
// algorithm: this.config.primary,
|
|
37
|
-
// usedFallback: false
|
|
38
|
-
// };
|
|
39
|
-
// } catch (err: any) {
|
|
40
|
-
// logger.warn("Primary hashing failed", {
|
|
41
|
-
// error: err.message,
|
|
42
|
-
// algorithm: this.config.primary
|
|
43
|
-
// });
|
|
44
|
-
|
|
45
|
-
// if (!options?.allowFallback || !this.fallbackAdapter) {
|
|
46
|
-
// throw new AdapterError(
|
|
47
|
-
// `Primary hashing (${this.config.primary}) failed. Fallback not allowed.`
|
|
48
|
-
// );
|
|
49
|
-
// }
|
|
50
|
-
|
|
51
|
-
// try {
|
|
52
|
-
// const hash = await this.fallbackAdapter.hash(value);
|
|
53
|
-
|
|
54
|
-
// // Log security downgrade warning
|
|
55
|
-
// logger.warn("SECURITY DOWNGRADE: Using fallback hashing", {
|
|
56
|
-
// from: this.config.primary,
|
|
57
|
-
// to: this.config.fallback
|
|
58
|
-
// });
|
|
59
|
-
|
|
60
|
-
// return {
|
|
61
|
-
// hash,
|
|
62
|
-
// algorithm: this.config.fallback || 'bcrypt',
|
|
63
|
-
// usedFallback: true
|
|
64
|
-
// };
|
|
65
|
-
// } catch (fallbackErr: any) {
|
|
66
|
-
// logger.error("Fallback hashing failed", {
|
|
67
|
-
// error: fallbackErr?.message,
|
|
68
|
-
// });
|
|
69
|
-
// throw new AdapterError(
|
|
70
|
-
// "Both primary and fallback hashing failed."
|
|
71
|
-
// );
|
|
72
|
-
// }
|
|
73
|
-
// }
|
|
74
|
-
// }
|
|
75
|
-
|
|
76
|
-
// async verify(value: string, hashed: string): Promise<boolean> {
|
|
77
|
-
// // primary adapter - first
|
|
78
|
-
// try {
|
|
79
|
-
// return await this.primaryAdapter.verify(value, hashed);
|
|
80
|
-
// } catch (primaryErr: any) {
|
|
81
|
-
// logger.warn("Primary verify failed", {
|
|
82
|
-
// error: primaryErr?.message,
|
|
83
|
-
// });
|
|
84
|
-
|
|
85
|
-
// // fallback exists - try it
|
|
86
|
-
// if (this.fallbackAdapter) {
|
|
87
|
-
// try {
|
|
88
|
-
// return await this.fallbackAdapter.verify(value, hashed);
|
|
89
|
-
// } catch (fallbackErr: any) {
|
|
90
|
-
// logger.error(" Fallback verify failed", {
|
|
91
|
-
// error: fallbackErr?.message,
|
|
92
|
-
// });
|
|
93
|
-
// throw new AdapterError(
|
|
94
|
-
// "Both primary and fallback verify failed."
|
|
95
|
-
// );
|
|
96
|
-
// }
|
|
97
|
-
// }
|
|
98
|
-
|
|
99
|
-
// throw new AdapterError(
|
|
100
|
-
// "Primary verify failed and no fallback adapter configured."
|
|
101
|
-
// );
|
|
102
|
-
// }
|
|
103
|
-
// }
|
|
104
|
-
// }
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
1
|
import { AdapterError } from "../core/errors/AdapterError";
|
|
110
2
|
import { HiSecureConfig } from "../core/types/HiSecureConfig";
|
|
111
3
|
import { logger } from "../logging";
|
|
@@ -1,65 +1,3 @@
|
|
|
1
|
-
// import express from "express";
|
|
2
|
-
// import qs from "qs";
|
|
3
|
-
// import { logger } from "../logging";
|
|
4
|
-
// import { AdapterError } from "../core/errors/AdapterError.js";
|
|
5
|
-
|
|
6
|
-
// export class JsonManager {
|
|
7
|
-
// middleware(options?: any) {
|
|
8
|
-
// try {
|
|
9
|
-
// const defaultOptions = {
|
|
10
|
-
// limit: '1mb',
|
|
11
|
-
// inflate: true,
|
|
12
|
-
// strict: true
|
|
13
|
-
// };
|
|
14
|
-
// return express.json({ ...defaultOptions, ...(options || {}) });
|
|
15
|
-
// } catch (err: any) {
|
|
16
|
-
// logger.error("JSON Manager: failed to create JSON parser");
|
|
17
|
-
// throw new AdapterError("JSON parser initialization failed.");
|
|
18
|
-
// }
|
|
19
|
-
// }
|
|
20
|
-
|
|
21
|
-
// urlencoded(options?: any) {
|
|
22
|
-
// try {
|
|
23
|
-
// const defaultOptions = {
|
|
24
|
-
// extended: true,
|
|
25
|
-
// limit: '1mb',
|
|
26
|
-
// parameterLimit: 1000
|
|
27
|
-
// };
|
|
28
|
-
// const opts = { ...defaultOptions, ...(options || {}) };
|
|
29
|
-
// return express.urlencoded(opts);
|
|
30
|
-
// } catch (err: any) {
|
|
31
|
-
// logger.error("URL-encoded parser failed");
|
|
32
|
-
// throw new AdapterError("URL-encoded parser initialization failed.");
|
|
33
|
-
// }
|
|
34
|
-
// }
|
|
35
|
-
|
|
36
|
-
// queryParser(options?: any) {
|
|
37
|
-
// return (req: any, res: any, next: any) => {
|
|
38
|
-
// try {
|
|
39
|
-
// if (!req.parsedQuery && req.url.includes('?')) {
|
|
40
|
-
// const queryString = req.url.split("?")[1] || "";
|
|
41
|
-
// const parsed = qs.parse(queryString, {
|
|
42
|
-
// depth: 5,
|
|
43
|
-
// parameterLimit: 100,
|
|
44
|
-
// ...options
|
|
45
|
-
// });
|
|
46
|
-
|
|
47
|
-
// req.parsedQuery = parsed;
|
|
48
|
-
// logger.debug(" Query parsed", {
|
|
49
|
-
// keys: Object.keys(parsed)
|
|
50
|
-
// });
|
|
51
|
-
// }
|
|
52
|
-
// next();
|
|
53
|
-
// } catch (err: any) {
|
|
54
|
-
// logger.error("Failed to parse query", { error: err?.message });
|
|
55
|
-
// next(new AdapterError("Query parsing failed."));
|
|
56
|
-
// }
|
|
57
|
-
// };
|
|
58
|
-
// }
|
|
59
|
-
// }
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
1
|
import express from "express";
|
|
64
2
|
import qs from "qs";
|
|
65
3
|
import { logger } from "../logging";
|
|
@@ -1,116 +1,3 @@
|
|
|
1
|
-
// import { HiSecureConfig } from "../core/types/HiSecureConfig.js";
|
|
2
|
-
// import { AdapterError } from "../core/errors/AdapterError.js";
|
|
3
|
-
// import { logger } from "../logging";
|
|
4
|
-
|
|
5
|
-
// interface RateLimiterAdapter {
|
|
6
|
-
// getMiddleware: (options?: any) => any;
|
|
7
|
-
// }
|
|
8
|
-
|
|
9
|
-
// export class RateLimitManager {
|
|
10
|
-
// private config: HiSecureConfig["rateLimiter"];
|
|
11
|
-
// private primaryAdapter: RateLimiterAdapter;
|
|
12
|
-
// private fallbackAdapter: RateLimiterAdapter | null;
|
|
13
|
-
|
|
14
|
-
// constructor(
|
|
15
|
-
// config: HiSecureConfig["rateLimiter"],
|
|
16
|
-
// primaryAdapter: RateLimiterAdapter,
|
|
17
|
-
// fallbackAdapter: RateLimiterAdapter | null
|
|
18
|
-
// ) {
|
|
19
|
-
// this.config = config;
|
|
20
|
-
// this.primaryAdapter = primaryAdapter;
|
|
21
|
-
// this.fallbackAdapter = fallbackAdapter;
|
|
22
|
-
// }
|
|
23
|
-
|
|
24
|
-
// middleware(opts?: { mode?: "strict" | "relaxed" | "api"; options?: any }) {
|
|
25
|
-
// let finalOptions: any = {};
|
|
26
|
-
|
|
27
|
-
// if (opts?.mode === "strict") {
|
|
28
|
-
// finalOptions = {
|
|
29
|
-
// windowMs: 10_000,
|
|
30
|
-
// max: 5,
|
|
31
|
-
// message: "Too many requests, please slow down."
|
|
32
|
-
// };
|
|
33
|
-
// } else if (opts?.mode === "relaxed") {
|
|
34
|
-
// finalOptions = {
|
|
35
|
-
// windowMs: 60_000,
|
|
36
|
-
// max: 100,
|
|
37
|
-
// message: "Rate limit exceeded."
|
|
38
|
-
// };
|
|
39
|
-
// } else if (opts?.mode === "api") {
|
|
40
|
-
// finalOptions = {
|
|
41
|
-
// windowMs: 15 * 60 * 1000,
|
|
42
|
-
// max: 100,
|
|
43
|
-
// message: "API rate limit exceeded."
|
|
44
|
-
// };
|
|
45
|
-
// } else {
|
|
46
|
-
// finalOptions = {
|
|
47
|
-
// windowMs: this.config.windowMs,
|
|
48
|
-
// max: this.config.maxRequests,
|
|
49
|
-
// message: this.config.message,
|
|
50
|
-
// standardHeaders: true,
|
|
51
|
-
// legacyHeaders: false
|
|
52
|
-
// };
|
|
53
|
-
// }
|
|
54
|
-
|
|
55
|
-
// if (opts?.options) {
|
|
56
|
-
// const allowedOverrides = ['message', 'skipFailedRequests', 'standardHeaders', 'legacyHeaders'];
|
|
57
|
-
// for (const key of allowedOverrides) {
|
|
58
|
-
// if (opts.options[key] !== undefined) {
|
|
59
|
-
// finalOptions[key] = opts.options[key];
|
|
60
|
-
// }
|
|
61
|
-
// }
|
|
62
|
-
|
|
63
|
-
// const attemptedOverrides = Object.keys(opts.options).filter(
|
|
64
|
-
// k => !allowedOverrides.includes(k) && k !== 'mode'
|
|
65
|
-
// );
|
|
66
|
-
// if (attemptedOverrides.length > 0) {
|
|
67
|
-
// logger.warn("Rate limit overrides ignored", {
|
|
68
|
-
// preset: opts?.mode || 'default',
|
|
69
|
-
// ignoredOptions: attemptedOverrides
|
|
70
|
-
// });
|
|
71
|
-
// }
|
|
72
|
-
// }
|
|
73
|
-
|
|
74
|
-
// if (finalOptions.standardHeaders === undefined) {
|
|
75
|
-
// finalOptions.standardHeaders = true;
|
|
76
|
-
// }
|
|
77
|
-
// if (finalOptions.legacyHeaders === undefined) {
|
|
78
|
-
// finalOptions.legacyHeaders = false;
|
|
79
|
-
// }
|
|
80
|
-
|
|
81
|
-
// try {
|
|
82
|
-
// logger.info("Applying rate limiting", {
|
|
83
|
-
// mode: opts?.mode || 'default',
|
|
84
|
-
// windowMs: finalOptions.windowMs,
|
|
85
|
-
// max: finalOptions.max
|
|
86
|
-
// });
|
|
87
|
-
|
|
88
|
-
// return this.primaryAdapter.getMiddleware(finalOptions);
|
|
89
|
-
// } catch (err: any) {
|
|
90
|
-
// logger.warn("Primary rate limiter failed → fallback", {
|
|
91
|
-
// error: err?.message
|
|
92
|
-
// });
|
|
93
|
-
|
|
94
|
-
// if (!this.fallbackAdapter) {
|
|
95
|
-
// throw new AdapterError("Rate limiters failed; no fallback adapter.");
|
|
96
|
-
// }
|
|
97
|
-
|
|
98
|
-
// try {
|
|
99
|
-
// logger.info("Using fallback rate limiter");
|
|
100
|
-
// return this.fallbackAdapter.getMiddleware(finalOptions);
|
|
101
|
-
// } catch (fallbackErr: any) {
|
|
102
|
-
// logger.error("Fallback limiter also failed", {
|
|
103
|
-
// error: fallbackErr?.message
|
|
104
|
-
// });
|
|
105
|
-
// throw new AdapterError("Both primary and fallback limiters failed.");
|
|
106
|
-
// }
|
|
107
|
-
// }
|
|
108
|
-
// }
|
|
109
|
-
// }
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
1
|
import { HiSecureConfig } from "../core/types/HiSecureConfig";
|
|
115
2
|
import { AdapterError } from "../core/errors/AdapterError";
|
|
116
3
|
import { logger } from "../logging";
|
|
@@ -1,106 +1,3 @@
|
|
|
1
|
-
// import { SanitizerError } from "../core/errors/SanitizerError.js";
|
|
2
|
-
// import { logger } from "../logging";
|
|
3
|
-
|
|
4
|
-
// interface SanitizerAdapter {
|
|
5
|
-
// sanitize: (value: string, options?: any) => string;
|
|
6
|
-
// }
|
|
7
|
-
|
|
8
|
-
// export class SanitizerManager {
|
|
9
|
-
// private primary: SanitizerAdapter;
|
|
10
|
-
// private fallback: SanitizerAdapter | null;
|
|
11
|
-
|
|
12
|
-
// constructor(primary: SanitizerAdapter, fallback: SanitizerAdapter | null = null) {
|
|
13
|
-
// this.primary = primary;
|
|
14
|
-
// this.fallback = fallback;
|
|
15
|
-
// }
|
|
16
|
-
|
|
17
|
-
// sanitize(value: string, options?: any): string {
|
|
18
|
-
|
|
19
|
-
// if (typeof value !== 'string') {
|
|
20
|
-
// return value;
|
|
21
|
-
// }
|
|
22
|
-
|
|
23
|
-
// try {
|
|
24
|
-
// return this.primary.sanitize(value, options);
|
|
25
|
-
// } catch (err: any) {
|
|
26
|
-
// logger.warn("Primary sanitizer failed", { error: err?.message });
|
|
27
|
-
|
|
28
|
-
// if (!this.fallback) {
|
|
29
|
-
// throw new SanitizerError("Primary sanitizer failed and no fallback available.");
|
|
30
|
-
// }
|
|
31
|
-
|
|
32
|
-
// logger.info("Using fallback sanitizer");
|
|
33
|
-
// return this.fallback.sanitize(value, options);
|
|
34
|
-
// }
|
|
35
|
-
// }
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
// middleware(options?: any) {
|
|
39
|
-
// return (req: any, _res: any, next: any) => {
|
|
40
|
-
// let fallbackTriggered = false;
|
|
41
|
-
|
|
42
|
-
// const safeSanitize = (value: string): string => {
|
|
43
|
-
// if (fallbackTriggered && this.fallback) {
|
|
44
|
-
// return this.fallback.sanitize(value, options);
|
|
45
|
-
// }
|
|
46
|
-
|
|
47
|
-
// try {
|
|
48
|
-
// return this.primary.sanitize(value, options);
|
|
49
|
-
// } catch (err: any) {
|
|
50
|
-
// if (!this.fallback) {
|
|
51
|
-
// throw err;
|
|
52
|
-
// }
|
|
53
|
-
|
|
54
|
-
// fallbackTriggered = true;
|
|
55
|
-
// logger.warn("Switching to fallback sanitizer for this request");
|
|
56
|
-
// return this.fallback.sanitize(value, options);
|
|
57
|
-
// }
|
|
58
|
-
// };
|
|
59
|
-
|
|
60
|
-
// try {
|
|
61
|
-
|
|
62
|
-
// if (req.body && typeof req.body === "object") {
|
|
63
|
-
// const originalBody = req.body;
|
|
64
|
-
// const sanitizedBody: any = Array.isArray(originalBody) ? [] : {};
|
|
65
|
-
|
|
66
|
-
// for (const key of Object.keys(originalBody)) {
|
|
67
|
-
// const value = originalBody[key];
|
|
68
|
-
|
|
69
|
-
// if (typeof value === "string") {
|
|
70
|
-
// sanitizedBody[key] = safeSanitize(value);
|
|
71
|
-
// } else if (Array.isArray(value)) {
|
|
72
|
-
// sanitizedBody[key] = value.map(item =>
|
|
73
|
-
// typeof item === "string" ? safeSanitize(item) : item
|
|
74
|
-
// );
|
|
75
|
-
// } else if (value && typeof value === "object") {
|
|
76
|
-
// sanitizedBody[key] = value;
|
|
77
|
-
// } else {
|
|
78
|
-
// sanitizedBody[key] = value;
|
|
79
|
-
// }
|
|
80
|
-
// }
|
|
81
|
-
|
|
82
|
-
// req.sanitizedBody = sanitizedBody;
|
|
83
|
-
|
|
84
|
-
// logger.debug("Request body sanitized", {
|
|
85
|
-
// originalKeys: Object.keys(originalBody),
|
|
86
|
-
// sanitizedKeys: Object.keys(sanitizedBody),
|
|
87
|
-
// usedFallback: fallbackTriggered
|
|
88
|
-
// });
|
|
89
|
-
// }
|
|
90
|
-
|
|
91
|
-
// next();
|
|
92
|
-
// } catch (err: any) {
|
|
93
|
-
// logger.error("Sanitizer middleware failed", {
|
|
94
|
-
// error: err?.message
|
|
95
|
-
// });
|
|
96
|
-
// next(new SanitizerError("Sanitizer middleware failure"));
|
|
97
|
-
// }
|
|
98
|
-
// };
|
|
99
|
-
// }
|
|
100
|
-
// }
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
1
|
import { SanitizerError } from "../core/errors/SanitizerError";
|
|
105
2
|
import { logger } from "../logging";
|
|
106
3
|
|