Initial commit: StreamFlow IPTV platform
This commit is contained in:
commit
73a8ae9ffd
1240 changed files with 278451 additions and 0 deletions
298
backend/routes/log-management.js
Normal file
298
backend/routes/log-management.js
Normal file
|
|
@ -0,0 +1,298 @@
|
|||
/**
|
||||
* Log Management API Routes (CWE-53 Compliance)
|
||||
* Admin-only endpoints for log retention, archival, and integrity
|
||||
*/
|
||||
|
||||
const express = require('express');
|
||||
const router = express.Router();
|
||||
const { authenticate } = require('../middleware/auth');
|
||||
const { requirePermission } = require('../middleware/rbac');
|
||||
const { readLimiter, modifyLimiter } = require('../middleware/rateLimiter');
|
||||
const logManagement = require('../jobs/logManagement');
|
||||
const SecurityAuditLogger = require('../utils/securityAudit');
|
||||
const logger = require('../utils/logger');
|
||||
const path = require('path');
|
||||
const fs = require('fs').promises;
|
||||
|
||||
/**
|
||||
* GET /api/log-management/statistics
|
||||
* Get log management statistics
|
||||
*/
|
||||
router.get('/statistics',
|
||||
authenticate,
|
||||
requirePermission('security.view_audit'),
|
||||
readLimiter,
|
||||
async (req, res) => {
|
||||
try {
|
||||
const stats = await logManagement.getStatistics();
|
||||
|
||||
await SecurityAuditLogger.logSensitiveDataAccess(req.user.userId, 'log_statistics', {
|
||||
ip: req.ip,
|
||||
userAgent: req.headers['user-agent']
|
||||
});
|
||||
|
||||
res.json({
|
||||
success: true,
|
||||
data: stats
|
||||
});
|
||||
} catch (error) {
|
||||
logger.error('[LogManagement API] Error getting statistics:', error);
|
||||
res.status(500).json({
|
||||
success: false,
|
||||
message: 'Failed to get log statistics'
|
||||
});
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
/**
|
||||
* GET /api/log-management/archives
|
||||
* List available log archives
|
||||
*/
|
||||
router.get('/archives',
|
||||
authenticate,
|
||||
requirePermission('security.view_audit'),
|
||||
readLimiter,
|
||||
async (req, res) => {
|
||||
try {
|
||||
const archives = await logManagement.listArchives();
|
||||
|
||||
await SecurityAuditLogger.logSensitiveDataAccess(req.user.userId, 'log_archives_list', {
|
||||
ip: req.ip,
|
||||
userAgent: req.headers['user-agent'],
|
||||
recordCount: archives.length
|
||||
});
|
||||
|
||||
res.json({
|
||||
success: true,
|
||||
data: archives
|
||||
});
|
||||
} catch (error) {
|
||||
logger.error('[LogManagement API] Error listing archives:', error);
|
||||
res.status(500).json({
|
||||
success: false,
|
||||
message: 'Failed to list archives'
|
||||
});
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
/**
|
||||
* POST /api/log-management/cleanup
|
||||
* Manual trigger for log cleanup
|
||||
* Admin only
|
||||
*/
|
||||
router.post('/cleanup',
|
||||
authenticate,
|
||||
requirePermission('security.manage'),
|
||||
modifyLimiter,
|
||||
async (req, res) => {
|
||||
try {
|
||||
const { retentionDays } = req.body;
|
||||
const days = parseInt(retentionDays) || 90;
|
||||
|
||||
if (days < 7) {
|
||||
return res.status(400).json({
|
||||
success: false,
|
||||
message: 'Retention days must be at least 7'
|
||||
});
|
||||
}
|
||||
|
||||
const result = await logManagement.manualCleanup(days);
|
||||
|
||||
await SecurityAuditLogger.logAdminActivity(req.user.userId, 'log_cleanup_manual', {
|
||||
ip: req.ip,
|
||||
userAgent: req.headers['user-agent'],
|
||||
retentionDays: days,
|
||||
...result
|
||||
});
|
||||
|
||||
res.json({
|
||||
success: true,
|
||||
message: `Deleted ${result.auditDeleted + result.aggregatedDeleted} old log entries`,
|
||||
data: result
|
||||
});
|
||||
} catch (error) {
|
||||
logger.error('[LogManagement API] Error during manual cleanup:', error);
|
||||
res.status(500).json({
|
||||
success: false,
|
||||
message: 'Failed to perform log cleanup'
|
||||
});
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
/**
|
||||
* POST /api/log-management/verify-integrity
|
||||
* Manual trigger for integrity verification
|
||||
* Admin only
|
||||
*/
|
||||
router.post('/verify-integrity',
|
||||
authenticate,
|
||||
requirePermission('security.view_audit'),
|
||||
modifyLimiter,
|
||||
async (req, res) => {
|
||||
try {
|
||||
const result = await logManagement.manualIntegrityCheck();
|
||||
|
||||
if (!result) {
|
||||
return res.status(500).json({
|
||||
success: false,
|
||||
message: 'Integrity verification failed'
|
||||
});
|
||||
}
|
||||
|
||||
await SecurityAuditLogger.logAdminActivity(req.user.userId, 'log_integrity_check', {
|
||||
ip: req.ip,
|
||||
userAgent: req.headers['user-agent'],
|
||||
verified: result.verified,
|
||||
tampered: result.tampered
|
||||
});
|
||||
|
||||
res.json({
|
||||
success: true,
|
||||
message: result.tampered > 0
|
||||
? `⚠️ WARNING: ${result.tampered} tampered logs detected!`
|
||||
: `All ${result.verified} logs verified successfully`,
|
||||
data: result,
|
||||
alert: result.tampered > 0
|
||||
});
|
||||
} catch (error) {
|
||||
logger.error('[LogManagement API] Error during integrity check:', error);
|
||||
res.status(500).json({
|
||||
success: false,
|
||||
message: 'Failed to verify log integrity'
|
||||
});
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
/**
|
||||
* GET /api/log-management/archives/download/:filename
|
||||
* Download a log archive
|
||||
* Admin only
|
||||
*/
|
||||
router.get('/archives/download/:filename',
|
||||
authenticate,
|
||||
requirePermission('security.view_audit'),
|
||||
readLimiter,
|
||||
async (req, res) => {
|
||||
try {
|
||||
const { filename } = req.params;
|
||||
|
||||
// Security: prevent path traversal
|
||||
if (filename.includes('..') || filename.includes('/') || filename.includes('\\')) {
|
||||
return res.status(400).json({
|
||||
success: false,
|
||||
message: 'Invalid filename'
|
||||
});
|
||||
}
|
||||
|
||||
// Security: only allow .json.gz files
|
||||
if (!filename.endsWith('.json.gz')) {
|
||||
return res.status(400).json({
|
||||
success: false,
|
||||
message: 'Invalid file type'
|
||||
});
|
||||
}
|
||||
|
||||
const archiveDir = path.join(__dirname, '../../data/log-archives');
|
||||
const filePath = path.join(archiveDir, filename);
|
||||
|
||||
// Check if file exists
|
||||
try {
|
||||
await fs.access(filePath);
|
||||
} catch (error) {
|
||||
return res.status(404).json({
|
||||
success: false,
|
||||
message: 'Archive not found'
|
||||
});
|
||||
}
|
||||
|
||||
// Log the access
|
||||
await SecurityAuditLogger.logSensitiveDataAccess(req.user.userId, 'log_archive_download', {
|
||||
ip: req.ip,
|
||||
userAgent: req.headers['user-agent'],
|
||||
filename,
|
||||
accessMethod: 'download'
|
||||
});
|
||||
|
||||
// Send file
|
||||
res.download(filePath, filename);
|
||||
} catch (error) {
|
||||
logger.error('[LogManagement API] Error downloading archive:', error);
|
||||
res.status(500).json({
|
||||
success: false,
|
||||
message: 'Failed to download archive'
|
||||
});
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
/**
|
||||
* DELETE /api/log-management/archives/:filename
|
||||
* Delete a log archive
|
||||
* Admin only
|
||||
*/
|
||||
router.delete('/archives/:filename',
|
||||
authenticate,
|
||||
requirePermission('security.manage'),
|
||||
modifyLimiter,
|
||||
async (req, res) => {
|
||||
try {
|
||||
const { filename } = req.params;
|
||||
|
||||
// Security: prevent path traversal
|
||||
if (filename.includes('..') || filename.includes('/') || filename.includes('\\')) {
|
||||
return res.status(400).json({
|
||||
success: false,
|
||||
message: 'Invalid filename'
|
||||
});
|
||||
}
|
||||
|
||||
// Security: only allow .json.gz files
|
||||
if (!filename.endsWith('.json.gz')) {
|
||||
return res.status(400).json({
|
||||
success: false,
|
||||
message: 'Invalid file type'
|
||||
});
|
||||
}
|
||||
|
||||
const archiveDir = path.join(__dirname, '../../data/log-archives');
|
||||
const filePath = path.join(archiveDir, filename);
|
||||
|
||||
// Check if file exists
|
||||
try {
|
||||
await fs.access(filePath);
|
||||
} catch (error) {
|
||||
return res.status(404).json({
|
||||
success: false,
|
||||
message: 'Archive not found'
|
||||
});
|
||||
}
|
||||
|
||||
// Delete file
|
||||
await fs.unlink(filePath);
|
||||
|
||||
// Log the deletion
|
||||
await SecurityAuditLogger.logAdminActivity(req.user.userId, 'log_archive_deleted', {
|
||||
ip: req.ip,
|
||||
userAgent: req.headers['user-agent'],
|
||||
filename
|
||||
});
|
||||
|
||||
res.json({
|
||||
success: true,
|
||||
message: 'Archive deleted successfully'
|
||||
});
|
||||
} catch (error) {
|
||||
logger.error('[LogManagement API] Error deleting archive:', error);
|
||||
res.status(500).json({
|
||||
success: false,
|
||||
message: 'Failed to delete archive'
|
||||
});
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
module.exports = router;
|
||||
Loading…
Add table
Add a link
Reference in a new issue