hi-secure 1.0.15 → 1.0.16
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 +1 -1
- package/dist/adapters/ArgonAdapter.d.ts.map +1 -1
- package/dist/adapters/ArgonAdapter.js +43 -5
- package/dist/adapters/ArgonAdapter.js.map +1 -1
- package/dist/adapters/BcryptAdapter.d.ts.map +1 -1
- package/dist/adapters/BcryptAdapter.js +43 -3
- package/dist/adapters/BcryptAdapter.js.map +1 -1
- package/dist/adapters/ExpressRLAdapter.d.ts.map +1 -1
- package/dist/adapters/ExpressRLAdapter.js +48 -6
- package/dist/adapters/ExpressRLAdapter.js.map +1 -1
- package/dist/adapters/ExpressValidatorAdapter.d.ts.map +1 -1
- package/dist/adapters/ExpressValidatorAdapter.js +50 -10
- package/dist/adapters/ExpressValidatorAdapter.js.map +1 -1
- package/dist/adapters/GoogleAdapter.d.ts.map +1 -1
- package/dist/adapters/GoogleAdapter.js +82 -16
- package/dist/adapters/GoogleAdapter.js.map +1 -1
- package/dist/adapters/JWTAdapter.d.ts.map +1 -1
- package/dist/adapters/JWTAdapter.js +104 -15
- package/dist/adapters/JWTAdapter.js.map +1 -1
- package/dist/adapters/RLFlexibleAdapter.d.ts.map +1 -1
- package/dist/adapters/RLFlexibleAdapter.js +87 -12
- package/dist/adapters/RLFlexibleAdapter.js.map +1 -1
- package/dist/adapters/SanitizeHtmlAdapter.d.ts.map +1 -1
- package/dist/adapters/SanitizeHtmlAdapter.js +81 -13
- package/dist/adapters/SanitizeHtmlAdapter.js.map +1 -1
- package/dist/adapters/XSSAdapter.d.ts +1 -1
- package/dist/adapters/XSSAdapter.d.ts.map +1 -1
- package/dist/adapters/XSSAdapter.js +137 -20
- package/dist/adapters/XSSAdapter.js.map +1 -1
- package/dist/adapters/ZodAdapter.d.ts +1 -1
- package/dist/adapters/ZodAdapter.d.ts.map +1 -1
- package/dist/adapters/ZodAdapter.js +13 -8
- package/dist/adapters/ZodAdapter.js.map +1 -1
- package/dist/core/HiSecure.d.ts +3 -4
- package/dist/core/HiSecure.d.ts.map +1 -1
- package/dist/core/HiSecure.js +108 -121
- package/dist/core/HiSecure.js.map +1 -1
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +8 -1
- package/dist/index.js.map +1 -1
- package/dist/logging/index.d.ts.map +1 -1
- package/dist/logging/index.js +2 -0
- package/dist/logging/index.js.map +1 -1
- package/dist/logging/morganSetup.d.ts.map +1 -1
- package/dist/logging/morganSetup.js +22 -1
- package/dist/logging/morganSetup.js.map +1 -1
- package/dist/logging/winstonSetup.d.ts.map +1 -1
- package/dist/logging/winstonSetup.js +61 -3
- package/dist/logging/winstonSetup.js.map +1 -1
- package/dist/managers/AuthManager.d.ts +2 -2
- package/dist/managers/AuthManager.d.ts.map +1 -1
- package/dist/managers/AuthManager.js +167 -31
- package/dist/managers/AuthManager.js.map +1 -1
- package/dist/managers/CorsManager.d.ts.map +1 -1
- package/dist/managers/CorsManager.js +46 -11
- package/dist/managers/CorsManager.js.map +1 -1
- package/dist/managers/HashManager.d.ts +1 -1
- package/dist/managers/HashManager.d.ts.map +1 -1
- package/dist/managers/HashManager.js +127 -17
- package/dist/managers/HashManager.js.map +1 -1
- package/dist/managers/JsonManager.d.ts +1 -1
- package/dist/managers/JsonManager.d.ts.map +1 -1
- package/dist/managers/JsonManager.js +99 -16
- package/dist/managers/JsonManager.js.map +1 -1
- package/dist/managers/RateLimitManager.d.ts +1 -1
- package/dist/managers/RateLimitManager.d.ts.map +1 -1
- package/dist/managers/RateLimitManager.js +46 -22
- package/dist/managers/RateLimitManager.js.map +1 -1
- package/dist/managers/SanitizerManager.d.ts.map +1 -1
- package/dist/managers/SanitizerManager.js +112 -15
- package/dist/managers/SanitizerManager.js.map +1 -1
- package/dist/managers/ValidatorManager.d.ts.map +1 -1
- package/dist/managers/ValidatorManager.js +90 -7
- package/dist/managers/ValidatorManager.js.map +1 -1
- package/package.json +2 -6
- package/readme.md +3 -6
- package/src/adapters/ArgonAdapter.ts +55 -6
- package/src/adapters/BcryptAdapter.ts +56 -8
- package/src/adapters/ExpressRLAdapter.ts +62 -9
- package/src/adapters/ExpressValidatorAdapter.ts +67 -11
- package/src/adapters/GoogleAdapter.ts +106 -21
- package/src/adapters/JWTAdapter.ts +129 -21
- package/src/adapters/RLFlexibleAdapter.ts +113 -16
- package/src/adapters/SanitizeHtmlAdapter.ts +111 -18
- package/src/adapters/XSSAdapter.ts +183 -39
- package/src/adapters/ZodAdapter.ts +56 -10
- package/src/core/HiSecure.ts +496 -162
- package/src/index.ts +4 -0
- package/src/logging/index.ts +6 -0
- package/src/logging/morganSetup.ts +36 -1
- package/src/logging/winstonSetup.ts +97 -8
- package/src/managers/AuthManager.ts +205 -34
- package/src/managers/CorsManager.ts +63 -16
- package/src/managers/HashManager.ts +156 -19
- package/src/managers/JsonManager.ts +119 -15
- package/src/managers/RateLimitManager.ts +174 -29
- package/src/managers/SanitizerManager.ts +150 -25
- package/src/managers/ValidatorManager.ts +115 -15
|
@@ -1,21 +1,135 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
// import { FilterXSS, getDefaultWhiteList, whiteList } from 'xss';
|
|
3
|
+
// import { AdapterError } from "../core/errors/AdapterError.js";
|
|
4
|
+
// import { logger } from "../logging/index.js";
|
|
2
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
6
|
exports.XSSAdapter = void 0;
|
|
7
|
+
// export interface XSSOptions {
|
|
8
|
+
// whiteList?: typeof whiteList;
|
|
9
|
+
// stripIgnoreTag?: boolean;
|
|
10
|
+
// stripIgnoreTagBody?: string[];
|
|
11
|
+
// allowCommentTag?: boolean;
|
|
12
|
+
// css?: boolean | { [key: string]: boolean };
|
|
13
|
+
// onTag?: (tag: string, html: string, options: any) => string;
|
|
14
|
+
// onTagAttr?: (tag: string, name: string, value: string, isWhiteAttr: boolean) => string;
|
|
15
|
+
// onIgnoreTag?: (tag: string, html: string, options: any) => string;
|
|
16
|
+
// [key: string]: any;
|
|
17
|
+
// }
|
|
18
|
+
// export class XSSAdapter {
|
|
19
|
+
// private globalOptions: XSSOptions;
|
|
20
|
+
// private defaultFilter: FilterXSS;
|
|
21
|
+
// constructor(options: XSSOptions = {}) {
|
|
22
|
+
// this.globalOptions = options;
|
|
23
|
+
// // Default safe configuration
|
|
24
|
+
// const defaultOptions: XSSOptions = {
|
|
25
|
+
// whiteList: getDefaultWhiteList(),
|
|
26
|
+
// stripIgnoreTag: true,
|
|
27
|
+
// stripIgnoreTagBody: ['script', 'style', 'iframe', 'object', 'embed'],
|
|
28
|
+
// allowCommentTag: false,
|
|
29
|
+
// css: false,
|
|
30
|
+
// onTag: (tag, html, options) => {
|
|
31
|
+
// if (tag === 'a') {
|
|
32
|
+
// return html.replace(/<a /i, '<a target="_blank" rel="noopener noreferrer" ');
|
|
33
|
+
// }
|
|
34
|
+
// return html;
|
|
35
|
+
// }
|
|
36
|
+
// };
|
|
37
|
+
// const finalOptions = { ...defaultOptions, ...options };
|
|
38
|
+
// this.defaultFilter = new FilterXSS(finalOptions);
|
|
39
|
+
// }
|
|
40
|
+
// sanitize(input: string, dynamicOptions?: XSSOptions): string {
|
|
41
|
+
// try {
|
|
42
|
+
// if (typeof input !== "string") {
|
|
43
|
+
// return input as any;
|
|
44
|
+
// }
|
|
45
|
+
// if (!dynamicOptions || Object.keys(dynamicOptions).length === 0) {
|
|
46
|
+
// return this.defaultFilter.process(input);
|
|
47
|
+
// }
|
|
48
|
+
// const mergedOptions = { ...this.globalOptions, ...dynamicOptions };
|
|
49
|
+
// const customFilter = new FilterXSS(mergedOptions);
|
|
50
|
+
// return customFilter.process(input);
|
|
51
|
+
// } catch (err: any) {
|
|
52
|
+
// logger.error("XSS sanitizer failed", {
|
|
53
|
+
// error: err?.message,
|
|
54
|
+
// preview: input?.slice?.(0, 80)
|
|
55
|
+
// });
|
|
56
|
+
// throw new AdapterError("XSS sanitizer failed.");
|
|
57
|
+
// }
|
|
58
|
+
// }
|
|
59
|
+
// middleware(dynamicOptions?: XSSOptions) {
|
|
60
|
+
// return (req: any, _res: any, next: any) => {
|
|
61
|
+
// try {
|
|
62
|
+
// if (req.body && typeof req.body === "object") {
|
|
63
|
+
// const originalBody = req.body;
|
|
64
|
+
// const sanitizedBody: any = Array.isArray(originalBody) ? [] : {};
|
|
65
|
+
// for (const key of Object.keys(originalBody)) {
|
|
66
|
+
// const val = originalBody[key];
|
|
67
|
+
// if (typeof val === "string") {
|
|
68
|
+
// sanitizedBody[key] = this.sanitize(val, dynamicOptions);
|
|
69
|
+
// } else if (Array.isArray(val)) {
|
|
70
|
+
// sanitizedBody[key] = val.map((v) =>
|
|
71
|
+
// typeof v === "string"
|
|
72
|
+
// ? this.sanitize(v, dynamicOptions)
|
|
73
|
+
// : v
|
|
74
|
+
// );
|
|
75
|
+
// } else if (val && typeof val === "object") {
|
|
76
|
+
// sanitizedBody[key] = this.deepSanitize(val, dynamicOptions);
|
|
77
|
+
// } else {
|
|
78
|
+
// sanitizedBody[key] = val;
|
|
79
|
+
// }
|
|
80
|
+
// }
|
|
81
|
+
// req.sanitizedBody = sanitizedBody;
|
|
82
|
+
// logger.debug("XSS sanitizer applied", {
|
|
83
|
+
// originalKeys: Object.keys(originalBody),
|
|
84
|
+
// sanitizedKeys: Object.keys(sanitizedBody)
|
|
85
|
+
// });
|
|
86
|
+
// }
|
|
87
|
+
// next();
|
|
88
|
+
// } catch (err: any) {
|
|
89
|
+
// logger.error("XSS middleware failed", {
|
|
90
|
+
// error: err?.message || err
|
|
91
|
+
// });
|
|
92
|
+
// next(err);
|
|
93
|
+
// }
|
|
94
|
+
// };
|
|
95
|
+
// }
|
|
96
|
+
// private deepSanitize(obj: any, options?: XSSOptions, visited = new WeakSet()): any {
|
|
97
|
+
// if (obj && typeof obj === "object") {
|
|
98
|
+
// if (visited.has(obj)) {
|
|
99
|
+
// return obj;
|
|
100
|
+
// }
|
|
101
|
+
// visited.add(obj);
|
|
102
|
+
// }
|
|
103
|
+
// if (typeof obj === "string") {
|
|
104
|
+
// return this.sanitize(obj, options);
|
|
105
|
+
// }
|
|
106
|
+
// if (Array.isArray(obj)) {
|
|
107
|
+
// return obj.map(item => this.deepSanitize(item, options, visited));
|
|
108
|
+
// }
|
|
109
|
+
// if (obj && typeof obj === "object") {
|
|
110
|
+
// const result: any = {};
|
|
111
|
+
// for (const key of Object.keys(obj)) {
|
|
112
|
+
// result[key] = this.deepSanitize(obj[key], options, visited);
|
|
113
|
+
// }
|
|
114
|
+
// return result;
|
|
115
|
+
// }
|
|
116
|
+
// return obj;
|
|
117
|
+
// }
|
|
118
|
+
// }
|
|
4
119
|
const xss_1 = require("xss");
|
|
5
|
-
const
|
|
6
|
-
const
|
|
120
|
+
const AdapterError_1 = require("../core/errors/AdapterError");
|
|
121
|
+
const logging_1 = require("../logging");
|
|
7
122
|
class XSSAdapter {
|
|
8
123
|
constructor(options = {}) {
|
|
9
124
|
this.globalOptions = options;
|
|
10
|
-
// Default safe configuration
|
|
11
125
|
const defaultOptions = {
|
|
12
126
|
whiteList: (0, xss_1.getDefaultWhiteList)(),
|
|
13
127
|
stripIgnoreTag: true,
|
|
14
|
-
stripIgnoreTagBody: [
|
|
128
|
+
stripIgnoreTagBody: ["script", "style", "iframe", "object", "embed"],
|
|
15
129
|
allowCommentTag: false,
|
|
16
130
|
css: false,
|
|
17
|
-
onTag: (tag, html
|
|
18
|
-
if (tag ===
|
|
131
|
+
onTag: (tag, html) => {
|
|
132
|
+
if (tag === "a") {
|
|
19
133
|
return html.replace(/<a /i, '<a target="_blank" rel="noopener noreferrer" ');
|
|
20
134
|
}
|
|
21
135
|
return html;
|
|
@@ -26,9 +140,8 @@ class XSSAdapter {
|
|
|
26
140
|
}
|
|
27
141
|
sanitize(input, dynamicOptions) {
|
|
28
142
|
try {
|
|
29
|
-
if (typeof input !== "string")
|
|
143
|
+
if (typeof input !== "string")
|
|
30
144
|
return input;
|
|
31
|
-
}
|
|
32
145
|
if (!dynamicOptions || Object.keys(dynamicOptions).length === 0) {
|
|
33
146
|
return this.defaultFilter.process(input);
|
|
34
147
|
}
|
|
@@ -37,11 +150,12 @@ class XSSAdapter {
|
|
|
37
150
|
return customFilter.process(input);
|
|
38
151
|
}
|
|
39
152
|
catch (err) {
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
153
|
+
logging_1.logger.error("XSS sanitization failed", {
|
|
154
|
+
adapter: "xss",
|
|
155
|
+
operation: "sanitize",
|
|
156
|
+
reason: err?.message
|
|
43
157
|
});
|
|
44
|
-
throw new
|
|
158
|
+
throw new AdapterError_1.AdapterError("XSS sanitizer failed.");
|
|
45
159
|
}
|
|
46
160
|
}
|
|
47
161
|
middleware(dynamicOptions) {
|
|
@@ -56,7 +170,7 @@ class XSSAdapter {
|
|
|
56
170
|
sanitizedBody[key] = this.sanitize(val, dynamicOptions);
|
|
57
171
|
}
|
|
58
172
|
else if (Array.isArray(val)) {
|
|
59
|
-
sanitizedBody[key] = val.map(
|
|
173
|
+
sanitizedBody[key] = val.map(v => typeof v === "string"
|
|
60
174
|
? this.sanitize(v, dynamicOptions)
|
|
61
175
|
: v);
|
|
62
176
|
}
|
|
@@ -68,16 +182,20 @@ class XSSAdapter {
|
|
|
68
182
|
}
|
|
69
183
|
}
|
|
70
184
|
req.sanitizedBody = sanitizedBody;
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
185
|
+
// ✅ visible + safe info log
|
|
186
|
+
logging_1.logger.info("XSS sanitization applied", {
|
|
187
|
+
adapter: "xss",
|
|
188
|
+
operation: "middleware",
|
|
189
|
+
keys: Object.keys(sanitizedBody)
|
|
74
190
|
});
|
|
75
191
|
}
|
|
76
192
|
next();
|
|
77
193
|
}
|
|
78
194
|
catch (err) {
|
|
79
|
-
|
|
80
|
-
|
|
195
|
+
logging_1.logger.error("XSS middleware failed", {
|
|
196
|
+
adapter: "xss",
|
|
197
|
+
operation: "middleware",
|
|
198
|
+
reason: err?.message
|
|
81
199
|
});
|
|
82
200
|
next(err);
|
|
83
201
|
}
|
|
@@ -85,9 +203,8 @@ class XSSAdapter {
|
|
|
85
203
|
}
|
|
86
204
|
deepSanitize(obj, options, visited = new WeakSet()) {
|
|
87
205
|
if (obj && typeof obj === "object") {
|
|
88
|
-
if (visited.has(obj))
|
|
206
|
+
if (visited.has(obj))
|
|
89
207
|
return obj;
|
|
90
|
-
}
|
|
91
208
|
visited.add(obj);
|
|
92
209
|
}
|
|
93
210
|
if (typeof obj === "string") {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"XSSAdapter.js","sourceRoot":"","sources":["../../src/adapters/XSSAdapter.ts"],"names":[],"mappings":"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","sourcesContent":["import { FilterXSS, getDefaultWhiteList, whiteList } from 'xss';\r\nimport { AdapterError } from \"../core/errors/AdapterError.js\";\r\nimport { logger } from \"../logging/index.js\";\r\n\r\nexport interface XSSOptions {\r\n whiteList?: typeof whiteList;\r\n stripIgnoreTag?: boolean;\r\n stripIgnoreTagBody?: string[];\r\n allowCommentTag?: boolean;\r\n css?: boolean | { [key: string]: boolean };\r\n onTag?: (tag: string, html: string, options: any) => string;\r\n onTagAttr?: (tag: string, name: string, value: string, isWhiteAttr: boolean) => string;\r\n onIgnoreTag?: (tag: string, html: string, options: any) => string;\r\n [key: string]: any;\r\n}\r\n\r\nexport class XSSAdapter {\r\n private globalOptions: XSSOptions;\r\n private defaultFilter: FilterXSS;\r\n\r\n constructor(options: XSSOptions = {}) {\r\n this.globalOptions = options;\r\n \r\n // Default safe configuration\r\n const defaultOptions: XSSOptions = {\r\n whiteList: getDefaultWhiteList(),\r\n stripIgnoreTag: true, \r\n stripIgnoreTagBody: ['script', 'style', 'iframe', 'object', 'embed'],\r\n allowCommentTag: false,\r\n css: false, \r\n onTag: (tag, html, options) => {\r\n \r\n if (tag === 'a') {\r\n return html.replace(/<a /i, '<a target=\"_blank\" rel=\"noopener noreferrer\" ');\r\n }\r\n return html;\r\n }\r\n };\r\n\r\n const finalOptions = { ...defaultOptions, ...options };\r\n this.defaultFilter = new FilterXSS(finalOptions);\r\n }\r\n\r\n \r\n sanitize(input: string, dynamicOptions?: XSSOptions): string {\r\n try {\r\n if (typeof input !== \"string\") {\r\n return input as any;\r\n }\r\n\r\n \r\n if (!dynamicOptions || Object.keys(dynamicOptions).length === 0) {\r\n return this.defaultFilter.process(input);\r\n }\r\n\r\n \r\n const mergedOptions = { ...this.globalOptions, ...dynamicOptions };\r\n const customFilter = new FilterXSS(mergedOptions);\r\n \r\n return customFilter.process(input);\r\n\r\n } catch (err: any) {\r\n logger.error(\"XSS sanitizer failed\", {\r\n error: err?.message,\r\n preview: input?.slice?.(0, 80)\r\n });\r\n throw new AdapterError(\"XSS sanitizer failed.\");\r\n }\r\n }\r\n\r\n \r\n middleware(dynamicOptions?: XSSOptions) {\r\n return (req: any, _res: any, next: any) => {\r\n try {\r\n if (req.body && typeof req.body === \"object\") {\r\n const originalBody = req.body;\r\n const sanitizedBody: any = Array.isArray(originalBody) ? [] : {};\r\n \r\n for (const key of Object.keys(originalBody)) {\r\n const val = originalBody[key];\r\n\r\n if (typeof val === \"string\") {\r\n sanitizedBody[key] = this.sanitize(val, dynamicOptions);\r\n } else if (Array.isArray(val)) {\r\n sanitizedBody[key] = val.map((v) =>\r\n typeof v === \"string\"\r\n ? this.sanitize(v, dynamicOptions)\r\n : v\r\n );\r\n } else if (val && typeof val === \"object\") {\r\n \r\n sanitizedBody[key] = this.deepSanitize(val, dynamicOptions);\r\n } else {\r\n sanitizedBody[key] = val;\r\n }\r\n }\r\n \r\n \r\n req.sanitizedBody = sanitizedBody;\r\n \r\n logger.debug(\"XSS sanitizer applied\", {\r\n originalKeys: Object.keys(originalBody),\r\n sanitizedKeys: Object.keys(sanitizedBody)\r\n });\r\n }\r\n\r\n next();\r\n } catch (err: any) {\r\n logger.error(\"XSS middleware failed\", {\r\n error: err?.message || err\r\n });\r\n next(err);\r\n }\r\n };\r\n }\r\n\r\n \r\n private deepSanitize(obj: any, options?: XSSOptions, visited = new WeakSet()): any {\r\n \r\n if (obj && typeof obj === \"object\") {\r\n if (visited.has(obj)) {\r\n return obj;\r\n }\r\n visited.add(obj);\r\n }\r\n\r\n if (typeof obj === \"string\") {\r\n return this.sanitize(obj, options);\r\n }\r\n\r\n if (Array.isArray(obj)) {\r\n return obj.map(item => this.deepSanitize(item, options, visited));\r\n }\r\n\r\n if (obj && typeof obj === \"object\") {\r\n const result: any = {};\r\n for (const key of Object.keys(obj)) {\r\n result[key] = this.deepSanitize(obj[key], options, visited);\r\n }\r\n return result;\r\n }\r\n\r\n return obj;\r\n }\r\n}"]}
|
|
1
|
+
{"version":3,"file":"XSSAdapter.js","sourceRoot":"","sources":["../../src/adapters/XSSAdapter.ts"],"names":[],"mappings":"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","sourcesContent":["// import { FilterXSS, getDefaultWhiteList, whiteList } from 'xss';\r\n// import { AdapterError } from \"../core/errors/AdapterError.js\";\r\n// import { logger } from \"../logging/index.js\";\r\n\r\n// export interface XSSOptions {\r\n// whiteList?: typeof whiteList;\r\n// stripIgnoreTag?: boolean;\r\n// stripIgnoreTagBody?: string[];\r\n// allowCommentTag?: boolean;\r\n// css?: boolean | { [key: string]: boolean };\r\n// onTag?: (tag: string, html: string, options: any) => string;\r\n// onTagAttr?: (tag: string, name: string, value: string, isWhiteAttr: boolean) => string;\r\n// onIgnoreTag?: (tag: string, html: string, options: any) => string;\r\n// [key: string]: any;\r\n// }\r\n\r\n// export class XSSAdapter {\r\n// private globalOptions: XSSOptions;\r\n// private defaultFilter: FilterXSS;\r\n\r\n// constructor(options: XSSOptions = {}) {\r\n// this.globalOptions = options;\r\n \r\n// // Default safe configuration\r\n// const defaultOptions: XSSOptions = {\r\n// whiteList: getDefaultWhiteList(),\r\n// stripIgnoreTag: true, \r\n// stripIgnoreTagBody: ['script', 'style', 'iframe', 'object', 'embed'],\r\n// allowCommentTag: false,\r\n// css: false, \r\n// onTag: (tag, html, options) => {\r\n \r\n// if (tag === 'a') {\r\n// return html.replace(/<a /i, '<a target=\"_blank\" rel=\"noopener noreferrer\" ');\r\n// }\r\n// return html;\r\n// }\r\n// };\r\n\r\n// const finalOptions = { ...defaultOptions, ...options };\r\n// this.defaultFilter = new FilterXSS(finalOptions);\r\n// }\r\n\r\n \r\n// sanitize(input: string, dynamicOptions?: XSSOptions): string {\r\n// try {\r\n// if (typeof input !== \"string\") {\r\n// return input as any;\r\n// }\r\n\r\n \r\n// if (!dynamicOptions || Object.keys(dynamicOptions).length === 0) {\r\n// return this.defaultFilter.process(input);\r\n// }\r\n\r\n \r\n// const mergedOptions = { ...this.globalOptions, ...dynamicOptions };\r\n// const customFilter = new FilterXSS(mergedOptions);\r\n \r\n// return customFilter.process(input);\r\n\r\n// } catch (err: any) {\r\n// logger.error(\"XSS sanitizer failed\", {\r\n// error: err?.message,\r\n// preview: input?.slice?.(0, 80)\r\n// });\r\n// throw new AdapterError(\"XSS sanitizer failed.\");\r\n// }\r\n// }\r\n\r\n \r\n// middleware(dynamicOptions?: XSSOptions) {\r\n// return (req: any, _res: any, next: any) => {\r\n// try {\r\n// if (req.body && typeof req.body === \"object\") {\r\n// const originalBody = req.body;\r\n// const sanitizedBody: any = Array.isArray(originalBody) ? [] : {};\r\n \r\n// for (const key of Object.keys(originalBody)) {\r\n// const val = originalBody[key];\r\n\r\n// if (typeof val === \"string\") {\r\n// sanitizedBody[key] = this.sanitize(val, dynamicOptions);\r\n// } else if (Array.isArray(val)) {\r\n// sanitizedBody[key] = val.map((v) =>\r\n// typeof v === \"string\"\r\n// ? this.sanitize(v, dynamicOptions)\r\n// : v\r\n// );\r\n// } else if (val && typeof val === \"object\") {\r\n \r\n// sanitizedBody[key] = this.deepSanitize(val, dynamicOptions);\r\n// } else {\r\n// sanitizedBody[key] = val;\r\n// }\r\n// }\r\n \r\n \r\n// req.sanitizedBody = sanitizedBody;\r\n \r\n// logger.debug(\"XSS sanitizer applied\", {\r\n// originalKeys: Object.keys(originalBody),\r\n// sanitizedKeys: Object.keys(sanitizedBody)\r\n// });\r\n// }\r\n\r\n// next();\r\n// } catch (err: any) {\r\n// logger.error(\"XSS middleware failed\", {\r\n// error: err?.message || err\r\n// });\r\n// next(err);\r\n// }\r\n// };\r\n// }\r\n\r\n \r\n// private deepSanitize(obj: any, options?: XSSOptions, visited = new WeakSet()): any {\r\n \r\n// if (obj && typeof obj === \"object\") {\r\n// if (visited.has(obj)) {\r\n// return obj;\r\n// }\r\n// visited.add(obj);\r\n// }\r\n\r\n// if (typeof obj === \"string\") {\r\n// return this.sanitize(obj, options);\r\n// }\r\n\r\n// if (Array.isArray(obj)) {\r\n// return obj.map(item => this.deepSanitize(item, options, visited));\r\n// }\r\n\r\n// if (obj && typeof obj === \"object\") {\r\n// const result: any = {};\r\n// for (const key of Object.keys(obj)) {\r\n// result[key] = this.deepSanitize(obj[key], options, visited);\r\n// }\r\n// return result;\r\n// }\r\n\r\n// return obj;\r\n// }\r\n// }\r\n\r\n\r\n\r\n\r\nimport { FilterXSS, getDefaultWhiteList, whiteList } from \"xss\";\r\nimport { AdapterError } from \"../core/errors/AdapterError\";\r\nimport { logger } from \"../logging\";\r\n\r\nexport interface XSSOptions {\r\n whiteList?: typeof whiteList;\r\n stripIgnoreTag?: boolean;\r\n stripIgnoreTagBody?: string[];\r\n allowCommentTag?: boolean;\r\n css?: boolean | { [key: string]: boolean };\r\n onTag?: (tag: string, html: string, options: any) => string;\r\n onTagAttr?: (tag: string, name: string, value: string, isWhiteAttr: boolean) => string;\r\n onIgnoreTag?: (tag: string, html: string, options: any) => string;\r\n [key: string]: any;\r\n}\r\n\r\nexport class XSSAdapter {\r\n private globalOptions: XSSOptions;\r\n private defaultFilter: FilterXSS;\r\n\r\n constructor(options: XSSOptions = {}) {\r\n this.globalOptions = options;\r\n\r\n const defaultOptions: XSSOptions = {\r\n whiteList: getDefaultWhiteList(),\r\n stripIgnoreTag: true,\r\n stripIgnoreTagBody: [\"script\", \"style\", \"iframe\", \"object\", \"embed\"],\r\n allowCommentTag: false,\r\n css: false,\r\n onTag: (tag, html) => {\r\n if (tag === \"a\") {\r\n return html.replace(\r\n /<a /i,\r\n '<a target=\"_blank\" rel=\"noopener noreferrer\" '\r\n );\r\n }\r\n return html;\r\n }\r\n };\r\n\r\n const finalOptions = { ...defaultOptions, ...options };\r\n this.defaultFilter = new FilterXSS(finalOptions);\r\n }\r\n\r\n sanitize(input: string, dynamicOptions?: XSSOptions): string {\r\n try {\r\n if (typeof input !== \"string\") return input as any;\r\n\r\n if (!dynamicOptions || Object.keys(dynamicOptions).length === 0) {\r\n return this.defaultFilter.process(input);\r\n }\r\n\r\n const mergedOptions = { ...this.globalOptions, ...dynamicOptions };\r\n const customFilter = new FilterXSS(mergedOptions);\r\n\r\n return customFilter.process(input);\r\n\r\n } catch (err: any) {\r\n logger.error(\"XSS sanitization failed\", {\r\n adapter: \"xss\",\r\n operation: \"sanitize\",\r\n reason: err?.message\r\n });\r\n\r\n throw new AdapterError(\"XSS sanitizer failed.\");\r\n }\r\n }\r\n\r\n middleware(dynamicOptions?: XSSOptions) {\r\n return (req: any, _res: any, next: any) => {\r\n try {\r\n if (req.body && typeof req.body === \"object\") {\r\n const originalBody = req.body;\r\n const sanitizedBody: any = Array.isArray(originalBody) ? [] : {};\r\n\r\n for (const key of Object.keys(originalBody)) {\r\n const val = originalBody[key];\r\n\r\n if (typeof val === \"string\") {\r\n sanitizedBody[key] = this.sanitize(val, dynamicOptions);\r\n } else if (Array.isArray(val)) {\r\n sanitizedBody[key] = val.map(v =>\r\n typeof v === \"string\"\r\n ? this.sanitize(v, dynamicOptions)\r\n : v\r\n );\r\n } else if (val && typeof val === \"object\") {\r\n sanitizedBody[key] = this.deepSanitize(val, dynamicOptions);\r\n } else {\r\n sanitizedBody[key] = val;\r\n }\r\n }\r\n\r\n req.sanitizedBody = sanitizedBody;\r\n\r\n // ✅ visible + safe info log\r\n logger.info(\"XSS sanitization applied\", {\r\n adapter: \"xss\",\r\n operation: \"middleware\",\r\n keys: Object.keys(sanitizedBody)\r\n });\r\n }\r\n\r\n next();\r\n } catch (err: any) {\r\n logger.error(\"XSS middleware failed\", {\r\n adapter: \"xss\",\r\n operation: \"middleware\",\r\n reason: err?.message\r\n });\r\n next(err);\r\n }\r\n };\r\n }\r\n\r\n private deepSanitize(obj: any, options?: XSSOptions, visited = new WeakSet()): any {\r\n if (obj && typeof obj === \"object\") {\r\n if (visited.has(obj)) return obj;\r\n visited.add(obj);\r\n }\r\n\r\n if (typeof obj === \"string\") {\r\n return this.sanitize(obj, options);\r\n }\r\n\r\n if (Array.isArray(obj)) {\r\n return obj.map(item => this.deepSanitize(item, options, visited));\r\n }\r\n\r\n if (obj && typeof obj === \"object\") {\r\n const result: any = {};\r\n for (const key of Object.keys(obj)) {\r\n result[key] = this.deepSanitize(obj[key], options, visited);\r\n }\r\n return result;\r\n }\r\n\r\n return obj;\r\n }\r\n}\r\n"]}
|
|
@@ -2,6 +2,6 @@ import { ZodSchema } from "zod";
|
|
|
2
2
|
export declare class ZodAdapter {
|
|
3
3
|
private globalSchema?;
|
|
4
4
|
constructor(globalSchema?: ZodSchema);
|
|
5
|
-
validate(dynamicSchema?: ZodSchema): (req: any,
|
|
5
|
+
validate(dynamicSchema?: ZodSchema): (req: any, _res: any, next: any) => any;
|
|
6
6
|
}
|
|
7
7
|
//# sourceMappingURL=ZodAdapter.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ZodAdapter.d.ts","sourceRoot":"","sources":["../../src/adapters/ZodAdapter.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"ZodAdapter.d.ts","sourceRoot":"","sources":["../../src/adapters/ZodAdapter.ts"],"names":[],"mappings":"AA8CA,OAAO,EAAE,SAAS,EAAY,MAAM,KAAK,CAAC;AAI1C,qBAAa,UAAU;IACnB,OAAO,CAAC,YAAY,CAAC,CAAY;gBAErB,YAAY,CAAC,EAAE,SAAS;IAIpC,QAAQ,CAAC,aAAa,CAAC,EAAE,SAAS,IACtB,KAAK,GAAG,EAAE,MAAM,GAAG,EAAE,MAAM,GAAG;CA6B7C"}
|
|
@@ -1,14 +1,17 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
// import { ZodSchema, ZodError } from "zod";
|
|
3
|
+
// import { ValidationError } from "../core/errors/ValidationError.js";
|
|
4
|
+
// import { logger } from "../logging/index.js";
|
|
2
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
6
|
exports.ZodAdapter = void 0;
|
|
4
|
-
const
|
|
5
|
-
const
|
|
7
|
+
const ValidationError_1 = require("../core/errors/ValidationError");
|
|
8
|
+
const logging_1 = require("../logging");
|
|
6
9
|
class ZodAdapter {
|
|
7
10
|
constructor(globalSchema) {
|
|
8
11
|
this.globalSchema = globalSchema;
|
|
9
12
|
}
|
|
10
13
|
validate(dynamicSchema) {
|
|
11
|
-
return (req,
|
|
14
|
+
return (req, _res, next) => {
|
|
12
15
|
const schema = dynamicSchema || this.globalSchema;
|
|
13
16
|
if (!schema)
|
|
14
17
|
return next();
|
|
@@ -21,13 +24,15 @@ class ZodAdapter {
|
|
|
21
24
|
path: issue.path.join("."),
|
|
22
25
|
code: issue.code
|
|
23
26
|
}));
|
|
24
|
-
|
|
25
|
-
|
|
27
|
+
logging_1.logger.warn("Zod validation failed", {
|
|
28
|
+
adapter: "zod",
|
|
29
|
+
operation: "validate",
|
|
26
30
|
method: req.method,
|
|
27
|
-
|
|
28
|
-
|
|
31
|
+
path: req.path,
|
|
32
|
+
issueCount: issues.length,
|
|
33
|
+
issues
|
|
29
34
|
});
|
|
30
|
-
return next(new
|
|
35
|
+
return next(new ValidationError_1.ValidationError("Validation failed.", issues));
|
|
31
36
|
};
|
|
32
37
|
}
|
|
33
38
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ZodAdapter.js","sourceRoot":"","sources":["../../src/adapters/ZodAdapter.ts"],"names":[],"mappings":";;;
|
|
1
|
+
{"version":3,"file":"ZodAdapter.js","sourceRoot":"","sources":["../../src/adapters/ZodAdapter.ts"],"names":[],"mappings":";AAAA,6CAA6C;AAC7C,wEAAwE;AACxE,gDAAgD;;;AA6ChD,oEAAiE;AACjE,wCAAoC;AAEpC,MAAa,UAAU;IAGnB,YAAY,YAAwB;QAChC,IAAI,CAAC,YAAY,GAAG,YAAY,CAAC;IACrC,CAAC;IAED,QAAQ,CAAC,aAAyB;QAC9B,OAAO,CAAC,GAAQ,EAAE,IAAS,EAAE,IAAS,EAAE,EAAE;YACtC,MAAM,MAAM,GAAG,aAAa,IAAI,IAAI,CAAC,YAAY,CAAC;YAClD,IAAI,CAAC,MAAM;gBAAE,OAAO,IAAI,EAAE,CAAC;YAE3B,MAAM,MAAM,GAAG,MAAM,CAAC,SAAS,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;YAC1C,IAAI,MAAM,CAAC,OAAO;gBAAE,OAAO,IAAI,EAAE,CAAC;YAElC,MAAM,MAAM,GAAa,MAAM,CAAC,KAAK,CAAC;YAEtC,MAAM,MAAM,GAAG,MAAM,CAAC,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;gBACvC,OAAO,EAAE,KAAK,CAAC,OAAO;gBACtB,IAAI,EAAE,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC;gBAC1B,IAAI,EAAE,KAAK,CAAC,IAAI;aACnB,CAAC,CAAC,CAAC;YAEJ,gBAAM,CAAC,IAAI,CAAC,uBAAuB,EAAE;gBACjC,OAAO,EAAE,KAAK;gBACd,SAAS,EAAE,UAAU;gBACrB,MAAM,EAAE,GAAG,CAAC,MAAM;gBAClB,IAAI,EAAE,GAAG,CAAC,IAAI;gBACd,UAAU,EAAE,MAAM,CAAC,MAAM;gBACzB,MAAM;aACT,CAAC,CAAC;YAEH,OAAO,IAAI,CACP,IAAI,iCAAe,CAAC,oBAAoB,EAAE,MAAa,CAAC,CAC3D,CAAC;QACN,CAAC,CAAC;IACN,CAAC;CACJ;AArCD,gCAqCC","sourcesContent":["// import { ZodSchema, ZodError } from \"zod\";\r\n// import { ValidationError } from \"../core/errors/ValidationError.js\"; \r\n// import { logger } from \"../logging/index.js\";\r\n\r\n// export class ZodAdapter {\r\n// private globalSchema?: ZodSchema;\r\n\r\n// constructor(globalSchema?: ZodSchema) {\r\n// this.globalSchema = globalSchema;\r\n// }\r\n\r\n// validate(dynamicSchema?: ZodSchema) {\r\n// return (req: any, res: any, next: any) => {\r\n// const schema = dynamicSchema || this.globalSchema;\r\n\r\n// if (!schema) return next();\r\n\r\n// const result = schema.safeParse(req.body);\r\n\r\n// if (result.success) return next();\r\n\r\n// const zodErr: ZodError = result.error;\r\n\r\n// const issues = zodErr.issues.map(issue => ({\r\n// message: issue.message,\r\n// path: issue.path.join(\".\"),\r\n// code: issue.code\r\n// }));\r\n\r\n// logger.warn(\"Zod validation failed\", {\r\n// path: req.path,\r\n// method: req.method,\r\n// issues,\r\n// preview: JSON.stringify(req.body).slice(0, 200)\r\n// });\r\n\r\n// return next(\r\n// new ValidationError(\"Validation failed.\", issues as any) \r\n// );\r\n// };\r\n// }\r\n// }\r\n\r\n\r\n\r\n\r\nimport { ZodSchema, ZodError } from \"zod\";\r\nimport { ValidationError } from \"../core/errors/ValidationError\";\r\nimport { logger } from \"../logging\";\r\n\r\nexport class ZodAdapter {\r\n private globalSchema?: ZodSchema;\r\n\r\n constructor(globalSchema?: ZodSchema) {\r\n this.globalSchema = globalSchema;\r\n }\r\n\r\n validate(dynamicSchema?: ZodSchema) {\r\n return (req: any, _res: any, next: any) => {\r\n const schema = dynamicSchema || this.globalSchema;\r\n if (!schema) return next();\r\n\r\n const result = schema.safeParse(req.body);\r\n if (result.success) return next();\r\n\r\n const zodErr: ZodError = result.error;\r\n\r\n const issues = zodErr.issues.map(issue => ({\r\n message: issue.message,\r\n path: issue.path.join(\".\"),\r\n code: issue.code\r\n }));\r\n\r\n logger.warn(\"Zod validation failed\", {\r\n adapter: \"zod\",\r\n operation: \"validate\",\r\n method: req.method,\r\n path: req.path,\r\n issueCount: issues.length,\r\n issues\r\n });\r\n\r\n return next(\r\n new ValidationError(\"Validation failed.\", issues as any)\r\n );\r\n };\r\n }\r\n}\r\n"]}
|
package/dist/core/HiSecure.d.ts
CHANGED
|
@@ -28,11 +28,10 @@ export declare class HiSecure {
|
|
|
28
28
|
static getInstance(config?: Partial<HiSecureConfig>): HiSecure;
|
|
29
29
|
static resetInstance(): void;
|
|
30
30
|
init(): void;
|
|
31
|
-
isInitialized(): boolean;
|
|
32
31
|
static auth(options?: {
|
|
33
32
|
required?: boolean;
|
|
34
33
|
roles?: string[];
|
|
35
|
-
}): (req: import("express").Request,
|
|
34
|
+
}): (req: import("express").Request, _res: import("express").Response, next: import("express").NextFunction) => void;
|
|
36
35
|
static validate(schema: ValidationSchema): (req: any, res: any, next: any) => any;
|
|
37
36
|
static sanitize(options?: any): (req: any, _res: any, next: any) => void;
|
|
38
37
|
static rateLimit(preset: "strict" | "relaxed" | "api" | object): any;
|
|
@@ -42,8 +41,8 @@ export declare class HiSecure {
|
|
|
42
41
|
end(): any;
|
|
43
42
|
}, next: (err?: any) => any) => void;
|
|
44
43
|
static json(options?: any): import("connect").NextHandleFunction[];
|
|
45
|
-
static hash(
|
|
46
|
-
static verify(
|
|
44
|
+
static hash(value: string): Promise<string>;
|
|
45
|
+
static verify(value: string, hash: string): Promise<boolean>;
|
|
47
46
|
static jwt: {
|
|
48
47
|
sign: (payload: object, options?: any) => string;
|
|
49
48
|
verify: (token: string) => string | import("jsonwebtoken").Jwt | import("jsonwebtoken").JwtPayload;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"HiSecure.d.ts","sourceRoot":"","sources":["../../src/core/HiSecure.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"HiSecure.d.ts","sourceRoot":"","sources":["../../src/core/HiSecure.ts"],"names":[],"mappings":"AAuWA,OAAO,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAC;AAkB3D,OAAO,EAAE,WAAW,EAAE,MAAM,4BAA4B,CAAC;AACzD,OAAO,EAAE,gBAAgB,EAAE,MAAM,iCAAiC,CAAC;AACnE,OAAO,EAAE,gBAAgB,EAAE,MAAM,iCAAiC,CAAC;AACnE,OAAO,EAAE,gBAAgB,EAAE,MAAM,iCAAiC,CAAC;AACnE,OAAO,EAAE,WAAW,EAAE,MAAM,4BAA4B,CAAC;AACzD,OAAO,EAAE,WAAW,EAAE,MAAM,4BAA4B,CAAC;AACzD,OAAO,EAAE,WAAW,EAAE,MAAM,4BAA4B,CAAC;AASzD,OAAO,EAAE,aAAa,EAAE,gBAAgB,EAAE,MAAM,0BAA0B,CAAC;AAE3E,qBAAa,QAAQ;IACjB,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAyB;IAChD,OAAO,CAAC,MAAM,CAAiB;IAC/B,OAAO,CAAC,WAAW,CAAS;IAGrB,WAAW,EAAG,WAAW,CAAC;IAC1B,gBAAgB,EAAG,gBAAgB,CAAC;IACpC,gBAAgB,EAAG,gBAAgB,CAAC;IACpC,gBAAgB,EAAG,gBAAgB,CAAC;IACpC,WAAW,EAAG,WAAW,CAAC;IAC1B,WAAW,EAAG,WAAW,CAAC;IAC1B,WAAW,CAAC,EAAE,WAAW,CAAC;IAGjC,OAAO,CAAC,cAAc,CAAM;IAC5B,OAAO,CAAC,eAAe,CAAM;IAC7B,OAAO,CAAC,kBAAkB,CAAM;IAChC,OAAO,CAAC,mBAAmB,CAAM;IACjC,OAAO,CAAC,gBAAgB,CAAM;IAC9B,OAAO,CAAC,iBAAiB,CAAM;IAE/B,OAAO;IAQP,MAAM,CAAC,WAAW,CAAC,MAAM,CAAC,EAAE,OAAO,CAAC,cAAc,CAAC,GAAG,QAAQ;IAW9D,MAAM,CAAC,aAAa,IAAI,IAAI;IAI5B,IAAI,IAAI,IAAI;IA8BZ,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE;QAAE,QAAQ,CAAC,EAAE,OAAO,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,EAAE,CAAA;KAAE;IAQ9D,MAAM,CAAC,QAAQ,CAAC,MAAM,EAAE,gBAAgB;IAIxC,MAAM,CAAC,QAAQ,CAAC,OAAO,CAAC,EAAE,GAAG;IAI7B,MAAM,CAAC,SAAS,CAAC,MAAM,EAAE,QAAQ,GAAG,SAAS,GAAG,KAAK,GAAG,MAAM;IAoB9D,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,GAAG;kBA9dtB,CAAC;;;iBAGY,CAAC;IA+djB,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,GAAG;WAYZ,IAAI,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;WAMpC,MAAM,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAIlE,MAAM,CAAC,GAAG;wBACU,MAAM,YAAY,GAAG;wBAGrB,MAAM;;qCAIO,MAAM;;MAGrC;IAMF,MAAM,CAAC,UAAU,CAAC,OAAO,CAAC,EAAE,aAAa,GAAG,KAAK,GAAG,QAAQ,GAAG,QAAQ;IAyBvE,OAAO,CAAC,aAAa;IA0CrB,OAAO,CAAC,aAAa;IA6BrB,OAAO,CAAC,oBAAoB;IAuB5B,OAAO,CAAC,qBAAqB;CAyBhC"}
|