diff --git a/bin/src/server.rs b/bin/src/server.rs index 72596b4..b88b0bc 100644 --- a/bin/src/server.rs +++ b/bin/src/server.rs @@ -53,7 +53,7 @@ pub async fn get_qmdl( } // Bundles the server's static files (html/css/js) into the binary for easy distribution -static STATIC_DIR: Dir<'_> = include_dir!("$CARGO_MANIFEST_DIR/static"); +static STATIC_DIR: Dir<'_> = include_dir!("$CARGO_MANIFEST_DIR/web/build"); pub async fn serve_static( State(state): State>, @@ -67,7 +67,8 @@ pub async fn serve_static( if state.debug_mode { let mut build_path = std::path::PathBuf::new(); build_path.push("bin"); - build_path.push("static"); + build_path.push("web"); + build_path.push("build"); for part in path.split("/") { build_path.push(part); } diff --git a/bin/static/css/style.css b/bin/static/css/style.css deleted file mode 100644 index 4ef7e54..0000000 --- a/bin/static/css/style.css +++ /dev/null @@ -1,45 +0,0 @@ -td, -th { - border: 1px solid rgb(190, 190, 190); - padding: 10px; -} - -td { - text-align: center; -} - -tr:nth-child(even) { - background-color: #eee; -} - -th[scope='col'] { - background-color: #696969; - color: #fff; -} - -th[scope='row'] { - background-color: #d7d9f2; -} - -tr.current { - background-color: #53fe7b; - font-weight: bold; -} - -tr.warning { - background-color: #fe537b; - font-weight: bold; -} - -caption { - padding: 10px; - caption-side: bottom; -} - -table { - border-collapse: collapse; - border: 2px solid rgb(200, 200, 200); - letter-spacing: 1px; - font-family: sans-serif; - font-size: 0.8rem; -} diff --git a/bin/static/images/eff.png b/bin/static/images/eff.png deleted file mode 100644 index 0b1e44d..0000000 Binary files a/bin/static/images/eff.png and /dev/null differ diff --git a/bin/static/images/orca.gif b/bin/static/images/orca.gif deleted file mode 100644 index d700048..0000000 Binary files a/bin/static/images/orca.gif and /dev/null differ diff --git a/bin/static/index.html b/bin/static/index.html deleted file mode 100644 index 89e0fda..0000000 --- a/bin/static/index.html +++ /dev/null @@ -1,46 +0,0 @@ - - - - rayhunter - - - - - -
- - - -
- - - - - - - - - - - - - -
NameDate StartedDate of Last MessageSize (bytes)PCAPQMDLAnalysis ResultActions
-
-

Live System stats

-
Loading...
-
-
-

Analysis Report of Current Capture

-
Loading...
-
- - diff --git a/bin/static/js/main.js b/bin/static/js/main.js deleted file mode 100644 index 42d23aa..0000000 --- a/bin/static/js/main.js +++ /dev/null @@ -1,235 +0,0 @@ -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 analysisReportDiv = document.getElementById('analysis-report'); - 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); - currentLine = ''; - // 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.analysis.warnings.push({ - timestamp, - warning, - }) - } - } - } - if (entry.analysis.warnings.length === 0) { - entry.analysis_result = `0 warnings!`; - } else { - entry.analysis_result = `!!! ${entry.analysis.warnings.length} warnings !!!`; - for (const warning of entry.analysis.warnings) { - for (const event of warning.warning.events) { - if (event === null) continue; - msg = `${warning.timestamp}: ${event.message}` - entry.analysis_result += `
${msg}` - } - } - } -} - -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; - for (let i=1; i { - await req('POST', uri); - populateDivs(); - }; - 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 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`, 'qmdl')); - row.appendChild(qmdlTd); - - const analysisResult = document.createElement('td'); - analysisResult.innerHTML = entry.analysis_result; - if (entry.analysis.warnings.length > 0) { - row.classList.add("warning"); - } - row.appendChild(analysisResult); - - const actionsButtons = document.createElement('td'); - actionsButtons.appendChild(createButton(`/api/delete-recording/${entry.name}`, 'Delete')); - row.appendChild(actionsButtons); - - return row; -} - -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)); -} - -async function getSystemStats() { - return JSON.parse(await req('GET', '/api/system-stats')); -} - -async function getQmdlManifest() { - const manifest = JSON.parse(await req('GET', '/api/qmdl-manifest')); - if (manifest.current_entry) { - parseQmdlEntry(manifest.current_entry); - } - for (entry of manifest.entries) { - parseQmdlEntry(entry); - } - // sort them in reverse chronological order - manifest.entries.reverse(); - return manifest; -} - -function parseQmdlEntry(entry) { - entry.status = STATUS_NEEDS_UPDATE; - entry.analysis_result = 'Waiting...'; - entry.start_time = new Date(entry.start_time); - if (entry.last_message_time === null) { - entry.last_message_time = "N/A"; - } else { - entry.last_message_time = new Date(entry.last_message_time); - } -} - -async function startRecording() { - await req('POST', '/api/start-recording'); - populateDivs(); -} - -async function stopRecording() { - await req('POST', '/api/stop-recording'); - populateDivs(); -} - -async function deleteAllRecodings() { - if (window.confirm("Are you sure you want to permanently delete all of your recordings?")) { - await req('POST', '/api/delete-all-recordings'); - populateDivs(); - } -} - -async function req(method, url) { - const response = await fetch(url, { - method: method, - }); - const body = await response.text(); - if (response.status >= 200 && response.status < 300) { - return body; - } else { - throw new Error(body); - } -} diff --git a/bin/web/static/favicon.png b/bin/web/static/favicon.png index 825b9e6..0b1e44d 100644 Binary files a/bin/web/static/favicon.png and b/bin/web/static/favicon.png differ