import * as plugins from '../plugins.js'; import { logger } from '../logger.js'; /** * Log level for security events */ export enum SecurityLogLevel { INFO = 'info', WARN = 'warn', ERROR = 'error', CRITICAL = 'critical' } /** * Security event types for categorization */ export enum SecurityEventType { AUTHENTICATION = 'authentication', ACCESS_CONTROL = 'access_control', EMAIL_VALIDATION = 'email_validation', EMAIL_PROCESSING = 'email_processing', EMAIL_FORWARDING = 'email_forwarding', EMAIL_DELIVERY = 'email_delivery', DKIM = 'dkim', SPF = 'spf', DMARC = 'dmarc', RATE_LIMIT = 'rate_limit', RATE_LIMITING = 'rate_limiting', SPAM = 'spam', MALWARE = 'malware', CONNECTION = 'connection', DATA_EXPOSURE = 'data_exposure', CONFIGURATION = 'configuration', IP_REPUTATION = 'ip_reputation' } /** * Security event interface */ export interface ISecurityEvent { timestamp: number; level: SecurityLogLevel; type: SecurityEventType; message: string; details?: any; ipAddress?: string; userId?: string; sessionId?: string; emailId?: string; domain?: string; action?: string; result?: string; success?: boolean; } /** * Security logger for enhanced security monitoring */ export class SecurityLogger { private static instance: SecurityLogger; private securityEvents: ISecurityEvent[] = []; private maxEventHistory: number; private enableNotifications: boolean; private constructor(options?: { maxEventHistory?: number; enableNotifications?: boolean; }) { this.maxEventHistory = options?.maxEventHistory || 1000; this.enableNotifications = options?.enableNotifications || false; } /** * Get singleton instance */ public static getInstance(options?: { maxEventHistory?: number; enableNotifications?: boolean; }): SecurityLogger { if (!SecurityLogger.instance) { SecurityLogger.instance = new SecurityLogger(options); } return SecurityLogger.instance; } /** * Log a security event * @param event The security event to log */ public logEvent(event: Omit): void { const fullEvent: ISecurityEvent = { ...event, timestamp: Date.now() }; // Store in memory buffer this.securityEvents.push(fullEvent); // Trim history if needed if (this.securityEvents.length > this.maxEventHistory) { this.securityEvents.shift(); } // Log to regular logger with appropriate level switch (event.level) { case SecurityLogLevel.INFO: logger.log('info', `[SECURITY:${event.type}] ${event.message}`, event.details); break; case SecurityLogLevel.WARN: logger.log('warn', `[SECURITY:${event.type}] ${event.message}`, event.details); break; case SecurityLogLevel.ERROR: case SecurityLogLevel.CRITICAL: logger.log('error', `[SECURITY:${event.type}] ${event.message}`, event.details); // Send notification for critical events if enabled if (event.level === SecurityLogLevel.CRITICAL && this.enableNotifications) { this.sendNotification(fullEvent); } break; } } /** * Get recent security events * @param limit Maximum number of events to return * @param filter Filter for specific event types * @returns Recent security events */ public getRecentEvents(limit: number = 100, filter?: { level?: SecurityLogLevel; type?: SecurityEventType; fromTimestamp?: number; toTimestamp?: number; }): ISecurityEvent[] { let filteredEvents = this.securityEvents; // Apply filters if (filter) { if (filter.level) { filteredEvents = filteredEvents.filter(event => event.level === filter.level); } if (filter.type) { filteredEvents = filteredEvents.filter(event => event.type === filter.type); } if (filter.fromTimestamp) { filteredEvents = filteredEvents.filter(event => event.timestamp >= filter.fromTimestamp); } if (filter.toTimestamp) { filteredEvents = filteredEvents.filter(event => event.timestamp <= filter.toTimestamp); } } // Return most recent events up to limit return filteredEvents .sort((a, b) => b.timestamp - a.timestamp) .slice(0, limit); } /** * Get events by security level * @param level The security level to filter by * @param limit Maximum number of events to return * @returns Security events matching the level */ public getEventsByLevel(level: SecurityLogLevel, limit: number = 100): ISecurityEvent[] { return this.getRecentEvents(limit, { level }); } /** * Get events by security type * @param type The event type to filter by * @param limit Maximum number of events to return * @returns Security events matching the type */ public getEventsByType(type: SecurityEventType, limit: number = 100): ISecurityEvent[] { return this.getRecentEvents(limit, { type }); } /** * Get security events for a specific IP address * @param ipAddress The IP address to filter by * @param limit Maximum number of events to return * @returns Security events for the IP address */ public getEventsByIP(ipAddress: string, limit: number = 100): ISecurityEvent[] { return this.securityEvents .filter(event => event.ipAddress === ipAddress) .sort((a, b) => b.timestamp - a.timestamp) .slice(0, limit); } /** * Get security events for a specific domain * @param domain The domain to filter by * @param limit Maximum number of events to return * @returns Security events for the domain */ public getEventsByDomain(domain: string, limit: number = 100): ISecurityEvent[] { return this.securityEvents .filter(event => event.domain === domain) .sort((a, b) => b.timestamp - a.timestamp) .slice(0, limit); } /** * Send a notification for critical security events * @param event The security event to notify about * @private */ private sendNotification(event: ISecurityEvent): void { // In a production environment, this would integrate with a notification service // For now, we'll just log that we would send a notification logger.log('error', `[SECURITY NOTIFICATION] ${event.message}`, { ...event, notificationSent: true }); // Future integration with alerting systems would go here } /** * Clear event history */ public clearEvents(): void { this.securityEvents = []; } /** * Get statistical summary of security events * @param timeWindow Optional time window in milliseconds * @returns Summary of security events */ public getEventsSummary(timeWindow?: number): { total: number; byLevel: Record; byType: Record; topIPs: Array<{ ip: string; count: number }>; topDomains: Array<{ domain: string; count: number }>; } { // Filter by time window if provided let events = this.securityEvents; if (timeWindow) { const cutoff = Date.now() - timeWindow; events = events.filter(e => e.timestamp >= cutoff); } // Count by level const byLevel = Object.values(SecurityLogLevel).reduce((acc, level) => { acc[level] = events.filter(e => e.level === level).length; return acc; }, {} as Record); // Count by type const byType = Object.values(SecurityEventType).reduce((acc, type) => { acc[type] = events.filter(e => e.type === type).length; return acc; }, {} as Record); // Count by IP const ipCounts = new Map(); events.forEach(e => { if (e.ipAddress) { ipCounts.set(e.ipAddress, (ipCounts.get(e.ipAddress) || 0) + 1); } }); // Count by domain const domainCounts = new Map(); events.forEach(e => { if (e.domain) { domainCounts.set(e.domain, (domainCounts.get(e.domain) || 0) + 1); } }); // Sort and limit top entries const topIPs = Array.from(ipCounts.entries()) .map(([ip, count]) => ({ ip, count })) .sort((a, b) => b.count - a.count) .slice(0, 10); const topDomains = Array.from(domainCounts.entries()) .map(([domain, count]) => ({ domain, count })) .sort((a, b) => b.count - a.count) .slice(0, 10); return { total: events.length, byLevel, byType, topIPs, topDomains }; } }