@zintrust/core 0.4.18 → 0.4.19
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/src/cli/commands/AddCommand.d.ts +16 -0
- package/src/cli/commands/AddCommand.d.ts.map +1 -1
- package/src/cli/commands/AddCommand.js +157 -28
- package/src/cli/commands/DockerCommand.d.ts.map +1 -1
- package/src/cli/commands/DockerCommand.js +32 -4
- package/src/cli/commands/StartCommand.d.ts +7 -0
- package/src/cli/commands/StartCommand.d.ts.map +1 -1
- package/src/cli/commands/StartCommand.js +109 -20
- package/src/config/middleware.d.ts +23 -0
- package/src/config/middleware.d.ts.map +1 -1
- package/src/config/middleware.js +66 -31
- package/src/index.d.ts +2 -0
- package/src/index.d.ts.map +1 -1
- package/src/index.js +5 -3
- package/src/middleware/AuthMiddleware.d.ts +2 -0
- package/src/middleware/AuthMiddleware.d.ts.map +1 -1
- package/src/middleware/AuthMiddleware.js +8 -1
- package/src/middleware/BulletproofAuthMiddleware.d.ts +2 -0
- package/src/middleware/BulletproofAuthMiddleware.d.ts.map +1 -1
- package/src/middleware/BulletproofAuthMiddleware.js +13 -5
- package/src/middleware/CsrfMiddleware.d.ts +2 -0
- package/src/middleware/CsrfMiddleware.d.ts.map +1 -1
- package/src/middleware/CsrfMiddleware.js +9 -3
- package/src/middleware/ErrorHandlerMiddleware.d.ts +5 -1
- package/src/middleware/ErrorHandlerMiddleware.d.ts.map +1 -1
- package/src/middleware/ErrorHandlerMiddleware.js +12 -2
- package/src/middleware/JwtAuthMiddleware.d.ts +2 -0
- package/src/middleware/JwtAuthMiddleware.d.ts.map +1 -1
- package/src/middleware/JwtAuthMiddleware.js +39 -4
- package/src/middleware/MiddlewareFailureResponder.d.ts +15 -0
- package/src/middleware/MiddlewareFailureResponder.d.ts.map +1 -0
- package/src/middleware/MiddlewareFailureResponder.js +15 -0
- package/src/middleware/RateLimiter.d.ts +2 -0
- package/src/middleware/RateLimiter.d.ts.map +1 -1
- package/src/middleware/RateLimiter.js +10 -4
- package/src/middleware/ValidationMiddleware.d.ts +11 -6
- package/src/middleware/ValidationMiddleware.d.ts.map +1 -1
- package/src/middleware/ValidationMiddleware.js +48 -19
- package/src/middleware/index.d.ts +1 -0
- package/src/middleware/index.d.ts.map +1 -1
- package/src/middleware/index.js +1 -0
- package/src/runtime/WorkersModule.d.ts.map +1 -1
- package/src/runtime/WorkersModule.js +4 -3
- package/src/security/Xss.d.ts +2 -2
- package/src/security/Xss.d.ts.map +1 -1
- package/src/security/Xss.js +3 -4
- package/src/templates/project/basic/app/Middleware/AuthFailureResponder.ts.tpl +10 -0
- package/src/templates/project/basic/config/middleware.ts.tpl +18 -0
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
* Zero-dependency implementation
|
|
5
5
|
*/
|
|
6
6
|
import type { IRequest } from '../http/Request';
|
|
7
|
+
import { type MiddlewareFailureResponder } from './MiddlewareFailureResponder';
|
|
7
8
|
import type { Middleware } from './MiddlewareStack';
|
|
8
9
|
export interface RateLimitOptions {
|
|
9
10
|
windowMs: number;
|
|
@@ -20,6 +21,7 @@ export interface RateLimitOptions {
|
|
|
20
21
|
* - 'db' uses Cache.store('mongodb')
|
|
21
22
|
*/
|
|
22
23
|
store?: RateLimitStoreName;
|
|
24
|
+
onFailure?: MiddlewareFailureResponder;
|
|
23
25
|
}
|
|
24
26
|
export type RateLimitStoreName = 'memory' | 'redis' | 'kv' | 'db';
|
|
25
27
|
export declare const RateLimiter: Readonly<{
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"RateLimiter.d.ts","sourceRoot":"","sources":["../../../src/middleware/RateLimiter.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAKH,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AAE9C,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,6BAA6B,CAAC;AAE9D,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,EAAE,MAAM,CAAC;IACjB,GAAG,EAAE,MAAM,CAAC;IACZ,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,YAAY,CAAC,EAAE,CAAC,GAAG,EAAE,QAAQ,KAAK,MAAM,CAAC;IAEzC;;;;;;OAMG;IACH,KAAK,CAAC,EAAE,kBAAkB,CAAC;
|
|
1
|
+
{"version":3,"file":"RateLimiter.d.ts","sourceRoot":"","sources":["../../../src/middleware/RateLimiter.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAKH,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AAE9C,OAAO,EAEL,KAAK,0BAA0B,EAChC,MAAM,wCAAwC,CAAC;AAChD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,6BAA6B,CAAC;AAE9D,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,EAAE,MAAM,CAAC;IACjB,GAAG,EAAE,MAAM,CAAC;IACZ,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,YAAY,CAAC,EAAE,CAAC,GAAG,EAAE,QAAQ,KAAK,MAAM,CAAC;IAEzC;;;;;;OAMG;IACH,KAAK,CAAC,EAAE,kBAAkB,CAAC;IAC3B,SAAS,CAAC,EAAE,0BAA0B,CAAC;CACxC;AAED,MAAM,MAAM,kBAAkB,GAAG,QAAQ,GAAG,OAAO,GAAG,IAAI,GAAG,IAAI,CAAC;AAqKlE,eAAO,MAAM,WAAW;IACtB;;;OAGG;uBACgB;QAAE,KAAK,CAAC,EAAE,kBAAkB,CAAA;KAAE,GAAG,IAAI;IAKxD;;;;OAIG;iBACgB,MAAM,eAAe,MAAM,gBAAgB,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAYvF;;OAEG;yBACwB,MAAM,eAAe,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAQzE;;;OAGG;cACa,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAQxC;;OAEG;eACc,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAKvC;;OAEG;qBACa,gBAAgB,GAAqB,UAAU;EAqF/D,CAAC"}
|
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
import { Cache } from '../cache/Cache.js';
|
|
7
7
|
import { Env } from '../config/env.js';
|
|
8
8
|
import { Logger } from '../config/logger.js';
|
|
9
|
+
import { respondWithMiddlewareFailure, } from './MiddlewareFailureResponder.js';
|
|
9
10
|
const createMemoryStore = () => {
|
|
10
11
|
const entries = new Map();
|
|
11
12
|
let nextCleanupAt = Date.now() + 60_000;
|
|
@@ -257,10 +258,15 @@ export const RateLimiter = Object.freeze({
|
|
|
257
258
|
// Check limit
|
|
258
259
|
if (count > config.max) {
|
|
259
260
|
Logger.warn(`Rate limit exceeded for IP: ${key}`);
|
|
260
|
-
res
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
261
|
+
await respondWithMiddlewareFailure(req, res, config.onFailure, {
|
|
262
|
+
middleware: 'rateLimit',
|
|
263
|
+
reason: 'rate_limit_exceeded',
|
|
264
|
+
statusCode: config.statusCode ?? 429,
|
|
265
|
+
message: config.message ?? 'Too many requests',
|
|
266
|
+
body: {
|
|
267
|
+
error: 'Too Many Requests',
|
|
268
|
+
message: config.message,
|
|
269
|
+
},
|
|
264
270
|
});
|
|
265
271
|
return;
|
|
266
272
|
}
|
|
@@ -1,12 +1,17 @@
|
|
|
1
|
+
import { type MiddlewareFailureResponder } from './MiddlewareFailureResponder';
|
|
1
2
|
import type { Middleware } from './MiddlewareStack';
|
|
2
3
|
import type { ISchema, TypedSchema } from '../validation/Validator';
|
|
4
|
+
type ValidationMiddlewareOptions = Readonly<{
|
|
5
|
+
onFailure?: MiddlewareFailureResponder;
|
|
6
|
+
middlewareKey?: string;
|
|
7
|
+
}>;
|
|
3
8
|
type FieldSanitizers = Readonly<Record<string, (value: unknown) => unknown>>;
|
|
4
9
|
export declare const ValidationMiddleware: Readonly<{
|
|
5
|
-
create(schema: ISchema): Middleware;
|
|
6
|
-
createBody<TSchema extends TypedSchema<unknown>>(schema: TSchema): Middleware;
|
|
7
|
-
createBodyWithSanitization<TSchema extends TypedSchema<unknown>>(schema: TSchema, sanitizers?: FieldSanitizers): Middleware;
|
|
8
|
-
createQuery<TSchema extends TypedSchema<unknown>>(schema: TSchema): Middleware;
|
|
9
|
-
createParams<TSchema extends TypedSchema<unknown>>(schema: TSchema): Middleware;
|
|
10
|
+
create(schema: ISchema, options?: ValidationMiddlewareOptions): Middleware;
|
|
11
|
+
createBody<TSchema extends TypedSchema<unknown>>(schema: TSchema, options?: ValidationMiddlewareOptions): Middleware;
|
|
12
|
+
createBodyWithSanitization<TSchema extends TypedSchema<unknown>>(schema: TSchema, sanitizers?: FieldSanitizers, options?: ValidationMiddlewareOptions): Middleware;
|
|
13
|
+
createQuery<TSchema extends TypedSchema<unknown>>(schema: TSchema, options?: ValidationMiddlewareOptions): Middleware;
|
|
14
|
+
createParams<TSchema extends TypedSchema<unknown>>(schema: TSchema, options?: ValidationMiddlewareOptions): Middleware;
|
|
10
15
|
/**
|
|
11
16
|
* Create body validation middleware with bulletproof sanitization error handling.
|
|
12
17
|
* Automatically converts SanitizerError to 422 validation response.
|
|
@@ -19,7 +24,7 @@ export declare const ValidationMiddleware: Readonly<{
|
|
|
19
24
|
* @param sanitizers - Optional field sanitizers to apply before validation
|
|
20
25
|
* @returns Middleware with bulletproof error handling
|
|
21
26
|
*/
|
|
22
|
-
createBodyWithBulletproofSanitization<TSchema extends TypedSchema<unknown>>(schema: TSchema, sanitizers?: FieldSanitizers): Middleware;
|
|
27
|
+
createBodyWithBulletproofSanitization<TSchema extends TypedSchema<unknown>>(schema: TSchema, sanitizers?: FieldSanitizers, options?: ValidationMiddlewareOptions): Middleware;
|
|
23
28
|
}>;
|
|
24
29
|
export {};
|
|
25
30
|
//# sourceMappingURL=ValidationMiddleware.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ValidationMiddleware.d.ts","sourceRoot":"","sources":["../../../src/middleware/ValidationMiddleware.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,6BAA6B,CAAC;AAE9D,OAAO,KAAK,EAAe,OAAO,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAC;
|
|
1
|
+
{"version":3,"file":"ValidationMiddleware.d.ts","sourceRoot":"","sources":["../../../src/middleware/ValidationMiddleware.ts"],"names":[],"mappings":"AAIA,OAAO,EAEL,KAAK,0BAA0B,EAChC,MAAM,wCAAwC,CAAC;AAChD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,6BAA6B,CAAC;AAE9D,OAAO,KAAK,EAAe,OAAO,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAC;AAI/E,KAAK,2BAA2B,GAAG,QAAQ,CAAC;IAC1C,SAAS,CAAC,EAAE,0BAA0B,CAAC;IACvC,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB,CAAC,CAAC;AAQH,KAAK,eAAe,GAAG,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,OAAO,CAAC,CAAC,CAAC;AA+H7E,eAAO,MAAM,oBAAoB;mBAChB,OAAO,YAAW,2BAA2B,GAAQ,UAAU;eAwBnE,OAAO,SAAS,WAAW,CAAC,OAAO,CAAC,UACrC,OAAO,YACN,2BAA2B,GACnC,UAAU;+BA0Bc,OAAO,SAAS,WAAW,CAAC,OAAO,CAAC,UACrD,OAAO,eACF,eAAe,YACnB,2BAA2B,GACnC,UAAU;gBA6BD,OAAO,SAAS,WAAW,CAAC,OAAO,CAAC,UACtC,OAAO,YACN,2BAA2B,GACnC,UAAU;iBAeA,OAAO,SAAS,WAAW,CAAC,OAAO,CAAC,UACvC,OAAO,YACN,2BAA2B,GACnC,UAAU;IAeb;;;;;;;;;;;OAWG;0CACmC,OAAO,SAAS,WAAW,CAAC,OAAO,CAAC,UAChE,OAAO,eACF,eAAe,YACnB,2BAA2B,GACnC,UAAU;EA4Cb,CAAC"}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { Env } from '../config/env.js';
|
|
2
2
|
import { Logger } from '../config/logger.js';
|
|
3
|
+
import { respondWithMiddlewareFailure, } from './MiddlewareFailureResponder.js';
|
|
3
4
|
import { Xss } from '../security/Xss.js';
|
|
4
5
|
import { Validator } from '../validation/Validator.js';
|
|
5
6
|
const toRecord = (value) => {
|
|
@@ -73,7 +74,7 @@ const getBodyForValidation = (req) => {
|
|
|
73
74
|
const raw = safeCall(() => req.getBody?.());
|
|
74
75
|
return toBodyRecord(raw);
|
|
75
76
|
};
|
|
76
|
-
const handleValidationError = (res, error) => {
|
|
77
|
+
const handleValidationError = async (req, res, error, options) => {
|
|
77
78
|
// Temporary: log validation error details to help debugging failing requests.
|
|
78
79
|
// Remove this detailed debug logging once the issue is investigated.
|
|
79
80
|
Logger.warn('Validation failed');
|
|
@@ -88,21 +89,42 @@ const handleValidationError = (res, error) => {
|
|
|
88
89
|
// best-effort: fall back to direct log
|
|
89
90
|
Logger.debug('[Validation] errors (toObject threw):', err);
|
|
90
91
|
}
|
|
91
|
-
|
|
92
|
+
await respondWithMiddlewareFailure(req, res, options.onFailure, {
|
|
93
|
+
middleware: options.middlewareKey ?? 'validation',
|
|
94
|
+
reason: 'validation_error',
|
|
95
|
+
statusCode: 422,
|
|
96
|
+
message: 'Validation failed',
|
|
97
|
+
body: { errors: err.toObject() },
|
|
98
|
+
error,
|
|
99
|
+
});
|
|
92
100
|
return;
|
|
93
101
|
}
|
|
94
102
|
// Fallback: log raw error
|
|
95
103
|
Logger.debug('[Validation] error:', err);
|
|
96
|
-
|
|
104
|
+
await respondWithMiddlewareFailure(req, res, options.onFailure, {
|
|
105
|
+
middleware: options.middlewareKey ?? 'validation',
|
|
106
|
+
reason: 'invalid_request_body',
|
|
107
|
+
statusCode: 400,
|
|
108
|
+
message: 'Invalid request body',
|
|
109
|
+
body: { error: 'Invalid request body' },
|
|
110
|
+
error,
|
|
111
|
+
});
|
|
97
112
|
}
|
|
98
113
|
catch (error_) {
|
|
99
114
|
// Ensure we don't throw while handling validation errors
|
|
100
115
|
Logger.debug('[Validation] failed to log error details:', error_);
|
|
101
|
-
|
|
116
|
+
await respondWithMiddlewareFailure(req, res, options.onFailure, {
|
|
117
|
+
middleware: options.middlewareKey ?? 'validation',
|
|
118
|
+
reason: 'invalid_request_body',
|
|
119
|
+
statusCode: 400,
|
|
120
|
+
message: 'Invalid request body',
|
|
121
|
+
body: { error: 'Invalid request body' },
|
|
122
|
+
error,
|
|
123
|
+
});
|
|
102
124
|
}
|
|
103
125
|
};
|
|
104
126
|
export const ValidationMiddleware = Object.freeze({
|
|
105
|
-
create(schema) {
|
|
127
|
+
create(schema, options = {}) {
|
|
106
128
|
return async (req, res, next) => {
|
|
107
129
|
const method = req.getMethod();
|
|
108
130
|
if (method === 'GET' || method === 'DELETE') {
|
|
@@ -120,11 +142,11 @@ export const ValidationMiddleware = Object.freeze({
|
|
|
120
142
|
await next();
|
|
121
143
|
}
|
|
122
144
|
catch (error) {
|
|
123
|
-
handleValidationError(res, error);
|
|
145
|
+
await handleValidationError(req, res, error, options);
|
|
124
146
|
}
|
|
125
147
|
};
|
|
126
148
|
},
|
|
127
|
-
createBody(schema) {
|
|
149
|
+
createBody(schema, options = {}) {
|
|
128
150
|
return async (req, res, next) => {
|
|
129
151
|
const method = req.getMethod();
|
|
130
152
|
if (method === 'GET' || method === 'DELETE') {
|
|
@@ -142,11 +164,11 @@ export const ValidationMiddleware = Object.freeze({
|
|
|
142
164
|
await next();
|
|
143
165
|
}
|
|
144
166
|
catch (error) {
|
|
145
|
-
handleValidationError(res, error);
|
|
167
|
+
await handleValidationError(req, res, error, options);
|
|
146
168
|
}
|
|
147
169
|
};
|
|
148
170
|
},
|
|
149
|
-
createBodyWithSanitization(schema, sanitizers) {
|
|
171
|
+
createBodyWithSanitization(schema, sanitizers, options = {}) {
|
|
150
172
|
return async (req, res, next) => {
|
|
151
173
|
const method = req.getMethod();
|
|
152
174
|
if (method === 'GET' || method === 'DELETE') {
|
|
@@ -165,11 +187,11 @@ export const ValidationMiddleware = Object.freeze({
|
|
|
165
187
|
await next();
|
|
166
188
|
}
|
|
167
189
|
catch (error) {
|
|
168
|
-
handleValidationError(res, error);
|
|
190
|
+
await handleValidationError(req, res, error, options);
|
|
169
191
|
}
|
|
170
192
|
};
|
|
171
193
|
},
|
|
172
|
-
createQuery(schema) {
|
|
194
|
+
createQuery(schema, options = {}) {
|
|
173
195
|
return async (req, res, next) => {
|
|
174
196
|
try {
|
|
175
197
|
const query = toRecord(req.getQuery());
|
|
@@ -178,11 +200,11 @@ export const ValidationMiddleware = Object.freeze({
|
|
|
178
200
|
await next();
|
|
179
201
|
}
|
|
180
202
|
catch (error) {
|
|
181
|
-
handleValidationError(res, error);
|
|
203
|
+
await handleValidationError(req, res, error, options);
|
|
182
204
|
}
|
|
183
205
|
};
|
|
184
206
|
},
|
|
185
|
-
createParams(schema) {
|
|
207
|
+
createParams(schema, options = {}) {
|
|
186
208
|
return async (req, res, next) => {
|
|
187
209
|
try {
|
|
188
210
|
const params = toRecord(req.getParams());
|
|
@@ -191,7 +213,7 @@ export const ValidationMiddleware = Object.freeze({
|
|
|
191
213
|
await next();
|
|
192
214
|
}
|
|
193
215
|
catch (error) {
|
|
194
|
-
handleValidationError(res, error);
|
|
216
|
+
await handleValidationError(req, res, error, options);
|
|
195
217
|
}
|
|
196
218
|
};
|
|
197
219
|
},
|
|
@@ -207,7 +229,7 @@ export const ValidationMiddleware = Object.freeze({
|
|
|
207
229
|
* @param sanitizers - Optional field sanitizers to apply before validation
|
|
208
230
|
* @returns Middleware with bulletproof error handling
|
|
209
231
|
*/
|
|
210
|
-
createBodyWithBulletproofSanitization(schema, sanitizers) {
|
|
232
|
+
createBodyWithBulletproofSanitization(schema, sanitizers, options = {}) {
|
|
211
233
|
return async (req, res, next) => {
|
|
212
234
|
const method = req.getMethod();
|
|
213
235
|
if (method === 'GET' || method === 'DELETE') {
|
|
@@ -228,14 +250,21 @@ export const ValidationMiddleware = Object.freeze({
|
|
|
228
250
|
catch (error) {
|
|
229
251
|
// Handle SanitizerError by converting to validation error format
|
|
230
252
|
if (isSanitizerError(error)) {
|
|
231
|
-
res.
|
|
232
|
-
|
|
233
|
-
|
|
253
|
+
await respondWithMiddlewareFailure(req, res, options.onFailure, {
|
|
254
|
+
middleware: options.middlewareKey ?? 'validation',
|
|
255
|
+
reason: 'sanitization_error',
|
|
256
|
+
statusCode: 422,
|
|
257
|
+
message: error.message,
|
|
258
|
+
body: {
|
|
259
|
+
errors: {
|
|
260
|
+
sanitization: [error.message],
|
|
261
|
+
},
|
|
234
262
|
},
|
|
263
|
+
error,
|
|
235
264
|
});
|
|
236
265
|
return;
|
|
237
266
|
}
|
|
238
|
-
handleValidationError(res, error);
|
|
267
|
+
await handleValidationError(req, res, error, options);
|
|
239
268
|
}
|
|
240
269
|
};
|
|
241
270
|
},
|
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
export * from './CsrfMiddleware';
|
|
6
6
|
export * from './ErrorHandlerMiddleware';
|
|
7
7
|
export * from './LoggingMiddleware';
|
|
8
|
+
export * from './MiddlewareFailureResponder';
|
|
8
9
|
export * from './MiddlewareStack';
|
|
9
10
|
export * from './RateLimiter';
|
|
10
11
|
export * from './SecurityMiddleware';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/middleware/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,cAAc,4BAA4B,CAAC;AAC3C,cAAc,oCAAoC,CAAC;AACnD,cAAc,+BAA+B,CAAC;AAC9C,cAAc,6BAA6B,CAAC;AAC5C,cAAc,yBAAyB,CAAC;AACxC,cAAc,gCAAgC,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/middleware/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,cAAc,4BAA4B,CAAC;AAC3C,cAAc,oCAAoC,CAAC;AACnD,cAAc,+BAA+B,CAAC;AAC9C,cAAc,wCAAwC,CAAC;AACvD,cAAc,6BAA6B,CAAC;AAC5C,cAAc,yBAAyB,CAAC;AACxC,cAAc,gCAAgC,CAAC"}
|
package/src/middleware/index.js
CHANGED
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
export * from './CsrfMiddleware.js';
|
|
6
6
|
export * from './ErrorHandlerMiddleware.js';
|
|
7
7
|
export * from './LoggingMiddleware.js';
|
|
8
|
+
export * from './MiddlewareFailureResponder.js';
|
|
8
9
|
export * from './MiddlewareStack.js';
|
|
9
10
|
export * from './RateLimiter.js';
|
|
10
11
|
export * from './SecurityMiddleware.js';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"WorkersModule.d.ts","sourceRoot":"","sources":["../../../src/runtime/WorkersModule.ts"],"names":[],"mappings":"AAOA,KAAK,aAAa,GAAG,cAAc,mBAAmB,CAAC,CAAC;AACxD,KAAK,kBAAkB,GAAG,cAAc,yBAAyB,CAAC,CAAC;
|
|
1
|
+
{"version":3,"file":"WorkersModule.d.ts","sourceRoot":"","sources":["../../../src/runtime/WorkersModule.ts"],"names":[],"mappings":"AAOA,KAAK,aAAa,GAAG,cAAc,mBAAmB,CAAC,CAAC;AACxD,KAAK,kBAAkB,GAAG,cAAc,yBAAyB,CAAC,CAAC;AA8WnE,eAAO,MAAM,iBAAiB,QAAa,OAAO,CAAC,aAAa,CAwB/D,CAAC;AA4CF,eAAO,MAAM,sBAAsB,QAAa,OAAO,CAAC,kBAAkB,CAkBzE,CAAC"}
|
|
@@ -268,6 +268,7 @@ const isMissingOptionalWorkersModuleError = (error) => {
|
|
|
268
268
|
});
|
|
269
269
|
};
|
|
270
270
|
const handleImportFailure = async (error) => {
|
|
271
|
+
let finalError = error;
|
|
271
272
|
if (shouldRetryAfterFailure(error)) {
|
|
272
273
|
patchAfterFailureAttempted = true;
|
|
273
274
|
const { replacements, filesChanged } = patchWorkersDist();
|
|
@@ -281,7 +282,7 @@ const handleImportFailure = async (error) => {
|
|
|
281
282
|
return await workersModulePromise;
|
|
282
283
|
}
|
|
283
284
|
catch (retryError) {
|
|
284
|
-
|
|
285
|
+
finalError = retryError;
|
|
285
286
|
}
|
|
286
287
|
}
|
|
287
288
|
}
|
|
@@ -290,12 +291,12 @@ const handleImportFailure = async (error) => {
|
|
|
290
291
|
workersModulePromise = Promise.resolve(localFallback);
|
|
291
292
|
return localFallback;
|
|
292
293
|
}
|
|
293
|
-
if (isMissingOptionalWorkersModuleError(
|
|
294
|
+
if (isMissingOptionalWorkersModuleError(finalError)) {
|
|
294
295
|
Logger.info('Optional @zintrust/workers package is unavailable; worker routes are disabled.');
|
|
295
296
|
workersModulePromise = Promise.resolve(createDisabledWorkersModule());
|
|
296
297
|
return workersModulePromise;
|
|
297
298
|
}
|
|
298
|
-
throw
|
|
299
|
+
throw finalError;
|
|
299
300
|
};
|
|
300
301
|
const tryLocalFallback = async () => {
|
|
301
302
|
const localFallback = await importLocalWorkersModule();
|
package/src/security/Xss.d.ts
CHANGED
|
@@ -2,8 +2,8 @@
|
|
|
2
2
|
* XSS Sanitizer
|
|
3
3
|
* Recursive, zero-dependency input sanitization utility.
|
|
4
4
|
*
|
|
5
|
-
* This is intentionally conservative:
|
|
6
|
-
* - Strings: strip tags
|
|
5
|
+
* This is intentionally conservative for request-body handling:
|
|
6
|
+
* - Strings: strip markup tags but preserve plain text characters.
|
|
7
7
|
* - Arrays/Objects: sanitize recursively.
|
|
8
8
|
*/
|
|
9
9
|
export interface IXss {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Xss.d.ts","sourceRoot":"","sources":["../../../src/security/Xss.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;
|
|
1
|
+
{"version":3,"file":"Xss.d.ts","sourceRoot":"","sources":["../../../src/security/Xss.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAsDH,MAAM,WAAW,IAAI;IACnB,QAAQ,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAAC;CACnC;AAED,eAAO,MAAM,GAAG,EAAE,IAIhB,CAAC;AAEH,eAAe,GAAG,CAAC"}
|
package/src/security/Xss.js
CHANGED
|
@@ -2,11 +2,10 @@
|
|
|
2
2
|
* XSS Sanitizer
|
|
3
3
|
* Recursive, zero-dependency input sanitization utility.
|
|
4
4
|
*
|
|
5
|
-
* This is intentionally conservative:
|
|
6
|
-
* - Strings: strip tags
|
|
5
|
+
* This is intentionally conservative for request-body handling:
|
|
6
|
+
* - Strings: strip markup tags but preserve plain text characters.
|
|
7
7
|
* - Arrays/Objects: sanitize recursively.
|
|
8
8
|
*/
|
|
9
|
-
import { XssProtection } from './XssProtection.js';
|
|
10
9
|
const stripTags = (value) => {
|
|
11
10
|
// Remove all HTML tags in linear time (no regex backtracking / ReDoS risk).
|
|
12
11
|
let out = '';
|
|
@@ -28,7 +27,7 @@ const stripTags = (value) => {
|
|
|
28
27
|
};
|
|
29
28
|
const sanitizeRecursive = (input, seen) => {
|
|
30
29
|
if (typeof input === 'string') {
|
|
31
|
-
return
|
|
30
|
+
return stripTags(input);
|
|
32
31
|
}
|
|
33
32
|
if (Array.isArray(input)) {
|
|
34
33
|
if (seen.has(input))
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { MiddlewareFailureResponder } from '@zintrust/core';
|
|
2
|
+
|
|
3
|
+
export const authFailureResponder: MiddlewareFailureResponder = async (_req, res, context) => {
|
|
4
|
+
res.setStatus(context.statusCode).json({
|
|
5
|
+
error: {
|
|
6
|
+
code: context.reason,
|
|
7
|
+
message: context.message,
|
|
8
|
+
},
|
|
9
|
+
});
|
|
10
|
+
};
|
|
@@ -9,6 +9,12 @@ import type { MiddlewaresType } from '@zintrust/core';
|
|
|
9
9
|
* 2. Import it below.
|
|
10
10
|
* 3. Register route middleware under `route` or append global middleware under `global`.
|
|
11
11
|
* 4. Use the route key in `routes/*.ts`.
|
|
12
|
+
* 5. Use `responders` when you only want to reshape built-in failure payloads.
|
|
13
|
+
*
|
|
14
|
+
* Built-in middleware keys are overrideable by reusing the same key under `route`.
|
|
15
|
+
* For example, `route.jwt = MyJwtMiddleware` replaces the framework `jwt` middleware
|
|
16
|
+
* anywhere that key is used, including shared global slots such as `log`, `error`,
|
|
17
|
+
* `security`, `rateLimit`, `csrf`, and `sanitizeBody`.
|
|
12
18
|
*
|
|
13
19
|
* For custom route keys, extend the framework type locally in your route file:
|
|
14
20
|
* `type AppMiddlewareKey = MiddlewareKey | 'yourMiddleware';`
|
|
@@ -16,6 +22,8 @@ import type { MiddlewaresType } from '@zintrust/core';
|
|
|
16
22
|
|
|
17
23
|
// Example custom middleware import:
|
|
18
24
|
// import { AuthMiddleware } from '@app/Middleware/AuthMiddleware';
|
|
25
|
+
// import { authFailureResponder } from '@app/Middleware/AuthFailureResponder';
|
|
26
|
+
// import { JwtAuthOverrideMiddleware } from '@app/Middleware/JwtAuthOverrideMiddleware';
|
|
19
27
|
|
|
20
28
|
export default {
|
|
21
29
|
skipPaths: Env.get('CSRF_SKIP_PATHS', '')
|
|
@@ -37,10 +45,20 @@ export default {
|
|
|
37
45
|
max: 20,
|
|
38
46
|
message: 'Too many user mutation requests, please try again later.',
|
|
39
47
|
},
|
|
48
|
+
responders: {
|
|
49
|
+
// auth: authFailureResponder,
|
|
50
|
+
// jwt: authFailureResponder,
|
|
51
|
+
// bulletproof: authFailureResponder,
|
|
52
|
+
// csrf: authFailureResponder,
|
|
53
|
+
// rateLimit: authFailureResponder,
|
|
54
|
+
// error: authFailureResponder,
|
|
55
|
+
},
|
|
40
56
|
global: [
|
|
41
57
|
// AuthMiddleware,
|
|
42
58
|
],
|
|
43
59
|
route: {
|
|
44
60
|
// authMiddleware: AuthMiddleware,
|
|
61
|
+
// Plug-and-play built-in override example:
|
|
62
|
+
// jwt: JwtAuthOverrideMiddleware,
|
|
45
63
|
},
|
|
46
64
|
} as MiddlewaresType;
|