@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.
Files changed (46) hide show
  1. package/README.md +443 -0
  2. package/build/core/containerPool.d.ts +44 -0
  3. package/build/core/containerPool.js +103 -0
  4. package/build/core/core.d.ts +123 -0
  5. package/build/core/core.js +107 -0
  6. package/build/core/errors.d.ts +25 -0
  7. package/build/core/errors.js +59 -0
  8. package/build/core/handler.d.ts +72 -0
  9. package/build/core/handler.js +151 -0
  10. package/build/core/index.d.ts +8 -0
  11. package/build/core/index.js +24 -0
  12. package/build/core/logger.d.ts +42 -0
  13. package/build/core/logger.js +135 -0
  14. package/build/core/performanceMonitor.d.ts +73 -0
  15. package/build/core/performanceMonitor.js +189 -0
  16. package/build/index.d.ts +3 -0
  17. package/build/index.js +19 -0
  18. package/build/middlewares/authenticationMiddleware.d.ts +52 -0
  19. package/build/middlewares/authenticationMiddleware.js +204 -0
  20. package/build/middlewares/bodyParserMiddleware.d.ts +31 -0
  21. package/build/middlewares/bodyParserMiddleware.js +217 -0
  22. package/build/middlewares/bodyValidationMiddleware.d.ts +12 -0
  23. package/build/middlewares/bodyValidationMiddleware.js +34 -0
  24. package/build/middlewares/dependencyInjectionMiddleware.d.ts +14 -0
  25. package/build/middlewares/dependencyInjectionMiddleware.js +48 -0
  26. package/build/middlewares/errorHandlerMiddleware.d.ts +6 -0
  27. package/build/middlewares/errorHandlerMiddleware.js +64 -0
  28. package/build/middlewares/headerVariablesMiddleware.d.ts +8 -0
  29. package/build/middlewares/headerVariablesMiddleware.js +32 -0
  30. package/build/middlewares/httpAttributesMiddleware.d.ts +10 -0
  31. package/build/middlewares/httpAttributesMiddleware.js +71 -0
  32. package/build/middlewares/index.d.ts +14 -0
  33. package/build/middlewares/index.js +30 -0
  34. package/build/middlewares/queryParametersMiddleware.d.ts +8 -0
  35. package/build/middlewares/queryParametersMiddleware.js +51 -0
  36. package/build/middlewares/rateLimitingMiddleware.d.ts +157 -0
  37. package/build/middlewares/rateLimitingMiddleware.js +237 -0
  38. package/build/middlewares/responseWrapperMiddleware.d.ts +11 -0
  39. package/build/middlewares/responseWrapperMiddleware.js +34 -0
  40. package/build/middlewares/securityAuditMiddleware.d.ts +124 -0
  41. package/build/middlewares/securityAuditMiddleware.js +395 -0
  42. package/build/middlewares/securityHeadersMiddleware.d.ts +128 -0
  43. package/build/middlewares/securityHeadersMiddleware.js +183 -0
  44. package/build/middlewares/validationMiddleware.d.ts +9 -0
  45. package/build/middlewares/validationMiddleware.js +40 -0
  46. package/package.json +73 -0
@@ -0,0 +1,395 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.securityEventTracker = exports.SecurityAuditPresets = exports.securityAudit = exports.SecurityAuditMiddleware = void 0;
4
+ const core_1 = require("../core");
5
+ const logger_1 = require("../core/logger");
6
+ const DEFAULT_EXCLUDE_HEADERS = [
7
+ 'authorization',
8
+ 'cookie',
9
+ 'set-cookie',
10
+ 'x-api-key',
11
+ 'x-auth-token',
12
+ ];
13
+ const DEFAULT_SUSPICIOUS_PATTERNS = {
14
+ sqlInjection: [
15
+ /(\b(SELECT|INSERT|UPDATE|DELETE|DROP|CREATE|ALTER|EXEC(UTE)?|UNION|SCRIPT)\b)/i,
16
+ /(('%27)|('))(('%6F)|o|('%4F'))(('%72)|r|('%52'))/i,
17
+ /(((')|('))\s*(('%6F)|o|('%4F'))(('%72)|r|('%52')))/i,
18
+ /((')|('))union/i,
19
+ ],
20
+ xss: [
21
+ /<script[^>]*>.*?<\/script>/gi,
22
+ /javascript:/gi,
23
+ /vbscript:/gi,
24
+ /on\w+\s*=/gi,
25
+ /<iframe[^>]*>.*?<\/iframe>/gi,
26
+ ],
27
+ pathTraversal: [
28
+ /\.\.[/\\]/g,
29
+ /%2e%2e[/\\]/gi,
30
+ /%252e%252e[/\\]/gi,
31
+ /\.\.[%2f%5c]/gi,
32
+ ],
33
+ commandInjection: [
34
+ /[;&|`$()]/g,
35
+ /%[0-9a-f]{2}/gi,
36
+ /\b(cat|ls|ps|id|pwd|uname|whoami|curl|wget)\b/i,
37
+ ],
38
+ };
39
+ /**
40
+ * Security event tracking for anomaly detection
41
+ */
42
+ class SecurityEventTracker {
43
+ events = new Map();
44
+ maxEventsPerClient = 100;
45
+ timeWindow = 60 * 60 * 1000; // 1 hour
46
+ addEvent(event) {
47
+ const clientKey = event.clientIP;
48
+ const clientEvents = this.events.get(clientKey) || [];
49
+ // Remove old events outside time window
50
+ const cutoff = Date.now() - this.timeWindow;
51
+ const recentEvents = clientEvents.filter((e) => new Date(e.timestamp).getTime() > cutoff);
52
+ // Add new event
53
+ recentEvents.push(event);
54
+ // Limit number of events stored per client
55
+ if (recentEvents.length > this.maxEventsPerClient) {
56
+ recentEvents.splice(0, recentEvents.length - this.maxEventsPerClient);
57
+ }
58
+ this.events.set(clientKey, recentEvents);
59
+ }
60
+ getClientEvents(clientIP, minutes = 60) {
61
+ const cutoff = Date.now() - minutes * 60 * 1000;
62
+ const events = this.events.get(clientIP) || [];
63
+ return events.filter((e) => new Date(e.timestamp).getTime() > cutoff);
64
+ }
65
+ detectAnomalies(clientIP) {
66
+ const recentEvents = this.getClientEvents(clientIP, 10); // Last 10 minutes
67
+ const anomalies = [];
68
+ // Multiple failed authentication attempts
69
+ const authFailures = recentEvents.filter((e) => e.type === 'AUTHENTICATION_FAILURE');
70
+ if (authFailures.length >= 5) {
71
+ anomalies.push({
72
+ type: 'UNUSUAL_BEHAVIOR',
73
+ severity: 'HIGH',
74
+ timestamp: new Date().toISOString(),
75
+ requestId: 'anomaly-detection',
76
+ clientIP,
77
+ endpoint: 'multiple-endpoints',
78
+ method: 'MULTIPLE',
79
+ details: {
80
+ anomalyType: 'multiple_auth_failures',
81
+ count: authFailures.length,
82
+ timeWindow: '10 minutes',
83
+ },
84
+ });
85
+ }
86
+ // High rate of suspicious requests
87
+ const suspiciousEvents = recentEvents.filter((e) => ['INJECTION_ATTEMPT', 'MALFORMED_REQUEST', 'SUSPICIOUS_REQUEST'].includes(e.type));
88
+ if (suspiciousEvents.length >= 10) {
89
+ anomalies.push({
90
+ type: 'UNUSUAL_BEHAVIOR',
91
+ severity: 'CRITICAL',
92
+ timestamp: new Date().toISOString(),
93
+ requestId: 'anomaly-detection',
94
+ clientIP,
95
+ endpoint: 'multiple-endpoints',
96
+ method: 'MULTIPLE',
97
+ details: {
98
+ anomalyType: 'high_suspicious_activity',
99
+ count: suspiciousEvents.length,
100
+ timeWindow: '10 minutes',
101
+ },
102
+ });
103
+ }
104
+ return anomalies;
105
+ }
106
+ }
107
+ const securityEventTracker = new SecurityEventTracker();
108
+ exports.securityEventTracker = securityEventTracker;
109
+ /**
110
+ * Check for suspicious patterns in request data
111
+ */
112
+ const detectSuspiciousPatterns = (data, patterns = DEFAULT_SUSPICIOUS_PATTERNS) => {
113
+ const detected = [];
114
+ for (const [type, regexList] of Object.entries(patterns)) {
115
+ for (const regex of regexList || []) {
116
+ if (regex.test(data)) {
117
+ detected.push({ type, pattern: regex.source });
118
+ }
119
+ }
120
+ }
121
+ return detected;
122
+ };
123
+ /**
124
+ * Sanitize data for logging (remove sensitive information)
125
+ */
126
+ const sanitizeForLogging = (data, maxSize = 1024) => {
127
+ if (typeof data === 'string') {
128
+ return data.length > maxSize
129
+ ? data.substring(0, maxSize) + '...[truncated]'
130
+ : data;
131
+ }
132
+ try {
133
+ const jsonStr = JSON.stringify(data);
134
+ return jsonStr.length > maxSize
135
+ ? jsonStr.substring(0, maxSize) + '...[truncated]'
136
+ : jsonStr;
137
+ }
138
+ catch {
139
+ return '[unserializable data]';
140
+ }
141
+ };
142
+ /**
143
+ * Extract client information from request
144
+ */
145
+ const extractClientInfo = (context) => ({
146
+ clientIP: context.req.ip ||
147
+ (Array.isArray(context.req.headers?.['x-forwarded-for'])
148
+ ? context.req.headers['x-forwarded-for'][0]
149
+ : context.req.headers?.['x-forwarded-for']) ||
150
+ 'unknown',
151
+ userAgent: context.req.headers?.['user-agent'],
152
+ userId: context.user && typeof context.user === 'object' && 'sub' in context.user
153
+ ? context.user.sub
154
+ : undefined,
155
+ });
156
+ /**
157
+ * Security Audit Middleware
158
+ * Provides comprehensive security event logging and monitoring
159
+ */
160
+ class SecurityAuditMiddleware {
161
+ options;
162
+ constructor(options = {}) {
163
+ this.options = {
164
+ logRequests: false,
165
+ logResponses: false,
166
+ logBodies: false,
167
+ maxBodyLogSize: 1024,
168
+ excludeHeaders: [
169
+ ...DEFAULT_EXCLUDE_HEADERS,
170
+ ...(options.excludeHeaders || []),
171
+ ],
172
+ enableAnomalyDetection: true,
173
+ onSecurityEvent: options.onSecurityEvent,
174
+ suspiciousPatterns: {
175
+ ...DEFAULT_SUSPICIOUS_PATTERNS,
176
+ ...options.suspiciousPatterns,
177
+ },
178
+ };
179
+ }
180
+ async before(context) {
181
+ const startTime = Date.now();
182
+ const { clientIP, userAgent, userId } = extractClientInfo(context);
183
+ // Store start time for performance monitoring
184
+ context.businessData.set('audit_start_time', startTime);
185
+ context.businessData.set('audit_client_info', {
186
+ clientIP,
187
+ userAgent,
188
+ userId,
189
+ });
190
+ // Log incoming request if enabled
191
+ if (this.options.logRequests) {
192
+ const requestData = {
193
+ method: context.req.method,
194
+ url: context.req.url || context.req.path,
195
+ headers: this.sanitizeHeaders(context.req.headers || {}),
196
+ clientIP,
197
+ userAgent,
198
+ userId,
199
+ };
200
+ if (this.options.logBodies && context.req.body) {
201
+ requestData.body = sanitizeForLogging(context.req.body, this.options.maxBodyLogSize);
202
+ }
203
+ logger_1.logger.info('Incoming request', requestData);
204
+ }
205
+ // Check for suspicious patterns in URL and headers
206
+ const url = context.req.url || context.req.path || '';
207
+ const suspiciousInUrl = detectSuspiciousPatterns(url, this.options.suspiciousPatterns);
208
+ if (suspiciousInUrl.length > 0) {
209
+ await this.logSecurityEvent({
210
+ type: 'INJECTION_ATTEMPT',
211
+ severity: 'HIGH',
212
+ timestamp: new Date().toISOString(),
213
+ requestId: context.requestId,
214
+ clientIP,
215
+ userAgent,
216
+ userId,
217
+ endpoint: url,
218
+ method: context.req.method || 'UNKNOWN',
219
+ details: {
220
+ suspiciousPatterns: suspiciousInUrl,
221
+ location: 'url',
222
+ },
223
+ });
224
+ }
225
+ // Check request body for suspicious patterns
226
+ if (context.req.body && typeof context.req.body === 'string') {
227
+ const suspiciousInBody = detectSuspiciousPatterns(context.req.body, this.options.suspiciousPatterns);
228
+ if (suspiciousInBody.length > 0) {
229
+ await this.logSecurityEvent({
230
+ type: 'INJECTION_ATTEMPT',
231
+ severity: 'HIGH',
232
+ timestamp: new Date().toISOString(),
233
+ requestId: context.requestId,
234
+ clientIP,
235
+ userAgent,
236
+ userId,
237
+ endpoint: url,
238
+ method: context.req.method || 'UNKNOWN',
239
+ details: {
240
+ suspiciousPatterns: suspiciousInBody,
241
+ location: 'body',
242
+ },
243
+ });
244
+ }
245
+ }
246
+ // Run anomaly detection
247
+ if (this.options.enableAnomalyDetection) {
248
+ const anomalies = securityEventTracker.detectAnomalies(clientIP);
249
+ for (const anomaly of anomalies) {
250
+ await this.logSecurityEvent(anomaly);
251
+ }
252
+ }
253
+ }
254
+ async after(context) {
255
+ const startTime = context.businessData.get('audit_start_time');
256
+ const clientInfo = context.businessData.get('audit_client_info');
257
+ const duration = Date.now() - startTime;
258
+ // Log response if enabled
259
+ if (this.options.logResponses) {
260
+ const responseData = {
261
+ statusCode: context.res.statusCode,
262
+ duration: `${duration}ms`,
263
+ ...clientInfo,
264
+ };
265
+ if (this.options.logBodies && context.responseData) {
266
+ responseData.responseBody = sanitizeForLogging(context.responseData, this.options.maxBodyLogSize);
267
+ }
268
+ logger_1.logger.info('Outgoing response', responseData);
269
+ }
270
+ }
271
+ async onError(error, context) {
272
+ const clientInfo = context.businessData.get('audit_client_info');
273
+ if (!clientInfo)
274
+ return;
275
+ const { clientIP, userAgent, userId } = clientInfo;
276
+ const url = context.req.url || context.req.path || '';
277
+ let eventType = 'SUSPICIOUS_REQUEST';
278
+ let severity = 'MEDIUM';
279
+ // Classify error types
280
+ if (error instanceof core_1.HttpError) {
281
+ switch (error.status) {
282
+ case 401:
283
+ eventType = 'AUTHENTICATION_FAILURE';
284
+ severity = 'MEDIUM';
285
+ break;
286
+ case 403:
287
+ eventType = 'AUTHORIZATION_FAILURE';
288
+ severity = 'HIGH';
289
+ break;
290
+ case 400:
291
+ eventType = 'INVALID_INPUT';
292
+ severity = 'LOW';
293
+ break;
294
+ case 429:
295
+ eventType = 'RATE_LIMIT_EXCEEDED';
296
+ severity = 'HIGH';
297
+ break;
298
+ default:
299
+ eventType = 'SUSPICIOUS_REQUEST';
300
+ severity = 'MEDIUM';
301
+ }
302
+ }
303
+ await this.logSecurityEvent({
304
+ type: eventType,
305
+ severity,
306
+ timestamp: new Date().toISOString(),
307
+ requestId: context.requestId,
308
+ clientIP,
309
+ userAgent,
310
+ userId,
311
+ endpoint: url,
312
+ method: context.req.method || 'UNKNOWN',
313
+ details: {
314
+ error: error.message,
315
+ errorType: error.constructor.name,
316
+ statusCode: error instanceof core_1.HttpError ? error.status : undefined,
317
+ },
318
+ });
319
+ }
320
+ async logSecurityEvent(event) {
321
+ // Add to tracker for anomaly detection
322
+ if (this.options.enableAnomalyDetection) {
323
+ securityEventTracker.addEvent(event);
324
+ }
325
+ // Log the security event
326
+ logger_1.logger.warn('Security event detected', event);
327
+ // Call custom handler if provided
328
+ if (this.options.onSecurityEvent) {
329
+ try {
330
+ await this.options.onSecurityEvent(event);
331
+ }
332
+ catch (handlerError) {
333
+ logger_1.logger.error('Security event handler failed', {
334
+ error: handlerError instanceof Error
335
+ ? handlerError.message
336
+ : 'Unknown error',
337
+ originalEvent: event,
338
+ });
339
+ }
340
+ }
341
+ }
342
+ sanitizeHeaders(headers) {
343
+ const sanitized = {};
344
+ for (const [key, value] of Object.entries(headers)) {
345
+ if (this.options.excludeHeaders.includes(key.toLowerCase())) {
346
+ sanitized[key] = '[REDACTED]';
347
+ }
348
+ else {
349
+ sanitized[key] = value;
350
+ }
351
+ }
352
+ return sanitized;
353
+ }
354
+ }
355
+ exports.SecurityAuditMiddleware = SecurityAuditMiddleware;
356
+ /**
357
+ * Security Audit Middleware Factory
358
+ * @param options Security audit configuration
359
+ * @returns BaseMiddleware
360
+ */
361
+ const securityAudit = (options = {}) => new SecurityAuditMiddleware(options);
362
+ exports.securityAudit = securityAudit;
363
+ /**
364
+ * Predefined security audit configurations
365
+ */
366
+ exports.SecurityAuditPresets = {
367
+ /**
368
+ * Full monitoring with detailed logging
369
+ */
370
+ COMPREHENSIVE: {
371
+ logRequests: true,
372
+ logResponses: true,
373
+ logBodies: false, // Be careful with sensitive data
374
+ enableAnomalyDetection: true,
375
+ },
376
+ /**
377
+ * Security events only
378
+ */
379
+ SECURITY_ONLY: {
380
+ logRequests: false,
381
+ logResponses: false,
382
+ logBodies: false,
383
+ enableAnomalyDetection: true,
384
+ },
385
+ /**
386
+ * Development mode with full logging
387
+ */
388
+ DEVELOPMENT: {
389
+ logRequests: true,
390
+ logResponses: true,
391
+ logBodies: true,
392
+ enableAnomalyDetection: false,
393
+ },
394
+ };
395
+ //# sourceMappingURL=securityAuditMiddleware.js.map
@@ -0,0 +1,128 @@
1
+ import { BaseMiddleware, Context } from '../core';
2
+ export interface SecurityHeadersOptions {
3
+ /**
4
+ * Content Security Policy directive
5
+ * @default "default-src 'self'"
6
+ */
7
+ contentSecurityPolicy?: string;
8
+ /**
9
+ * Strict-Transport-Security max-age in seconds
10
+ * @default 31536000 (1 year)
11
+ */
12
+ hstsMaxAge?: number;
13
+ /**
14
+ * Enable HSTS includeSubDomains
15
+ * @default true
16
+ */
17
+ hstsIncludeSubDomains?: boolean;
18
+ /**
19
+ * Frame options policy
20
+ * @default 'DENY'
21
+ */
22
+ frameOptions?: 'DENY' | 'SAMEORIGIN' | 'ALLOW-FROM';
23
+ /**
24
+ * X-Content-Type-Options
25
+ * @default 'nosniff'
26
+ */
27
+ contentTypeOptions?: 'nosniff';
28
+ /**
29
+ * Referrer Policy
30
+ * @default 'strict-origin-when-cross-origin'
31
+ */
32
+ referrerPolicy?: string;
33
+ /**
34
+ * Permissions Policy (formerly Feature Policy)
35
+ * @default 'geolocation=(), microphone=(), camera=()'
36
+ */
37
+ permissionsPolicy?: string;
38
+ /**
39
+ * Cross-Origin-Embedder-Policy
40
+ * @default 'require-corp'
41
+ */
42
+ crossOriginEmbedderPolicy?: string;
43
+ /**
44
+ * Cross-Origin-Opener-Policy
45
+ * @default 'same-origin'
46
+ */
47
+ crossOriginOpenerPolicy?: string;
48
+ /**
49
+ * Cross-Origin-Resource-Policy
50
+ * @default 'same-origin'
51
+ */
52
+ crossOriginResourcePolicy?: string;
53
+ /**
54
+ * CORS configuration
55
+ */
56
+ cors?: {
57
+ origin?: string | string[] | boolean;
58
+ methods?: string[];
59
+ allowedHeaders?: string[];
60
+ exposedHeaders?: string[];
61
+ credentials?: boolean;
62
+ maxAge?: number;
63
+ };
64
+ /**
65
+ * Remove server identification headers
66
+ * @default true
67
+ */
68
+ removeServerHeader?: boolean;
69
+ /**
70
+ * Remove X-Powered-By headers
71
+ * @default true
72
+ */
73
+ removePoweredBy?: boolean;
74
+ }
75
+ /**
76
+ * Security Headers Middleware
77
+ * Implements comprehensive security headers following OWASP recommendations
78
+ */
79
+ export declare class SecurityHeadersMiddleware implements BaseMiddleware {
80
+ private options;
81
+ constructor(options?: SecurityHeadersOptions);
82
+ before(context: Context): Promise<void>;
83
+ }
84
+ /**
85
+ * Security Headers Middleware Factory
86
+ * @param options Security headers configuration
87
+ * @returns BaseMiddleware
88
+ */
89
+ export declare const securityHeaders: (options?: SecurityHeadersOptions) => BaseMiddleware;
90
+ /**
91
+ * Predefined security configurations
92
+ */
93
+ export declare const SecurityPresets: {
94
+ /**
95
+ * Strict security configuration for high-security applications
96
+ */
97
+ readonly STRICT: {
98
+ contentSecurityPolicy: string;
99
+ hstsMaxAge: number;
100
+ frameOptions: "DENY";
101
+ crossOriginEmbedderPolicy: string;
102
+ crossOriginOpenerPolicy: string;
103
+ crossOriginResourcePolicy: string;
104
+ };
105
+ /**
106
+ * Balanced security configuration for most applications
107
+ */
108
+ readonly BALANCED: {
109
+ contentSecurityPolicy: string;
110
+ hstsMaxAge: number;
111
+ frameOptions: "SAMEORIGIN";
112
+ };
113
+ /**
114
+ * Permissive security configuration for development
115
+ */
116
+ readonly DEVELOPMENT: {
117
+ contentSecurityPolicy: string;
118
+ hstsMaxAge: number;
119
+ frameOptions: "SAMEORIGIN";
120
+ cors: {
121
+ origin: true;
122
+ methods: string[];
123
+ allowedHeaders: string[];
124
+ credentials: true;
125
+ };
126
+ };
127
+ };
128
+ //# sourceMappingURL=securityHeadersMiddleware.d.ts.map