From dbf98d598d3525e3df353ed3abd0dd4f098f84a5 Mon Sep 17 00:00:00 2001 From: mysticmomba Date: Tue, 6 Oct 2026 16:27:32 -0400 Subject: [PATCH 1/9] fix: Status Colors on Monitor tab now reflect status of host. Closes #7 --- src/styles.css | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/styles.css b/src/styles.css index 5cc067f..a38e826 100644 --- a/src/styles.css +++ b/src/styles.css @@ -1146,17 +1146,17 @@ body { text-shadow: 0 0 6px var(--status-up-glow); } -.monitor-status-Down { +#monitor-table .monitor-status-Down { color: var(--status-down); text-shadow: 0 0 6px var(--status-down-glow); } -.monitor-status-Degraded { +#monitor-table .monitor-status-Degraded { color: var(--status-filtered); text-shadow: 0 0 6px var(--status-filtered-glow); } -.monitor-status-Unknown { +#monitor-table .monitor-status-Unknown { color: var(--status-unknown); } From 8cc8189820ad8edc3a5111f60201cfd6549e5f90 Mon Sep 17 00:00:00 2001 From: mysticmomba Date: Tue, 6 Oct 2026 16:36:30 -0400 Subject: [PATCH 2/9] fix: Removed unused function. --- CHANGELOG.md | 5 +++++ src-tauri/src/net/dns.rs | 30 ------------------------------ 2 files changed, 5 insertions(+), 30 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e1a7f2e..2776758 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,8 @@ +## [unreleased] + +### πŸ› Bug Fixes + +- Status Colors on Monitor tab now reflect status of host. Closes #7 ## [0.2.0] - 2026-09-24 ### πŸš€ Features diff --git a/src-tauri/src/net/dns.rs b/src-tauri/src/net/dns.rs index 189d520..29e0169 100644 --- a/src-tauri/src/net/dns.rs +++ b/src-tauri/src/net/dns.rs @@ -1,5 +1,4 @@ use std::net::IpAddr; -use tokio::task::JoinSet; /// Perform reverse DNS lookup on a single IP. /// Returns the hostname if found, None otherwise. @@ -18,33 +17,4 @@ pub async fn reverse_lookup(ip: IpAddr) -> Option { } _ => None, } -} - -/// Perform reverse DNS lookups on a batch of IPs concurrently. -/// Returns a Vec of (IpAddr, Option) pairs. -pub async fn reverse_lookup_batch( - ips: &[IpAddr], - max_concurrent: usize, -) -> Vec<(IpAddr, Option)> { - let mut results = Vec::with_capacity(ips.len()); - - for chunk in ips.chunks(max_concurrent) { - let mut join_set = JoinSet::new(); - - for &ip in chunk { - join_set.spawn(async move { - let hostname = reverse_lookup(ip).await; - (ip, hostname) - }); - } - - while let Some(result) = join_set.join_next().await { - match result { - Ok(pair) => results.push(pair), - Err(e) => tracing::warn!("DNS lookup task panicked: {}", e), - } - } - } - - results } \ No newline at end of file From c5931c723f628c679cc26fcfbe4bcab0113c1939 Mon Sep 17 00:00:00 2001 From: mysticmomba Date: Tue, 6 Oct 2026 16:49:04 -0400 Subject: [PATCH 3/9] feat: Added Auto Labeling to Montior Tab. When sending hosts from the scan tab, it will bring their hostnames over to the label section. When adding a one off host to the montior tab, it will auto query it's hostname. You can also edit labels by double clicking. Closes #3 --- CHANGELOG.md | 1 + src-tauri/src/commands/monitor.rs | 16 ++++++++ src-tauri/src/lib.rs | 2 + src/main.js | 66 ++++++++++++++++++++++++++++--- src/styles.css | 20 ++++++++++ 5 files changed, 99 insertions(+), 6 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2776758..1dcd270 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,7 @@ ### πŸ› Bug Fixes - Status Colors on Monitor tab now reflect status of host. Closes #7 +- Removed unused function. ## [0.2.0] - 2026-09-24 ### πŸš€ Features diff --git a/src-tauri/src/commands/monitor.rs b/src-tauri/src/commands/monitor.rs index bb5b864..3b3b022 100644 --- a/src-tauri/src/commands/monitor.rs +++ b/src-tauri/src/commands/monitor.rs @@ -180,3 +180,19 @@ pub async fn monitor_stop() -> Result<(), String> { } Ok(()) } +#[tauri::command] +pub async fn monitor_update_label(ip: String, label: String) -> Result<(), String> { + let parsed: IpAddr = ip.parse().map_err(|e| format!("Invalid IP: {}", e))?; + let state = get_monitor(); + let mut guard = state.lock().await; + if let Some(entry) = guard.entries.get_mut(&parsed) { + entry.label = if label.is_empty() { None } else { Some(label) }; + } + Ok(()) +} + +#[tauri::command] +pub async fn monitor_resolve_host(ip: String) -> Result, String> { + let parsed: IpAddr = ip.parse().map_err(|e| format!("Invalid IP: {}", e))?; + Ok(crate::net::dns::reverse_lookup(parsed).await) +} diff --git a/src-tauri/src/lib.rs b/src-tauri/src/lib.rs index 8a6c46c..43bb668 100644 --- a/src-tauri/src/lib.rs +++ b/src-tauri/src/lib.rs @@ -32,6 +32,8 @@ pub fn run() { commands::updater::check_for_update, commands::actions::check_privileges, commands::changelog::get_changelog, + commands::monitor::monitor_update_label, + commands::monitor::monitor_resolve_host ]) .run(tauri::generate_context!()) .expect("error while running tauri application"); diff --git a/src/main.js b/src/main.js index 6827aff..d0e7358 100644 --- a/src/main.js +++ b/src/main.js @@ -609,7 +609,7 @@ const sender = (() => { if (action.startsWith('nmap')) { nmapTab.setTarget(hosts.map((h) => String(h.ip))); } else if (action.startsWith('monitor')) { - monitorTab.setTargets(hosts.map(function (h) { return String(h.ip); })); + monitorTab.setTargets(hosts); } document.querySelectorAll('.send-menu').forEach((m) => m.hidden = true); @@ -675,7 +675,8 @@ const ctxMenu = (() => { traceroute.run(ip); break; case 'send-monitor': - monitorTab.setTargets([ip]); + var monHost = table.getAll().find(function (h) { return String(h.ip) === ip; }); + monitorTab.setTargets(monHost ? [monHost] : [ip]); break; case 'send-nmap': nmapTab.setTarget([ip]); @@ -967,7 +968,7 @@ const monitorTab = (() => { return '' + '' + ip + '' - + '' + label + '' + + '' + label + '' + '' + e.status + '' + '' + lastRtt + '' + '' + minRtt + '' @@ -994,6 +995,16 @@ const monitorTab = (() => { try { await invoke('monitor_add_hosts', { hosts: hosts }); + + for (var i = 0; i < hosts.length; i++) { + try { + var hostname = await invoke('monitor_resolve_host', { ip: hosts[i].ip }); + if (hostname) { + await invoke('monitor_update_label', { ip: hosts[i].ip, label: hostname }); + } + } catch (e) { } + } + var updated = await invoke('monitor_get_entries'); entries = {}; updated.forEach(function (e) { entries[e.ip] = e; }); @@ -1048,9 +1059,20 @@ const monitorTab = (() => { } } - function setTargets(ips) { - els.input().value = ips.join(', '); - // Switch to monitor tab + function setTargets(hosts) { + var items = hosts.map(function (h) { + if (typeof h === 'string') return { ip: h, label: null }; + return { ip: String(h.ip), label: h.hostname || null }; + }); + + invoke('monitor_add_hosts', { hosts: items }).then(function () { + return invoke('monitor_get_entries'); + }).then(function (updated) { + entries = {}; + updated.forEach(function (e) { entries[e.ip] = e; }); + render(); + }); + document.querySelectorAll('.tab').forEach(function (t) { t.classList.remove('active'); }); document.querySelectorAll('.view').forEach(function (v) { v.classList.remove('active'); }); document.querySelector('[data-tab="monitor"]').classList.add('active'); @@ -1085,6 +1107,38 @@ const monitorTab = (() => { var btn = e.target.closest('.btn-remove'); if (btn) removeHost(btn.dataset.ip); }); + els.body().addEventListener('dblclick', function (e) { + var cell = e.target.closest('.editable-label'); + if (!cell) return; + var ip = cell.dataset.ip; + var currentLabel = cell.textContent === '-' ? '' : cell.textContent; + + var input = document.createElement('input'); + input.type = 'text'; + input.value = currentLabel; + input.className = 'label-edit-input'; + cell.textContent = ''; + cell.appendChild(input); + input.focus(); + input.select(); + + function save() { + var newLabel = input.value.trim(); + invoke('monitor_update_label', { ip: ip, label: newLabel }).then(function () { + return invoke('monitor_get_entries'); + }).then(function (updated) { + entries = {}; + updated.forEach(function (e) { entries[e.ip] = e; }); + render(); + }); + } + + input.addEventListener('blur', save); + input.addEventListener('keydown', function (ev) { + if (ev.key === 'Enter') save(); + if (ev.key === 'Escape') render(); + }); + }); setupListeners(); } diff --git a/src/styles.css b/src/styles.css index a38e826..58f6ca4 100644 --- a/src/styles.css +++ b/src/styles.css @@ -1494,4 +1494,24 @@ body { :root[data-theme="midnight"] .toolbar-circuit { filter: brightness(0.8); +} + +.editable-label { + cursor: pointer; +} + +.editable-label:hover { + background: var(--cyan-dim); +} + +.label-edit-input { + width: 100%; + padding: 2px 6px; + font-family: var(--font-mono); + font-size: 12px; + color: var(--text-primary); + background: var(--bg-primary); + border: 1px solid var(--cyan); + border-radius: var(--radius); + outline: none; } \ No newline at end of file From d6ba6270c57a5966c42e07d320d9c868a3221cb5 Mon Sep 17 00:00:00 2001 From: mysticmomba Date: Thu, 8 Oct 2026 10:43:46 -0400 Subject: [PATCH 4/9] Updated Changelog --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1dcd270..40b9771 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,9 @@ ## [unreleased] +### πŸš€ Features + +- Added Auto Labeling to Montior Tab. When sending hosts from the scan tab, it will bring their hostnames over to the label section. When adding a one off host to the montior tab, it will auto query it's hostname. You can also edit labels by double clicking. Closes #3 + ### πŸ› Bug Fixes - Status Colors on Monitor tab now reflect status of host. Closes #7 From 1df9c2f00c0eb8983767c3d52e143bc94b175262 Mon Sep 17 00:00:00 2001 From: mysticmomba Date: Thu, 8 Oct 2026 10:52:50 -0400 Subject: [PATCH 5/9] =?UTF-8?q?fix:=20Fixed=20Screen=20Refresh=20Bug=20on?= =?UTF-8?q?=20Monitor=20Tab.=20Now=20When=20You=20Go=20To=20Change=20a=20L?= =?UTF-8?q?abel=20While=20the=20Monitor=20Is=20Running.=20The=20Page=20Sto?= =?UTF-8?q?ps=20Refreshing=20Until=20You=E2=80=99re=20Done=20Changing=20th?= =?UTF-8?q?e=20Name.=20This=20Is=20To=20Prevent=20Your=20Text=20Box=20From?= =?UTF-8?q?=20Being=20Deselected=20When=20the=20Table=20Refreshes.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main.js | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/main.js b/src/main.js index d0e7358..1c557c8 100644 --- a/src/main.js +++ b/src/main.js @@ -927,6 +927,7 @@ const nmapTab = (() => { const monitorTab = (() => { let running = false; let entries = {}; + var editingLabel = false; var els = { input: () => document.getElementById('monitor-input'), @@ -953,6 +954,7 @@ const monitorTab = (() => { } function render() { + if (editingLabel) return; var body = els.body(); var ips = Object.keys(entries).sort(); @@ -1112,7 +1114,7 @@ const monitorTab = (() => { if (!cell) return; var ip = cell.dataset.ip; var currentLabel = cell.textContent === '-' ? '' : cell.textContent; - + editingLabel = true; var input = document.createElement('input'); input.type = 'text'; input.value = currentLabel; @@ -1124,6 +1126,7 @@ const monitorTab = (() => { function save() { var newLabel = input.value.trim(); + editingLabel = false; invoke('monitor_update_label', { ip: ip, label: newLabel }).then(function () { return invoke('monitor_get_entries'); }).then(function (updated) { @@ -1136,7 +1139,9 @@ const monitorTab = (() => { input.addEventListener('blur', save); input.addEventListener('keydown', function (ev) { if (ev.key === 'Enter') save(); - if (ev.key === 'Escape') render(); + if (ev.key === 'Escape') + editingLabel = false; + render(); }); }); From aaeb7636a12090764f3ff515ceb46b0aebb6ec1d Mon Sep 17 00:00:00 2001 From: mysticmomba Date: Thu, 8 Oct 2026 11:00:40 -0400 Subject: [PATCH 6/9] feat: Added Always on Top Toggle. Closes #5 --- CHANGELOG.md | 1 + src-tauri/capabilities/default.json | 3 ++- src/index.html | 4 ++++ src/main.js | 11 +++++++++-- src/styles.css | 9 +++++++++ 5 files changed, 25 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 40b9771..7f14486 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,7 @@ - Status Colors on Monitor tab now reflect status of host. Closes #7 - Removed unused function. +- Fixed Screen Refresh Bug on Monitor Tab. Now When You Go To Change a Label While the Monitor Is Running. The Page Stops Refreshing Until You’re Done Changing the Name. This Is To Prevent Your Text Box From Being Deselected When the Table Refreshes. ## [0.2.0] - 2026-09-24 ### πŸš€ Features diff --git a/src-tauri/capabilities/default.json b/src-tauri/capabilities/default.json index 778bfb5..5b8f97a 100644 --- a/src-tauri/capabilities/default.json +++ b/src-tauri/capabilities/default.json @@ -6,6 +6,7 @@ "permissions": [ "core:default", "opener:default", - "dialog:default" + "dialog:default", + "core:window:allow-set-always-on-top" ] } diff --git a/src/index.html b/src/index.html index 2a97886..f45203b 100644 --- a/src/index.html +++ b/src/index.html @@ -200,6 +200,10 @@
Argus + unprivileged
@@ -247,7 +248,7 @@ - +
diff --git a/src/main.js b/src/main.js index bdae8c0..864a02c 100644 --- a/src/main.js +++ b/src/main.js @@ -22,15 +22,63 @@ var theme = (() => { } catch (e) { } } + var HACKER_KEY = 'argus-hacker-unlocked'; + + function isHackerUnlocked() { + try { + return localStorage.getItem(HACKER_KEY) === 'true'; + } catch (e) { + return false; + } + } + + function unlockHacker() { + try { + localStorage.setItem(HACKER_KEY, 'true'); + } catch (e) { } + addHackerOption(); + } + + function addHackerOption() { + var picker = document.getElementById('theme-picker'); + if (!picker.querySelector('option[value="hacker"]')) { + var opt = document.createElement('option'); + opt.value = 'hacker'; + opt.textContent = '\u2588 H4CK3R'; + picker.appendChild(opt); + } + } + function init() { var saved = get(); set(saved); + // Add hacker option if previously unlocked + if (isHackerUnlocked()) { + addHackerOption(); + } + var picker = document.getElementById('theme-picker'); picker.value = saved; picker.addEventListener('change', function () { set(picker.value); }); + + // Easter egg: listen on the scan input + var scanInput = document.getElementById('ip-range-input'); + scanInput.addEventListener('input', function () { + var val = scanInput.value.toLowerCase().trim(); + if (val === 'all your base are belong to us') { + if (!isHackerUnlocked()) { + unlockHacker(); + set('hacker'); + picker.value = 'hacker'; + scanInput.value = ''; + console.log('%c> ACCESS GRANTED', 'color: #00ff41; font-size: 20px; font-family: monospace;'); + console.log('%c> HACKER THEME UNLOCKED', 'color: #00ff41; font-size: 14px; font-family: monospace;'); + } + } + }); } // Apply immediately (before DOMContentLoaded) to prevent flash diff --git a/src/styles.css b/src/styles.css index 2fdd735..cca5fb1 100644 --- a/src/styles.css +++ b/src/styles.css @@ -1478,6 +1478,174 @@ body { --danger-hover: #c62825; } +/* ===== Theme: Catppuccin Mocha ===== */ + +:root[data-theme="mocha"] { + --bg-primary: #1e1e2e; + --bg-secondary: #181825; + --bg-tertiary: #313244; + --bg-hover: #45475a; + --bg-active: #585b70; + --border: #313244; + --border-bright: #45475a; + + --text-primary: #cdd6f4; + --text-secondary: #a6adc8; + --text-muted: #6c7086; + + --cyan: #89b4fa; + --cyan-hover: #7ba4eb; + --cyan-dim: rgba(137, 180, 250, 0.08); + --cyan-glow: rgba(137, 180, 250, 0.2); + --cyan-subtle: rgba(137, 180, 250, 0.03); + + --status-up: #a6e3a1; + --status-up-glow: rgba(166, 227, 161, 0.15); + --status-down: #f38ba8; + --status-down-glow: rgba(243, 139, 168, 0.15); + --status-filtered: #f9e2af; + --status-filtered-glow: rgba(249, 226, 175, 0.15); + --status-unknown: #6c7086; + + --danger: #f38ba8; + --danger-hover: #e57a97; +} + +:root[data-theme="mocha"] .toolbar-circuit { + filter: hue-rotate(40deg) saturate(0.6) brightness(0.9); +} + +:root[data-theme="latte"] .port-tag { + background: rgba(30, 102, 245, 0.1); + border-color: rgba(30, 102, 245, 0.2); +} + +:root[data-theme="latte"] #privilege-status::before { + background: var(--status-up); + box-shadow: 0 0 4px rgba(64, 160, 43, 0.3); +} + +:root[data-theme="latte"] ::-webkit-scrollbar-track { + background: var(--bg-primary); +} + +:root[data-theme="latte"] ::-webkit-scrollbar-thumb { + background: var(--border-bright); +} + +/* ===== Theme: Hacker (Easter Egg) ===== */ + +:root[data-theme="hacker"] { + --bg-primary: #000000; + --bg-secondary: #0a0a0a; + --bg-tertiary: #0d0d0d; + --bg-hover: #1a1a1a; + --bg-active: #222222; + --border: #0a3a0a; + --border-bright: #0f4f0f; + + --text-primary: #00ff41; + --text-secondary: #00cc33; + --text-muted: #006b1d; + + --cyan: #00ff41; + --cyan-hover: #00dd38; + --cyan-dim: rgba(0, 255, 65, 0.06); + --cyan-glow: rgba(0, 255, 65, 0.3); + --cyan-subtle: rgba(0, 255, 65, 0.02); + + --status-up: #00ff41; + --status-up-glow: rgba(0, 255, 65, 0.2); + --status-down: #ff0040; + --status-down-glow: rgba(255, 0, 64, 0.2); + --status-filtered: #ffff00; + --status-filtered-glow: rgba(255, 255, 0, 0.15); + --status-unknown: #006b1d; + + --danger: #ff0040; + --danger-hover: #dd0038; + + --font-mono: "Courier New", "Lucida Console", monospace; + --font-sans: "Courier New", "Lucida Console", monospace; +} + +:root[data-theme="hacker"] .toolbar-circuit { + filter: hue-rotate(-60deg) saturate(3) brightness(0.8); +} + +:root[data-theme="hacker"] body { + font-family: "Courier New", "Lucida Console", monospace; +} + +:root[data-theme="hacker"] .app-title { + letter-spacing: 5px; +} + +:root[data-theme="hacker"] .btn-primary { + text-shadow: 0 0 8px rgba(0, 255, 65, 0.5); +} + +:root[data-theme="hacker"] #results-table td, +:root[data-theme="hacker"] #monitor-table td { + text-shadow: 0 0 3px rgba(0, 255, 65, 0.15); +} + +#crt-overlay { + display: none; + position: fixed; + top: 0; + left: 0; + right: 0; + bottom: 0; + pointer-events: none; + z-index: 9999; +} + +:root[data-theme="hacker"] #crt-overlay { + display: block; + background: + repeating-linear-gradient(0deg, + rgba(0, 0, 0, 0.4) 0px, + rgba(0, 0, 0, 0.4) 1px, + transparent 1px, + transparent 4px), + linear-gradient(180deg, + transparent 0%, + rgba(0, 255, 65, 0.03) 50%, + transparent 100%); + animation: crt-flicker 3s infinite; +} + +@keyframes crt-flicker { + 0% { + opacity: 1; + } + + 5% { + opacity: 0.85; + } + + 10% { + opacity: 1; + } + + 40% { + opacity: 0.95; + } + + 45% { + opacity: 1; + } + + 80% { + opacity: 0.9; + } + + 85% { + opacity: 1; + } +} + /* ===== Circuit art theme tinting ===== */ :root[data-theme="dracula"] .toolbar-circuit { From 82c07ad81ac49263872c2da0eff76a929190d6f0 Mon Sep 17 00:00:00 2001 From: mysticmomba Date: Thu, 8 Oct 2026 11:23:19 -0400 Subject: [PATCH 8/9] Updated Version --- src-tauri/Cargo.lock | 2 +- src-tauri/Cargo.toml | 2 +- src-tauri/tauri.conf.json | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src-tauri/Cargo.lock b/src-tauri/Cargo.lock index ee13966..1f4f06a 100644 --- a/src-tauri/Cargo.lock +++ b/src-tauri/Cargo.lock @@ -49,7 +49,7 @@ checksum = "330a5ed07fa54e4702c9d6c4174f74427fc0ef6e214bbd677ae50a5099946470" [[package]] name = "argus" -version = "0.2.0" +version = "0.3.0" dependencies = [ "csv", "dns-lookup", diff --git a/src-tauri/Cargo.toml b/src-tauri/Cargo.toml index 07a3276..a904673 100644 --- a/src-tauri/Cargo.toml +++ b/src-tauri/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "argus" -version = "0.2.0" +version = "0.3.0" description = "An All in One Network Utility" authors = ["James Brotosky Date: Thu, 8 Oct 2026 11:23:41 -0400 Subject: [PATCH 9/9] Updated Changelog --- CHANGELOG.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ed8097d..4c73be8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,9 +1,10 @@ -## [unreleased] +## [0.3.0] - 2026-10-08 ### πŸš€ Features - Added Auto Labeling to Montior Tab. When sending hosts from the scan tab, it will bring their hostnames over to the label section. When adding a one off host to the montior tab, it will auto query it's hostname. You can also edit labels by double clicking. Closes #3 - Added Always on Top Toggle. Closes #5 +- Added New Theme ### πŸ› Bug Fixes