mirror of
https://github.com/EFForg/rayhunter.git
synced 2026-04-26 23:49:59 -07:00
On-demand analysis of past recordings
* rayhunter-daemon: API for triggering and reading analysis * rayhunter-daemon: rename readonly mode to debug mode * rayhunter-daemon: debug mode allows live-loading frontend files * rayhunter-check: rework to handle directories * rayhunter-check: better output * CI: build rayhunter-check
This commit is contained in:
committed by
Cooper Quintin
parent
c59fb7c013
commit
df84faa1f9
@@ -1,16 +1,99 @@
|
||||
const STATUS_RUNNING = 'running';
|
||||
const STATUS_QUEUED = 'queued';
|
||||
const STATUS_NEEDS_UPDATE = 'needs-update';
|
||||
const STATUS_COMPLETE = 'complete';
|
||||
|
||||
async function populateDivs() {
|
||||
const systemStats = await getSystemStats();
|
||||
const systemStatsDiv = document.getElementById('system-stats');
|
||||
systemStatsDiv.innerHTML = JSON.stringify(systemStats, null, 2);
|
||||
|
||||
const analysisReport = await getAnalysisReport();
|
||||
const analysisReportDiv = document.getElementById('analysis-report');
|
||||
analysisReportDiv.innerHTML = JSON.stringify(analysisReport, null, 2);
|
||||
try {
|
||||
const analysisReport = await getAnalysisReport('live');
|
||||
analysisReportDiv.innerHTML = JSON.stringify(analysisReport, null, 2);
|
||||
} catch (e) {
|
||||
analysisReportDiv.innerHTML = e.toString();
|
||||
}
|
||||
|
||||
const qmdlManifest = await getQmdlManifest();
|
||||
await updateAnalysisStatus(qmdlManifest);
|
||||
await updateAnalysisResults(qmdlManifest);
|
||||
updateQmdlManifestTable(qmdlManifest);
|
||||
}
|
||||
|
||||
function setStatus(qmdlManifest, name, status) {
|
||||
// ignore qmdlManifest.current_entry, it's always running
|
||||
for (const entry of qmdlManifest.entries) {
|
||||
if (entry.name === name) {
|
||||
entry['status'] = status;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async function updateAnalysisStatus(qmdlManifest) {
|
||||
const status = JSON.parse(await req('GET', '/api/analysis'));
|
||||
if (status.running) {
|
||||
setStatus(qmdlManifest, status.running, STATUS_RUNNING);
|
||||
}
|
||||
for (const queued in status.queued) {
|
||||
setStatus(qmdlManifest, queued, STATUS_QUEUED);
|
||||
}
|
||||
}
|
||||
|
||||
function parseNewlineDelimitedJSON(inputStr) {
|
||||
const lines = inputStr.split('\n');
|
||||
const result = [];
|
||||
let currentLine = '';
|
||||
while (lines.length > 0) {
|
||||
currentLine += lines.shift();
|
||||
try {
|
||||
const entry = JSON.parse(currentLine);
|
||||
result.push(entry);
|
||||
// if this chunk wasn't valid JSON, there was an escaped newline in the
|
||||
// JSON line, so simply continue to the next one
|
||||
} catch (e) {}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
async function updateEntryAnalysisResult(entry) {
|
||||
entry.analysis = {
|
||||
warnings: [],
|
||||
};
|
||||
const report = parseNewlineDelimitedJSON(await req('GET', `/api/analysis-report/${entry.name}`));
|
||||
for (const row of report) {
|
||||
if (row["analysis"]) {
|
||||
const timestamp = new Date(row["timestamp"]);
|
||||
const analysis = row["analysis"];
|
||||
for (const warning of analysis) {
|
||||
entry.warnings.push({
|
||||
timestamp,
|
||||
warning,
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
if (entry.analysis.warnings.length === 0) {
|
||||
entry.analysis_result = `0 warnings!`;
|
||||
} else {
|
||||
entry.analysis_result = `!!! ${entry.analysis.warnings.length} warnings !!!`;
|
||||
}
|
||||
}
|
||||
|
||||
async function updateAnalysisResults(qmdlManifest) {
|
||||
if (qmdlManifest.current_entry) {
|
||||
await updateEntryAnalysisResult(qmdlManifest.current_entry);
|
||||
}
|
||||
for (const entry of qmdlManifest.entries) {
|
||||
if (entry.status === STATUS_NEEDS_UPDATE) {
|
||||
await updateEntryAnalysisResult(entry);
|
||||
entry.status = STATUS_COMPLETE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function updateQmdlManifestTable(manifest) {
|
||||
const table = document.getElementById('qmdl-manifest-table');
|
||||
const numRows = table.rows.length;
|
||||
@@ -18,43 +101,52 @@ function updateQmdlManifestTable(manifest) {
|
||||
table.deleteRow(1);
|
||||
}
|
||||
if (manifest.current_entry) {
|
||||
const row = createEntryRow(manifest.current_entry);
|
||||
const row = createEntryRow(manifest.current_entry, true);
|
||||
row.classList.add('current');
|
||||
table.appendChild(row)
|
||||
}
|
||||
for (let entry of manifest.entries) {
|
||||
table.appendChild(createEntryRow(entry));
|
||||
table.appendChild(createEntryRow(entry), false);
|
||||
}
|
||||
}
|
||||
|
||||
function createEntryRow(entry) {
|
||||
function createLink(uri, text) {
|
||||
const link = document.createElement('a');
|
||||
link.href = uri;
|
||||
link.innerText = text;
|
||||
return link;
|
||||
}
|
||||
|
||||
function createEntryRow(entry, isCurrent) {
|
||||
const row = document.createElement('tr');
|
||||
const name = document.createElement('th');
|
||||
name.scope = 'row';
|
||||
name.innerText = entry.name;
|
||||
row.appendChild(name);
|
||||
|
||||
for (const key of ['start_time', 'last_message_time', 'qmdl_size_bytes']) {
|
||||
const td = document.createElement('td');
|
||||
td.innerText = entry[key];
|
||||
row.appendChild(td);
|
||||
}
|
||||
const pcap_td = document.createElement('td');
|
||||
const pcap_link = document.createElement('a');
|
||||
pcap_link.href = `/api/pcap/${entry.name}`;
|
||||
pcap_link.innerText = 'pcap';
|
||||
pcap_td.appendChild(pcap_link);
|
||||
row.appendChild(pcap_td);
|
||||
const qmdl_td = document.createElement('td');
|
||||
const qmdl_link = document.createElement('a');
|
||||
qmdl_link.href = `/api/qmdl/${entry.name}`;
|
||||
qmdl_link.innerText = 'qmdl';
|
||||
qmdl_td.appendChild(qmdl_link);
|
||||
row.appendChild(qmdl_td);
|
||||
|
||||
const pcapTd = document.createElement('td');
|
||||
pcapTd.appendChild(createLink(`/api/pcap/${entry.name}`, 'pcap'));
|
||||
row.appendChild(pcapTd);
|
||||
|
||||
const qmdlTd = document.createElement('td');
|
||||
qmdlTd.appendChild(createLink(`/api/qmdl/${entry.name}`, 'qmdl'));
|
||||
row.appendChild(qmdlTd);
|
||||
|
||||
const analysisResult = document.createElement('td');
|
||||
analysisResult.innerText = entry.analysis_result;
|
||||
row.appendChild(analysisResult);
|
||||
|
||||
return row;
|
||||
}
|
||||
|
||||
async function getAnalysisReport() {
|
||||
const rows = await req('GET', '/api/analysis-report');
|
||||
async function getAnalysisReport(name) {
|
||||
const rows = await req('GET', `/api/analysis-report/${name}`);
|
||||
return rows.split('\n')
|
||||
.filter(row => row.length > 0)
|
||||
.map(row => JSON.parse(row));
|
||||
@@ -67,6 +159,8 @@ async function getSystemStats() {
|
||||
async function getQmdlManifest() {
|
||||
const manifest = JSON.parse(await req('GET', '/api/qmdl-manifest'));
|
||||
if (manifest.current_entry) {
|
||||
manifest.current_entry.status = STATUS_NEEDS_UPDATE;
|
||||
manifest.current_entry.analysis_result = 'Waiting...';
|
||||
manifest.current_entry.start_time = new Date(manifest.current_entry.start_time);
|
||||
if (manifest.current_entry.last_message_time === undefined) {
|
||||
manifest.current_entry.last_message_time = "N/A";
|
||||
@@ -75,6 +169,8 @@ async function getQmdlManifest() {
|
||||
}
|
||||
}
|
||||
for (entry of manifest.entries) {
|
||||
entry.status = STATUS_NEEDS_UPDATE;
|
||||
entry.analysis_result = 'Waiting...';
|
||||
entry.start_time = new Date(entry.start_time);
|
||||
entry.last_message_time = new Date(entry.last_message_time);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user