secure-kit
Version:
Production-grade security + performance toolkit for backend frameworks with OWASP Top 10 compliance
127 lines • 5.91 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.FastifyAdapter = void 0;
const security_1 = require("../core/security");
const performance_1 = require("../core/performance");
const config_1 = require("../core/config");
class FastifyAdapter {
constructor(config) {
this.config = config_1.ConfigManager.createConfig(config);
this.securityManager = new security_1.SecurityManager(this.config);
this.performanceManager = new performance_1.PerformanceManager(this.config);
}
createPlugin() {
return async (fastify, _options) => {
// Register main security hooks
fastify.addHook('onRequest', async (request, reply) => {
const startTime = Date.now();
request.startTime = startTime;
// Apply security headers
this.securityManager.applySecurityHeaders(reply);
// CORS validation
const origin = request.headers.origin;
if (origin &&
!this.securityManager.validateCORS(origin, request.method)) {
reply.status(403).send({ error: 'CORS policy violation' });
return;
}
// Rate limiting
const clientIp = this.getClientIP(request);
const rateLimitInfo = this.securityManager.checkRateLimit(clientIp);
if (rateLimitInfo && rateLimitInfo.remaining === 0) {
reply.header('Retry-After', rateLimitInfo.retryAfter?.toString() || '60');
reply.status(429).send({
error: 'Rate limit exceeded',
retryAfter: rateLimitInfo.retryAfter,
});
return;
}
// Apply rate limit headers
if (rateLimitInfo) {
reply.header('X-RateLimit-Limit', rateLimitInfo.limit.toString());
reply.header('X-RateLimit-Remaining', rateLimitInfo.remaining.toString());
reply.header('X-RateLimit-Reset', rateLimitInfo.resetTime.toISOString());
}
// JWT validation (if Authorization header is present)
const authHeader = request.headers.authorization;
if (authHeader && authHeader.startsWith('Bearer ')) {
const token = authHeader.substring(7);
const jwtValidation = this.securityManager.validateJWT(token);
if (!jwtValidation.valid) {
reply.status(401).send({ error: jwtValidation.error });
return;
}
request.user = jwtValidation.payload;
}
});
// Performance monitoring hook
fastify.addHook('onSend', async (request, reply, payload) => {
const startTime = request.startTime || Date.now();
// Optimize response
const optimized = this.performanceManager.optimizeResponse(payload);
// Apply caching headers
this.performanceManager.applyCachingHeaders(reply, optimized.data);
// Record metrics
const duration = Date.now() - startTime;
const payloadSize = Buffer.isBuffer(optimized.data)
? optimized.data.length
: JSON.stringify(optimized.data).length;
this.performanceManager.recordMetrics(duration, payloadSize);
return optimized.data;
});
// Register security routes
this.registerSecurityRoutes(fastify);
};
}
registerSecurityRoutes(fastify) {
// CSRF token endpoint
if (this.config.security?.csrf?.enabled) {
fastify.get('/csrf-token', async (_request, reply) => {
const token = this.securityManager.generateCSRFToken();
// Set cookie using headers for basic implementation
reply.header('Set-Cookie', `csrf-token=${token}; HttpOnly; Secure; SameSite=Strict; Max-Age=3600`);
return { csrfToken: token };
});
}
// Security events endpoint
if (this.config.logging?.enabled) {
fastify.get('/security-events', async (_request, _reply) => {
const events = this.securityManager.getSecurityEvents();
return { events };
});
// Performance metrics endpoint
fastify.get('/performance-metrics', async (_request, _reply) => {
const metrics = this.performanceManager.getMetrics();
const avgResponseTime = this.performanceManager.getAverageResponseTime();
const avgPayloadSize = this.performanceManager.getAveragePayloadSize();
const memoryUsage = this.performanceManager.getMemoryUsage();
const suggestions = this.performanceManager.getOptimizationSuggestions();
return {
metrics: metrics.slice(-100),
summary: {
averageResponseTime: avgResponseTime,
averagePayloadSize: avgPayloadSize,
memoryUsage,
suggestions,
},
};
});
}
}
// Helper methods
getClientIP(request) {
return request.ip || request.socket.remoteAddress || 'unknown';
}
// Utility methods for external use
getSecurityManager() {
return this.securityManager;
}
getPerformanceManager() {
return this.performanceManager;
}
getConfig() {
return this.config;
}
}
exports.FastifyAdapter = FastifyAdapter;
//# sourceMappingURL=fastify.js.map