33 Commits
Author SHA1 Message Date
mysticmomba b380ab3cb2 Merge pull request 'Development' (#20) from development into master
Reviewed-on: #20
2026-10-09 12:59:43 -04:00
mysticmomba e5d0398ac0 Merge pull request 'Fix/notifications' (#19) from fix/notifications into development
Reviewed-on: #19
2026-10-09 12:59:32 -04:00
mysticmomba 87463bd8bc Updated main.js 2026-10-09 12:58:57 -04:00
mysticmomba d7181b8226 Updated changelog with version number 2026-10-09 12:58:10 -04:00
mysticmomba f0736d4ecd Update Version Numbers 2026-10-09 12:57:39 -04:00
mysticmomba 069e1ab19a fix: Fixed Windows Desktop Notifications. Windows Only Allows Notifications From Registered Applications. Added a Function in the Standalone Binary To Register It in the Registry As if It Were Installed. 2026-10-09 12:56:59 -04:00
mysticmomba 4b030cd7d2 Merge pull request 'Development' (#18) from development into master
Reviewed-on: #18
2026-10-09 11:51:10 -04:00
mysticmomba b80fff7609 Merge pull request 'Updated version number in code' (#17) from feat/minimizetotray into development
Reviewed-on: #17
2026-10-09 11:50:30 -04:00
mysticmomba a6558576ab Updated version number in code 2026-10-09 11:49:52 -04:00
mysticmomba 5ef796671f Merge pull request 'Feat/minimizetotray' (#16) from feat/minimizetotray into development
Reviewed-on: #16
2026-10-09 11:48:53 -04:00
mysticmomba 20b5c6e798 Updated change log to reflect version 2026-10-09 11:47:53 -04:00
mysticmomba 08eca1aac4 Updated Changelog 2026-10-09 11:47:14 -04:00
mysticmomba 2ce736e10f feat: Added Desktop Notifications While Minimized. This Will Send Notifications to the Desktop if a Host Status Changes While It’s Minimized to the System Tray. Closes #12. 2026-10-09 11:44:39 -04:00
mysticmomba 8f8e77242b feat: Added Minimize to System Tray While Monitor Is Running. Closes #6. 2026-10-09 11:16:32 -04:00
mysticmomba cf2cc9f8ed Added build script 2026-10-09 09:46:32 -04:00
mysticmomba b616243d48 Merge pull request 'Development' (#15) from development into master
Reviewed-on: #15
2026-10-09 09:38:48 -04:00
mysticmomba fd8bb16d40 Updated Theme 2026-10-09 09:38:24 -04:00
mysticmomba ed9ed59de9 Updated themes a tad 2026-10-08 15:12:29 -04:00
mysticmomba 56038b7a7e feat: Added more themes 2026-10-08 12:50:48 -04:00
mysticmomba 8227024076 Merge pull request 'Updated License' (#14) from development into master
Reviewed-on: #14
2026-10-08 12:25:55 -04:00
mysticmomba 7a8465b7fb Updated License 2026-10-08 12:25:34 -04:00
mysticmomba 518f8cfe36 Merge pull request 'Development' (#8) from development into master
Reviewed-on: #8
2026-10-08 11:25:29 -04:00
mysticmomba 29e0ae9d48 Updated Changelog 2026-10-08 11:23:41 -04:00
mysticmomba 82c07ad81a Updated Version 2026-10-08 11:23:19 -04:00
mysticmomba 1fe24d22ed feat: Added New Theme 2026-10-08 11:22:28 -04:00
mysticmomba aaeb7636a1 feat: Added Always on Top Toggle. Closes #5 2026-10-08 11:00:40 -04:00
mysticmomba 1df9c2f00c fix: 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. 2026-10-08 10:52:50 -04:00
mysticmomba d6ba6270c5 Updated Changelog 2026-10-08 10:43:46 -04:00
mysticmomba c5931c723f 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 2026-10-06 16:49:04 -04:00
mysticmomba 8cc8189820 fix: Removed unused function. 2026-10-06 16:36:30 -04:00
mysticmomba dbf98d598d fix: Status Colors on Monitor tab now reflect status of host. Closes #7 2026-10-06 16:27:32 -04:00
mysticmomba dbe8f2fb68 Merge pull request 'Fixed main.js' (#2) from development into master
Reviewed-on: #2
2026-09-24 10:28:40 -04:00
mysticmomba af5f65f166 Merge pull request '[0.2.0] - 2026-09-24' (#1) from development into master
Reviewed-on: #1
2026-09-24 10:18:36 -04:00
24 changed files with 950 additions and 271 deletions
+25
View File
@@ -1,3 +1,28 @@
## [0.4.1] - 2026-10-09
### 🐛 Bug Fixes
- Fixed Windows Desktop Notifications. Windows Only Allows Notifications From Registered Applications. Added a Function in the Standalone Binary To Register It in the Registry As if It Were Installed.
## [0.4.0] - 2026-10-09
### 🚀 Features
- Added more themes
- Added Minimize to System Tray While Monitor Is Running. Closes #6.
- Added Desktop Notifications While Minimized. This Will Send Notifications to the Desktop if a Host Status Changes While It’s Minimized to the System Tray. Closes #12.
## [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
- 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 ## [0.2.0] - 2026-09-24
### 🚀 Features ### 🚀 Features
+1 -1
View File
@@ -625,7 +625,7 @@ state the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found. the "copyright" line and a pointer to where the full notice is found.
Argus, an all in one network utility Argus, an all in one network utility
Copyright (C) 2026 Jamse Brotosky Copyright (C) 2026 James Brotosky
This program is free software: you can redistribute it and/or modify This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published it under the terms of the GNU Affero General Public License as published
Executable
+6
View File
@@ -0,0 +1,6 @@
#!/bin/bash
cd src-tauri && cargo clean
cargo clippy --fix --all-targets --allow-dirty
cargo fmt
cargo tauri build
cargo tauri build --runner cargo-xwin --target x86_64-pc-windows-msvc
+185 -189
View File
@@ -19,15 +19,15 @@ dependencies = [
[[package]] [[package]]
name = "alloc-no-stdlib" name = "alloc-no-stdlib"
version = "2.0.4" version = "3.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cc7bb162ec39d46ab1ca8c77bf72e890535becd1751bb45f64c597edb4c8c6b3" checksum = "c2fb6cfd47bf496ff64095c20eaba0c201404ee38714d4142fcfa1dc334fcc7a"
[[package]] [[package]]
name = "alloc-stdlib" name = "alloc-stdlib"
version = "0.2.4" version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0e76a019e91224d279006ff972f1e984179a6e9feb050adba6ce8274aef23195" checksum = "0b5c1865780388bfa186411ab5f247819487fc4864c6e9c3106611fa347586e1"
dependencies = [ dependencies = [
"alloc-no-stdlib", "alloc-no-stdlib",
] ]
@@ -49,7 +49,7 @@ checksum = "330a5ed07fa54e4702c9d6c4174f74427fc0ef6e214bbd677ae50a5099946470"
[[package]] [[package]]
name = "argus" name = "argus"
version = "0.2.0" version = "0.4.1"
dependencies = [ dependencies = [
"csv", "csv",
"dns-lookup", "dns-lookup",
@@ -66,7 +66,9 @@ dependencies = [
"tauri", "tauri",
"tauri-build", "tauri-build",
"tauri-plugin-dialog", "tauri-plugin-dialog",
"tauri-plugin-notification",
"tauri-plugin-opener", "tauri-plugin-opener",
"tauri-plugin-single-instance",
"tokio", "tokio",
"tracing", "tracing",
"tracing-subscriber", "tracing-subscriber",
@@ -319,9 +321,9 @@ dependencies = [
[[package]] [[package]]
name = "brotli" name = "brotli"
version = "8.0.4" version = "9.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5cc91aac060a7a1e25823bdccbfb6af1875b88f17c6daac97894eed8207166b3" checksum = "f8b851b75c23ca7873623d612fe49bd1989aeb03d08fb9432187eb253d3d4c6b"
dependencies = [ dependencies = [
"alloc-no-stdlib", "alloc-no-stdlib",
"alloc-stdlib", "alloc-stdlib",
@@ -330,9 +332,9 @@ dependencies = [
[[package]] [[package]]
name = "brotli-decompressor" name = "brotli-decompressor"
version = "5.0.3" version = "6.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3a32acac15fe1967bc3986b2a6347dffc965602354ea6f450ad07e8bfd253583" checksum = "941cd9bd4ddab83cb46fa5a2d428f1c857b24ac78cb876cf7beb710840934bd7"
dependencies = [ dependencies = [
"alloc-no-stdlib", "alloc-no-stdlib",
"alloc-stdlib", "alloc-stdlib",
@@ -433,12 +435,13 @@ dependencies = [
[[package]] [[package]]
name = "cargo_toml" name = "cargo_toml"
version = "0.22.3" version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "374b7c592d9c00c1f4972ea58390ac6b18cbb6ab79011f3bdc90a0b82ca06b77" checksum = "82f4b26e751e711a5302649417f2da046dce6391b2ea30a4820f37462314f0b9"
dependencies = [ dependencies = [
"semver",
"serde", "serde",
"toml 0.9.12+spec-1.1.0", "toml 1.1.6+spec-1.1.0",
] ]
[[package]] [[package]]
@@ -459,13 +462,13 @@ checksum = "6d43a04d8753f35258c91f8ec639f792891f748a1edbd759cf1dcea3382ad83c"
[[package]] [[package]]
name = "cfb" name = "cfb"
version = "0.7.3" version = "0.14.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d38f2da7a0a2c4ccf0065be06397cc26a81f4e528be095826eee9d4adbb8c60f" checksum = "a347dcabdae9c31b0825fd6a8bed285ec9c2acb89c47827126d52fa4f59cece3"
dependencies = [ dependencies = [
"byteorder",
"fnv", "fnv",
"uuid", "uuid",
"web-time",
] ]
[[package]] [[package]]
@@ -626,9 +629,9 @@ dependencies = [
[[package]] [[package]]
name = "cssparser" name = "cssparser"
version = "0.36.0" version = "0.37.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dae61cf9c0abb83bd659dab65b7e4e38d8236824c85f0f804f173567bda257d2" checksum = "8c9cdaae01d5ed7882b04d795e7f752f46ff52d2fa3b50a20d28c464510bba98"
dependencies = [ dependencies = [
"cssparser-macros", "cssparser-macros",
"dtoa-short", "dtoa-short",
@@ -639,12 +642,12 @@ dependencies = [
[[package]] [[package]]
name = "cssparser-macros" name = "cssparser-macros"
version = "0.6.1" version = "0.7.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "13b588ba4ac1a99f7f2964d24b3d896ddc6bf847ee3855dbd4366f058cfcd331" checksum = "d045de693cb712d0b22c6a64be5b953f67b3ce00ab5ad3dd5d8b441886ab8e1a"
dependencies = [ dependencies = [
"quote", "quote",
"syn 2.0.119", "syn 3.0.6",
] ]
[[package]] [[package]]
@@ -670,19 +673,9 @@ dependencies = [
[[package]] [[package]]
name = "ctor" name = "ctor"
version = "0.8.0" version = "1.0.13"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "352d39c2f7bef1d6ad73db6f5160efcaed66d94ef8c6c573a8410c00bf909a98" checksum = "914a755b7c2d4af2bdcff7ce1739e2db9a1b81a9b07123d8015786ae03c0980d"
dependencies = [
"ctor-proc-macro",
"dtor",
]
[[package]]
name = "ctor-proc-macro"
version = "0.0.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "52560adf09603e58c9a7ee1fe1dcb95a16927b17c127f0ac02d6e768a0e25bc1"
[[package]] [[package]]
name = "darling" name = "darling"
@@ -802,9 +795,9 @@ dependencies = [
[[package]] [[package]]
name = "dirs" name = "dirs"
version = "6.0.0" version = "7.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c3e8aa94d75141228480295a7d0e7feb620b1a5ad9f12bc40be62411e38cce4e" checksum = "8d57d423b3c82e89b9a24ca3091fee61f456a26edbd28d26c65906f4bc1dcd8f"
dependencies = [ dependencies = [
"dirs-sys", "dirs-sys",
] ]
@@ -881,9 +874,9 @@ dependencies = [
[[package]] [[package]]
name = "dom_query" name = "dom_query"
version = "0.27.0" version = "0.28.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "521e380c0c8afb8d9a1e83a1822ee03556fc3e3e7dbc1fd30be14e37f9cb3f89" checksum = "fac5fca71e65e94cc718a6e2af65d6e0f9c6027751c2aa562fbb5087fda639bc"
dependencies = [ dependencies = [
"bit-set", "bit-set",
"cssparser", "cssparser",
@@ -918,21 +911,6 @@ dependencies = [
"dtoa", "dtoa",
] ]
[[package]]
name = "dtor"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f1057d6c64987086ff8ed0fd3fbf377a6b7d205cc7715868cd401705f715cbe4"
dependencies = [
"dtor-proc-macro",
]
[[package]]
name = "dtor-proc-macro"
version = "0.0.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f678cf4a922c215c63e0de95eb1ff08a958a81d47e485cf9da1e27bf6305cfa5"
[[package]] [[package]]
name = "dunce" name = "dunce"
version = "1.0.5" version = "1.0.5"
@@ -1617,9 +1595,9 @@ checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70"
[[package]] [[package]]
name = "html5ever" name = "html5ever"
version = "0.38.0" version = "0.39.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1054432bae2f14e0061e33d23402fbaa67a921d319d56adc6bcf887ddad1cbc2" checksum = "46a1761807faccc9a19e86944bbf40610014066306f96edcdedc2fb714bcb7b8"
dependencies = [ dependencies = [
"log", "log",
"markup5ever", "markup5ever",
@@ -1910,9 +1888,9 @@ dependencies = [
[[package]] [[package]]
name = "infer" name = "infer"
version = "0.19.0" version = "0.22.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a588916bfdfd92e71cacef98a63d9b1f0d74d6599980d11894290e7ddefffcf7" checksum = "f4200d433cbd5178df7797c9c2e75b348b728e39631cf14520d1e2fc424201f4"
dependencies = [ dependencies = [
"cfb", "cfb",
] ]
@@ -2100,21 +2078,21 @@ dependencies = [
[[package]] [[package]]
name = "json-patch" name = "json-patch"
version = "3.0.1" version = "4.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "863726d7afb6bc2590eeff7135d923545e5e964f004c2ccf8716c25e70a86f08" checksum = "7421438de105a0827e44fadd05377727847d717c80ce29a229f85fd04c427b72"
dependencies = [ dependencies = [
"jsonptr", "jsonptr",
"serde", "serde",
"serde_json", "serde_json",
"thiserror 1.0.69", "thiserror 2.0.20",
] ]
[[package]] [[package]]
name = "jsonptr" name = "jsonptr"
version = "0.6.3" version = "0.7.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5dea2b27dd239b2556ed7a25ba842fe47fd602e7fc7433c2a8d6106d4d9edd70" checksum = "a5a3cc660ba5d72bce0b3bb295bf20847ccbb40fd423f3f05b61273672e561fe"
dependencies = [ dependencies = [
"serde", "serde",
"serde_json", "serde_json",
@@ -2122,13 +2100,12 @@ dependencies = [
[[package]] [[package]]
name = "keyboard-types" name = "keyboard-types"
version = "0.7.0" version = "0.8.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b750dcadc39a09dbadd74e118f6dd6598df77fa01df0cfcdc52c28dece74528a" checksum = "0fbe853b403ae61a04233030ae8a79d94975281ed9770a1f9e246732b534b28d"
dependencies = [ dependencies = [
"bitflags 2.13.2", "bitflags 2.13.2",
"serde", "serde",
"unicode-segmentation",
] ]
[[package]] [[package]]
@@ -2223,10 +2200,24 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f9f8bd3e56ce4dfc153cf470fffbfa98c7620958b312ca5c3a4b8d5181fd13c6" checksum = "f9f8bd3e56ce4dfc153cf470fffbfa98c7620958b312ca5c3a4b8d5181fd13c6"
[[package]] [[package]]
name = "markup5ever" name = "mac-notification-sys"
version = "0.38.0" version = "0.6.15"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8983d30f2915feeaaab2d6babdd6bc7e9ed1a00b66b5e6d74df19aa9c0e91862" checksum = "fd604973958ddcc11b561193c0fb96ba146506ef2f231ef2e7c35fd2cbc9beca"
dependencies = [
"cc",
"log",
"objc2",
"objc2-foundation",
"time",
"uuid",
]
[[package]]
name = "markup5ever"
version = "0.39.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7122d987ec5f704ee56f6e5b41a7d93722e9aae27ae07cafa4036c4d3f9757de"
dependencies = [ dependencies = [
"log", "log",
"tendril", "tendril",
@@ -2296,9 +2287,9 @@ dependencies = [
[[package]] [[package]]
name = "muda" name = "muda"
version = "0.19.3" version = "0.20.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1dd04e60bc0b07438a6771710ee1698f98f6ebbc7f89b61264af1563b8aeb878" checksum = "cca139e57da4383727f189e43e66e84fa372347027fc996f9f1a007ec0a37996"
dependencies = [ dependencies = [
"crossbeam-channel", "crossbeam-channel",
"dpi", "dpi",
@@ -2374,6 +2365,12 @@ dependencies = [
"thiserror 1.0.69", "thiserror 1.0.69",
] ]
[[package]]
name = "ndk-context"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "27b02d87554356db9e9a873add8782d4ea6e3e58ea071a9adb9a2e8ddb884a8b"
[[package]] [[package]]
name = "ndk-sys" name = "ndk-sys"
version = "0.6.0+11769913" version = "0.6.0+11769913"
@@ -2389,6 +2386,20 @@ version = "1.0.6"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "650eef8c711430f1a879fdd01d4745a7deea475becfb90269c06775983bbf086" checksum = "650eef8c711430f1a879fdd01d4745a7deea475becfb90269c06775983bbf086"
[[package]]
name = "notify-rust"
version = "4.18.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4587364a9a0074333429b3df75a30a205340c56a536ca3eb6ca0e59b87bbf8af"
dependencies = [
"futures-lite",
"log",
"mac-notification-sys",
"serde",
"tauri-winrt-notification",
"zbus",
]
[[package]] [[package]]
name = "nu-ansi-term" name = "nu-ansi-term"
version = "0.50.3" version = "0.50.3"
@@ -2456,6 +2467,7 @@ dependencies = [
"objc2", "objc2",
"objc2-core-foundation", "objc2-core-foundation",
"objc2-foundation", "objc2-foundation",
"objc2-quartz-core",
] ]
[[package]] [[package]]
@@ -3454,9 +3466,9 @@ dependencies = [
[[package]] [[package]]
name = "selectors" name = "selectors"
version = "0.36.1" version = "0.38.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c5d9c0c92a92d33f08817311cf3f2c29a3538a8240e94a6a3c622ce652d7e00c" checksum = "8adfa1c298912827b8a28b223b3b874357397ae706e6190acd9bf28cee99114d"
dependencies = [ dependencies = [
"bitflags 2.13.2", "bitflags 2.13.2",
"cssparser", "cssparser",
@@ -3923,9 +3935,9 @@ dependencies = [
[[package]] [[package]]
name = "tao" name = "tao"
version = "0.35.3" version = "0.37.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d1c93047acf68669466a34690ac58cca7010bd1b201e1ec86f1fd0a75d3dd4a9" checksum = "f37f381f4e048e6cdf038b5705f8cf14ad108279d46eb968140a7b291aba9400"
dependencies = [ dependencies = [
"bitflags 2.13.2", "bitflags 2.13.2",
"block2", "block2",
@@ -3943,20 +3955,20 @@ dependencies = [
"libc", "libc",
"log", "log",
"ndk", "ndk",
"ndk-context",
"ndk-sys", "ndk-sys",
"objc2", "objc2",
"objc2-app-kit", "objc2-app-kit",
"objc2-foundation", "objc2-foundation",
"objc2-ui-kit", "objc2-ui-kit",
"once_cell",
"parking_lot", "parking_lot",
"percent-encoding", "percent-encoding",
"raw-window-handle", "raw-window-handle",
"tao-macros", "tao-macros",
"unicode-segmentation", "unicode-segmentation",
"url", "url",
"windows 0.61.3", "windows 0.62.2",
"windows-core 0.61.2", "windows-core 0.62.2",
"windows-version", "windows-version",
"x11-dl", "x11-dl",
] ]
@@ -3980,9 +3992,9 @@ checksum = "61c41af27dd6d1e27b1b16b489db798443478cef1f06a660c96db617ba5de3b1"
[[package]] [[package]]
name = "tauri" name = "tauri"
version = "2.11.6" version = "2.12.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6fa5bacdb9bbad5954af3d1bd6cf6ae9192cab1b2e270f4a07f904610b9e85f4" checksum = "d061d042ccd2df9c9f1508c1e63d835278c0a4c8801eb41764080e51f2eaaf34"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"bytes", "bytes",
@@ -4026,14 +4038,14 @@ dependencies = [
"webkit2gtk", "webkit2gtk",
"webview2-com", "webview2-com",
"window-vibrancy", "window-vibrancy",
"windows 0.61.3", "windows 0.62.2",
] ]
[[package]] [[package]]
name = "tauri-build" name = "tauri-build"
version = "2.6.3" version = "2.7.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bc9ce40b16101cb6ea63d3e221567affd1c3a9205f95d7bc574941a10636b632" checksum = "59563ca5b331fd97f27ee9672ec8d36d33bb3c9e2c9f6710a1a5687256052e45"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"cargo_toml", "cargo_toml",
@@ -4052,16 +4064,16 @@ dependencies = [
[[package]] [[package]]
name = "tauri-codegen" name = "tauri-codegen"
version = "2.6.3" version = "2.7.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "08279169ff42f8fc45a1dbc9dcae888893ba95288142e5880c59b93a26d2cfc5" checksum = "e50213e463086ecc283d7e9f51c30cc0fd304ad457425158018be26dbf0d0a80"
dependencies = [ dependencies = [
"base64 0.22.1", "base64 0.22.1",
"brotli", "brotli",
"ico", "ico",
"json-patch", "json-patch",
"plist", "plist",
"png 0.17.16", "png 0.18.1",
"proc-macro2", "proc-macro2",
"quote", "quote",
"semver", "semver",
@@ -4079,9 +4091,9 @@ dependencies = [
[[package]] [[package]]
name = "tauri-macros" name = "tauri-macros"
version = "2.6.3" version = "2.7.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e8b394794f399a421811d06966343e7933fcae92d59f5180b9388d1174497a45" checksum = "8129fb43bb6e0d6b73ad3315cd172beaab17cd28899c594b1b32c80edbbfd99c"
dependencies = [ dependencies = [
"heck 0.5.0", "heck 0.5.0",
"proc-macro2", "proc-macro2",
@@ -4093,9 +4105,9 @@ dependencies = [
[[package]] [[package]]
name = "tauri-plugin" name = "tauri-plugin"
version = "2.6.3" version = "2.7.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "74be5dd4bed9afbd145e5716b5fa2ec28cbc29c34ffa61c258c9273d896c8020" checksum = "1140cf34a3b3b836a13103dcab17f18831d5cc3534cbd435dc01a5c6daa65aa2"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"glob", "glob",
@@ -4149,6 +4161,25 @@ dependencies = [
"url", "url",
] ]
[[package]]
name = "tauri-plugin-notification"
version = "2.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "533770889abb60a0407d5a32096182f0e6463f5a3dfaa675be94580aa14070e1"
dependencies = [
"log",
"notify-rust",
"rand",
"serde",
"serde_json",
"serde_repr",
"tauri",
"tauri-plugin",
"thiserror 2.0.20",
"time",
"url",
]
[[package]] [[package]]
name = "tauri-plugin-opener" name = "tauri-plugin-opener"
version = "2.5.5" version = "2.5.5"
@@ -4172,10 +4203,26 @@ dependencies = [
] ]
[[package]] [[package]]
name = "tauri-runtime" name = "tauri-plugin-single-instance"
version = "2.11.3" version = "2.4.5"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b0b4bc95aed361b0019067d189a1174a603d460d0f6c72606512d59fc9c12ec8" checksum = "db817fe9295e19b7d8357e900af31edb93703dd9fb6de524b007b47b6afc63b0"
dependencies = [
"serde",
"serde_json",
"tauri",
"thiserror 2.0.20",
"tokio",
"tracing",
"windows-sys 0.60.2",
"zbus",
]
[[package]]
name = "tauri-runtime"
version = "2.12.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c2a57a2a9b8c8b7fc00d35b510fe808ded7f9f1b44fc1cdda6aee38632ea5413"
dependencies = [ dependencies = [
"cookie", "cookie",
"dpi", "dpi",
@@ -4193,14 +4240,14 @@ dependencies = [
"url", "url",
"webkit2gtk", "webkit2gtk",
"webview2-com", "webview2-com",
"windows 0.61.3", "windows 0.62.2",
] ]
[[package]] [[package]]
name = "tauri-runtime-wry" name = "tauri-runtime-wry"
version = "2.11.4" version = "2.12.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4e6fac707727b7a2f48e4ded90976324267371073edbb415ffb73bb0458d203f" checksum = "7f9e7e0c9f80a5130773cfabb6df4dc924518fb1b2c923726966804634b57d22"
dependencies = [ dependencies = [
"gtk", "gtk",
"http", "http",
@@ -4218,15 +4265,15 @@ dependencies = [
"url", "url",
"webkit2gtk", "webkit2gtk",
"webview2-com", "webview2-com",
"windows 0.61.3", "windows 0.62.2",
"wry", "wry",
] ]
[[package]] [[package]]
name = "tauri-utils" name = "tauri-utils"
version = "2.9.3" version = "2.10.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3e176a18e67764923c4f1ce66f25ae4abe5f688384d5eb1a0fa6c77f3d90f887" checksum = "2ff55a614843b9a3f010f211df637c94df2607175b8d0f6e0f4a7c19e18621ee"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"brotli", "brotli",
@@ -4271,6 +4318,17 @@ dependencies = [
"toml 1.1.6+spec-1.1.0", "toml 1.1.6+spec-1.1.0",
] ]
[[package]]
name = "tauri-winrt-notification"
version = "0.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f37a6c354fd28fc9e322ed9bd47e3959576dad28c9d58ea1cf888cce1c7ccb36"
dependencies = [
"thiserror 2.0.20",
"windows 0.62.2",
"windows-version",
]
[[package]] [[package]]
name = "tempfile" name = "tempfile"
version = "3.27.0" version = "3.27.0"
@@ -4462,21 +4520,6 @@ dependencies = [
"toml_edit 0.20.2", "toml_edit 0.20.2",
] ]
[[package]]
name = "toml"
version = "0.9.12+spec-1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cf92845e79fc2e2def6a5d828f0801e29a2f8acc037becc5ab08595c7d5e9863"
dependencies = [
"indexmap 2.14.2",
"serde_core",
"serde_spanned 1.1.1",
"toml_datetime 0.7.5+spec-1.1.0",
"toml_parser",
"toml_writer",
"winnow 0.7.15",
]
[[package]] [[package]]
name = "toml" name = "toml"
version = "1.1.6+spec-1.1.0" version = "1.1.6+spec-1.1.0"
@@ -4501,15 +4544,6 @@ dependencies = [
"serde", "serde",
] ]
[[package]]
name = "toml_datetime"
version = "0.7.5+spec-1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "92e1cfed4a3038bc5a127e35a2d360f145e1f4b971b551a2ba5fd7aedf7e1347"
dependencies = [
"serde_core",
]
[[package]] [[package]]
name = "toml_datetime" name = "toml_datetime"
version = "1.1.1+spec-1.1.0" version = "1.1.1+spec-1.1.0"
@@ -4678,9 +4712,9 @@ dependencies = [
[[package]] [[package]]
name = "tray-icon" name = "tray-icon"
version = "0.24.2" version = "0.25.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "045979e3f037cd18ad1cb2a419dfda133c5c29c9f3453370079f2255d46c257e" checksum = "b2b9c52859a94554803ccd4a24b98f74148ebc73b90676d783f3490b1bff9d72"
dependencies = [ dependencies = [
"crossbeam-channel", "crossbeam-channel",
"dirs", "dirs",
@@ -4727,47 +4761,6 @@ dependencies = [
"windows-sys 0.61.2", "windows-sys 0.61.2",
] ]
[[package]]
name = "unic-char-property"
version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a8c57a407d9b6fa02b4795eb81c5b6652060a15a7903ea981f3d723e6c0be221"
dependencies = [
"unic-char-range",
]
[[package]]
name = "unic-char-range"
version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0398022d5f700414f6b899e10b8348231abf9173fa93144cbc1a43b9793c1fbc"
[[package]]
name = "unic-common"
version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "80d7ff825a6a654ee85a63e80f92f054f904f21e7d12da4e22f9834a4aaa35bc"
[[package]]
name = "unic-ucd-ident"
version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e230a37c0381caa9219d67cf063aa3a375ffed5bf541a452db16e744bdab6987"
dependencies = [
"unic-char-property",
"unic-char-range",
"unic-ucd-version",
]
[[package]]
name = "unic-ucd-version"
version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "96bd2f2237fe450fcd0a1d2f5f4e91711124f7857ba2e964247776ebeeb7b0c4"
dependencies = [
"unic-common",
]
[[package]] [[package]]
name = "unicase" name = "unicase"
version = "2.9.0" version = "2.9.0"
@@ -4813,13 +4806,13 @@ dependencies = [
[[package]] [[package]]
name = "urlpattern" name = "urlpattern"
version = "0.3.0" version = "0.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "70acd30e3aa1450bc2eece896ce2ad0d178e9c079493819301573dae3c37ba6d" checksum = "df16f50ef4cc145211879a3867ba757076b25dfee812040dcb0658bd9ae7904b"
dependencies = [ dependencies = [
"icu_properties",
"regex", "regex",
"serde", "serde",
"unic-ucd-ident",
"url", "url",
] ]
@@ -4997,6 +4990,16 @@ dependencies = [
"wasm-bindgen", "wasm-bindgen",
] ]
[[package]]
name = "web-time"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5a6580f308b1fad9207618087a65c04e7a10bc77e02c8e84e9b00dd4b12fa0bb"
dependencies = [
"js-sys",
"wasm-bindgen",
]
[[package]] [[package]]
name = "web_atoms" name = "web_atoms"
version = "0.2.6" version = "0.2.6"
@@ -5055,16 +5058,14 @@ dependencies = [
[[package]] [[package]]
name = "webview2-com" name = "webview2-com"
version = "0.38.2" version = "0.39.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7130243a7a5b33c54a444e54842e6a9e133de08b5ad7b5861cd8ed9a6a5bc96a" checksum = "3f89fca7a704cee10dcb3654c1dbb8941d1783132f1917358af75bec37a7d7e6"
dependencies = [ dependencies = [
"webview2-com-macros", "webview2-com-macros",
"webview2-com-sys", "webview2-com-sys",
"windows 0.61.3", "windows 0.62.2",
"windows-core 0.61.2", "windows-core 0.62.2",
"windows-implement",
"windows-interface",
] ]
[[package]] [[package]]
@@ -5080,13 +5081,13 @@ dependencies = [
[[package]] [[package]]
name = "webview2-com-sys" name = "webview2-com-sys"
version = "0.38.2" version = "0.39.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "381336cfffd772377d291702245447a5251a2ffa5bad679c99e61bc48bacbf9c" checksum = "b3a07132775117d6065853d9d1178157b8c90e228de47129d6bce2c7edebedfb"
dependencies = [ dependencies = [
"thiserror 2.0.20", "thiserror 2.0.20",
"windows 0.61.3", "windows 0.62.2",
"windows-core 0.61.2", "windows-core 0.62.2",
] ]
[[package]] [[package]]
@@ -5122,16 +5123,17 @@ checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
[[package]] [[package]]
name = "window-vibrancy" name = "window-vibrancy"
version = "0.6.0" version = "0.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d9bec5a31f3f9362f2258fd0e9c9dd61a9ca432e7306cc78c444258f0dce9a9c" checksum = "111e51caca442cafd9bab396628ac4d814880eaea4e63dfd76a12e9f342b5580"
dependencies = [ dependencies = [
"objc2", "objc2",
"objc2-app-kit", "objc2-app-kit",
"objc2-core-foundation", "objc2-core-foundation",
"objc2-foundation", "objc2-foundation",
"objc2-quartz-core",
"raw-window-handle", "raw-window-handle",
"windows-sys 0.59.0", "windows-sys 0.61.2",
"windows-version", "windows-version",
] ]
@@ -5594,12 +5596,6 @@ dependencies = [
"memchr", "memchr",
] ]
[[package]]
name = "winnow"
version = "0.7.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "df79d97927682d2fd8adb29682d1140b343be4ac0f08fd68b7765d9c059d3945"
[[package]] [[package]]
name = "winnow" name = "winnow"
version = "1.0.4" version = "1.0.4"
@@ -5633,9 +5629,9 @@ checksum = "3ad82d2a33cdc9674dc7465672f271e096168fcdbe0f799d9e6db8c5892679dc"
[[package]] [[package]]
name = "wry" name = "wry"
version = "0.55.1" version = "0.57.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "186f9871daa55fd9c016578b810d149de58367113db7fb72b462d2323ce19514" checksum = "a819957a01b3119af85e638a38d242af76dbc87d130dca67bfd0441072e21ff0"
dependencies = [ dependencies = [
"base64 0.22.1", "base64 0.22.1",
"block2", "block2",
@@ -5669,8 +5665,8 @@ dependencies = [
"webkit2gtk", "webkit2gtk",
"webkit2gtk-sys", "webkit2gtk-sys",
"webview2-com", "webview2-com",
"windows 0.61.3", "windows 0.62.2",
"windows-core 0.61.2", "windows-core 0.62.2",
"windows-version", "windows-version",
"x11-dl", "x11-dl",
] ]
+4 -2
View File
@@ -1,6 +1,6 @@
[package] [package]
name = "argus" name = "argus"
version = "0.2.0" version = "0.4.1"
description = "An All in One Network Utility" description = "An All in One Network Utility"
authors = ["James Brotosky <james.brotosky@racooncity.org"] authors = ["James Brotosky <james.brotosky@racooncity.org"]
edition = "2021" edition = "2021"
@@ -18,7 +18,8 @@ crate-type = ["staticlib", "cdylib", "rlib"]
tauri-build = { version = "2", features = [] } tauri-build = { version = "2", features = [] }
[dependencies] [dependencies]
tauri = { version = "2", features = [] } tauri = { version = "2", features = ["tray-icon"] }
tauri-plugin-single-instance = "2"
tauri-plugin-opener = "2" tauri-plugin-opener = "2"
serde = { version = "1", features = ["derive"] } serde = { version = "1", features = ["derive"] }
serde_json = "1" serde_json = "1"
@@ -35,6 +36,7 @@ reqwest = { version = "0.12", features = ["json"] }
libc = "0.2.189" libc = "0.2.189"
pulldown-cmark = { version = "0.13.4", features = ["html"] } pulldown-cmark = { version = "0.13.4", features = ["html"] }
semver = "1.0.28" semver = "1.0.28"
tauri-plugin-notification = "2.5.1"
[target.'cfg(windows)'.dependencies] [target.'cfg(windows)'.dependencies]
is_elevated = "0.1" is_elevated = "0.1"
+4 -1
View File
@@ -6,6 +6,9 @@
"permissions": [ "permissions": [
"core:default", "core:default",
"opener:default", "opener:default",
"dialog:default" "dialog:default",
"core:window:allow-set-always-on-top",
"notification:default",
"core:window:allow-is-visible"
] ]
} }
+1 -1
View File
@@ -16,4 +16,4 @@ pub async fn check_privileges() -> Result<bool, String> {
// On Windows, check if running as administrator // On Windows, check if running as administrator
Ok(is_elevated::is_elevated()) Ok(is_elevated::is_elevated())
} }
} }
+4 -5
View File
@@ -1,16 +1,15 @@
use pulldown_cmark::{Options, Parser, html}; use pulldown_cmark::{html, Options, Parser};
const CHANGELOG_MD: &str = include_str!("../../../CHANGELOG.md"); const CHANGELOG_MD: &str = include_str!("../../../CHANGELOG.md");
#[tauri::command] #[tauri::command]
pub async fn get_changelog() -> Result<String, String> { pub async fn get_changelog() -> Result<String, String> {
let options = Options::ENABLE_HEADING_ATTRIBUTES let options =
| Options::ENABLE_STRIKETHROUGH Options::ENABLE_HEADING_ATTRIBUTES | Options::ENABLE_STRIKETHROUGH | Options::ENABLE_TABLES;
| Options::ENABLE_TABLES;
let parser = Parser::new_ext(CHANGELOG_MD, options); let parser = Parser::new_ext(CHANGELOG_MD, options);
let mut html_output = String::new(); let mut html_output = String::new();
html::push_html(&mut html_output, parser); html::push_html(&mut html_output, parser);
Ok(html_output) Ok(html_output)
} }
+2 -3
View File
@@ -11,8 +11,7 @@ pub struct ExportRequest {
#[tauri::command] #[tauri::command]
pub async fn export_csv(request: ExportRequest) -> Result<(), String> { pub async fn export_csv(request: ExportRequest) -> Result<(), String> {
let file = File::create(&request.path) let file = File::create(&request.path).map_err(|e| format!("Failed to create file: {}", e))?;
.map_err(|e| format!("Failed to create file: {}", e))?;
let mut writer = csv::Writer::from_writer(file); let mut writer = csv::Writer::from_writer(file);
@@ -43,4 +42,4 @@ pub async fn export_csv(request: ExportRequest) -> Result<(), String> {
tracing::info!("Exported {} hosts to {}", request.hosts.len(), request.path); tracing::info!("Exported {} hosts to {}", request.hosts.len(), request.path);
Ok(()) Ok(())
} }
+21
View File
@@ -180,3 +180,24 @@ pub async fn monitor_stop() -> Result<(), String> {
} }
Ok(()) 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<Option<String>, String> {
let parsed: IpAddr = ip.parse().map_err(|e| format!("Invalid IP: {}", e))?;
Ok(crate::net::dns::reverse_lookup(parsed).await)
}
pub fn is_monitor_running() -> bool {
let state = get_monitor();
let guard = state.blocking_lock();
guard.running
}
+10 -1
View File
@@ -40,7 +40,16 @@ pub async fn start_scan(app: AppHandle, config: ScanConfig) -> Result<(), String
let port_timeout_ms = config.port_timeout_ms.unwrap_or(1000); let port_timeout_ms = config.port_timeout_ms.unwrap_or(1000);
tokio::spawn(async move { tokio::spawn(async move {
ping_sweep(&app, &ips, timeout_ms, cancel, port_scan, ports, port_timeout_ms).await; ping_sweep(
&app,
&ips,
timeout_ms,
cancel,
port_scan,
ports,
port_timeout_ms,
)
.await;
}); });
Ok(()) Ok(())
} }
+104
View File
@@ -3,7 +3,52 @@ mod models;
mod net; mod net;
mod scanner; mod scanner;
use tauri::menu::{Menu, MenuItem};
use tauri::tray::TrayIconBuilder;
use tauri::Manager;
#[cfg_attr(mobile, tauri::mobile_entry_point)] #[cfg_attr(mobile, tauri::mobile_entry_point)]
#[cfg(target_os = "windows")]
fn register_aumid() {
let app_id = "io.argus.app";
let key_path = format!("HKCU\\Software\\Classes\\AppUserModelId\\{}", app_id);
// Check if already registered
let check = std::process::Command::new("reg")
.args(["query", &key_path])
.output();
if let Ok(o) = check {
if o.status.success() {
tracing::debug!("AUMID already registered");
return;
}
}
// Not registered, create it
let output = std::process::Command::new("reg")
.args([
"add",
&key_path,
"/v", "DisplayName",
"/t", "REG_SZ",
"/d", "Argus",
"/f",
])
.output();
match output {
Ok(o) if o.status.success() => {
tracing::debug!("AUMID registered successfully");
}
Ok(o) => {
tracing::warn!("AUMID registration failed: {}", String::from_utf8_lossy(&o.stderr));
}
Err(e) => {
tracing::warn!("Failed to run reg command: {}", e);
}
}
}
pub fn run() { pub fn run() {
tracing_subscriber::fmt() tracing_subscriber::fmt()
.with_env_filter( .with_env_filter(
@@ -13,8 +58,65 @@ pub fn run() {
.init(); .init();
tauri::Builder::default() tauri::Builder::default()
.plugin(tauri_plugin_single_instance::init(|app, _args, _cwd| {
if let Some(window) = app.get_webview_window("main") {
let _ = window.show();
let _ = window.set_focus();
}
}))
.plugin(tauri_plugin_opener::init()) .plugin(tauri_plugin_opener::init())
.plugin(tauri_plugin_dialog::init()) .plugin(tauri_plugin_dialog::init())
.plugin(tauri_plugin_notification::init())
.setup(|app| {
let show = MenuItem::with_id(app, "show", "Show Argus", true, None::<&str>)?;
let quit = MenuItem::with_id(app, "quit", "Quit", true, None::<&str>)?;
let menu = Menu::with_items(app, &[&show, &quit])?;
#[cfg(target_os = "windows")]
register_aumid();
let _tray = TrayIconBuilder::new()
.icon(app.default_window_icon().unwrap().clone())
.tooltip("Argus - Network Scanner")
.menu(&menu)
.show_menu_on_left_click(false)
.on_menu_event(|app, event| match event.id.as_ref() {
"show" => {
if let Some(window) = app.get_webview_window("main") {
let _ = window.show();
let _ = window.set_focus();
}
}
"quit" => {
app.exit(0);
}
_ => {}
})
.on_tray_icon_event(|tray, event| {
if let tauri::tray::TrayIconEvent::DoubleClick { .. } = event {
if let Some(window) = tray.app_handle().get_webview_window("main") {
let _ = window.show();
let _ = window.set_focus();
}
}
})
.build(app)?;
// Hide to tray when monitor is running
let app_handle = app.handle().clone();
if let Some(window) = app.get_webview_window("main") {
window.on_window_event(move |event| {
if let tauri::WindowEvent::CloseRequested { api, .. } = event {
if commands::monitor::is_monitor_running() {
api.prevent_close();
if let Some(win) = app_handle.get_webview_window("main") {
let _ = win.hide();
}
}
}
});
}
Ok(())
})
.invoke_handler(tauri::generate_handler![ .invoke_handler(tauri::generate_handler![
commands::scan::start_scan, commands::scan::start_scan,
commands::scan::stop_scan, commands::scan::stop_scan,
@@ -32,6 +134,8 @@ pub fn run() {
commands::updater::check_for_update, commands::updater::check_for_update,
commands::actions::check_privileges, commands::actions::check_privileges,
commands::changelog::get_changelog, commands::changelog::get_changelog,
commands::monitor::monitor_update_label,
commands::monitor::monitor_resolve_host
]) ])
.run(tauri::generate_context!()) .run(tauri::generate_context!())
.expect("error while running tauri application"); .expect("error while running tauri application");
+4 -4
View File
@@ -6,7 +6,7 @@ pub enum HostStatus {
Up, Up,
Down, Down,
Filtered, Filtered,
Unknown Unknown,
} }
#[derive(Debug, Clone, Serialize, Deserialize)] #[derive(Debug, Clone, Serialize, Deserialize)]
@@ -42,7 +42,7 @@ pub struct PortResult {
pub struct NetbiosInfo { pub struct NetbiosInfo {
pub computer_name: Option<String>, pub computer_name: Option<String>,
pub workgroup: Option<String>, pub workgroup: Option<String>,
pub mac_from_netbios: Option<String> pub mac_from_netbios: Option<String>,
} }
#[derive(Debug, Clone, Serialize, Deserialize)] #[derive(Debug, Clone, Serialize, Deserialize)]
@@ -79,7 +79,7 @@ impl HostResult {
updated_at: now_ms(), updated_at: now_ms(),
} }
} }
pub fn down(ip: IpAddr) -> Self { pub fn down(ip: IpAddr) -> Self {
Self { Self {
ip, ip,
@@ -93,4 +93,4 @@ impl HostResult {
updated_at: now_ms(), updated_at: now_ms(),
} }
} }
} }
+1 -1
View File
@@ -1,2 +1,2 @@
pub mod host; pub mod host;
pub mod monitor; pub mod monitor;
+1 -33
View File
@@ -1,12 +1,9 @@
use std::net::IpAddr; use std::net::IpAddr;
use tokio::task::JoinSet;
/// Perform reverse DNS lookup on a single IP. /// Perform reverse DNS lookup on a single IP.
/// Returns the hostname if found, None otherwise. /// Returns the hostname if found, None otherwise.
pub async fn reverse_lookup(ip: IpAddr) -> Option<String> { pub async fn reverse_lookup(ip: IpAddr) -> Option<String> {
let result = tokio::task::spawn_blocking(move || { let result = tokio::task::spawn_blocking(move || dns_lookup::lookup_addr(&ip)).await;
dns_lookup::lookup_addr(&ip)
}).await;
match result { match result {
Ok(Ok(hostname)) => { Ok(Ok(hostname)) => {
@@ -19,32 +16,3 @@ pub async fn reverse_lookup(ip: IpAddr) -> Option<String> {
_ => None, _ => None,
} }
} }
/// Perform reverse DNS lookups on a batch of IPs concurrently.
/// Returns a Vec of (IpAddr, Option<hostname>) pairs.
pub async fn reverse_lookup_batch(
ips: &[IpAddr],
max_concurrent: usize,
) -> Vec<(IpAddr, Option<String>)> {
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
}
+1 -1
View File
@@ -1,2 +1,2 @@
pub mod dns;
pub mod range; pub mod range;
pub mod dns;
+1 -1
View File
@@ -140,4 +140,4 @@ mod tests {
fn test_reversed_range() { fn test_reversed_range() {
assert!(parse_ip_range("192.168.1.10-192.168.1.1").is_err()); assert!(parse_ip_range("192.168.1.10-192.168.1.1").is_err());
} }
} }
+1 -1
View File
@@ -1,3 +1,3 @@
pub mod netbios;
pub mod ping; pub mod ping;
pub mod ports; pub mod ports;
pub mod netbios;
+1 -2
View File
@@ -91,8 +91,7 @@ pub async fn ping_sweep(
let nb_fut = query_netbios(enriched.ip, 500); let nb_fut = query_netbios(enriched.ip, 500);
if port_scan { if port_scan {
let scan_ports = ports2 let scan_ports = ports2.unwrap_or_else(|| DEFAULT_PORTS.to_vec());
.unwrap_or_else(|| DEFAULT_PORTS.to_vec());
let (nb_result, port_results) = tokio::join!( let (nb_result, port_results) = tokio::join!(
nb_fut, nb_fut,
scan_host_ports(enriched.ip, &scan_ports, port_timeout_ms) scan_host_ports(enriched.ip, &scan_ports, port_timeout_ms)
+16 -11
View File
@@ -42,8 +42,7 @@ fn service_name(port: u16) -> Option<String> {
} }
pub const DEFAULT_PORTS: &[u16] = &[ pub const DEFAULT_PORTS: &[u16] = &[
21, 22, 23, 25, 53, 80, 110, 111, 135, 139, 143, 21, 22, 23, 25, 53, 80, 110, 111, 135, 139, 143, 443, 445, 993, 995, 1433, 1521, 3306, 3389,
443, 445, 993, 995, 1433, 1521, 3306, 3389,
5432, 5900, 5985, 5986, 8080, 8088, 8443, 5432, 5900, 5985, 5986, 8080, 8088, 8443,
]; ];
@@ -96,7 +95,10 @@ async fn grab_banner(mut stream: TcpStream, port: u16) -> Option<String> {
}; };
if let Some(data) = probe { if let Some(data) = probe {
if timeout(banner_timeout, stream.write_all(data)).await.is_err() { if timeout(banner_timeout, stream.write_all(data))
.await
.is_err()
{
return None; return None;
} }
} }
@@ -107,8 +109,15 @@ async fn grab_banner(mut stream: TcpStream, port: u16) -> Option<String> {
Ok(Ok(n)) if n > 0 => { Ok(Ok(n)) if n > 0 => {
buf.truncate(n); buf.truncate(n);
// Strip to printable ASCII, replace control chars // Strip to printable ASCII, replace control chars
let banner: String = buf.iter() let banner: String = buf
.map(|&b| if b >= 0x20 && b < 0x7f { b as char } else { ' ' }) .iter()
.map(|&b| {
if (0x20..0x7f).contains(&b) {
b as char
} else {
' '
}
})
.collect(); .collect();
let banner = banner.trim().to_string(); let banner = banner.trim().to_string();
if banner.is_empty() { if banner.is_empty() {
@@ -124,11 +133,7 @@ async fn grab_banner(mut stream: TcpStream, port: u16) -> Option<String> {
const MAX_PORT_CONCURRENT: usize = 64; const MAX_PORT_CONCURRENT: usize = 64;
pub async fn scan_host_ports( pub async fn scan_host_ports(ip: IpAddr, ports: &[u16], timeout_ms: u64) -> Vec<PortResult> {
ip: IpAddr,
ports: &[u16],
timeout_ms: u64,
) -> Vec<PortResult> {
let mut results = Vec::with_capacity(ports.len()); let mut results = Vec::with_capacity(ports.len());
for chunk in ports.chunks(MAX_PORT_CONCURRENT) { for chunk in ports.chunks(MAX_PORT_CONCURRENT) {
@@ -148,4 +153,4 @@ pub async fn scan_host_ports(
results.sort_by_key(|p| p.port); results.sort_by_key(|p| p.port);
results results
} }
+1 -1
View File
@@ -1,7 +1,7 @@
{ {
"$schema": "https://schema.tauri.app/config/2", "$schema": "https://schema.tauri.app/config/2",
"productName": "argus", "productName": "argus",
"version": "0.2.0", "version": "0.4.1",
"identifier": "io.argus.app", "identifier": "io.argus.app",
"build": { "build": {
"frontendDist": "../src" "frontendDist": "../src"
+11 -1
View File
@@ -200,12 +200,22 @@
<div id="status-bar"> <div id="status-bar">
<span class="status-bar-item" id="status-bar-version">Argus</span> <span class="status-bar-item" id="status-bar-version">Argus</span>
<button id="btn-changelog" class="status-bar-btn">Changelog</button> <button id="btn-changelog" class="status-bar-btn">Changelog</button>
<label class="toggle-label status-bar-toggle">
<input type="checkbox" id="chk-always-on-top" />
<span>Always on Top</span>
</label>
<select id="theme-picker" class="theme-picker"> <select id="theme-picker" class="theme-picker">
<option value="cyber">Cyber</option> <option value="cyber">Cyber</option>
<option value="midnight">Midnight</option> <option value="midnight">Midnight</option>
<option value="dracula">Dracula</option> <option value="dracula">Dracula</option>
<option value="nord">Nord</option> <option value="nord">Nord</option>
<option value="solarized">Solarized Dark</option> <option value="solarized">Solarized Dark</option>
<option value="mocha">Catppuccin Mocha</option>
<option value="onedark">One Dark</option>
<option value="rosepine">Rosé Pine</option>
<option value="rosepine-moon">Rosé Pine Moon</option>
<option value="tokyonight">Tokyo Night</option>
<option value="iceberg">Iceberg</option>
</select> </select>
<span class="status-bar-item" id="privilege-status">unprivileged</span> <span class="status-bar-item" id="privilege-status">unprivileged</span>
</div> </div>
@@ -243,7 +253,7 @@
<button class="ctx-item" data-action="send-monitor">Send to Monitor</button> <button class="ctx-item" data-action="send-monitor">Send to Monitor</button>
<button class="ctx-item" data-action="send-nmap">Send to Nmap</button> <button class="ctx-item" data-action="send-nmap">Send to Nmap</button>
</div> </div>
<div id="crt-overlay"></div>
<script src="main.js"></script> <script src="main.js"></script>
</body> </body>
+159 -8
View File
@@ -22,15 +22,63 @@ var theme = (() => {
} catch (e) { } } 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() { function init() {
var saved = get(); var saved = get();
set(saved); set(saved);
// Add hacker option if previously unlocked
if (isHackerUnlocked()) {
addHackerOption();
}
var picker = document.getElementById('theme-picker'); var picker = document.getElementById('theme-picker');
picker.value = saved; picker.value = saved;
picker.addEventListener('change', function () { picker.addEventListener('change', function () {
set(picker.value); 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 // Apply immediately (before DOMContentLoaded) to prevent flash
@@ -609,7 +657,7 @@ const sender = (() => {
if (action.startsWith('nmap')) { if (action.startsWith('nmap')) {
nmapTab.setTarget(hosts.map((h) => String(h.ip))); nmapTab.setTarget(hosts.map((h) => String(h.ip)));
} else if (action.startsWith('monitor')) { } 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); document.querySelectorAll('.send-menu').forEach((m) => m.hidden = true);
@@ -675,7 +723,8 @@ const ctxMenu = (() => {
traceroute.run(ip); traceroute.run(ip);
break; break;
case 'send-monitor': case 'send-monitor':
monitorTab.setTargets([ip]); var monHost = table.getAll().find(function (h) { return String(h.ip) === ip; });
monitorTab.setTargets(monHost ? [monHost] : [ip]);
break; break;
case 'send-nmap': case 'send-nmap':
nmapTab.setTarget([ip]); nmapTab.setTarget([ip]);
@@ -926,7 +975,7 @@ const nmapTab = (() => {
const monitorTab = (() => { const monitorTab = (() => {
let running = false; let running = false;
let entries = {}; let entries = {};
var editingLabel = false;
var els = { var els = {
input: () => document.getElementById('monitor-input'), input: () => document.getElementById('monitor-input'),
interval: () => document.getElementById('monitor-interval'), interval: () => document.getElementById('monitor-interval'),
@@ -937,6 +986,26 @@ const monitorTab = (() => {
body: () => document.getElementById('monitor-body'), body: () => document.getElementById('monitor-body'),
}; };
var reminderInterval = null;
async function notify(title, body) {
try {
var current = window.__TAURI__.window.getCurrentWindow();
var visible = await current.isVisible();
if (visible) return;
var notif = window.__TAURI__.notification;
var granted = await notif.isPermissionGranted();
if (!granted) {
var perm = await notif.requestPermission();
if (perm !== 'granted') return;
}
notif.sendNotification({ title: title, body: body });
} catch (e) {
console.log('Notification error:', e);
}
}
function setRunning(active) { function setRunning(active) {
running = active; running = active;
els.btnStart().disabled = active; els.btnStart().disabled = active;
@@ -952,6 +1021,7 @@ const monitorTab = (() => {
} }
function render() { function render() {
if (editingLabel) return;
var body = els.body(); var body = els.body();
var ips = Object.keys(entries).sort(); var ips = Object.keys(entries).sort();
@@ -967,7 +1037,7 @@ const monitorTab = (() => {
return '<tr data-ip="' + ip + '">' return '<tr data-ip="' + ip + '">'
+ '<td>' + ip + '</td>' + '<td>' + ip + '</td>'
+ '<td>' + label + '</td>' + '<td class="editable-label" data-ip="' + ip + '">' + label + '</td>'
+ '<td class="' + statusClass + '">' + e.status + '</td>' + '<td class="' + statusClass + '">' + e.status + '</td>'
+ '<td>' + lastRtt + '</td>' + '<td>' + lastRtt + '</td>'
+ '<td>' + minRtt + '</td>' + '<td>' + minRtt + '</td>'
@@ -994,6 +1064,16 @@ const monitorTab = (() => {
try { try {
await invoke('monitor_add_hosts', { hosts: hosts }); 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'); var updated = await invoke('monitor_get_entries');
entries = {}; entries = {};
updated.forEach(function (e) { entries[e.ip] = e; }); updated.forEach(function (e) { entries[e.ip] = e; });
@@ -1022,6 +1102,14 @@ const monitorTab = (() => {
try { try {
await invoke('monitor_start', { intervalMs: interval }); await invoke('monitor_start', { intervalMs: interval });
// Start 15-minute reminder
if (reminderInterval) clearInterval(reminderInterval);
reminderInterval = setInterval(function () {
var count = Object.keys(entries).length;
notify('Argus Monitor Active',
'The monitor is still running with ' + count + ' hosts. Close the monitor to stop pinging.');
}, 15 * 60 * 1000);
} catch (err) { } catch (err) {
console.error('Monitor start error:', err); console.error('Monitor start error:', err);
setRunning(false); setRunning(false);
@@ -1034,6 +1122,10 @@ const monitorTab = (() => {
} catch (err) { } catch (err) {
console.error('Monitor stop error:', err); console.error('Monitor stop error:', err);
} }
if (reminderInterval) {
clearInterval(reminderInterval);
reminderInterval = null;
}
setRunning(false); setRunning(false);
} }
@@ -1048,9 +1140,20 @@ const monitorTab = (() => {
} }
} }
function setTargets(ips) { function setTargets(hosts) {
els.input().value = ips.join(', '); var items = hosts.map(function (h) {
// Switch to monitor tab 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('.tab').forEach(function (t) { t.classList.remove('active'); });
document.querySelectorAll('.view').forEach(function (v) { v.classList.remove('active'); }); document.querySelectorAll('.view').forEach(function (v) { v.classList.remove('active'); });
document.querySelector('[data-tab="monitor"]').classList.add('active'); document.querySelector('[data-tab="monitor"]').classList.add('active');
@@ -1066,7 +1169,13 @@ const monitorTab = (() => {
await listen('monitor:state-change', function (e) { await listen('monitor:state-change', function (e) {
var data = e.payload; var data = e.payload;
console.log('State change:', data.ip, data.old, '->', data.new); console.log('State change:', data.ip, data.old, '->', data['new']);
var label = entries[data.ip] ? (entries[data.ip].label || data.ip) : data.ip;
if (data['new'] === 'Down') {
notify('Host Down', label + ' (' + data.ip + ') is no longer responding');
} else if (data['new'] === 'Up' && data.old === 'Down') {
notify('Host Recovered', label + ' (' + data.ip + ') is back online');
}
}); });
} }
@@ -1085,6 +1194,41 @@ const monitorTab = (() => {
var btn = e.target.closest('.btn-remove'); var btn = e.target.closest('.btn-remove');
if (btn) removeHost(btn.dataset.ip); 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;
editingLabel = true;
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();
editingLabel = false;
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')
editingLabel = false;
render();
});
});
setupListeners(); setupListeners();
} }
@@ -1196,6 +1340,13 @@ window.addEventListener('DOMContentLoaded', () => {
updater.init(); updater.init();
changelog.init(); changelog.init();
theme.init(); theme.init();
// Always on top toggle
document.getElementById('chk-always-on-top').addEventListener('change', function (e) {
if (window.__TAURI__ && window.__TAURI__.window) {
var current = window.__TAURI__.window.getCurrentWindow();
current.setAlwaysOnTop(e.target.checked);
}
});
document.getElementById('btn-export-all').addEventListener('click', exporter.csvAll); document.getElementById('btn-export-all').addEventListener('click', exporter.csvAll);
document.getElementById('btn-export-up').addEventListener('click', exporter.csvUp); document.getElementById('btn-export-up').addEventListener('click', exporter.csvUp);
console.log('[Argus] Ready'); console.log('[Argus] Ready');
+386 -4
View File
@@ -1146,17 +1146,17 @@ body {
text-shadow: 0 0 6px var(--status-up-glow); text-shadow: 0 0 6px var(--status-up-glow);
} }
.monitor-status-Down { #monitor-table .monitor-status-Down {
color: var(--status-down); color: var(--status-down);
text-shadow: 0 0 6px var(--status-down-glow); text-shadow: 0 0 6px var(--status-down-glow);
} }
.monitor-status-Degraded { #monitor-table .monitor-status-Degraded {
color: var(--status-filtered); color: var(--status-filtered);
text-shadow: 0 0 6px var(--status-filtered-glow); text-shadow: 0 0 6px var(--status-filtered-glow);
} }
.monitor-status-Unknown { #monitor-table .monitor-status-Unknown {
color: var(--status-unknown); color: var(--status-unknown);
} }
@@ -1456,7 +1456,7 @@ body {
--border: #0d4450; --border: #0d4450;
--border-bright: #1a5c6a; --border-bright: #1a5c6a;
--text-primary: #93a1a1; --text-primary: #cb4b16;
--text-secondary: #839496; --text-secondary: #839496;
--text-muted: #586e75; --text-muted: #586e75;
@@ -1478,6 +1478,359 @@ body {
--danger-hover: #c62825; --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: #94e2d5;
--text-secondary: #a6adc8;
--text-muted: #6c7086;
--cyan: #b4befe;
--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="mocha"] .port-tag {
background: rgba(30, 102, 245, 0.1);
border-color: rgba(30, 102, 245, 0.2);
}
:root[data-theme="mocha"] #privilege-status::before {
background: var(--status-up);
box-shadow: 0 0 4px rgba(64, 160, 43, 0.3);
}
:root[data-theme="mocha"] ::-webkit-scrollbar-track {
background: var(--bg-primary);
}
:root[data-theme="mocha"] ::-webkit-scrollbar-thumb {
background: var(--border-bright);
}
/* ===== Theme: One Dark ===== */
:root[data-theme="onedark"] {
--bg-primary: #282c34;
--bg-secondary: #21252b;
--bg-tertiary: #2c313a;
--bg-hover: #3e4451;
--bg-active: #4b5263;
--border: #3e4451;
--border-bright: #4b5263;
--text-primary: #abb2bf;
--text-secondary: #848b98;
--text-muted: #5c6370;
--cyan: #61afef;
--cyan-hover: #519fdf;
--cyan-dim: rgba(97, 175, 239, 0.08);
--cyan-glow: rgba(97, 175, 239, 0.2);
--cyan-subtle: rgba(97, 175, 239, 0.03);
--status-up: #98c379;
--status-up-glow: rgba(152, 195, 121, 0.15);
--status-down: #e06c75;
--status-down-glow: rgba(224, 108, 117, 0.15);
--status-filtered: #e5c07b;
--status-filtered-glow: rgba(229, 192, 123, 0.15);
--status-unknown: #5c6370;
--danger: #e06c75;
--danger-hover: #d05f68;
}
:root[data-theme="onedark"] .toolbar-circuit {
filter: hue-rotate(30deg) saturate(0.6);
}
/* ===== Theme: Rosé Pine ===== */
:root[data-theme="rosepine"] {
--bg-primary: #191724;
--bg-secondary: #1f1d2e;
--bg-tertiary: #26233a;
--bg-hover: #403d52;
--bg-active: #524f67;
--border: #26233a;
--border-bright: #403d52;
--text-primary: #31748f;
--text-secondary: #908caa;
--text-muted: #6e6a86;
--cyan: #c4a7e7;
--cyan-hover: #b498d7;
--cyan-dim: rgba(196, 167, 231, 0.08);
--cyan-glow: rgba(196, 167, 231, 0.2);
--cyan-subtle: rgba(196, 167, 231, 0.03);
--status-up: #9ccfd8;
--status-up-glow: rgba(156, 207, 216, 0.15);
--status-down: #eb6f92;
--status-down-glow: rgba(235, 111, 146, 0.15);
--status-filtered: #f6c177;
--status-filtered-glow: rgba(246, 193, 119, 0.15);
--status-unknown: #6e6a86;
--danger: #eb6f92;
--danger-hover: #db5f82;
}
:root[data-theme="rosepine"] .toolbar-circuit {
filter: hue-rotate(80deg) saturate(0.5) brightness(0.8);
}
/* ===== Theme: Rosé Pine Moon ===== */
:root[data-theme="rosepine-moon"] {
--bg-primary: #232136;
--bg-secondary: #2a273f;
--bg-tertiary: #393552;
--bg-hover: #44415a;
--bg-active: #56526e;
--border: #393552;
--border-bright: #44415a;
--text-primary: #9ccfd8;
--text-secondary: #908caa;
--text-muted: #6e6a86;
--cyan: #c4a7e7;
--cyan-hover: #b498d7;
--cyan-dim: rgba(196, 167, 231, 0.08);
--cyan-glow: rgba(196, 167, 231, 0.2);
--cyan-subtle: rgba(196, 167, 231, 0.03);
--status-up: #9ccfd8;
--status-up-glow: rgba(156, 207, 216, 0.15);
--status-down: #eb6f92;
--status-down-glow: rgba(235, 111, 146, 0.15);
--status-filtered: #f6c177;
--status-filtered-glow: rgba(246, 193, 119, 0.15);
--status-unknown: #6e6a86;
--danger: #eb6f92;
--danger-hover: #db5f82;
}
:root[data-theme="rosepine-moon"] .toolbar-circuit {
filter: hue-rotate(80deg) saturate(0.5) brightness(0.8);
}
/* ===== Theme: Tokyo Night ===== */
:root[data-theme="tokyonight"] {
--bg-primary: #1a1b26;
--bg-secondary: #16161e;
--bg-tertiary: #1f2335;
--bg-hover: #292e42;
--bg-active: #33384d;
--border: #1f2335;
--border-bright: #292e42;
--text-primary: #bb9af7;
--text-secondary: #a9b1d6;
--text-muted: #565f89;
--cyan: #7aa2f7;
--cyan-hover: #6a92e7;
--cyan-dim: rgba(122, 162, 247, 0.08);
--cyan-glow: rgba(122, 162, 247, 0.2);
--cyan-subtle: rgba(122, 162, 247, 0.03);
--status-up: #9ece6a;
--status-up-glow: rgba(158, 206, 106, 0.15);
--status-down: #f7768e;
--status-down-glow: rgba(247, 118, 142, 0.15);
--status-filtered: #e0af68;
--status-filtered-glow: rgba(224, 175, 104, 0.15);
--status-unknown: #565f89;
--danger: #f7768e;
--danger-hover: #e7667e;
}
:root[data-theme="tokyonight"] .toolbar-circuit {
filter: hue-rotate(40deg) saturate(0.5);
}
/* ===== Theme: Iceberg ===== */
:root[data-theme="iceberg"] {
--bg-primary: #161821;
--bg-secondary: #1e2132;
--bg-tertiary: #252837;
--bg-hover: #33374c;
--bg-active: #3d4259;
--border: #252837;
--border-bright: #33374c;
--text-primary: #c6c8d1;
--text-secondary: #818596;
--text-muted: #444b71;
--cyan: #84a0c6;
--cyan-hover: #7490b6;
--cyan-dim: rgba(132, 160, 198, 0.08);
--cyan-glow: rgba(132, 160, 198, 0.2);
--cyan-subtle: rgba(132, 160, 198, 0.03);
--status-up: #b4be82;
--status-up-glow: rgba(180, 190, 130, 0.15);
--status-down: #e27878;
--status-down-glow: rgba(226, 120, 120, 0.15);
--status-filtered: #e2a478;
--status-filtered-glow: rgba(226, 164, 120, 0.15);
--status-unknown: #444b71;
--danger: #e27878;
--danger-hover: #d26868;
}
:root[data-theme="iceberg"] .toolbar-circuit {
filter: hue-rotate(30deg) saturate(0.4) brightness(0.9);
}
/* ===== 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.5) 0px,
rgba(0, 0, 0, 0.5) 1px,
transparent 1px,
transparent 4px),
linear-gradient(180deg,
transparent 0%,
rgba(0, 255, 65, 0.09) 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 ===== */ /* ===== Circuit art theme tinting ===== */
:root[data-theme="dracula"] .toolbar-circuit { :root[data-theme="dracula"] .toolbar-circuit {
@@ -1494,4 +1847,33 @@ body {
:root[data-theme="midnight"] .toolbar-circuit { :root[data-theme="midnight"] .toolbar-circuit {
filter: brightness(0.8); 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;
}
.status-bar-toggle {
font-size: 11px;
color: var(--text-muted);
}
.status-bar-toggle input:checked+span {
color: var(--cyan);
} }