mastercontroller 1.2.11 → 1.2.13
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/CSPConfig.js +319 -0
- package/EventHandlerValidator.js +464 -0
- package/MasterAction.js +296 -72
- package/MasterBackendErrorHandler.js +769 -0
- package/MasterBenchmark.js +89 -0
- package/MasterBuildOptimizer.js +376 -0
- package/MasterBundleAnalyzer.js +108 -0
- package/MasterCache.js +400 -0
- package/MasterControl.js +77 -7
- package/MasterErrorHandler.js +487 -0
- package/MasterErrorLogger.js +360 -0
- package/MasterErrorMiddleware.js +407 -0
- package/MasterHtml.js +101 -14
- package/MasterMemoryMonitor.js +188 -0
- package/MasterProfiler.js +409 -0
- package/MasterRouter.js +273 -66
- package/MasterSanitizer.js +429 -0
- package/MasterTemplate.js +96 -3
- package/MasterValidator.js +546 -0
- package/README.md +0 -44
- package/SecurityMiddleware.js +486 -0
- package/SessionSecurity.js +416 -0
- package/package.json +2 -2
- package/ssr/ErrorBoundary.js +353 -0
- package/ssr/HTMLUtils.js +15 -0
- package/ssr/HydrationMismatch.js +265 -0
- package/ssr/PerformanceMonitor.js +233 -0
- package/ssr/SSRErrorHandler.js +273 -0
- package/ssr/hydration-client.js +93 -0
- package/ssr/runtime-ssr.cjs +553 -0
- package/ssr/ssr-shims.js +73 -0
- package/examples/FileServingExample.js +0 -88
|
@@ -0,0 +1,486 @@
|
|
|
1
|
+
// version 1.0.0
|
|
2
|
+
// MasterController Security Middleware - CSRF, Headers, Rate Limiting, CORS
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Security middleware for MasterController
|
|
6
|
+
* Provides: CSRF protection, Security headers, Rate limiting, CORS
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
const crypto = require('crypto');
|
|
10
|
+
const { logger } = require('./MasterErrorLogger');
|
|
11
|
+
|
|
12
|
+
// Rate limiting store
|
|
13
|
+
const rateLimitStore = new Map();
|
|
14
|
+
|
|
15
|
+
// CSRF token store (use Redis in production)
|
|
16
|
+
const csrfTokenStore = new Map();
|
|
17
|
+
|
|
18
|
+
// Security headers configuration
|
|
19
|
+
const SECURITY_HEADERS = {
|
|
20
|
+
// Prevent XSS attacks
|
|
21
|
+
'X-XSS-Protection': '1; mode=block',
|
|
22
|
+
|
|
23
|
+
// Prevent clickjacking
|
|
24
|
+
'X-Frame-Options': 'SAMEORIGIN',
|
|
25
|
+
|
|
26
|
+
// Prevent MIME type sniffing
|
|
27
|
+
'X-Content-Type-Options': 'nosniff',
|
|
28
|
+
|
|
29
|
+
// Prevent DNS prefetching
|
|
30
|
+
'X-DNS-Prefetch-Control': 'off',
|
|
31
|
+
|
|
32
|
+
// Disable browser features
|
|
33
|
+
'Permissions-Policy': 'geolocation=(), microphone=(), camera=()',
|
|
34
|
+
|
|
35
|
+
// Referrer policy
|
|
36
|
+
'Referrer-Policy': 'strict-origin-when-cross-origin',
|
|
37
|
+
|
|
38
|
+
// Remove X-Powered-By header
|
|
39
|
+
'X-Powered-By': ''
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
// HSTS (HTTP Strict Transport Security) - only in production
|
|
43
|
+
const HSTS_HEADER = {
|
|
44
|
+
'Strict-Transport-Security': 'max-age=31536000; includeSubDomains; preload'
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
class SecurityMiddleware {
|
|
48
|
+
constructor(options = {}) {
|
|
49
|
+
this.csrfEnabled = options.csrf !== false;
|
|
50
|
+
this.rateLimitEnabled = options.rateLimit !== false;
|
|
51
|
+
this.corsEnabled = options.cors !== false;
|
|
52
|
+
this.headersEnabled = options.headers !== false;
|
|
53
|
+
|
|
54
|
+
// Rate limit config
|
|
55
|
+
this.rateLimitWindow = options.rateLimitWindow || 60000; // 1 minute
|
|
56
|
+
this.rateLimitMax = options.rateLimitMax || 100; // 100 requests per window
|
|
57
|
+
|
|
58
|
+
// CSRF config
|
|
59
|
+
this.csrfCookieName = options.csrfCookieName || '_csrf';
|
|
60
|
+
this.csrfHeaderName = options.csrfHeaderName || 'x-csrf-token';
|
|
61
|
+
this.csrfTokenExpiry = options.csrfTokenExpiry || 3600000; // 1 hour
|
|
62
|
+
|
|
63
|
+
// CORS config
|
|
64
|
+
this.corsOrigins = options.corsOrigins || ['*'];
|
|
65
|
+
this.corsMethods = options.corsMethods || ['GET', 'POST', 'PUT', 'DELETE', 'PATCH', 'OPTIONS'];
|
|
66
|
+
this.corsHeaders = options.corsHeaders || ['Content-Type', 'Authorization', 'X-Requested-With'];
|
|
67
|
+
|
|
68
|
+
// Start cleanup interval
|
|
69
|
+
this._startCleanup();
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* Apply security headers to response
|
|
74
|
+
*/
|
|
75
|
+
securityHeadersMiddleware(req, res, next) {
|
|
76
|
+
if (!this.headersEnabled) {
|
|
77
|
+
return next();
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
// Apply standard security headers
|
|
81
|
+
for (const [header, value] of Object.entries(SECURITY_HEADERS)) {
|
|
82
|
+
if (value === '') {
|
|
83
|
+
res.removeHeader(header);
|
|
84
|
+
} else {
|
|
85
|
+
res.setHeader(header, value);
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
// Apply HSTS only in production over HTTPS
|
|
90
|
+
const isProduction = process.env.NODE_ENV === 'production';
|
|
91
|
+
const isHTTPS = req.connection.encrypted || req.headers['x-forwarded-proto'] === 'https';
|
|
92
|
+
|
|
93
|
+
if (isProduction && isHTTPS) {
|
|
94
|
+
for (const [header, value] of Object.entries(HSTS_HEADER)) {
|
|
95
|
+
res.setHeader(header, value);
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
next();
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* CORS middleware
|
|
104
|
+
*/
|
|
105
|
+
corsMiddleware(req, res, next) {
|
|
106
|
+
if (!this.corsEnabled) {
|
|
107
|
+
return next();
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
const origin = req.headers.origin;
|
|
111
|
+
|
|
112
|
+
// Check if origin is allowed
|
|
113
|
+
if (this.corsOrigins.includes('*') || this.corsOrigins.includes(origin)) {
|
|
114
|
+
res.setHeader('Access-Control-Allow-Origin', origin || '*');
|
|
115
|
+
res.setHeader('Access-Control-Allow-Methods', this.corsMethods.join(', '));
|
|
116
|
+
res.setHeader('Access-Control-Allow-Headers', this.corsHeaders.join(', '));
|
|
117
|
+
res.setHeader('Access-Control-Allow-Credentials', 'true');
|
|
118
|
+
res.setHeader('Access-Control-Max-Age', '86400'); // 24 hours
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
// Handle preflight requests
|
|
122
|
+
if (req.method === 'OPTIONS') {
|
|
123
|
+
res.writeHead(204);
|
|
124
|
+
res.end();
|
|
125
|
+
return;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
next();
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
/**
|
|
132
|
+
* Rate limiting middleware
|
|
133
|
+
*/
|
|
134
|
+
rateLimitMiddleware(req, res, next) {
|
|
135
|
+
if (!this.rateLimitEnabled) {
|
|
136
|
+
return next();
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
const identifier = this._getClientIdentifier(req);
|
|
140
|
+
const now = Date.now();
|
|
141
|
+
const windowStart = now - this.rateLimitWindow;
|
|
142
|
+
|
|
143
|
+
// Get or create rate limit record
|
|
144
|
+
let record = rateLimitStore.get(identifier);
|
|
145
|
+
if (!record) {
|
|
146
|
+
record = { requests: [], blocked: false, blockExpiry: 0 };
|
|
147
|
+
rateLimitStore.set(identifier, record);
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
// Check if blocked
|
|
151
|
+
if (record.blocked && now < record.blockExpiry) {
|
|
152
|
+
const retryAfter = Math.ceil((record.blockExpiry - now) / 1000);
|
|
153
|
+
res.setHeader('Retry-After', retryAfter);
|
|
154
|
+
res.setHeader('X-RateLimit-Limit', this.rateLimitMax);
|
|
155
|
+
res.setHeader('X-RateLimit-Remaining', 0);
|
|
156
|
+
res.setHeader('X-RateLimit-Reset', new Date(record.blockExpiry).toISOString());
|
|
157
|
+
|
|
158
|
+
logger.warn({
|
|
159
|
+
code: 'MC_SECURITY_RATE_LIMIT_EXCEEDED',
|
|
160
|
+
message: 'Rate limit exceeded',
|
|
161
|
+
identifier,
|
|
162
|
+
ip: this._getClientIP(req)
|
|
163
|
+
});
|
|
164
|
+
|
|
165
|
+
res.writeHead(429, { 'Content-Type': 'application/json' });
|
|
166
|
+
res.end(JSON.stringify({
|
|
167
|
+
error: 'Too Many Requests',
|
|
168
|
+
message: 'Rate limit exceeded. Please try again later.',
|
|
169
|
+
retryAfter: retryAfter
|
|
170
|
+
}));
|
|
171
|
+
return;
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
// Remove old requests outside window
|
|
175
|
+
record.requests = record.requests.filter(timestamp => timestamp > windowStart);
|
|
176
|
+
|
|
177
|
+
// Check if limit exceeded
|
|
178
|
+
if (record.requests.length >= this.rateLimitMax) {
|
|
179
|
+
record.blocked = true;
|
|
180
|
+
record.blockExpiry = now + this.rateLimitWindow;
|
|
181
|
+
|
|
182
|
+
logger.warn({
|
|
183
|
+
code: 'MC_SECURITY_RATE_LIMIT_TRIGGERED',
|
|
184
|
+
message: 'Rate limit triggered',
|
|
185
|
+
identifier,
|
|
186
|
+
ip: this._getClientIP(req),
|
|
187
|
+
requests: record.requests.length
|
|
188
|
+
});
|
|
189
|
+
|
|
190
|
+
const retryAfter = Math.ceil(this.rateLimitWindow / 1000);
|
|
191
|
+
res.setHeader('Retry-After', retryAfter);
|
|
192
|
+
res.writeHead(429, { 'Content-Type': 'application/json' });
|
|
193
|
+
res.end(JSON.stringify({
|
|
194
|
+
error: 'Too Many Requests',
|
|
195
|
+
message: 'Rate limit exceeded. Please try again later.',
|
|
196
|
+
retryAfter: retryAfter
|
|
197
|
+
}));
|
|
198
|
+
return;
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
// Add current request
|
|
202
|
+
record.requests.push(now);
|
|
203
|
+
|
|
204
|
+
// Set rate limit headers
|
|
205
|
+
const remaining = this.rateLimitMax - record.requests.length;
|
|
206
|
+
const resetTime = now + this.rateLimitWindow;
|
|
207
|
+
|
|
208
|
+
res.setHeader('X-RateLimit-Limit', this.rateLimitMax);
|
|
209
|
+
res.setHeader('X-RateLimit-Remaining', remaining);
|
|
210
|
+
res.setHeader('X-RateLimit-Reset', new Date(resetTime).toISOString());
|
|
211
|
+
|
|
212
|
+
next();
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
/**
|
|
216
|
+
* CSRF protection middleware
|
|
217
|
+
*/
|
|
218
|
+
csrfMiddleware(req, res, next) {
|
|
219
|
+
if (!this.csrfEnabled) {
|
|
220
|
+
return next();
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
// Skip CSRF for safe methods
|
|
224
|
+
const safeMethods = ['GET', 'HEAD', 'OPTIONS'];
|
|
225
|
+
if (safeMethods.includes(req.method)) {
|
|
226
|
+
return next();
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
// Get CSRF token from request
|
|
230
|
+
const tokenFromHeader = req.headers[this.csrfHeaderName];
|
|
231
|
+
const tokenFromBody = req.body && req.body._csrf;
|
|
232
|
+
const tokenFromQuery = req.url.includes('_csrf=') ? this._getQueryParam(req.url, '_csrf') : null;
|
|
233
|
+
|
|
234
|
+
const clientToken = tokenFromHeader || tokenFromBody || tokenFromQuery;
|
|
235
|
+
|
|
236
|
+
if (!clientToken) {
|
|
237
|
+
logger.warn({
|
|
238
|
+
code: 'MC_SECURITY_CSRF_MISSING',
|
|
239
|
+
message: 'CSRF token missing',
|
|
240
|
+
method: req.method,
|
|
241
|
+
path: req.url,
|
|
242
|
+
ip: this._getClientIP(req)
|
|
243
|
+
});
|
|
244
|
+
|
|
245
|
+
res.writeHead(403, { 'Content-Type': 'application/json' });
|
|
246
|
+
res.end(JSON.stringify({
|
|
247
|
+
error: 'Forbidden',
|
|
248
|
+
message: 'CSRF token missing'
|
|
249
|
+
}));
|
|
250
|
+
return;
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
// Verify CSRF token
|
|
254
|
+
const storedToken = csrfTokenStore.get(clientToken);
|
|
255
|
+
|
|
256
|
+
if (!storedToken) {
|
|
257
|
+
logger.warn({
|
|
258
|
+
code: 'MC_SECURITY_CSRF_INVALID',
|
|
259
|
+
message: 'CSRF token invalid',
|
|
260
|
+
method: req.method,
|
|
261
|
+
path: req.url,
|
|
262
|
+
ip: this._getClientIP(req)
|
|
263
|
+
});
|
|
264
|
+
|
|
265
|
+
res.writeHead(403, { 'Content-Type': 'application/json' });
|
|
266
|
+
res.end(JSON.stringify({
|
|
267
|
+
error: 'Forbidden',
|
|
268
|
+
message: 'CSRF token invalid'
|
|
269
|
+
}));
|
|
270
|
+
return;
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
// Check token expiry
|
|
274
|
+
if (Date.now() > storedToken.expiry) {
|
|
275
|
+
csrfTokenStore.delete(clientToken);
|
|
276
|
+
|
|
277
|
+
logger.warn({
|
|
278
|
+
code: 'MC_SECURITY_CSRF_EXPIRED',
|
|
279
|
+
message: 'CSRF token expired',
|
|
280
|
+
method: req.method,
|
|
281
|
+
path: req.url,
|
|
282
|
+
ip: this._getClientIP(req)
|
|
283
|
+
});
|
|
284
|
+
|
|
285
|
+
res.writeHead(403, { 'Content-Type': 'application/json' });
|
|
286
|
+
res.end(JSON.stringify({
|
|
287
|
+
error: 'Forbidden',
|
|
288
|
+
message: 'CSRF token expired'
|
|
289
|
+
}));
|
|
290
|
+
return;
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
// Token valid, continue
|
|
294
|
+
next();
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
/**
|
|
298
|
+
* Generate CSRF token
|
|
299
|
+
*/
|
|
300
|
+
generateCSRFToken(sessionId = null) {
|
|
301
|
+
const token = crypto.randomBytes(32).toString('hex');
|
|
302
|
+
const expiry = Date.now() + this.csrfTokenExpiry;
|
|
303
|
+
|
|
304
|
+
csrfTokenStore.set(token, {
|
|
305
|
+
sessionId,
|
|
306
|
+
expiry,
|
|
307
|
+
createdAt: Date.now()
|
|
308
|
+
});
|
|
309
|
+
|
|
310
|
+
return token;
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
/**
|
|
314
|
+
* Validate CSRF token manually
|
|
315
|
+
*/
|
|
316
|
+
validateCSRFToken(token) {
|
|
317
|
+
const storedToken = csrfTokenStore.get(token);
|
|
318
|
+
|
|
319
|
+
if (!storedToken) {
|
|
320
|
+
return { valid: false, reason: 'Token not found' };
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
if (Date.now() > storedToken.expiry) {
|
|
324
|
+
csrfTokenStore.delete(token);
|
|
325
|
+
return { valid: false, reason: 'Token expired' };
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
return { valid: true };
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
/**
|
|
332
|
+
* Get client identifier for rate limiting
|
|
333
|
+
*/
|
|
334
|
+
_getClientIdentifier(req) {
|
|
335
|
+
// Use session ID if available
|
|
336
|
+
if (req.session && req.session.id) {
|
|
337
|
+
return `session:${req.session.id}`;
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
// Use API key if available
|
|
341
|
+
if (req.headers['x-api-key']) {
|
|
342
|
+
return `api:${req.headers['x-api-key']}`;
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
// Fall back to IP
|
|
346
|
+
return `ip:${this._getClientIP(req)}`;
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
/**
|
|
350
|
+
* Get client IP address
|
|
351
|
+
*/
|
|
352
|
+
_getClientIP(req) {
|
|
353
|
+
// Check for forwarded IP (behind proxy/load balancer)
|
|
354
|
+
const forwarded = req.headers['x-forwarded-for'];
|
|
355
|
+
if (forwarded) {
|
|
356
|
+
return forwarded.split(',')[0].trim();
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
// Check for real IP header
|
|
360
|
+
if (req.headers['x-real-ip']) {
|
|
361
|
+
return req.headers['x-real-ip'];
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
// Fall back to connection remote address
|
|
365
|
+
return req.connection.remoteAddress || req.socket.remoteAddress || 'unknown';
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
/**
|
|
369
|
+
* Get query parameter from URL
|
|
370
|
+
*/
|
|
371
|
+
_getQueryParam(url, param) {
|
|
372
|
+
const match = url.match(new RegExp(`[?&]${param}=([^&]*)`));
|
|
373
|
+
return match ? decodeURIComponent(match[1]) : null;
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
/**
|
|
377
|
+
* Cleanup expired tokens and rate limit records
|
|
378
|
+
*/
|
|
379
|
+
_startCleanup() {
|
|
380
|
+
setInterval(() => {
|
|
381
|
+
const now = Date.now();
|
|
382
|
+
|
|
383
|
+
// Cleanup expired CSRF tokens
|
|
384
|
+
for (const [token, data] of csrfTokenStore.entries()) {
|
|
385
|
+
if (now > data.expiry) {
|
|
386
|
+
csrfTokenStore.delete(token);
|
|
387
|
+
}
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
// Cleanup old rate limit records
|
|
391
|
+
for (const [identifier, record] of rateLimitStore.entries()) {
|
|
392
|
+
const windowStart = now - this.rateLimitWindow;
|
|
393
|
+
record.requests = record.requests.filter(timestamp => timestamp > windowStart);
|
|
394
|
+
|
|
395
|
+
// Remove empty records
|
|
396
|
+
if (record.requests.length === 0 && !record.blocked) {
|
|
397
|
+
rateLimitStore.delete(identifier);
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
// Unblock if expiry passed
|
|
401
|
+
if (record.blocked && now > record.blockExpiry) {
|
|
402
|
+
record.blocked = false;
|
|
403
|
+
record.requests = [];
|
|
404
|
+
}
|
|
405
|
+
}
|
|
406
|
+
}, 60000); // Run every minute
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
/**
|
|
410
|
+
* Clear rate limit for identifier (useful for testing)
|
|
411
|
+
*/
|
|
412
|
+
clearRateLimit(identifier) {
|
|
413
|
+
rateLimitStore.delete(identifier);
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
/**
|
|
417
|
+
* Get rate limit status for identifier
|
|
418
|
+
*/
|
|
419
|
+
getRateLimitStatus(identifier) {
|
|
420
|
+
const record = rateLimitStore.get(identifier);
|
|
421
|
+
if (!record) {
|
|
422
|
+
return {
|
|
423
|
+
requests: 0,
|
|
424
|
+
remaining: this.rateLimitMax,
|
|
425
|
+
blocked: false
|
|
426
|
+
};
|
|
427
|
+
}
|
|
428
|
+
|
|
429
|
+
const now = Date.now();
|
|
430
|
+
const windowStart = now - this.rateLimitWindow;
|
|
431
|
+
const recentRequests = record.requests.filter(timestamp => timestamp > windowStart);
|
|
432
|
+
|
|
433
|
+
return {
|
|
434
|
+
requests: recentRequests.length,
|
|
435
|
+
remaining: Math.max(0, this.rateLimitMax - recentRequests.length),
|
|
436
|
+
blocked: record.blocked && now < record.blockExpiry,
|
|
437
|
+
blockExpiry: record.blocked ? record.blockExpiry : null
|
|
438
|
+
};
|
|
439
|
+
}
|
|
440
|
+
}
|
|
441
|
+
|
|
442
|
+
// Create singleton instance
|
|
443
|
+
const security = new SecurityMiddleware();
|
|
444
|
+
|
|
445
|
+
/**
|
|
446
|
+
* Factory functions for middleware
|
|
447
|
+
*/
|
|
448
|
+
|
|
449
|
+
function securityHeaders() {
|
|
450
|
+
return (req, res, next) => security.securityHeadersMiddleware(req, res, next);
|
|
451
|
+
}
|
|
452
|
+
|
|
453
|
+
function cors(options = {}) {
|
|
454
|
+
const instance = new SecurityMiddleware({ ...options, headers: false, csrf: false, rateLimit: false });
|
|
455
|
+
return (req, res, next) => instance.corsMiddleware(req, res, next);
|
|
456
|
+
}
|
|
457
|
+
|
|
458
|
+
function rateLimit(options = {}) {
|
|
459
|
+
const instance = new SecurityMiddleware({ ...options, headers: false, csrf: false, cors: false });
|
|
460
|
+
return (req, res, next) => instance.rateLimitMiddleware(req, res, next);
|
|
461
|
+
}
|
|
462
|
+
|
|
463
|
+
function csrf(options = {}) {
|
|
464
|
+
const instance = new SecurityMiddleware({ ...options, headers: false, cors: false, rateLimit: false });
|
|
465
|
+
return (req, res, next) => instance.csrfMiddleware(req, res, next);
|
|
466
|
+
}
|
|
467
|
+
|
|
468
|
+
function generateCSRFToken(sessionId) {
|
|
469
|
+
return security.generateCSRFToken(sessionId);
|
|
470
|
+
}
|
|
471
|
+
|
|
472
|
+
function validateCSRFToken(token) {
|
|
473
|
+
return security.validateCSRFToken(token);
|
|
474
|
+
}
|
|
475
|
+
|
|
476
|
+
module.exports = {
|
|
477
|
+
SecurityMiddleware,
|
|
478
|
+
security,
|
|
479
|
+
securityHeaders,
|
|
480
|
+
cors,
|
|
481
|
+
rateLimit,
|
|
482
|
+
csrf,
|
|
483
|
+
generateCSRFToken,
|
|
484
|
+
validateCSRFToken,
|
|
485
|
+
SECURITY_HEADERS
|
|
486
|
+
};
|