Skip to main content
Glama
unified-security-engine.ts43.1 kB
/** * Unified Security Management Engine * * Consolidates 11 security services into a single, comprehensive engine: * - unified-security-config.ts: Central configuration * - security-config.ts: Configuration management * - audit-logger.ts: Security audit logging * - auth-integration.ts: Authentication and authorization * - data-sanitizer.ts: Input sanitization * - path-validator.ts: Path security validation * - concurrent-access.ts: Concurrent access management * - filesystem-security.ts: Filesystem security * - security-middleware.ts: Security middleware layer * - vibe-task-manager-security-validator.ts: Security boundary validation * * This unified engine provides: * - Centralized security policy management * - Comprehensive audit logging and monitoring * - Advanced authentication and authorization * - Input sanitization and validation * - Path security and filesystem protection * - Concurrent access control with deadlock prevention * - Security middleware for request processing * - Real-time threat detection and response */ import { EventEmitter } from 'events'; import { promises as fs } from 'fs'; import { resolve, normalize } from 'path'; import crypto from 'crypto'; import { EnhancedError, ErrorFactory, createErrorContext } from '../utils/enhanced-errors.js'; import { Result, createSuccess, createFailure } from './unified-lifecycle-manager.js'; import { getUnifiedSecurityConfig } from '../security/unified-security-config.js'; import logger from '../../../logger.js'; // ============================================================================= // BRANDED TYPES FOR TYPE SAFETY // ============================================================================= export type SecurityId = string & { readonly __brand: 'SecurityId' }; export type SessionId = string & { readonly __brand: 'SessionId' }; export type LockId = string & { readonly __brand: 'LockId' }; export type AuditId = string & { readonly __brand: 'AuditId' }; export function createSecurityId(id: string): SecurityId { if (!id || id.trim().length === 0) { throw new Error('Security ID cannot be empty'); } return id as SecurityId; } export function createSessionId(id: string): SessionId { if (!id || id.trim().length === 0) { throw new Error('Session ID cannot be empty'); } return id as SessionId; } export function createLockId(id: string): LockId { if (!id || id.trim().length === 0) { throw new Error('Lock ID cannot be empty'); } return id as LockId; } export function createAuditId(id: string): AuditId { if (!id || id.trim().length === 0) { throw new Error('Audit ID cannot be empty'); } return id as AuditId; } // ============================================================================= // CORE TYPES AND INTERFACES // ============================================================================= /** * User role types */ export type UserRole = 'admin' | 'manager' | 'developer' | 'viewer' | 'guest'; /** * Permission types */ export type Permission = | 'task:create' | 'task:read' | 'task:update' | 'task:delete' | 'task:execute' | 'project:create' | 'project:read' | 'project:update' | 'project:delete' | 'agent:manage' | 'agent:assign' | 'agent:monitor' | 'system:admin' | 'system:config' | 'system:audit' | 'file:read' | 'file:write' | 'file:execute'; /** * Security event types */ export type SecurityEventType = | 'authentication' | 'authorization' | 'access_attempt' | 'data_access' | 'data_modification' | 'security_violation' | 'system_event' | 'suspicious_activity' | 'compliance_event' | 'error_event'; /** * Security event severity */ export type SecurityEventSeverity = 'info' | 'low' | 'medium' | 'high' | 'critical'; /** * Path operation type */ export type PathOperation = 'read' | 'write' | 'execute'; /** * Lock operation type */ export type LockOperation = 'read' | 'write' | 'execute'; /** * User authentication context */ export interface UserContext { userId: string; sessionId: SessionId; role: UserRole; permissions: Permission[]; authenticatedAt: Date; lastActivity: Date; metadata: Record<string, unknown>; } /** * Security validation result */ export interface SecurityValidationResult { isValid: boolean; normalizedPath?: string; sanitizedData?: unknown; violations: SecurityViolation[]; warnings: string[]; performanceMetrics: { totalTime: number; pathValidationTime?: number; sanitizationTime?: number; authorizationTime?: number; }; } /** * Security violation */ export interface SecurityViolation { type: 'path_traversal' | 'outside_boundary' | 'invalid_input' | 'unauthorized_access' | 'concurrent_violation' | 'injection_attempt'; severity: SecurityEventSeverity; field?: string; originalValue?: unknown; sanitizedValue?: unknown; message: string; timestamp: Date; } /** * Path validation result */ export interface PathValidationResult { isValid: boolean; normalizedPath?: string; error?: string; warnings?: string[]; violationType?: 'path_traversal' | 'outside_boundary' | 'invalid_path' | 'dangerous_characters' | 'invalid_extension'; auditInfo: { originalPath: string; timestamp: Date; validationTime: number; }; } /** * Data sanitization result */ export interface SanitizationResult<T> { success: boolean; sanitizedData?: T; originalData: T; violations: SecurityViolation[]; sanitizationTime: number; } /** * Lock information */ export interface LockInfo { id: LockId; resource: string; owner: string; sessionId?: SessionId; operation: LockOperation; acquiredAt: Date; expiresAt: Date; metadata?: Record<string, unknown>; } /** * Lock acquisition result */ export interface LockAcquisitionResult { success: boolean; lockId?: LockId; error?: string; waitTime?: number; existingLock?: LockInfo; } /** * Security audit event */ export interface SecurityAuditEvent { id: AuditId; type: SecurityEventType; severity: SecurityEventSeverity; timestamp: Date; userId?: string; sessionId?: SessionId; resource?: string; action: string; result: 'success' | 'failure' | 'blocked'; details: Record<string, unknown>; ipAddress?: string; userAgent?: string; metadata: Record<string, unknown>; } /** * Security configuration */ export interface UnifiedSecurityEngineConfig { // Global settings enabled: boolean; strictMode: boolean; performanceThresholdMs: number; logViolations: boolean; blockOnCriticalViolations: boolean; // Authentication settings authentication: { enabled: boolean; tokenExpiryMinutes: number; maxSessionsPerUser: number; requireStrongPasswords: boolean; enableMFA: boolean; }; // Authorization settings authorization: { enabled: boolean; defaultRole: UserRole; roleHierarchy: Record<UserRole, UserRole[]>; permissionCache: boolean; }; // Path security settings pathSecurity: { enabled: boolean; allowedReadPaths: string[]; allowedWritePaths: string[]; allowedExtensions: string[]; blockSystemPaths: boolean; followSymlinks: boolean; }; // Data sanitization settings dataSanitization: { enabled: boolean; strictMode: boolean; allowHtml: boolean; allowScripts: boolean; maxStringLength: number; sanitizeFileNames: boolean; }; // Concurrent access settings concurrentAccess: { enabled: boolean; maxLockDuration: number; deadlockDetection: boolean; lockCleanupInterval: number; maxLocksPerResource: number; }; // Audit settings audit: { enabled: boolean; logLevel: SecurityEventSeverity; retentionDays: number; enableIntegrityChecks: boolean; compressLogs: boolean; }; // Filesystem security settings filesystem: { enabled: boolean; systemDirectoryBlacklist: string[]; maxFileSize: number; allowedMimeTypes: string[]; scanForMalware: boolean; }; } /** * Security statistics */ export interface SecurityStatistics { totalEvents: number; eventsByType: Record<SecurityEventType, number>; eventsBySeverity: Record<SecurityEventSeverity, number>; violationCount: number; blockedAttempts: number; activeUsers: number; activeSessions: number; activeLocks: number; averageResponseTime: number; securityScore: number; // 0-100 } // ============================================================================= // UNIFIED SECURITY ENGINE // ============================================================================= /** * Unified Security Management Engine * * Consolidates all security functionality into a single, comprehensive engine * with advanced features for authentication, authorization, audit logging, * path validation, data sanitization, and concurrent access control. */ export class UnifiedSecurityEngine extends EventEmitter { private static instance: UnifiedSecurityEngine | null = null; // Core configuration private readonly config: UnifiedSecurityEngineConfig; private initialized = false; // Security state private readonly activeSessions = new Map<SessionId, UserContext>(); private readonly activeLocks = new Map<LockId, LockInfo>(); private readonly auditEvents = new Map<AuditId, SecurityAuditEvent>(); private readonly permissionCache = new Map<string, Permission[]>(); // Performance tracking private eventCount = 0; private eventsByType = new Map<SecurityEventType, number>(); private eventsBySeverity = new Map<SecurityEventSeverity, number>(); private violationCount = 0; private blockedAttempts = 0; private totalResponseTime = 0; // Background processes private lockCleanupTimer: NodeJS.Timeout | null = null; private auditCleanupTimer: NodeJS.Timeout | null = null; private metricsTimer: NodeJS.Timeout | null = null; private constructor(config: UnifiedSecurityEngineConfig) { super(); this.config = config; // Initialize event counters ['authentication', 'authorization', 'access_attempt', 'data_access', 'data_modification', 'security_violation', 'system_event', 'suspicious_activity', 'compliance_event', 'error_event'].forEach(type => { this.eventsByType.set(type as SecurityEventType, 0); }); ['info', 'low', 'medium', 'high', 'critical'].forEach(severity => { this.eventsBySeverity.set(severity as SecurityEventSeverity, 0); }); logger.info('Unified Security Engine initialized'); } /** * Get singleton instance */ public static getInstance(config?: UnifiedSecurityEngineConfig): UnifiedSecurityEngine { if (!UnifiedSecurityEngine.instance) { if (!config) { throw new Error('Configuration required for first initialization'); } UnifiedSecurityEngine.instance = new UnifiedSecurityEngine(config); } return UnifiedSecurityEngine.instance; } /** * Reset singleton instance (for testing) */ public static resetInstance(): void { if (UnifiedSecurityEngine.instance) { UnifiedSecurityEngine.instance.dispose(); UnifiedSecurityEngine.instance = null; } } // ============================================================================= // INITIALIZATION AND LIFECYCLE // ============================================================================= /** * Initialize the security engine */ public async initialize(): Promise<Result<void, EnhancedError>> { if (this.initialized) { return createSuccess(undefined); } try { // Load security configuration await this.loadSecurityConfiguration(); // Initialize security components await this.initializeSecurityComponents(); // Start background processes this.startBackgroundProcesses(); this.initialized = true; this.emit('initialized'); logger.info('Security engine initialized successfully'); return createSuccess(undefined); } catch (error) { return createFailure(ErrorFactory.createError( 'system', `Failed to initialize security engine: ${error instanceof Error ? error.message : 'Unknown error'}`, createErrorContext('UnifiedSecurityEngine', 'initialize').build(), { cause: error instanceof Error ? error : undefined } )); } } /** * Load security configuration */ private async loadSecurityConfiguration(): Promise<void> { try { getUnifiedSecurityConfig(); // Merge with default configuration logger.info('Security configuration loaded successfully'); } catch (error) { logger.warn('Failed to load security configuration, using defaults:', error); } } /** * Initialize security components */ private async initializeSecurityComponents(): Promise<void> { // Initialize audit logging await this.initializeAuditLogging(); // Initialize path security await this.initializePathSecurity(); // Initialize concurrent access management await this.initializeConcurrentAccess(); logger.info('Security components initialized'); } /** * Initialize audit logging */ private async initializeAuditLogging(): Promise<void> { if (!this.config.audit.enabled) { return; } // Log security engine startup await this.logSecurityEvent({ type: 'system_event', severity: 'info', action: 'security_engine_startup', result: 'success', details: { config: { strictMode: this.config.strictMode, auditEnabled: this.config.audit.enabled, pathSecurityEnabled: this.config.pathSecurity.enabled } } }); } /** * Initialize path security */ private async initializePathSecurity(): Promise<void> { if (!this.config.pathSecurity.enabled) { return; } // Validate configured paths for (const path of this.config.pathSecurity.allowedReadPaths) { try { await fs.access(path); } catch { logger.warn(`Configured read path does not exist: ${path}`); } } for (const path of this.config.pathSecurity.allowedWritePaths) { try { await fs.access(path); } catch { logger.warn(`Configured write path does not exist: ${path}`); } } } /** * Initialize concurrent access management */ private async initializeConcurrentAccess(): Promise<void> { if (!this.config.concurrentAccess.enabled) { return; } // Clean up any stale locks from previous sessions await this.cleanupStaleLocks(); } /** * Start background processes */ private startBackgroundProcesses(): void { // Lock cleanup process if (this.config.concurrentAccess.enabled) { this.lockCleanupTimer = setInterval(() => { this.cleanupStaleLocks().catch(error => { logger.error('Lock cleanup process failed:', error); }); }, this.config.concurrentAccess.lockCleanupInterval * 1000); } // Audit cleanup process if (this.config.audit.enabled) { this.auditCleanupTimer = setInterval(() => { this.cleanupOldAuditEvents().catch(error => { logger.error('Audit cleanup process failed:', error); }); }, 24 * 60 * 60 * 1000); // Daily } // Metrics collection this.metricsTimer = setInterval(() => { this.collectMetrics(); }, 60 * 1000); // Every minute logger.info('Security background processes started'); } // ============================================================================= // AUTHENTICATION AND AUTHORIZATION // ============================================================================= /** * Authenticate user and create session */ public async authenticateUser(credentials: { userId: string; token: string; metadata?: Record<string, unknown> }): Promise<Result<UserContext, EnhancedError>> { const startTime = Date.now(); try { if (!this.config.authentication.enabled) { return createFailure(ErrorFactory.createError( 'permission', 'Authentication is disabled', createErrorContext('UnifiedSecurityEngine', 'authenticateUser').build() )); } // Validate credentials (simplified for demo) const isValid = await this.validateCredentials(credentials); if (!isValid) { await this.logSecurityEvent({ type: 'authentication', severity: 'medium', action: 'authentication_failed', result: 'failure', details: { userId: credentials.userId, reason: 'invalid_credentials' } }); return createFailure(ErrorFactory.createError( 'permission', 'Invalid credentials', createErrorContext('UnifiedSecurityEngine', 'authenticateUser').build() )); } // Create session const sessionId = createSessionId(crypto.randomUUID()); const userContext: UserContext = { userId: credentials.userId, sessionId, role: this.determineUserRole(credentials.userId), permissions: await this.getUserPermissions(credentials.userId), authenticatedAt: new Date(), lastActivity: new Date(), metadata: credentials.metadata || {} }; this.activeSessions.set(sessionId, userContext); await this.logSecurityEvent({ type: 'authentication', severity: 'info', action: 'authentication_success', result: 'success', details: { userId: credentials.userId, sessionId, role: userContext.role } }); this.trackPerformance('authentication', Date.now() - startTime); this.emit('userAuthenticated', userContext); return createSuccess(userContext); } catch (error) { return createFailure(ErrorFactory.createError( 'system', `Authentication failed: ${error instanceof Error ? error.message : 'Unknown error'}`, createErrorContext('UnifiedSecurityEngine', 'authenticateUser').build(), { cause: error instanceof Error ? error : undefined } )); } } /** * Authorize user action */ public async authorizeAction(sessionId: SessionId, permission: Permission, resource?: string): Promise<Result<boolean, EnhancedError>> { const startTime = Date.now(); try { if (!this.config.authorization.enabled) { return createSuccess(true); } const userContext = this.activeSessions.get(sessionId); if (!userContext) { await this.logSecurityEvent({ type: 'authorization', severity: 'medium', action: 'authorization_failed', result: 'failure', details: { sessionId, permission, resource, reason: 'invalid_session' } }); return createFailure(ErrorFactory.createError( 'permission', 'Invalid session', createErrorContext('UnifiedSecurityEngine', 'authorizeAction').build() )); } // Check permission const hasPermission = userContext.permissions.includes(permission) || userContext.permissions.includes('system:admin' as Permission); if (!hasPermission) { await this.logSecurityEvent({ type: 'authorization', severity: 'medium', action: 'authorization_denied', result: 'blocked', details: { userId: userContext.userId, sessionId, permission, resource, userRole: userContext.role, userPermissions: userContext.permissions } }); this.blockedAttempts++; return createSuccess(false); } // Update last activity userContext.lastActivity = new Date(); await this.logSecurityEvent({ type: 'authorization', severity: 'info', action: 'authorization_granted', result: 'success', details: { userId: userContext.userId, sessionId, permission, resource } }); this.trackPerformance('authorization', Date.now() - startTime); return createSuccess(true); } catch (error) { return createFailure(ErrorFactory.createError( 'system', `Authorization failed: ${error instanceof Error ? error.message : 'Unknown error'}`, createErrorContext('UnifiedSecurityEngine', 'authorizeAction').build(), { cause: error instanceof Error ? error : undefined } )); } } // ============================================================================= // PATH VALIDATION AND FILESYSTEM SECURITY // ============================================================================= /** * Validate file path for security */ public async validatePath(inputPath: string, operation: PathOperation): Promise<Result<PathValidationResult, EnhancedError>> { const startTime = Date.now(); try { if (!this.config.pathSecurity.enabled) { return createSuccess({ isValid: true, normalizedPath: inputPath, auditInfo: { originalPath: inputPath, timestamp: new Date(), validationTime: Date.now() - startTime } }); } const result: PathValidationResult = { isValid: false, auditInfo: { originalPath: inputPath, timestamp: new Date(), validationTime: 0 } }; // Normalize path let normalizedPath: string; try { normalizedPath = resolve(normalize(inputPath)); } catch { result.error = 'Invalid path format'; result.violationType = 'invalid_path'; result.auditInfo.validationTime = Date.now() - startTime; return createSuccess(result); } // Check for path traversal if (inputPath.includes('..') || inputPath.includes('~')) { result.error = 'Path traversal detected'; result.violationType = 'path_traversal'; result.auditInfo.validationTime = Date.now() - startTime; await this.logSecurityEvent({ type: 'security_violation', severity: 'high', action: 'path_traversal_attempt', result: 'blocked', details: { originalPath: inputPath, normalizedPath, operation } }); this.violationCount++; return createSuccess(result); } // Check against allowed paths const allowedPaths = operation === 'read' ? this.config.pathSecurity.allowedReadPaths : this.config.pathSecurity.allowedWritePaths; const isAllowed = allowedPaths.some(allowedPath => { const resolvedAllowedPath = resolve(allowedPath); return normalizedPath.startsWith(resolvedAllowedPath); }); if (!isAllowed) { result.error = 'Path outside allowed boundaries'; result.violationType = 'outside_boundary'; result.auditInfo.validationTime = Date.now() - startTime; await this.logSecurityEvent({ type: 'security_violation', severity: 'medium', action: 'boundary_violation', result: 'blocked', details: { originalPath: inputPath, normalizedPath, operation, allowedPaths } }); this.violationCount++; return createSuccess(result); } // Check file extension if configured if (this.config.pathSecurity.allowedExtensions.length > 0) { const ext = inputPath.split('.').pop()?.toLowerCase(); const extWithDot = ext ? `.${ext}` : ''; if (ext && !this.config.pathSecurity.allowedExtensions.includes(extWithDot)) { result.error = 'File extension not allowed'; result.violationType = 'invalid_extension'; result.warnings = [`Extension '${extWithDot}' is not in allowed list: ${this.config.pathSecurity.allowedExtensions.join(', ')}`]; result.auditInfo.validationTime = Date.now() - startTime; return createSuccess(result); } } // Path is valid result.isValid = true; result.normalizedPath = normalizedPath; result.auditInfo.validationTime = Date.now() - startTime; this.trackPerformance('path_validation', Date.now() - startTime); return createSuccess(result); } catch (error) { return createFailure(ErrorFactory.createError( 'system', `Path validation failed: ${error instanceof Error ? error.message : 'Unknown error'}`, createErrorContext('UnifiedSecurityEngine', 'validatePath').build(), { cause: error instanceof Error ? error : undefined } )); } } // ============================================================================= // DATA SANITIZATION // ============================================================================= /** * Sanitize input data */ public async sanitizeData<T>(data: T): Promise<Result<SanitizationResult<T>, EnhancedError>> { const startTime = Date.now(); try { if (!this.config.dataSanitization.enabled) { return createSuccess({ success: true, sanitizedData: data, originalData: data, violations: [], sanitizationTime: Date.now() - startTime }); } const result: SanitizationResult<T> = { success: false, originalData: data, violations: [], sanitizationTime: 0 }; // Sanitize based on data type let sanitizedData: T; if (typeof data === 'string') { sanitizedData = this.sanitizeString(data as unknown as string) as unknown as T; } else if (typeof data === 'object' && data !== null) { sanitizedData = this.sanitizeObject(data) as T; } else { sanitizedData = data; } result.success = true; result.sanitizedData = sanitizedData; result.sanitizationTime = Date.now() - startTime; this.trackPerformance('sanitization', Date.now() - startTime); return createSuccess(result); } catch (error) { return createFailure(ErrorFactory.createError( 'system', `Data sanitization failed: ${error instanceof Error ? error.message : 'Unknown error'}`, createErrorContext('UnifiedSecurityEngine', 'sanitizeData').build(), { cause: error instanceof Error ? error : undefined } )); } } /** * Sanitize string input */ private sanitizeString(input: string): string { let sanitized = input; // Remove potential script tags if (!this.config.dataSanitization.allowScripts) { sanitized = sanitized.replace(/<script\b[^<]*(?:(?!<\/script>)<[^<]*)*<\/script>/gi, ''); } // Remove potential HTML if not allowed if (!this.config.dataSanitization.allowHtml) { sanitized = sanitized.replace(/<[^>]*>/g, ''); } // Limit string length if (sanitized.length > this.config.dataSanitization.maxStringLength) { sanitized = sanitized.substring(0, this.config.dataSanitization.maxStringLength); } // Remove null bytes and other dangerous characters sanitized = sanitized.replace(/\0/g, ''); return sanitized; } /** * Sanitize object input */ private sanitizeObject(input: unknown): unknown { if (Array.isArray(input)) { return input.map(item => this.sanitizeObject(item)); } if (typeof input === 'object' && input !== null) { const sanitized: Record<string, unknown> = {}; for (const [key, value] of Object.entries(input)) { const sanitizedKey = this.sanitizeString(key); sanitized[sanitizedKey] = this.sanitizeObject(value); } return sanitized; } if (typeof input === 'string') { return this.sanitizeString(input); } return input; } // ============================================================================= // CONCURRENT ACCESS MANAGEMENT // ============================================================================= /** * Acquire lock for resource */ public async acquireLock(resource: string, operation: LockOperation, sessionId?: SessionId, timeoutMs?: number): Promise<Result<LockAcquisitionResult, EnhancedError>> { const startTime = Date.now(); try { if (!this.config.concurrentAccess.enabled) { return createSuccess({ success: true, lockId: createLockId(crypto.randomUUID()) }); } const lockId = createLockId(crypto.randomUUID()); const timeout = timeoutMs || this.config.concurrentAccess.maxLockDuration; // Check for existing locks const existingLock = Array.from(this.activeLocks.values()).find(lock => lock.resource === resource && (lock.operation === 'write' || operation === 'write') ); if (existingLock) { return createSuccess({ success: false, error: 'Resource is locked', existingLock, waitTime: Date.now() - startTime }); } // Create lock const lockInfo: LockInfo = { id: lockId, resource, owner: sessionId ? this.activeSessions.get(sessionId)?.userId || 'unknown' : 'system', sessionId, operation, acquiredAt: new Date(), expiresAt: new Date(Date.now() + timeout), metadata: {} }; this.activeLocks.set(lockId, lockInfo); await this.logSecurityEvent({ type: 'system_event', severity: 'info', action: 'lock_acquired', result: 'success', details: { lockId, resource, operation, owner: lockInfo.owner } }); this.emit('lockAcquired', lockInfo); return createSuccess({ success: true, lockId, waitTime: Date.now() - startTime }); } catch (error) { return createFailure(ErrorFactory.createError( 'system', `Lock acquisition failed: ${error instanceof Error ? error.message : 'Unknown error'}`, createErrorContext('UnifiedSecurityEngine', 'acquireLock').build(), { cause: error instanceof Error ? error : undefined } )); } } /** * Release lock */ public async releaseLock(lockId: LockId): Promise<Result<void, EnhancedError>> { try { const lockInfo = this.activeLocks.get(lockId); if (!lockInfo) { return createFailure(ErrorFactory.createError( 'validation', `Lock not found: ${lockId}`, createErrorContext('UnifiedSecurityEngine', 'releaseLock').build() )); } this.activeLocks.delete(lockId); await this.logSecurityEvent({ type: 'system_event', severity: 'info', action: 'lock_released', result: 'success', details: { lockId, resource: lockInfo.resource, owner: lockInfo.owner } }); this.emit('lockReleased', lockInfo); return createSuccess(undefined); } catch (error) { return createFailure(ErrorFactory.createError( 'system', `Lock release failed: ${error instanceof Error ? error.message : 'Unknown error'}`, createErrorContext('UnifiedSecurityEngine', 'releaseLock').build(), { cause: error instanceof Error ? error : undefined } )); } } // ============================================================================= // AUDIT LOGGING // ============================================================================= /** * Log security event */ public async logSecurityEvent(event: Omit<SecurityAuditEvent, 'id' | 'timestamp' | 'metadata'>): Promise<Result<AuditId, EnhancedError>> { try { if (!this.config.audit.enabled) { return createSuccess(createAuditId('disabled')); } const auditId = createAuditId(crypto.randomUUID()); const auditEvent: SecurityAuditEvent = { id: auditId, timestamp: new Date(), metadata: {}, ...event }; this.auditEvents.set(auditId, auditEvent); // Update statistics this.eventCount++; this.eventsByType.set(event.type, (this.eventsByType.get(event.type) || 0) + 1); this.eventsBySeverity.set(event.severity, (this.eventsBySeverity.get(event.severity) || 0) + 1); // Log to system logger based on severity const logMessage = `Security Event: ${event.action} - ${event.result}`; switch (event.severity) { case 'critical': case 'high': logger.error(logMessage, auditEvent); break; case 'medium': logger.warn(logMessage, auditEvent); break; default: logger.info(logMessage, auditEvent); } this.emit('securityEvent', auditEvent); return createSuccess(auditId); } catch (error) { return createFailure(ErrorFactory.createError( 'system', `Security event logging failed: ${error instanceof Error ? error.message : 'Unknown error'}`, createErrorContext('UnifiedSecurityEngine', 'logSecurityEvent').build(), { cause: error instanceof Error ? error : undefined } )); } } // ============================================================================= // UTILITY METHODS // ============================================================================= /** * Validate user credentials */ private async validateCredentials(credentials: { userId: string; token: string }): Promise<boolean> { // Simplified validation - in production, this would check against a secure store return credentials.userId.length > 0 && credentials.token.length > 0; } /** * Determine user role */ private determineUserRole(userId: string): UserRole { // Simplified role determination - in production, this would check against a user store if (userId === 'admin') return 'admin'; if (userId.startsWith('manager')) return 'manager'; if (userId.startsWith('dev')) return 'developer'; return 'viewer'; } /** * Get user permissions */ private async getUserPermissions(userId: string): Promise<Permission[]> { const cacheKey = `permissions:${userId}`; if (this.config.authorization.permissionCache && this.permissionCache.has(cacheKey)) { return this.permissionCache.get(cacheKey)!; } // Simplified permission assignment - in production, this would check against a permission store const role = this.determineUserRole(userId); let permissions: Permission[] = []; switch (role) { case 'admin': permissions = ['system:admin', 'system:config', 'system:audit'] as Permission[]; break; case 'manager': permissions = ['project:create', 'project:read', 'project:update', 'task:create', 'task:read', 'task:update', 'agent:manage'] as Permission[]; break; case 'developer': permissions = ['task:create', 'task:read', 'task:update', 'task:execute', 'file:read', 'file:write'] as Permission[]; break; case 'viewer': permissions = ['task:read', 'project:read', 'file:read'] as Permission[]; break; default: permissions = []; } if (this.config.authorization.permissionCache) { this.permissionCache.set(cacheKey, permissions); } return permissions; } /** * Clean up stale locks */ private async cleanupStaleLocks(): Promise<void> { const now = new Date(); const staleLocks: LockId[] = []; for (const [lockId, lockInfo] of this.activeLocks.entries()) { if (lockInfo.expiresAt < now) { staleLocks.push(lockId); } } for (const lockId of staleLocks) { const lockInfo = this.activeLocks.get(lockId); this.activeLocks.delete(lockId); if (lockInfo) { await this.logSecurityEvent({ type: 'system_event', severity: 'info', action: 'lock_expired', result: 'success', details: { lockId, resource: lockInfo.resource, owner: lockInfo.owner } }); } } if (staleLocks.length > 0) { logger.debug(`Cleaned up ${staleLocks.length} stale locks`); } } /** * Clean up old audit events */ private async cleanupOldAuditEvents(): Promise<void> { const cutoffDate = new Date(Date.now() - this.config.audit.retentionDays * 24 * 60 * 60 * 1000); const oldEvents: AuditId[] = []; for (const [auditId, event] of this.auditEvents.entries()) { if (event.timestamp < cutoffDate) { oldEvents.push(auditId); } } for (const auditId of oldEvents) { this.auditEvents.delete(auditId); } if (oldEvents.length > 0) { logger.debug(`Cleaned up ${oldEvents.length} old audit events`); } } /** * Track performance metrics */ private trackPerformance(operation: string, responseTime: number): void { this.totalResponseTime += responseTime; if (responseTime > this.config.performanceThresholdMs) { logger.warn(`Security operation '${operation}' exceeded performance threshold: ${responseTime}ms`); } } /** * Collect metrics */ private collectMetrics(): void { const stats: SecurityStatistics = { totalEvents: this.eventCount, eventsByType: Object.fromEntries(this.eventsByType) as Record<SecurityEventType, number>, eventsBySeverity: Object.fromEntries(this.eventsBySeverity) as Record<SecurityEventSeverity, number>, violationCount: this.violationCount, blockedAttempts: this.blockedAttempts, activeUsers: new Set(Array.from(this.activeSessions.values()).map(s => s.userId)).size, activeSessions: this.activeSessions.size, activeLocks: this.activeLocks.size, averageResponseTime: this.eventCount > 0 ? this.totalResponseTime / this.eventCount : 0, securityScore: this.calculateSecurityScore() }; this.emit('metricsCollected', stats); } /** * Calculate security score (0-100) */ private calculateSecurityScore(): number { let score = 100; // Deduct points for violations if (this.violationCount > 0) { score -= Math.min(this.violationCount * 2, 30); } // Deduct points for blocked attempts if (this.blockedAttempts > 0) { score -= Math.min(this.blockedAttempts * 1, 20); } // Deduct points for performance issues const avgResponseTime = this.eventCount > 0 ? this.totalResponseTime / this.eventCount : 0; if (avgResponseTime > this.config.performanceThresholdMs) { score -= 10; } return Math.max(score, 0); } /** * Get security statistics */ public getStatistics(): SecurityStatistics { return { totalEvents: this.eventCount, eventsByType: Object.fromEntries(this.eventsByType) as Record<SecurityEventType, number>, eventsBySeverity: Object.fromEntries(this.eventsBySeverity) as Record<SecurityEventSeverity, number>, violationCount: this.violationCount, blockedAttempts: this.blockedAttempts, activeUsers: new Set(Array.from(this.activeSessions.values()).map(s => s.userId)).size, activeSessions: this.activeSessions.size, activeLocks: this.activeLocks.size, averageResponseTime: this.eventCount > 0 ? this.totalResponseTime / this.eventCount : 0, securityScore: this.calculateSecurityScore() }; } // ============================================================================= // CLEANUP AND DISPOSAL // ============================================================================= /** * Dispose of the engine and clean up resources */ public dispose(): void { // Stop timers if (this.lockCleanupTimer) { clearInterval(this.lockCleanupTimer); this.lockCleanupTimer = null; } if (this.auditCleanupTimer) { clearInterval(this.auditCleanupTimer); this.auditCleanupTimer = null; } if (this.metricsTimer) { clearInterval(this.metricsTimer); this.metricsTimer = null; } // Clear state this.activeSessions.clear(); this.activeLocks.clear(); this.auditEvents.clear(); this.permissionCache.clear(); // Remove all listeners this.removeAllListeners(); this.initialized = false; logger.info('Unified Security Engine disposed'); } } // ============================================================================= // DEFAULT CONFIGURATION // ============================================================================= /** * Create default configuration for the unified security engine */ export function createDefaultSecurityConfig(): UnifiedSecurityEngineConfig { return { enabled: true, strictMode: false, performanceThresholdMs: 1000, logViolations: true, blockOnCriticalViolations: true, authentication: { enabled: true, tokenExpiryMinutes: 60, maxSessionsPerUser: 5, requireStrongPasswords: true, enableMFA: false }, authorization: { enabled: true, defaultRole: 'viewer', roleHierarchy: { admin: ['manager', 'developer', 'viewer', 'guest'], manager: ['developer', 'viewer', 'guest'], developer: ['viewer', 'guest'], viewer: ['guest'], guest: [] }, permissionCache: true }, pathSecurity: { enabled: true, allowedReadPaths: [process.cwd()], allowedWritePaths: [process.cwd()], allowedExtensions: ['.ts', '.js', '.json', '.md', '.txt', '.yaml', '.yml'], blockSystemPaths: true, followSymlinks: false }, dataSanitization: { enabled: true, strictMode: false, allowHtml: false, allowScripts: false, maxStringLength: 10000, sanitizeFileNames: true }, concurrentAccess: { enabled: true, maxLockDuration: 300000, // 5 minutes deadlockDetection: true, lockCleanupInterval: 60, // 1 minute maxLocksPerResource: 10 }, audit: { enabled: true, logLevel: 'info', retentionDays: 30, enableIntegrityChecks: true, compressLogs: false }, filesystem: { enabled: true, systemDirectoryBlacklist: [ '/private/var/spool', '/System', '/usr/bin', '/usr/sbin', '/bin', '/sbin' ], maxFileSize: 10485760, // 10MB allowedMimeTypes: ['text/plain', 'application/json', 'text/markdown'], scanForMalware: false } }; }

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/freshtechbro/vibe-coder-mcp'

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