const fs = require('fs'); const csv = require('csv-parser'); const PDFDocument = require('pdfkit'); const inputFile = process.argv[2]; if (!inputFile) { console.error('Please provide a log file path as an argument.'); process.exit(1); } const stats = { totalEvents: 0, severityCounts: {}, dropEvents: 0, dropBySrcIP: {}, thermalWarnings: 0, possibleAttacks: 0, attackDetails: [], startTime: null, endTime: null, timeline: {} // Format: "YYYY-MM-DD HH:00": { Info: 0, Error: 0, ... } }; const THREAT_KEYWORDS = ['attack', 'exploit', 'malware', 'bad password', 'auth fail', 'intrusion']; console.log(`Starting analysis of ${inputFile}...`); // Helper to update timeline function updateTimeline(dateStr, timeStr, severity) { try { // Assuming Date format MM/DD/YYYY and Time HH:MM:SS const hourKey = `${dateStr} ${timeStr.split(':')[0]}:00`; if (!stats.timeline[hourKey]) stats.timeline[hourKey] = {}; stats.timeline[hourKey][severity] = (stats.timeline[hourKey][severity] || 0) + 1; // Track start/end time if (!stats.startTime) stats.startTime = `${dateStr} ${timeStr}`; stats.endTime = `${dateStr} ${timeStr}`; } catch (e) { // Ignore parsing errors for timeline } } fs.createReadStream(inputFile) .pipe(csv({ skipLines: 1 })) .on('data', (row) => { stats.totalEvents++; const level = (row['Level'] || 'Unknown').trim(); const message = (row['Messages'] || '').toString(); const date = row['Date']; const time = row['Time']; // Stats stats.severityCounts[level] = (stats.severityCounts[level] || 0) + 1; updateTimeline(date, time, level); // Security Rules if (message.includes('DROP')) { stats.dropEvents++; const srcMatch = message.match(/SRC=([\d\.]+)/); if (srcMatch && srcMatch[1]) { const ip = srcMatch[1]; stats.dropBySrcIP[ip] = (stats.dropBySrcIP[ip] || 0) + 1; } } if (level === 'Emergency' && message.includes('THERMAL')) { stats.thermalWarnings++; } const lowerMsg = message.toLowerCase(); for (const word of THREAT_KEYWORDS) { if (lowerMsg.includes(word)) { stats.possibleAttacks++; // Increase capture limit for HTML report if (stats.possibleAttacks <= 100) { stats.attackDetails.push({ date, time, level, msg: message }); } break; } } }) .on('end', () => { generateReports(); }); function generateReports() { const reportBase = inputFile.replace(/\.csv$/i, ''); generatePDFReport(`${reportBase}.report.pdf`); generateHTMLReport(`${reportBase}.report.html`); console.log('\nAnalysis Complete.'); console.log(`PDF Report: ${reportBase}.report.pdf`); console.log(`HTML Report: ${reportBase}.report.html`); } function generatePDFReport(filename) { const doc = new PDFDocument(); doc.pipe(fs.createWriteStream(filename)); // Title doc.fontSize(20).text('ASUS Log Security Analysis', { align: 'center' }); doc.moveDown(); // Summary doc.fontSize(12).text(`Analyzed File: ${inputFile}`); doc.text(`Time Period: ${stats.startTime} to ${stats.endTime}`); doc.text(`Total Log Lines: ${stats.totalEvents.toLocaleString()}`); doc.moveDown(); // Key Stats doc.fontSize(14).text('Security Summary', { underline: true }); doc.fontSize(12).text(`Total Firewall Drops: ${stats.dropEvents.toLocaleString()}`); doc.text(`Potential Threats: ${stats.possibleAttacks.toLocaleString()}`); doc.text(`Thermal Warnings: ${stats.thermalWarnings}`); doc.moveDown(); // Chart: Severity Breakdown (Simple Bar Chart) doc.addPage(); doc.fontSize(14).text('Severity Breakdown', { align: 'center' }); doc.moveDown(); const severities = Object.entries(stats.severityCounts).sort(([,a], [,b]) => b - a); const maxVal = Math.max(...Object.values(stats.severityCounts)); const startX = 50; let startY = 150; const barHeight = 20; const maxBarWidth = 400; severities.forEach(([label, count]) => { const width = (count / maxVal) * maxBarWidth; doc.rect(startX + 100, startY, width, barHeight).fill('blue'); doc.fillColor('black').text(label, startX, startY + 5); doc.text(count.toLocaleString(), startX + 100 + width + 5, startY + 5); startY += 30; }); // Table: Top Blocked IPs doc.addPage(); doc.fontSize(14).text('Top 10 Blocked Source IPs', { underline: true }); doc.moveDown(); const topIPs = Object.entries(stats.dropBySrcIP).sort(([,a], [,b]) => b - a).slice(0, 10); topIPs.forEach(([ip, count], i) => { doc.fontSize(12).text(`${i+1}. ${ip}: ${count.toLocaleString()} drops`); }); doc.end(); } function generateHTMLReport(filename) { // Aggregating timeline for Chart.js const labels = Object.keys(stats.timeline).sort(); const datasets = []; // Check which severities exist const allSeverities = new Set(); labels.forEach(t => Object.keys(stats.timeline[t]).forEach(s => allSeverities.add(s))); const colors = { 'Info': '#36a2eb', 'Warning': '#ffcd56', 'Error': '#ff6384', 'Emergency': '#c45850' }; allSeverities.forEach(sev => { const data = labels.map(t => stats.timeline[t][sev] || 0); datasets.push({ label: sev, data: data, borderColor: colors[sev] || '#999', fill: false }); }); const htmlContent = `
File: ${inputFile}
Period: ${stats.startTime} - ${stats.endTime}
Total Events: ${stats.totalEvents.toLocaleString()}
Firewall Drops: ${stats.dropEvents.toLocaleString()}
Threats: ${stats.possibleAttacks}
| Date | Time | Level | Message |
|---|---|---|---|
| ${d.date} | ${d.time} | ${d.level} | ${d.msg} |