Initial Commit

This commit is contained in:
ExilProductions
2026-01-14 17:52:35 +01:00
parent 2d3b97c5db
commit cf066ef305
28 changed files with 1922 additions and 0 deletions

85
server/middleware.ts Normal file
View File

@@ -0,0 +1,85 @@
import helmet from 'helmet';
import rateLimit from 'express-rate-limit';
import { Request, Response, NextFunction } from 'express';
import { config } from './config';
import { securityLogger } from './logger';
// Security headers middleware
export const securityHeaders = helmet({
contentSecurityPolicy: {
directives: {
defaultSrc: ["'self'"],
styleSrc: ["'self'", "'unsafe-inline'"],
scriptSrc: ["'self'"],
imgSrc: ["'self'", "data:", "blob:"],
connectSrc: ["'self'"],
fontSrc: ["'self'"],
objectSrc: ["'none'"],
mediaSrc: ["'self'"],
frameSrc: ["'none'"],
},
},
crossOriginEmbedderPolicy: false, // Req. for Socket.io
hsts: {
maxAge: 31536000,
includeSubDomains: true,
preload: true
}
});
// Rate limiting
export const createRateLimit = rateLimit({
windowMs: config.rateLimit.windowMs,
max: config.rateLimit.maxRequests,
message: {
error: 'Too many requests from this IP, please try again later.',
retryAfter: Math.ceil(config.rateLimit.windowMs / 1000)
},
standardHeaders: true,
legacyHeaders: false,
handler: (req: Request, res: Response) => {
securityLogger.rateLimitExceeded(
req.ip || req.connection.remoteAddress || 'unknown',
req.path
);
res.status(429).json({
error: 'Too many requests from this IP, please try again later.',
retryAfter: Math.ceil(config.rateLimit.windowMs / 1000)
});
}
});
// Request logging
export const requestLogger = (req: Request, res: Response, next: NextFunction) => {
next();
};
// Sanitize input
export const sanitizeInput = (req: Request, res: Response, next: NextFunction) => {
// Recursively sanitize string values
const sanitizeValue = (value: any): any => {
if (typeof value === 'string') {
return value
.replace(/<script\b[^<]*(?:(?!<\/script>)<[^<]*)*<\/script>/gi, '') // Remove script tags
.replace(/<[^>]*>/g, '') // Remove HTML tags
.trim();
}
if (Array.isArray(value)) {
return value.map(sanitizeValue);
}
if (value && typeof value === 'object') {
const sanitized: any = {};
for (const [key, val] of Object.entries(value)) {
sanitized[key] = sanitizeValue(val);
}
return sanitized;
}
return value;
};
req.body = sanitizeValue(req.body);
req.query = sanitizeValue(req.query);
req.params = sanitizeValue(req.params);
next();
};