109 lines
2.8 KiB
JavaScript
109 lines
2.8 KiB
JavaScript
const fs = require('fs');
|
|
const path = require('path');
|
|
|
|
class SecurityLogger {
|
|
constructor() {
|
|
// Default to logs directory, but allow override via environment
|
|
this.logDir = process.env.SECURITY_LOG_DIR || path.join(__dirname, '..', 'logs');
|
|
this.logFile = path.join(this.logDir, 'security-audit.log');
|
|
|
|
// Ensure log directory exists
|
|
this.ensureLogDirectory();
|
|
}
|
|
|
|
ensureLogDirectory() {
|
|
try {
|
|
if (!fs.existsSync(this.logDir)) {
|
|
fs.mkdirSync(this.logDir, { recursive: true });
|
|
}
|
|
} catch (error) {
|
|
console.error('Failed to create log directory:', error.message);
|
|
// Fallback to console logging only
|
|
this.logFile = null;
|
|
}
|
|
}
|
|
|
|
logSecurityEvent(level, message, metadata = {}) {
|
|
const timestamp = new Date().toISOString();
|
|
const logEntry = {
|
|
timestamp,
|
|
level: level.toUpperCase(),
|
|
message,
|
|
...metadata
|
|
};
|
|
|
|
// Always log to console for immediate visibility
|
|
console.log(`[SECURITY AUDIT] ${timestamp} - ${message}`);
|
|
|
|
// Also log to file if available
|
|
if (this.logFile) {
|
|
try {
|
|
const logLine = JSON.stringify(logEntry) + '\n';
|
|
fs.appendFileSync(this.logFile, logLine);
|
|
} catch (error) {
|
|
console.error('Failed to write to security log file:', error.message);
|
|
}
|
|
}
|
|
}
|
|
|
|
logIPRestriction(ip, tenant, userAgent, denied = true) {
|
|
const action = denied ? 'denied access to' : 'granted access to';
|
|
this.logSecurityEvent('WARNING', `IP ${ip} ${action} tenant ${tenant}`, {
|
|
type: 'IP_RESTRICTION',
|
|
ip,
|
|
tenant,
|
|
userAgent: userAgent || 'unknown',
|
|
denied
|
|
});
|
|
}
|
|
|
|
logAuthFailure(reason, metadata = {}) {
|
|
this.logSecurityEvent('ERROR', `Authentication failure: ${reason}`, {
|
|
type: 'AUTH_FAILURE',
|
|
reason,
|
|
...metadata
|
|
});
|
|
}
|
|
|
|
logSuspiciousActivity(activity, metadata = {}) {
|
|
this.logSecurityEvent('CRITICAL', `Suspicious activity detected: ${activity}`, {
|
|
type: 'SUSPICIOUS_ACTIVITY',
|
|
activity,
|
|
...metadata
|
|
});
|
|
}
|
|
|
|
// Get recent security events for monitoring
|
|
getRecentEvents(count = 100) {
|
|
if (!this.logFile || !fs.existsSync(this.logFile)) {
|
|
return [];
|
|
}
|
|
|
|
try {
|
|
const content = fs.readFileSync(this.logFile, 'utf8');
|
|
const lines = content.trim().split('\n').filter(line => line);
|
|
|
|
return lines
|
|
.slice(-count)
|
|
.map(line => {
|
|
try {
|
|
return JSON.parse(line);
|
|
} catch {
|
|
return null;
|
|
}
|
|
})
|
|
.filter(Boolean);
|
|
} catch (error) {
|
|
console.error('Failed to read security log file:', error.message);
|
|
return [];
|
|
}
|
|
}
|
|
}
|
|
|
|
// Singleton instance
|
|
const securityLogger = new SecurityLogger();
|
|
|
|
module.exports = {
|
|
SecurityLogger,
|
|
securityLogger
|
|
}; |