WebPass / webpass /static /js /network.js
ag235772's picture
Initial Release: WebPass V2 with Steganography, Crypto Vault, and Cloud Toggle
136c0f7
document.addEventListener("DOMContentLoaded", () => {
let table = null;
const allPackets = [];
const protoCounts = { TCP: 0, UDP: 0, DNS: 0, Other: 0 };
const srcCounts = {};
let protocolChart = null;
// --- New variables for smoother, dynamic updates ---
let uiUpdateScheduled = false;
const UI_UPDATE_INTERVAL = 1000; // Update heavy visuals once per second
function initChart() {
const ctx = document.getElementById('protocolChart')?.getContext('2d');
if (!ctx) return;
protocolChart = new Chart(ctx, {
type: 'doughnut',
data: {
labels: ['TCP', 'UDP', 'DNS', 'Other'],
datasets: [{ data: [0, 0, 0, 0], backgroundColor: ['#0d6efd', '#ffc107', '#dc3545', '#6f42c1'] }]
},
options: { responsive: true, maintainAspectRatio: false, plugins: { legend: { position: 'bottom' } } }
});
}
function initDataTable() {
const cols = ["Time", "Source", "Destination", "Protocol", "Length"];
let headerRow = '<tr>';
cols.forEach(txt => headerRow += `<th>${txt}</th>`);
headerRow += '</tr>';
$("#table-header").html(headerRow);
table = $('#packet-table').DataTable({
deferRender: true,
scroller: true,
scrollY: "60vh",
scrollCollapse: true,
paging: true,
lengthChange: false,
info: true,
order: [[0, 'desc']],
language: { search: "", searchPlaceholder: "Search..." },
createdRow: function(row, data, dataIndex) {
if (allPackets[dataIndex]) {
$(row).data('packet', allPackets[dataIndex]);
}
}
});
}
function getProtocol(pkt) {
if (pkt.proto === "DNS") return "DNS";
if (pkt.proto === 6) return "TCP";
if (pkt.proto === 17) return "UDP";
return "Other";
}
// --- Main Update Logic ---
// This function updates all the heavy visual elements
function updateHeavyVisuals() {
// Update KPI cards (except total, which is updated instantly)
$('#count-TCP').text(protoCounts.TCP);
$('#count-UDP').text(protoCounts.UDP);
$('#count-DNS').text(protoCounts.DNS);
if (protocolChart) {
protocolChart.data.datasets[0].data = [protoCounts.TCP, protoCounts.UDP, protoCounts.DNS, protoCounts.Other];
protocolChart.update('none'); // 'none' for smooth animation
}
const topSources = Object.entries(srcCounts).sort(([, a], [, b]) => b - a).slice(0, 5);
const ul = $("#top-sources").empty();
topSources.forEach(([ip, count]) => {
$("<li>").addClass("list-group-item d-flex justify-content-between align-items-center").html(`${ip} <span class="badge bg-primary rounded-pill">${count}</span>`).appendTo(ul);
});
}
// This function processes all historical data once on load
function processHistoricalData(historicalPackets) {
historicalPackets.forEach(pkt => {
allPackets.push(pkt);
const proto = getProtocol(pkt);
if (protoCounts.hasOwnProperty(proto)) protoCounts[proto]++;
srcCounts[pkt.src] = (srcCounts[pkt.src] || 0) + 1;
});
const rowsToAdd = allPackets.map(p => {
const time = new Date(p.timestamp * 1000).toLocaleTimeString();
return [time, p.src, p.dst, getProtocol(p), p.length || '-'];
});
table.rows.add(rowsToAdd).draw();
$('#count-All').text(allPackets.length);
updateHeavyVisuals(); // Update heavy visuals once after history is loaded
}
// --- INITIALIZATION AND DATA LOADING ---
initChart();
initDataTable();
fetch("/api/packets")
.then(r => r.ok ? r.json() : [])
.then(processHistoricalData)
.catch(err => console.error("Error loading history:", err));
// --- LIVE SOCKET.IO UPDATES ---
const socket = io();
socket.on('new_packet', pkt => {
// 1. Instantly update the in-memory data
allPackets.push(pkt);
const proto = getProtocol(pkt);
if (protoCounts.hasOwnProperty(proto)) protoCounts[proto]++;
srcCounts[pkt.src] = (srcCounts[pkt.src] || 0) + 1;
// 2. Instantly update the total count and add the row to the table
$('#count-All').text(allPackets.length);
const time = new Date(pkt.timestamp * 1000).toLocaleTimeString();
// ** THIS IS THE BUG FIX **
// It was `p.length` before, which is undefined. It is now `pkt.length`.
const rowData = [time, pkt.src, pkt.dst, getProtocol(pkt), pkt.length || '-'];
table.row.add(rowData).draw(false);
// 3. Schedule a throttled update for the heavy visuals
if (!uiUpdateScheduled) {
uiUpdateScheduled = true;
setTimeout(() => {
updateHeavyVisuals();
uiUpdateScheduled = false;
}, UI_UPDATE_INTERVAL);
}
});
// --- EVENT HANDLERS ---
$("#packet-table tbody").on("click", "tr", function(){
const pkt = $(this).data('packet');
if (!pkt) return;
let html = '<ul class="list-group">';
Object.entries(pkt).forEach(([k,v])=> {
html += `<li class="list-group-item"><strong>${k}:</strong> ${v}</li>`;
});
html += '</ul>';
$("#packet-detail-body").html(html);
new bootstrap.Modal($("#packetDetailModal")).show();
});
$("#download-btn").on("click", () => {
if (!allPackets.length) {
return alert("No packet data to download.");
}
const ws = XLSX.utils.json_to_sheet(allPackets);
const wb = XLSX.utils.book_new();
XLSX.utils.book_append_sheet(wb, ws, "NetworkData");
const ts = new Date().toISOString().replace(/[:.]/g,"-");
const name = `network_data_${ts}.xlsx`;
XLSX.writeFile(wb, name);
});
});