UNPKG

@pulzar/core

Version:

Next-generation Node.js framework for ultra-fast web applications with zero-reflection DI, GraphQL, WebSockets, events, and edge runtime support

173 lines 5.74 kB
import { logger } from "../utils/logger"; export class SecurityManager { app; options; csrfTokens = new Map(); rateLimitStore = new Map(); constructor(options = {}) { this.options = { csp: { enabled: true, directives: { "default-src": ["'self'"], "script-src": ["'self'", "'unsafe-inline'"], }, }, hsts: { enabled: true, maxAge: 31536000, }, xss: { enabled: true, mode: "block", }, csrf: { enabled: true, ignoredMethods: ["GET", "HEAD", "OPTIONS"], }, rateLimit: { enabled: true, windowMs: 15 * 60 * 1000, max: 100, }, ...options, }; } async initialize(app) { this.app = app; try { if (this.options.csp.enabled) { await this.setupCSP(); } if (this.options.hsts.enabled) { await this.setupHSTS(); } if (this.options.xss.enabled) { await this.setupXSSProtection(); } if (this.options.csrf.enabled) { await this.setupCSRFProtection(); } if (this.options.rateLimit.enabled) { await this.setupRateLimit(); } logger.info("Security manager initialized", { csp: this.options.csp.enabled, hsts: this.options.hsts.enabled, xss: this.options.xss.enabled, csrf: this.options.csrf.enabled, rateLimit: this.options.rateLimit.enabled, }); } catch (error) { logger.error("Failed to initialize security manager", { error }); throw error; } } async setupCSP() { if (!this.app) return; this.app.addHook("onSend", async (request, reply, payload) => { const cspValue = this.buildCSPHeader(); reply.header("Content-Security-Policy", cspValue); return payload; }); logger.debug("CSP protection enabled"); } buildCSPHeader() { const directives = []; for (const [directive, sources] of Object.entries(this.options.csp.directives)) { if (Array.isArray(sources)) { directives.push(`${directive} ${sources.join(" ")}`); } else { directives.push(`${directive} ${sources}`); } } return directives.join("; "); } async setupHSTS() { if (!this.app) return; this.app.addHook("onSend", async (request, reply, payload) => { reply.header("Strict-Transport-Security", `max-age=${this.options.hsts.maxAge}`); return payload; }); logger.debug("HSTS protection enabled"); } async setupXSSProtection() { if (!this.app) return; this.app.addHook("onSend", async (request, reply, payload) => { reply.header("X-XSS-Protection", "1; mode=block"); reply.header("X-Content-Type-Options", "nosniff"); return payload; }); logger.debug("XSS protection enabled"); } async setupCSRFProtection() { if (!this.app) return; this.app.get("/csrf-token", async (request, reply) => { const token = this.generateCSRFToken(request); return { csrfToken: token }; }); logger.debug("CSRF protection enabled"); } generateCSRFToken(request) { const sessionId = request.ip || "anonymous"; const token = Math.random().toString(36).substring(2); const expires = Date.now() + 60 * 60 * 1000; this.csrfTokens.set(sessionId, { token, expires }); return token; } async setupRateLimit() { if (!this.app) return; this.app.addHook("preHandler", async (request, reply) => { const key = request.ip || "unknown"; const now = Date.now(); const windowMs = this.options.rateLimit.windowMs; const maxRequests = this.options.rateLimit.max; let rateData = this.rateLimitStore.get(key); if (!rateData || now > rateData.resetTime) { rateData = { count: 0, resetTime: now + windowMs, }; } rateData.count++; this.rateLimitStore.set(key, rateData); if (rateData.count > maxRequests) { reply.code(429).send({ error: "Too Many Requests", statusCode: 429, }); return; } }); logger.debug("Rate limiting enabled"); } getStats() { return { csp: this.options.csp.enabled, hsts: this.options.hsts.enabled, xss: this.options.xss.enabled, csrf: { enabled: this.options.csrf.enabled, activeSessions: this.csrfTokens.size, }, rateLimit: { enabled: this.options.rateLimit.enabled, activeKeys: this.rateLimitStore.size, }, }; } async shutdown() { this.csrfTokens.clear(); this.rateLimitStore.clear(); logger.info("Security manager shutdown"); } } export default SecurityManager; //# sourceMappingURL=security-manager.js.map