192 lines
5.4 KiB
JavaScript
192 lines
5.4 KiB
JavaScript
const express = require('express');
|
|
const router = express.Router();
|
|
const { Op } = require('sequelize');
|
|
const { authenticateToken, requireRole } = require('../middleware/auth');
|
|
|
|
// Security logs endpoint - tenant-specific with admin-only access
|
|
router.get('/', authenticateToken, requireRole('admin'), async (req, res) => {
|
|
try {
|
|
const {
|
|
page = 1,
|
|
limit = 50,
|
|
level = 'all',
|
|
eventType = 'all',
|
|
timeRange = '24h',
|
|
search = ''
|
|
} = req.query;
|
|
|
|
const { SecurityLog } = require('../models');
|
|
|
|
// Build where conditions - only show logs for current tenant
|
|
let whereConditions = {
|
|
tenant_id: req.user.tenant_id // Ensure tenant isolation
|
|
};
|
|
|
|
// Filter by security level
|
|
if (level !== 'all') {
|
|
whereConditions.level = level;
|
|
}
|
|
|
|
// Filter by event type
|
|
if (eventType !== 'all') {
|
|
whereConditions.event_type = eventType;
|
|
}
|
|
|
|
// Filter by time range
|
|
const now = new Date();
|
|
let startTime;
|
|
switch (timeRange) {
|
|
case '1h':
|
|
startTime = new Date(now.getTime() - 60 * 60 * 1000);
|
|
break;
|
|
case '24h':
|
|
startTime = new Date(now.getTime() - 24 * 60 * 60 * 1000);
|
|
break;
|
|
case '7d':
|
|
startTime = new Date(now.getTime() - 7 * 24 * 60 * 60 * 1000);
|
|
break;
|
|
case '30d':
|
|
startTime = new Date(now.getTime() - 30 * 24 * 60 * 60 * 1000);
|
|
break;
|
|
default:
|
|
startTime = new Date(now.getTime() - 24 * 60 * 60 * 1000);
|
|
}
|
|
|
|
if (timeRange !== 'all') {
|
|
whereConditions.timestamp = { [Op.gte]: startTime };
|
|
}
|
|
|
|
// Search filter - only search within tenant's logs
|
|
if (search) {
|
|
whereConditions[Op.or] = [
|
|
{ message: { [Op.iLike]: `%${search}%` } },
|
|
{ 'metadata.ip_address': { [Op.iLike]: `%${search}%` } },
|
|
{ 'metadata.username': { [Op.iLike]: `%${search}%` } }
|
|
];
|
|
}
|
|
|
|
const offset = (parseInt(page) - 1) * parseInt(limit);
|
|
|
|
const { rows: logs, count: total } = await SecurityLog.findAndCountAll({
|
|
where: whereConditions,
|
|
order: [['timestamp', 'DESC']],
|
|
limit: parseInt(limit),
|
|
offset: offset,
|
|
attributes: [
|
|
'id',
|
|
'timestamp',
|
|
'level',
|
|
'event_type',
|
|
'message',
|
|
'metadata'
|
|
] // Don't expose sensitive internal data
|
|
});
|
|
|
|
res.json({
|
|
success: true,
|
|
logs,
|
|
total,
|
|
page: parseInt(page),
|
|
limit: parseInt(limit),
|
|
totalPages: Math.ceil(total / parseInt(limit))
|
|
});
|
|
|
|
} catch (error) {
|
|
console.error('Error retrieving tenant security logs:', error);
|
|
res.status(500).json({
|
|
success: false,
|
|
message: 'Failed to retrieve security logs',
|
|
error: process.env.NODE_ENV === 'development' ? error.message : undefined
|
|
});
|
|
}
|
|
});
|
|
|
|
// Security logs summary endpoint for dashboard widgets
|
|
router.get('/summary', authenticateToken, requireRole('admin'), async (req, res) => {
|
|
try {
|
|
const { timeRange = '24h' } = req.query;
|
|
const { SecurityLog } = require('../models');
|
|
|
|
// Calculate time range
|
|
const now = new Date();
|
|
let startTime;
|
|
switch (timeRange) {
|
|
case '1h':
|
|
startTime = new Date(now.getTime() - 60 * 60 * 1000);
|
|
break;
|
|
case '24h':
|
|
startTime = new Date(now.getTime() - 24 * 60 * 60 * 1000);
|
|
break;
|
|
case '7d':
|
|
startTime = new Date(now.getTime() - 7 * 24 * 60 * 60 * 1000);
|
|
break;
|
|
case '30d':
|
|
startTime = new Date(now.getTime() - 30 * 24 * 60 * 60 * 1000);
|
|
break;
|
|
default:
|
|
startTime = new Date(now.getTime() - 24 * 60 * 60 * 1000);
|
|
}
|
|
|
|
const baseWhere = {
|
|
tenant_id: req.user.tenant_id,
|
|
timestamp: { [Op.gte]: startTime }
|
|
};
|
|
|
|
// Get summary statistics
|
|
const [
|
|
totalLogs,
|
|
criticalLogs,
|
|
highLogs,
|
|
failedLogins,
|
|
successfulLogins,
|
|
countryAlerts,
|
|
bruteForceAttempts
|
|
] = await Promise.all([
|
|
SecurityLog.count({ where: baseWhere }),
|
|
SecurityLog.count({ where: { ...baseWhere, level: 'critical' } }),
|
|
SecurityLog.count({ where: { ...baseWhere, level: 'high' } }),
|
|
SecurityLog.count({ where: { ...baseWhere, event_type: 'failed_login' } }),
|
|
SecurityLog.count({ where: { ...baseWhere, event_type: 'successful_login' } }),
|
|
SecurityLog.count({ where: { ...baseWhere, event_type: 'country_alert' } }),
|
|
SecurityLog.count({ where: { ...baseWhere, event_type: 'brute_force' } })
|
|
]);
|
|
|
|
// Get recent critical events
|
|
const recentCriticalEvents = await SecurityLog.findAll({
|
|
where: { ...baseWhere, level: { [Op.in]: ['critical', 'high'] } },
|
|
order: [['timestamp', 'DESC']],
|
|
limit: 5,
|
|
attributes: ['timestamp', 'level', 'event_type', 'message']
|
|
});
|
|
|
|
res.json({
|
|
success: true,
|
|
summary: {
|
|
period: {
|
|
start: startTime.toISOString(),
|
|
end: now.toISOString(),
|
|
range: timeRange
|
|
},
|
|
totals: {
|
|
totalLogs,
|
|
criticalLogs,
|
|
highLogs,
|
|
failedLogins,
|
|
successfulLogins,
|
|
countryAlerts,
|
|
bruteForceAttempts
|
|
},
|
|
recentCriticalEvents
|
|
}
|
|
});
|
|
|
|
} catch (error) {
|
|
console.error('Error retrieving security logs summary:', error);
|
|
res.status(500).json({
|
|
success: false,
|
|
message: 'Failed to retrieve security logs summary'
|
|
});
|
|
}
|
|
});
|
|
|
|
module.exports = router; |