167 lines
4.4 KiB
TypeScript
167 lines
4.4 KiB
TypeScript
/**
|
|
* Antivirus Admin Routes
|
|
* Admin endpoints for ClamAV management and audit logs.
|
|
*/
|
|
|
|
import { Router, Request, Response } from 'express';
|
|
import { authenticateToken } from '../middlewares/auth.middleware';
|
|
import { requireAdmin } from '../middlewares/authorization.middleware';
|
|
import { asyncHandler } from '../middlewares/errorHandler.middleware';
|
|
import {
|
|
getToggleStatus,
|
|
setToggleStatus,
|
|
getToggleHistory,
|
|
} from '../services/clamav/clamavToggleManager';
|
|
import { pingDaemon } from '../services/clamav/clamavScanWrapper';
|
|
import {
|
|
readAuditLogs,
|
|
getAuditStats,
|
|
exportAuditLogsCSV,
|
|
logSecurityEvent,
|
|
SecurityEventType,
|
|
} from '../services/logging/securityEventLogger';
|
|
|
|
const router = Router();
|
|
|
|
// All routes require admin authentication
|
|
router.use(authenticateToken, requireAdmin);
|
|
|
|
/**
|
|
* GET /api/v1/antivirus/clamav-status
|
|
* Get ClamAV toggle status, daemon health, and recent toggle history
|
|
*/
|
|
router.get(
|
|
'/clamav-status',
|
|
asyncHandler(async (_req: Request, res: Response) => {
|
|
const toggleStatus = getToggleStatus();
|
|
const daemonStatus = await pingDaemon();
|
|
const recentHistory = getToggleHistory(10);
|
|
|
|
res.json({
|
|
success: true,
|
|
toggle: toggleStatus,
|
|
daemon: daemonStatus,
|
|
recentHistory,
|
|
});
|
|
})
|
|
);
|
|
|
|
/**
|
|
* POST /api/v1/antivirus/clamav-toggle
|
|
* Enable or disable ClamAV scanning
|
|
* Body: { enabled: boolean, reason: string }
|
|
*/
|
|
router.post(
|
|
'/clamav-toggle',
|
|
asyncHandler(async (req: Request, res: Response) => {
|
|
const { enabled, reason } = req.body;
|
|
|
|
if (typeof enabled !== 'boolean') {
|
|
res.status(400).json({
|
|
success: false,
|
|
message: '"enabled" must be a boolean',
|
|
});
|
|
return;
|
|
}
|
|
|
|
if (!reason || typeof reason !== 'string') {
|
|
res.status(400).json({
|
|
success: false,
|
|
message: '"reason" is required',
|
|
});
|
|
return;
|
|
}
|
|
|
|
const userId = (req as any).user?.id || (req as any).user?.email || 'unknown';
|
|
const result = setToggleStatus(enabled, userId, reason);
|
|
|
|
// Log the admin action
|
|
logSecurityEvent(SecurityEventType.CLAMAV_TOGGLE_CHANGED, {
|
|
enabled,
|
|
reason,
|
|
changedBy: userId,
|
|
}, userId);
|
|
|
|
res.json({
|
|
success: true,
|
|
message: `ClamAV scanning ${enabled ? 'enabled' : 'disabled'}`,
|
|
state: result.state,
|
|
});
|
|
})
|
|
);
|
|
|
|
/**
|
|
* GET /api/v1/antivirus/audit-logs
|
|
* Search and paginate security audit logs
|
|
* Query params: eventType, severity, category, startDate, endDate, limit, offset
|
|
*/
|
|
router.get(
|
|
'/audit-logs',
|
|
asyncHandler(async (req: Request, res: Response) => {
|
|
const {
|
|
eventType,
|
|
severity,
|
|
category,
|
|
startDate,
|
|
endDate,
|
|
limit = '50',
|
|
offset = '0',
|
|
} = req.query;
|
|
|
|
const result = readAuditLogs({
|
|
eventType: eventType as string,
|
|
severity: severity as string,
|
|
category: category as string,
|
|
startDate: startDate as string,
|
|
endDate: endDate as string,
|
|
limit: parseInt(limit as string, 10),
|
|
offset: parseInt(offset as string, 10),
|
|
});
|
|
|
|
res.json({
|
|
success: true,
|
|
...result,
|
|
});
|
|
})
|
|
);
|
|
|
|
/**
|
|
* GET /api/v1/antivirus/audit-logs/export
|
|
* Export filtered audit logs as CSV
|
|
*/
|
|
router.get(
|
|
'/audit-logs/export',
|
|
asyncHandler(async (req: Request, res: Response) => {
|
|
const { eventType, severity, startDate, endDate } = req.query;
|
|
|
|
const csv = exportAuditLogsCSV({
|
|
eventType: eventType as string,
|
|
severity: severity as string,
|
|
startDate: startDate as string,
|
|
endDate: endDate as string,
|
|
});
|
|
|
|
res.setHeader('Content-Type', 'text/csv');
|
|
res.setHeader('Content-Disposition', `attachment; filename=audit-logs-${new Date().toISOString().split('T')[0]}.csv`);
|
|
res.send(csv);
|
|
})
|
|
);
|
|
|
|
/**
|
|
* GET /api/v1/antivirus/audit-stats
|
|
* Get audit log statistics
|
|
*/
|
|
router.get(
|
|
'/audit-stats',
|
|
asyncHandler(async (_req: Request, res: Response) => {
|
|
const stats = getAuditStats();
|
|
|
|
res.json({
|
|
success: true,
|
|
stats,
|
|
});
|
|
})
|
|
);
|
|
|
|
export default router;
|