@noony-serverless/core 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +443 -0
- package/build/core/containerPool.d.ts +44 -0
- package/build/core/containerPool.js +103 -0
- package/build/core/core.d.ts +123 -0
- package/build/core/core.js +107 -0
- package/build/core/errors.d.ts +25 -0
- package/build/core/errors.js +59 -0
- package/build/core/handler.d.ts +72 -0
- package/build/core/handler.js +151 -0
- package/build/core/index.d.ts +8 -0
- package/build/core/index.js +24 -0
- package/build/core/logger.d.ts +42 -0
- package/build/core/logger.js +135 -0
- package/build/core/performanceMonitor.d.ts +73 -0
- package/build/core/performanceMonitor.js +189 -0
- package/build/index.d.ts +3 -0
- package/build/index.js +19 -0
- package/build/middlewares/authenticationMiddleware.d.ts +52 -0
- package/build/middlewares/authenticationMiddleware.js +204 -0
- package/build/middlewares/bodyParserMiddleware.d.ts +31 -0
- package/build/middlewares/bodyParserMiddleware.js +217 -0
- package/build/middlewares/bodyValidationMiddleware.d.ts +12 -0
- package/build/middlewares/bodyValidationMiddleware.js +34 -0
- package/build/middlewares/dependencyInjectionMiddleware.d.ts +14 -0
- package/build/middlewares/dependencyInjectionMiddleware.js +48 -0
- package/build/middlewares/errorHandlerMiddleware.d.ts +6 -0
- package/build/middlewares/errorHandlerMiddleware.js +64 -0
- package/build/middlewares/headerVariablesMiddleware.d.ts +8 -0
- package/build/middlewares/headerVariablesMiddleware.js +32 -0
- package/build/middlewares/httpAttributesMiddleware.d.ts +10 -0
- package/build/middlewares/httpAttributesMiddleware.js +71 -0
- package/build/middlewares/index.d.ts +14 -0
- package/build/middlewares/index.js +30 -0
- package/build/middlewares/queryParametersMiddleware.d.ts +8 -0
- package/build/middlewares/queryParametersMiddleware.js +51 -0
- package/build/middlewares/rateLimitingMiddleware.d.ts +157 -0
- package/build/middlewares/rateLimitingMiddleware.js +237 -0
- package/build/middlewares/responseWrapperMiddleware.d.ts +11 -0
- package/build/middlewares/responseWrapperMiddleware.js +34 -0
- package/build/middlewares/securityAuditMiddleware.d.ts +124 -0
- package/build/middlewares/securityAuditMiddleware.js +395 -0
- package/build/middlewares/securityHeadersMiddleware.d.ts +128 -0
- package/build/middlewares/securityHeadersMiddleware.js +183 -0
- package/build/middlewares/validationMiddleware.d.ts +9 -0
- package/build/middlewares/validationMiddleware.js +40 -0
- package/package.json +73 -0
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
import { BaseMiddleware, Context } from '../core';
|
|
2
|
+
export interface RateLimitOptions {
|
|
3
|
+
/**
|
|
4
|
+
* Maximum number of requests per window
|
|
5
|
+
* @default 100
|
|
6
|
+
*/
|
|
7
|
+
maxRequests?: number;
|
|
8
|
+
/**
|
|
9
|
+
* Time window in milliseconds
|
|
10
|
+
* @default 60000 (1 minute)
|
|
11
|
+
*/
|
|
12
|
+
windowMs?: number;
|
|
13
|
+
/**
|
|
14
|
+
* Function to generate rate limiting key
|
|
15
|
+
* @default Uses IP address
|
|
16
|
+
*/
|
|
17
|
+
keyGenerator?: (context: Context) => string;
|
|
18
|
+
/**
|
|
19
|
+
* Custom error message
|
|
20
|
+
* @default 'Too many requests, please try again later'
|
|
21
|
+
*/
|
|
22
|
+
message?: string;
|
|
23
|
+
/**
|
|
24
|
+
* HTTP status code for rate limit exceeded
|
|
25
|
+
* @default 429
|
|
26
|
+
*/
|
|
27
|
+
statusCode?: number;
|
|
28
|
+
/**
|
|
29
|
+
* Skip rate limiting for certain requests
|
|
30
|
+
*/
|
|
31
|
+
skip?: (context: Context) => boolean;
|
|
32
|
+
/**
|
|
33
|
+
* Headers to include in response
|
|
34
|
+
*/
|
|
35
|
+
headers?: boolean;
|
|
36
|
+
/**
|
|
37
|
+
* Different limits for different request types
|
|
38
|
+
*/
|
|
39
|
+
dynamicLimits?: {
|
|
40
|
+
[key: string]: {
|
|
41
|
+
maxRequests: number;
|
|
42
|
+
windowMs: number;
|
|
43
|
+
matcher: (context: Context) => boolean;
|
|
44
|
+
};
|
|
45
|
+
};
|
|
46
|
+
/**
|
|
47
|
+
* Storage backend (default: in-memory)
|
|
48
|
+
* Use Redis or other persistent storage in production
|
|
49
|
+
*/
|
|
50
|
+
store?: RateLimitStore;
|
|
51
|
+
}
|
|
52
|
+
export interface RateLimitStore {
|
|
53
|
+
increment(key: string, windowMs: number): Promise<{
|
|
54
|
+
count: number;
|
|
55
|
+
resetTime: number;
|
|
56
|
+
}>;
|
|
57
|
+
get(key: string): Promise<{
|
|
58
|
+
count: number;
|
|
59
|
+
resetTime: number;
|
|
60
|
+
} | null>;
|
|
61
|
+
reset(key: string): Promise<void>;
|
|
62
|
+
}
|
|
63
|
+
export interface RateLimitInfo {
|
|
64
|
+
limit: number;
|
|
65
|
+
current: number;
|
|
66
|
+
remaining: number;
|
|
67
|
+
resetTime: number;
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* In-memory rate limit store (use Redis in production)
|
|
71
|
+
*/
|
|
72
|
+
declare class MemoryStore implements RateLimitStore {
|
|
73
|
+
private store;
|
|
74
|
+
private cleanupInterval;
|
|
75
|
+
constructor();
|
|
76
|
+
increment(key: string, windowMs: number): Promise<{
|
|
77
|
+
count: number;
|
|
78
|
+
resetTime: number;
|
|
79
|
+
}>;
|
|
80
|
+
get(key: string): Promise<{
|
|
81
|
+
count: number;
|
|
82
|
+
resetTime: number;
|
|
83
|
+
} | null>;
|
|
84
|
+
reset(key: string): Promise<void>;
|
|
85
|
+
private cleanup;
|
|
86
|
+
destroy(): void;
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* Rate Limiting Middleware
|
|
90
|
+
* Implements sliding window rate limiting with comprehensive features
|
|
91
|
+
*/
|
|
92
|
+
export declare class RateLimitingMiddleware implements BaseMiddleware {
|
|
93
|
+
private store;
|
|
94
|
+
private options;
|
|
95
|
+
constructor(options?: RateLimitOptions);
|
|
96
|
+
before(context: Context): Promise<void>;
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* Rate Limiting Middleware Factory
|
|
100
|
+
* @param options Rate limiting configuration
|
|
101
|
+
* @returns BaseMiddleware
|
|
102
|
+
*/
|
|
103
|
+
export declare const rateLimiting: (options?: RateLimitOptions) => BaseMiddleware;
|
|
104
|
+
/**
|
|
105
|
+
* Predefined rate limit configurations
|
|
106
|
+
*/
|
|
107
|
+
export declare const RateLimitPresets: {
|
|
108
|
+
/**
|
|
109
|
+
* Very strict limits for sensitive endpoints
|
|
110
|
+
*/
|
|
111
|
+
readonly STRICT: {
|
|
112
|
+
maxRequests: number;
|
|
113
|
+
windowMs: number;
|
|
114
|
+
message: string;
|
|
115
|
+
};
|
|
116
|
+
/**
|
|
117
|
+
* Standard API limits
|
|
118
|
+
*/
|
|
119
|
+
readonly API: {
|
|
120
|
+
maxRequests: number;
|
|
121
|
+
windowMs: number;
|
|
122
|
+
dynamicLimits: {
|
|
123
|
+
authenticated: {
|
|
124
|
+
maxRequests: number;
|
|
125
|
+
windowMs: number;
|
|
126
|
+
matcher: (context: Context) => boolean;
|
|
127
|
+
};
|
|
128
|
+
};
|
|
129
|
+
};
|
|
130
|
+
/**
|
|
131
|
+
* Authentication endpoint limits
|
|
132
|
+
*/
|
|
133
|
+
readonly AUTH: {
|
|
134
|
+
maxRequests: number;
|
|
135
|
+
windowMs: number;
|
|
136
|
+
message: string;
|
|
137
|
+
};
|
|
138
|
+
/**
|
|
139
|
+
* Public endpoint limits
|
|
140
|
+
*/
|
|
141
|
+
readonly PUBLIC: {
|
|
142
|
+
maxRequests: number;
|
|
143
|
+
windowMs: number;
|
|
144
|
+
};
|
|
145
|
+
/**
|
|
146
|
+
* Development mode - very permissive
|
|
147
|
+
*/
|
|
148
|
+
readonly DEVELOPMENT: {
|
|
149
|
+
maxRequests: number;
|
|
150
|
+
windowMs: number;
|
|
151
|
+
};
|
|
152
|
+
};
|
|
153
|
+
/**
|
|
154
|
+
* Export memory store for testing and custom implementations
|
|
155
|
+
*/
|
|
156
|
+
export { MemoryStore };
|
|
157
|
+
//# sourceMappingURL=rateLimitingMiddleware.d.ts.map
|
|
@@ -0,0 +1,237 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.MemoryStore = exports.RateLimitPresets = exports.rateLimiting = exports.RateLimitingMiddleware = void 0;
|
|
4
|
+
const core_1 = require("../core");
|
|
5
|
+
const logger_1 = require("../core/logger");
|
|
6
|
+
/**
|
|
7
|
+
* In-memory rate limit store (use Redis in production)
|
|
8
|
+
*/
|
|
9
|
+
class MemoryStore {
|
|
10
|
+
store = new Map();
|
|
11
|
+
cleanupInterval;
|
|
12
|
+
constructor() {
|
|
13
|
+
// Cleanup expired entries every 5 minutes
|
|
14
|
+
this.cleanupInterval = setInterval(() => {
|
|
15
|
+
this.cleanup();
|
|
16
|
+
}, 5 * 60 * 1000);
|
|
17
|
+
}
|
|
18
|
+
async increment(key, windowMs) {
|
|
19
|
+
const now = Date.now();
|
|
20
|
+
const resetTime = now + windowMs;
|
|
21
|
+
const existing = this.store.get(key);
|
|
22
|
+
if (existing && now < existing.resetTime) {
|
|
23
|
+
existing.count++;
|
|
24
|
+
return existing;
|
|
25
|
+
}
|
|
26
|
+
else {
|
|
27
|
+
const newEntry = { count: 1, resetTime };
|
|
28
|
+
this.store.set(key, newEntry);
|
|
29
|
+
return newEntry;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
async get(key) {
|
|
33
|
+
const entry = this.store.get(key);
|
|
34
|
+
if (entry && Date.now() < entry.resetTime) {
|
|
35
|
+
return entry;
|
|
36
|
+
}
|
|
37
|
+
if (entry) {
|
|
38
|
+
this.store.delete(key);
|
|
39
|
+
}
|
|
40
|
+
return null;
|
|
41
|
+
}
|
|
42
|
+
async reset(key) {
|
|
43
|
+
this.store.delete(key);
|
|
44
|
+
}
|
|
45
|
+
cleanup() {
|
|
46
|
+
const now = Date.now();
|
|
47
|
+
for (const [key, entry] of this.store.entries()) {
|
|
48
|
+
if (now >= entry.resetTime) {
|
|
49
|
+
this.store.delete(key);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
destroy() {
|
|
54
|
+
clearInterval(this.cleanupInterval);
|
|
55
|
+
this.store.clear();
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
exports.MemoryStore = MemoryStore;
|
|
59
|
+
/**
|
|
60
|
+
* Default key generator using IP address with user identification
|
|
61
|
+
*/
|
|
62
|
+
const defaultKeyGenerator = (context) => {
|
|
63
|
+
const ip = context.req.ip ||
|
|
64
|
+
(Array.isArray(context.req.headers?.['x-forwarded-for'])
|
|
65
|
+
? context.req.headers['x-forwarded-for'][0]
|
|
66
|
+
: context.req.headers?.['x-forwarded-for']) ||
|
|
67
|
+
'unknown';
|
|
68
|
+
// Include user ID if authenticated for per-user limits
|
|
69
|
+
const userId = context.user && typeof context.user === 'object' && 'sub' in context.user
|
|
70
|
+
? context.user.sub
|
|
71
|
+
: null;
|
|
72
|
+
return userId ? `user:${userId}` : `ip:${ip}`;
|
|
73
|
+
};
|
|
74
|
+
/**
|
|
75
|
+
* Apply rate limit headers to response
|
|
76
|
+
*/
|
|
77
|
+
const setRateLimitHeaders = (context, info) => {
|
|
78
|
+
context.res.header('X-RateLimit-Limit', String(info.limit));
|
|
79
|
+
context.res.header('X-RateLimit-Remaining', String(Math.max(0, info.remaining)));
|
|
80
|
+
context.res.header('X-RateLimit-Reset', String(Math.ceil(info.resetTime / 1000)));
|
|
81
|
+
context.res.header('Retry-After', String(Math.ceil((info.resetTime - Date.now()) / 1000)));
|
|
82
|
+
};
|
|
83
|
+
/**
|
|
84
|
+
* Determine the appropriate rate limit for the request
|
|
85
|
+
*/
|
|
86
|
+
const getRateLimit = (context, options) => {
|
|
87
|
+
// Check dynamic limits first
|
|
88
|
+
if (options.dynamicLimits) {
|
|
89
|
+
for (const [name, config] of Object.entries(options.dynamicLimits)) {
|
|
90
|
+
if (config.matcher(context)) {
|
|
91
|
+
logger_1.logger.debug('Applied dynamic rate limit', {
|
|
92
|
+
limitName: name,
|
|
93
|
+
maxRequests: config.maxRequests,
|
|
94
|
+
windowMs: config.windowMs,
|
|
95
|
+
});
|
|
96
|
+
return { maxRequests: config.maxRequests, windowMs: config.windowMs };
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
// Default limits
|
|
101
|
+
return {
|
|
102
|
+
maxRequests: options.maxRequests || 100,
|
|
103
|
+
windowMs: options.windowMs || 60000,
|
|
104
|
+
};
|
|
105
|
+
};
|
|
106
|
+
/**
|
|
107
|
+
* Rate Limiting Middleware
|
|
108
|
+
* Implements sliding window rate limiting with comprehensive features
|
|
109
|
+
*/
|
|
110
|
+
class RateLimitingMiddleware {
|
|
111
|
+
store;
|
|
112
|
+
options;
|
|
113
|
+
constructor(options = {}) {
|
|
114
|
+
this.store = options.store || new MemoryStore();
|
|
115
|
+
this.options = {
|
|
116
|
+
maxRequests: 100,
|
|
117
|
+
windowMs: 60000,
|
|
118
|
+
message: 'Too many requests, please try again later',
|
|
119
|
+
statusCode: 429,
|
|
120
|
+
headers: true,
|
|
121
|
+
keyGenerator: options.keyGenerator || defaultKeyGenerator,
|
|
122
|
+
skip: options.skip,
|
|
123
|
+
dynamicLimits: options.dynamicLimits,
|
|
124
|
+
store: options.store,
|
|
125
|
+
};
|
|
126
|
+
}
|
|
127
|
+
async before(context) {
|
|
128
|
+
// Skip rate limiting if configured
|
|
129
|
+
if (this.options.skip && this.options.skip(context)) {
|
|
130
|
+
return;
|
|
131
|
+
}
|
|
132
|
+
const key = this.options.keyGenerator(context);
|
|
133
|
+
const { maxRequests, windowMs } = getRateLimit(context, this.options);
|
|
134
|
+
try {
|
|
135
|
+
const result = await this.store.increment(key, windowMs);
|
|
136
|
+
const rateLimitInfo = {
|
|
137
|
+
limit: maxRequests,
|
|
138
|
+
current: result.count,
|
|
139
|
+
remaining: Math.max(0, maxRequests - result.count),
|
|
140
|
+
resetTime: result.resetTime,
|
|
141
|
+
};
|
|
142
|
+
// Set rate limit headers
|
|
143
|
+
if (this.options.headers) {
|
|
144
|
+
setRateLimitHeaders(context, rateLimitInfo);
|
|
145
|
+
}
|
|
146
|
+
// Check if limit exceeded
|
|
147
|
+
if (result.count > maxRequests) {
|
|
148
|
+
logger_1.logger.warn('Rate limit exceeded', {
|
|
149
|
+
key,
|
|
150
|
+
count: result.count,
|
|
151
|
+
limit: maxRequests,
|
|
152
|
+
resetTime: new Date(result.resetTime).toISOString(),
|
|
153
|
+
userAgent: context.req.headers?.['user-agent'],
|
|
154
|
+
endpoint: context.req.path || context.req.url,
|
|
155
|
+
});
|
|
156
|
+
throw new core_1.SecurityError(this.options.message);
|
|
157
|
+
}
|
|
158
|
+
// Log approaching limit
|
|
159
|
+
if (result.count > maxRequests * 0.8) {
|
|
160
|
+
logger_1.logger.debug('Approaching rate limit', {
|
|
161
|
+
key,
|
|
162
|
+
count: result.count,
|
|
163
|
+
limit: maxRequests,
|
|
164
|
+
percentage: Math.round((result.count / maxRequests) * 100),
|
|
165
|
+
});
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
catch (error) {
|
|
169
|
+
if (error instanceof core_1.SecurityError) {
|
|
170
|
+
throw error;
|
|
171
|
+
}
|
|
172
|
+
// Log store errors but don't block requests
|
|
173
|
+
logger_1.logger.error('Rate limiting store error', {
|
|
174
|
+
error: error instanceof Error ? error.message : 'Unknown error',
|
|
175
|
+
key,
|
|
176
|
+
});
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
exports.RateLimitingMiddleware = RateLimitingMiddleware;
|
|
181
|
+
/**
|
|
182
|
+
* Rate Limiting Middleware Factory
|
|
183
|
+
* @param options Rate limiting configuration
|
|
184
|
+
* @returns BaseMiddleware
|
|
185
|
+
*/
|
|
186
|
+
const rateLimiting = (options = {}) => new RateLimitingMiddleware(options);
|
|
187
|
+
exports.rateLimiting = rateLimiting;
|
|
188
|
+
/**
|
|
189
|
+
* Predefined rate limit configurations
|
|
190
|
+
*/
|
|
191
|
+
exports.RateLimitPresets = {
|
|
192
|
+
/**
|
|
193
|
+
* Very strict limits for sensitive endpoints
|
|
194
|
+
*/
|
|
195
|
+
STRICT: {
|
|
196
|
+
maxRequests: 5,
|
|
197
|
+
windowMs: 60000, // 1 minute
|
|
198
|
+
message: 'Too many requests to sensitive endpoint',
|
|
199
|
+
},
|
|
200
|
+
/**
|
|
201
|
+
* Standard API limits
|
|
202
|
+
*/
|
|
203
|
+
API: {
|
|
204
|
+
maxRequests: 100,
|
|
205
|
+
windowMs: 60000, // 1 minute
|
|
206
|
+
dynamicLimits: {
|
|
207
|
+
authenticated: {
|
|
208
|
+
maxRequests: 1000,
|
|
209
|
+
windowMs: 60000,
|
|
210
|
+
matcher: (context) => !!context.user,
|
|
211
|
+
},
|
|
212
|
+
},
|
|
213
|
+
},
|
|
214
|
+
/**
|
|
215
|
+
* Authentication endpoint limits
|
|
216
|
+
*/
|
|
217
|
+
AUTH: {
|
|
218
|
+
maxRequests: 10,
|
|
219
|
+
windowMs: 60000, // 1 minute
|
|
220
|
+
message: 'Too many authentication attempts',
|
|
221
|
+
},
|
|
222
|
+
/**
|
|
223
|
+
* Public endpoint limits
|
|
224
|
+
*/
|
|
225
|
+
PUBLIC: {
|
|
226
|
+
maxRequests: 50,
|
|
227
|
+
windowMs: 60000, // 1 minute
|
|
228
|
+
},
|
|
229
|
+
/**
|
|
230
|
+
* Development mode - very permissive
|
|
231
|
+
*/
|
|
232
|
+
DEVELOPMENT: {
|
|
233
|
+
maxRequests: 10000,
|
|
234
|
+
windowMs: 60000, // 1 minute
|
|
235
|
+
},
|
|
236
|
+
};
|
|
237
|
+
//# sourceMappingURL=rateLimitingMiddleware.js.map
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { BaseMiddleware } from '../core/handler';
|
|
2
|
+
import { Context } from '../core/core';
|
|
3
|
+
export declare class ResponseWrapperMiddleware<T> implements BaseMiddleware {
|
|
4
|
+
after(context: Context): Promise<void>;
|
|
5
|
+
}
|
|
6
|
+
export declare const responseWrapperMiddleware: <T>() => BaseMiddleware;
|
|
7
|
+
/**
|
|
8
|
+
* Helper function to set response data in context for later wrapping
|
|
9
|
+
*/
|
|
10
|
+
export declare function setResponseData<T>(context: Context, data: T): void;
|
|
11
|
+
//# sourceMappingURL=responseWrapperMiddleware.d.ts.map
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.responseWrapperMiddleware = exports.ResponseWrapperMiddleware = void 0;
|
|
4
|
+
exports.setResponseData = setResponseData;
|
|
5
|
+
const wrapResponse = (context) => {
|
|
6
|
+
if (!context.res.headersSent) {
|
|
7
|
+
const statusCode = context.res.statusCode || 200;
|
|
8
|
+
const body = context.responseData;
|
|
9
|
+
context.res.status(statusCode).json({
|
|
10
|
+
success: true,
|
|
11
|
+
payload: body,
|
|
12
|
+
timestamp: new Date().toISOString(),
|
|
13
|
+
});
|
|
14
|
+
}
|
|
15
|
+
};
|
|
16
|
+
class ResponseWrapperMiddleware {
|
|
17
|
+
async after(context) {
|
|
18
|
+
wrapResponse(context);
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
exports.ResponseWrapperMiddleware = ResponseWrapperMiddleware;
|
|
22
|
+
const responseWrapperMiddleware = () => ({
|
|
23
|
+
after: async (context) => {
|
|
24
|
+
wrapResponse(context);
|
|
25
|
+
},
|
|
26
|
+
});
|
|
27
|
+
exports.responseWrapperMiddleware = responseWrapperMiddleware;
|
|
28
|
+
/**
|
|
29
|
+
* Helper function to set response data in context for later wrapping
|
|
30
|
+
*/
|
|
31
|
+
function setResponseData(context, data) {
|
|
32
|
+
context.responseData = data;
|
|
33
|
+
}
|
|
34
|
+
//# sourceMappingURL=responseWrapperMiddleware.js.map
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
import { BaseMiddleware, Context } from '../core';
|
|
2
|
+
export interface SecurityEvent {
|
|
3
|
+
type: SecurityEventType;
|
|
4
|
+
severity: SecuritySeverity;
|
|
5
|
+
timestamp: string;
|
|
6
|
+
requestId: string;
|
|
7
|
+
clientIP: string;
|
|
8
|
+
userAgent?: string;
|
|
9
|
+
userId?: string;
|
|
10
|
+
endpoint: string;
|
|
11
|
+
method: string;
|
|
12
|
+
details: Record<string, unknown>;
|
|
13
|
+
}
|
|
14
|
+
export type SecurityEventType = 'SUSPICIOUS_REQUEST' | 'AUTHENTICATION_FAILURE' | 'AUTHORIZATION_FAILURE' | 'RATE_LIMIT_EXCEEDED' | 'INVALID_INPUT' | 'TOKEN_MANIPULATION' | 'UNUSUAL_BEHAVIOR' | 'SECURITY_HEADER_VIOLATION' | 'INJECTION_ATTEMPT' | 'MALFORMED_REQUEST';
|
|
15
|
+
export type SecuritySeverity = 'LOW' | 'MEDIUM' | 'HIGH' | 'CRITICAL';
|
|
16
|
+
export interface SecurityAuditOptions {
|
|
17
|
+
/**
|
|
18
|
+
* Enable detailed request logging
|
|
19
|
+
* @default false
|
|
20
|
+
*/
|
|
21
|
+
logRequests?: boolean;
|
|
22
|
+
/**
|
|
23
|
+
* Enable response logging
|
|
24
|
+
* @default false
|
|
25
|
+
*/
|
|
26
|
+
logResponses?: boolean;
|
|
27
|
+
/**
|
|
28
|
+
* Log request/response bodies (be careful with sensitive data)
|
|
29
|
+
* @default false
|
|
30
|
+
*/
|
|
31
|
+
logBodies?: boolean;
|
|
32
|
+
/**
|
|
33
|
+
* Maximum body size to log (in bytes)
|
|
34
|
+
* @default 1024
|
|
35
|
+
*/
|
|
36
|
+
maxBodyLogSize?: number;
|
|
37
|
+
/**
|
|
38
|
+
* Headers to exclude from logging (security headers, auth tokens, etc.)
|
|
39
|
+
*/
|
|
40
|
+
excludeHeaders?: string[];
|
|
41
|
+
/**
|
|
42
|
+
* Custom security event handler
|
|
43
|
+
*/
|
|
44
|
+
onSecurityEvent?: (event: SecurityEvent) => Promise<void> | void;
|
|
45
|
+
/**
|
|
46
|
+
* Enable anomaly detection
|
|
47
|
+
* @default true
|
|
48
|
+
*/
|
|
49
|
+
enableAnomalyDetection?: boolean;
|
|
50
|
+
/**
|
|
51
|
+
* Suspicious patterns to detect
|
|
52
|
+
*/
|
|
53
|
+
suspiciousPatterns?: {
|
|
54
|
+
sqlInjection?: RegExp[];
|
|
55
|
+
xss?: RegExp[];
|
|
56
|
+
pathTraversal?: RegExp[];
|
|
57
|
+
commandInjection?: RegExp[];
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Security event tracking for anomaly detection
|
|
62
|
+
*/
|
|
63
|
+
declare class SecurityEventTracker {
|
|
64
|
+
private events;
|
|
65
|
+
private readonly maxEventsPerClient;
|
|
66
|
+
private readonly timeWindow;
|
|
67
|
+
addEvent(event: SecurityEvent): void;
|
|
68
|
+
getClientEvents(clientIP: string, minutes?: number): SecurityEvent[];
|
|
69
|
+
detectAnomalies(clientIP: string): SecurityEvent[];
|
|
70
|
+
}
|
|
71
|
+
declare const securityEventTracker: SecurityEventTracker;
|
|
72
|
+
/**
|
|
73
|
+
* Security Audit Middleware
|
|
74
|
+
* Provides comprehensive security event logging and monitoring
|
|
75
|
+
*/
|
|
76
|
+
export declare class SecurityAuditMiddleware implements BaseMiddleware {
|
|
77
|
+
private options;
|
|
78
|
+
constructor(options?: SecurityAuditOptions);
|
|
79
|
+
before(context: Context): Promise<void>;
|
|
80
|
+
after(context: Context): Promise<void>;
|
|
81
|
+
onError(error: Error, context: Context): Promise<void>;
|
|
82
|
+
private logSecurityEvent;
|
|
83
|
+
private sanitizeHeaders;
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Security Audit Middleware Factory
|
|
87
|
+
* @param options Security audit configuration
|
|
88
|
+
* @returns BaseMiddleware
|
|
89
|
+
*/
|
|
90
|
+
export declare const securityAudit: (options?: SecurityAuditOptions) => BaseMiddleware;
|
|
91
|
+
/**
|
|
92
|
+
* Predefined security audit configurations
|
|
93
|
+
*/
|
|
94
|
+
export declare const SecurityAuditPresets: {
|
|
95
|
+
/**
|
|
96
|
+
* Full monitoring with detailed logging
|
|
97
|
+
*/
|
|
98
|
+
readonly COMPREHENSIVE: {
|
|
99
|
+
logRequests: true;
|
|
100
|
+
logResponses: true;
|
|
101
|
+
logBodies: false;
|
|
102
|
+
enableAnomalyDetection: true;
|
|
103
|
+
};
|
|
104
|
+
/**
|
|
105
|
+
* Security events only
|
|
106
|
+
*/
|
|
107
|
+
readonly SECURITY_ONLY: {
|
|
108
|
+
logRequests: false;
|
|
109
|
+
logResponses: false;
|
|
110
|
+
logBodies: false;
|
|
111
|
+
enableAnomalyDetection: true;
|
|
112
|
+
};
|
|
113
|
+
/**
|
|
114
|
+
* Development mode with full logging
|
|
115
|
+
*/
|
|
116
|
+
readonly DEVELOPMENT: {
|
|
117
|
+
logRequests: true;
|
|
118
|
+
logResponses: true;
|
|
119
|
+
logBodies: true;
|
|
120
|
+
enableAnomalyDetection: false;
|
|
121
|
+
};
|
|
122
|
+
};
|
|
123
|
+
export { securityEventTracker };
|
|
124
|
+
//# sourceMappingURL=securityAuditMiddleware.d.ts.map
|