Skip to main content
Glama

Curupira

by drzln
index.ts7.07 kB
/** * Security module index * * Aggregates all security components */ import type { FastifyInstance, FastifyRequest, FastifyReply } from 'fastify' import { AuthManager, type AuthConfig } from './auth.js' import { CommandWhitelist, type WhitelistConfig } from './whitelist.js' import { DataSanitizer, type SanitizerConfig } from './sanitizer.js' import { AuditLogger, type AuditConfig } from './audit.js' import { RateLimiter, type RateLimitConfig } from './rate-limit.js' import { logger } from '../config/logger.js' export interface SecurityConfig { enabled: boolean environment: 'development' | 'staging' | 'production' auth?: AuthConfig whitelist?: WhitelistConfig sanitizer?: SanitizerConfig audit?: AuditConfig rateLimit?: RateLimitConfig } export class SecurityManager { private config: SecurityConfig private auth: AuthManager private whitelist: CommandWhitelist private sanitizer: DataSanitizer private audit: AuditLogger private rateLimiter: RateLimiter constructor(config: SecurityConfig) { this.config = config // Initialize components with defaults based on environment this.auth = new AuthManager(this.getAuthConfig()) this.whitelist = new CommandWhitelist(this.getWhitelistConfig()) this.sanitizer = new DataSanitizer(this.getSanitizerConfig()) this.audit = new AuditLogger(this.getAuditConfig()) this.rateLimiter = new RateLimiter(this.getRateLimitConfig()) } /** * Apply security to Fastify instance */ async applyToFastify(fastify: FastifyInstance) { if (!this.config.enabled) { logger.warn('Security is disabled') return } // Apply rate limiting await this.rateLimiter.apply(fastify) // Add authentication hook for protected routes fastify.addHook('onRequest', async (request, reply) => { // Skip auth for health/metrics endpoints if (request.url === '/health' || request.url === '/metrics' || request.url === '/docs') { return } // Apply authentication if (this.auth && this.config.auth?.enabled) { await this.auth.authenticate(request, reply) } }) // Add security headers fastify.addHook('onSend', async (request, reply) => { reply.header('X-Content-Type-Options', 'nosniff') reply.header('X-Frame-Options', 'DENY') reply.header('X-XSS-Protection', '1; mode=block') reply.header('Referrer-Policy', 'no-referrer') if (this.config.environment === 'production') { reply.header('Strict-Transport-Security', 'max-age=31536000; includeSubDomains') } }) logger.info({ environment: this.config.environment }, 'Security applied to Fastify') } /** * Check if CDP method is allowed */ isCDPMethodAllowed(method: string, params?: any): boolean { if (!this.config.enabled || !this.config.whitelist?.enabled) { return true } const allowed = this.whitelist.isCDPMethodAllowed(method) if (!allowed) { this.audit.logSecurityBlock( {} as FastifyRequest, 'CDP method not allowed', { method } ) } return allowed } /** * Check if tool is allowed */ isToolAllowed(toolName: string, request?: FastifyRequest): boolean { if (!this.config.enabled || !this.config.whitelist?.enabled) { return true } const allowed = this.whitelist.isToolAllowed(toolName) if (!allowed && request) { this.audit.logSecurityBlock( request, 'Tool not allowed', { toolName } ) } return allowed } /** * Check if resource is allowed */ isResourceAllowed(uri: string, request?: FastifyRequest): boolean { if (!this.config.enabled || !this.config.whitelist?.enabled) { return true } const allowed = this.whitelist.isResourceAllowed(uri) if (!allowed && request) { this.audit.logSecurityBlock( request, 'Resource not allowed', { uri } ) } return allowed } /** * Sanitize data before sending */ sanitizeData(data: any): any { if (!this.config.enabled || !this.config.sanitizer?.enabled) { return data } return this.sanitizer.sanitize(data) } /** * Sanitize CDP parameters */ sanitizeCDPParams(method: string, params: any): any { if (!this.config.enabled || !this.config.whitelist?.enabled) { return params } return this.whitelist.sanitizeCDPParams(method, params) } /** * Get security components */ getComponents() { return { auth: this.auth, whitelist: this.whitelist, sanitizer: this.sanitizer, audit: this.audit, rateLimiter: this.rateLimiter, } } /** * Get auth config with defaults */ private getAuthConfig(): AuthConfig { const defaults: AuthConfig = { enabled: this.config.environment !== 'development', algorithms: ['HS256', 'RS256'], } return { ...defaults, ...this.config.auth } } /** * Get whitelist config with defaults */ private getWhitelistConfig(): WhitelistConfig { const defaults = this.config.environment === 'production' ? CommandWhitelist.getProductionDefaults() : { enabled: false } return { ...defaults, ...this.config.whitelist } } /** * Get sanitizer config with defaults */ private getSanitizerConfig(): SanitizerConfig { const defaults: SanitizerConfig = { enabled: this.config.environment !== 'development', maxDepth: 10, maxStringLength: 10000, redactedPlaceholder: '[REDACTED]', } return { ...defaults, ...this.config.sanitizer } } /** * Get audit config with defaults */ private getAuditConfig(): AuditConfig { const defaults: AuditConfig = { enabled: true, includeRequestBody: this.config.environment === 'development', includeResponseBody: false, } return { ...defaults, ...this.config.audit } } /** * Get rate limit config with defaults */ private getRateLimitConfig(): RateLimitConfig { const defaults = this.config.environment === 'production' ? RateLimiter.getProductionDefaults() : RateLimiter.getDevelopmentDefaults() return { ...defaults, ...this.config.rateLimit } } /** * Get security statistics */ getStatistics() { return { enabled: this.config.enabled, environment: this.config.environment, auth: { enabled: this.config.auth?.enabled || false, }, whitelist: this.whitelist.getStatistics(), sanitizer: this.sanitizer.getStatistics(), audit: this.audit.getStatistics(), } } } // Re-export all security components export { AuthManager, type AuthConfig } from './auth.js' export { CommandWhitelist, type WhitelistConfig } from './whitelist.js' export { DataSanitizer, type SanitizerConfig } from './sanitizer.js' export { AuditLogger, type AuditConfig, type AuditEvent, type AuditEventType } from './audit.js' export { RateLimiter, type RateLimitConfig } from './rate-limit.js'

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/drzln/curupira'

If you have feedback or need assistance with the MCP directory API, please join our Discord server