532 lines
16 KiB
JavaScript
532 lines
16 KiB
JavaScript
|
|
/**
|
||
|
|
* Security Audit Logger
|
||
|
|
* Tracks security-related events for compliance and forensics
|
||
|
|
* Integrated with SIEM for centralized log aggregation
|
||
|
|
*/
|
||
|
|
|
||
|
|
const logger = require('./logger');
|
||
|
|
const { db } = require('../database/db');
|
||
|
|
const logAggregator = require('./logAggregator');
|
||
|
|
|
||
|
|
class SecurityAuditLogger {
|
||
|
|
/**
|
||
|
|
* Log authentication events
|
||
|
|
*/
|
||
|
|
static async logAuthEvent(eventType, userId, details = {}) {
|
||
|
|
const event = {
|
||
|
|
event_type: eventType,
|
||
|
|
user_id: userId,
|
||
|
|
ip_address: details.ip || 'unknown',
|
||
|
|
user_agent: details.userAgent || 'unknown',
|
||
|
|
success: details.success !== false,
|
||
|
|
failure_reason: details.failureReason || null,
|
||
|
|
metadata: JSON.stringify(details.metadata || {}),
|
||
|
|
timestamp: new Date().toISOString()
|
||
|
|
};
|
||
|
|
|
||
|
|
try {
|
||
|
|
await new Promise((resolve, reject) => {
|
||
|
|
db.run(
|
||
|
|
`INSERT INTO security_audit_log (event_type, user_id, ip_address, user_agent, success, failure_reason, metadata, timestamp)
|
||
|
|
VALUES (?, ?, ?, ?, ?, ?, ?, ?)`,
|
||
|
|
[event.event_type, event.user_id, event.ip_address, event.user_agent, event.success ? 1 : 0, event.failure_reason, event.metadata, event.timestamp],
|
||
|
|
(err) => err ? reject(err) : resolve()
|
||
|
|
);
|
||
|
|
});
|
||
|
|
|
||
|
|
logger.info(`[SECURITY] ${eventType}: user=${userId}, ip=${event.ip_address}, success=${event.success}`);
|
||
|
|
|
||
|
|
// Aggregate to SIEM
|
||
|
|
const level = event.success ? 'info' : 'warn';
|
||
|
|
const source = eventType.startsWith('LOGIN') || eventType.includes('PASSWORD') ? 'authentication' : 'security_audit';
|
||
|
|
logAggregator.aggregate(source, level, 'authentication', `${eventType}: ${event.success ? 'success' : 'failure'}`, {
|
||
|
|
userId: event.user_id,
|
||
|
|
ip: event.ip_address,
|
||
|
|
userAgent: event.user_agent,
|
||
|
|
failureReason: event.failure_reason,
|
||
|
|
metadata: details.metadata || {}
|
||
|
|
});
|
||
|
|
} catch (error) {
|
||
|
|
logger.error('Failed to log security event:', error);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Log login attempt
|
||
|
|
*/
|
||
|
|
static async logLoginAttempt(username, success, details = {}) {
|
||
|
|
return this.logAuthEvent('LOGIN_ATTEMPT', null, {
|
||
|
|
success,
|
||
|
|
failureReason: success ? null : (details.reason || 'Invalid credentials'),
|
||
|
|
ip: details.ip,
|
||
|
|
userAgent: details.userAgent,
|
||
|
|
metadata: { username }
|
||
|
|
});
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Log successful login
|
||
|
|
*/
|
||
|
|
static async logLoginSuccess(userId, details = {}) {
|
||
|
|
return this.logAuthEvent('LOGIN_SUCCESS', userId, {
|
||
|
|
success: true,
|
||
|
|
ip: details.ip,
|
||
|
|
userAgent: details.userAgent,
|
||
|
|
metadata: { twoFactorUsed: details.twoFactorUsed || false }
|
||
|
|
});
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Log failed login
|
||
|
|
*/
|
||
|
|
static async logLoginFailure(username, reason, details = {}) {
|
||
|
|
return this.logAuthEvent('LOGIN_FAILURE', null, {
|
||
|
|
success: false,
|
||
|
|
failureReason: reason,
|
||
|
|
ip: details.ip,
|
||
|
|
userAgent: details.userAgent,
|
||
|
|
metadata: { username }
|
||
|
|
});
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Log account lockout
|
||
|
|
*/
|
||
|
|
static async logAccountLockout(userId, details = {}) {
|
||
|
|
return this.logAuthEvent('ACCOUNT_LOCKOUT', userId, {
|
||
|
|
success: false,
|
||
|
|
failureReason: 'Too many failed login attempts',
|
||
|
|
ip: details.ip,
|
||
|
|
userAgent: details.userAgent,
|
||
|
|
metadata: { failedAttempts: details.failedAttempts }
|
||
|
|
});
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Log password change
|
||
|
|
*/
|
||
|
|
static async logPasswordChange(userId, details = {}) {
|
||
|
|
return this.logAuthEvent('PASSWORD_CHANGE', userId, {
|
||
|
|
success: true,
|
||
|
|
ip: details.ip,
|
||
|
|
userAgent: details.userAgent,
|
||
|
|
metadata: { forced: details.forced || false, expired: details.expired || false }
|
||
|
|
});
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Log 2FA events
|
||
|
|
*/
|
||
|
|
static async log2FAEvent(eventType, userId, success, details = {}) {
|
||
|
|
return this.logAuthEvent(eventType, userId, {
|
||
|
|
success,
|
||
|
|
failureReason: success ? null : (details.reason || 'Invalid code'),
|
||
|
|
ip: details.ip,
|
||
|
|
userAgent: details.userAgent,
|
||
|
|
metadata: details.metadata || {}
|
||
|
|
});
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Log session events
|
||
|
|
*/
|
||
|
|
static async logSessionEvent(eventType, userId, details = {}) {
|
||
|
|
return this.logAuthEvent(eventType, userId, {
|
||
|
|
success: true,
|
||
|
|
ip: details.ip,
|
||
|
|
userAgent: details.userAgent,
|
||
|
|
metadata: { sessionId: details.sessionId }
|
||
|
|
});
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Log privilege escalation
|
||
|
|
*/
|
||
|
|
static async logPrivilegeEscalation(userId, details = {}) {
|
||
|
|
return this.logAuthEvent('PRIVILEGE_ESCALATION', userId, {
|
||
|
|
success: true,
|
||
|
|
ip: details.ip,
|
||
|
|
userAgent: details.userAgent,
|
||
|
|
metadata: {
|
||
|
|
fromRole: details.fromRole,
|
||
|
|
toRole: details.toRole,
|
||
|
|
grantedBy: details.grantedBy
|
||
|
|
}
|
||
|
|
});
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Get recent security events for a user
|
||
|
|
*/
|
||
|
|
static async getUserSecurityEvents(userId, limit = 50) {
|
||
|
|
return new Promise((resolve, reject) => {
|
||
|
|
db.all(
|
||
|
|
`SELECT * FROM security_audit_log
|
||
|
|
WHERE user_id = ?
|
||
|
|
ORDER BY timestamp DESC
|
||
|
|
LIMIT ?`,
|
||
|
|
[userId, limit],
|
||
|
|
(err, rows) => err ? reject(err) : resolve(rows)
|
||
|
|
);
|
||
|
|
});
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Get failed login attempts for an IP
|
||
|
|
*/
|
||
|
|
static async getFailedAttemptsForIP(ipAddress, timeWindowMinutes = 30) {
|
||
|
|
const cutoffTime = new Date(Date.now() - timeWindowMinutes * 60 * 1000).toISOString();
|
||
|
|
|
||
|
|
return new Promise((resolve, reject) => {
|
||
|
|
db.get(
|
||
|
|
`SELECT COUNT(*) as count
|
||
|
|
FROM security_audit_log
|
||
|
|
WHERE event_type IN ('LOGIN_FAILURE', 'LOGIN_ATTEMPT')
|
||
|
|
AND success = 0
|
||
|
|
AND ip_address = ?
|
||
|
|
AND timestamp > ?`,
|
||
|
|
[ipAddress, cutoffTime],
|
||
|
|
(err, row) => err ? reject(err) : resolve(row.count || 0)
|
||
|
|
);
|
||
|
|
});
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Get failed login attempts for a user
|
||
|
|
*/
|
||
|
|
static async getFailedAttemptsForUser(username, timeWindowMinutes = 30) {
|
||
|
|
const cutoffTime = new Date(Date.now() - timeWindowMinutes * 60 * 1000).toISOString();
|
||
|
|
|
||
|
|
return new Promise((resolve, reject) => {
|
||
|
|
db.get(
|
||
|
|
`SELECT COUNT(*) as count
|
||
|
|
FROM security_audit_log
|
||
|
|
WHERE event_type IN ('LOGIN_FAILURE', 'LOGIN_ATTEMPT')
|
||
|
|
AND success = 0
|
||
|
|
AND metadata LIKE ?
|
||
|
|
AND timestamp > ?`,
|
||
|
|
[`%"username":"${username}"%`, cutoffTime],
|
||
|
|
(err, row) => err ? reject(err) : resolve(row.count || 0)
|
||
|
|
);
|
||
|
|
});
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Clear old audit logs (data retention)
|
||
|
|
*/
|
||
|
|
static async cleanupOldLogs(retentionDays = 90) {
|
||
|
|
const cutoffDate = new Date(Date.now() - retentionDays * 24 * 60 * 60 * 1000).toISOString();
|
||
|
|
|
||
|
|
return new Promise((resolve, reject) => {
|
||
|
|
db.run(
|
||
|
|
'DELETE FROM security_audit_log WHERE timestamp < ?',
|
||
|
|
[cutoffDate],
|
||
|
|
function(err) {
|
||
|
|
if (err) reject(err);
|
||
|
|
else {
|
||
|
|
logger.info(`Cleaned up ${this.changes} old security audit logs`);
|
||
|
|
resolve(this.changes);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
);
|
||
|
|
});
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* CWE-778: Log token issuance (JWT, OAuth, etc.)
|
||
|
|
* Includes relevant metadata such as client ID, IP address, device info
|
||
|
|
*/
|
||
|
|
static async logTokenIssuance(userId, tokenType, details = {}) {
|
||
|
|
return this.logAuthEvent('TOKEN_ISSUED', userId, {
|
||
|
|
success: true,
|
||
|
|
ip: details.ip,
|
||
|
|
userAgent: details.userAgent,
|
||
|
|
metadata: {
|
||
|
|
tokenType: tokenType, // 'JWT', 'REFRESH', 'TEMP_2FA', 'OAUTH'
|
||
|
|
clientId: details.clientId,
|
||
|
|
deviceInfo: details.deviceInfo || this.extractDeviceInfo(details.userAgent),
|
||
|
|
expiresIn: details.expiresIn,
|
||
|
|
purpose: details.purpose, // 'login', '2fa', 'registration', 'password_reset'
|
||
|
|
scope: details.scope,
|
||
|
|
grantType: details.grantType
|
||
|
|
}
|
||
|
|
});
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* CWE-778: Log token refresh
|
||
|
|
*/
|
||
|
|
static async logTokenRefresh(userId, details = {}) {
|
||
|
|
return this.logAuthEvent('TOKEN_REFRESHED', userId, {
|
||
|
|
success: true,
|
||
|
|
ip: details.ip,
|
||
|
|
userAgent: details.userAgent,
|
||
|
|
metadata: {
|
||
|
|
tokenType: details.tokenType || 'JWT',
|
||
|
|
clientId: details.clientId,
|
||
|
|
deviceInfo: details.deviceInfo || this.extractDeviceInfo(details.userAgent),
|
||
|
|
oldTokenExpiry: details.oldTokenExpiry,
|
||
|
|
newTokenExpiry: details.newTokenExpiry
|
||
|
|
}
|
||
|
|
});
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* CWE-778: Log token revocation
|
||
|
|
*/
|
||
|
|
static async logTokenRevocation(userId, reason, details = {}) {
|
||
|
|
return this.logAuthEvent('TOKEN_REVOKED', userId, {
|
||
|
|
success: true,
|
||
|
|
ip: details.ip,
|
||
|
|
userAgent: details.userAgent,
|
||
|
|
metadata: {
|
||
|
|
reason: reason, // 'logout', 'password_change', 'security_breach', 'admin_action'
|
||
|
|
tokenType: details.tokenType || 'JWT',
|
||
|
|
sessionId: details.sessionId,
|
||
|
|
revokedBy: details.revokedBy // user_id of admin who revoked it
|
||
|
|
}
|
||
|
|
});
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* CWE-778: Log privilege changes
|
||
|
|
* Any activities where user's privilege level changes
|
||
|
|
*/
|
||
|
|
static async logPrivilegeChange(userId, action, details = {}) {
|
||
|
|
return this.logAuthEvent('PRIVILEGE_CHANGE', userId, {
|
||
|
|
success: true,
|
||
|
|
ip: details.ip,
|
||
|
|
userAgent: details.userAgent,
|
||
|
|
metadata: {
|
||
|
|
action: action, // 'role_assigned', 'role_removed', 'permission_granted', 'permission_revoked'
|
||
|
|
previousRole: details.previousRole,
|
||
|
|
newRole: details.newRole,
|
||
|
|
previousPermissions: details.previousPermissions,
|
||
|
|
newPermissions: details.newPermissions,
|
||
|
|
changedBy: details.changedBy, // user_id of admin who made the change
|
||
|
|
changedByUsername: details.changedByUsername,
|
||
|
|
reason: details.reason,
|
||
|
|
affectedUser: details.affectedUser // username of the user being changed
|
||
|
|
}
|
||
|
|
});
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* CWE-778: Log permission grant
|
||
|
|
*/
|
||
|
|
static async logPermissionGrant(userId, permission, details = {}) {
|
||
|
|
return this.logAuthEvent('PERMISSION_GRANTED', userId, {
|
||
|
|
success: true,
|
||
|
|
ip: details.ip,
|
||
|
|
userAgent: details.userAgent,
|
||
|
|
metadata: {
|
||
|
|
permission: permission,
|
||
|
|
grantedBy: details.grantedBy,
|
||
|
|
grantedByUsername: details.grantedByUsername,
|
||
|
|
scope: details.scope,
|
||
|
|
expiresAt: details.expiresAt
|
||
|
|
}
|
||
|
|
});
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* CWE-778: Log permission revocation
|
||
|
|
*/
|
||
|
|
static async logPermissionRevocation(userId, permission, details = {}) {
|
||
|
|
return this.logAuthEvent('PERMISSION_REVOKED', userId, {
|
||
|
|
success: true,
|
||
|
|
ip: details.ip,
|
||
|
|
userAgent: details.userAgent,
|
||
|
|
metadata: {
|
||
|
|
permission: permission,
|
||
|
|
revokedBy: details.revokedBy,
|
||
|
|
revokedByUsername: details.revokedByUsername,
|
||
|
|
reason: details.reason
|
||
|
|
}
|
||
|
|
});
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* CWE-778: Log user activation/deactivation
|
||
|
|
*/
|
||
|
|
static async logAccountStatusChange(userId, newStatus, details = {}) {
|
||
|
|
return this.logAuthEvent('ACCOUNT_STATUS_CHANGED', userId, {
|
||
|
|
success: true,
|
||
|
|
ip: details.ip,
|
||
|
|
userAgent: details.userAgent,
|
||
|
|
metadata: {
|
||
|
|
previousStatus: details.previousStatus,
|
||
|
|
newStatus: newStatus, // 'active', 'inactive', 'suspended', 'locked'
|
||
|
|
changedBy: details.changedBy,
|
||
|
|
changedByUsername: details.changedByUsername,
|
||
|
|
reason: details.reason
|
||
|
|
}
|
||
|
|
});
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* CWE-778: Log administrative activities
|
||
|
|
* For admin actions like user creation, deletion, unlock, force logout
|
||
|
|
*/
|
||
|
|
static async logAdminActivity(adminId, action, details = {}) {
|
||
|
|
return this.logAuthEvent('ADMIN_ACTIVITY', adminId, {
|
||
|
|
success: true,
|
||
|
|
ip: details.ip,
|
||
|
|
userAgent: details.userAgent,
|
||
|
|
metadata: {
|
||
|
|
action: action, // 'user_created', 'user_deleted', 'account_unlocked', 'password_reset', 'force_logout'
|
||
|
|
targetUserId: details.targetUserId,
|
||
|
|
targetUsername: details.targetUsername,
|
||
|
|
adminUsername: details.adminUsername,
|
||
|
|
changes: details.changes,
|
||
|
|
reason: details.reason,
|
||
|
|
deviceInfo: details.deviceInfo || this.extractDeviceInfo(details.userAgent)
|
||
|
|
}
|
||
|
|
});
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* CWE-778: Log sensitive data access
|
||
|
|
* For accessing user lists, settings, VPN configs, backups, etc.
|
||
|
|
*/
|
||
|
|
static async logSensitiveDataAccess(userId, dataType, details = {}) {
|
||
|
|
return this.logAuthEvent('SENSITIVE_DATA_ACCESS', userId, {
|
||
|
|
success: true,
|
||
|
|
ip: details.ip,
|
||
|
|
userAgent: details.userAgent,
|
||
|
|
metadata: {
|
||
|
|
dataType: dataType, // 'user_list', 'user_details', 'settings', 'vpn_configs', 'backups', 'audit_logs'
|
||
|
|
accessMethod: details.accessMethod || 'view', // 'view', 'export', 'download'
|
||
|
|
recordCount: details.recordCount,
|
||
|
|
filters: details.filters,
|
||
|
|
scope: details.scope, // 'own', 'all', 'specific'
|
||
|
|
deviceInfo: details.deviceInfo || this.extractDeviceInfo(details.userAgent)
|
||
|
|
}
|
||
|
|
});
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Extract device info from user agent
|
||
|
|
*/
|
||
|
|
static extractDeviceInfo(userAgent = '') {
|
||
|
|
if (!userAgent) return { deviceType: 'unknown', os: 'unknown', browser: 'unknown' };
|
||
|
|
|
||
|
|
const ua = userAgent.toLowerCase();
|
||
|
|
|
||
|
|
// Device type
|
||
|
|
let deviceType = 'desktop';
|
||
|
|
if (/bot|crawler|spider/.test(ua)) deviceType = 'bot';
|
||
|
|
else if (/mobile|android|iphone|ipod/.test(ua)) deviceType = 'mobile';
|
||
|
|
else if (/tablet|ipad/.test(ua)) deviceType = 'tablet';
|
||
|
|
|
||
|
|
// Operating System
|
||
|
|
let os = 'unknown';
|
||
|
|
if (/windows/.test(ua)) os = 'Windows';
|
||
|
|
else if (/mac os|macos/.test(ua)) os = 'macOS';
|
||
|
|
else if (/linux/.test(ua)) os = 'Linux';
|
||
|
|
else if (/android/.test(ua)) os = 'Android';
|
||
|
|
else if (/ios|iphone|ipad/.test(ua)) os = 'iOS';
|
||
|
|
|
||
|
|
// Browser
|
||
|
|
let browser = 'unknown';
|
||
|
|
if (/firefox/.test(ua)) browser = 'Firefox';
|
||
|
|
else if (/chrome/.test(ua) && !/edge|edg/.test(ua)) browser = 'Chrome';
|
||
|
|
else if (/safari/.test(ua) && !/chrome/.test(ua)) browser = 'Safari';
|
||
|
|
else if (/edge|edg/.test(ua)) browser = 'Edge';
|
||
|
|
else if (/opera|opr/.test(ua)) browser = 'Opera';
|
||
|
|
|
||
|
|
return { deviceType, os, browser };
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Get comprehensive audit statistics
|
||
|
|
*/
|
||
|
|
static async getAuditStatistics(timeRangeDays = 30) {
|
||
|
|
const cutoffDate = new Date(Date.now() - timeRangeDays * 24 * 60 * 60 * 1000).toISOString();
|
||
|
|
|
||
|
|
return new Promise((resolve, reject) => {
|
||
|
|
db.all(
|
||
|
|
`SELECT
|
||
|
|
event_type,
|
||
|
|
success,
|
||
|
|
COUNT(*) as count,
|
||
|
|
COUNT(DISTINCT user_id) as unique_users,
|
||
|
|
COUNT(DISTINCT ip_address) as unique_ips
|
||
|
|
FROM security_audit_log
|
||
|
|
WHERE timestamp > ?
|
||
|
|
GROUP BY event_type, success
|
||
|
|
ORDER BY count DESC`,
|
||
|
|
[cutoffDate],
|
||
|
|
(err, rows) => err ? reject(err) : resolve(rows)
|
||
|
|
);
|
||
|
|
});
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Log system events (startup, shutdown, cleanup, etc.)
|
||
|
|
*/
|
||
|
|
static async logSystemEvent(eventType, success, details = {}) {
|
||
|
|
return this.logAuthEvent(`SYSTEM_${eventType.toUpperCase()}`, null, {
|
||
|
|
success,
|
||
|
|
failureReason: success ? null : (details.error || 'System event failed'),
|
||
|
|
metadata: details
|
||
|
|
});
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Log security incidents (tampering, breaches, etc.)
|
||
|
|
*/
|
||
|
|
static async logSecurityIncident(incidentType, details = {}) {
|
||
|
|
const event = {
|
||
|
|
event_type: `SECURITY_INCIDENT_${incidentType.toUpperCase()}`,
|
||
|
|
user_id: details.userId || null,
|
||
|
|
ip_address: details.ip || 'system',
|
||
|
|
user_agent: details.userAgent || 'system',
|
||
|
|
success: false,
|
||
|
|
failure_reason: `Security incident: ${incidentType}`,
|
||
|
|
metadata: JSON.stringify(details),
|
||
|
|
timestamp: new Date().toISOString()
|
||
|
|
};
|
||
|
|
|
||
|
|
try {
|
||
|
|
await new Promise((resolve, reject) => {
|
||
|
|
db.run(
|
||
|
|
`INSERT INTO security_audit_log (event_type, user_id, ip_address, user_agent, success, failure_reason, metadata, timestamp)
|
||
|
|
VALUES (?, ?, ?, ?, ?, ?, ?, ?)`,
|
||
|
|
[event.event_type, event.user_id, event.ip_address, event.user_agent, 0, event.failure_reason, event.metadata, event.timestamp],
|
||
|
|
(err) => err ? reject(err) : resolve()
|
||
|
|
);
|
||
|
|
});
|
||
|
|
|
||
|
|
logger.error(`[SECURITY INCIDENT] ${incidentType}: ${JSON.stringify(details)}`);
|
||
|
|
|
||
|
|
// Aggregate to SIEM with CRITICAL level
|
||
|
|
logAggregator.aggregate('security_audit', 'critical', 'security_incident', `Security incident: ${incidentType}`, {
|
||
|
|
incidentType,
|
||
|
|
...details
|
||
|
|
});
|
||
|
|
} catch (error) {
|
||
|
|
logger.error('Failed to log security incident:', error);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Log admin activities (user management, config changes, etc.)
|
||
|
|
*/
|
||
|
|
static async logAdminActivity(adminId, action, details = {}) {
|
||
|
|
return this.logAuthEvent(`ADMIN_${action.toUpperCase()}`, adminId, {
|
||
|
|
success: true,
|
||
|
|
ip: details.ip,
|
||
|
|
userAgent: details.userAgent,
|
||
|
|
metadata: {
|
||
|
|
action,
|
||
|
|
target: details.target || details.targetUserId,
|
||
|
|
changes: details.changes,
|
||
|
|
...details
|
||
|
|
}
|
||
|
|
});
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
module.exports = SecurityAuditLogger;
|