@zintrust/core 0.4.18 → 0.4.20
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/functions/cloudflare.d.ts.map +1 -1
- package/src/functions/cloudflare.js +28 -12
- package/src/http/Kernel.d.ts.map +1 -1
- package/src/http/Kernel.js +27 -1
- 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/SecurityMiddleware.d.ts +1 -1
- package/src/middleware/SecurityMiddleware.d.ts.map +1 -1
- package/src/middleware/SecurityMiddleware.js +38 -7
- 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/RuntimeAdapter.d.ts.map +1 -1
- package/src/runtime/RuntimeAdapter.js +12 -2
- 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
|
@@ -3,6 +3,7 @@ import { Logger } from '../config/logger.js';
|
|
|
3
3
|
import ErrorRouting from '../routes/error.js';
|
|
4
4
|
import { ErrorResponse } from '../http/ErrorResponse.js';
|
|
5
5
|
import { RequestContext } from '../http/RequestContext.js';
|
|
6
|
+
import { respondWithMiddlewareFailure, } from './MiddlewareFailureResponder.js';
|
|
6
7
|
const isWritableEnded = (res) => {
|
|
7
8
|
if (typeof res.getRaw !== 'function')
|
|
8
9
|
return false;
|
|
@@ -22,7 +23,7 @@ const shouldHideStackFromResponse = (error) => {
|
|
|
22
23
|
candidate.statusCode === 404);
|
|
23
24
|
};
|
|
24
25
|
export const ErrorHandlerMiddleware = Object.freeze({
|
|
25
|
-
create() {
|
|
26
|
+
create(options = {}) {
|
|
26
27
|
return async (req, res, next) => {
|
|
27
28
|
try {
|
|
28
29
|
await next();
|
|
@@ -40,7 +41,16 @@ export const ErrorHandlerMiddleware = Object.freeze({
|
|
|
40
41
|
await handleInternalServerErrorWithWrappers(req, res, error, requestId);
|
|
41
42
|
}
|
|
42
43
|
else {
|
|
43
|
-
|
|
44
|
+
const body = ErrorResponse.internalServerError('Internal server error', requestId, includeStack ? error?.stack : undefined);
|
|
45
|
+
await respondWithMiddlewareFailure(req, res, options.onFailure, {
|
|
46
|
+
middleware: 'error',
|
|
47
|
+
reason: 'unhandled_exception',
|
|
48
|
+
statusCode: 500,
|
|
49
|
+
message: 'Internal server error',
|
|
50
|
+
body,
|
|
51
|
+
error,
|
|
52
|
+
requestId,
|
|
53
|
+
});
|
|
44
54
|
}
|
|
45
55
|
}
|
|
46
56
|
}
|
|
@@ -1,8 +1,10 @@
|
|
|
1
|
+
import { type MiddlewareFailureResponder } from './MiddlewareFailureResponder';
|
|
1
2
|
import type { Middleware } from './MiddlewareStack';
|
|
2
3
|
import type { JwtAlgorithm } from '../security/JwtManager';
|
|
3
4
|
export interface JwtAuthOptions {
|
|
4
5
|
algorithm?: JwtAlgorithm;
|
|
5
6
|
secret?: string;
|
|
7
|
+
onUnauthorized?: MiddlewareFailureResponder;
|
|
6
8
|
}
|
|
7
9
|
export declare const JwtAuthMiddleware: Readonly<{
|
|
8
10
|
create(options?: JwtAuthOptions): Middleware;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"JwtAuthMiddleware.d.ts","sourceRoot":"","sources":["../../../src/middleware/JwtAuthMiddleware.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,6BAA6B,CAAC;AAC9D,OAAO,KAAK,EAAe,YAAY,EAAE,MAAM,sBAAsB,CAAC;AAItE,MAAM,WAAW,cAAc;IAC7B,SAAS,CAAC,EAAE,YAAY,CAAC;IACzB,MAAM,CAAC,EAAE,MAAM,CAAC;
|
|
1
|
+
{"version":3,"file":"JwtAuthMiddleware.d.ts","sourceRoot":"","sources":["../../../src/middleware/JwtAuthMiddleware.ts"],"names":[],"mappings":"AAKA,OAAO,EAEL,KAAK,0BAA0B,EAChC,MAAM,wCAAwC,CAAC;AAChD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,6BAA6B,CAAC;AAC9D,OAAO,KAAK,EAAe,YAAY,EAAE,MAAM,sBAAsB,CAAC;AAItE,MAAM,WAAW,cAAc;IAC7B,SAAS,CAAC,EAAE,YAAY,CAAC;IACzB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,cAAc,CAAC,EAAE,0BAA0B,CAAC;CAC7C;AAuCD,eAAO,MAAM,iBAAiB;qBACZ,cAAc,GAAQ,UAAU;EA6FhD,CAAC;AAEH,eAAe,iBAAiB,CAAC"}
|
|
@@ -1,8 +1,18 @@
|
|
|
1
1
|
import { Logger } from '../config/logger.js';
|
|
2
2
|
import { securityConfig } from '../config/security.js';
|
|
3
3
|
import { RequestContext } from '../http/RequestContext.js';
|
|
4
|
+
import { respondWithMiddlewareFailure, } from './MiddlewareFailureResponder.js';
|
|
4
5
|
import { JwtManager } from '../security/JwtManager.js';
|
|
5
6
|
import { JwtSessions } from '../security/JwtSessions.js';
|
|
7
|
+
const getJwtFailureReason = (error) => {
|
|
8
|
+
if (typeof error !== 'object' || error === null)
|
|
9
|
+
return 'invalid_token';
|
|
10
|
+
const candidate = error;
|
|
11
|
+
if (candidate.name === 'TokenExpiredError' || candidate.code === 'TOKEN_EXPIRED') {
|
|
12
|
+
return 'expired_token';
|
|
13
|
+
}
|
|
14
|
+
return 'invalid_token';
|
|
15
|
+
};
|
|
6
16
|
const getHeaderValue = (value) => {
|
|
7
17
|
if (Array.isArray(value))
|
|
8
18
|
return typeof value[0] === 'string' ? value[0] : '';
|
|
@@ -44,19 +54,37 @@ export const JwtAuthMiddleware = Object.freeze({
|
|
|
44
54
|
}
|
|
45
55
|
const authorizationHeader = getHeaderValue(req.getHeader('authorization'));
|
|
46
56
|
if (authorizationHeader === '') {
|
|
47
|
-
|
|
57
|
+
await respondWithMiddlewareFailure(req, res, options.onUnauthorized, {
|
|
58
|
+
middleware: 'jwt',
|
|
59
|
+
reason: 'missing_authorization_header',
|
|
60
|
+
statusCode: 401,
|
|
61
|
+
message: 'Missing authorization header',
|
|
62
|
+
body: { error: 'Missing authorization header' },
|
|
63
|
+
});
|
|
48
64
|
return;
|
|
49
65
|
}
|
|
50
66
|
const token = getBearerToken(authorizationHeader);
|
|
51
67
|
if (token === null) {
|
|
52
|
-
|
|
68
|
+
await respondWithMiddlewareFailure(req, res, options.onUnauthorized, {
|
|
69
|
+
middleware: 'jwt',
|
|
70
|
+
reason: 'invalid_authorization_header_format',
|
|
71
|
+
statusCode: 401,
|
|
72
|
+
message: 'Invalid authorization header format',
|
|
73
|
+
body: { error: 'Invalid authorization header format' },
|
|
74
|
+
});
|
|
53
75
|
return;
|
|
54
76
|
}
|
|
55
77
|
try {
|
|
56
78
|
const payload = jwt.verify(token, algorithm);
|
|
57
79
|
// Session allowlist: token must exist in the session store to be accepted.
|
|
58
80
|
if (!(await JwtSessions.isActive(token))) {
|
|
59
|
-
|
|
81
|
+
await respondWithMiddlewareFailure(req, res, options.onUnauthorized, {
|
|
82
|
+
middleware: 'jwt',
|
|
83
|
+
reason: 'inactive_session',
|
|
84
|
+
statusCode: 401,
|
|
85
|
+
message: 'Invalid or expired token',
|
|
86
|
+
body: { error: 'Invalid or expired token' },
|
|
87
|
+
});
|
|
60
88
|
return;
|
|
61
89
|
}
|
|
62
90
|
req.user = payload;
|
|
@@ -77,7 +105,14 @@ export const JwtAuthMiddleware = Object.freeze({
|
|
|
77
105
|
algorithm,
|
|
78
106
|
error: error instanceof Error ? error.message : String(error),
|
|
79
107
|
});
|
|
80
|
-
|
|
108
|
+
await respondWithMiddlewareFailure(req, res, options.onUnauthorized, {
|
|
109
|
+
middleware: 'jwt',
|
|
110
|
+
reason: getJwtFailureReason(error),
|
|
111
|
+
statusCode: 401,
|
|
112
|
+
message: 'Invalid or expired token',
|
|
113
|
+
body: { error: 'Invalid or expired token' },
|
|
114
|
+
error,
|
|
115
|
+
});
|
|
81
116
|
}
|
|
82
117
|
};
|
|
83
118
|
},
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { IRequest } from '../http/Request';
|
|
2
|
+
import type { IResponse } from '../http/Response';
|
|
3
|
+
export type MiddlewareFailureContext = Readonly<{
|
|
4
|
+
middleware: string;
|
|
5
|
+
reason: string;
|
|
6
|
+
statusCode: number;
|
|
7
|
+
message: string;
|
|
8
|
+
body: unknown;
|
|
9
|
+
error?: unknown;
|
|
10
|
+
requestId?: string;
|
|
11
|
+
}>;
|
|
12
|
+
export type MiddlewareFailureResponder = (req: IRequest, res: IResponse, context: MiddlewareFailureContext) => void | Promise<void>;
|
|
13
|
+
export declare const defaultMiddlewareFailureResponder: MiddlewareFailureResponder;
|
|
14
|
+
export declare const respondWithMiddlewareFailure: (req: IRequest, res: IResponse, responder: MiddlewareFailureResponder | undefined, context: MiddlewareFailureContext) => Promise<void>;
|
|
15
|
+
//# sourceMappingURL=MiddlewareFailureResponder.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"MiddlewareFailureResponder.d.ts","sourceRoot":"","sources":["../../../src/middleware/MiddlewareFailureResponder.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AAC9C,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAEhD,MAAM,MAAM,wBAAwB,GAAG,QAAQ,CAAC;IAC9C,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,EAAE,MAAM,CAAC;IACnB,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,OAAO,CAAC;IACd,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,CAAC,CAAC;AAEH,MAAM,MAAM,0BAA0B,GAAG,CACvC,GAAG,EAAE,QAAQ,EACb,GAAG,EAAE,SAAS,EACd,OAAO,EAAE,wBAAwB,KAC9B,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;AAE1B,eAAO,MAAM,iCAAiC,EAAE,0BAgB/C,CAAC;AAEF,eAAO,MAAM,4BAA4B,GACvC,KAAK,QAAQ,EACb,KAAK,SAAS,EACd,WAAW,0BAA0B,GAAG,SAAS,EACjD,SAAS,wBAAwB,KAChC,OAAO,CAAC,IAAI,CAEd,CAAC"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { isObject } from '../helper/index.js';
|
|
2
|
+
export const defaultMiddlewareFailureResponder = (_req, res, context) => {
|
|
3
|
+
const statusTarget = res.setStatus(context.statusCode);
|
|
4
|
+
const responseTarget = isObject(statusTarget) ? statusTarget : res;
|
|
5
|
+
if (typeof responseTarget.json === 'function') {
|
|
6
|
+
responseTarget.json(context.body);
|
|
7
|
+
return;
|
|
8
|
+
}
|
|
9
|
+
if (typeof responseTarget.send === 'function') {
|
|
10
|
+
responseTarget.send(JSON.stringify(context.body));
|
|
11
|
+
}
|
|
12
|
+
};
|
|
13
|
+
export const respondWithMiddlewareFailure = async (req, res, responder, context) => {
|
|
14
|
+
await (responder ?? defaultMiddlewareFailureResponder)(req, res, context);
|
|
15
|
+
};
|
|
@@ -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 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SecurityMiddleware.d.ts","sourceRoot":"","sources":["../../../src/middleware/SecurityMiddleware.ts"],"names":[],"mappings":"AAAA;;;;GAIG;
|
|
1
|
+
{"version":3,"file":"SecurityMiddleware.d.ts","sourceRoot":"","sources":["../../../src/middleware/SecurityMiddleware.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAKH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,6BAA6B,CAAC;AAE9D,MAAM,WAAW,eAAe;IAC9B,IAAI,CAAC,EAAE;QACL,MAAM,CAAC,EAAE,MAAM,CAAC;QAChB,iBAAiB,CAAC,EAAE,OAAO,CAAC;QAC5B,OAAO,CAAC,EAAE,OAAO,CAAC;KACnB,CAAC;IACF,UAAU,CAAC,EAAE;QACX,MAAM,CAAC,EAAE,MAAM,GAAG,YAAY,CAAC;KAChC,CAAC;IACF,IAAI,CAAC,EAAE;QACL,MAAM,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC;QAC3B,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;QACnB,cAAc,CAAC,EAAE,MAAM,EAAE,CAAC;QAC1B,WAAW,CAAC,EAAE,OAAO,CAAC;QACtB,MAAM,CAAC,EAAE,MAAM,CAAC;KACjB,CAAC;IACF,GAAG,CAAC,EAAE;QACJ,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,CAAC;KACvC,CAAC;CACH;AAiID,eAAO,MAAM,kBAAkB;IAC7B;;OAEG;qBACa,eAAe,GAAQ,UAAU;EAgBjD,CAAC"}
|
|
@@ -3,6 +3,17 @@
|
|
|
3
3
|
* Implements standard security headers and CORS protection
|
|
4
4
|
* Zero-dependency implementation replacing helmet/cors
|
|
5
5
|
*/
|
|
6
|
+
import { securityConfig } from '../config/security.js';
|
|
7
|
+
const normalizeCorsList = (values, fallback) => {
|
|
8
|
+
const normalized = (values ?? [])
|
|
9
|
+
.map((value) => (typeof value === 'string' ? value.trim() : ''))
|
|
10
|
+
.filter((value) => value !== '');
|
|
11
|
+
return normalized.length > 0 ? normalized : fallback;
|
|
12
|
+
};
|
|
13
|
+
const resolveCorsOrigin = () => {
|
|
14
|
+
const origins = normalizeCorsList(securityConfig.cors.origins, ['*']);
|
|
15
|
+
return origins.includes('*') ? '*' : origins;
|
|
16
|
+
};
|
|
6
17
|
const DEFAULT_OPTIONS = {
|
|
7
18
|
hsts: {
|
|
8
19
|
maxAge: 15552000, // 180 days
|
|
@@ -13,13 +24,33 @@ const DEFAULT_OPTIONS = {
|
|
|
13
24
|
action: 'SAMEORIGIN',
|
|
14
25
|
},
|
|
15
26
|
cors: {
|
|
16
|
-
origin:
|
|
17
|
-
methods:
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
27
|
+
origin: resolveCorsOrigin(),
|
|
28
|
+
methods: normalizeCorsList(securityConfig.cors.methods, [
|
|
29
|
+
'GET',
|
|
30
|
+
'HEAD',
|
|
31
|
+
'PUT',
|
|
32
|
+
'PATCH',
|
|
33
|
+
'POST',
|
|
34
|
+
'DELETE',
|
|
35
|
+
]),
|
|
36
|
+
allowedHeaders: normalizeCorsList(securityConfig.cors.allowedHeaders, [
|
|
37
|
+
'Content-Type',
|
|
38
|
+
'Authorization',
|
|
39
|
+
'X-Requested-With',
|
|
40
|
+
'X-CSRF-Token',
|
|
41
|
+
]),
|
|
42
|
+
credentials: securityConfig.cors.credentials,
|
|
43
|
+
maxAge: securityConfig.cors.maxAge,
|
|
21
44
|
},
|
|
22
45
|
};
|
|
46
|
+
const mergeSecurityOptions = (options) => {
|
|
47
|
+
return {
|
|
48
|
+
hsts: { ...DEFAULT_OPTIONS.hsts, ...options.hsts },
|
|
49
|
+
frameguard: { ...DEFAULT_OPTIONS.frameguard, ...options.frameguard },
|
|
50
|
+
cors: { ...DEFAULT_OPTIONS.cors, ...options.cors },
|
|
51
|
+
csp: options.csp ?? DEFAULT_OPTIONS.csp,
|
|
52
|
+
};
|
|
53
|
+
};
|
|
23
54
|
function applyHsts(res, hsts) {
|
|
24
55
|
if (!hsts)
|
|
25
56
|
return;
|
|
@@ -73,7 +104,7 @@ function applyCors(req, res, cors) {
|
|
|
73
104
|
res.setHeader('Access-Control-Allow-Headers', cors.allowedHeaders.join(', '));
|
|
74
105
|
}
|
|
75
106
|
if (cors.credentials !== undefined) {
|
|
76
|
-
res.setHeader('Access-Control-Allow-Credentials', 'true');
|
|
107
|
+
res.setHeader('Access-Control-Allow-Credentials', cors.credentials ? 'true' : 'false');
|
|
77
108
|
}
|
|
78
109
|
if (cors.maxAge !== undefined) {
|
|
79
110
|
res.setHeader('Access-Control-Max-Age', cors.maxAge.toString());
|
|
@@ -90,7 +121,7 @@ export const SecurityMiddleware = Object.freeze({
|
|
|
90
121
|
* Create security middleware with options
|
|
91
122
|
*/
|
|
92
123
|
create(options = {}) {
|
|
93
|
-
const config =
|
|
124
|
+
const config = mergeSecurityOptions(options);
|
|
94
125
|
return async (req, res, next) => {
|
|
95
126
|
applyHsts(res, config.hsts);
|
|
96
127
|
applyFrameguard(res, config.frameguard);
|
|
@@ -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":"RuntimeAdapter.d.ts","sourceRoot":"","sources":["../../../src/runtime/RuntimeAdapter.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"RuntimeAdapter.d.ts","sourceRoot":"","sources":["../../../src/runtime/RuntimeAdapter.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAO7E,KAAK,KAAK,GAAG,MAAM,GAAG,MAAM,GAAG,cAAc,CAAC,UAAU,CAAC,GAAG,IAAI,CAAC;AAEjE;;GAEG;AACH,MAAM,MAAM,YAAY,GAAG,MAAM,CAAC;AAElC;;GAEG;AACH,MAAM,WAAW,eAAe;IAC9B,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC,CAAC;IAC3C,IAAI,CAAC,EAAE,KAAK,CAAC;IACb,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC,CAAC;IAC1C,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,MAAM,CAAC,EAAE,WAAW,CAAC;CACtB;AAED,MAAM,WAAW,gBAAgB;IAC/B,UAAU,EAAE,MAAM,CAAC;IACnB,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC,CAAC;IAC3C,IAAI,CAAC,EAAE,KAAK,CAAC;IACb,eAAe,CAAC,EAAE,OAAO,CAAC;CAC3B;AAED;;;GAGG;AACH,MAAM,WAAW,cAAc;IAC7B;;OAEG;IACH,QAAQ,EAAE,QAAQ,GAAG,QAAQ,GAAG,SAAS,GAAG,YAAY,GAAG,MAAM,CAAC;IAElE;;;OAGG;IACH,MAAM,CAAC,KAAK,EAAE,OAAO,EAAE,OAAO,CAAC,EAAE,OAAO,GAAG,OAAO,CAAC,gBAAgB,CAAC,CAAC;IAErE;;OAEG;IACH,YAAY,CAAC,KAAK,EAAE,OAAO,GAAG,eAAe,CAAC;IAE9C;;OAEG;IACH,cAAc,CAAC,QAAQ,EAAE,gBAAgB,GAAG,OAAO,CAAC;IAEpD;;OAEG;IACH,SAAS,IAAI;QACX,KAAK,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,OAAO,GAAG,IAAI,CAAC;QACzC,IAAI,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,OAAO,GAAG,IAAI,CAAC;QACxC,IAAI,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,OAAO,GAAG,IAAI,CAAC;QACxC,KAAK,CAAC,GAAG,EAAE,MAAM,EAAE,GAAG,CAAC,EAAE,KAAK,GAAG,IAAI,CAAC;KACvC,CAAC;IAEF;;OAEG;IACH,6BAA6B,IAAI,OAAO,CAAC;IAEzC;;OAEG;IACH,cAAc,IAAI;QAChB,OAAO,EAAE,MAAM,CAAC,UAAU,CAAC,UAAU,CAAC,CAAC;QACvC,OAAO,EAAE,MAAM,CAAC;QAChB,YAAY,EAAE,MAAM,CAAC;QACrB,MAAM,CAAC,EAAE,MAAM,CAAC;QAChB,MAAM,CAAC,EAAE,MAAM,CAAC;QAChB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;KACxB,CAAC;CACH;AAED;;GAEG;AACH,MAAM,MAAM,eAAe,GAAG,CAC5B,GAAG,EAAE,eAAe,EACpB,GAAG,EAAE,cAAc,EACnB,IAAI,EAAE,KAAK,KACR,OAAO,CAAC,IAAI,CAAC,CAAC;AAEnB;;GAEG;AACH,MAAM,WAAW,aAAa;IAC5B,OAAO,EAAE,eAAe,CAAC;IACzB,MAAM,CAAC,EAAE;QACP,KAAK,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,OAAO,GAAG,IAAI,CAAC;QACzC,IAAI,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,OAAO,GAAG,IAAI,CAAC;QACxC,IAAI,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,OAAO,GAAG,IAAI,CAAC;QACxC,KAAK,CAAC,GAAG,EAAE,MAAM,EAAE,GAAG,CAAC,EAAE,KAAK,GAAG,IAAI,CAAC;KACvC,CAAC;IACF,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED;;GAEG;AACH,MAAM,WAAW,aAAa;IAC5B,UAAU,EAAE,MAAM,CAAC;IACnB,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC,CAAC;IAC3C,IAAI,EAAE,KAAK,CAAC;IACZ,eAAe,EAAE,OAAO,CAAC;IACzB,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,aAAa,CAAC;IACvC,SAAS,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,EAAE,GAAG,aAAa,CAAC;IAChE,UAAU,CAAC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC,GAAG,aAAa,CAAC;IACtE,OAAO,CAAC,IAAI,EAAE,KAAK,EAAE,QAAQ,CAAC,EAAE,OAAO,GAAG,aAAa,CAAC;IACxD,OAAO,CAAC,IAAI,EAAE,OAAO,GAAG,aAAa,CAAC;IACtC,UAAU,IAAI,gBAAgB,CAAC;CAChC;AAED,eAAO,MAAM,YAAY;cACb,aAAa;EA0EvB,CAAC;AAEH;;GAEG;AACH,eAAO,MAAM,aAAa;uBACL,MAAM,WAAW,MAAM,YAAY,OAAO,GAAG,aAAa;EAW7E,CAAC;AAgGH,KAAK,OAAO,GAAG;IACb,UAAU,EAAE,MAAM,CAAC;IACnB,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC,CAAC;IAC3C,IAAI,EAAE,KAAK,CAAC;CACb,CAAC;AAkHF,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,eAAe,GAAG;IAC/D,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC7B,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC7B,YAAY,EAAE,OAAO,CAAC;CACvB,CAMA"}
|
|
@@ -159,8 +159,18 @@ const applyWriteHead = (responseData, statusCode, headers) => {
|
|
|
159
159
|
};
|
|
160
160
|
const resData = (responseData, request) => {
|
|
161
161
|
return {
|
|
162
|
-
statusCode
|
|
163
|
-
|
|
162
|
+
get statusCode() {
|
|
163
|
+
return responseData.statusCode;
|
|
164
|
+
},
|
|
165
|
+
set statusCode(value) {
|
|
166
|
+
responseData.statusCode = value;
|
|
167
|
+
},
|
|
168
|
+
get headers() {
|
|
169
|
+
return responseData.headers;
|
|
170
|
+
},
|
|
171
|
+
set headers(value) {
|
|
172
|
+
responseData.headers = value;
|
|
173
|
+
},
|
|
164
174
|
writeHead: function (statusCode, headers) {
|
|
165
175
|
this._writer = applyWriteHead(responseData, statusCode, headers);
|
|
166
176
|
// Handle abortion if signal is present
|
|
@@ -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"}
|